Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix sound for the third time (on dev/feature this time) #7205

Merged
Show file tree
Hide file tree
Changes from 6 commits
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
53 changes: 53 additions & 0 deletions src/main/java/ch/njol/skript/bukkitutil/SoundUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ch.njol.skript.bukkitutil;

import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Locale;

public class SoundUtils {
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved

// Sound.class is an interface (rather than an enum) as of MC 1.21.3
private static final boolean SOUND_IS_INTERFACE = Sound.class.isInterface();

/**
* Gets the key of a sound, given its enum-name-style name.
* @param soundString The enum name to use to find the sound.
* @return The key of the sound.
*/
public static @Nullable NamespacedKey getKey(String soundString) {
soundString = soundString.toUpperCase(Locale.ENGLISH);
if (SOUND_IS_INTERFACE) {
try {
//noinspection deprecation
return Sound.valueOf(soundString).getKey();
} catch (IllegalArgumentException ignore) {
}
} else {
try {
//noinspection unchecked,rawtypes
Enum soundEnum = Enum.valueOf((Class) Sound.class, soundString);
return ((Keyed) soundEnum).getKey();
} catch (IllegalArgumentException ignore) {
}
}
return null;
}

/**
* returns the key string for a sound. For version compat.
* @param sound The sound to get the key string of.
* @return The key string of the {@link NamespacedKey} of the sound.
*/
public static @NotNull NamespacedKey getKey(Sound sound) {
if (SOUND_IS_INTERFACE) {
//noinspection deprecation
return sound.getKey();
} else {
return ((Keyed) sound).getKey();
}
}
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved
}
55 changes: 13 additions & 42 deletions src/main/java/ch/njol/skript/effects/EffPlaySound.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.njol.skript.effects;

import ch.njol.skript.Skript;
import ch.njol.skript.bukkitutil.SoundUtils;
import ch.njol.skript.bukkitutil.sounds.SoundReceiver;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
Expand All @@ -11,7 +12,6 @@
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import org.bukkit.Keyed;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
Expand Down Expand Up @@ -73,7 +73,6 @@ public class EffPlaySound extends Effect {
private static final boolean ENTITY_EMITTER_SOUND = Skript.methodExists(Player.class, "playSound", Entity.class, Sound.class, SoundCategory.class, float.class, float.class);
private static final boolean ENTITY_EMITTER_STRING = Skript.methodExists(Player.class, "playSound", Entity.class, String.class, SoundCategory.class, float.class, float.class);
private static final boolean ENTITY_EMITTER = ENTITY_EMITTER_SOUND || ENTITY_EMITTER_STRING;
private static final boolean SOUND_IS_INTERFACE = Sound.class.isInterface();

public static final Pattern KEY_PATTERN = Pattern.compile("([a-z0-9._-]+:)?([a-z0-9/._-]+)");

Expand All @@ -90,26 +89,20 @@ public class EffPlaySound extends Effect {
);
}

@SuppressWarnings("NotNullFieldNotInitialized")
private Expression<String> sounds;

@Nullable
private Expression<SoundCategory> category;

@Nullable
private Expression<Player> players;
private @Nullable Expression<SoundCategory> category;

@Nullable
private Expression<Number> volume;
private @Nullable Expression<Player> players;

@Nullable
private Expression<Number> pitch;
private @Nullable Expression<Number> volume;

@Nullable
private Expression<Number> seed;
private @Nullable Expression<Number> pitch;

@Nullable
private Expression<?> emitters;
private @Nullable Expression<Number> seed;

private @Nullable Expression<?> emitters;

