diff --git a/defaultconfigs/1.21.11/config.yml b/defaultconfigs/1.21.11/config.yml index c3ea6204..22de446f 100644 --- a/defaultconfigs/1.21.11/config.yml +++ b/defaultconfigs/1.21.11/config.yml @@ -476,6 +476,32 @@ monetary_cost: work_penalty: 1.0 # for work penalty (aka use penalty) recipe: 1.0 # for custom anvil recipe cost +# Chance that an anvil get degraded +# set it to zero if you wish to disable it +anvil_degradation: 0.12 + +# see https://www.digminecraft.com/lists/sound_list_pc.php +# for a list of most of the sounds +anvil_sound: + enabled: true + # The sound are weighted so if there is multiples of them one is selected randomly + # so if you want to add a "rare sound" as an easter egg you can ! + # If invalid, it will be removed from the list. and if empty it will use the default + use: + default: + sound: block.anvil.use + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + destroy: + default: + sound: block.anvil.destroy + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + # Whether to show debug logging debug_log: false diff --git a/defaultconfigs/1.21.9/config.yml b/defaultconfigs/1.21.9/config.yml index 614c8df0..4d1ae9d6 100644 --- a/defaultconfigs/1.21.9/config.yml +++ b/defaultconfigs/1.21.9/config.yml @@ -468,6 +468,33 @@ monetary_cost: work_penalty: 1.0 # for work penalty (aka use penalty) recipe: 1.0 # for custom anvil recipe cost +# Chance that an anvil get degraded +# set it to zero if you wish to disable it +anvil_degradation: 0.12 + +# see https://www.digminecraft.com/lists/sound_list_pc.php +# for a list of most of the sounds +anvil_sound: + enabled: true + # The sound are weighted so if there is multiples of them one is selected randomly + # so if you want to add a "rare sound" as an easter egg you can ! + # If invalid, it will be removed from the list. and if empty it will use the default + use: + default: + sound: block.anvil.use + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + destroy: + default: + sound: block.anvil.destroy + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + + # Whether to show debug logging debug_log: false diff --git a/defaultconfigs/1.21/config.yml b/defaultconfigs/1.21/config.yml index a0bcbd86..50b94f1b 100644 --- a/defaultconfigs/1.21/config.yml +++ b/defaultconfigs/1.21/config.yml @@ -456,6 +456,33 @@ monetary_cost: work_penalty: 1.0 # for work penalty (aka use penalty) recipe: 1.0 # for custom anvil recipe cost +# Chance that an anvil get degraded +# set it to zero if you wish to disable it +anvil_degradation: 0.12 + +# see https://www.digminecraft.com/lists/sound_list_pc.php +# for a list of most of the sounds +anvil_sound: + enabled: true + # The sound are weighted so if there is multiples of them one is selected randomly + # so if you want to add a "rare sound" as an easter egg you can ! + # If invalid, it will be removed from the list. and if empty it will use the default + use: + default: + sound: block.anvil.use + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + destroy: + default: + sound: block.anvil.destroy + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + + # Whether to show debug logging debug_log: false diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/config/AnvilFinishOptions.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/config/AnvilFinishOptions.kt new file mode 100644 index 00000000..4cda8d83 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/config/AnvilFinishOptions.kt @@ -0,0 +1,146 @@ +package xyz.alexcrea.cuanvil.config + +import io.delilaheve.CustomAnvil +import org.bukkit.NamespacedKey +import org.bukkit.Registry +import org.bukkit.Sound +import org.bukkit.SoundCategory +import org.bukkit.configuration.ConfigurationSection +import java.util.Random +import java.util.logging.Level + +object AnvilFinishOptions { + + data class ConfiguredSound( + val sound: Sound, + val category: SoundCategory, + val volume: Float, + val pitch: Float, + val weight: Double, + ) + + // Paths + private const val SOUND_ENABLED = "anvil_sound.enabled" + + private const val USE_SOUNDS_ROOT = "anvil_sound.use" + private const val DESTROY_SOUNDS_ROOT = "anvil_sound.destroy" + + private const val ANVIL_DEGRADATION_PATH = "anvil_degradation" + + // Defaults + private const val DEFAULT_SOUND_ENABLED = true + private val DEFAULT_USE_SOUND = ConfiguredSound( + Sound.BLOCK_ANVIL_USE, + SoundCategory.BLOCKS, + 1.0f, + 1.0f, + 1.0, + ) + + private val DEFAULT_DESTROY_SOUND = ConfiguredSound( + Sound.BLOCK_ANVIL_DESTROY, + SoundCategory.BLOCKS, + 1.0f, + 1.0f, + 1.0, + ) + private const val DEFAULT_ANVIL_DEGRADATION_PATH = 0.12 + + // Others + private val RANDOM = Random() + + // Fetch + val sound_enabled: Boolean + get() { + return ConfigHolder.DEFAULT_CONFIG + .config + .getBoolean(SOUND_ENABLED, DEFAULT_SOUND_ENABLED) + } + + fun getAnvilSound(wasDestroyed: Boolean): ConfiguredSound { + return if(wasDestroyed) + getRandomDestroySound() + else getRandomUseSound() + } + + val degradation_chance: Double + get() { + return ConfigHolder.DEFAULT_CONFIG + .config + .getDouble(ANVIL_DEGRADATION_PATH, DEFAULT_ANVIL_DEGRADATION_PATH) + } + + // Utils + private fun getRandomUseSound(): ConfiguredSound { + return fromListing(USE_SOUNDS_ROOT, DEFAULT_USE_SOUND) + } + + private fun getRandomDestroySound(): ConfiguredSound { + return fromListing(DESTROY_SOUNDS_ROOT, DEFAULT_DESTROY_SOUND) + } + + private fun fromListing(path: String, default: ConfiguredSound): ConfiguredSound { + val section = ConfigHolder.DEFAULT_CONFIG + .config.getConfigurationSection(path) ?: return default + + val list = readSounds(section) + return weightedRandom(list, default) + } + + private fun readSounds(section: ConfigurationSection): List { + val sounds = ArrayList() + + for (key in section.getKeys(false)) { + if(!section.isConfigurationSection(key)) continue + + val result = readSound(section.getConfigurationSection(key)!!) + if(result == null) { + CustomAnvil.instance.logger.warning("Couldn't read sounds for key $key") + continue + } + + sounds.add(result) + } + return sounds + } + + private fun readSound(section: ConfigurationSection): ConfiguredSound? { + val name = section.getString("sound", null)?: return null + val key = NamespacedKey.fromString(name)?: return null + val sound = Registry.SOUNDS.get(key)?: return null + + val categoryName = section.getString("category", null)?: return null + val category = try { + SoundCategory.valueOf(categoryName.uppercase()) + } catch (_: IllegalArgumentException) { + return null + } + + val volume = section.getDouble("volume", 1.0).toFloat() + val pitch = section.getDouble("pitch", 1.0).toFloat() + val weight = section.getDouble("weight", 1.0) + if(weight <= 0) return null + + return ConfiguredSound(sound, category, volume, pitch, weight) + } + + private fun weightedRandom(sounds: List, default: ConfiguredSound): ConfiguredSound { + if(sounds.isEmpty()) return default + + val weightSum = sounds.sumOf { it.weight } + if(weightSum == .0) return sounds.first() + + val selectedWeight = RANDOM.nextDouble(weightSum) + + var currentSum = .0 + sounds.forEach { + currentSum += it.weight + if(currentSum > selectedWeight) return it + } + + // What ? how + CustomAnvil.instance.logger.log(Level.SEVERE, "Something very... very wrong happen on sound handling. please report this to the developer") + return default + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt index 2bfc97d0..22821589 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt @@ -4,13 +4,16 @@ import io.delilaheve.CustomAnvil import io.delilaheve.util.ConfigOptions import io.delilaheve.util.ItemUtil.canMergeWith import org.bukkit.GameMode +import org.bukkit.Location 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.Listener import org.bukkit.event.inventory.ClickType import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.BookMeta import org.bukkit.inventory.view.AnvilView @@ -20,6 +23,7 @@ import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.AnvilResult import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.CustomCraftResult import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.LoreEditResult import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.UnitRepairResult +import xyz.alexcrea.cuanvil.config.AnvilFinishOptions import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentDisplayName @@ -349,7 +353,9 @@ class AnvilResultListener : Listener { player.inventory.setItem(slotDestination.slot, result.item) } - // TODO probably anvil damage & sound here ?? + if (event.click != ClickType.MIDDLE) + handleAnvilMechanic(player, view, player.gameMode != GameMode.CREATIVE) + return true } @@ -377,6 +383,68 @@ class AnvilResultListener : Listener { } } + // Process both sound & degradation + private fun handleAnvilMechanic(player: HumanEntity, view: AnvilView, canDegrade: Boolean) { + // ok so we do not provide a getLocation on view ? + val inv = view.topInventory as? AnvilInventory + val location = inv?.location + + val wasDestroyed = canDegrade && tryDegradeAnvil(view, location) + tryPlaySound(location, player, wasDestroyed) + } + + private fun tryDegradeAnvil(view: AnvilView, location: Location?): Boolean { + val world = location?.world ?: return false + if (Math.random() > AnvilFinishOptions.degradation_chance) return false + + val block = world.getBlockAt(location) + + val next = when (block.type) { + Material.ANVIL -> Material.CHIPPED_ANVIL + Material.CHIPPED_ANVIL -> Material.DAMAGED_ANVIL + Material.DAMAGED_ANVIL -> Material.AIR + else -> return false + } + + block.type = next + + if (next == Material.AIR) { + view.close() + return true + } + + return false + } + + private fun tryPlaySound( + location: Location?, + player: HumanEntity, + wasDestroyed: Boolean, + ) { + val world = location?.world + + if (!AnvilFinishOptions.sound_enabled) return + + val sound = AnvilFinishOptions.getAnvilSound(wasDestroyed) + if(world == null) { + player.world.playSound( + player, + sound.sound, + sound.category, + sound.volume, + sound.pitch, + ) + } else { + world.playSound( + location, + sound.sound, + sound.category, + sound.volume, + sound.pitch, + ) + } + } + private fun onUnitRepairExtract( rightItem: ItemStack, event: InventoryClickEvent, diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 6d946d4d..218c3a1f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -463,6 +463,32 @@ monetary_cost: work_penalty: 1.0 # for work penalty (aka use penalty) recipe: 1.0 # for custom anvil recipe cost +# Chance that an anvil get degraded +# set it to zero if you wish to disable it +anvil_degradation: 0.12 + +# see https://www.digminecraft.com/lists/sound_list_pc.php +# for a list of most of the sounds +anvil_sound: + enabled: true + # The sound are weighted so if there is multiples of them one is selected randomly + # so if you want to add a "rare sound" as an easter egg you can ! + # If invalid, it will be removed from the list. and if empty it will use the default + use: + default: + sound: block.anvil.use + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + destroy: + default: + sound: block.anvil.destroy + category: blocks + volume: 1.0 + pitch: 1.0 + weight: 1.0 + # Whether to show debug logging debug_log: false