mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-10-29 11:52:22 +00:00
Compare commits
5 Commits
99f7437d9d
...
8e049822a3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e049822a3 | ||
|
|
06f979d7bf | ||
|
|
f78586675d | ||
|
|
46bcd29998 | ||
|
|
df69410e67 |
@ -1,3 +1,15 @@
|
||||
Version 2.2.042
|
||||
You can now define custom sounds to be played in sounds.yml (Thank you JeBobs, see notes)
|
||||
Added a cap to how much Blast Mining PVP damage can do to other players
|
||||
|
||||
Notes:
|
||||
The new sounds.yml config file allows you to override the sounds played by mcMMO.
|
||||
Simply define the ID of the sound you want to play for each sound.
|
||||
For example, add an entry for Sounds.TOOL_READY.CustomSoundId into sounds.yml to override the sound played when a tool is "readied".
|
||||
If you are on older versions (1.18, 1.19, etc), instead of registering an ID, you specify the Sound enum.
|
||||
Those who are on newer versions, can define the ID of any sound registered with Paper/Spigot, this allows you to even play custom sounds so long as they are properly loaded on the server.
|
||||
Vanilla minecraft sounds tend to have IDs like "minecraft:ui.toast.challenge_complete", you can google what these keys are.
|
||||
|
||||
Version 2.2.041
|
||||
Fixed Berserk failing to crack blocks
|
||||
Added 'Skills.Unarmed.Block_Cracker.Allow_Block_Cracker' to config.yml
|
||||
|
||||
@ -29,7 +29,7 @@ public class SoundConfig extends BukkitConfig {
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
for (SoundType soundType : SoundType.values()) {
|
||||
if (config.getDouble("Sounds." + soundType.toString() + ".Volume") < 0) {
|
||||
if (config.getDouble("Sounds." + soundType + ".Volume") < 0) {
|
||||
LogUtils.debug(mcMMO.p.getLogger(),
|
||||
"[mcMMO] Sound volume cannot be below 0 for " + soundType);
|
||||
return false;
|
||||
@ -52,17 +52,22 @@ public class SoundConfig extends BukkitConfig {
|
||||
}
|
||||
|
||||
public float getVolume(SoundType soundType) {
|
||||
String key = "Sounds." + soundType.toString() + ".Volume";
|
||||
String key = "Sounds." + soundType + ".Volume";
|
||||
return (float) config.getDouble(key, 1.0);
|
||||
}
|
||||
|
||||
public float getPitch(SoundType soundType) {
|
||||
String key = "Sounds." + soundType.toString() + ".Pitch";
|
||||
String key = "Sounds." + soundType + ".Pitch";
|
||||
return (float) config.getDouble(key, 1.0);
|
||||
}
|
||||
|
||||
public String getSound(SoundType soundType) {
|
||||
final String key = "Sounds." + soundType + ".CustomSoundId";
|
||||
return config.getString(key);
|
||||
}
|
||||
|
||||
public boolean getIsEnabled(SoundType soundType) {
|
||||
String key = "Sounds." + soundType.toString() + ".Enabled";
|
||||
String key = "Sounds." + soundType + ".Enable";
|
||||
return config.getBoolean(key, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,8 +385,8 @@ public class EntityListener implements Listener {
|
||||
if (animalTamer != null && ((OfflinePlayer) animalTamer).isOnline()) {
|
||||
attacker = (Entity) animalTamer;
|
||||
}
|
||||
} else if (attacker instanceof TNTPrimed && defender instanceof Player) {
|
||||
if (BlastMining.processBlastMiningExplosion(event, (TNTPrimed) attacker,
|
||||
} else if (attacker instanceof TNTPrimed tntAttacker && defender instanceof Player) {
|
||||
if (BlastMining.processBlastMiningExplosion(event, tntAttacker,
|
||||
(Player) defender)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -10,7 +10,8 @@ import org.bukkit.entity.TNTPrimed;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
|
||||
public class BlastMining {
|
||||
public final static int MAXIMUM_REMOTE_DETONATION_DISTANCE = 100;
|
||||
public static final int MAXIMUM_REMOTE_DETONATION_DISTANCE = 100;
|
||||
private static final double BLAST_MINING_PVP_DAMAGE_CAP = 24D;
|
||||
|
||||
public static double getBlastRadiusModifier(int rank) {
|
||||
return mcMMO.p.getAdvancedConfig().getBlastRadiusModifier(rank);
|
||||
@ -41,17 +42,22 @@ public class BlastMining {
|
||||
}
|
||||
|
||||
public static boolean processBlastMiningExplosion(EntityDamageByEntityEvent event,
|
||||
TNTPrimed tnt, Player defender) {
|
||||
if (!tnt.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT)
|
||||
TNTPrimed tntAttacker, Player defender) {
|
||||
if (!tntAttacker.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT)
|
||||
|| !UserManager.hasPlayerDataKey(defender)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can make this assumption because we (should) be the only ones using this exact metadata
|
||||
Player player = mcMMO.p.getServer().getPlayerExact(
|
||||
tnt.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString());
|
||||
tntAttacker.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString());
|
||||
|
||||
if (!(player != null && player.equals(defender))) {
|
||||
double cappedDamage = Math.min(event.getDamage(), BLAST_MINING_PVP_DAMAGE_CAP);
|
||||
event.setDamage(Math.max(cappedDamage, 0D));
|
||||
if (event.getFinalDamage() <= 0) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -67,7 +73,7 @@ public class BlastMining {
|
||||
|
||||
event.setDamage(miningManager.processDemolitionsExpertise(event.getDamage()));
|
||||
|
||||
if (event.getFinalDamage() == 0) {
|
||||
if (event.getFinalDamage() <= 0) {
|
||||
event.setCancelled(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@ import com.gmail.nossr50.config.SoundConfig;
|
||||
import com.gmail.nossr50.util.Misc;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.SoundCategory;
|
||||
@ -11,12 +13,12 @@ import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SoundManager {
|
||||
|
||||
private static final Map<SoundType, Sound> soundCache = new ConcurrentHashMap<>();
|
||||
private static final String NULL_FALLBACK_ID = null;
|
||||
private static Sound CRIPPLE_SOUND;
|
||||
|
||||
private static final String ITEM_MACE_SMASH_GROUND = "ITEM_MACE_SMASH_GROUND";
|
||||
|
||||
private static final String VALUE_OF = "valueOf";
|
||||
|
||||
private static final String ORG_BUKKIT_SOUND = "org.bukkit.Sound";
|
||||
|
||||
/**
|
||||
@ -98,16 +100,78 @@ public class SoundManager {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return switch (soundType)
|
||||
{
|
||||
case FIZZ -> getFizzPitch();
|
||||
case POP -> getPopPitch();
|
||||
default -> SoundConfig.getInstance().getPitch(soundType);
|
||||
};
|
||||
}
|
||||
|
||||
private static Sound getSound(SoundType soundType) {
|
||||
final String soundId = SoundConfig.getInstance().getSound(soundType);
|
||||
|
||||
// Legacy versions use a different lookup method
|
||||
if (SoundRegistryUtils.useLegacyLookup()) {
|
||||
return getSoundLegacyCustom(soundId, soundType);
|
||||
}
|
||||
|
||||
if (soundCache.containsKey(soundType)) {
|
||||
return soundCache.get(soundType);
|
||||
}
|
||||
|
||||
Sound sound;
|
||||
if (soundId != null && !soundId.isEmpty()) {
|
||||
sound = SoundRegistryUtils.getSound(soundId, soundType.id());
|
||||
} else {
|
||||
sound = SoundRegistryUtils.getSound(soundType.id(), NULL_FALLBACK_ID);
|
||||
}
|
||||
|
||||
if (sound != null) {
|
||||
soundCache.putIfAbsent(soundType, sound);
|
||||
return sound;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Could not find Sound for SoundType: " + soundType);
|
||||
}
|
||||
|
||||
private static Sound getSoundLegacyCustom(String id, SoundType soundType) {
|
||||
if (soundCache.containsKey(soundType)) {
|
||||
return soundCache.get(soundType);
|
||||
}
|
||||
|
||||
// Try to look up a custom legacy sound
|
||||
if (id != null && !id.isEmpty()) {
|
||||
Sound sound;
|
||||
if (Sound.class.isEnum()) {
|
||||
// Sound is only an ENUM in legacy versions
|
||||
// Use reflection to loop through the values, finding the first enum matching our ID
|
||||
try {
|
||||
Method method = Sound.class.getMethod("getKey");
|
||||
for (Object legacyEnumEntry : Sound.class.getEnumConstants()) {
|
||||
// This enum extends Keyed which adds the getKey() method
|
||||
// we need to invoke this method to get the NamespacedKey and compare to our ID
|
||||
if (method.invoke(legacyEnumEntry).toString().equals(id)) {
|
||||
sound = (Sound) legacyEnumEntry;
|
||||
soundCache.putIfAbsent(soundType, sound);
|
||||
return sound;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException | InvocationTargetException |
|
||||
IllegalAccessException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unable to find legacy sound by ID %s for SoundType %s"
|
||||
.formatted(id, soundType));
|
||||
}
|
||||
// Failsafe -- we haven't found a matching sound
|
||||
final Sound sound = getSoundLegacyFallBack(soundType);
|
||||
soundCache.putIfAbsent(soundType, sound);
|
||||
return sound;
|
||||
}
|
||||
|
||||
private static Sound getSoundLegacyFallBack(SoundType soundType) {
|
||||
return switch (soundType) {
|
||||
case ANVIL -> Sound.BLOCK_ANVIL_PLACE;
|
||||
case ITEM_BREAK -> Sound.ENTITY_ITEM_BREAK;
|
||||
@ -153,8 +217,4 @@ public class SoundManager {
|
||||
public static float getPopPitch() {
|
||||
return ((Misc.getRandom().nextFloat() - Misc.getRandom().nextFloat()) * 0.7F + 1.0F) * 2.0F;
|
||||
}
|
||||
|
||||
public static float getKrakenPitch() {
|
||||
return (Misc.getRandom().nextFloat() - Misc.getRandom().nextFloat()) * 0.2F + 1.0F;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
package com.gmail.nossr50.util.sounds;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.AttributeMapper;
|
||||
import com.gmail.nossr50.util.LogUtils;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Sound;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class SoundRegistryUtils {
|
||||
|
||||
private static Method registryLookup;
|
||||
private static Object soundReg;
|
||||
|
||||
public static final String PAPER_SOUND_REGISTRY_FIELD = "SOUND_EVENT";
|
||||
public static final String SPIGOT_SOUND_REGISTRY_FIELD = "SOUNDS";
|
||||
public static final String METHOD_GET_OR_THROW_NAME = "getOrThrow";
|
||||
public static final String METHOD_GET_NAME = "get";
|
||||
|
||||
static {
|
||||
boolean foundRegistry = false;
|
||||
Class<?> registry;
|
||||
try {
|
||||
registry = Class.forName(AttributeMapper.ORG_BUKKIT_REGISTRY);
|
||||
try {
|
||||
// First check for Paper's sound registry, held by field SOUND_EVENT
|
||||
soundReg = registry.getField(PAPER_SOUND_REGISTRY_FIELD).get(null);
|
||||
foundRegistry = true;
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
try {
|
||||
soundReg = registry.getField(SPIGOT_SOUND_REGISTRY_FIELD);
|
||||
foundRegistry = true;
|
||||
} catch (NoSuchFieldException ex) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (foundRegistry) {
|
||||
try {
|
||||
// getOrThrow isn't in all API versions, but we use it if it exists
|
||||
registryLookup = soundReg.getClass().getMethod(METHOD_GET_OR_THROW_NAME,
|
||||
NamespacedKey.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
registryLookup = soundReg.getClass().getMethod(METHOD_GET_NAME,
|
||||
NamespacedKey.class);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
// ignored exception
|
||||
registryLookup = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean useLegacyLookup() {
|
||||
return registryLookup == null;
|
||||
}
|
||||
|
||||
public static @Nullable Sound getSound(String id, String fallBackId) {
|
||||
if (registryLookup != null) {
|
||||
try {
|
||||
return (Sound) registryLookup.invoke(soundReg, NamespacedKey.fromString(id));
|
||||
} catch(InvocationTargetException | IllegalAccessException
|
||||
| IllegalArgumentException e) {
|
||||
if (fallBackId != null) {
|
||||
LogUtils.debug(mcMMO.p.getLogger(),
|
||||
format("Could not find sound with ID '%s', trying fallback ID '%s'", id,
|
||||
fallBackId));
|
||||
try {
|
||||
return (Sound) registryLookup.invoke(soundReg,
|
||||
NamespacedKey.fromString(fallBackId));
|
||||
} catch (IllegalAccessException | InvocationTargetException ex) {
|
||||
mcMMO.p.getLogger().severe(format("Could not find sound with ID %s,"
|
||||
+ " fallback ID of %s also failed.", id, fallBackId));
|
||||
}
|
||||
} else {
|
||||
mcMMO.p.getLogger().severe(format("Could not find sound with ID %s.", id));
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,31 +1,39 @@
|
||||
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;
|
||||
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");
|
||||
|
||||
private final String soundRegistryId;
|
||||
|
||||
public boolean usesCustomPitch() {
|
||||
switch (this) {
|
||||
case POP:
|
||||
case FIZZ:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
SoundType(String soundRegistryId) {
|
||||
this.soundRegistryId = soundRegistryId;
|
||||
}
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return soundRegistryId;
|
||||
}
|
||||
|
||||
public boolean usesCustomPitch()
|
||||
{
|
||||
return switch (this) {
|
||||
case POP, FIZZ -> true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -4,71 +4,90 @@ Sounds:
|
||||
# 1.0 = Max volume
|
||||
# 0.0 = No Volume
|
||||
MasterVolume: 1.0
|
||||
# If you want to use custom sounds, provide an ID for CustomSoundId
|
||||
# Sound IDs are strings, such as minecraft:entity.player.levelup
|
||||
ITEM_CONSUMED:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 1.0
|
||||
CustomSoundId: ''
|
||||
GLASS:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 1.0
|
||||
CustomSoundId: ''
|
||||
ANVIL:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 0.3
|
||||
CustomSoundId: ''
|
||||
#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
|
||||
CustomSoundId: ''
|
||||
LEVEL_UP:
|
||||
Enable: true
|
||||
Volume: 0.3
|
||||
Pitch: 0.5
|
||||
CustomSoundId: ''
|
||||
ITEM_BREAK:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 1.0
|
||||
CustomSoundId: ''
|
||||
#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
|
||||
CustomSoundId: ''
|
||||
CHIMAERA_WING:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 0.6
|
||||
CustomSoundId: ''
|
||||
ROLL_ACTIVATED:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 0.7
|
||||
CustomSoundId: ''
|
||||
SKILL_UNLOCKED:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 1.4
|
||||
CustomSoundId: ''
|
||||
DEFLECT_ARROWS:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 2.0
|
||||
CustomSoundId: ''
|
||||
TOOL_READY:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 0.4
|
||||
CustomSoundId: ''
|
||||
ABILITY_ACTIVATED_GENERIC:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 0.1
|
||||
CustomSoundId: ''
|
||||
ABILITY_ACTIVATED_BERSERK:
|
||||
Enable: true
|
||||
Volume: 0.5
|
||||
Pitch: 1.7
|
||||
CustomSoundId: ''
|
||||
TIRED:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 1.7
|
||||
CustomSoundId: ''
|
||||
BLEED:
|
||||
Enable: true
|
||||
Volume: 2.0
|
||||
Pitch: 2.0
|
||||
CustomSoundId: ''
|
||||
CRIPPLE:
|
||||
Enable: true
|
||||
Volume: 1.0
|
||||
Pitch: 0.5
|
||||
Pitch: 0.5
|
||||
CustomSoundId: ''
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user