@Override
@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -151,7 +144,7 @@ protected void execute(Event event) {
// validate strings
List<NamespacedKey> validSounds = new ArrayList<>();
for (String sound : sounds.getArray(event)) {
NamespacedKey key = getSoundKeyFromEnum(sound);
NamespacedKey key = SoundUtils.getKey(sound);
if (key == null) {
sound = sound.toLowerCase(Locale.ENGLISH);
Matcher keyMatcher = KEY_PATTERN.matcher(sound);
Expand Down Expand Up @@ -204,12 +197,12 @@ protected void execute(Event event) {
}
} else if (emitters != null) {
for (Object emitter : emitters.getArray(event)) {
if (ENTITY_EMITTER && emitter instanceof Entity) {
SoundReceiver receiver = SoundReceiver.of(((Entity) emitter).getWorld());
if (ENTITY_EMITTER && emitter instanceof Entity entity) {
SoundReceiver receiver = SoundReceiver.of(entity.getWorld());
for (NamespacedKey sound : validSounds)
receiver.playSound(((Entity) emitter), sound, category, volume, pitch, seed);
} else if (emitter instanceof Location) {
SoundReceiver receiver = SoundReceiver.of(((Location) emitter).getWorld());
} else if (emitter instanceof Location location) {
SoundReceiver receiver = SoundReceiver.of(location.getWorld());
for (NamespacedKey sound : validSounds)
receiver.playSound(((Location) emitter), sound, category, volume, pitch, seed);
}
Expand Down Expand Up @@ -239,26 +232,4 @@ public String toString(@Nullable Event event, boolean debug) {
return builder.toString();
}

@SuppressWarnings({"deprecation", "unchecked", "rawtypes"})
private static @Nullable NamespacedKey getSoundKeyFromEnum(String soundString) {
soundString = soundString.toUpperCase(Locale.ENGLISH);
// Sound.class is an Interface (rather than an enum) as of MC 1.21.3
if (SOUND_IS_INTERFACE) {
try {
Sound sound = Sound.valueOf(soundString);
return sound.getKey();
} catch (IllegalArgumentException ignore) {
}
} else {
try {
Enum soundEnum = Enum.valueOf((Class) Sound.class, soundString);
if (soundEnum instanceof Keyed) {
return ((Keyed) soundEnum).getKey();
}
} catch (IllegalArgumentException ignore) {
}
}
return null;
}

}
5 changes: 2 additions & 3 deletions src/main/java/ch/njol/skript/expressions/ExprBlockSound.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.njol.skript.expressions;

import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.bukkitutil.SoundUtils;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
Expand Down Expand Up @@ -78,9 +79,7 @@ public Sound getSound(SoundGroup group) {
SimplePropertyExpression.register(ExprBlockSound.class, String.class, "(1:break|2:fall|3:hit|4:place|5:step) sound[s]", "blocks/blockdatas/itemtypes");
}

@SuppressWarnings("NotNullFieldNotInitialized")
private SoundType soundType;
@SuppressWarnings("NotNullFieldNotInitialized")
private Expression<?> objects;

@Override
Expand All @@ -96,7 +95,7 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
.map(this::convertAndGetSound)
.filter(Objects::nonNull)
.distinct()
.map(Sound::name)
.map(sound -> SoundUtils.getKey(sound).getKey())
.toArray(String[]::new);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.bukkitutil.SoundUtils;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
Expand Down Expand Up @@ -150,7 +151,7 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
.map(entity -> soundType.getSound(entity, height, item, bigOrSpeedy))
.filter(Objects::nonNull)
.distinct()
.map(Sound::name)
.map(sound -> SoundUtils.getKey(sound).getKey())
.toArray(String[]::new);
}

Expand Down
34 changes: 17 additions & 17 deletions src/test/skript/tests/syntaxes/expressions/ExprBlockSound.sk
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@ test "block sounds (1.20+)":

set {_before} to blockdata of (block at (spawn of world "world"))
set {_20} to whether running minecraft "1.20"
set {_empty} to "INTENTIONALLY_EMPTY" if running minecraft "1.20" else "BLOCK_STONE_PLACE"
set {_empty} to "INTENTIONALLY_EMPTY" if running minecraft "1.20" else "BLOCK.STONE.PLACE"

# === TESTS ===

set {_stone::*} to getObjects(stone)
assert break sound of {_stone::*} is "BLOCK_STONE_BREAK" with "break sound of stone wasn't BLOCK_STONE_BREAK"
assert fall sound of {_stone::*} is "BLOCK_STONE_FALL" with "fall sound of stone wasn't BLOCK_STONE_FALL"
assert hit sound of {_stone::*} is "BLOCK_STONE_HIT" with "hit sound of stone wasn't BLOCK_STONE_HIT"
assert place sound of {_stone::*} is "BLOCK_STONE_PLACE" with "place sound of stone wasn't BLOCK_STONE_PLACE"
assert step sound of {_stone::*} is "BLOCK_STONE_STEP" with "step sound of stone wasn't BLOCK_STONE_STEP"
assert break sound of {_stone::*} is "BLOCK.STONE.BREAK" with "break sound of stone wasn't BLOCK.STONE.BREAK"
assert fall sound of {_stone::*} is "BLOCK.STONE.FALL" with "fall sound of stone wasn't BLOCK.STONE.FALL"
assert hit sound of {_stone::*} is "BLOCK.STONE.HIT" with "hit sound of stone wasn't BLOCK.STONE.HIT"
assert place sound of {_stone::*} is "BLOCK.STONE.PLACE" with "place sound of stone wasn't BLOCK.STONE.PLACE"
assert step sound of {_stone::*} is "BLOCK.STONE.STEP" with "step sound of stone wasn't BLOCK.STONE.STEP"

set {_wool::*} to getObjects(wool)
assert break sound of {_wool::*} is "BLOCK_WOOL_BREAK" with "break sound of stone wasn't BLOCK_WOOL_BREAK"
assert fall sound of {_wool::*} is "BLOCK_WOOL_FALL" with "fall sound of stone wasn't BLOCK_WOOL_FALL"
assert hit sound of {_wool::*} is "BLOCK_WOOL_HIT" with "hit sound of stone wasn't BLOCK_WOOL_HIT"
assert place sound of {_wool::*} is "BLOCK_WOOL_PLACE" with "place sound of stone wasn't BLOCK_WOOL_PLACE"
assert step sound of {_wool::*} is "BLOCK_WOOL_STEP" with "step sound of stone wasn't BLOCK_WOOL_STEP"

assert break sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK_STONE_BREAK") with "break sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert fall sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK_STONE_FALL") with "fall sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert hit sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK_STONE_HIT") with "hit sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert place sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK_STONE_PLACE") with "place sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert step sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK_STONE_STEP") with "step sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert break sound of {_wool::*} is "BLOCK.WOOL.BREAK" with "break sound of stone wasn't BLOCK.WOOL.BREAK"
assert fall sound of {_wool::*} is "BLOCK.WOOL.FALL" with "fall sound of stone wasn't BLOCK.WOOL.FALL"
assert hit sound of {_wool::*} is "BLOCK.WOOL.HIT" with "hit sound of stone wasn't BLOCK.WOOL.HIT"
assert place sound of {_wool::*} is "BLOCK.WOOL.PLACE" with "place sound of stone wasn't BLOCK.WOOL.PLACE"
assert step sound of {_wool::*} is "BLOCK.WOOL.STEP" with "step sound of stone wasn't BLOCK.WOOL.STEP"

assert break sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK.STONE.BREAK") with "break sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert fall sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK.STONE.FALL") with "fall sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert hit sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK.STONE.HIT") with "hit sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert place sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK.STONE.PLACE") with "place sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"
assert step sound of (water, lava and bubble column) is ("INTENTIONALLY_EMPTY" if {_20} is true else "BLOCK.STONE.STEP") with "step sound of water, lava, or bubble column wasn't INTENTIONALLY_EMPTY"

assert break sound of (diamond, diamond sword and {_none}) is not set with "break sound of non-block item shouldn't be set"
assert fall sound of (diamond, diamond sword and {_none}) is not set with "fall sound of non-block item shouldn't be set"
Expand Down
28 changes: 14 additions & 14 deletions src/test/skript/tests/syntaxes/expressions/ExprEntitySound.sk
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
test "entity sounds":
spawn a zombie at (spawn of world "world"):
assert damage sound of entity is "ENTITY_ZOMBIE_HURT" with "damage sound of zombie should return ENTITY_ZOMBIE_HURT"
assert death sound of entity is "ENTITY_ZOMBIE_DEATH" with "death sound of zombie should return ENTITY_ZOMBIE_DEATH"
assert swim sound of entity is "ENTITY_HOSTILE_SWIM" with "swim sound of zombie should return ENTITY_HOSTILE_SWIM"
assert normal fall damage sound of entity is "ENTITY_HOSTILE_SMALL_FALL" with "fall sound of zombie should return ENTITY_HOSTILE_SMALL_FALL"
assert high fall damage sound of entity is "ENTITY_HOSTILE_BIG_FALL" with "high fall sound of zombie should return ENTITY_HOSTILE_BIG_FALL"
assert fall damage sound from a height of 10 of entity is "ENTITY_HOSTILE_BIG_FALL" with "fall sound from height of 10 sound of zombie should return ENTITY_HOSTILE_BIG_FALL"
assert fall damage sound from a height of {_none} of entity is "ENTITY_HOSTILE_SMALL_FALL" with "fall sound from invalid height sound of zombie should return ENTITY_HOSTILE_SMALL_FALL"
assert splash sound of entity is "ENTITY_HOSTILE_SPLASH" with "splash sound of zombie should return ENTITY_HOSTILE_SPLASH"
assert speedy splash sound of entity is "ENTITY_GENERIC_SPLASH" with "speedy splash sound of zombie should return ENTITY_GENERIC_SPLASH"
assert eating sound of entity is "ENTITY_GENERIC_EAT" with "eating sound of zombie should return ENTITY_GENERIC_EAT"
assert eating sound of entity using golden apple is "ENTITY_GENERIC_EAT" with "eating sound of zombie using golden apple should return ENTITY_GENERIC_EAT"
assert drinking sound of entity is "ENTITY_GENERIC_DRINK" with "drinking sound of zombie should return ENTITY_GENERIC_DRINK"
assert drinking sound of entity using potion is "ENTITY_GENERIC_DRINK" with "drinking sound of zombie using potion should return ENTITY_GENERIC_DRINK"
assert ambient sound of entity is "ENTITY_ZOMBIE_AMBIENT" with "ambient sound of zombie should return ENTITY_ZOMBIE_AMBIENT"
assert damage sound of entity is "ENTITY.ZOMBIE.HURT" with "damage sound of zombie should return ENTITY.ZOMBIE.HURT"
assert death sound of entity is "ENTITY.ZOMBIE.DEATH" with "death sound of zombie should return ENTITY.ZOMBIE.DEATH"
assert swim sound of entity is "ENTITY.HOSTILE.SWIM" with "swim sound of zombie should return ENTITY.HOSTILE.SWIM"
assert normal fall damage sound of entity is "ENTITY.HOSTILE.SMALL_FALL" with "fall sound of zombie should return ENTITY.HOSTILE.SMALL_FALL"
assert high fall damage sound of entity is "ENTITY.HOSTILE.BIG_FALL" with "high fall sound of zombie should return ENTITY.HOSTILE.BIG_FALL"
assert fall damage sound from a height of 10 of entity is "ENTITY.HOSTILE.BIG_FALL" with "fall sound from height of 10 sound of zombie should return ENTITY.HOSTILE.BIG_FALL"
assert fall damage sound from a height of {_none} of entity is "ENTITY.HOSTILE.SMALL_FALL" with "fall sound from invalid height sound of zombie should return ENTITY.HOSTILE.SMALL_FALL"
assert splash sound of entity is "ENTITY.HOSTILE.SPLASH" with "splash sound of zombie should return ENTITY.HOSTILE.SPLASH"
assert speedy splash sound of entity is "ENTITY.GENERIC.SPLASH" with "speedy splash sound of zombie should return ENTITY.GENERIC.SPLASH"
assert eating sound of entity is "ENTITY.GENERIC.EAT" with "eating sound of zombie should return ENTITY.GENERIC.EAT"
assert eating sound of entity using golden apple is "ENTITY.GENERIC.EAT" with "eating sound of zombie using golden apple should return ENTITY.GENERIC.EAT"
assert drinking sound of entity is "ENTITY.GENERIC.DRINK" with "drinking sound of zombie should return ENTITY.GENERIC.DRINK"
assert drinking sound of entity using potion is "ENTITY.GENERIC.DRINK" with "drinking sound of zombie using potion should return ENTITY.GENERIC.DRINK"
assert ambient sound of entity is "ENTITY.ZOMBIE.AMBIENT" with "ambient sound of zombie should return ENTITY.ZOMBIE.AMBIENT"
delete entity
Loading