Compare commits

...

6 commits

Author SHA1 Message Date
37cd603575
back to java 21 (oops !) 2026-07-11 23:17:05 +02:00
a49044b522
Backport of anvil sound and degradation #122 (#123) 2026-07-11 22:54:45 +02:00
5bd78b4444
backport anvil mechanic 2026-07-11 22:51:24 +02:00
c38e8025cd
sound & anvil damage done 2026-07-11 22:45:44 +02:00
3dd706b4a8
add sound & degradation in config 2026-07-11 22:45:44 +02:00
015ca99475
anvil sound & degrade basic feature
# Conflicts:
#	src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt
2026-07-11 22:45:39 +02:00
7 changed files with 309 additions and 2 deletions

View file

@ -32,7 +32,7 @@ jobs:
uses: actions/setup-java@v4
with:
java-version: |
25
21
distribution: 'temurin'
cache: gradle

View file

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

View file

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

View file

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

View file

@ -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<ConfiguredSound> {
val sounds = ArrayList<ConfiguredSound>()
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<ConfiguredSound>, 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
}
}

View file

@ -4,7 +4,9 @@ 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
@ -21,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
@ -354,7 +357,9 @@ class AnvilResultListener : Listener {
player.inventory.setItem(slotDestination.slot, result.item)
}
// TODO probably anvil damage & sound here ??
if (event.click != ClickType.MIDDLE)
handleAnvilMechanic(player, inventory, player.gameMode != GameMode.CREATIVE)
return true
}
@ -382,6 +387,56 @@ class AnvilResultListener : Listener {
}
}
// Process both sound & degradation
private fun handleAnvilMechanic(player: HumanEntity, inventory: AnvilInventory, canDegrade: Boolean) {
// ok so we do not provide a getLocation on view ?
val location = inventory.location
val wasDestroyed = canDegrade && tryDegradeAnvil(player, location)
tryPlaySound(location, wasDestroyed)
}
private fun tryDegradeAnvil(player: HumanEntity, 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) {
player.closeInventory()
return true
}
return false
}
private fun tryPlaySound(
location: Location?,
wasDestroyed: Boolean,
) {
val world = location?.world
if (!AnvilFinishOptions.sound_enabled) return
val sound = AnvilFinishOptions.getAnvilSound(wasDestroyed)
world?.playSound(
location,
sound.sound,
sound.category,
sound.volume,
sound.pitch,
)
}
private fun onUnitRepairExtract(
rightItem: ItemStack,
event: InventoryClickEvent,

View file

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