- Support for
[ExcellentEnchants](https://www.spigotmc.org/resources/excellentenchants--75-vanilla-like-enchantments.61693/)
- Add enchantment merge level limit (& config gui for to configure it)
- Use namespace for enchantment instead of name (still use name as
backup)
- Deprecated API method using enchantment name and replaced them with
namespace methods
- Improved main logic code readability (but may break thing)

Multiplies changes (improved logic, namespace...) make this version
likely to have something broken. Next version(s) may be fix
This commit is contained in:
alexcrea 2024-10-15 08:42:22 +02:00 committed by GitHub
commit 7266d4b0c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 2048 additions and 1463 deletions

View file

@ -14,7 +14,7 @@ plugins {
} }
group = "xyz.alexcrea" group = "xyz.alexcrea"
version = "1.6.2" version = "1.6.3"
repositories { repositories {
// EcoEnchants // EcoEnchants
@ -36,6 +36,10 @@ dependencies {
compileOnly("com.willfp:EcoEnchants:12.5.1") compileOnly("com.willfp:EcoEnchants:12.5.1")
compileOnly("com.willfp:eco:6.70.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 // Disenchantment
compileOnly("cz.kominekjan:Disenchantment:v5.4.0") compileOnly("cz.kominekjan:Disenchantment:v5.4.0")

View file

@ -97,49 +97,46 @@ default_limit: 5
# #
# Valid range of 1 - 255 for each enchantment # Valid range of 1 - 255 for each enchantment
enchant_limits: enchant_limits:
aqua_affinity: 1 minecraft:aqua_affinity: 1
binding_curse: 1 minecraft:binding_curse: 1
channeling: 1 minecraft:channeling: 1
flame: 1 minecraft:flame: 1
infinity: 1 minecraft:infinity: 1
mending: 1 minecraft:mending: 1
multishot: 1 minecraft:multishot: 1
silk_touch: 1 minecraft:silk_touch: 1
vanishing_curse: 1 minecraft:vanishing_curse: 1
depth_strider: 3 # anything more than 3 is treated as 3 by the game minecraft:depth_strider: 3 # anything more than 3 is treated as 3 by the game
protection: 4 minecraft:protection: 4
fire_protection: 4 minecraft:fire_protection: 4
blast_protection: 4 minecraft:blast_protection: 4
projectile_protection: 4 minecraft:projectile_protection: 4
feather_falling: 4 minecraft:feather_falling: 4
thorns: 3 minecraft:thorns: 3
respiration: 3 minecraft:respiration: 3
sharpness: 5 minecraft:sharpness: 5
smite: 5 minecraft:smite: 5
bane_of_arthropods: 5 minecraft:bane_of_arthropods: 5
knockback: 2 minecraft:knockback: 2
fire_aspect: 2 minecraft:fire_aspect: 2
looting: 3 minecraft:looting: 3
sweeping: 3 minecraft:sweeping: 3
sweeping_edge: 3 minecraft:sweeping_edge: 3
efficiency: 5 minecraft:efficiency: 5
unbreaking: 3 minecraft:unbreaking: 3
fortune: 3 minecraft:fortune: 3
power: 5 minecraft:power: 5
punch: 2 minecraft:punch: 2
luck_of_the_sea: 3 minecraft:luck_of_the_sea: 3
lure: 3 minecraft:lure: 3
frost_walker: 2 minecraft:frost_walker: 2
impaling: 5 minecraft:impaling: 5
riptide: 3 minecraft:riptide: 3
loyalty: 3 minecraft:loyalty: 3
piercing: 4 minecraft:piercing: 4
quick_charge: 3 minecraft:quick_charge: 3
soul_speed: 3 minecraft:soul_speed: 3
swift_sneak: 3 minecraft:swift_sneak: 3
density: 5
breach: 4
wind_burst: 3
# Multipliers used to calculate the enchantment's value in repair/combining # 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 # With default values protection 4 would have a value of 4 when
# coming from either a book (4 * 1) or an item (4 * 1) # coming from either a book (4 * 1) or an item (4 * 1)
enchant_values: enchant_values:
aqua_affinity: minecraft:aqua_affinity:
item: 4 item: 4
book: 2 book: 2
bane_of_arthropods: minecraft:bane_of_arthropods:
item: 2 item: 2
book: 1 book: 1
binding_curse: minecraft:binding_curse:
item: 8 item: 8
book: 4 book: 4
blast_protection: minecraft:blast_protection:
item: 4 item: 4
book: 2 book: 2
channeling: minecraft:channeling:
item: 8 item: 8
book: 4 book: 4
depth_strider: minecraft:depth_strider:
item: 4 item: 4
book: 2 book: 2
efficiency: minecraft:efficiency:
item: 1 item: 1
book: 1 book: 1
flame: minecraft:flame:
item: 4 item: 4
book: 2 book: 2
feather_falling: minecraft:feather_falling:
item: 2 item: 2
book: 1 book: 1
fire_aspect: minecraft:fire_aspect:
item: 4 item: 4
book: 2 book: 2
fire_protection: minecraft:fire_protection:
item: 2 item: 2
book: 1 book: 1
fortune: minecraft:fortune:
item: 4 item: 4
book: 2 book: 2
frost_walker: minecraft:frost_walker:
item: 4 item: 4
book: 2 book: 2
impaling: minecraft:impaling:
item: 4 item: 4
book: 2 book: 2
infinity: minecraft:infinity:
item: 8 item: 8
book: 4 book: 4
knockback: minecraft:knockback:
item: 2 item: 2
book: 1 book: 1
looting: minecraft:looting:
item: 4 item: 4
book: 2 book: 2
loyalty: minecraft:loyalty:
item: 1 item: 1
book: 1 book: 1
luck_of_the_sea: minecraft:luck_of_the_sea:
item: 4 item: 4
book: 2 book: 2
lure: minecraft:lure:
item: 4 item: 4
book: 2 book: 2
mending: minecraft:mending:
item: 4 item: 4
book: 2 book: 2
multishot: minecraft:multishot:
item: 4 item: 4
book: 2 book: 2
piercing: minecraft:piercing:
item: 1 item: 1
book: 1 book: 1
power: minecraft:power:
item: 1 item: 1
book: 1 book: 1
projectile_protection: minecraft:projectile_protection:
item: 2 item: 2
book: 1 book: 1
protection: minecraft:protection:
item: 1 item: 1
book: 1 book: 1
punch: minecraft:punch:
item: 4 item: 4
book: 2 book: 2
quick_charge: minecraft:quick_charge:
item: 2 item: 2
book: 1 book: 1
respiration: minecraft:respiration:
item: 4 item: 4
book: 2 book: 2
riptide: minecraft:riptide:
item: 4 item: 4
book: 2 book: 2
silk_touch: minecraft:silk_touch:
item: 8 item: 8
book: 4 book: 4
sharpness: minecraft:sharpness:
item: 1 item: 1
book: 1 book: 1
smite: minecraft:smite:
item: 2 item: 2
book: 1 book: 1
soul_speed: minecraft:soul_speed:
item: 8 item: 8
book: 4 book: 4
swift_sneak: minecraft:swift_sneak:
item: 8 item: 8
book: 4 book: 4
sweeping: minecraft:sweeping:
item: 4 item: 4
book: 2 book: 2
sweeping_edge: minecraft:sweeping_edge:
item: 4 item: 4
book: 2 book: 2
thorns: minecraft:thorns:
item: 8 item: 8
book: 4 book: 4
unbreaking: minecraft:unbreaking:
item: 2 item: 2
book: 1 book: 1
vanishing_curse: minecraft:vanishing_curse:
item: 8 item: 8
book: 4 book: 4
density:
item: 1 # Disable enchantment merging for level above the set value
book: 1 # Enchantment merging is when, for example, 2 unbreaking II book combine to give sharpness III
breach: # But Enchantment above this value can still be applied. following the previous example, we could still apply a unbreaking III book to a sword
item: 4 # Even if disable-merge-over of unbreaking is set to 2
book: 2 # -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent.
wind_burst: disable-merge-over:
item: 4 # Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla)
book: 2 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 # Whether to show debug logging
debug_log: false debug_log: false
@ -296,4 +295,3 @@ debug_log_verbose: false
force_protocolib: false force_protocolib: false
configVersion: 1.6.2 configVersion: 1.6.2
lowMinecraftVersion: '1.21'

View file

@ -17,158 +17,158 @@
# ---------------------------------------------------- # ----------------------------------------------------
restriction_aqua_affinity: restriction_aqua_affinity:
enchantments: [ aqua_affinity ] enchantments: [ minecraft:aqua_affinity ]
notAffectedGroups: [ enchanted_book, helmets ] notAffectedGroups: [ enchanted_book, helmets ]
restriction_bane_of_arthropods: restriction_bane_of_arthropods:
enchantments: [ bane_of_arthropods ] enchantments: [ minecraft:bane_of_arthropods ]
notAffectedGroups: [ enchanted_book, melee_weapons ] notAffectedGroups: [ enchanted_book, melee_weapons ]
restriction_blast_protection: restriction_blast_protection:
enchantments: [ blast_protection ] enchantments: [ minecraft:blast_protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_channeling: restriction_channeling:
enchantments: [ channeling ] enchantments: [ minecraft:channeling ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_binding_curse: restriction_binding_curse:
enchantments: [ binding_curse ] enchantments: [ minecraft:binding_curse ]
notAffectedGroups: [ enchanted_book, wearable ] notAffectedGroups: [ enchanted_book, wearable ]
restriction_vanishing_curse: restriction_vanishing_curse:
enchantments: [ vanishing_curse ] enchantments: [ minecraft:vanishing_curse ]
notAffectedGroups: [ enchanted_book, can_vanish ] notAffectedGroups: [ enchanted_book, can_vanish ]
restriction_depth_strider: restriction_depth_strider:
enchantments: [ depth_strider ] enchantments: [ minecraft:depth_strider ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_efficiency: restriction_efficiency:
enchantments: [ efficiency ] enchantments: [ minecraft:efficiency ]
notAffectedGroups: [ enchanted_book, tools, shears ] notAffectedGroups: [ enchanted_book, tools, shears ]
restriction_feather_falling: restriction_feather_falling:
enchantments: [ feather_falling ] enchantments: [ minecraft:feather_falling ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_fire_aspect: restriction_fire_aspect:
enchantments: [ fire_aspect ] enchantments: [ minecraft:fire_aspect ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
restriction_fire_protection: restriction_fire_protection:
enchantments: [ fire_protection ] enchantments: [ minecraft:fire_protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_flame: restriction_flame:
enchantments: [ flame ] enchantments: [ minecraft:flame ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_fortune: restriction_fortune:
enchantments: [ fortune ] enchantments: [ minecraft:fortune ]
notAffectedGroups: [ enchanted_book, tools ] notAffectedGroups: [ enchanted_book, tools ]
restriction_frost_walker: restriction_frost_walker:
enchantments: [ frost_walker ] enchantments: [ minecraft:frost_walker ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_impaling: restriction_impaling:
enchantments: [ impaling ] enchantments: [ minecraft:impaling ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_infinity: restriction_infinity:
enchantments: [ infinity ] enchantments: [ minecraft:infinity ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_knockback: restriction_knockback:
enchantments: [ knockback ] enchantments: [ minecraft:knockback ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
restriction_looting: restriction_looting:
enchantments: [ looting ] enchantments: [ minecraft:looting ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
restriction_loyalty: restriction_loyalty:
enchantments: [ loyalty ] enchantments: [ minecraft:loyalty ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_lure: restriction_lure:
enchantments: [ lure ] enchantments: [ minecraft:lure ]
notAffectedGroups: [ enchanted_book, fishing_rod ] notAffectedGroups: [ enchanted_book, fishing_rod ]
restriction_mending: restriction_mending:
enchantments: [ mending ] enchantments: [ minecraft:mending ]
notAffectedGroups: [ enchanted_book, can_unbreak ] notAffectedGroups: [ enchanted_book, can_unbreak ]
restriction_multishot: restriction_minecraft_multishot:
enchantments: [ multishot ] enchantments: [ minecraft:multishot ]
notAffectedGroups: [ enchanted_book, crossbow ] notAffectedGroups: [ enchanted_book, crossbow ]
restriction_piercing: restriction_piercing:
enchantments: [ piercing ] enchantments: [ minecraft:piercing ]
notAffectedGroups: [ enchanted_book, crossbow ] notAffectedGroups: [ enchanted_book, crossbow ]
restriction_power: restriction_power:
enchantments: [ power ] enchantments: [ minecraft:power ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_projectile_protection: restriction_projectile_protection:
enchantments: [ projectile_protection ] enchantments: [ minecraft:projectile_protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_protection: restriction_protection:
enchantments: [ protection ] enchantments: [ minecraft:protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_punch: restriction_punch:
enchantments: [ punch ] enchantments: [ minecraft:punch ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_quick_charge: restriction_quick_charge:
enchantments: [ quick_charge ] enchantments: [ minecraft:quick_charge ]
notAffectedGroups: [ enchanted_book, crossbow ] notAffectedGroups: [ enchanted_book, crossbow ]
restriction_respiration: restriction_respiration:
enchantments: [ respiration ] enchantments: [ minecraft:respiration ]
notAffectedGroups: [ enchanted_book, helmets ] notAffectedGroups: [ enchanted_book, helmets ]
restriction_riptide: restriction_riptide:
enchantments: [ riptide ] enchantments: [ minecraft:riptide ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_sharpness: restriction_sharpness:
enchantments: [ sharpness ] enchantments: [ minecraft:sharpness ]
notAffectedGroups: [ enchanted_book, melee_weapons ] notAffectedGroups: [ enchanted_book, melee_weapons ]
restriction_silk_touch: restriction__silk_touch:
enchantments: [ silk_touch ] enchantments: [ minecraft:silk_touch ]
notAffectedGroups: [ enchanted_book, tools ] notAffectedGroups: [ enchanted_book, tools ]
restriction_smite: restriction_smite:
enchantments: [ smite ] enchantments: [ minecraft:smite ]
notAffectedGroups: [ enchanted_book, melee_weapons ] notAffectedGroups: [ enchanted_book, melee_weapons ]
restriction_soul_speed: restriction_soul_speed:
enchantments: [ soul_speed ] enchantments: [ minecraft:soul_speed ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_sweeping_edge: restriction_sweeping_edge:
enchantments: [ sweeping, sweeping_edge ] enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
# Do not exist in 1.18, that mean useInFuture will be set to true # 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 # useInFuture set to true also mean it will not warn if there is an issue
restriction_swift_sneak: restriction_swift_sneak:
useInFuture: true useInFuture: true
enchantments: [ swift_sneak ] enchantments: [ minecraft:swift_sneak ]
notAffectedGroups: [ enchanted_book, leggings ] notAffectedGroups: [ enchanted_book, leggings ]
restriction_thorns: restriction_thorns:
enchantments: [ thorns ] enchantments: [ minecraft:thorns ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_unbreaking: restriction__unbreaking:
enchantments: [ unbreaking ] enchantments: [ minecraft:unbreaking ]
notAffectedGroups: [ enchanted_book, can_unbreak ] notAffectedGroups: [ enchanted_book, can_unbreak ]
# ---------------------------------------------------- # ----------------------------------------------------
@ -180,60 +180,60 @@ restriction_unbreaking:
sword_enchant_conflict: sword_enchant_conflict:
enchantments: enchantments:
- bane_of_arthropods - minecraft:bane_of_arthropods
- smite - minecraft:smite
- sharpness - minecraft:sharpness
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
protection_enchant_conflict: protection_enchant_conflict:
enchantments: enchantments:
- blast_protection - minecraft:blast_protection
- fire_protection - minecraft:fire_protection
- projectile_protection - minecraft:projectile_protection
- protection - minecraft:protection
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
trident_conflict1: trident_conflict1:
enchantments: enchantments:
- channeling - minecraft:channeling
- riptide - minecraft:riptide
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
trident_conflict2: trident_conflict2:
enchantments: enchantments:
- loyalty - minecraft:loyalty
- riptide - minecraft:riptide
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
boot_conflict: boot_conflict:
enchantments: enchantments:
- depth_strider - minecraft:depth_strider
- frost_walker - minecraft:frost_walker
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
tool_conflict: tool_conflict:
enchantments: enchantments:
- fortune - minecraft:fortune
- silk_touch - minecraft:silk_touch
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
bow_conflict: bow_conflict:
enchantments: enchantments:
- mending - minecraft:mending
- infinity - minecraft:infinity
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
crossbow_conflict: crossbow_conflict:
enchantments: enchantments:
- multishot - minecraft:multishot
- piercing - minecraft:piercing
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1

View file

@ -97,49 +97,46 @@ default_limit: 5
# #
# Valid range of 1 - 255 for each enchantment # Valid range of 1 - 255 for each enchantment
enchant_limits: enchant_limits:
aqua_affinity: 1 minecraft:aqua_affinity: 1
binding_curse: 1 minecraft:binding_curse: 1
channeling: 1 minecraft:channeling: 1
flame: 1 minecraft:flame: 1
infinity: 1 minecraft:infinity: 1
mending: 1 minecraft:mending: 1
multishot: 1 minecraft:multishot: 1
silk_touch: 1 minecraft:silk_touch: 1
vanishing_curse: 1 minecraft:vanishing_curse: 1
depth_strider: 3 # anything more than 3 is treated as 3 by the game minecraft:depth_strider: 3 # anything more than 3 is treated as 3 by the game
protection: 4 minecraft:protection: 4
fire_protection: 4 minecraft:fire_protection: 4
blast_protection: 4 minecraft:blast_protection: 4
projectile_protection: 4 minecraft:projectile_protection: 4
feather_falling: 4 minecraft:feather_falling: 4
thorns: 3 minecraft:thorns: 3
respiration: 3 minecraft:respiration: 3
sharpness: 5 minecraft:sharpness: 5
smite: 5 minecraft:smite: 5
bane_of_arthropods: 5 minecraft:bane_of_arthropods: 5
knockback: 2 minecraft:knockback: 2
fire_aspect: 2 minecraft:fire_aspect: 2
looting: 3 minecraft:looting: 3
sweeping: 3 minecraft:sweeping: 3
sweeping_edge: 3 minecraft:sweeping_edge: 3
efficiency: 5 minecraft:efficiency: 5
unbreaking: 3 minecraft:unbreaking: 3
fortune: 3 minecraft:fortune: 3
power: 5 minecraft:power: 5
punch: 2 minecraft:punch: 2
luck_of_the_sea: 3 minecraft:luck_of_the_sea: 3
lure: 3 minecraft:lure: 3
frost_walker: 2 minecraft:frost_walker: 2
impaling: 5 minecraft:impaling: 5
riptide: 3 minecraft:riptide: 3
loyalty: 3 minecraft:loyalty: 3
piercing: 4 minecraft:piercing: 4
quick_charge: 3 minecraft:quick_charge: 3
soul_speed: 3 minecraft:soul_speed: 3
swift_sneak: 3 minecraft:swift_sneak: 3
density: 5
breach: 4
wind_burst: 3
# Multipliers used to calculate the enchantment's value in repair/combining # 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 # With default values protection 4 would have a value of 4 when
# coming from either a book (4 * 1) or an item (4 * 1) # coming from either a book (4 * 1) or an item (4 * 1)
enchant_values: enchant_values:
aqua_affinity: minecraft:aqua_affinity:
item: 4 item: 4
book: 2 book: 2
bane_of_arthropods: minecraft:bane_of_arthropods:
item: 2 item: 2
book: 1 book: 1
binding_curse: minecraft:binding_curse:
item: 8 item: 8
book: 4 book: 4
blast_protection: minecraft:blast_protection:
item: 4 item: 4
book: 2 book: 2
channeling: minecraft:channeling:
item: 8 item: 8
book: 4 book: 4
depth_strider: minecraft:depth_strider:
item: 4 item: 4
book: 2 book: 2
efficiency: minecraft:efficiency:
item: 1 item: 1
book: 1 book: 1
flame: minecraft:flame:
item: 4 item: 4
book: 2 book: 2
feather_falling: minecraft:feather_falling:
item: 2 item: 2
book: 1 book: 1
fire_aspect: minecraft:fire_aspect:
item: 4 item: 4
book: 2 book: 2
fire_protection: minecraft:fire_protection:
item: 2 item: 2
book: 1 book: 1
fortune: minecraft:fortune:
item: 4 item: 4
book: 2 book: 2
frost_walker: minecraft:frost_walker:
item: 4 item: 4
book: 2 book: 2
impaling: minecraft:impaling:
item: 4 item: 4
book: 2 book: 2
infinity: minecraft:infinity:
item: 8 item: 8
book: 4 book: 4
knockback: minecraft:knockback:
item: 2 item: 2
book: 1 book: 1
looting: minecraft:looting:
item: 4 item: 4
book: 2 book: 2
loyalty: minecraft:loyalty:
item: 1 item: 1
book: 1 book: 1
luck_of_the_sea: minecraft:luck_of_the_sea:
item: 4 item: 4
book: 2 book: 2
lure: minecraft:lure:
item: 4 item: 4
book: 2 book: 2
mending: minecraft:mending:
item: 4 item: 4
book: 2 book: 2
multishot: minecraft:multishot:
item: 4 item: 4
book: 2 book: 2
piercing: minecraft:piercing:
item: 1 item: 1
book: 1 book: 1
power: minecraft:power:
item: 1 item: 1
book: 1 book: 1
projectile_protection: minecraft:projectile_protection:
item: 2 item: 2
book: 1 book: 1
protection: minecraft:protection:
item: 1 item: 1
book: 1 book: 1
punch: minecraft:punch:
item: 4 item: 4
book: 2 book: 2
quick_charge: minecraft:quick_charge:
item: 2 item: 2
book: 1 book: 1
respiration: minecraft:respiration:
item: 4 item: 4
book: 2 book: 2
riptide: minecraft:riptide:
item: 4 item: 4
book: 2 book: 2
silk_touch: minecraft:silk_touch:
item: 8 item: 8
book: 4 book: 4
sharpness: minecraft:sharpness:
item: 1 item: 1
book: 1 book: 1
smite: minecraft:smite:
item: 2 item: 2
book: 1 book: 1
soul_speed: minecraft:soul_speed:
item: 8 item: 8
book: 4 book: 4
swift_sneak: minecraft:swift_sneak:
item: 8 item: 8
book: 4 book: 4
sweeping: minecraft:sweeping:
item: 4 item: 4
book: 2 book: 2
sweeping_edge: minecraft:sweeping_edge:
item: 4 item: 4
book: 2 book: 2
thorns: minecraft:thorns:
item: 8 item: 8
book: 4 book: 4
unbreaking: minecraft:unbreaking:
item: 2 item: 2
book: 1 book: 1
vanishing_curse: minecraft:vanishing_curse:
item: 8 item: 8
book: 4 book: 4
density:
item: 1 # Disable enchantment merging for level above the set value
book: 1 # Enchantment merging is when, for example, 2 unbreaking II book combine to give sharpness III
breach: # But Enchantment above this value can still be applied. following the previous example, we could still apply a unbreaking III book to a sword
item: 4 # Even if disable-merge-over of unbreaking is set to 2
book: 2 # -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent.
wind_burst: disable-merge-over:
item: 4 # Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla)
book: 2 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 # Whether to show debug logging
debug_log: false debug_log: false
@ -296,4 +295,3 @@ debug_log_verbose: false
force_protocolib: false force_protocolib: false
configVersion: 1.6.2 configVersion: 1.6.2
lowMinecraftVersion: '1.21'

View file

@ -17,278 +17,159 @@
# ---------------------------------------------------- # ----------------------------------------------------
restriction_aqua_affinity: restriction_aqua_affinity:
enchantments: enchantments: [ minecraft:aqua_affinity ]
- aqua_affinity notAffectedGroups: [ enchanted_book, helmets ]
notAffectedGroups:
- enchanted_book
- helmets
restriction_bane_of_arthropods: restriction_bane_of_arthropods:
enchantments: enchantments: [ minecraft:bane_of_arthropods ]
- bane_of_arthropods notAffectedGroups: [ enchanted_book, melee_weapons ]
notAffectedGroups:
- enchanted_book
- melee_weapons
- mace
restriction_blast_protection: restriction_blast_protection:
enchantments: enchantments: [ minecraft:blast_protection ]
- blast_protection notAffectedGroups: [ enchanted_book, armors ]
notAffectedGroups:
- enchanted_book
- armors
restriction_channeling: restriction_channeling:
enchantments: enchantments: [ minecraft:channeling ]
- channeling notAffectedGroups: [ enchanted_book, trident ]
notAffectedGroups:
- enchanted_book
- trident
restriction_binding_curse: restriction_binding_curse:
enchantments: enchantments: [ minecraft:binding_curse ]
- binding_curse notAffectedGroups: [ enchanted_book, wearable ]
notAffectedGroups:
- enchanted_book
- wearable
restriction_vanishing_curse: restriction_vanishing_curse:
enchantments: enchantments: [ minecraft:vanishing_curse ]
- vanishing_curse notAffectedGroups: [ enchanted_book, can_vanish ]
notAffectedGroups:
- enchanted_book
- can_vanish
restriction_depth_strider: restriction_depth_strider:
enchantments: enchantments: [ minecraft:depth_strider ]
- depth_strider notAffectedGroups: [ enchanted_book, boots ]
notAffectedGroups:
- enchanted_book
- boots
restriction_efficiency: restriction_efficiency:
enchantments: enchantments: [ minecraft:efficiency ]
- efficiency notAffectedGroups: [ enchanted_book, tools, shears ]
notAffectedGroups:
- enchanted_book
- tools
- shears
restriction_feather_falling: restriction_feather_falling:
enchantments: enchantments: [ minecraft:feather_falling ]
- feather_falling notAffectedGroups: [ enchanted_book, boots ]
notAffectedGroups:
- enchanted_book
- boots
restriction_fire_aspect: restriction_fire_aspect:
enchantments: enchantments: [ minecraft:fire_aspect ]
- fire_aspect notAffectedGroups: [ enchanted_book, swords ]
notAffectedGroups:
- enchanted_book
- swords
- mace
restriction_fire_protection: restriction_fire_protection:
enchantments: enchantments: [ minecraft:fire_protection ]
- fire_protection notAffectedGroups: [ enchanted_book, armors ]
notAffectedGroups:
- enchanted_book
- armors
restriction_flame: restriction_flame:
enchantments: enchantments: [ minecraft:flame ]
- flame notAffectedGroups: [ enchanted_book, bow ]
notAffectedGroups:
- enchanted_book
- bow
restriction_fortune: restriction_fortune:
enchantments: enchantments: [ minecraft:fortune ]
- fortune notAffectedGroups: [ enchanted_book, tools ]
notAffectedGroups:
- enchanted_book
- tools
restriction_frost_walker: restriction_frost_walker:
enchantments: enchantments: [ minecraft:frost_walker ]
- frost_walker notAffectedGroups: [ enchanted_book, boots ]
notAffectedGroups:
- enchanted_book
- boots
restriction_impaling: restriction_impaling:
enchantments: enchantments: [ minecraft:impaling ]
- impaling notAffectedGroups: [ enchanted_book, trident ]
notAffectedGroups:
- enchanted_book
- trident
restriction_infinity: restriction_infinity:
enchantments: enchantments: [ minecraft:infinity ]
- infinity notAffectedGroups: [ enchanted_book, bow ]
notAffectedGroups:
- enchanted_book
- bow
restriction_knockback: restriction_knockback:
enchantments: enchantments: [ minecraft:knockback ]
- knockback notAffectedGroups: [ enchanted_book, swords ]
notAffectedGroups:
- enchanted_book
- swords
restriction_looting: restriction_looting:
enchantments: enchantments: [ minecraft:looting ]
- looting notAffectedGroups: [ enchanted_book, swords ]
notAffectedGroups:
- enchanted_book
- swords
restriction_loyalty: restriction_loyalty:
enchantments: enchantments: [ minecraft:loyalty ]
- loyalty notAffectedGroups: [ enchanted_book, trident ]
notAffectedGroups:
- enchanted_book
- trident
restriction_lure: restriction_lure:
enchantments: enchantments: [ minecraft:lure ]
- lure notAffectedGroups: [ enchanted_book, fishing_rod ]
notAffectedGroups:
- enchanted_book
- fishing_rod
restriction_mending: restriction_mending:
enchantments: enchantments: [ minecraft:mending ]
- mending notAffectedGroups: [ enchanted_book, can_unbreak ]
notAffectedGroups:
- enchanted_book
- can_unbreak
restriction_multishot: restriction_minecraft_multishot:
enchantments: enchantments: [ minecraft:multishot ]
- multishot notAffectedGroups: [ enchanted_book, crossbow ]
notAffectedGroups:
- enchanted_book
- crossbow
restriction_piercing: restriction_piercing:
enchantments: enchantments: [ minecraft:piercing ]
- piercing notAffectedGroups: [ enchanted_book, crossbow ]
notAffectedGroups:
- enchanted_book
- crossbow
restriction_power: restriction_power:
enchantments: enchantments: [ minecraft:power ]
- power notAffectedGroups: [ enchanted_book, bow ]
notAffectedGroups:
- enchanted_book
- bow
restriction_projectile_protection: restriction_projectile_protection:
enchantments: enchantments: [ minecraft:projectile_protection ]
- projectile_protection notAffectedGroups: [ enchanted_book, armors ]
notAffectedGroups:
- enchanted_book
- armors
restriction_protection: restriction_protection:
enchantments: enchantments: [ minecraft:protection ]
- protection notAffectedGroups: [ enchanted_book, armors ]
notAffectedGroups:
- enchanted_book
- armors
restriction_punch: restriction_punch:
enchantments: enchantments: [ minecraft:punch ]
- punch notAffectedGroups: [ enchanted_book, bow ]
notAffectedGroups:
- enchanted_book
- bow
restriction_quick_charge: restriction_quick_charge:
enchantments: enchantments: [ minecraft:quick_charge ]
- quick_charge notAffectedGroups: [ enchanted_book, crossbow ]
notAffectedGroups:
- enchanted_book
- crossbow
restriction_respiration: restriction_respiration:
enchantments: enchantments: [ minecraft:respiration ]
- respiration notAffectedGroups: [ enchanted_book, helmets ]
notAffectedGroups:
- enchanted_book
- helmets
restriction_riptide: restriction_riptide:
enchantments: enchantments: [ minecraft:riptide ]
- riptide notAffectedGroups: [ enchanted_book, trident ]
notAffectedGroups:
- enchanted_book
- trident
restriction_sharpness: restriction_sharpness:
enchantments: enchantments: [ minecraft:sharpness ]
- sharpness notAffectedGroups: [ enchanted_book, melee_weapons ]
notAffectedGroups:
- enchanted_book
- melee_weapons
restriction_silk_touch: restriction__silk_touch:
enchantments: enchantments: [ minecraft:silk_touch ]
- silk_touch notAffectedGroups: [ enchanted_book, tools ]
notAffectedGroups:
- enchanted_book
- tools
restriction_smite: restriction_smite:
enchantments: enchantments: [ minecraft:smite ]
- smite notAffectedGroups: [ enchanted_book, melee_weapons ]
notAffectedGroups:
- enchanted_book
- melee_weapons
- mace
restriction_soul_speed: restriction_soul_speed:
enchantments: enchantments: [ minecraft:soul_speed ]
- soul_speed notAffectedGroups: [ enchanted_book, boots ]
notAffectedGroups:
- enchanted_book
- boots
restriction_sweeping_edge: restriction_sweeping_edge:
enchantments: enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ]
- sweeping notAffectedGroups: [ enchanted_book, swords ]
- sweeping_edge
notAffectedGroups:
- enchanted_book
- swords
# Do not exist in 1.18, that mean useInFuture will be set to true # 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 # useInFuture set to true also mean it will not warn if there is an issue
restriction_swift_sneak: restriction_swift_sneak:
useInFuture: true useInFuture: true
enchantments: enchantments: [ minecraft:swift_sneak ]
- swift_sneak notAffectedGroups: [ enchanted_book, leggings ]
notAffectedGroups:
- enchanted_book
- leggings
restriction_thorns: restriction_thorns:
enchantments: enchantments: [ minecraft:thorns ]
- thorns notAffectedGroups: [ enchanted_book, armors ]
notAffectedGroups:
- enchanted_book
- armors
restriction_unbreaking: restriction__unbreaking:
enchantments: enchantments: [ minecraft:unbreaking ]
- unbreaking notAffectedGroups: [ enchanted_book, can_unbreak ]
notAffectedGroups:
- enchanted_book
- can_unbreak
# ---------------------------------------------------- # ----------------------------------------------------
# Now we have conflicts about enchantment Incompatibility # Now we have conflicts about enchantment Incompatibility
@ -299,87 +180,62 @@ restriction_unbreaking:
sword_enchant_conflict: sword_enchant_conflict:
enchantments: enchantments:
- bane_of_arthropods - minecraft:bane_of_arthropods
- smite - minecraft:smite
- sharpness - minecraft:sharpness
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
protection_enchant_conflict: protection_enchant_conflict:
enchantments: enchantments:
- blast_protection - minecraft:blast_protection
- fire_protection - minecraft:fire_protection
- projectile_protection - minecraft:projectile_protection
- protection - minecraft:protection
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
trident_conflict1: trident_conflict1:
enchantments: enchantments:
- channeling - minecraft:channeling
- riptide - minecraft:riptide
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
trident_conflict2: trident_conflict2:
enchantments: enchantments:
- loyalty - minecraft:loyalty
- riptide - minecraft:riptide
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
boot_conflict: boot_conflict:
enchantments: enchantments:
- depth_strider - minecraft:depth_strider
- frost_walker - minecraft:frost_walker
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
tool_conflict: tool_conflict:
enchantments: enchantments:
- fortune - minecraft:fortune
- silk_touch - minecraft:silk_touch
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
bow_conflict: bow_conflict:
enchantments: enchantments:
- mending - minecraft:mending
- infinity - minecraft:infinity
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
crossbow_conflict: crossbow_conflict:
enchantments: enchantments:
- multishot - minecraft:multishot
- piercing - minecraft:piercing
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 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
maxEnchantmentBeforeConflict: 1
# ---------------------------------------------------- # ----------------------------------------------------
# Bellow is for custom conflicts. # Bellow is for custom conflicts.

View file

@ -121,6 +121,7 @@ wearable:
- player_head - player_head
- creeper_head - creeper_head
- dragon_head - dragon_head
# do not exist in 1.18 but exist in future update
- piglin_head - piglin_head
groups: groups:
- armors - armors
@ -187,6 +188,7 @@ can_unbreak:
- shield - shield
- carrot_on_a_stick - carrot_on_a_stick
- warped_fungus_on_a_stick - warped_fungus_on_a_stick
# do not exist in 1.18 but exist in future update
- brush - brush
groups: groups:
- melee_weapons - melee_weapons
@ -197,7 +199,6 @@ can_unbreak:
- crossbow - crossbow
- fishing_rod - fishing_rod
- shears - shears
- mace
can_vanish: can_vanish:
type: include type: include
@ -206,8 +207,4 @@ can_vanish:
groups: groups:
- wearable - wearable
- can_unbreak - can_unbreak
mace:
type: include
items:
- mace

View file

@ -188,5 +188,3 @@ warped_planks:
wooden_shovel: 0.25 wooden_shovel: 0.25
wooden_hoe: 0.25 wooden_hoe: 0.25
shield: 0.25 shield: 0.25
breeze_rod:
mace: 0.25

Binary file not shown.

BIN
libs/nightcore-2.6.4.jar Normal file

Binary file not shown.

View file

@ -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<Any>?
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
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if (view !is CraftInventoryView) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -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<Any>? {
if(view !is CraftInventoryView<*>) return null
val container = view.handle
return container.javaClass
}
}

View file

@ -119,7 +119,7 @@ public class ConflictAPI {
private static List<String> extractEnchantments(@NotNull ConflictBuilder builder){ private static List<String> extractEnchantments(@NotNull ConflictBuilder builder){
List<String> result = new ArrayList<>(builder.getEnchantmentNames()); List<String> result = new ArrayList<>(builder.getEnchantmentNames());
for (NamespacedKey enchantmentKey : builder.getEnchantmentKeys()) { for (NamespacedKey enchantmentKey : builder.getEnchantmentKeys()) {
result.add(enchantmentKey.getKey()); result.add(enchantmentKey.toString());
} }
return result; return result;

View file

@ -10,6 +10,7 @@ import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.group.*; import xyz.alexcrea.cuanvil.group.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
@ -372,7 +373,7 @@ public class ConflictBuilder {
*/ */
protected void appendEnchantments(@NotNull EnchantConflictGroup conflict){ protected void appendEnchantments(@NotNull EnchantConflictGroup conflict){
for (String enchantmentName : getEnchantmentNames()){ 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()); CustomAnvil.instance.getLogger().warning("Could not find enchantment " + enchantmentName + " for conflict " + getName());
ConflictAPI.logConflictOrigin(this); ConflictAPI.logConflictOrigin(this);
} }
@ -399,6 +400,24 @@ public class ConflictBuilder {
return true; 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<CAEnchantment> enchantments){
int numberValid = 0;
for (CAEnchantment enchantment : enchantments) {
if(appendEnchantment(conflict, enchantment)){
numberValid++;
}
}
return numberValid;
}
/** /**
* Extract group abstract material group. * Extract group abstract material group.
* *

View file

@ -18,6 +18,7 @@ import xyz.alexcrea.cuanvil.gui.config.global.EnchantCostConfigGui;
import xyz.alexcrea.cuanvil.gui.config.global.EnchantLimitConfigGui; import xyz.alexcrea.cuanvil.gui.config.global.EnchantLimitConfigGui;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -104,7 +105,7 @@ public class EnchantmentApi {
* @return True if successful. * @return True if successful.
*/ */
public static boolean unregisterEnchantment(@NotNull NamespacedKey key){ public static boolean unregisterEnchantment(@NotNull NamespacedKey key){
CAEnchantment enchantment = CAEnchantmentRegistry.getInstance().getByKey(key); CAEnchantment enchantment = CAEnchantment.getByKey(key);
return unregisterEnchantment(enchantment); return unregisterEnchantment(enchantment);
} }
@ -126,7 +127,7 @@ public class EnchantmentApi {
*/ */
@Nullable @Nullable
public static CAEnchantment getByKey(@NotNull NamespacedKey key){ 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 * @param name The name used to fetch
* @return The custom anvil enchantment of this name. null if not found. * @return The custom anvil enchantment of this name. null if not found.
* @deprecated use {@link #getListByName(String)}
*/ */
@Deprecated(since = "1.6.3")
@Nullable @Nullable
public static CAEnchantment getByName(@NotNull String name){ 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<CAEnchantment> getListByName(@NotNull String name){
return CAEnchantment.getListByName(name);
} }
/** /**
@ -167,9 +180,9 @@ public class EnchantmentApi {
private static void writeDefaultConfig(FileConfiguration defaultConfig, CAEnchantment enchantment) { 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(); EnchantmentRarity rarity = enchantment.defaultRarity();
defaultConfig.set(basePath + ".item", rarity.getItemValue()); defaultConfig.set(basePath + ".item", rarity.getItemValue());

View file

@ -12,6 +12,7 @@ import xyz.alexcrea.cuanvil.group.EnchantConflictGroup;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -226,12 +227,24 @@ public interface CAEnchantment {
} }
/** /**
* Gets a list of all the unoptimised enchantments. * Gets the enchantment by the provided name.
* @param name The enchantment name * @param name Name to fetch.
* @return List of enchantment. * @return Registered enchantment. null if absent.
*
* @deprecated use {@link #getListByName(String)}
*/ */
@Deprecated(since = "1.6.3")
static @Nullable CAEnchantment getByName(@NotNull String name){ static @Nullable CAEnchantment getByName(@NotNull String name){
return CAEnchantmentRegistry.getInstance().getByName(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<CAEnchantment> getListByName(@NotNull String name){
return CAEnchantmentRegistry.getInstance().getListByName(name);
}
} }

View file

@ -22,7 +22,7 @@ public class CAEnchantmentRegistry {
// Register enchantment functions // Register enchantment functions
private final HashMap<NamespacedKey, CAEnchantment> byKeyMap; private final HashMap<NamespacedKey, CAEnchantment> byKeyMap;
private final HashMap<String, CAEnchantment> byNameMap; private final HashMap<String, List<CAEnchantment>> byNameMap;
private final SortedSet<CAEnchantment> nameSortedEnchantments; private final SortedSet<CAEnchantment> nameSortedEnchantments;
@ -62,6 +62,8 @@ public class CAEnchantmentRegistry {
} }
private static boolean hasWarnedRegistering = false;
/** /**
* Can be used to register new enchantment. * Can be used to register new enchantment.
* <p> * <p>
@ -73,19 +75,25 @@ public class CAEnchantmentRegistry {
public boolean register(@NotNull CAEnchantment enchantment){ public boolean register(@NotNull CAEnchantment enchantment){
if(byKeyMap.containsKey(enchantment.getKey())){ if(byKeyMap.containsKey(enchantment.getKey())){
CustomAnvil.instance.getLogger().log(Level.WARNING, 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")); new IllegalStateException(enchantment.getKey()+" enchantment was already registered"));
return false; return false;
} }
if(byNameMap.containsKey(enchantment.getName())){
if((!hasWarnedRegistering) && byNameMap.containsKey(enchantment.getName())){
hasWarnedRegistering = true;
CustomAnvil.instance.getLogger().log(Level.WARNING, CustomAnvil.instance.getLogger().log(Level.WARNING,
"Duplicate registered enchantment name. There will have issue. " + "Duplicate registered enchantment name. Please check that configuration is using namespace.");
"\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"));
} }
byKeyMap.put(enchantment.getKey(), enchantment); 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); nameSortedEnchantments.add(enchantment);
if(!enchantment.isGetOptimised()){ if(!enchantment.isGetOptimised()){
@ -112,7 +120,7 @@ public class CAEnchantmentRegistry {
public boolean unregister(@Nullable CAEnchantment enchantment){ public boolean unregister(@Nullable CAEnchantment enchantment){
if(enchantment == null) return false; if(enchantment == null) return false;
byKeyMap.remove(enchantment.getKey()); byKeyMap.remove(enchantment.getKey());
byNameMap.remove(enchantment.getName()); byNameMap.get(enchantment.getName()).remove(enchantment);
nameSortedEnchantments.remove(enchantment); nameSortedEnchantments.remove(enchantment);
@ -135,10 +143,26 @@ public class CAEnchantmentRegistry {
* Gets the enchantment by the provided name. * Gets the enchantment by the provided name.
* @param name Name to fetch. * @param name Name to fetch.
* @return Registered enchantment. null if absent. * @return Registered enchantment. null if absent.
*
* @deprecated use {@link #getListByName(String)}
*/ */
@Deprecated(since = "1.6.3")
@Nullable @Nullable
public CAEnchantment getByName(@NotNull String name){ public CAEnchantment getByName(@NotNull String name){
return byNameMap.get(name); List<CAEnchantment> 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<CAEnchantment> getListByName(@NotNull String name){
return byNameMap.getOrDefault(name, Collections.emptyList());
} }
/** /**

View file

@ -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<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
if(!definition.hasConflicts()) return false;
Set<String> conflicts = definition.getConflicts();
for (CAEnchantment caEnchantment : enchantments.keySet()) {
if(conflicts.contains(caEnchantment.getName())) return true;
}
return false;
}
@Override
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat, @NotNull ItemStack item) {
if(Material.ENCHANTED_BOOK.equals(itemMat)) return false;
return !definition.getSupportedItems().is(item);
}
}

View file

@ -30,7 +30,7 @@ public class MainConfigGui extends ChestGui {
public void init(PacketManager packetManager) { public void init(PacketManager packetManager) {
Pattern pattern = new Pattern( Pattern pattern = new Pattern(
GuiSharedConstant.EMPTY_GUI_FULL_LINE, GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"012304567", "012345678",
"Q00000000" "Q00000000"
); );
PatternPane pane = new PatternPane(0, 0, 9, 3, pattern); 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()); GuiItem enchantLimitItem = GuiGlobalItems.goToGuiItem(enchantLimitItemstack, new EnchantLimitConfigGui());
pane.bindItem('2', enchantLimitItem); 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 // enchant cost item
ItemStack enchantCostItemstack = new ItemStack(Material.EXPERIENCE_BOTTLE); ItemStack enchantCostItemstack = new ItemStack(Material.EXPERIENCE_BOTTLE);
ItemMeta enchantCostMeta = enchantCostItemstack.getItemMeta(); ItemMeta enchantCostMeta = enchantCostItemstack.getItemMeta();
@ -72,7 +84,7 @@ public class MainConfigGui extends ChestGui {
enchantCostItemstack.setItemMeta(enchantCostMeta); enchantCostItemstack.setItemMeta(enchantCostMeta);
GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, new EnchantCostConfigGui()); GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, new EnchantCostConfigGui());
pane.bindItem('3', enchantCostItem); pane.bindItem('4', enchantCostItem);
// Enchantment Conflicts item // Enchantment Conflicts item
ItemStack enchantConflictItemstack = new ItemStack(Material.OAK_FENCE); ItemStack enchantConflictItemstack = new ItemStack(Material.OAK_FENCE);
@ -84,7 +96,7 @@ public class MainConfigGui extends ChestGui {
enchantConflictItemstack.setItemMeta(enchantConflictMeta); enchantConflictItemstack.setItemMeta(enchantConflictMeta);
GuiItem enchantConflictItem = GuiGlobalItems.goToGuiItem(enchantConflictItemstack, EnchantConflictGui.getInstance()); GuiItem enchantConflictItem = GuiGlobalItems.goToGuiItem(enchantConflictItemstack, EnchantConflictGui.getInstance());
pane.bindItem('4', enchantConflictItem); pane.bindItem('5', enchantConflictItem);
// Group config items // Group config items
ItemStack groupItemstack = new ItemStack(Material.CHEST); ItemStack groupItemstack = new ItemStack(Material.CHEST);
@ -97,7 +109,7 @@ public class MainConfigGui extends ChestGui {
GuiItem groupConfigItem = GuiGlobalItems.goToGuiItem(groupItemstack, GroupConfigGui.getInstance()); GuiItem groupConfigItem = GuiGlobalItems.goToGuiItem(groupItemstack, GroupConfigGui.getInstance());
pane.bindItem('5', groupConfigItem); pane.bindItem('6', groupConfigItem);
// Unit repair item // Unit repair item
ItemStack unirRepairItemstack = new ItemStack(Material.DIAMOND); ItemStack unirRepairItemstack = new ItemStack(Material.DIAMOND);
@ -109,7 +121,7 @@ public class MainConfigGui extends ChestGui {
unirRepairItemstack.setItemMeta(unitRepairMeta); unirRepairItemstack.setItemMeta(unitRepairMeta);
GuiItem unitRepairItem = GuiGlobalItems.goToGuiItem(unirRepairItemstack, UnitRepairConfigGui.getInstance()); GuiItem unitRepairItem = GuiGlobalItems.goToGuiItem(unirRepairItemstack, UnitRepairConfigGui.getInstance());
pane.bindItem('6', unitRepairItem); pane.bindItem('7', unitRepairItem);
// Custom recipe item // Custom recipe item
ItemStack customRecipeItemstack = new ItemStack(Material.CRAFTING_TABLE); ItemStack customRecipeItemstack = new ItemStack(Material.CRAFTING_TABLE);
@ -121,7 +133,7 @@ public class MainConfigGui extends ChestGui {
customRecipeItemstack.setItemMeta(customRecipeMeta); customRecipeItemstack.setItemMeta(customRecipeMeta);
GuiItem customRecipeItem = GuiGlobalItems.goToGuiItem(customRecipeItemstack, CustomRecipeConfigGui.getInstance()); GuiItem customRecipeItem = GuiGlobalItems.goToGuiItem(customRecipeItemstack, CustomRecipeConfigGui.getInstance());
pane.bindItem('7', customRecipeItem); pane.bindItem('8', customRecipeItem);
// quit item // quit item
ItemStack quitItemstack = new ItemStack(Material.BARRIER); ItemStack quitItemstack = new ItemStack(Material.BARRIER);

View file

@ -44,24 +44,16 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui<EnchantCostSe
@Override @Override
public EnchantCostSettingsGui.EnchantCostSettingFactory createFactory(CAEnchantment enchant) { public EnchantCostSettingsGui.EnchantCostSettingFactory createFactory(CAEnchantment enchant) {
String key = enchant.getKey().getKey().toLowerCase(Locale.ENGLISH); String key = enchant.getKey().toString().toLowerCase(Locale.ENGLISH);
String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key); String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key.replace(":", "_"));
// try to find rarity. default to 0 if not found return new EnchantCostSettingsGui.EnchantCostSettingFactory(prettyKey + " Cost", this,
EnchantmentRarity rarity = enchant.defaultRarity(); SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG,
try {
rarity = EnchantmentProperties.valueOf(key.toUpperCase(Locale.ENGLISH)).getRarity();
} catch (IllegalArgumentException ignored) {
}
return EnchantCostSettingsGui.enchantCostFactory(prettyKey + " Level Cost", this,
ConfigHolder.DEFAULT_CONFIG, SECTION_NAME + '.' + key,
Arrays.asList( Arrays.asList(
"§7How many level should " + prettyKey, "§7How many level should " + prettyKey,
"§7cost when applied by book or by another item." "§7cost when applied by book or by another item."
), ),
0, 255, enchant, 0, 255,
rarity.getItemValue(), rarity.getBookValue(),
1, 10, 50); 1, 10, 50);
} }

View file

@ -1,6 +1,7 @@
package xyz.alexcrea.cuanvil.gui.config.global; package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import io.delilaheve.util.ConfigOptions;
import org.bukkit.Material; import org.bukkit.Material;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
@ -37,17 +38,23 @@ public class EnchantLimitConfigGui extends AbstractEnchantConfigGui<IntSettingsG
@Override @Override
public IntSettingsGui.IntSettingFactory createFactory(CAEnchantment enchant) { public IntSettingsGui.IntSettingFactory createFactory(CAEnchantment enchant) {
String key = enchant.getKey().getKey().toLowerCase(Locale.ROOT); String key = enchant.getKey().toString().toLowerCase(Locale.ROOT);
String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key); String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key.replace(":", "_"));
return new IntSettingsGui.IntSettingFactory(prettyKey + " Level Limit", this, return new IntSettingsGui.IntSettingFactory(prettyKey + " Limit", this,
SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG, SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG,
Collections.singletonList( Collections.singletonList(
"§7Maximum applied level of " + prettyKey "§7Maximum applied level of " + prettyKey
), ),
0, 255, 0, 255,
enchant.defaultMaxLevel(), enchant.defaultMaxLevel(),
1, 5, 10, 50, 100); 1, 5, 10, 50, 100){
@Override
public int getConfiguredValue() {
return ConfigOptions.INSTANCE.enchantLimit(enchant);
}
};
} }
@Override @Override

View file

@ -0,0 +1,67 @@
package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import io.delilaheve.util.ConfigOptions;
import org.bukkit.Material;
import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.Arrays;
import java.util.Locale;
public class EnchantMergeLimitConfigGui extends AbstractEnchantConfigGui<IntSettingsGui.IntSettingFactory> {
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());
}
}

View file

@ -258,7 +258,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
String[] enchantKeys = new String[enchantments.size()]; String[] enchantKeys = new String[enchantments.size()];
int index = 0; int index = 0;
for (CAEnchantment enchantment : enchantments) { for (CAEnchantment enchantment : enchantments) {
enchantKeys[index++] = enchantment.getKey().getKey(); enchantKeys[index++] = enchantment.getKey().toString();
} }
ConfigHolder.CONFLICT_HOLDER.getConfig().set(enchantConflict + ".enchantments", enchantKeys); ConfigHolder.CONFLICT_HOLDER.getConfig().set(enchantConflict + ".enchantments", enchantKeys);

View file

@ -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.PatternPane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern; import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import io.delilaheve.CustomAnvil; import io.delilaheve.CustomAnvil;
import io.delilaheve.util.ConfigOptions;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemFlag;
@ -13,6 +14,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
@ -237,43 +239,13 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
return super.hadChange() || nowBook != beforeBook; 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<String> 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. * A factory for an enchantment cost setting gui that hold setting's information.
*/ */
public static class EnchantCostSettingFactory extends IntSettingsGui.IntSettingFactory { public static class EnchantCostSettingFactory extends IntSettingsGui.IntSettingFactory {
int defaultBookVal; int defaultBookVal;
@NotNull CAEnchantment enchantment;
/** /**
* Constructor for an enchantment cost setting gui factory. * Constructor for an enchantment cost setting gui factory.
@ -285,25 +257,27 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
* @param displayLore Gui display item lore. * @param displayLore Gui display item lore.
* @param min Minimum value of this setting. * @param min Minimum value of this setting.
* @param max Maximum value of this setting. * @param max Maximum value of this setting.
* @param defaultItemVal Default item value if not found on the config. * @param enchantment Enchantment to change the cost to
* @param defaultBookVal Default book value if not found on the config.
* @param steps List of step the value can increment/decrement. * @param steps List of step the value can increment/decrement.
* List's size should be between 1 (included) and 3 (included). * List's size should be between 1 (included) and 3 (included).
* it is visually preferable to have an odd number of step. * it is visually preferable to have an odd number of step.
* If step only contain 1 value, no step item should be displayed. * If step only contain 1 value, no step item should be displayed.
*/ */
protected EnchantCostSettingFactory( public EnchantCostSettingFactory(
@NotNull String title, ValueUpdatableGui parent, @NotNull String title, ValueUpdatableGui parent,
@NotNull String configPath, @NotNull ConfigHolder config, @NotNull String configPath, @NotNull ConfigHolder config,
@Nullable List<String> displayLore, @Nullable List<String> displayLore,
int min, int max, int defaultItemVal, int defaultBookVal, @NotNull CAEnchantment enchantment,
int... steps) { int min, int max, int... steps) {
super(title, parent, super(title, parent,
configPath, config, configPath, config,
displayLore, displayLore,
min, max, defaultItemVal, steps); min, max, enchantment.defaultRarity().getItemValue(),
this.defaultBookVal = defaultBookVal; steps);
this.defaultBookVal = enchantment.defaultRarity().getBookValue();
this.enchantment = enchantment;
} }
/** /**
@ -311,14 +285,14 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
*/ */
@Override @Override
public int getConfiguredValue() { 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. * @return The configured value for the enchant setting book value.
*/ */
public int getConfiguredBookValue() { public int getConfiguredBookValue() {
return this.config.getConfig().getInt(this.configPath + BOOK_PATH, this.defaultBookVal); return ConfigOptions.INSTANCE.enchantmentValue(enchantment, true);
} }
@Override @Override

View file

@ -45,13 +45,13 @@ public class Update_1_21 {
addToStringList(groupConfig, "can_unbreak.groups", "mace"); addToStringList(groupConfig, "can_unbreak.groups", "mace");
// Add new enchant conflicts // 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_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_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"); addToStringList(conflictConfig, "restriction_wind_burst.notAffectedGroups", "mace", "enchanted_book");
// Add mace to conflicts // Add mace to conflicts
@ -59,13 +59,14 @@ public class Update_1_21 {
addToStringList(conflictConfig, "restriction_smite.notAffectedGroups", "mace"); addToStringList(conflictConfig, "restriction_smite.notAffectedGroups", "mace");
addToStringList(conflictConfig, "restriction_bane_of_arthropods.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); conflictConfig.set("mace_enchant_conflict.maxEnchantmentBeforeConflict", 1);
// Add level limit // Add level limit
baseConfig.set("enchant_limits.density", 5); baseConfig.set("enchant_limits.minecraft:density", 5);
baseConfig.set("enchant_limits.breach", 4); baseConfig.set("enchant_limits.minecraft:breach", 4);
baseConfig.set("enchant_limits.wind_burst", 3); baseConfig.set("enchant_limits.minecraft:wind_burst", 3);
// Add enchant values // Add enchant values
baseConfig.set("enchant_values.density.item", 1); baseConfig.set("enchant_values.density.item", 1);

View file

@ -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
}

View file

@ -13,7 +13,10 @@ import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui import xyz.alexcrea.cuanvil.gui.config.MainConfigGui
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant 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.ChatEventListener
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
import xyz.alexcrea.cuanvil.update.PluginSetDefault import xyz.alexcrea.cuanvil.update.PluginSetDefault
import xyz.alexcrea.cuanvil.update.Update_1_21 import xyz.alexcrea.cuanvil.update.Update_1_21
import xyz.alexcrea.cuanvil.update.plugin.PluginUpdates import xyz.alexcrea.cuanvil.update.plugin.PluginUpdates
@ -110,7 +113,9 @@ class CustomAnvil : JavaPlugin() {
DependencyManager.loadDependency() DependencyManager.loadDependency()
// Register anvil events // 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 // Load metrics
Metrics(this, bstatsPluginId) Metrics(this, bstatsPluginId)

View file

@ -41,6 +41,8 @@ object ConfigOptions {
const val ENCHANT_LIMIT_ROOT = "enchant_limits" const val ENCHANT_LIMIT_ROOT = "enchant_limits"
const val ENCHANT_VALUES_ROOT = "enchant_values" const val ENCHANT_VALUES_ROOT = "enchant_values"
const val DISABLE_MERGE_OVER_ROOT = "disable-merge-over"
// Keys for specific enchantment values // Keys for specific enchantment values
private const val KEY_BOOK = "book" private const val KEY_BOOK = "book"
private const val KEY_ITEM = "item" private const val KEY_ITEM = "item"
@ -110,6 +112,9 @@ object ConfigOptions {
// Default value for an enchantment multiplier // Default value for an enchantment multiplier
private const val DEFAULT_ENCHANT_VALUE = 0 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 // Get methods
// ------------- // -------------
@ -296,21 +301,28 @@ object ConfigOptions {
* Get the given [enchantment]'s limit * Get the given [enchantment]'s limit
*/ */
fun enchantLimit(enchantment: CAEnchantment): Int { 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 * Get the given [enchantmentName]'s limit
*/ */
private fun enchantLimit(enchantmentName: String): Int { private fun enchantLimit(enchantmentName: String): Int? {
val default = getDefaultLevel(enchantmentName)
val path = "${ENCHANT_LIMIT_ROOT}.$enchantmentName" val path = "${ENCHANT_LIMIT_ROOT}.$enchantmentName"
return CustomAnvil.instance return CustomAnvil.instance
.config .config
.getInt(path, default) .getInt(path, ENCHANT_LIMIT_RANGE.first-1)
.takeIf { it in ENCHANT_LIMIT_RANGE } .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 private fun getDefaultLevel(enchantmentName: String, // compatibility with 1.20.5. TODO better update system
) : Int { ) : Int {
if(enchantmentName == "sweeping_edge"){ if(enchantmentName == "sweeping_edge"){
return enchantLimit("sweeping") val limit = enchantLimit("sweeping")
if(limit != null) return limit
} }
return defaultEnchantLimit return defaultEnchantLimit
} }
@ -332,7 +346,17 @@ object ConfigOptions {
enchantment: CAEnchantment, enchantment: CAEnchantment,
isFromBook: Boolean isFromBook: Boolean
): Int { ): 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( private fun enchantmentValue(
enchantmentName: String, enchantmentName: String,
isFromBook: Boolean isFromBook: Boolean
): Int { ): Int? {
val default = getDefaultValue(enchantmentName, isFromBook)
val typeKey = if (isFromBook) KEY_BOOK else KEY_ITEM val typeKey = if (isFromBook) KEY_BOOK else KEY_ITEM
val path = "${ENCHANT_VALUES_ROOT}.${enchantmentName}.$typeKey" val path = "${ENCHANT_VALUES_ROOT}.${enchantmentName}.$typeKey"
return CustomAnvil.instance return CustomAnvil.instance
.config .config
.getInt(path, default) .getInt(path, DEFAULT_ENCHANT_VALUE - 1)
.takeIf { it >= DEFAULT_ENCHANT_VALUE } .takeIf { it >= DEFAULT_ENCHANT_VALUE }
?: DEFAULT_ENCHANT_VALUE
} }
/** /**
* Get default value if enchantment do not exist on config * 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 { 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)
return if(isFromBook) rarity.bookValue rarity.bookValue
else rarity.itemValue else
rarity.itemValue
} }
return DEFAULT_ENCHANT_VALUE /**
* 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_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 }
} }
} }

View file

@ -76,7 +76,11 @@ object EnchantmentUtil {
} }
// ... and they're the same level // ... and they're the same level
else { 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 var newLevel = oldLevel + 1
newLevel = max(min(newLevel, maxLevel), oldLevel) newLevel = max(min(newLevel, maxLevel), oldLevel)
this[enchantment] = newLevel this[enchantment] = newLevel

View file

@ -6,6 +6,8 @@ import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.AnvilInventory
import xyz.alexcrea.cuanvil.config.ConfigHolder 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.PacketManager
import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector
import xyz.alexcrea.cuanvil.dependency.scheduler.BukkitScheduler import xyz.alexcrea.cuanvil.dependency.scheduler.BukkitScheduler
@ -17,8 +19,12 @@ object DependencyManager {
var isFolia: Boolean = false var isFolia: Boolean = false
lateinit var scheduler: TaskScheduler lateinit var scheduler: TaskScheduler
lateinit var packetManager: PacketManager lateinit var packetManager: PacketManager
var externGuiTester: ExternGuiTester? = null
var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null
var ecoEnchantCompatibility: EcoEnchantDependency? = null var ecoEnchantCompatibility: EcoEnchantDependency? = null
var excellentEnchantsCompatibility: ExcellentEnchantsDependency? = null
var disenchantmentCompatibility: DisenchantmentDependency? = null var disenchantmentCompatibility: DisenchantmentDependency? = null
fun loadDependency(){ fun loadDependency(){
@ -35,6 +41,7 @@ object DependencyManager {
// Packet Manager // Packet Manager
val forceProtocolib = ConfigHolder.DEFAULT_CONFIG.config.getBoolean("force_protocolib", false) val forceProtocolib = ConfigHolder.DEFAULT_CONFIG.config.getBoolean("force_protocolib", false)
packetManager = PacketManagerSelector.selectPacketManager(forceProtocolib) packetManager = PacketManagerSelector.selectPacketManager(forceProtocolib)
externGuiTester = GuiTesterSelector.selectGuiTester
// Enchantment Squared dependency // Enchantment Squared dependency
if(pluginManager.isPluginEnabled("EnchantsSquared")){ if(pluginManager.isPluginEnabled("EnchantsSquared")){
@ -48,6 +55,12 @@ object DependencyManager {
ecoEnchantCompatibility!!.disableAnvilListener() ecoEnchantCompatibility!!.disableAnvilListener()
} }
// Excellent Enchants dependency
if(pluginManager.isPluginEnabled("ExcellentEnchants")){
excellentEnchantsCompatibility = ExcellentEnchantsDependency()
excellentEnchantsCompatibility!!.redirectListeners()
}
// Disenchantment dependency // Disenchantment dependency
if(pluginManager.isPluginEnabled("Disenchantment")){ if(pluginManager.isPluginEnabled("Disenchantment")){
disenchantmentCompatibility = DisenchantmentDependency() disenchantmentCompatibility = DisenchantmentDependency()
@ -64,6 +77,7 @@ object DependencyManager {
fun registerEnchantments() { fun registerEnchantments() {
enchantmentSquaredCompatibility?.registerEnchantments() enchantmentSquaredCompatibility?.registerEnchantments()
ecoEnchantCompatibility?.registerEnchantments() ecoEnchantCompatibility?.registerEnchantments()
excellentEnchantsCompatibility?.registerEnchantments()
} }
@ -79,16 +93,30 @@ object DependencyManager {
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent): Boolean { fun tryEventPreAnvilBypass(event: PrepareAnvilEvent): Boolean {
var bypass = false var bypass = false
// Test if disenchantment used special prepare anvil
if(disenchantmentCompatibility?.testPrepareAnvil(event) == true) bypass = true 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 return bypass
} }
fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean {
var bypass = false var bypass = false
// Test if disenchantment used special event click
if(disenchantmentCompatibility?.testAnvilResult(event, inventory) == true) bypass = true 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 return bypass
} }

View file

@ -4,13 +4,13 @@ import cz.kominekjan.disenchantment.events.DisenchantClickEvent
import cz.kominekjan.disenchantment.events.DisenchantEvent import cz.kominekjan.disenchantment.events.DisenchantEvent
import cz.kominekjan.disenchantment.events.ShatterClickEvent import cz.kominekjan.disenchantment.events.ShatterClickEvent
import cz.kominekjan.disenchantment.events.ShatterEvent import cz.kominekjan.disenchantment.events.ShatterEvent
import io.delilaheve.AnvilEventListener
import io.delilaheve.CustomAnvil import io.delilaheve.CustomAnvil
import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.AnvilInventory
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.plugin.RegisteredListener import org.bukkit.plugin.RegisteredListener
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
import xyz.alexcrea.cuanvil.util.AnvilXpUtil import xyz.alexcrea.cuanvil.util.AnvilXpUtil
class DisenchantmentDependency { class DisenchantmentDependency {
@ -26,7 +26,6 @@ class DisenchantmentDependency {
private lateinit var itemClickEvent: DisenchantClickEvent private lateinit var itemClickEvent: DisenchantClickEvent
fun redirectListeners() { fun redirectListeners() {
val toUnregister = ArrayList<RegisteredListener>() val toUnregister = ArrayList<RegisteredListener>()
// get required PrepareAnvilEvent listener // get required PrepareAnvilEvent listener
for (registeredListener in PrepareAnvilEvent.getHandlerList().registeredListeners) { for (registeredListener in PrepareAnvilEvent.getHandlerList().registeredListeners) {
@ -96,7 +95,7 @@ class DisenchantmentDependency {
} }
fun testAnvilResult(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { 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 // Test event if change the result
itemClickEvent.onDisenchantmentClickEvent(event) itemClickEvent.onDisenchantmentClickEvent(event)
@ -115,7 +114,7 @@ class DisenchantmentDependency {
} }
private fun testAnvilInventoryChange(inventory: AnvilInventory, previous: ItemStack?): Boolean { 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 return currentResult == previous
} }

View file

@ -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<RegisteredListener>()
// 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;
}
}

View file

@ -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
}
}
}

View file

@ -15,6 +15,9 @@ class EnchantConflictGroup(
fun addEnchantment(enchant: CAEnchantment) { fun addEnchantment(enchant: CAEnchantment) {
enchantments.add(enchant) enchantments.add(enchant)
} }
fun addEnchantments(enchants: List<CAEnchantment>) {
enchantments.addAll(enchants)
}
fun allowed(enchants: Set<CAEnchantment>, mat: Material): Boolean { fun allowed(enchants: Set<CAEnchantment>, mat: Material): Boolean {
if (enchantments.size < minBeforeBlock) { if (enchantments.size < minBeforeBlock) {

View file

@ -30,9 +30,9 @@ class EnchantConflictManager {
const val DEFAULT_GROUP_NAME = "joinedGroup" const val DEFAULT_GROUP_NAME = "joinedGroup"
// 1.20.5 compatibility TODO better update system // 1.20.5 compatibility TODO better update system
private val SWEEPING_EDGE_ENCHANT = private val SWEEPING_EDGE_ENCHANT = Collections.singletonList<CAEnchantment>(
CAEnchantment.getByKey(NamespacedKey.minecraft("sweeping_edge")) ?: 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 // Read and add enchantment to conflict
val enchantList = section.getStringList(ENCH_LIST_PATH) val enchantList = section.getStringList(ENCH_LIST_PATH)
for (enchantName in enchantList) { for (enchantName in enchantList) {
val enchant = getEnchantByName(enchantName) val enchants = getEnchantByIdentifier(enchantName)
if (enchant == null) { if (enchants.isEmpty()) {
if (!futureUse) { //TODO future use will be deprecated once the new update system is finished 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") CustomAnvil.instance.logger.warning("Enchantment $enchantName do not exist but was asked for conflict $conflictName")
} }
continue continue
} }
conflict.addEnchantment(enchant) conflict.addEnchantments(enchants)
} }
if (conflict.getEnchants().isEmpty()) { if (conflict.getEnchants().isEmpty()) {
if (!futureUse) { //TODO future use will be deprecated once the new update system is finished if (!futureUse) { //TODO future use will be deprecated once the new update system is finished
@ -112,16 +112,23 @@ class EnchantConflictManager {
return conflict return conflict
} }
private fun getEnchantByName(enchantName: String): CAEnchantment? { private fun getEnchantByIdentifier(enchantName: String): List<CAEnchantment> {
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 // Temporary solution for 1.20.5
when(enchantName){ when(enchantName){
"sweeping", "sweeping_edge" -> { "minecraft:sweeping", "sweeping",
"minecraft:sweeping_edge", "sweeping_edge" -> {
return SWEEPING_EDGE_ENCHANT return SWEEPING_EDGE_ENCHANT
} }
} }
return CAEnchantment.getByName(enchantName) return CAEnchantment.getListByName(enchantName)
} }

View file

@ -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)
}
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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)
}
}
}

View file

@ -97,46 +97,46 @@ default_limit: 5
# #
# Valid range of 1 - 255 for each enchantment # Valid range of 1 - 255 for each enchantment
enchant_limits: enchant_limits:
aqua_affinity: 1 minecraft:aqua_affinity: 1
binding_curse: 1 minecraft:binding_curse: 1
channeling: 1 minecraft:channeling: 1
flame: 1 minecraft:flame: 1
infinity: 1 minecraft:infinity: 1
mending: 1 minecraft:mending: 1
multishot: 1 minecraft:multishot: 1
silk_touch: 1 minecraft:silk_touch: 1
vanishing_curse: 1 minecraft:vanishing_curse: 1
depth_strider: 3 # anything more than 3 is treated as 3 by the game minecraft:depth_strider: 3 # anything more than 3 is treated as 3 by the game
protection: 4 minecraft:protection: 4
fire_protection: 4 minecraft:fire_protection: 4
blast_protection: 4 minecraft:blast_protection: 4
projectile_protection: 4 minecraft:projectile_protection: 4
feather_falling: 4 minecraft:feather_falling: 4
thorns: 3 minecraft:thorns: 3
respiration: 3 minecraft:respiration: 3
sharpness: 5 minecraft:sharpness: 5
smite: 5 minecraft:smite: 5
bane_of_arthropods: 5 minecraft:bane_of_arthropods: 5
knockback: 2 minecraft:knockback: 2
fire_aspect: 2 minecraft:fire_aspect: 2
looting: 3 minecraft:looting: 3
sweeping: 3 minecraft:sweeping: 3
sweeping_edge: 3 minecraft:sweeping_edge: 3
efficiency: 5 minecraft:efficiency: 5
unbreaking: 3 minecraft:unbreaking: 3
fortune: 3 minecraft:fortune: 3
power: 5 minecraft:power: 5
punch: 2 minecraft:punch: 2
luck_of_the_sea: 3 minecraft:luck_of_the_sea: 3
lure: 3 minecraft:lure: 3
frost_walker: 2 minecraft:frost_walker: 2
impaling: 5 minecraft:impaling: 5
riptide: 3 minecraft:riptide: 3
loyalty: 3 minecraft:loyalty: 3
piercing: 4 minecraft:piercing: 4
quick_charge: 3 minecraft:quick_charge: 3
soul_speed: 3 minecraft:soul_speed: 3
swift_sneak: 3 minecraft:swift_sneak: 3
# Multipliers used to calculate the enchantment's value in repair/combining # 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 # With default values protection 4 would have a value of 4 when
# coming from either a book (4 * 1) or an item (4 * 1) # coming from either a book (4 * 1) or an item (4 * 1)
enchant_values: enchant_values:
aqua_affinity: minecraft:aqua_affinity:
item: 4 item: 4
book: 2 book: 2
bane_of_arthropods: minecraft:bane_of_arthropods:
item: 2 item: 2
book: 1 book: 1
binding_curse: minecraft:binding_curse:
item: 8 item: 8
book: 4 book: 4
blast_protection: minecraft:blast_protection:
item: 4 item: 4
book: 2 book: 2
channeling: minecraft:channeling:
item: 8 item: 8
book: 4 book: 4
depth_strider: minecraft:depth_strider:
item: 4 item: 4
book: 2 book: 2
efficiency: minecraft:efficiency:
item: 1 item: 1
book: 1 book: 1
flame: minecraft:flame:
item: 4 item: 4
book: 2 book: 2
feather_falling: minecraft:feather_falling:
item: 2 item: 2
book: 1 book: 1
fire_aspect: minecraft:fire_aspect:
item: 4 item: 4
book: 2 book: 2
fire_protection: minecraft:fire_protection:
item: 2 item: 2
book: 1 book: 1
fortune: minecraft:fortune:
item: 4 item: 4
book: 2 book: 2
frost_walker: minecraft:frost_walker:
item: 4 item: 4
book: 2 book: 2
impaling: minecraft:impaling:
item: 4 item: 4
book: 2 book: 2
infinity: minecraft:infinity:
item: 8 item: 8
book: 4 book: 4
knockback: minecraft:knockback:
item: 2 item: 2
book: 1 book: 1
looting: minecraft:looting:
item: 4 item: 4
book: 2 book: 2
loyalty: minecraft:loyalty:
item: 1 item: 1
book: 1 book: 1
luck_of_the_sea: minecraft:luck_of_the_sea:
item: 4 item: 4
book: 2 book: 2
lure: minecraft:lure:
item: 4 item: 4
book: 2 book: 2
mending: minecraft:mending:
item: 4 item: 4
book: 2 book: 2
multishot: minecraft:multishot:
item: 4 item: 4
book: 2 book: 2
piercing: minecraft:piercing:
item: 1 item: 1
book: 1 book: 1
power: minecraft:power:
item: 1 item: 1
book: 1 book: 1
projectile_protection: minecraft:projectile_protection:
item: 2 item: 2
book: 1 book: 1
protection: minecraft:protection:
item: 1 item: 1
book: 1 book: 1
punch: minecraft:punch:
item: 4 item: 4
book: 2 book: 2
quick_charge: minecraft:quick_charge:
item: 2 item: 2
book: 1 book: 1
respiration: minecraft:respiration:
item: 4 item: 4
book: 2 book: 2
riptide: minecraft:riptide:
item: 4 item: 4
book: 2 book: 2
silk_touch: minecraft:silk_touch:
item: 8 item: 8
book: 4 book: 4
sharpness: minecraft:sharpness:
item: 1 item: 1
book: 1 book: 1
smite: minecraft:smite:
item: 2 item: 2
book: 1 book: 1
soul_speed: minecraft:soul_speed:
item: 8 item: 8
book: 4 book: 4
swift_sneak: minecraft:swift_sneak:
item: 8 item: 8
book: 4 book: 4
sweeping: minecraft:sweeping:
item: 4 item: 4
book: 2 book: 2
sweeping_edge: minecraft:sweeping_edge:
item: 4 item: 4
book: 2 book: 2
thorns: minecraft:thorns:
item: 8 item: 8
book: 4 book: 4
unbreaking: minecraft:unbreaking:
item: 2 item: 2
book: 1 book: 1
vanishing_curse: minecraft:vanishing_curse:
item: 8 item: 8
book: 4 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 # Whether to show debug logging
debug_log: false debug_log: false

View file

@ -17,158 +17,158 @@
# ---------------------------------------------------- # ----------------------------------------------------
restriction_aqua_affinity: restriction_aqua_affinity:
enchantments: [ aqua_affinity ] enchantments: [ minecraft:aqua_affinity ]
notAffectedGroups: [ enchanted_book, helmets ] notAffectedGroups: [ enchanted_book, helmets ]
restriction_bane_of_arthropods: restriction_bane_of_arthropods:
enchantments: [ bane_of_arthropods ] enchantments: [ minecraft:bane_of_arthropods ]
notAffectedGroups: [ enchanted_book, melee_weapons ] notAffectedGroups: [ enchanted_book, melee_weapons ]
restriction_blast_protection: restriction_blast_protection:
enchantments: [ blast_protection ] enchantments: [ minecraft:blast_protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_channeling: restriction_channeling:
enchantments: [ channeling ] enchantments: [ minecraft:channeling ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_binding_curse: restriction_binding_curse:
enchantments: [ binding_curse ] enchantments: [ minecraft:binding_curse ]
notAffectedGroups: [ enchanted_book, wearable ] notAffectedGroups: [ enchanted_book, wearable ]
restriction_vanishing_curse: restriction_vanishing_curse:
enchantments: [ vanishing_curse ] enchantments: [ minecraft:vanishing_curse ]
notAffectedGroups: [ enchanted_book, can_vanish ] notAffectedGroups: [ enchanted_book, can_vanish ]
restriction_depth_strider: restriction_depth_strider:
enchantments: [ depth_strider ] enchantments: [ minecraft:depth_strider ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_efficiency: restriction_efficiency:
enchantments: [ efficiency ] enchantments: [ minecraft:efficiency ]
notAffectedGroups: [ enchanted_book, tools, shears ] notAffectedGroups: [ enchanted_book, tools, shears ]
restriction_feather_falling: restriction_feather_falling:
enchantments: [ feather_falling ] enchantments: [ minecraft:feather_falling ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_fire_aspect: restriction_fire_aspect:
enchantments: [ fire_aspect ] enchantments: [ minecraft:fire_aspect ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
restriction_fire_protection: restriction_fire_protection:
enchantments: [ fire_protection ] enchantments: [ minecraft:fire_protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_flame: restriction_flame:
enchantments: [ flame ] enchantments: [ minecraft:flame ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_fortune: restriction_fortune:
enchantments: [ fortune ] enchantments: [ minecraft:fortune ]
notAffectedGroups: [ enchanted_book, tools ] notAffectedGroups: [ enchanted_book, tools ]
restriction_frost_walker: restriction_frost_walker:
enchantments: [ frost_walker ] enchantments: [ minecraft:frost_walker ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_impaling: restriction_impaling:
enchantments: [ impaling ] enchantments: [ minecraft:impaling ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_infinity: restriction_infinity:
enchantments: [ infinity ] enchantments: [ minecraft:infinity ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_knockback: restriction_knockback:
enchantments: [ knockback ] enchantments: [ minecraft:knockback ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
restriction_looting: restriction_looting:
enchantments: [ looting ] enchantments: [ minecraft:looting ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
restriction_loyalty: restriction_loyalty:
enchantments: [ loyalty ] enchantments: [ minecraft:loyalty ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_lure: restriction_lure:
enchantments: [ lure ] enchantments: [ minecraft:lure ]
notAffectedGroups: [ enchanted_book, fishing_rod ] notAffectedGroups: [ enchanted_book, fishing_rod ]
restriction_mending: restriction_mending:
enchantments: [ mending ] enchantments: [ minecraft:mending ]
notAffectedGroups: [ enchanted_book, can_unbreak ] notAffectedGroups: [ enchanted_book, can_unbreak ]
restriction_multishot: restriction_minecraft_multishot:
enchantments: [ multishot ] enchantments: [ minecraft:multishot ]
notAffectedGroups: [ enchanted_book, crossbow ] notAffectedGroups: [ enchanted_book, crossbow ]
restriction_piercing: restriction_piercing:
enchantments: [ piercing ] enchantments: [ minecraft:piercing ]
notAffectedGroups: [ enchanted_book, crossbow ] notAffectedGroups: [ enchanted_book, crossbow ]
restriction_power: restriction_power:
enchantments: [ power ] enchantments: [ minecraft:power ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_projectile_protection: restriction_projectile_protection:
enchantments: [ projectile_protection ] enchantments: [ minecraft:projectile_protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_protection: restriction_protection:
enchantments: [ protection ] enchantments: [ minecraft:protection ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_punch: restriction_punch:
enchantments: [ punch ] enchantments: [ minecraft:punch ]
notAffectedGroups: [ enchanted_book, bow ] notAffectedGroups: [ enchanted_book, bow ]
restriction_quick_charge: restriction_quick_charge:
enchantments: [ quick_charge ] enchantments: [ minecraft:quick_charge ]
notAffectedGroups: [ enchanted_book, crossbow ] notAffectedGroups: [ enchanted_book, crossbow ]
restriction_respiration: restriction_respiration:
enchantments: [ respiration ] enchantments: [ minecraft:respiration ]
notAffectedGroups: [ enchanted_book, helmets ] notAffectedGroups: [ enchanted_book, helmets ]
restriction_riptide: restriction_riptide:
enchantments: [ riptide ] enchantments: [ minecraft:riptide ]
notAffectedGroups: [ enchanted_book, trident ] notAffectedGroups: [ enchanted_book, trident ]
restriction_sharpness: restriction_sharpness:
enchantments: [ sharpness ] enchantments: [ minecraft:sharpness ]
notAffectedGroups: [ enchanted_book, melee_weapons ] notAffectedGroups: [ enchanted_book, melee_weapons ]
restriction_silk_touch: restriction__silk_touch:
enchantments: [ silk_touch ] enchantments: [ minecraft:silk_touch ]
notAffectedGroups: [ enchanted_book, tools ] notAffectedGroups: [ enchanted_book, tools ]
restriction_smite: restriction_smite:
enchantments: [ smite ] enchantments: [ minecraft:smite ]
notAffectedGroups: [ enchanted_book, melee_weapons ] notAffectedGroups: [ enchanted_book, melee_weapons ]
restriction_soul_speed: restriction_soul_speed:
enchantments: [ soul_speed ] enchantments: [ minecraft:soul_speed ]
notAffectedGroups: [ enchanted_book, boots ] notAffectedGroups: [ enchanted_book, boots ]
restriction_sweeping_edge: restriction_sweeping_edge:
enchantments: [ sweeping, sweeping_edge ] enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
# Do not exist in 1.18, that mean useInFuture will be set to true # 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 # useInFuture set to true also mean it will not warn if there is an issue
restriction_swift_sneak: restriction_swift_sneak:
useInFuture: true useInFuture: true
enchantments: [ swift_sneak ] enchantments: [ minecraft:swift_sneak ]
notAffectedGroups: [ enchanted_book, leggings ] notAffectedGroups: [ enchanted_book, leggings ]
restriction_thorns: restriction_thorns:
enchantments: [ thorns ] enchantments: [ minecraft:thorns ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]
restriction_unbreaking: restriction__unbreaking:
enchantments: [ unbreaking ] enchantments: [ minecraft:unbreaking ]
notAffectedGroups: [ enchanted_book, can_unbreak ] notAffectedGroups: [ enchanted_book, can_unbreak ]
# ---------------------------------------------------- # ----------------------------------------------------
@ -180,60 +180,60 @@ restriction_unbreaking:
sword_enchant_conflict: sword_enchant_conflict:
enchantments: enchantments:
- bane_of_arthropods - minecraft:bane_of_arthropods
- smite - minecraft:smite
- sharpness - minecraft:sharpness
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
protection_enchant_conflict: protection_enchant_conflict:
enchantments: enchantments:
- blast_protection - minecraft:blast_protection
- fire_protection - minecraft:fire_protection
- projectile_protection - minecraft:projectile_protection
- protection - minecraft:protection
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
trident_conflict1: trident_conflict1:
enchantments: enchantments:
- channeling - minecraft:channeling
- riptide - minecraft:riptide
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
trident_conflict2: trident_conflict2:
enchantments: enchantments:
- loyalty - minecraft:loyalty
- riptide - minecraft:riptide
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
boot_conflict: boot_conflict:
enchantments: enchantments:
- depth_strider - minecraft:depth_strider
- frost_walker - minecraft:frost_walker
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
tool_conflict: tool_conflict:
enchantments: enchantments:
- fortune - minecraft:fortune
- silk_touch - minecraft:silk_touch
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
bow_conflict: bow_conflict:
enchantments: enchantments:
- mending - minecraft:mending
- infinity - minecraft:infinity
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
crossbow_conflict: crossbow_conflict:
enchantments: enchantments:
- multishot - minecraft:multishot
- piercing - minecraft:piercing
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1

View file

@ -1,7 +1,7 @@
main: io.delilaheve.CustomAnvil main: io.delilaheve.CustomAnvil
name: CustomAnvil name: CustomAnvil
prefix: "Custom Anvil" prefix: "Custom Anvil"
version: 1.6.2 version: 1.6.3
folia-supported: true folia-supported: true
description: Allow to customise anvil mechanics description: Allow to customise anvil mechanics
api-version: 1.16 api-version: 1.16
@ -49,8 +49,8 @@ permissions:
description: Allow player to use hexadecimal color if permission is required (toggleable) 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 # soft depend on old name (UnsafeEnchantsPlus), so I can disable it if it is on the same server (old name for this plugin)
# as it is the old name for this plugin # Also depend to other plugin for compatibility
softdepend: softdepend:
- UnsafeEnchantsPlus - UnsafeEnchantsPlus
- ProtocolLib - ProtocolLib
@ -58,3 +58,4 @@ softdepend:
- EnchantsSquared - EnchantsSquared
- EcoEnchants - EcoEnchants
- eco - eco
- ExcellentEnchants