Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/main/java/com/gmail/nossr50/config/SoundConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,18 @@ public float getPitch(SoundType soundType) {
return (float) config.getDouble(key, 1.0);
}

public String getSound(SoundType soundType) {
String key = "Sounds." + soundType.toString() + ".ID";
return (String) config.getString(key);
}

public boolean getIsEnabled(SoundType soundType) {
String key = "Sounds." + soundType.toString() + ".Enabled";
Copy link

Copilot AI Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key construction uses '.Enabled' but the YAML configuration uses '.Enable' (without 'd'). This will cause the configuration lookup to fail and always return the default value.

Suggested change
String key = "Sounds." + soundType.toString() + ".Enabled";
String key = "Sounds." + soundType.toString() + ".Enable";

Copilot uses AI. Check for mistakes.
return config.getBoolean(key, true);
}

public boolean getCustomSoundEnabled() {
String key = "Sounds.EnableCustomSounds";
return config.getBoolean(key, true);
Copy link

Copilot AI Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value for EnableCustomSounds should be 'false' to match the configuration file default, not 'true'. This could cause unexpected behavior when the configuration is not explicitly set.

Suggested change
return config.getBoolean(key, true);
return config.getBoolean(key, false);

Copilot uses AI. Check for mistakes.
}
}
50 changes: 50 additions & 0 deletions src/main/java/com/gmail/nossr50/util/sounds/SoundLookup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.gmail.nossr50.util.sounds;

import org.bukkit.NamespacedKey;
import java.lang.reflect.*;
import java.util.Locale;

public final class SoundLookup {

private static final boolean USE_PAPER_REGISTRY;

static {
boolean paper = false;
try { Class.forName("org.bukkit.Registry"); paper = true; } catch (ClassNotFoundException ignored) {}
USE_PAPER_REGISTRY = paper;
}

public static boolean exists(String id) {
if (USE_PAPER_REGISTRY) return paperRegistryExists(id);
return legacyEnumExists(id);
}

private static boolean paperRegistryExists(String id) {
try {
Class<?> registry = Class.forName("org.bukkit.Registry");
Object soundReg = registry.getField("SOUND_EVENT").get(null);
Method get = soundReg.getClass().getMethod("get", NamespacedKey.class);
return get.invoke(soundReg, NamespacedKey.fromString(id)) != null;
Copy link

Copilot AI Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NamespacedKey.fromString(id) can throw IllegalArgumentException for invalid namespaced keys. This should be wrapped in a try-catch block to prevent the exception from propagating and causing the method to return false incorrectly.

Suggested change
return get.invoke(soundReg, NamespacedKey.fromString(id)) != null;
NamespacedKey key;
try {
key = NamespacedKey.fromString(id);
} catch (IllegalArgumentException e) {
return false;
}
return get.invoke(soundReg, key) != null;

Copilot uses AI. Check for mistakes.
} catch (Throwable t) { return false; }
}

private static boolean legacyEnumExists(String id) {
String constant = toEnumName(id);
try {
Class<?> c = Class.forName("org.bukkit.Sound");
if (c.isEnum()) {
Enum.valueOf((Class<? extends Enum>) c, constant);
return true;
} else {
c.getField(constant).get(null);
return true;
}
} catch (Throwable t) { return false; }
}

private static String toEnumName(String id) {
int i = id.indexOf(':');
String core = i >= 0 ? id.substring(i + 1) : id;
return core.replace('.', '_').toUpperCase(Locale.ROOT);
}
}
54 changes: 14 additions & 40 deletions src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,52 +98,26 @@ private static float getVolume(SoundType soundType) {
}

private static float getPitch(SoundType soundType) {
if (soundType == SoundType.FIZZ) {
return getFizzPitch();
} else if (soundType == SoundType.POP) {
return getPopPitch();
} else {
return SoundConfig.getInstance().getPitch(soundType);
}
}

