diff --git a/build.gradle.kts b/build.gradle.kts index 28cb586..807e2df 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,7 +14,7 @@ plugins { } group = "xyz.alexcrea" -version = "1.6.2" +version = "1.6.3" repositories { // EcoEnchants @@ -36,6 +36,10 @@ dependencies { compileOnly("com.willfp:EcoEnchants:12.5.1") compileOnly("com.willfp:eco:6.70.1") + // ExcellentEnchants + compileOnly(files("libs/nightcore-2.6.4.jar")) + compileOnly(files("libs/ExcellentEnchants-4.2.2.jar")) + // Disenchantment compileOnly("cz.kominekjan:Disenchantment:v5.4.0") diff --git a/defaultconfigs/1.18/config.yml b/defaultconfigs/1.18/config.yml index 5b47ec4..dd24558 100644 --- a/defaultconfigs/1.18/config.yml +++ b/defaultconfigs/1.18/config.yml @@ -97,49 +97,46 @@ default_limit: 5 # # Valid range of 1 - 255 for each enchantment enchant_limits: - aqua_affinity: 1 - binding_curse: 1 - channeling: 1 - flame: 1 - infinity: 1 - mending: 1 - multishot: 1 - silk_touch: 1 - vanishing_curse: 1 - depth_strider: 3 # anything more than 3 is treated as 3 by the game - protection: 4 - fire_protection: 4 - blast_protection: 4 - projectile_protection: 4 - feather_falling: 4 - thorns: 3 - respiration: 3 - sharpness: 5 - smite: 5 - bane_of_arthropods: 5 - knockback: 2 - fire_aspect: 2 - looting: 3 - sweeping: 3 - sweeping_edge: 3 - efficiency: 5 - unbreaking: 3 - fortune: 3 - power: 5 - punch: 2 - luck_of_the_sea: 3 - lure: 3 - frost_walker: 2 - impaling: 5 - riptide: 3 - loyalty: 3 - piercing: 4 - quick_charge: 3 - soul_speed: 3 - swift_sneak: 3 - density: 5 - breach: 4 - wind_burst: 3 + minecraft:aqua_affinity: 1 + minecraft:binding_curse: 1 + minecraft:channeling: 1 + minecraft:flame: 1 + minecraft:infinity: 1 + minecraft:mending: 1 + minecraft:multishot: 1 + minecraft:silk_touch: 1 + minecraft:vanishing_curse: 1 + minecraft:depth_strider: 3 # anything more than 3 is treated as 3 by the game + minecraft:protection: 4 + minecraft:fire_protection: 4 + minecraft:blast_protection: 4 + minecraft:projectile_protection: 4 + minecraft:feather_falling: 4 + minecraft:thorns: 3 + minecraft:respiration: 3 + minecraft:sharpness: 5 + minecraft:smite: 5 + minecraft:bane_of_arthropods: 5 + minecraft:knockback: 2 + minecraft:fire_aspect: 2 + minecraft:looting: 3 + minecraft:sweeping: 3 + minecraft:sweeping_edge: 3 + minecraft:efficiency: 5 + minecraft:unbreaking: 3 + minecraft:fortune: 3 + minecraft:power: 5 + minecraft:punch: 2 + minecraft:luck_of_the_sea: 3 + minecraft:lure: 3 + minecraft:frost_walker: 2 + minecraft:impaling: 5 + minecraft:riptide: 3 + minecraft:loyalty: 3 + minecraft:piercing: 4 + minecraft:quick_charge: 3 + minecraft:soul_speed: 3 + minecraft:swift_sneak: 3 # Multipliers used to calculate the enchantment's value in repair/combining # @@ -153,135 +150,137 @@ enchant_limits: # With default values protection 4 would have a value of 4 when # coming from either a book (4 * 1) or an item (4 * 1) enchant_values: - aqua_affinity: + minecraft:aqua_affinity: item: 4 book: 2 - bane_of_arthropods: + minecraft:bane_of_arthropods: item: 2 book: 1 - binding_curse: + minecraft:binding_curse: item: 8 book: 4 - blast_protection: + minecraft:blast_protection: item: 4 book: 2 - channeling: + minecraft:channeling: item: 8 book: 4 - depth_strider: + minecraft:depth_strider: item: 4 book: 2 - efficiency: + minecraft:efficiency: item: 1 book: 1 - flame: + minecraft:flame: item: 4 book: 2 - feather_falling: + minecraft:feather_falling: item: 2 book: 1 - fire_aspect: + minecraft:fire_aspect: item: 4 book: 2 - fire_protection: + minecraft:fire_protection: item: 2 book: 1 - fortune: + minecraft:fortune: item: 4 book: 2 - frost_walker: + minecraft:frost_walker: item: 4 book: 2 - impaling: + minecraft:impaling: item: 4 book: 2 - infinity: + minecraft:infinity: item: 8 book: 4 - knockback: + minecraft:knockback: item: 2 book: 1 - looting: + minecraft:looting: item: 4 book: 2 - loyalty: + minecraft:loyalty: item: 1 book: 1 - luck_of_the_sea: + minecraft:luck_of_the_sea: item: 4 book: 2 - lure: + minecraft:lure: item: 4 book: 2 - mending: + minecraft:mending: item: 4 book: 2 - multishot: + minecraft:multishot: item: 4 book: 2 - piercing: + minecraft:piercing: item: 1 book: 1 - power: + minecraft:power: item: 1 book: 1 - projectile_protection: + minecraft:projectile_protection: item: 2 book: 1 - protection: + minecraft:protection: item: 1 book: 1 - punch: + minecraft:punch: item: 4 book: 2 - quick_charge: + minecraft:quick_charge: item: 2 book: 1 - respiration: + minecraft:respiration: item: 4 book: 2 - riptide: + minecraft:riptide: item: 4 book: 2 - silk_touch: + minecraft:silk_touch: item: 8 book: 4 - sharpness: + minecraft:sharpness: item: 1 book: 1 - smite: + minecraft:smite: item: 2 book: 1 - soul_speed: + minecraft:soul_speed: item: 8 book: 4 - swift_sneak: + minecraft:swift_sneak: item: 8 book: 4 - sweeping: + minecraft:sweeping: item: 4 book: 2 - sweeping_edge: + minecraft:sweeping_edge: item: 4 book: 2 - thorns: + minecraft:thorns: item: 8 book: 4 - unbreaking: + minecraft:unbreaking: item: 2 book: 1 - vanishing_curse: + minecraft:vanishing_curse: item: 8 book: 4 - density: - item: 1 - book: 1 - breach: - item: 4 - book: 2 - wind_burst: - item: 4 - book: 2 + +# Disable enchantment merging for level above the set value +# Enchantment merging is when, for example, 2 unbreaking II book combine to give sharpness III +# But Enchantment above this value can still be applied. following the previous example, we could still apply a unbreaking III book to a sword +# Even if disable-merge-over of unbreaking is set to 2 +# -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent. +disable-merge-over: + # Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla) + minecraft:sharpness: -1 + # If uncommented. 2 unbreaking II book would not give an unbreaking III book. but unbreaking III book can still be applied + #minecraft:unbreaking: 2 # Whether to show debug logging debug_log: false @@ -296,4 +295,3 @@ debug_log_verbose: false force_protocolib: false configVersion: 1.6.2 -lowMinecraftVersion: '1.21' diff --git a/defaultconfigs/1.18/enchant_conflict.yml b/defaultconfigs/1.18/enchant_conflict.yml index ed154ab..0e8b3f3 100644 --- a/defaultconfigs/1.18/enchant_conflict.yml +++ b/defaultconfigs/1.18/enchant_conflict.yml @@ -17,158 +17,158 @@ # ---------------------------------------------------- restriction_aqua_affinity: - enchantments: [ aqua_affinity ] + enchantments: [ minecraft:aqua_affinity ] notAffectedGroups: [ enchanted_book, helmets ] restriction_bane_of_arthropods: - enchantments: [ bane_of_arthropods ] + enchantments: [ minecraft:bane_of_arthropods ] notAffectedGroups: [ enchanted_book, melee_weapons ] restriction_blast_protection: - enchantments: [ blast_protection ] + enchantments: [ minecraft:blast_protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_channeling: - enchantments: [ channeling ] + enchantments: [ minecraft:channeling ] notAffectedGroups: [ enchanted_book, trident ] restriction_binding_curse: - enchantments: [ binding_curse ] + enchantments: [ minecraft:binding_curse ] notAffectedGroups: [ enchanted_book, wearable ] restriction_vanishing_curse: - enchantments: [ vanishing_curse ] + enchantments: [ minecraft:vanishing_curse ] notAffectedGroups: [ enchanted_book, can_vanish ] restriction_depth_strider: - enchantments: [ depth_strider ] + enchantments: [ minecraft:depth_strider ] notAffectedGroups: [ enchanted_book, boots ] restriction_efficiency: - enchantments: [ efficiency ] + enchantments: [ minecraft:efficiency ] notAffectedGroups: [ enchanted_book, tools, shears ] restriction_feather_falling: - enchantments: [ feather_falling ] + enchantments: [ minecraft:feather_falling ] notAffectedGroups: [ enchanted_book, boots ] restriction_fire_aspect: - enchantments: [ fire_aspect ] + enchantments: [ minecraft:fire_aspect ] notAffectedGroups: [ enchanted_book, swords ] restriction_fire_protection: - enchantments: [ fire_protection ] + enchantments: [ minecraft:fire_protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_flame: - enchantments: [ flame ] + enchantments: [ minecraft:flame ] notAffectedGroups: [ enchanted_book, bow ] restriction_fortune: - enchantments: [ fortune ] + enchantments: [ minecraft:fortune ] notAffectedGroups: [ enchanted_book, tools ] restriction_frost_walker: - enchantments: [ frost_walker ] + enchantments: [ minecraft:frost_walker ] notAffectedGroups: [ enchanted_book, boots ] restriction_impaling: - enchantments: [ impaling ] + enchantments: [ minecraft:impaling ] notAffectedGroups: [ enchanted_book, trident ] restriction_infinity: - enchantments: [ infinity ] + enchantments: [ minecraft:infinity ] notAffectedGroups: [ enchanted_book, bow ] restriction_knockback: - enchantments: [ knockback ] + enchantments: [ minecraft:knockback ] notAffectedGroups: [ enchanted_book, swords ] restriction_looting: - enchantments: [ looting ] + enchantments: [ minecraft:looting ] notAffectedGroups: [ enchanted_book, swords ] restriction_loyalty: - enchantments: [ loyalty ] + enchantments: [ minecraft:loyalty ] notAffectedGroups: [ enchanted_book, trident ] restriction_lure: - enchantments: [ lure ] + enchantments: [ minecraft:lure ] notAffectedGroups: [ enchanted_book, fishing_rod ] restriction_mending: - enchantments: [ mending ] + enchantments: [ minecraft:mending ] notAffectedGroups: [ enchanted_book, can_unbreak ] -restriction_multishot: - enchantments: [ multishot ] +restriction_minecraft_multishot: + enchantments: [ minecraft:multishot ] notAffectedGroups: [ enchanted_book, crossbow ] restriction_piercing: - enchantments: [ piercing ] + enchantments: [ minecraft:piercing ] notAffectedGroups: [ enchanted_book, crossbow ] restriction_power: - enchantments: [ power ] + enchantments: [ minecraft:power ] notAffectedGroups: [ enchanted_book, bow ] restriction_projectile_protection: - enchantments: [ projectile_protection ] + enchantments: [ minecraft:projectile_protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_protection: - enchantments: [ protection ] + enchantments: [ minecraft:protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_punch: - enchantments: [ punch ] + enchantments: [ minecraft:punch ] notAffectedGroups: [ enchanted_book, bow ] restriction_quick_charge: - enchantments: [ quick_charge ] + enchantments: [ minecraft:quick_charge ] notAffectedGroups: [ enchanted_book, crossbow ] restriction_respiration: - enchantments: [ respiration ] + enchantments: [ minecraft:respiration ] notAffectedGroups: [ enchanted_book, helmets ] restriction_riptide: - enchantments: [ riptide ] + enchantments: [ minecraft:riptide ] notAffectedGroups: [ enchanted_book, trident ] restriction_sharpness: - enchantments: [ sharpness ] + enchantments: [ minecraft:sharpness ] notAffectedGroups: [ enchanted_book, melee_weapons ] -restriction_silk_touch: - enchantments: [ silk_touch ] +restriction__silk_touch: + enchantments: [ minecraft:silk_touch ] notAffectedGroups: [ enchanted_book, tools ] restriction_smite: - enchantments: [ smite ] + enchantments: [ minecraft:smite ] notAffectedGroups: [ enchanted_book, melee_weapons ] restriction_soul_speed: - enchantments: [ soul_speed ] + enchantments: [ minecraft:soul_speed ] notAffectedGroups: [ enchanted_book, boots ] restriction_sweeping_edge: - enchantments: [ sweeping, sweeping_edge ] + enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ] notAffectedGroups: [ enchanted_book, swords ] # Do not exist in 1.18, that mean useInFuture will be set to true # useInFuture set to true also mean it will not warn if there is an issue restriction_swift_sneak: useInFuture: true - enchantments: [ swift_sneak ] + enchantments: [ minecraft:swift_sneak ] notAffectedGroups: [ enchanted_book, leggings ] restriction_thorns: - enchantments: [ thorns ] + enchantments: [ minecraft:thorns ] notAffectedGroups: [ enchanted_book, armors ] -restriction_unbreaking: - enchantments: [ unbreaking ] +restriction__unbreaking: + enchantments: [ minecraft:unbreaking ] notAffectedGroups: [ enchanted_book, can_unbreak ] # ---------------------------------------------------- @@ -180,60 +180,60 @@ restriction_unbreaking: sword_enchant_conflict: enchantments: - - bane_of_arthropods - - smite - - sharpness + - minecraft:bane_of_arthropods + - minecraft:smite + - minecraft:sharpness notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 protection_enchant_conflict: enchantments: - - blast_protection - - fire_protection - - projectile_protection - - protection + - minecraft:blast_protection + - minecraft:fire_protection + - minecraft:projectile_protection + - minecraft:protection notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 trident_conflict1: enchantments: - - channeling - - riptide + - minecraft:channeling + - minecraft:riptide notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 trident_conflict2: enchantments: - - loyalty - - riptide + - minecraft:loyalty + - minecraft:riptide notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 boot_conflict: enchantments: - - depth_strider - - frost_walker + - minecraft:depth_strider + - minecraft:frost_walker notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 tool_conflict: enchantments: - - fortune - - silk_touch + - minecraft:fortune + - minecraft:silk_touch notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 bow_conflict: enchantments: - - mending - - infinity + - minecraft:mending + - minecraft:infinity notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 crossbow_conflict: enchantments: - - multishot - - piercing + - minecraft:multishot + - minecraft:piercing notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 diff --git a/defaultconfigs/1.21/config.yml b/defaultconfigs/1.21/config.yml index 5b47ec4..dd24558 100644 --- a/defaultconfigs/1.21/config.yml +++ b/defaultconfigs/1.21/config.yml @@ -97,49 +97,46 @@ default_limit: 5 # # Valid range of 1 - 255 for each enchantment enchant_limits: - aqua_affinity: 1 - binding_curse: 1 - channeling: 1 - flame: 1 - infinity: 1 - mending: 1 - multishot: 1 - silk_touch: 1 - vanishing_curse: 1 - depth_strider: 3 # anything more than 3 is treated as 3 by the game - protection: 4 - fire_protection: 4 - blast_protection: 4 - projectile_protection: 4 - feather_falling: 4 - thorns: 3 - respiration: 3 - sharpness: 5 - smite: 5 - bane_of_arthropods: 5 - knockback: 2 - fire_aspect: 2 - looting: 3 - sweeping: 3 - sweeping_edge: 3 - efficiency: 5 - unbreaking: 3 - fortune: 3 - power: 5 - punch: 2 - luck_of_the_sea: 3 - lure: 3 - frost_walker: 2 - impaling: 5 - riptide: 3 - loyalty: 3 - piercing: 4 - quick_charge: 3 - soul_speed: 3 - swift_sneak: 3 - density: 5 - breach: 4 - wind_burst: 3 + minecraft:aqua_affinity: 1 + minecraft:binding_curse: 1 + minecraft:channeling: 1 + minecraft:flame: 1 + minecraft:infinity: 1 + minecraft:mending: 1 + minecraft:multishot: 1 + minecraft:silk_touch: 1 + minecraft:vanishing_curse: 1 + minecraft:depth_strider: 3 # anything more than 3 is treated as 3 by the game + minecraft:protection: 4 + minecraft:fire_protection: 4 + minecraft:blast_protection: 4 + minecraft:projectile_protection: 4 + minecraft:feather_falling: 4 + minecraft:thorns: 3 + minecraft:respiration: 3 + minecraft:sharpness: 5 + minecraft:smite: 5 + minecraft:bane_of_arthropods: 5 + minecraft:knockback: 2 + minecraft:fire_aspect: 2 + minecraft:looting: 3 + minecraft:sweeping: 3 + minecraft:sweeping_edge: 3 + minecraft:efficiency: 5 + minecraft:unbreaking: 3 + minecraft:fortune: 3 + minecraft:power: 5 + minecraft:punch: 2 + minecraft:luck_of_the_sea: 3 + minecraft:lure: 3 + minecraft:frost_walker: 2 + minecraft:impaling: 5 + minecraft:riptide: 3 + minecraft:loyalty: 3 + minecraft:piercing: 4 + minecraft:quick_charge: 3 + minecraft:soul_speed: 3 + minecraft:swift_sneak: 3 # Multipliers used to calculate the enchantment's value in repair/combining # @@ -153,135 +150,137 @@ enchant_limits: # With default values protection 4 would have a value of 4 when # coming from either a book (4 * 1) or an item (4 * 1) enchant_values: - aqua_affinity: + minecraft:aqua_affinity: item: 4 book: 2 - bane_of_arthropods: + minecraft:bane_of_arthropods: item: 2 book: 1 - binding_curse: + minecraft:binding_curse: item: 8 book: 4 - blast_protection: + minecraft:blast_protection: item: 4 book: 2 - channeling: + minecraft:channeling: item: 8 book: 4 - depth_strider: + minecraft:depth_strider: item: 4 book: 2 - efficiency: + minecraft:efficiency: item: 1 book: 1 - flame: + minecraft:flame: item: 4 book: 2 - feather_falling: + minecraft:feather_falling: item: 2 book: 1 - fire_aspect: + minecraft:fire_aspect: item: 4 book: 2 - fire_protection: + minecraft:fire_protection: item: 2 book: 1 - fortune: + minecraft:fortune: item: 4 book: 2 - frost_walker: + minecraft:frost_walker: item: 4 book: 2 - impaling: + minecraft:impaling: item: 4 book: 2 - infinity: + minecraft:infinity: item: 8 book: 4 - knockback: + minecraft:knockback: item: 2 book: 1 - looting: + minecraft:looting: item: 4 book: 2 - loyalty: + minecraft:loyalty: item: 1 book: 1 - luck_of_the_sea: + minecraft:luck_of_the_sea: item: 4 book: 2 - lure: + minecraft:lure: item: 4 book: 2 - mending: + minecraft:mending: item: 4 book: 2 - multishot: + minecraft:multishot: item: 4 book: 2 - piercing: + minecraft:piercing: item: 1 book: 1 - power: + minecraft:power: item: 1 book: 1 - projectile_protection: + minecraft:projectile_protection: item: 2 book: 1 - protection: + minecraft:protection: item: 1 book: 1 - punch: + minecraft:punch: item: 4 book: 2 - quick_charge: + minecraft:quick_charge: item: 2 book: 1 - respiration: + minecraft:respiration: item: 4 book: 2 - riptide: + minecraft:riptide: item: 4 book: 2 - silk_touch: + minecraft:silk_touch: item: 8 book: 4 - sharpness: + minecraft:sharpness: item: 1 book: 1 - smite: + minecraft:smite: item: 2 book: 1 - soul_speed: + minecraft:soul_speed: item: 8 book: 4 - swift_sneak: + minecraft:swift_sneak: item: 8 book: 4 - sweeping: + minecraft:sweeping: item: 4 book: 2 - sweeping_edge: + minecraft:sweeping_edge: item: 4 book: 2 - thorns: + minecraft:thorns: item: 8 book: 4 - unbreaking: + minecraft:unbreaking: item: 2 book: 1 - vanishing_curse: + minecraft:vanishing_curse: item: 8 book: 4 - density: - item: 1 - book: 1 - breach: - item: 4 - book: 2 - wind_burst: - item: 4 - book: 2 + +# Disable enchantment merging for level above the set value +# Enchantment merging is when, for example, 2 unbreaking II book combine to give sharpness III +# But Enchantment above this value can still be applied. following the previous example, we could still apply a unbreaking III book to a sword +# Even if disable-merge-over of unbreaking is set to 2 +# -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent. +disable-merge-over: + # Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla) + minecraft:sharpness: -1 + # If uncommented. 2 unbreaking II book would not give an unbreaking III book. but unbreaking III book can still be applied + #minecraft:unbreaking: 2 # Whether to show debug logging debug_log: false @@ -296,4 +295,3 @@ debug_log_verbose: false force_protocolib: false configVersion: 1.6.2 -lowMinecraftVersion: '1.21' diff --git a/defaultconfigs/1.21/enchant_conflict.yml b/defaultconfigs/1.21/enchant_conflict.yml index dc3e951..0e8b3f3 100644 --- a/defaultconfigs/1.21/enchant_conflict.yml +++ b/defaultconfigs/1.21/enchant_conflict.yml @@ -17,278 +17,159 @@ # ---------------------------------------------------- restriction_aqua_affinity: - enchantments: - - aqua_affinity - notAffectedGroups: - - enchanted_book - - helmets + enchantments: [ minecraft:aqua_affinity ] + notAffectedGroups: [ enchanted_book, helmets ] restriction_bane_of_arthropods: - enchantments: - - bane_of_arthropods - notAffectedGroups: - - enchanted_book - - melee_weapons - - mace + enchantments: [ minecraft:bane_of_arthropods ] + notAffectedGroups: [ enchanted_book, melee_weapons ] restriction_blast_protection: - enchantments: - - blast_protection - notAffectedGroups: - - enchanted_book - - armors + enchantments: [ minecraft:blast_protection ] + notAffectedGroups: [ enchanted_book, armors ] restriction_channeling: - enchantments: - - channeling - notAffectedGroups: - - enchanted_book - - trident + enchantments: [ minecraft:channeling ] + notAffectedGroups: [ enchanted_book, trident ] restriction_binding_curse: - enchantments: - - binding_curse - notAffectedGroups: - - enchanted_book - - wearable + enchantments: [ minecraft:binding_curse ] + notAffectedGroups: [ enchanted_book, wearable ] restriction_vanishing_curse: - enchantments: - - vanishing_curse - notAffectedGroups: - - enchanted_book - - can_vanish + enchantments: [ minecraft:vanishing_curse ] + notAffectedGroups: [ enchanted_book, can_vanish ] restriction_depth_strider: - enchantments: - - depth_strider - notAffectedGroups: - - enchanted_book - - boots + enchantments: [ minecraft:depth_strider ] + notAffectedGroups: [ enchanted_book, boots ] restriction_efficiency: - enchantments: - - efficiency - notAffectedGroups: - - enchanted_book - - tools - - shears + enchantments: [ minecraft:efficiency ] + notAffectedGroups: [ enchanted_book, tools, shears ] restriction_feather_falling: - enchantments: - - feather_falling - notAffectedGroups: - - enchanted_book - - boots + enchantments: [ minecraft:feather_falling ] + notAffectedGroups: [ enchanted_book, boots ] restriction_fire_aspect: - enchantments: - - fire_aspect - notAffectedGroups: - - enchanted_book - - swords - - mace + enchantments: [ minecraft:fire_aspect ] + notAffectedGroups: [ enchanted_book, swords ] restriction_fire_protection: - enchantments: - - fire_protection - notAffectedGroups: - - enchanted_book - - armors + enchantments: [ minecraft:fire_protection ] + notAffectedGroups: [ enchanted_book, armors ] restriction_flame: - enchantments: - - flame - notAffectedGroups: - - enchanted_book - - bow + enchantments: [ minecraft:flame ] + notAffectedGroups: [ enchanted_book, bow ] restriction_fortune: - enchantments: - - fortune - notAffectedGroups: - - enchanted_book - - tools + enchantments: [ minecraft:fortune ] + notAffectedGroups: [ enchanted_book, tools ] restriction_frost_walker: - enchantments: - - frost_walker - notAffectedGroups: - - enchanted_book - - boots + enchantments: [ minecraft:frost_walker ] + notAffectedGroups: [ enchanted_book, boots ] restriction_impaling: - enchantments: - - impaling - notAffectedGroups: - - enchanted_book - - trident + enchantments: [ minecraft:impaling ] + notAffectedGroups: [ enchanted_book, trident ] restriction_infinity: - enchantments: - - infinity - notAffectedGroups: - - enchanted_book - - bow + enchantments: [ minecraft:infinity ] + notAffectedGroups: [ enchanted_book, bow ] restriction_knockback: - enchantments: - - knockback - notAffectedGroups: - - enchanted_book - - swords + enchantments: [ minecraft:knockback ] + notAffectedGroups: [ enchanted_book, swords ] restriction_looting: - enchantments: - - looting - notAffectedGroups: - - enchanted_book - - swords + enchantments: [ minecraft:looting ] + notAffectedGroups: [ enchanted_book, swords ] restriction_loyalty: - enchantments: - - loyalty - notAffectedGroups: - - enchanted_book - - trident + enchantments: [ minecraft:loyalty ] + notAffectedGroups: [ enchanted_book, trident ] restriction_lure: - enchantments: - - lure - notAffectedGroups: - - enchanted_book - - fishing_rod + enchantments: [ minecraft:lure ] + notAffectedGroups: [ enchanted_book, fishing_rod ] restriction_mending: - enchantments: - - mending - notAffectedGroups: - - enchanted_book - - can_unbreak + enchantments: [ minecraft:mending ] + notAffectedGroups: [ enchanted_book, can_unbreak ] -restriction_multishot: - enchantments: - - multishot - notAffectedGroups: - - enchanted_book - - crossbow +restriction_minecraft_multishot: + enchantments: [ minecraft:multishot ] + notAffectedGroups: [ enchanted_book, crossbow ] restriction_piercing: - enchantments: - - piercing - notAffectedGroups: - - enchanted_book - - crossbow + enchantments: [ minecraft:piercing ] + notAffectedGroups: [ enchanted_book, crossbow ] restriction_power: - enchantments: - - power - notAffectedGroups: - - enchanted_book - - bow + enchantments: [ minecraft:power ] + notAffectedGroups: [ enchanted_book, bow ] restriction_projectile_protection: - enchantments: - - projectile_protection - notAffectedGroups: - - enchanted_book - - armors + enchantments: [ minecraft:projectile_protection ] + notAffectedGroups: [ enchanted_book, armors ] restriction_protection: - enchantments: - - protection - notAffectedGroups: - - enchanted_book - - armors + enchantments: [ minecraft:protection ] + notAffectedGroups: [ enchanted_book, armors ] restriction_punch: - enchantments: - - punch - notAffectedGroups: - - enchanted_book - - bow + enchantments: [ minecraft:punch ] + notAffectedGroups: [ enchanted_book, bow ] restriction_quick_charge: - enchantments: - - quick_charge - notAffectedGroups: - - enchanted_book - - crossbow + enchantments: [ minecraft:quick_charge ] + notAffectedGroups: [ enchanted_book, crossbow ] restriction_respiration: - enchantments: - - respiration - notAffectedGroups: - - enchanted_book - - helmets + enchantments: [ minecraft:respiration ] + notAffectedGroups: [ enchanted_book, helmets ] restriction_riptide: - enchantments: - - riptide - notAffectedGroups: - - enchanted_book - - trident + enchantments: [ minecraft:riptide ] + notAffectedGroups: [ enchanted_book, trident ] restriction_sharpness: - enchantments: - - sharpness - notAffectedGroups: - - enchanted_book - - melee_weapons + enchantments: [ minecraft:sharpness ] + notAffectedGroups: [ enchanted_book, melee_weapons ] -restriction_silk_touch: - enchantments: - - silk_touch - notAffectedGroups: - - enchanted_book - - tools +restriction__silk_touch: + enchantments: [ minecraft:silk_touch ] + notAffectedGroups: [ enchanted_book, tools ] restriction_smite: - enchantments: - - smite - notAffectedGroups: - - enchanted_book - - melee_weapons - - mace + enchantments: [ minecraft:smite ] + notAffectedGroups: [ enchanted_book, melee_weapons ] restriction_soul_speed: - enchantments: - - soul_speed - notAffectedGroups: - - enchanted_book - - boots + enchantments: [ minecraft:soul_speed ] + notAffectedGroups: [ enchanted_book, boots ] restriction_sweeping_edge: - enchantments: - - sweeping - - sweeping_edge - notAffectedGroups: - - enchanted_book - - swords + enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ] + notAffectedGroups: [ enchanted_book, swords ] # Do not exist in 1.18, that mean useInFuture will be set to true # useInFuture set to true also mean it will not warn if there is an issue restriction_swift_sneak: useInFuture: true - enchantments: - - swift_sneak - notAffectedGroups: - - enchanted_book - - leggings + enchantments: [ minecraft:swift_sneak ] + notAffectedGroups: [ enchanted_book, leggings ] restriction_thorns: - enchantments: - - thorns - notAffectedGroups: - - enchanted_book - - armors + enchantments: [ minecraft:thorns ] + notAffectedGroups: [ enchanted_book, armors ] -restriction_unbreaking: - enchantments: - - unbreaking - notAffectedGroups: - - enchanted_book - - can_unbreak +restriction__unbreaking: + enchantments: [ minecraft:unbreaking ] + notAffectedGroups: [ enchanted_book, can_unbreak ] # ---------------------------------------------------- # Now we have conflicts about enchantment Incompatibility @@ -299,86 +180,61 @@ restriction_unbreaking: sword_enchant_conflict: enchantments: - - bane_of_arthropods - - smite - - sharpness - notAffectedGroups: [] + - minecraft:bane_of_arthropods + - minecraft:smite + - minecraft:sharpness + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 protection_enchant_conflict: enchantments: - - blast_protection - - fire_protection - - projectile_protection - - protection - notAffectedGroups: [] + - minecraft:blast_protection + - minecraft:fire_protection + - minecraft:projectile_protection + - minecraft:protection + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 trident_conflict1: enchantments: - - channeling - - riptide - notAffectedGroups: [] + - minecraft:channeling + - minecraft:riptide + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 trident_conflict2: enchantments: - - loyalty - - riptide - notAffectedGroups: [] + - minecraft:loyalty + - minecraft:riptide + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 boot_conflict: enchantments: - - depth_strider - - frost_walker - notAffectedGroups: [] + - minecraft:depth_strider + - minecraft:frost_walker + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 tool_conflict: enchantments: - - fortune - - silk_touch - notAffectedGroups: [] + - minecraft:fortune + - minecraft:silk_touch + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 bow_conflict: enchantments: - - mending - - infinity - notAffectedGroups: [] + - minecraft:mending + - minecraft:infinity + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 crossbow_conflict: enchantments: - - multishot - - piercing - notAffectedGroups: [] - maxEnchantmentBeforeConflict: 1 -restriction_density: - enchantments: - - density - notAffectedGroups: - - mace - - enchanted_book -restriction_breach: - enchantments: - - breach - notAffectedGroups: - - mace - - enchanted_book -restriction_wind_burst: - enchantments: - - wind_burst - notAffectedGroups: - - mace - - enchanted_book -mace_enchant_conflict: - enchantments: - - density - - breach - - smite - - bane_of_arthropods + - minecraft:multishot + - minecraft:piercing + notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 # ---------------------------------------------------- diff --git a/defaultconfigs/1.21/item_groups.yml b/defaultconfigs/1.21/item_groups.yml index 0add107..3c1eb5d 100644 --- a/defaultconfigs/1.21/item_groups.yml +++ b/defaultconfigs/1.21/item_groups.yml @@ -20,16 +20,16 @@ nothing: example_include: type: include items: - - stone - - polished_granite + - stone + - polished_granite # This group contain everything except polished granite and elements of example_include example_exclude: type: exclude items: - - polished_granite + - polished_granite groups: - - example_include + - example_include # Default configuration should be vanilla enchantment conflict group # there may have error, if you find one you can fix it ! @@ -38,176 +38,173 @@ example_exclude: swords: type: include items: - - wooden_sword - - stone_sword - - iron_sword - - diamond_sword - - golden_sword - - netherite_sword + - wooden_sword + - stone_sword + - iron_sword + - diamond_sword + - golden_sword + - netherite_sword axes: type: include items: - - wooden_axe - - stone_axe - - iron_axe - - diamond_axe - - golden_axe - - netherite_axe + - wooden_axe + - stone_axe + - iron_axe + - diamond_axe + - golden_axe + - netherite_axe melee_weapons: type: include groups: - - swords - - axes + - swords + - axes helmets: type: include items: - - leather_helmet - - chainmail_helmet - - iron_helmet - - diamond_helmet - - golden_helmet - - netherite_helmet - - turtle_helmet + - leather_helmet + - chainmail_helmet + - iron_helmet + - diamond_helmet + - golden_helmet + - netherite_helmet + - turtle_helmet chestplate: type: include items: - - leather_chestplate - - chainmail_chestplate - - iron_chestplate - - diamond_chestplate - - golden_chestplate - - netherite_chestplate + - leather_chestplate + - chainmail_chestplate + - iron_chestplate + - diamond_chestplate + - golden_chestplate + - netherite_chestplate leggings: type: include items: - - leather_leggings - - chainmail_leggings - - iron_leggings - - diamond_leggings - - golden_leggings - - netherite_leggings + - leather_leggings + - chainmail_leggings + - iron_leggings + - diamond_leggings + - golden_leggings + - netherite_leggings boots: type: include items: - - leather_boots - - chainmail_boots - - iron_boots - - diamond_boots - - golden_boots - - netherite_boots + - leather_boots + - chainmail_boots + - iron_boots + - diamond_boots + - golden_boots + - netherite_boots armors: type: include groups: - - helmets - - chestplate - - leggings - - boots + - helmets + - chestplate + - leggings + - boots wearable: type: include items: - - elytra - - carved_pumpkin - - skeleton_skull - - wither_skeleton_skull - - zombie_head - - player_head - - creeper_head - - dragon_head - - piglin_head + - elytra + - carved_pumpkin + - skeleton_skull + - wither_skeleton_skull + - zombie_head + - player_head + - creeper_head + - dragon_head + # do not exist in 1.18 but exist in future update + - piglin_head groups: - - armors + - armors tools: type: include items: - - wooden_pickaxe - - stone_pickaxe - - iron_pickaxe - - diamond_pickaxe - - golden_pickaxe - - netherite_pickaxe - - wooden_shovel - - stone_shovel - - iron_shovel - - diamond_shovel - - golden_shovel - - netherite_shovel - - wooden_hoe - - stone_hoe - - iron_hoe - - diamond_hoe - - golden_hoe - - netherite_hoe + - wooden_pickaxe + - stone_pickaxe + - iron_pickaxe + - diamond_pickaxe + - golden_pickaxe + - netherite_pickaxe + - wooden_shovel + - stone_shovel + - iron_shovel + - diamond_shovel + - golden_shovel + - netherite_shovel + - wooden_hoe + - stone_hoe + - iron_hoe + - diamond_hoe + - golden_hoe + - netherite_hoe groups: - - axes + - axes enchanted_book: type: include items: - - enchanted_book + - enchanted_book trident: type: include items: - - trident + - trident bow: type: include items: - - bow + - bow crossbow: type: include items: - - crossbow + - crossbow fishing_rod: type: include items: - - fishing_rod + - fishing_rod shears: type: include items: - - shears + - shears can_unbreak: type: include items: - - elytra - - flint_and_steel - - shield - - carrot_on_a_stick - - warped_fungus_on_a_stick - - brush + - elytra + - flint_and_steel + - shield + - carrot_on_a_stick + - warped_fungus_on_a_stick + # do not exist in 1.18 but exist in future update + - brush groups: - - melee_weapons - - tools - - armors - - trident - - bow - - crossbow - - fishing_rod - - shears - - mace + - melee_weapons + - tools + - armors + - trident + - bow + - crossbow + - fishing_rod + - shears can_vanish: type: include items: - - compass + - compass groups: - - wearable - - can_unbreak -mace: - type: include - items: - - mace + - wearable + - can_unbreak diff --git a/defaultconfigs/1.21/unit_repair_item.yml b/defaultconfigs/1.21/unit_repair_item.yml index ec548c6..2902cce 100644 --- a/defaultconfigs/1.21/unit_repair_item.yml +++ b/defaultconfigs/1.21/unit_repair_item.yml @@ -188,5 +188,3 @@ warped_planks: wooden_shovel: 0.25 wooden_hoe: 0.25 shield: 0.25 -breeze_rod: - mace: 0.25 diff --git a/libs/ExcellentEnchants-4.2.2.jar b/libs/ExcellentEnchants-4.2.2.jar new file mode 100644 index 0000000..23d9630 Binary files /dev/null and b/libs/ExcellentEnchants-4.2.2.jar differ diff --git a/libs/nightcore-2.6.4.jar b/libs/nightcore-2.6.4.jar new file mode 100644 index 0000000..0404681 Binary files /dev/null and b/libs/nightcore-2.6.4.jar differ diff --git a/nms/nms-common/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/ExternGuiTester.kt b/nms/nms-common/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/ExternGuiTester.kt new file mode 100644 index 0000000..3e11a43 --- /dev/null +++ b/nms/nms-common/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/ExternGuiTester.kt @@ -0,0 +1,24 @@ +package xyz.alexcrea.cuanvil.dependency.gui + +import org.bukkit.inventory.InventoryView + +interface ExternGuiTester { + + val wesjdAnvilGuiName: String? + + fun getContainerClass(inventory: InventoryView): Class? + + fun testIfGui(inventory: InventoryView): Boolean { + val clazz = getContainerClass(inventory) + if(clazz == null) return false + + val expectedWesjdGuiPath = "anvilgui.version.$wesjdAnvilGuiName" + + val clazzName = clazz.name + val isWejdsGui = clazzName.contains(expectedWesjdGuiPath) + + return isWejdsGui + } + + +} \ No newline at end of file diff --git a/nms/v1_17R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_17R1_ExternGuiTester.kt b/nms/v1_17R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_17R1_ExternGuiTester.kt new file mode 100644 index 0000000..8e352e0 --- /dev/null +++ b/nms/v1_17R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_17R1_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_17R1_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_17_R1" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} \ No newline at end of file diff --git a/nms/v1_18R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_18R1_ExternGuiTester.kt b/nms/v1_18R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_18R1_ExternGuiTester.kt new file mode 100644 index 0000000..659a0f6 --- /dev/null +++ b/nms/v1_18R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_18R1_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_18R1_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_18_R1" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} \ No newline at end of file diff --git a/nms/v1_18R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_18R2_ExternGuiTester.kt b/nms/v1_18R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_18R2_ExternGuiTester.kt new file mode 100644 index 0000000..1447716 --- /dev/null +++ b/nms/v1_18R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_18R2_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_18R2_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_18_R2" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} \ No newline at end of file diff --git a/nms/v1_19R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R1_ExternGuiTester.kt b/nms/v1_19R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R1_ExternGuiTester.kt new file mode 100644 index 0000000..c151924 --- /dev/null +++ b/nms/v1_19R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R1_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_19R1_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_19_R1" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} \ No newline at end of file diff --git a/nms/v1_19R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R2_ExternGuiTester.kt b/nms/v1_19R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R2_ExternGuiTester.kt new file mode 100644 index 0000000..ac46674 --- /dev/null +++ b/nms/v1_19R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R2_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_19R2_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_19_R2" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} \ No newline at end of file diff --git a/nms/v1_19R3/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R3_ExternGuiTester.kt b/nms/v1_19R3/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R3_ExternGuiTester.kt new file mode 100644 index 0000000..7ce5abd --- /dev/null +++ b/nms/v1_19R3/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_19R3_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_19R3_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_19_R3" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} \ No newline at end of file diff --git a/nms/v1_20R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R1_ExternGuiTester.kt b/nms/v1_20R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R1_ExternGuiTester.kt new file mode 100644 index 0000000..dae3b98 --- /dev/null +++ b/nms/v1_20R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R1_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_20R1_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_20_R1" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} diff --git a/nms/v1_20R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R2_ExternGuiTester.kt b/nms/v1_20R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R2_ExternGuiTester.kt new file mode 100644 index 0000000..6a8358a --- /dev/null +++ b/nms/v1_20R2/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R2_ExternGuiTester.kt @@ -0,0 +1,17 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester +import kotlin.jvm.javaClass + +class v1_20R2_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_20_R2" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} diff --git a/nms/v1_20R3/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R3_ExternGuiTester.kt b/nms/v1_20R3/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R3_ExternGuiTester.kt new file mode 100644 index 0000000..80362e2 --- /dev/null +++ b/nms/v1_20R3/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R3_ExternGuiTester.kt @@ -0,0 +1,17 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester +import kotlin.jvm.javaClass + +class v1_20R3_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_20_R3" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} diff --git a/nms/v1_20R4/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R4_ExternGuiTester.kt b/nms/v1_20R4/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R4_ExternGuiTester.kt new file mode 100644 index 0000000..16e867c --- /dev/null +++ b/nms/v1_20R4/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_20R4_ExternGuiTester.kt @@ -0,0 +1,17 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester +import kotlin.jvm.javaClass + +class v1_20R4_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_20_R4" + + override fun getContainerClass(view: InventoryView): Class? { + if (view !is CraftInventoryView) return null + val container = view.handle + + return container.javaClass + } +} diff --git a/nms/v1_21R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_21R1_ExternGuiTester.kt b/nms/v1_21R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_21R1_ExternGuiTester.kt new file mode 100644 index 0000000..9b73bc4 --- /dev/null +++ b/nms/v1_21R1/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/version/v1_21R1_ExternGuiTester.kt @@ -0,0 +1,16 @@ +package xyz.alexcrea.cuanvil.dependency.gui.version + +import org.bukkit.craftbukkit.inventory.CraftInventoryView +import org.bukkit.inventory.InventoryView +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester + +class v1_21R1_ExternGuiTester: ExternGuiTester { + override val wesjdAnvilGuiName = "Wrapper1_21_R1" + + override fun getContainerClass(view: InventoryView): Class? { + if(view !is CraftInventoryView<*>) return null + val container = view.handle + + return container.javaClass + } +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java index ad01827..8047382 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java +++ b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java @@ -119,7 +119,7 @@ public class ConflictAPI { private static List extractEnchantments(@NotNull ConflictBuilder builder){ List result = new ArrayList<>(builder.getEnchantmentNames()); for (NamespacedKey enchantmentKey : builder.getEnchantmentKeys()) { - result.add(enchantmentKey.getKey()); + result.add(enchantmentKey.toString()); } return result; diff --git a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java index 3e63b36..e3fd2d6 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java +++ b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java @@ -10,6 +10,7 @@ import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.group.*; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -372,7 +373,7 @@ public class ConflictBuilder { */ protected void appendEnchantments(@NotNull EnchantConflictGroup conflict){ for (String enchantmentName : getEnchantmentNames()){ - if(appendEnchantment(conflict, EnchantmentApi.getByName(enchantmentName))){ + if(appendEnchantments(conflict, EnchantmentApi.getListByName(enchantmentName)) == 0){ CustomAnvil.instance.getLogger().warning("Could not find enchantment " + enchantmentName + " for conflict " + getName()); ConflictAPI.logConflictOrigin(this); } @@ -399,6 +400,24 @@ public class ConflictBuilder { return true; } + /** + * Append a list of enchantments. + * + * @param conflict The conflict target + * @param enchantments List of enchantment to add + * @return Number of enchantment added + */ + protected static int appendEnchantments(@NotNull EnchantConflictGroup conflict, @NotNull List enchantments){ + int numberValid = 0; + for (CAEnchantment enchantment : enchantments) { + if(appendEnchantment(conflict, enchantment)){ + numberValid++; + } + } + + return numberValid; + } + /** * Extract group abstract material group. * diff --git a/src/main/java/xyz/alexcrea/cuanvil/api/EnchantmentApi.java b/src/main/java/xyz/alexcrea/cuanvil/api/EnchantmentApi.java index 01c5ed8..32a62c3 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/api/EnchantmentApi.java +++ b/src/main/java/xyz/alexcrea/cuanvil/api/EnchantmentApi.java @@ -18,6 +18,7 @@ import xyz.alexcrea.cuanvil.gui.config.global.EnchantCostConfigGui; import xyz.alexcrea.cuanvil.gui.config.global.EnchantLimitConfigGui; import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -104,7 +105,7 @@ public class EnchantmentApi { * @return True if successful. */ public static boolean unregisterEnchantment(@NotNull NamespacedKey key){ - CAEnchantment enchantment = CAEnchantmentRegistry.getInstance().getByKey(key); + CAEnchantment enchantment = CAEnchantment.getByKey(key); return unregisterEnchantment(enchantment); } @@ -126,7 +127,7 @@ public class EnchantmentApi { */ @Nullable public static CAEnchantment getByKey(@NotNull NamespacedKey key){ - return CAEnchantmentRegistry.getInstance().getByKey(key); + return CAEnchantment.getByKey(key); } /** @@ -134,10 +135,22 @@ public class EnchantmentApi { * * @param name The name used to fetch * @return The custom anvil enchantment of this name. null if not found. + * @deprecated use {@link #getListByName(String)} */ + @Deprecated(since = "1.6.3") @Nullable public static CAEnchantment getByName(@NotNull String name){ - return CAEnchantmentRegistry.getInstance().getByName(name); + return CAEnchantment.getByName(name); + } + + /** + * Get list of enchantment using the provided name. + * + * @param name The name used to fetch + * @return List of custom anvil enchantments of this name. May be empty if not found. + */ + public static List getListByName(@NotNull String name){ + return CAEnchantment.getListByName(name); } /** @@ -167,9 +180,9 @@ public class EnchantmentApi { private static void writeDefaultConfig(FileConfiguration defaultConfig, CAEnchantment enchantment) { - defaultConfig.set("enchant_limits." + enchantment.getKey().getKey(), enchantment.defaultMaxLevel()); + defaultConfig.set("enchant_limits." + enchantment.getKey(), enchantment.defaultMaxLevel()); - String basePath = "enchant_values." + enchantment.getKey().getKey(); + String basePath = "enchant_values." + enchantment.getKey(); EnchantmentRarity rarity = enchantment.defaultRarity(); defaultConfig.set(basePath + ".item", rarity.getItemValue()); diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantment.java index 0303733..1d94ba2 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantment.java @@ -12,6 +12,7 @@ import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -226,12 +227,24 @@ public interface CAEnchantment { } /** - * Gets a list of all the unoptimised enchantments. - * @param name The enchantment name - * @return List of enchantment. + * Gets the enchantment by the provided name. + * @param name Name to fetch. + * @return Registered enchantment. null if absent. + * + * @deprecated use {@link #getListByName(String)} */ + @Deprecated(since = "1.6.3") static @Nullable CAEnchantment getByName(@NotNull String name){ return CAEnchantmentRegistry.getInstance().getByName(name); } + /** + * Gets list of enchantment using the provided name. + * @param name Name to fetch. + * @return List of registered enchantment. + */ + static List getListByName(@NotNull String name){ + return CAEnchantmentRegistry.getInstance().getListByName(name); + } + } diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentRegistry.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentRegistry.java index 01262f9..1225209 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentRegistry.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentRegistry.java @@ -22,7 +22,7 @@ public class CAEnchantmentRegistry { // Register enchantment functions private final HashMap byKeyMap; - private final HashMap byNameMap; + private final HashMap> byNameMap; private final SortedSet nameSortedEnchantments; @@ -62,6 +62,8 @@ public class CAEnchantmentRegistry { } + private static boolean hasWarnedRegistering = false; + /** * Can be used to register new enchantment. *

@@ -73,19 +75,25 @@ public class CAEnchantmentRegistry { public boolean register(@NotNull CAEnchantment enchantment){ if(byKeyMap.containsKey(enchantment.getKey())){ CustomAnvil.instance.getLogger().log(Level.WARNING, - "Duplicate registered enchantment. This should NOT happen.", + "Duplicate registered enchantment. This should NOT happen any time.\n" + + "If you are a custom anvil developer. You maybe custom anvil detected your enchantment as a bukkit enchantment. " + + "maybe remove enchantment with the same key before registering yours", new IllegalStateException(enchantment.getKey()+" enchantment was already registered")); return false; } - if(byNameMap.containsKey(enchantment.getName())){ + + if((!hasWarnedRegistering) && byNameMap.containsKey(enchantment.getName())){ + hasWarnedRegistering = true; + CustomAnvil.instance.getLogger().log(Level.WARNING, - "Duplicate registered enchantment name. There will have issue. " + - "\nI hope this do not happen to you on a production server. If it do, there is probably a plugin trying to register an enchantment with the same name than another one", - new IllegalStateException(enchantment.getKey()+" enchantment name was already registered")); + "Duplicate registered enchantment name. Please check that configuration is using namespace."); } byKeyMap.put(enchantment.getKey(), enchantment); - byNameMap.put(enchantment.getName(), enchantment); + + byNameMap.putIfAbsent(enchantment.getName(), new ArrayList<>()); + byNameMap.get(enchantment.getName()).add(enchantment); + nameSortedEnchantments.add(enchantment); if(!enchantment.isGetOptimised()){ @@ -112,7 +120,7 @@ public class CAEnchantmentRegistry { public boolean unregister(@Nullable CAEnchantment enchantment){ if(enchantment == null) return false; byKeyMap.remove(enchantment.getKey()); - byNameMap.remove(enchantment.getName()); + byNameMap.get(enchantment.getName()).remove(enchantment); nameSortedEnchantments.remove(enchantment); @@ -135,10 +143,26 @@ public class CAEnchantmentRegistry { * Gets the enchantment by the provided name. * @param name Name to fetch. * @return Registered enchantment. null if absent. + * + * @deprecated use {@link #getListByName(String)} */ + @Deprecated(since = "1.6.3") @Nullable public CAEnchantment getByName(@NotNull String name){ - return byNameMap.get(name); + List enchantments = getListByName(name); + if(enchantments.isEmpty()) return null; + + return enchantments.get(0); + } + + /** + * Gets list of enchantment using the provided name. + * @param name Name to fetch. + * @return List of registered enchantment. + */ + @NotNull + public List getListByName(@NotNull String name){ + return byNameMap.getOrDefault(name, Collections.emptyList()); } /** diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEEEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEEEnchantment.java new file mode 100644 index 0000000..dfe60ff --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEEEnchantment.java @@ -0,0 +1,46 @@ +package xyz.alexcrea.cuanvil.enchant.wrapped; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment; +import su.nightexpress.excellentenchants.api.enchantment.Definition; +import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; +import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; + +import java.util.Map; +import java.util.Set; + +public class CAEEEnchantment extends CABukkitEnchantment implements AdditionalTestEnchantment { + + @NotNull CustomEnchantment eeenchantment; + @NotNull Definition definition; + + public CAEEEnchantment(@NotNull CustomEnchantment enchantment) { + super(enchantment.getBukkitEnchantment(), EnchantmentRarity.getRarity(enchantment.getDefinition().getAnvilCost())); + this.eeenchantment = enchantment; + this.definition = enchantment.getDefinition(); + + } + + @Override + public boolean isEnchantConflict(@NotNull Map enchantments, @NotNull Material itemMat) { + if(!definition.hasConflicts()) return false; + + Set conflicts = definition.getConflicts(); + + for (CAEnchantment caEnchantment : enchantments.keySet()) { + if(conflicts.contains(caEnchantment.getName())) return true; + } + + return false; + } + + @Override + public boolean isItemConflict(@NotNull Map enchantments, @NotNull Material itemMat, @NotNull ItemStack item) { + if(Material.ENCHANTED_BOOK.equals(itemMat)) return false; + + return !definition.getSupportedItems().is(item); + } +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/MainConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/MainConfigGui.java index 4f98cc3..e2224f7 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/MainConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/MainConfigGui.java @@ -30,7 +30,7 @@ public class MainConfigGui extends ChestGui { public void init(PacketManager packetManager) { Pattern pattern = new Pattern( GuiSharedConstant.EMPTY_GUI_FULL_LINE, - "012304567", + "012345678", "Q00000000" ); PatternPane pane = new PatternPane(0, 0, 9, 3, pattern); @@ -62,6 +62,18 @@ public class MainConfigGui extends ChestGui { GuiItem enchantLimitItem = GuiGlobalItems.goToGuiItem(enchantLimitItemstack, new EnchantLimitConfigGui()); pane.bindItem('2', enchantLimitItem); + // enchant level limit item + ItemStack enchantMergeLimitItemstack = new ItemStack(Material.ENCHANTED_BOOK); + ItemMeta enchantMergeLimitMeta = enchantMergeLimitItemstack.getItemMeta(); + assert enchantMergeLimitMeta != null; + + enchantMergeLimitMeta.setDisplayName("§aEnchantment Merge Limit"); + enchantMergeLimitMeta.setLore(Collections.singletonList("§7Click here to open enchantment merge limit menu")); + enchantMergeLimitItemstack.setItemMeta(enchantMergeLimitMeta); + + GuiItem enchantMergeLimitItem = GuiGlobalItems.goToGuiItem(enchantMergeLimitItemstack, new EnchantMergeLimitConfigGui()); + pane.bindItem('3', enchantMergeLimitItem); + // enchant cost item ItemStack enchantCostItemstack = new ItemStack(Material.EXPERIENCE_BOTTLE); ItemMeta enchantCostMeta = enchantCostItemstack.getItemMeta(); @@ -72,7 +84,7 @@ public class MainConfigGui extends ChestGui { enchantCostItemstack.setItemMeta(enchantCostMeta); GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, new EnchantCostConfigGui()); - pane.bindItem('3', enchantCostItem); + pane.bindItem('4', enchantCostItem); // Enchantment Conflicts item ItemStack enchantConflictItemstack = new ItemStack(Material.OAK_FENCE); @@ -84,7 +96,7 @@ public class MainConfigGui extends ChestGui { enchantConflictItemstack.setItemMeta(enchantConflictMeta); GuiItem enchantConflictItem = GuiGlobalItems.goToGuiItem(enchantConflictItemstack, EnchantConflictGui.getInstance()); - pane.bindItem('4', enchantConflictItem); + pane.bindItem('5', enchantConflictItem); // Group config items ItemStack groupItemstack = new ItemStack(Material.CHEST); @@ -97,7 +109,7 @@ public class MainConfigGui extends ChestGui { GuiItem groupConfigItem = GuiGlobalItems.goToGuiItem(groupItemstack, GroupConfigGui.getInstance()); - pane.bindItem('5', groupConfigItem); + pane.bindItem('6', groupConfigItem); // Unit repair item ItemStack unirRepairItemstack = new ItemStack(Material.DIAMOND); @@ -109,7 +121,7 @@ public class MainConfigGui extends ChestGui { unirRepairItemstack.setItemMeta(unitRepairMeta); GuiItem unitRepairItem = GuiGlobalItems.goToGuiItem(unirRepairItemstack, UnitRepairConfigGui.getInstance()); - pane.bindItem('6', unitRepairItem); + pane.bindItem('7', unitRepairItem); // Custom recipe item ItemStack customRecipeItemstack = new ItemStack(Material.CRAFTING_TABLE); @@ -121,7 +133,7 @@ public class MainConfigGui extends ChestGui { customRecipeItemstack.setItemMeta(customRecipeMeta); GuiItem customRecipeItem = GuiGlobalItems.goToGuiItem(customRecipeItemstack, CustomRecipeConfigGui.getInstance()); - pane.bindItem('7', customRecipeItem); + pane.bindItem('8', customRecipeItem); // quit item ItemStack quitItemstack = new ItemStack(Material.BARRIER); diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java index 6c44fac..a614536 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java @@ -44,24 +44,16 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui { + + private static final String SECTION_NAME = "disable-merge-over"; + + private static EnchantMergeLimitConfigGui INSTANCE = null; + + @Nullable + public static EnchantMergeLimitConfigGui getInstance() { + return INSTANCE; + } + + /** + * Constructor of this Global gui for enchantment level limit settings. + */ + public EnchantMergeLimitConfigGui() { + super("§8Enchantment Maximum Merge Level"); + if(INSTANCE == null) INSTANCE = this; + + init(); + } + + @Override + public IntSettingsGui.IntSettingFactory createFactory(CAEnchantment enchant) { + String key = enchant.getKey().toString().toLowerCase(Locale.ROOT); + String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key.replace(":", "_")); + + return new IntSettingsGui.IntSettingFactory(prettyKey + " Merge Limit", this, + SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG, + Arrays.asList( + "§7Maximum merge level for for " + prettyKey, + "", + "§7For example, if set to §e2§7, §alvl1 §7+ §alvl1 §7of will give a §alvl2", + "§7But §alvl2 §7+ §alvl2 §7will not give a §clv3§7.", + "§7Will still not merge above max enchantment level", + "§e-1 §7(default) will set the merge limit to enchantment's maximum level" + ), + -1, 255, -1, + 1, 5, 10, 50, 100){ + + @Override + public int getConfiguredValue() { + return ConfigOptions.INSTANCE.maxBeforeMergeDisabled(enchant); + } + }; + } + + @Override + public GuiItem itemFromFactory(CAEnchantment enchantment, IntSettingsGui.IntSettingFactory inventoryFactory) { + return inventoryFactory.getItem( + Material.ENCHANTED_BOOK, + inventoryFactory.getTitle()); + } +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java index 0c606e0..ccbcf63 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java @@ -258,7 +258,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl String[] enchantKeys = new String[enchantments.size()]; int index = 0; for (CAEnchantment enchantment : enchantments) { - enchantKeys[index++] = enchantment.getKey().getKey(); + enchantKeys[index++] = enchantment.getKey().toString(); } ConfigHolder.CONFLICT_HOLDER.getConfig().set(enchantConflict + ".enchantments", enchantKeys); diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantCostSettingsGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantCostSettingsGui.java index b0997cb..3bd923b 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantCostSettingsGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantCostSettingsGui.java @@ -5,6 +5,7 @@ import com.github.stefvanschie.inventoryframework.gui.type.util.Gui; import com.github.stefvanschie.inventoryframework.pane.PatternPane; import com.github.stefvanschie.inventoryframework.pane.util.Pattern; import io.delilaheve.CustomAnvil; +import io.delilaheve.util.ConfigOptions; import org.bukkit.Material; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemFlag; @@ -13,6 +14,7 @@ import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xyz.alexcrea.cuanvil.config.ConfigHolder; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; @@ -237,73 +239,45 @@ public class EnchantCostSettingsGui extends IntSettingsGui { return super.hadChange() || nowBook != beforeBook; } - /** - * Create an int setting factory from setting's parameters. - * - * @param title The title of the gui. - * @param parent Parent gui to go back when completed. - * @param config Configuration holder of this setting. - * @param configPath Configuration path of this setting. - * @param displayLore Gui display item lore. - * @param min Minimum value of this setting. - * @param max Maximum value of this setting. - * @param defaultItemVal Default item value if not found on the config. - * @param defaultBookVal Default book value if not found on the config. - * @param steps List of step the value can increment/decrement. - * List's size should be between 1 (included) and 3 (included). - * it is visually preferable to have an odd number of step. - * If step only contain 1 value, no step item should be displayed. - * @return A factory for an enchant cost setting gui. - */ - public static EnchantCostSettingFactory enchantCostFactory( - @NotNull String title, @NotNull ValueUpdatableGui parent, - @NotNull ConfigHolder config, @NotNull String configPath, - @Nullable List displayLore, - int min, int max, int defaultItemVal, int defaultBookVal, - int... steps) { - return new EnchantCostSettingFactory( - title, parent, - configPath, config, - displayLore, - min, max, defaultItemVal, defaultBookVal, steps); - } - /** * A factory for an enchantment cost setting gui that hold setting's information. */ public static class EnchantCostSettingFactory extends IntSettingsGui.IntSettingFactory { int defaultBookVal; + @NotNull CAEnchantment enchantment; /** * Constructor for an enchantment cost setting gui factory. * - * @param title The title of the gui. - * @param parent Parent gui to go back when completed. - * @param configPath Configuration path of this setting. - * @param config Configuration holder of this setting. - * @param displayLore Gui display item lore. - * @param min Minimum value of this setting. - * @param max Maximum value of this setting. - * @param defaultItemVal Default item value if not found on the config. - * @param defaultBookVal Default book value if not found on the config. - * @param steps List of step the value can increment/decrement. - * List's size should be between 1 (included) and 3 (included). - * it is visually preferable to have an odd number of step. - * If step only contain 1 value, no step item should be displayed. + * @param title The title of the gui. + * @param parent Parent gui to go back when completed. + * @param configPath Configuration path of this setting. + * @param config Configuration holder of this setting. + * @param displayLore Gui display item lore. + * @param min Minimum value of this setting. + * @param max Maximum value of this setting. + * @param enchantment Enchantment to change the cost to + * @param steps List of step the value can increment/decrement. + * List's size should be between 1 (included) and 3 (included). + * it is visually preferable to have an odd number of step. + * If step only contain 1 value, no step item should be displayed. */ - protected EnchantCostSettingFactory( + public EnchantCostSettingFactory( @NotNull String title, ValueUpdatableGui parent, @NotNull String configPath, @NotNull ConfigHolder config, @Nullable List displayLore, - int min, int max, int defaultItemVal, int defaultBookVal, - int... steps) { + @NotNull CAEnchantment enchantment, + int min, int max, int... steps) { super(title, parent, configPath, config, displayLore, - min, max, defaultItemVal, steps); - this.defaultBookVal = defaultBookVal; + min, max, enchantment.defaultRarity().getItemValue(), + steps); + + this.defaultBookVal = enchantment.defaultRarity().getBookValue(); + this.enchantment = enchantment; } /** @@ -311,14 +285,14 @@ public class EnchantCostSettingsGui extends IntSettingsGui { */ @Override public int getConfiguredValue() { - return this.config.getConfig().getInt(this.configPath + ITEM_PATH, this.defaultVal); + return ConfigOptions.INSTANCE.enchantmentValue(enchantment, false); } /** * @return The configured value for the enchant setting book value. */ public int getConfiguredBookValue() { - return this.config.getConfig().getInt(this.configPath + BOOK_PATH, this.defaultBookVal); + return ConfigOptions.INSTANCE.enchantmentValue(enchantment, true); } @Override diff --git a/src/main/java/xyz/alexcrea/cuanvil/update/Update_1_21.java b/src/main/java/xyz/alexcrea/cuanvil/update/Update_1_21.java index 3211497..af21989 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/update/Update_1_21.java +++ b/src/main/java/xyz/alexcrea/cuanvil/update/Update_1_21.java @@ -45,13 +45,13 @@ public class Update_1_21 { addToStringList(groupConfig, "can_unbreak.groups", "mace"); // Add new enchant conflicts - addToStringList(conflictConfig, "restriction_density.enchantments", "density"); + addToStringList(conflictConfig, "restriction_density.enchantments", "minecraft:density"); addToStringList(conflictConfig, "restriction_density.notAffectedGroups", "mace", "enchanted_book"); - addToStringList(conflictConfig, "restriction_breach.enchantments", "breach"); + addToStringList(conflictConfig, "restriction_breach.enchantments", "minecraft:breach"); addToStringList(conflictConfig, "restriction_breach.notAffectedGroups", "mace", "enchanted_book"); - addToStringList(conflictConfig, "restriction_wind_burst.enchantments", "wind_burst"); + addToStringList(conflictConfig, "restriction_wind_burst.enchantments", "minecraft:wind_burst"); addToStringList(conflictConfig, "restriction_wind_burst.notAffectedGroups", "mace", "enchanted_book"); // Add mace to conflicts @@ -59,13 +59,14 @@ public class Update_1_21 { addToStringList(conflictConfig, "restriction_smite.notAffectedGroups", "mace"); addToStringList(conflictConfig, "restriction_bane_of_arthropods.notAffectedGroups", "mace"); - addToStringList(conflictConfig, "mace_enchant_conflict.enchantments", "density", "breach", "smite", "bane_of_arthropods"); + addToStringList(conflictConfig, "mace_enchant_conflict.enchantments", + "minecraft:density", "minecraft:breach", "minecraft:smite", "minecraft:bane_of_arthropods"); conflictConfig.set("mace_enchant_conflict.maxEnchantmentBeforeConflict", 1); // Add level limit - baseConfig.set("enchant_limits.density", 5); - baseConfig.set("enchant_limits.breach", 4); - baseConfig.set("enchant_limits.wind_burst", 3); + baseConfig.set("enchant_limits.minecraft:density", 5); + baseConfig.set("enchant_limits.minecraft:breach", 4); + baseConfig.set("enchant_limits.minecraft:wind_burst", 3); // Add enchant values baseConfig.set("enchant_values.density.item", 1); diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt deleted file mode 100644 index e2f92e9..0000000 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ /dev/null @@ -1,580 +0,0 @@ -package io.delilaheve - -import io.delilaheve.util.ConfigOptions -import io.delilaheve.util.EnchantmentUtil.combineWith -import io.delilaheve.util.ItemUtil.canMergeWith -import io.delilaheve.util.ItemUtil.findEnchantments -import io.delilaheve.util.ItemUtil.isEnchantedBook -import io.delilaheve.util.ItemUtil.repairFrom -import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe -import io.delilaheve.util.ItemUtil.unitRepair -import org.bukkit.ChatColor -import org.bukkit.GameMode -import org.bukkit.Material -import org.bukkit.entity.HumanEntity -import org.bukkit.entity.Player -import org.bukkit.event.Event -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority.HIGHEST -import org.bukkit.event.Listener -import org.bukkit.event.inventory.ClickType -import org.bukkit.event.inventory.InventoryClickEvent -import org.bukkit.event.inventory.InventoryCloseEvent -import org.bukkit.event.inventory.PrepareAnvilEvent -import org.bukkit.inventory.AnvilInventory -import org.bukkit.inventory.InventoryView.Property.REPAIR_COST -import org.bukkit.inventory.ItemStack -import xyz.alexcrea.cuanvil.config.ConfigHolder -import xyz.alexcrea.cuanvil.dependency.DependencyManager -import xyz.alexcrea.cuanvil.dependency.packet.PacketManager -import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe -import xyz.alexcrea.cuanvil.util.AnvilXpUtil.calculatePenalty -import xyz.alexcrea.cuanvil.util.AnvilXpUtil.getRightValues -import xyz.alexcrea.cuanvil.util.AnvilXpUtil.setAnvilInvXp -import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair -import java.util.regex.Matcher -import java.util.regex.Pattern -import kotlin.math.min - - -/** - * Listener for anvil events - */ -class AnvilEventListener(private val packetManager: PacketManager) : Listener { - - companion object { - // Anvil's output slot - const val ANVIL_INPUT_LEFT = 0 - const val ANVIL_INPUT_RIGHT = 1 - const val ANVIL_OUTPUT_SLOT = 2 - - // static slot container - private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0) - private val CURSOR_SLOT = SlotContainer(SlotType.CURSOR, 0) - } - - /** - * Event handler logic for when an anvil contains items to be combined - */ - @EventHandler(priority = HIGHEST) - fun anvilCombineCheck(event: PrepareAnvilEvent) { - // Test if the event should bypass custom anvil. - if(DependencyManager.tryEventPreAnvilBypass(event)) return - - val inventory = event.inventory - val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return - val second = inventory.getItem(ANVIL_INPUT_RIGHT) - - // Should find player - val player = event.view.player - if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return - - // Test custom recipe - val recipe = getCustomRecipe(first, second) - CustomAnvil.verboseLog("custom recipe not null? ${recipe != null}") - if(recipe != null){ - val amount = getCustomRecipeAmount(recipe, first, second) - - val resultItem: ItemStack = recipe.resultItem!!.clone() - resultItem.amount *= amount - - event.result = resultItem - setAnvilInvXp(inventory, event.view, recipe.xpCostPerCraft * amount, true) - - return - } - - // Test rename lonely item - if (second == null) { - val resultItem = first.clone() - var anvilCost = handleRename(resultItem, inventory, player) - - // Test/stop if nothing changed. - if (first == resultItem) { - CustomAnvil.log("no right item, But input is same as output") - event.result = null - return - } - - event.result = resultItem - - anvilCost += calculatePenalty(first, null, resultItem) - - setAnvilInvXp(inventory, event.view, anvilCost) - return - } - - // Test for merge - if (first.canMergeWith(second)) { - val newEnchants = first.findEnchantments() - .combineWith(second.findEnchantments(), first, player) - val resultItem = first.clone() - resultItem.setEnchantmentsUnsafe(newEnchants) - - // Calculate enchantment cost - var anvilCost = getRightValues(second, resultItem) - // Calculate repair cost - if (!first.isEnchantedBook() && !second.isEnchantedBook()) { - // we only need to be concerned with repair when neither item is a book - val repaired = resultItem.repairFrom(first, second) - anvilCost += if (repaired) ConfigOptions.itemRepairCost else 0 - } - - // Test/stop if nothing changed. - if (first == resultItem) { - CustomAnvil.log("Mergable with second, But input is same as output") - event.result = null - return - } - // As calculatePenalty edit result, we need to calculate penalty after checking equality - anvilCost += calculatePenalty(first, second, resultItem) - // Calculate rename cost - anvilCost += handleRename(resultItem, inventory, player) - - // Finally, we set result - event.result = resultItem - - setAnvilInvXp(inventory, event.view, anvilCost) - return - } - - // Test for unit repair - val unitRepairAmount = first.getRepair(second) - if (unitRepairAmount != null) { - val resultItem = first.clone() - var anvilCost = handleRename(resultItem, inventory, player) - - val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount) - if (repairAmount > 0) { - anvilCost += repairAmount * ConfigOptions.unitRepairCost - } - // We do not care about right item penalty for unit repair - anvilCost += calculatePenalty(first, null, resultItem, true) - - // Test/stop if nothing changed. - if (first == resultItem) { - CustomAnvil.log("unit repair, But input is same as output") - event.result = null - return - } - event.result = resultItem - - setAnvilInvXp(inventory, event.view, anvilCost) - } else { - CustomAnvil.log("no anvil fuse type found") - event.result = null - } - - } - - private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int { - // Rename item and add renaming cost - resultItem.itemMeta?.let { - val displayName = ChatColor.stripColor(it.displayName) - var inventoryName = ChatColor.stripColor(inventory.renameText) - - var sumCost = 0 - - var useColor = false - if(ConfigOptions.renameColorPossible){ - val resultString = StringBuilder(inventoryName) - - useColor = handleRenamingColor(resultString, player) - - if(useColor) { - inventoryName = resultString.toString() - - sumCost+= ConfigOptions.useOfColorCost - } - } - - if ((!useColor && (!displayName.contentEquals(inventoryName))) || (useColor && !(it.displayName).contentEquals(inventoryName))) { - it.setDisplayName(inventoryName) - resultItem.itemMeta = it - - sumCost+= ConfigOptions.itemRenameCost - } - - return sumCost - } - return 0 - } - - private fun handleRenamingColor(textToColor: StringBuilder, player: HumanEntity): Boolean { - val usePermission = ConfigOptions.permissionNeededForColor - val canUseColorCode = ConfigOptions.allowColorCode && (!usePermission || player.hasPermission("ca.color.code")) - val canUseHexColor = ConfigOptions.allowHexadecimalColor && (!usePermission || player.hasPermission("ca.color.hex")) - - if((!canUseColorCode) && (!canUseHexColor)) return false - - var useColor = false - // Handle color code - if(canUseColorCode){ - var nbReplacement = replaceAll(textToColor, "&", "§", 2) - nbReplacement -= 2 * replaceAll(textToColor, "§§", "&", 2) - - if(nbReplacement > 0) useColor = true - } - - if(canUseHexColor){ - val nbReplacement = replaceHexToColor(textToColor, 7) - - if(nbReplacement > 0) useColor = true - } - - return useColor - } - - /** - * Replace every instance of "from" to "to". - * @param builder The builder to replace the string from. - * @param from The source that should be replaced. - * @param to The string that should replace. - * @param endOffset Amount of character that should be ignored at the end. - * @return The number of replacement was that was done. - */ - private fun replaceAll(builder: java.lang.StringBuilder, from: String, to: String, endOffset: Int): Int { - var index = builder.indexOf(from) - var numberOfChanges = 0 - - while (index != -1 && index < builder.length - endOffset) { - builder.replace(index, index + from.length, to) - index += to.length - index = builder.indexOf(from, index) - - numberOfChanges+=1 - } - - return numberOfChanges - } - - val HEX_PATTERN: Pattern = Pattern.compile("#[A-Fa-f0-9]{6}") // pattern to find hexadecimal string - /** - * Replace every hex color formatted like #000000 to the minecraft format - * @param builder The builder to replace the hex color from. - * @param endOffset Amount of character that should be ignored at the end. - * @return The number of replacement was that was done. - */ - private fun replaceHexToColor(builder: StringBuilder, endOffset: Int): Int { - val matcher: Matcher = HEX_PATTERN.matcher(builder) - - var numberOfChanges = 0 - var startIndex = 0 - - while(matcher.find(startIndex)){ - startIndex = matcher.start() - if(startIndex >= builder.length - endOffset) break - - builder.replace(startIndex, startIndex + 1, "§x") - startIndex+=2 - for (i in 0..5) { - builder.insert(startIndex, '§') - startIndex+=2 - } - - numberOfChanges+=1 - } - - return numberOfChanges - } - - /** - * Event handler logic for when a player is trying to pull an item out of the anvil - */ - @EventHandler(ignoreCancelled = true) - fun anvilExtractionCheck(event: InventoryClickEvent) { - val player = event.whoClicked as? Player ?: return - if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return - val inventory = event.inventory as? AnvilInventory ?: return - - if (event.rawSlot != ANVIL_OUTPUT_SLOT) { - return - } - // Test if the event should bypass custom anvil. - if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return - - val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return - val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return - val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) - - // Test custom recipe - val recipe = getCustomRecipe(leftItem, rightItem) - if(recipe != null){ - event.result = Event.Result.ALLOW - onCustomCraft( - event, recipe, player, - leftItem, rightItem, output, inventory) - return - } - - val canMerge = leftItem.canMergeWith(rightItem) - val unitRepairResult = leftItem.getRepair(rightItem) - val allowed = (rightItem == null) - || (canMerge) - || (unitRepairResult != null) - - // True if there was no change or not allowed - if ((output == inventory.getItem(ANVIL_INPUT_LEFT)) - || !allowed - ) { - event.result = Event.Result.DENY - return - } - if (rightItem == null) { - event.result = Event.Result.ALLOW - return - } - if (canMerge) { - event.result = Event.Result.ALLOW - } else if (unitRepairResult != null) { - onUnitRepairExtract( - leftItem, rightItem, output, - unitRepairResult, event, player, inventory - ) - - return - } - } - - private fun onCustomCraft(event: InventoryClickEvent, - recipe: AnvilCustomRecipe, - player: Player, - leftItem: ItemStack, - rightItem: ItemStack?, - output: ItemStack, - inventory: AnvilInventory) { - event.result = Event.Result.DENY - - if(recipe.leftItem == null) return // in case it changed - - val amount = getCustomRecipeAmount(recipe, leftItem, rightItem) - val xpCost = amount * recipe.xpCostPerCraft - - if ((player.gameMode != GameMode.CREATIVE) && (player.level < xpCost)) return - - // We give the item manually - // But first we check if we should give the item - val slotDestination = getActionSlot(event, player) - if (slotDestination.type == SlotType.NO_SLOT) return - - // If not creative middle click... - if (event.click != ClickType.MIDDLE) { - // We remove what should be removed - leftItem.amount -= amount * recipe.leftItem!!.amount - inventory.setItem(ANVIL_INPUT_LEFT, leftItem) - - if(rightItem != null){ - if(recipe.rightItem == null) return // in case it changed - - rightItem.amount -= amount * recipe.rightItem!!.amount - inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) - } - - if(player.gameMode != GameMode.CREATIVE){ - player.level -= xpCost - } - - // Then we try to find the new values for the anvil - val newAmount = getCustomRecipeAmount(recipe, leftItem, rightItem) - - CustomAnvil.verboseLog("new amount is $newAmount") - if(newAmount <= 0 || recipe.exactCount){ - inventory.setItem(ANVIL_OUTPUT_SLOT, null) - }else{ - val resultItem: ItemStack = recipe.resultItem!!.clone() - resultItem.amount *= newAmount - - val newXp = newAmount * newAmount - - inventory.repairCost = newXp - event.view.setProperty(REPAIR_COST, newXp) - - inventory.setItem(ANVIL_OUTPUT_SLOT, resultItem) - - player.updateInventory() - } - } - - // Finally, we add the item to the player - if (slotDestination.type == SlotType.CURSOR) { - player.setItemOnCursor(output) - } else {// We assume SlotType == SlotType.INVENTORY - player.inventory.setItem(slotDestination.slot, output) - } - - - } - - private fun onUnitRepairExtract( - leftItem: ItemStack, - rightItem: ItemStack, - output: ItemStack, - unitRepairResult: Double, - event: InventoryClickEvent, - player: Player, - inventory: AnvilInventory - ) { - val resultCopy = leftItem.clone() - val resultAmount = resultCopy.unitRepair( - rightItem.amount, unitRepairResult - ) - - // To avoid vanilla, we cancel the event for unit repair - event.result = Event.Result.DENY - event.isCancelled = true - // And we give the item manually - // But first we check if we should give the item - val slotDestination = getActionSlot(event, player) - if (slotDestination.type == SlotType.NO_SLOT) return - - // Test repair cost - var repairCost = 0 - if (player.gameMode != GameMode.CREATIVE) { - // Get repairCost - leftItem.itemMeta?.let { leftMeta -> - val leftName = leftMeta.displayName - output.itemMeta?.let { - // Rename cost - if (!leftName.contentEquals(it.displayName)) { - repairCost += ConfigOptions.itemRenameCost - - // Color cost - if(it.displayName.contains('§')){ - repairCost += ConfigOptions.useOfColorCost - } - } - } - } - - repairCost += calculatePenalty(leftItem, null, resultCopy) - repairCost += resultAmount * ConfigOptions.unitRepairCost - - if ( - !ConfigOptions.doRemoveCostLimit && - ConfigOptions.doCapCost) { - - repairCost = min(repairCost, ConfigOptions.maxAnvilCost) - } - - if ((inventory.maximumRepairCost <= repairCost) - || (player.level < repairCost) - ) return - } - // If not creative middle click... - if (event.click != ClickType.MIDDLE) { - // We remove what should be removed - inventory.setItem(ANVIL_INPUT_LEFT, null) - rightItem.amount -= resultAmount - inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) - inventory.setItem(ANVIL_OUTPUT_SLOT, null) - player.level -= repairCost - } - - // Finally, we add the item to the player - if (slotDestination.type == SlotType.CURSOR) { - player.setItemOnCursor(output) - } else {// We assume SlotType == SlotType.INVENTORY - player.inventory.setItem(slotDestination.slot, output) - } - } - - /** - * Get the destination slot or "NO_SLOT" slot container if there is no slot available - */ - private fun getActionSlot(event: InventoryClickEvent, player: Player): SlotContainer { - if (event.isShiftClick) { - val inventory = player.inventory - val firstEmpty = inventory.firstEmpty() - if (firstEmpty == -1) { - return NO_SLOT - } - //check hotbare full - var slotIndex = 8 - while (slotIndex >= 0 && ((inventory.getItem(slotIndex)?.type ?: Material.AIR) != Material.AIR)) { - slotIndex-- - } - if (slotIndex >= 0) { - return SlotContainer(SlotType.INVENTORY, slotIndex) - } - slotIndex = 35 //4*9 - 1 (max of player inventory) - while (slotIndex >= 9 && ((inventory.getItem(slotIndex)?.type ?: Material.AIR) != Material.AIR)) { - slotIndex-- - } - if (slotIndex < 9) { - return NO_SLOT - } - return SlotContainer(SlotType.INVENTORY, slotIndex) - } else { - if (player.itemOnCursor.type != Material.AIR) { - return NO_SLOT - } - return CURSOR_SLOT - } - } - - private fun getCustomRecipe ( - leftItem: ItemStack, - rightItem: ItemStack?) : AnvilCustomRecipe? { - - val recipeList = ConfigHolder.CUSTOM_RECIPE_HOLDER.recipeManager.recipeByMat[leftItem.type] ?: return null - - CustomAnvil.verboseLog("Testing " + recipeList.size+" recipe...") - for (recipe in recipeList) { - if(recipe.testItem(leftItem, rightItem)){ - return recipe - } - } - - return null - } - - private fun getCustomRecipeAmount( - recipe: AnvilCustomRecipe, - leftItem: ItemStack, - rightItem: ItemStack? - ): Int{ - return if(recipe.exactCount) { - if(leftItem.amount != recipe.leftItem!!.amount){ - 0 - }else if(rightItem != null && rightItem.amount != recipe.rightItem!!.amount){ - 0 - }else{ - 1 - } - } - else { - // test amount - val resultItem = recipe.resultItem!! // we know exist as the recipe was returned to us - val maxResultAmount = resultItem.type.maxStackSize/resultItem.amount - val maxLeftAmount = leftItem.amount/recipe.leftItem!!.amount - val maxRightAmount = if(rightItem == null){ maxLeftAmount } else{ rightItem.amount/recipe.rightItem!!.amount } - - CustomAnvil.verboseLog("resultItem: $resultItem, maxResultAmount: $maxResultAmount, maxLeftAmount: $maxLeftAmount, maxRightAmount: $maxRightAmount") - - min(min(maxResultAmount, maxLeftAmount), maxRightAmount) - } - } - - - @EventHandler - fun onAnvilClose(event: InventoryCloseEvent){ - val player = event.player - if(event.inventory !is AnvilInventory) return - if(player is Player && GameMode.CREATIVE != player.gameMode){ - packetManager.setInstantBuild(player, false) - } - - } - -} - - - - -private class SlotContainer(val type: SlotType, val slot: Int) -private enum class SlotType { - CURSOR, - INVENTORY, - NO_SLOT - -} diff --git a/src/main/kotlin/io/delilaheve/CustomAnvil.kt b/src/main/kotlin/io/delilaheve/CustomAnvil.kt index cbeb5cd..285e1c5 100644 --- a/src/main/kotlin/io/delilaheve/CustomAnvil.kt +++ b/src/main/kotlin/io/delilaheve/CustomAnvil.kt @@ -13,7 +13,10 @@ import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry import xyz.alexcrea.cuanvil.gui.config.MainConfigGui import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant +import xyz.alexcrea.cuanvil.listener.AnvilCloseListener +import xyz.alexcrea.cuanvil.listener.AnvilResultListener import xyz.alexcrea.cuanvil.listener.ChatEventListener +import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener import xyz.alexcrea.cuanvil.update.PluginSetDefault import xyz.alexcrea.cuanvil.update.Update_1_21 import xyz.alexcrea.cuanvil.update.plugin.PluginUpdates @@ -110,7 +113,9 @@ class CustomAnvil : JavaPlugin() { DependencyManager.loadDependency() // Register anvil events - server.pluginManager.registerEvents(AnvilEventListener(DependencyManager.packetManager), this) + server.pluginManager.registerEvents(PrepareAnvilListener(), this) + server.pluginManager.registerEvents(AnvilResultListener(), this) + server.pluginManager.registerEvents(AnvilCloseListener(DependencyManager.packetManager), this) // Load metrics Metrics(this, bstatsPluginId) diff --git a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt index 37fdf5a..f192ff9 100644 --- a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt +++ b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt @@ -41,6 +41,8 @@ object ConfigOptions { const val ENCHANT_LIMIT_ROOT = "enchant_limits" const val ENCHANT_VALUES_ROOT = "enchant_values" + const val DISABLE_MERGE_OVER_ROOT = "disable-merge-over" + // Keys for specific enchantment values private const val KEY_BOOK = "book" private const val KEY_ITEM = "item" @@ -110,6 +112,9 @@ object ConfigOptions { // Default value for an enchantment multiplier private const val DEFAULT_ENCHANT_VALUE = 0 + // Default max before merge disabled (negative mean enabled) + const val DEFAULT_MAX_BEFORE_MERGE_DISABLED = -1; + // ------------- // Get methods // ------------- @@ -296,21 +301,28 @@ object ConfigOptions { * Get the given [enchantment]'s limit */ fun enchantLimit(enchantment: CAEnchantment): Int { - return enchantLimit(enchantment.enchantmentName) + // Test namespace + var limit = enchantLimit(enchantment.key.toString()) + if(limit != null) return limit; + + // Test legacy (name only) + limit = enchantLimit(enchantment.enchantmentName) + if(limit != null) return limit; + + // get default (and test old legacy if present) + return getDefaultLevel(enchantment.enchantmentName) } /** * Get the given [enchantmentName]'s limit */ - private fun enchantLimit(enchantmentName: String): Int { - val default = getDefaultLevel(enchantmentName) + private fun enchantLimit(enchantmentName: String): Int? { val path = "${ENCHANT_LIMIT_ROOT}.$enchantmentName" return CustomAnvil.instance .config - .getInt(path, default) + .getInt(path, ENCHANT_LIMIT_RANGE.first-1) .takeIf { it in ENCHANT_LIMIT_RANGE } - ?: default } /** @@ -319,7 +331,9 @@ object ConfigOptions { private fun getDefaultLevel(enchantmentName: String, // compatibility with 1.20.5. TODO better update system ) : Int { if(enchantmentName == "sweeping_edge"){ - return enchantLimit("sweeping") + val limit = enchantLimit("sweeping") + if(limit != null) return limit + } return defaultEnchantLimit } @@ -332,7 +346,17 @@ object ConfigOptions { enchantment: CAEnchantment, isFromBook: Boolean ): Int { - return enchantmentValue(enchantment.enchantmentName, isFromBook) + // Test namespace + var limit = enchantmentValue(enchantment.key.toString(), isFromBook) + if(limit != null) return limit; + + // Test legacy (name only) + limit = enchantmentValue(enchantment.enchantmentName, isFromBook) + if(limit != null) return limit; + + // get default (and test old legacy if present) + return getDefaultValue(enchantment, isFromBook) + } /** @@ -342,36 +366,76 @@ object ConfigOptions { private fun enchantmentValue( enchantmentName: String, isFromBook: Boolean - ): Int { - val default = getDefaultValue(enchantmentName, isFromBook) - + ): Int? { val typeKey = if (isFromBook) KEY_BOOK else KEY_ITEM val path = "${ENCHANT_VALUES_ROOT}.${enchantmentName}.$typeKey" return CustomAnvil.instance .config - .getInt(path, default) + .getInt(path, DEFAULT_ENCHANT_VALUE - 1) .takeIf { it >= DEFAULT_ENCHANT_VALUE } - ?: DEFAULT_ENCHANT_VALUE } /** * Get default value if enchantment do not exist on config */ - private fun getDefaultValue(enchantmentName: String, // compatibility with 1.20.5. TODO better update system + private fun getDefaultValue(enchantment: CAEnchantment, // compatibility with 1.20.5. TODO better update system isFromBook: Boolean) : Int { - if(enchantmentName == "sweeping_edge"){ - return enchantmentValue("sweeping", isFromBook) + + val enchantmentName = enchantment.key.toString() + if(enchantmentName == "minecraft:sweeping_edge"){ + var limit = enchantmentValue("minecraft:sweeping", isFromBook) + if(limit != null) return limit + + // legacy name + limit = enchantmentValue("sweeping", isFromBook) + if(limit != null) return limit } - val enchantment = CAEnchantment.getByName(enchantmentName) - if(enchantment != null){ - val rarity = enchantment.defaultRarity() + val rarity = enchantment.defaultRarity() + return if(isFromBook) + rarity.bookValue + else + rarity.itemValue + } - return if(isFromBook) rarity.bookValue - else rarity.itemValue + /** + * Get the given [enchantmentName]'s level before merge is disabled + * a negative value would mean never disabled + */ + fun maxBeforeMergeDisabled(enchantment: CAEnchantment): Int { + val key = enchantment.key.toString() + var value = maxBeforeMergeDisabled(key) + if(value != null) return value + + // Legacy name + val legacy = enchantment.enchantmentName + value = maxBeforeMergeDisabled(legacy) + if(value != null) return value + + if(key == "minecraft:sweeping_edge"){ + value = maxBeforeMergeDisabled("minecraft:sweeping") + if(value != null) return value + + // legacy name of legacy enchantment name + value = maxBeforeMergeDisabled("sweeping") + if(value != null) return value } - return DEFAULT_ENCHANT_VALUE + return DEFAULT_MAX_BEFORE_MERGE_DISABLED + } + + /** + * Get the given [enchantmentName]'s level before merge is disabled + * a negative value would mean never disabled + */ + private fun maxBeforeMergeDisabled(enchantmentName: String) : Int? { + // find if set + val path = "${DISABLE_MERGE_OVER_ROOT}.$enchantmentName" + + return CustomAnvil.instance + .config + .getInt(path, ENCHANT_LIMIT_RANGE.min() - 1) + .takeIf { it in ENCHANT_LIMIT_RANGE } } } diff --git a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt index 95bdd36..2cde74c 100644 --- a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt +++ b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt @@ -76,7 +76,11 @@ object EnchantmentUtil { } // ... and they're the same level else { - // try to increase the enchantment level by 1 + // We test if it is allowed to merge at this level + val maxBeforeDisabled = ConfigOptions.maxBeforeMergeDisabled(enchantment) + if((maxBeforeDisabled > 0) && (oldLevel >= maxBeforeDisabled)) return@forEach + + // Now we increase the enchantment level by 1 var newLevel = oldLevel + 1 newLevel = max(min(newLevel, maxLevel), oldLevel) this[enchantment] = newLevel diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt index f122068..694f314 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt @@ -6,6 +6,8 @@ import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.inventory.AnvilInventory import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester +import xyz.alexcrea.cuanvil.dependency.gui.GuiTesterSelector import xyz.alexcrea.cuanvil.dependency.packet.PacketManager import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector import xyz.alexcrea.cuanvil.dependency.scheduler.BukkitScheduler @@ -17,8 +19,12 @@ object DependencyManager { var isFolia: Boolean = false lateinit var scheduler: TaskScheduler lateinit var packetManager: PacketManager + var externGuiTester: ExternGuiTester? = null + var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null var ecoEnchantCompatibility: EcoEnchantDependency? = null + var excellentEnchantsCompatibility: ExcellentEnchantsDependency? = null + var disenchantmentCompatibility: DisenchantmentDependency? = null fun loadDependency(){ @@ -35,6 +41,7 @@ object DependencyManager { // Packet Manager val forceProtocolib = ConfigHolder.DEFAULT_CONFIG.config.getBoolean("force_protocolib", false) packetManager = PacketManagerSelector.selectPacketManager(forceProtocolib) + externGuiTester = GuiTesterSelector.selectGuiTester // Enchantment Squared dependency if(pluginManager.isPluginEnabled("EnchantsSquared")){ @@ -48,6 +55,12 @@ object DependencyManager { ecoEnchantCompatibility!!.disableAnvilListener() } + // Excellent Enchants dependency + if(pluginManager.isPluginEnabled("ExcellentEnchants")){ + excellentEnchantsCompatibility = ExcellentEnchantsDependency() + excellentEnchantsCompatibility!!.redirectListeners() + } + // Disenchantment dependency if(pluginManager.isPluginEnabled("Disenchantment")){ disenchantmentCompatibility = DisenchantmentDependency() @@ -64,6 +77,7 @@ object DependencyManager { fun registerEnchantments() { enchantmentSquaredCompatibility?.registerEnchantments() ecoEnchantCompatibility?.registerEnchantments() + excellentEnchantsCompatibility?.registerEnchantments() } @@ -79,16 +93,30 @@ object DependencyManager { fun tryEventPreAnvilBypass(event: PrepareAnvilEvent): Boolean { var bypass = false + // Test if disenchantment used special prepare anvil if(disenchantmentCompatibility?.testPrepareAnvil(event) == true) bypass = true + // Test excellent enchantments used special prepare anvil + if(!bypass && (excellentEnchantsCompatibility?.testPrepareAnvil(event) == true)) bypass = true + + // Test if the inventory is a gui(version specific) + if(!bypass && (externGuiTester?.testIfGui(event.view) == true)) bypass = true + return bypass } fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { var bypass = false + // Test if disenchantment used special event click if(disenchantmentCompatibility?.testAnvilResult(event, inventory) == true) bypass = true + // Test if disenchantment used special event click + if(!bypass && (excellentEnchantsCompatibility?.testAnvilResult(event) == true)) bypass = true + + // Test if the inventory is a gui(version specific) + if(!bypass && (externGuiTester?.testIfGui(event.view) == true)) bypass = true + return bypass } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt index be27c05..439dbb4 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt @@ -4,13 +4,13 @@ import cz.kominekjan.disenchantment.events.DisenchantClickEvent import cz.kominekjan.disenchantment.events.DisenchantEvent import cz.kominekjan.disenchantment.events.ShatterClickEvent import cz.kominekjan.disenchantment.events.ShatterEvent -import io.delilaheve.AnvilEventListener import io.delilaheve.CustomAnvil import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.ItemStack import org.bukkit.plugin.RegisteredListener +import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener import xyz.alexcrea.cuanvil.util.AnvilXpUtil class DisenchantmentDependency { @@ -26,7 +26,6 @@ class DisenchantmentDependency { private lateinit var itemClickEvent: DisenchantClickEvent fun redirectListeners() { - val toUnregister = ArrayList() // get required PrepareAnvilEvent listener for (registeredListener in PrepareAnvilEvent.getHandlerList().registeredListeners) { @@ -96,7 +95,7 @@ class DisenchantmentDependency { } fun testAnvilResult(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { - val previousResultSlot = inventory.getItem(AnvilEventListener.ANVIL_OUTPUT_SLOT)?.clone() + val previousResultSlot = inventory.getItem(PrepareAnvilListener.ANVIL_OUTPUT_SLOT)?.clone() // Test event if change the result itemClickEvent.onDisenchantmentClickEvent(event) @@ -115,7 +114,7 @@ class DisenchantmentDependency { } private fun testAnvilInventoryChange(inventory: AnvilInventory, previous: ItemStack?): Boolean { - val currentResult = inventory.getItem(AnvilEventListener.ANVIL_OUTPUT_SLOT) + val currentResult = inventory.getItem(PrepareAnvilListener.ANVIL_OUTPUT_SLOT) return currentResult == previous } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/ExcellentEnchantsDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/ExcellentEnchantsDependency.kt new file mode 100644 index 0000000..437cd75 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/ExcellentEnchantsDependency.kt @@ -0,0 +1,107 @@ +package xyz.alexcrea.cuanvil.dependency + +import io.delilaheve.CustomAnvil +import org.bukkit.Material +import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.event.inventory.PrepareAnvilEvent +import org.bukkit.inventory.ItemStack +import org.bukkit.plugin.RegisteredListener +import su.nightexpress.excellentenchants.enchantment.impl.universal.CurseOfFragilityEnchant +import su.nightexpress.excellentenchants.enchantment.listener.AnvilListener +import su.nightexpress.excellentenchants.registry.EnchantRegistry +import xyz.alexcrea.cuanvil.api.EnchantmentApi +import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEEnchantment +import java.lang.reflect.Method + +class ExcellentEnchantsDependency { + + init { + CustomAnvil.instance.logger.info("Excellent Enchants Detected !") + } + + fun registerEnchantments() { + CustomAnvil.instance.logger.info("Preparing Excellent Enchants compatibility...") + + for (enchantment in EnchantRegistry.getRegistered()) { + EnchantmentApi.unregisterEnchantment(enchantment.bukkitEnchantment.key) // As excellent enchants is loaded before custom anvil and register enchantment to registry, we need to unregister old "vanilla" enchant. + EnchantmentApi.registerEnchantment(CAEEEnchantment(enchantment)) + } + + CustomAnvil.instance.logger.info("Excellent Enchants should now work as expected !") + } + + private lateinit var fragilityCurse: CurseOfFragilityEnchant + + private lateinit var anvilListener: AnvilListener + private lateinit var handleRechargeMethod: Method + private lateinit var handleCombineMethod: Method + + fun redirectListeners() { + val toUnregister = ArrayList() + // get required PrepareAnvilEvent listener + for (registeredListener in PrepareAnvilEvent.getHandlerList().registeredListeners) { + val listener = registeredListener.listener + + if(listener is CurseOfFragilityEnchant){ + this.fragilityCurse = listener + toUnregister.add(registeredListener) + } + + if(listener is AnvilListener){ + this.anvilListener = listener; + toUnregister.add(registeredListener) + } + + } + + for (listener in toUnregister) { + PrepareAnvilEvent.getHandlerList().unregister(listener) + + } + + // Unregister inventory click event + InventoryClickEvent.getHandlerList().unregister(this.anvilListener) + + findAnvilFunctions() + } + + private fun findAnvilFunctions() { + this.handleRechargeMethod = AnvilListener::class.java.getDeclaredMethod("handleRecharge", + PrepareAnvilEvent::class.java, ItemStack::class.java, ItemStack::class.java) + this.handleRechargeMethod.setAccessible(true) + + this.handleCombineMethod = AnvilListener::class.java.getDeclaredMethod("handleCombine", + PrepareAnvilEvent::class.java, ItemStack::class.java, ItemStack::class.java, ItemStack::class.java) + this.handleCombineMethod.setAccessible(true) + + } + + fun testPrepareAnvil(event: PrepareAnvilEvent): Boolean { + if(event.result != null){ + this.fragilityCurse.onItemAnvil(event) + if(event.result == null) return true + } + + var first: ItemStack? = event.inventory.getItem(0) + var second: ItemStack? = event.inventory.getItem(1) + var result = event.result + + if (first == null) first = ItemStack(Material.AIR) + if (second == null) second = ItemStack(Material.AIR) + if (result == null) result = ItemStack(Material.AIR) + + if(handleRechargeMethod.invoke(this.anvilListener, event, first, second) as Boolean) return true + return handleCombineMethod.invoke(this.anvilListener, event, first, second, result) as Boolean + } + + fun testAnvilResult(event: InventoryClickEvent): Any { + if(event.inventory.getItem(2) != null){ + this.anvilListener.onClickAnvil(event) + return event.inventory.getItem(2) == null + } + + + return false; + } + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/GuiTesterSelector.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/GuiTesterSelector.kt new file mode 100644 index 0000000..b1c27a1 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/gui/GuiTesterSelector.kt @@ -0,0 +1,51 @@ +package xyz.alexcrea.cuanvil.dependency.gui + +import xyz.alexcrea.cuanvil.dependency.gui.version.*; +import xyz.alexcrea.cuanvil.update.UpdateUtils + +object GuiTesterSelector { + + val selectGuiTester: ExternGuiTester? + get() { + val versionParts = UpdateUtils.currentMinecraftVersionArray() + if (versionParts[0] != 1) return null + + return when (versionParts[1]) { + // Can't support 1.16.5 bc 1.16.5 paper userdev do not exist + + 17 -> when (versionParts[2]) { + 0, 1 -> v1_17R1_ExternGuiTester() + else -> null + } + + 18 -> when (versionParts[2]) { + 0, 1 -> v1_18R1_ExternGuiTester() + 2 -> v1_18R2_ExternGuiTester() + else -> null + } + + 19 -> when (versionParts[2]) { + 0, 1, 2 -> v1_19R1_ExternGuiTester() + 3 -> v1_19R2_ExternGuiTester() + 4 -> v1_19R3_ExternGuiTester() + else -> null + } + + 20 -> when (versionParts[2]) { + 0, 1 -> v1_20R1_ExternGuiTester() + 2 -> v1_20R2_ExternGuiTester() + 3, 4 -> v1_20R3_ExternGuiTester() + 5, 6 -> v1_20R4_ExternGuiTester() + else -> null + } + + 21 -> when (versionParts[2]) { + 0, 1 -> v1_21R1_ExternGuiTester() + else -> null + } + + else -> null + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt index c58c6bf..56e923f 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt @@ -15,6 +15,9 @@ class EnchantConflictGroup( fun addEnchantment(enchant: CAEnchantment) { enchantments.add(enchant) } + fun addEnchantments(enchants: List) { + enchantments.addAll(enchants) + } fun allowed(enchants: Set, mat: Material): Boolean { if (enchantments.size < minBeforeBlock) { diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt index abebcbc..0c0850b 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt @@ -30,9 +30,9 @@ class EnchantConflictManager { const val DEFAULT_GROUP_NAME = "joinedGroup" // 1.20.5 compatibility TODO better update system - private val SWEEPING_EDGE_ENCHANT = + private val SWEEPING_EDGE_ENCHANT = Collections.singletonList( CAEnchantment.getByKey(NamespacedKey.minecraft("sweeping_edge")) ?: - CAEnchantment.getByKey(Enchantment.SWEEPING_EDGE.key) + CAEnchantment.getByKey(Enchantment.SWEEPING_EDGE.key)) } @@ -94,14 +94,14 @@ class EnchantConflictManager { // Read and add enchantment to conflict val enchantList = section.getStringList(ENCH_LIST_PATH) for (enchantName in enchantList) { - val enchant = getEnchantByName(enchantName) - if (enchant == null) { + val enchants = getEnchantByIdentifier(enchantName) + if (enchants.isEmpty()) { if (!futureUse) { //TODO future use will be deprecated once the new update system is finished CustomAnvil.instance.logger.warning("Enchantment $enchantName do not exist but was asked for conflict $conflictName") } continue } - conflict.addEnchantment(enchant) + conflict.addEnchantments(enchants) } if (conflict.getEnchants().isEmpty()) { if (!futureUse) { //TODO future use will be deprecated once the new update system is finished @@ -112,16 +112,23 @@ class EnchantConflictManager { return conflict } - private fun getEnchantByName(enchantName: String): CAEnchantment? { + private fun getEnchantByIdentifier(enchantName: String): List { + val key = NamespacedKey.fromString(enchantName) + if(key != null){ + val enchantment = CAEnchantment.getByKey(key) + if(enchantment != null) return Collections.singletonList(enchantment) + + } // Temporary solution for 1.20.5 when(enchantName){ - "sweeping", "sweeping_edge" -> { + "minecraft:sweeping", "sweeping", + "minecraft:sweeping_edge", "sweeping_edge" -> { return SWEEPING_EDGE_ENCHANT } } - return CAEnchantment.getByName(enchantName) + return CAEnchantment.getListByName(enchantName) } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilCloseListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilCloseListener.kt new file mode 100644 index 0000000..60a0339 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilCloseListener.kt @@ -0,0 +1,23 @@ +package xyz.alexcrea.cuanvil.listener + +import org.bukkit.GameMode +import org.bukkit.entity.Player +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.inventory.InventoryCloseEvent +import org.bukkit.inventory.AnvilInventory +import xyz.alexcrea.cuanvil.dependency.packet.PacketManager + +class AnvilCloseListener(private val packetManager: PacketManager) : Listener { + + @EventHandler + fun onAnvilClose(event: InventoryCloseEvent){ + val player = event.player + if(event.inventory !is AnvilInventory) return + if(player is Player && GameMode.CREATIVE != player.gameMode){ + packetManager.setInstantBuild(player, false) + } + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt new file mode 100644 index 0000000..fbc603d --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt @@ -0,0 +1,292 @@ +package xyz.alexcrea.cuanvil.listener + +import io.delilaheve.CustomAnvil +import io.delilaheve.util.ConfigOptions +import io.delilaheve.util.ItemUtil.canMergeWith +import io.delilaheve.util.ItemUtil.unitRepair +import org.bukkit.GameMode +import org.bukkit.Material +import org.bukkit.entity.Player +import org.bukkit.event.Event +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.inventory.ClickType +import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.inventory.AnvilInventory +import org.bukkit.inventory.InventoryView +import org.bukkit.inventory.ItemStack +import xyz.alexcrea.cuanvil.dependency.DependencyManager +import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_LEFT +import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_RIGHT +import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT +import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe +import xyz.alexcrea.cuanvil.util.AnvilXpUtil +import xyz.alexcrea.cuanvil.util.CustomRecipeUtil +import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair +import kotlin.math.min + +class AnvilResultListener: Listener { + + companion object { + // static slot container + private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0) + private val CURSOR_SLOT = SlotContainer(SlotType.CURSOR, 0) + } + + /** + * Event handler logic for when a player is trying to pull an item out of the anvil + */ + @EventHandler(ignoreCancelled = true) + fun anvilExtractionCheck(event: InventoryClickEvent) { + val player = event.whoClicked as? Player ?: return + if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return + val inventory = event.inventory as? AnvilInventory ?: return + + if (event.rawSlot != ANVIL_OUTPUT_SLOT) { + return + } + // Test if the event should bypass custom anvil. + if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return + + val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return + val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return + val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) + + // Test custom recipe + val recipe = CustomRecipeUtil.getCustomRecipe(leftItem, rightItem) + if(recipe != null){ + event.result = Event.Result.ALLOW + onCustomCraft( + event, recipe, player, + leftItem, rightItem, output, inventory) + return + } + + val canMerge = leftItem.canMergeWith(rightItem) + val unitRepairResult = leftItem.getRepair(rightItem) + val allowed = (rightItem == null) + || (canMerge) + || (unitRepairResult != null) + + // True if there was no change or not allowed + if ((output == inventory.getItem(ANVIL_INPUT_LEFT)) + || !allowed + ) { + event.result = Event.Result.DENY + return + } + if (rightItem == null) { + event.result = Event.Result.ALLOW + return + } + if (canMerge) { + event.result = Event.Result.ALLOW + } else if (unitRepairResult != null) { + onUnitRepairExtract( + leftItem, rightItem, output, + unitRepairResult, event, player, inventory + ) + + return + } + } + + + private fun onCustomCraft(event: InventoryClickEvent, + recipe: AnvilCustomRecipe, + player: Player, + leftItem: ItemStack, + rightItem: ItemStack?, + output: ItemStack, + inventory: AnvilInventory + ) { + event.result = Event.Result.DENY + + if(recipe.leftItem == null) return // in case it changed + + val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, leftItem, rightItem) + val xpCost = amount * recipe.xpCostPerCraft + + if ((player.gameMode != GameMode.CREATIVE) && (player.level < xpCost)) return + + // We give the item manually + // But first we check if we should give the item + val slotDestination = getActionSlot(event, player) + if (slotDestination.type == SlotType.NO_SLOT) return + + // Handle not creative middle click... + if (event.click != ClickType.MIDDLE && + !handleCustomCraftClick(event, recipe, inventory, player, leftItem, rightItem, amount, xpCost)) return; + + // Finally, we add the item to the player + if (slotDestination.type == SlotType.CURSOR) { + player.setItemOnCursor(output) + } else {// We assume SlotType == SlotType.INVENTORY + player.inventory.setItem(slotDestination.slot, output) + } + } + + private fun handleCustomCraftClick(event: InventoryClickEvent, recipe: AnvilCustomRecipe, + inventory: AnvilInventory, player: Player, + leftItem: ItemStack, rightItem: ItemStack?, + amount: Int, xpCost: Int): Boolean { + // We remove what should be removed + if(rightItem != null){ + if(recipe.rightItem == null) return false// in case it changed + + rightItem.amount -= amount * recipe.rightItem!!.amount + inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) + } + + leftItem.amount -= amount * recipe.leftItem!!.amount + inventory.setItem(ANVIL_INPUT_LEFT, leftItem) + + if(player.gameMode != GameMode.CREATIVE){ + player.level -= xpCost + } + + // Then we try to find the new values for the anvil + val newAmount = CustomRecipeUtil.getCustomRecipeAmount(recipe, leftItem, rightItem) + + CustomAnvil.verboseLog("new amount is $newAmount") + if(newAmount <= 0 || recipe.exactCount){ + inventory.setItem(ANVIL_OUTPUT_SLOT, null) + }else{ + val resultItem: ItemStack = recipe.resultItem!!.clone() + resultItem.amount *= newAmount + + val newXp = newAmount * newAmount + + inventory.repairCost = newXp + event.view.setProperty(InventoryView.Property.REPAIR_COST, newXp) + + inventory.setItem(ANVIL_OUTPUT_SLOT, resultItem) + + player.updateInventory() + } + return true + } + + private fun onUnitRepairExtract( + leftItem: ItemStack, + rightItem: ItemStack, + output: ItemStack, + unitRepairResult: Double, + event: InventoryClickEvent, + player: Player, + inventory: AnvilInventory + ) { + val resultCopy = leftItem.clone() + val resultAmount = resultCopy.unitRepair( + rightItem.amount, unitRepairResult + ) + + // To avoid vanilla, we cancel the event for unit repair + event.result = Event.Result.DENY + event.isCancelled = true + // And we give the item manually + // But first we check if we should give the item + val slotDestination = getActionSlot(event, player) + if (slotDestination.type == SlotType.NO_SLOT) return + + // Test repair cost + val repairCost = getUnitRepairCost(inventory, player, leftItem, output, resultCopy, resultAmount) + if(repairCost == Int.MIN_VALUE) return + + // If not creative middle click... + if (event.click != ClickType.MIDDLE) { + // We remove what should be removed + inventory.setItem(ANVIL_INPUT_LEFT, null) + rightItem.amount -= resultAmount + inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) + inventory.setItem(ANVIL_OUTPUT_SLOT, null) + player.level -= repairCost + } + + // Finally, we add the item to the player + if (slotDestination.type == SlotType.CURSOR) { + player.setItemOnCursor(output) + } else {// We assume SlotType == SlotType.INVENTORY + player.inventory.setItem(slotDestination.slot, output) + } + } + + private fun getUnitRepairCost(inventory: AnvilInventory, player: Player, + leftItem: ItemStack, output: ItemStack, + resultCopy: ItemStack, resultAmount: Int): Int { + if (player.gameMode == GameMode.CREATIVE) return 0 + + var repairCost = 0; + // Get repairCost + leftItem.itemMeta?.let { leftMeta -> + val leftName = leftMeta.displayName + output.itemMeta?.let { + // Rename cost + if (!leftName.contentEquals(it.displayName)) { + repairCost += ConfigOptions.itemRenameCost + + // Color cost + if(it.displayName.contains('§')){ + repairCost += ConfigOptions.useOfColorCost + } + } + } + } + + repairCost += AnvilXpUtil.calculatePenalty(leftItem, null, resultCopy) + repairCost += resultAmount * ConfigOptions.unitRepairCost + + if ( + !ConfigOptions.doRemoveCostLimit && + ConfigOptions.doCapCost + ) { + repairCost = min(repairCost, ConfigOptions.maxAnvilCost) + } + + if ((inventory.maximumRepairCost <= repairCost) + || (player.level < repairCost) + ) return Int.MIN_VALUE + + return repairCost + } + + /** + * Get the destination slot or "NO_SLOT" slot container if there is no slot available + */ + private fun getActionSlot(event: InventoryClickEvent, player: Player): SlotContainer { + if (event.isShiftClick) { + val inventory = player.inventory + val firstEmpty = inventory.firstEmpty() + if (firstEmpty == -1) { + return NO_SLOT + } + //check hotbare full + var slotIndex = 8 + while (slotIndex >= 0 && ((inventory.getItem(slotIndex)?.type ?: Material.AIR) != Material.AIR)) { + slotIndex-- + } + if (slotIndex >= 0) { + return SlotContainer(SlotType.INVENTORY, slotIndex) + } + slotIndex = 35 //4*9 - 1 (max of player inventory) + while (slotIndex >= 9 && ((inventory.getItem(slotIndex)?.type ?: Material.AIR) != Material.AIR)) { + slotIndex-- + } + if (slotIndex < 9) { + return NO_SLOT + } + return SlotContainer(SlotType.INVENTORY, slotIndex) + } + else if (player.itemOnCursor.type != Material.AIR) return NO_SLOT + return CURSOR_SLOT + } + + private class SlotContainer(val type: SlotType, val slot: Int) + private enum class SlotType { + CURSOR, + INVENTORY, + NO_SLOT + + } + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt new file mode 100644 index 0000000..57de82f --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt @@ -0,0 +1,206 @@ +package xyz.alexcrea.cuanvil.listener + +import io.delilaheve.CustomAnvil +import io.delilaheve.util.ConfigOptions +import io.delilaheve.util.EnchantmentUtil.combineWith +import io.delilaheve.util.ItemUtil.canMergeWith +import io.delilaheve.util.ItemUtil.findEnchantments +import io.delilaheve.util.ItemUtil.isEnchantedBook +import io.delilaheve.util.ItemUtil.repairFrom +import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe +import io.delilaheve.util.ItemUtil.unitRepair +import org.bukkit.ChatColor +import org.bukkit.entity.HumanEntity +import org.bukkit.event.EventHandler +import org.bukkit.event.EventPriority +import org.bukkit.event.Listener +import org.bukkit.event.inventory.PrepareAnvilEvent +import org.bukkit.inventory.AnvilInventory +import org.bukkit.inventory.ItemStack +import xyz.alexcrea.cuanvil.dependency.DependencyManager +import xyz.alexcrea.cuanvil.util.AnvilColorUtil +import xyz.alexcrea.cuanvil.util.AnvilXpUtil +import xyz.alexcrea.cuanvil.util.CustomRecipeUtil +import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair + +/** + * Listener for anvil events + */ +class PrepareAnvilListener : Listener { + + companion object { + + // Anvil's output slot + const val ANVIL_INPUT_LEFT = 0 + const val ANVIL_INPUT_RIGHT = 1 + const val ANVIL_OUTPUT_SLOT = 2 + } + + /** + * Event handler logic for when an anvil contains items to be combined + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + fun anvilCombineCheck(event: PrepareAnvilEvent) { + // Test if the event should bypass custom anvil. + if(DependencyManager.tryEventPreAnvilBypass(event)) return + + val inventory = event.inventory + val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return + val second = inventory.getItem(ANVIL_INPUT_RIGHT) + + // Should find player + val player = event.view.player + if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return + + // Test custom recipe + if(testCustomRecipe(event, inventory, first, second)) return + + // Test rename lonely item + if(second == null) { + doRenaming(event, inventory, player, first) + return + } + + // Test for merge + if (first.canMergeWith(second)) { + doMerge(event, inventory, player, first, second) + return + } + + // Test for unit repair + if(testUnitRepair(event, inventory, player, first, second)) return + + CustomAnvil.log("no anvil fuse type found") + event.result = null + + } + + private fun testCustomRecipe(event: PrepareAnvilEvent, inventory: AnvilInventory, first: ItemStack, second: ItemStack?): Boolean { + val recipe = CustomRecipeUtil.getCustomRecipe(first, second) + CustomAnvil.verboseLog("custom recipe not null? ${recipe != null}") + if(recipe == null) return false + + val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, first, second) + + val resultItem: ItemStack = recipe.resultItem!!.clone() + resultItem.amount *= amount + + event.result = resultItem + AnvilXpUtil.setAnvilInvXp(inventory, event.view, recipe.xpCostPerCraft * amount, true) + + return true + } + + private fun doRenaming(event: PrepareAnvilEvent, inventory: AnvilInventory, + player: HumanEntity, first: ItemStack) { + val resultItem = first.clone() + var anvilCost = handleRename(resultItem, inventory, player) + + // Test/stop if nothing changed. + if (first == resultItem) { + CustomAnvil.log("no right item, But input is same as output") + event.result = null + return + } + + event.result = resultItem + + anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem) + + AnvilXpUtil.setAnvilInvXp(inventory, event.view, anvilCost) + } + + private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int { + // Rename item and add renaming cost + resultItem.itemMeta?.let { + val displayName = ChatColor.stripColor(it.displayName) + var inventoryName = ChatColor.stripColor(inventory.renameText) + + var sumCost = 0 + + var useColor = false + if(ConfigOptions.renameColorPossible){ + val resultString = StringBuilder(inventoryName) + + useColor = AnvilColorUtil.handleRenamingColor(resultString, player) + + if(useColor) { + inventoryName = resultString.toString() + + sumCost+= ConfigOptions.useOfColorCost + } + } + + if ((!useColor && (!displayName.contentEquals(inventoryName))) || (useColor && !(it.displayName).contentEquals(inventoryName))) { + it.setDisplayName(inventoryName) + resultItem.itemMeta = it + + sumCost+= ConfigOptions.itemRenameCost + } + + return sumCost + } + return 0 + } + + private fun doMerge(event: PrepareAnvilEvent, inventory: AnvilInventory, + player: HumanEntity, + first: ItemStack, second: ItemStack) { + val newEnchants = first.findEnchantments() + .combineWith(second.findEnchantments(), first, player) + val resultItem = first.clone() + resultItem.setEnchantmentsUnsafe(newEnchants) + + // Calculate enchantment cost + var anvilCost = AnvilXpUtil.getRightValues(second, resultItem) + // Calculate repair cost + if (!first.isEnchantedBook() && !second.isEnchantedBook()) { + // we only need to be concerned with repair when neither item is a book + val repaired = resultItem.repairFrom(first, second) + anvilCost += if (repaired) ConfigOptions.itemRepairCost else 0 + } + + // Test/stop if nothing changed. + if (first == resultItem) { + CustomAnvil.log("Mergable with second, But input is same as output") + event.result = null + return + } + // As calculatePenalty edit result, we need to calculate penalty after checking equality + anvilCost += AnvilXpUtil.calculatePenalty(first, second, resultItem) + // Calculate rename cost + anvilCost += handleRename(resultItem, inventory, player) + + // Finally, we set result + event.result = resultItem + + AnvilXpUtil.setAnvilInvXp(inventory, event.view, anvilCost) + } + + private fun testUnitRepair(event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity, + first: ItemStack, second: ItemStack): Boolean { + val unitRepairAmount = first.getRepair(second) ?: return false + + val resultItem = first.clone() + var anvilCost = handleRename(resultItem, inventory, player) + + val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount) + if (repairAmount > 0) { + anvilCost += repairAmount * ConfigOptions.unitRepairCost + } + // We do not care about right item penalty for unit repair + anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem, true) + + // Test/stop if nothing changed. + if (first == resultItem) { + CustomAnvil.log("unit repair, But input is same as output") + event.result = null + return true + } + event.result = resultItem + + AnvilXpUtil.setAnvilInvXp(inventory, event.view, anvilCost) + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilColorUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilColorUtil.kt new file mode 100644 index 0000000..0e216e8 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilColorUtil.kt @@ -0,0 +1,88 @@ +package xyz.alexcrea.cuanvil.util + +import io.delilaheve.util.ConfigOptions +import org.bukkit.entity.HumanEntity +import java.util.regex.Matcher +import java.util.regex.Pattern + +object AnvilColorUtil { + private val HEX_PATTERN: Pattern = Pattern.compile("#[A-Fa-f0-9]{6}") // pattern to find hexadecimal string + + fun handleRenamingColor(textToColor: StringBuilder, player: HumanEntity): Boolean { + val usePermission = ConfigOptions.permissionNeededForColor + val canUseColorCode = ConfigOptions.allowColorCode && (!usePermission || player.hasPermission("ca.color.code")) + val canUseHexColor = ConfigOptions.allowHexadecimalColor && (!usePermission || player.hasPermission("ca.color.hex")) + + if((!canUseColorCode) && (!canUseHexColor)) return false + + var useColor = false + // Handle color code + if(canUseColorCode){ + var nbReplacement = replaceAll(textToColor, "&", "§", 2) + nbReplacement -= 2 * replaceAll(textToColor, "§§", "&", 2) + + if(nbReplacement > 0) useColor = true + } + + if(canUseHexColor){ + val nbReplacement = replaceHexToColor(textToColor, 7) + + if(nbReplacement > 0) useColor = true + } + + return useColor + } + + /** + * Replace every instance of "from" to "to". + * @param builder The builder to replace the string from. + * @param from The source that should be replaced. + * @param to The string that should replace. + * @param endOffset Amount of character that should be ignored at the end. + * @return The number of replacement was that was done. + */ + private fun replaceAll(builder: java.lang.StringBuilder, from: String, to: String, endOffset: Int): Int { + var index = builder.indexOf(from) + var numberOfChanges = 0 + + while (index != -1 && index < builder.length - endOffset) { + builder.replace(index, index + from.length, to) + index += to.length + index = builder.indexOf(from, index) + + numberOfChanges+=1 + } + + return numberOfChanges + } + + /** + * Replace every hex color formatted like #000000 to the minecraft format + * @param builder The builder to replace the hex color from. + * @param endOffset Amount of character that should be ignored at the end. + * @return The number of replacement was that was done. + */ + private fun replaceHexToColor(builder: StringBuilder, endOffset: Int): Int { + val matcher: Matcher = HEX_PATTERN.matcher(builder) + + var numberOfChanges = 0 + var startIndex = 0 + + while(matcher.find(startIndex)){ + startIndex = matcher.start() + if(startIndex >= builder.length - endOffset) break + + builder.replace(startIndex, startIndex + 1, "§x") + startIndex+=2 + for (i in 0..5) { + builder.insert(startIndex, '§') + startIndex+=2 + } + + numberOfChanges+=1 + } + + return numberOfChanges + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/CustomRecipeUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/CustomRecipeUtil.kt new file mode 100644 index 0000000..3ec5e71 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/CustomRecipeUtil.kt @@ -0,0 +1,54 @@ +package xyz.alexcrea.cuanvil.util + +import io.delilaheve.CustomAnvil +import org.bukkit.inventory.ItemStack +import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe +import kotlin.math.min + +object CustomRecipeUtil { + + fun getCustomRecipe ( + leftItem: ItemStack, + rightItem: ItemStack?) : AnvilCustomRecipe? { + + val recipeList = ConfigHolder.CUSTOM_RECIPE_HOLDER.recipeManager.recipeByMat[leftItem.type] ?: return null + + CustomAnvil.verboseLog("Testing " + recipeList.size + " recipe...") + for (recipe in recipeList) { + if(recipe.testItem(leftItem, rightItem)){ + return recipe + } + } + + return null + } + + fun getCustomRecipeAmount( + recipe: AnvilCustomRecipe, + leftItem: ItemStack, + rightItem: ItemStack? + ): Int{ + return if(recipe.exactCount) { + if(leftItem.amount != recipe.leftItem!!.amount){ + 0 + }else if(rightItem != null && rightItem.amount != recipe.rightItem!!.amount){ + 0 + }else{ + 1 + } + } + else { + // test amount + val resultItem = recipe.resultItem!! // we know exist as the recipe was returned to us + val maxResultAmount = resultItem.type.maxStackSize/resultItem.amount + val maxLeftAmount = leftItem.amount/recipe.leftItem!!.amount + val maxRightAmount = if(rightItem == null){ maxLeftAmount } else{ rightItem.amount/recipe.rightItem!!.amount } + + CustomAnvil.verboseLog("resultItem: $resultItem, maxResultAmount: $maxResultAmount, maxLeftAmount: $maxLeftAmount, maxRightAmount: $maxRightAmount") + + min(min(maxResultAmount, maxLeftAmount), maxRightAmount) + } + } + +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 462866d..dd24558 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -97,46 +97,46 @@ default_limit: 5 # # Valid range of 1 - 255 for each enchantment enchant_limits: - aqua_affinity: 1 - binding_curse: 1 - channeling: 1 - flame: 1 - infinity: 1 - mending: 1 - multishot: 1 - silk_touch: 1 - vanishing_curse: 1 - depth_strider: 3 # anything more than 3 is treated as 3 by the game - protection: 4 - fire_protection: 4 - blast_protection: 4 - projectile_protection: 4 - feather_falling: 4 - thorns: 3 - respiration: 3 - sharpness: 5 - smite: 5 - bane_of_arthropods: 5 - knockback: 2 - fire_aspect: 2 - looting: 3 - sweeping: 3 - sweeping_edge: 3 - efficiency: 5 - unbreaking: 3 - fortune: 3 - power: 5 - punch: 2 - luck_of_the_sea: 3 - lure: 3 - frost_walker: 2 - impaling: 5 - riptide: 3 - loyalty: 3 - piercing: 4 - quick_charge: 3 - soul_speed: 3 - swift_sneak: 3 + minecraft:aqua_affinity: 1 + minecraft:binding_curse: 1 + minecraft:channeling: 1 + minecraft:flame: 1 + minecraft:infinity: 1 + minecraft:mending: 1 + minecraft:multishot: 1 + minecraft:silk_touch: 1 + minecraft:vanishing_curse: 1 + minecraft:depth_strider: 3 # anything more than 3 is treated as 3 by the game + minecraft:protection: 4 + minecraft:fire_protection: 4 + minecraft:blast_protection: 4 + minecraft:projectile_protection: 4 + minecraft:feather_falling: 4 + minecraft:thorns: 3 + minecraft:respiration: 3 + minecraft:sharpness: 5 + minecraft:smite: 5 + minecraft:bane_of_arthropods: 5 + minecraft:knockback: 2 + minecraft:fire_aspect: 2 + minecraft:looting: 3 + minecraft:sweeping: 3 + minecraft:sweeping_edge: 3 + minecraft:efficiency: 5 + minecraft:unbreaking: 3 + minecraft:fortune: 3 + minecraft:power: 5 + minecraft:punch: 2 + minecraft:luck_of_the_sea: 3 + minecraft:lure: 3 + minecraft:frost_walker: 2 + minecraft:impaling: 5 + minecraft:riptide: 3 + minecraft:loyalty: 3 + minecraft:piercing: 4 + minecraft:quick_charge: 3 + minecraft:soul_speed: 3 + minecraft:swift_sneak: 3 # Multipliers used to calculate the enchantment's value in repair/combining # @@ -150,127 +150,138 @@ enchant_limits: # With default values protection 4 would have a value of 4 when # coming from either a book (4 * 1) or an item (4 * 1) enchant_values: - aqua_affinity: + minecraft:aqua_affinity: item: 4 book: 2 - bane_of_arthropods: + minecraft:bane_of_arthropods: item: 2 book: 1 - binding_curse: + minecraft:binding_curse: item: 8 book: 4 - blast_protection: + minecraft:blast_protection: item: 4 book: 2 - channeling: + minecraft:channeling: item: 8 book: 4 - depth_strider: + minecraft:depth_strider: item: 4 book: 2 - efficiency: + minecraft:efficiency: item: 1 book: 1 - flame: + minecraft:flame: item: 4 book: 2 - feather_falling: + minecraft:feather_falling: item: 2 book: 1 - fire_aspect: + minecraft:fire_aspect: item: 4 book: 2 - fire_protection: + minecraft:fire_protection: item: 2 book: 1 - fortune: + minecraft:fortune: item: 4 book: 2 - frost_walker: + minecraft:frost_walker: item: 4 book: 2 - impaling: + minecraft:impaling: item: 4 book: 2 - infinity: + minecraft:infinity: item: 8 book: 4 - knockback: + minecraft:knockback: item: 2 book: 1 - looting: + minecraft:looting: item: 4 book: 2 - loyalty: + minecraft:loyalty: item: 1 book: 1 - luck_of_the_sea: + minecraft:luck_of_the_sea: item: 4 book: 2 - lure: + minecraft:lure: item: 4 book: 2 - mending: + minecraft:mending: item: 4 book: 2 - multishot: + minecraft:multishot: item: 4 book: 2 - piercing: + minecraft:piercing: item: 1 book: 1 - power: + minecraft:power: item: 1 book: 1 - projectile_protection: + minecraft:projectile_protection: item: 2 book: 1 - protection: + minecraft:protection: item: 1 book: 1 - punch: + minecraft:punch: item: 4 book: 2 - quick_charge: + minecraft:quick_charge: item: 2 book: 1 - respiration: + minecraft:respiration: item: 4 book: 2 - riptide: + minecraft:riptide: item: 4 book: 2 - silk_touch: + minecraft:silk_touch: item: 8 book: 4 - sharpness: + minecraft:sharpness: item: 1 book: 1 - smite: + minecraft:smite: item: 2 book: 1 - soul_speed: + minecraft:soul_speed: item: 8 book: 4 - swift_sneak: + minecraft:swift_sneak: item: 8 book: 4 - sweeping: + minecraft:sweeping: item: 4 book: 2 - sweeping_edge: + minecraft:sweeping_edge: item: 4 book: 2 - thorns: + minecraft:thorns: item: 8 book: 4 - unbreaking: + minecraft:unbreaking: item: 2 book: 1 - vanishing_curse: + minecraft:vanishing_curse: item: 8 book: 4 +# Disable enchantment merging for level above the set value +# Enchantment merging is when, for example, 2 unbreaking II book combine to give sharpness III +# But Enchantment above this value can still be applied. following the previous example, we could still apply a unbreaking III book to a sword +# Even if disable-merge-over of unbreaking is set to 2 +# -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent. +disable-merge-over: + # Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla) + minecraft:sharpness: -1 + # If uncommented. 2 unbreaking II book would not give an unbreaking III book. but unbreaking III book can still be applied + #minecraft:unbreaking: 2 + # Whether to show debug logging debug_log: false diff --git a/src/main/resources/enchant_conflict.yml b/src/main/resources/enchant_conflict.yml index ed154ab..0e8b3f3 100644 --- a/src/main/resources/enchant_conflict.yml +++ b/src/main/resources/enchant_conflict.yml @@ -17,158 +17,158 @@ # ---------------------------------------------------- restriction_aqua_affinity: - enchantments: [ aqua_affinity ] + enchantments: [ minecraft:aqua_affinity ] notAffectedGroups: [ enchanted_book, helmets ] restriction_bane_of_arthropods: - enchantments: [ bane_of_arthropods ] + enchantments: [ minecraft:bane_of_arthropods ] notAffectedGroups: [ enchanted_book, melee_weapons ] restriction_blast_protection: - enchantments: [ blast_protection ] + enchantments: [ minecraft:blast_protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_channeling: - enchantments: [ channeling ] + enchantments: [ minecraft:channeling ] notAffectedGroups: [ enchanted_book, trident ] restriction_binding_curse: - enchantments: [ binding_curse ] + enchantments: [ minecraft:binding_curse ] notAffectedGroups: [ enchanted_book, wearable ] restriction_vanishing_curse: - enchantments: [ vanishing_curse ] + enchantments: [ minecraft:vanishing_curse ] notAffectedGroups: [ enchanted_book, can_vanish ] restriction_depth_strider: - enchantments: [ depth_strider ] + enchantments: [ minecraft:depth_strider ] notAffectedGroups: [ enchanted_book, boots ] restriction_efficiency: - enchantments: [ efficiency ] + enchantments: [ minecraft:efficiency ] notAffectedGroups: [ enchanted_book, tools, shears ] restriction_feather_falling: - enchantments: [ feather_falling ] + enchantments: [ minecraft:feather_falling ] notAffectedGroups: [ enchanted_book, boots ] restriction_fire_aspect: - enchantments: [ fire_aspect ] + enchantments: [ minecraft:fire_aspect ] notAffectedGroups: [ enchanted_book, swords ] restriction_fire_protection: - enchantments: [ fire_protection ] + enchantments: [ minecraft:fire_protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_flame: - enchantments: [ flame ] + enchantments: [ minecraft:flame ] notAffectedGroups: [ enchanted_book, bow ] restriction_fortune: - enchantments: [ fortune ] + enchantments: [ minecraft:fortune ] notAffectedGroups: [ enchanted_book, tools ] restriction_frost_walker: - enchantments: [ frost_walker ] + enchantments: [ minecraft:frost_walker ] notAffectedGroups: [ enchanted_book, boots ] restriction_impaling: - enchantments: [ impaling ] + enchantments: [ minecraft:impaling ] notAffectedGroups: [ enchanted_book, trident ] restriction_infinity: - enchantments: [ infinity ] + enchantments: [ minecraft:infinity ] notAffectedGroups: [ enchanted_book, bow ] restriction_knockback: - enchantments: [ knockback ] + enchantments: [ minecraft:knockback ] notAffectedGroups: [ enchanted_book, swords ] restriction_looting: - enchantments: [ looting ] + enchantments: [ minecraft:looting ] notAffectedGroups: [ enchanted_book, swords ] restriction_loyalty: - enchantments: [ loyalty ] + enchantments: [ minecraft:loyalty ] notAffectedGroups: [ enchanted_book, trident ] restriction_lure: - enchantments: [ lure ] + enchantments: [ minecraft:lure ] notAffectedGroups: [ enchanted_book, fishing_rod ] restriction_mending: - enchantments: [ mending ] + enchantments: [ minecraft:mending ] notAffectedGroups: [ enchanted_book, can_unbreak ] -restriction_multishot: - enchantments: [ multishot ] +restriction_minecraft_multishot: + enchantments: [ minecraft:multishot ] notAffectedGroups: [ enchanted_book, crossbow ] restriction_piercing: - enchantments: [ piercing ] + enchantments: [ minecraft:piercing ] notAffectedGroups: [ enchanted_book, crossbow ] restriction_power: - enchantments: [ power ] + enchantments: [ minecraft:power ] notAffectedGroups: [ enchanted_book, bow ] restriction_projectile_protection: - enchantments: [ projectile_protection ] + enchantments: [ minecraft:projectile_protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_protection: - enchantments: [ protection ] + enchantments: [ minecraft:protection ] notAffectedGroups: [ enchanted_book, armors ] restriction_punch: - enchantments: [ punch ] + enchantments: [ minecraft:punch ] notAffectedGroups: [ enchanted_book, bow ] restriction_quick_charge: - enchantments: [ quick_charge ] + enchantments: [ minecraft:quick_charge ] notAffectedGroups: [ enchanted_book, crossbow ] restriction_respiration: - enchantments: [ respiration ] + enchantments: [ minecraft:respiration ] notAffectedGroups: [ enchanted_book, helmets ] restriction_riptide: - enchantments: [ riptide ] + enchantments: [ minecraft:riptide ] notAffectedGroups: [ enchanted_book, trident ] restriction_sharpness: - enchantments: [ sharpness ] + enchantments: [ minecraft:sharpness ] notAffectedGroups: [ enchanted_book, melee_weapons ] -restriction_silk_touch: - enchantments: [ silk_touch ] +restriction__silk_touch: + enchantments: [ minecraft:silk_touch ] notAffectedGroups: [ enchanted_book, tools ] restriction_smite: - enchantments: [ smite ] + enchantments: [ minecraft:smite ] notAffectedGroups: [ enchanted_book, melee_weapons ] restriction_soul_speed: - enchantments: [ soul_speed ] + enchantments: [ minecraft:soul_speed ] notAffectedGroups: [ enchanted_book, boots ] restriction_sweeping_edge: - enchantments: [ sweeping, sweeping_edge ] + enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ] notAffectedGroups: [ enchanted_book, swords ] # Do not exist in 1.18, that mean useInFuture will be set to true # useInFuture set to true also mean it will not warn if there is an issue restriction_swift_sneak: useInFuture: true - enchantments: [ swift_sneak ] + enchantments: [ minecraft:swift_sneak ] notAffectedGroups: [ enchanted_book, leggings ] restriction_thorns: - enchantments: [ thorns ] + enchantments: [ minecraft:thorns ] notAffectedGroups: [ enchanted_book, armors ] -restriction_unbreaking: - enchantments: [ unbreaking ] +restriction__unbreaking: + enchantments: [ minecraft:unbreaking ] notAffectedGroups: [ enchanted_book, can_unbreak ] # ---------------------------------------------------- @@ -180,60 +180,60 @@ restriction_unbreaking: sword_enchant_conflict: enchantments: - - bane_of_arthropods - - smite - - sharpness + - minecraft:bane_of_arthropods + - minecraft:smite + - minecraft:sharpness notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 protection_enchant_conflict: enchantments: - - blast_protection - - fire_protection - - projectile_protection - - protection + - minecraft:blast_protection + - minecraft:fire_protection + - minecraft:projectile_protection + - minecraft:protection notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 trident_conflict1: enchantments: - - channeling - - riptide + - minecraft:channeling + - minecraft:riptide notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 trident_conflict2: enchantments: - - loyalty - - riptide + - minecraft:loyalty + - minecraft:riptide notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 boot_conflict: enchantments: - - depth_strider - - frost_walker + - minecraft:depth_strider + - minecraft:frost_walker notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 tool_conflict: enchantments: - - fortune - - silk_touch + - minecraft:fortune + - minecraft:silk_touch notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 bow_conflict: enchantments: - - mending - - infinity + - minecraft:mending + - minecraft:infinity notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 crossbow_conflict: enchantments: - - multishot - - piercing + - minecraft:multishot + - minecraft:piercing notAffectedGroups: [ ] maxEnchantmentBeforeConflict: 1 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5cb7359..cea596d 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ main: io.delilaheve.CustomAnvil name: CustomAnvil prefix: "Custom Anvil" -version: 1.6.2 +version: 1.6.3 folia-supported: true description: Allow to customise anvil mechanics api-version: 1.16 @@ -49,12 +49,13 @@ permissions: description: Allow player to use hexadecimal color if permission is required (toggleable) -# soft depend on old name, so I can disable it if it is on the same server -# as it is the old name for this plugin +# soft depend on old name (UnsafeEnchantsPlus), so I can disable it if it is on the same server (old name for this plugin) +# Also depend to other plugin for compatibility softdepend: - UnsafeEnchantsPlus - ProtocolLib - Disenchantment - EnchantsSquared - EcoEnchants - - eco \ No newline at end of file + - eco + - ExcellentEnchants