Skip to content

Commit

Permalink
Adds block sound expression and test (#7040)
Browse files Browse the repository at this point in the history
* Adds block sound syntax
- Allows getting the break, fall, hit, place, and step sound of a block/blockdata/itemtype

* Suggestions

* Suggestion

Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>

* Implements SoundType enum to get a sound given a group, and makes tests better
- This also reduces some annoying switch stuff with the soundType from before

* Fixes tests failing due to 1.19 not using INTENTIONALLY_EMPTY sound

---------

Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
  • Loading branch information
cheeezburga and sovdeeth authored Oct 13, 2024
1 parent 97055a2 commit 99731b0
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 0 deletions.
137 changes: 137 additions & 0 deletions src/main/java/ch/njol/skript/expressions/ExprBlockSound.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package ch.njol.skript.expressions;

import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.util.Kleenean;
import org.bukkit.Sound;
import org.bukkit.SoundGroup;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

@Name("Block Sound")
@Description({
"Gets the sound that a given block, blockdata, or itemtype will use in a specific scenario.",
"This will return a string in the form of \"SOUND_EXAMPLE\", which can be used in the play sound syntax.",
"",
"Check out <a href=\"https://minecraft.wiki/w/Sounds.json\">this website</a> for a list of sounds in Minecraft, " +
"or <a href=\"https://minecraft.wiki/w/Sound\">this one</a> to go to the Sounds wiki page."
})
@Examples({
"play sound (break sound of dirt) at all players",
"set {_sounds::*} to place sounds of dirt, grass block, blue wool and stone"
})
@Since("INSERT VERSION")
public class ExprBlockSound extends SimpleExpression<String> {

public enum SoundType {
BREAK {
@Override
public Sound getSound(SoundGroup group) {
return group.getBreakSound();
}
},

FALL {
@Override
public Sound getSound(SoundGroup group) {
return group.getFallSound();
}
},

HIT {
@Override
public Sound getSound(SoundGroup group) {
return group.getHitSound();
}
},

PLACE {
@Override
public Sound getSound(SoundGroup group) {
return group.getPlaceSound();
}
},

STEP {
@Override
public Sound getSound(SoundGroup group) {
return group.getStepSound();
}
};

public abstract @Nullable Sound getSound(SoundGroup group);
}

static {
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
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
soundType = SoundType.values()[parseResult.mark - 1];
objects = exprs[0];
return true;
}

@Override
protected String @Nullable [] get(Event event) {
return objects.stream(event)
.map(this::convertAndGetSound)
.filter(Objects::nonNull)
.distinct()
.map(Sound::name)
.toArray(String[]::new);
}

private @Nullable SoundGroup getSoundGroup(Object object) {
if (object instanceof Block block) {
return block.getBlockData().getSoundGroup();
} else if (object instanceof BlockData data) {
return data.getSoundGroup();
} else if (object instanceof ItemType item) {
if (item.hasBlock())
return item.getMaterial().createBlockData().getSoundGroup();
}
return null;
}

private @Nullable Sound convertAndGetSound(Object object) {
SoundGroup group = getSoundGroup(object);
if (group == null)
return null;
return this.soundType.getSound(group);
}

@Override
public boolean isSingle() {
return objects.isSingle();
}

@Override
public @NotNull Class<? extends String> getReturnType() {
return String.class;
}

@Override
public @NotNull String toString(@Nullable Event event, boolean debug) {
return this.soundType.name().toLowerCase() + " sound of " + objects.toString(event, debug);
}

}
46 changes: 46 additions & 0 deletions src/test/skript/tests/syntaxes/expressions/ExprBlockSound.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
test "block sounds (1.20+)":

# === SETUP ===

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"

# === 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"

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 (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"
assert hit sound of (diamond, diamond sword and {_none}) is not set with "hit sound of non-block item shouldn't be set"
assert place sound of (diamond, diamond sword and {_none}) is not set with "place sound of non-block item shouldn't be set"
assert step sound of (diamond, diamond sword and {_none}) is not set with "step sound of non-block item shouldn't be set"

# === CLEANUP ===

set blockdata of {_block} to {_before}

local function getObjects(i: itemtype) :: objects:
if (block at (spawn of world "world")) is not {_i}:
set block at (spawn of world "world") to {_i}
set {_block} to block at (spawn of world "world")
set {_data} to blockdata of {_block}
return {_block}, {_data} and {_i}

0 comments on commit 99731b0

Please sign in to comment.