private static Sound getSound(SoundType soundType) {
return switch (soundType) {
case ANVIL -> Sound.BLOCK_ANVIL_PLACE;
case ITEM_BREAK -> Sound.ENTITY_ITEM_BREAK;
case POP -> Sound.ENTITY_ITEM_PICKUP;
case CHIMAERA_WING -> Sound.ENTITY_BAT_TAKEOFF;
case LEVEL_UP -> Sound.ENTITY_PLAYER_LEVELUP;
case FIZZ -> Sound.BLOCK_FIRE_EXTINGUISH;
case TOOL_READY -> Sound.ITEM_ARMOR_EQUIP_GOLD;
case ROLL_ACTIVATED -> Sound.ENTITY_LLAMA_SWAG;
case SKILL_UNLOCKED -> Sound.UI_TOAST_CHALLENGE_COMPLETE;
case ABILITY_ACTIVATED_BERSERK, TIRED -> Sound.BLOCK_CONDUIT_AMBIENT;
case ABILITY_ACTIVATED_GENERIC -> Sound.ITEM_TRIDENT_RIPTIDE_3;
case DEFLECT_ARROWS, BLEED -> Sound.ENTITY_ENDER_EYE_DEATH;
case GLASS -> Sound.BLOCK_GLASS_BREAK;
case ITEM_CONSUMED -> Sound.ITEM_BOTTLE_EMPTY;
case CRIPPLE -> getCrippleSound();
return switch (soundType)
{
case FIZZ -> getFizzPitch();
case POP -> getPopPitch();
default -> SoundConfig.getInstance().getPitch(soundType);
};
}

private static Sound getCrippleSound() {
if (CRIPPLE_SOUND != null) {
return CRIPPLE_SOUND;
}
private static String getSound(SoundType soundType)
{
String sound = SoundConfig.getInstance().getSound(soundType);

try {
// Spigot changed the class from enum to interface around 1.21.3
final Class<?> clazz = Class.forName(ORG_BUKKIT_SOUND);
final Method valueOf = clazz.getMethod(VALUE_OF);
CRIPPLE_SOUND = (Sound) valueOf.invoke(null, ITEM_MACE_SMASH_GROUND);
} catch (IllegalArgumentException | ClassNotFoundException | NoSuchMethodException |
InvocationTargetException
| IllegalAccessException e) {
CRIPPLE_SOUND = Sound.BLOCK_ANVIL_PLACE;
if (SoundConfig.getInstance().getCustomSoundEnabled())
{
return sound;
}

return CRIPPLE_SOUND;
return SoundLookup.exists(sound)
? sound
: soundType.id();
}

public static float getFizzPitch() {
Expand Down
56 changes: 29 additions & 27 deletions src/main/java/com/gmail/nossr50/util/sounds/SoundType.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
package com.gmail.nossr50.util.sounds;

public enum SoundType {
ANVIL,
LEVEL_UP,
FIZZ,
ITEM_BREAK,
POP,
CHIMAERA_WING,
ROLL_ACTIVATED,
SKILL_UNLOCKED,
DEFLECT_ARROWS,
TOOL_READY,
ABILITY_ACTIVATED_GENERIC,
ABILITY_ACTIVATED_BERSERK,
BLEED,
GLASS,
ITEM_CONSUMED,
CRIPPLE,
TIRED;

public boolean usesCustomPitch() {
switch (this) {
case POP:
case FIZZ:
return true;
default:
return false;
}
ANVIL("minecraft:block.anvil.place"),
ITEM_BREAK("minecraft:entity.item.break"),
POP("minecraft:entity.item.pickup"),
CHIMAERA_WING("minecraft:entity.bat.takeoff"),
LEVEL_UP("minecraft:entity.player.levelup"),
FIZZ("minecraft:block.fire.extinguish"),
TOOL_READY("minecraft:item.armor.equip_gold"),
ROLL_ACTIVATED("minecraft:entity.llama.swag"),
SKILL_UNLOCKED("minecraft:ui.toast.challenge_complete"),
ABILITY_ACTIVATED_BERSERK("minecraft:block.conduit.ambient"),
TIRED("minecraft:block.conduit.ambient"),
ABILITY_ACTIVATED_GENERIC("minecraft:item.trident.riptide_3"),
DEFLECT_ARROWS("minecraft:entity.ender_eye.death"),
BLEED("minecraft:entity.ender_eye.death"),
GLASS("minecraft:block.glass.break"),
ITEM_CONSUMED("minecraft:item.bottle.empty"),
CRIPPLE("minecraft:block.anvil.place");
Copy link

Copilot AI Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CRIPPLE sound is using 'minecraft:block.anvil.place' as fallback, but based on the sounds.yml configuration, it should use 'minecraft:item.mace.smash_ground'. This inconsistency means the fallback won't match the configured sound ID.

Suggested change
CRIPPLE("minecraft:block.anvil.place");
CRIPPLE("minecraft:item.mace.smash_ground");

Copilot uses AI. Check for mistakes.

private final String id;
SoundType(String id) { this.id = id; }
public String id() { return id; }

public boolean usesCustomPitch()
{
return switch (this) {
case POP, FIZZ -> true;
default -> false;
};
}
}
}
21 changes: 20 additions & 1 deletion src/main/resources/sounds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,90 @@ Sounds:
# 1.0 = Max volume
# 0.0 = No Volume
MasterVolume: 1.0
# Enable this to allow sounds from resource packs. WARNING: This will disable default sound fallback if your ID is invalid!
EnableCustomSounds: false
ITEM_CONSUMED:
Enable: true
Volume: 1.0
Pitch: 1.0
ID: "minecraft:item.bottle.empty"
GLASS:
Enable: true
Volume: 1.0
Pitch: 1.0
ID: "minecraft:block.glass.break"
ANVIL:
Enable: true
Volume: 1.0
Pitch: 0.3
ID: "minecraft:block.anvil.place"
#Fizz, and Pop make use of a adding and multiplying random numbers together to make a unique pitch everytime they are heard
FIZZ:
Enable: true
Volume: 0.5
ID: "minecraft:block.fire.extinguish"
LEVEL_UP:
Enable: true
Volume: 0.3
Pitch: 0.5
ID: "minecraft:entity.player.levelup"
ITEM_BREAK:
Enable: true
Volume: 1.0
Pitch: 1.0
ID: "minecraft:entity.item.break"
#Fizz, and Pop make use of a adding and multiplying random numbers together to make a unique pitch everytime they are heard
POP:
Enable: true
Volume: 0.2
ID: "minecraft:entity.item.pickup"
CHIMAERA_WING:
Enable: true
Volume: 1.0
Pitch: 0.6
ID: "minecraft:entity.bat.takeoff"
ROLL_ACTIVATED:
Enable: true
Volume: 1.0
Pitch: 0.7
ID: "minecraft:entity.llama.swag"
SKILL_UNLOCKED:
Enable: true
Volume: 1.0
Pitch: 1.4
ID: "minecraft:ui.toast.challenge_complete"
DEFLECT_ARROWS:
Enable: true
Volume: 1.0
Pitch: 2.0
ID: "minecraft:entity.ender_eye.death"
TOOL_READY:
Enable: true
Volume: 1.0
Pitch: 0.4
ID: "minecraft:item.armor.equip_gold"
ABILITY_ACTIVATED_GENERIC:
Enable: true
Volume: 1.0
Pitch: 0.1
ID: "minecraft:item.trident.riptide_3"
ABILITY_ACTIVATED_BERSERK:
Enable: true
Volume: 0.5
Pitch: 1.7
ID: "minecraft:block.conduit.ambient"
TIRED:
Enable: true
Volume: 1.0
Pitch: 1.7
ID: "minecraft:block.conduit.ambient"
BLEED:
Enable: true
Volume: 2.0
Pitch: 2.0
ID: "minecraft:entity.ender_eye.death"
CRIPPLE:
Enable: true
Volume: 1.0
Pitch: 0.5
Pitch: 0.5
ID: "minecraft:item.mace.smash_ground"