From 1f322369a09bb8b34c78aa1351f085a155593c20 Mon Sep 17 00:00:00 2001 From: Bukkit/Spigot Date: Fri, 17 Nov 2023 19:54:43 +1300 Subject: [PATCH] #938: Various Sound API improvements By: Jishuna --- .../src/main/java/org/bukkit/Instrument.java | 65 +++++++++------ paper-api/src/main/java/org/bukkit/Note.java | 18 +++++ paper-api/src/main/java/org/bukkit/World.java | 76 ++++++++++++++++++ .../main/java/org/bukkit/entity/Player.java | 79 ++++++++++++++++--- 4 files changed, 203 insertions(+), 35 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/Instrument.java b/paper-api/src/main/java/org/bukkit/Instrument.java index de976be713..032d7b812d 100644 --- a/paper-api/src/main/java/org/bukkit/Instrument.java +++ b/paper-api/src/main/java/org/bukkit/Instrument.java @@ -9,110 +9,123 @@ public enum Instrument { /** * Piano is the standard instrument for a note block. */ - PIANO(0x0), + PIANO(0x0, Sound.BLOCK_NOTE_BLOCK_HARP), /** * Bass drum is normally played when a note block is on top of a * stone-like block. */ - BASS_DRUM(0x1), + BASS_DRUM(0x1, Sound.BLOCK_NOTE_BLOCK_BASEDRUM), /** * Snare drum is normally played when a note block is on top of a sandy * block. */ - SNARE_DRUM(0x2), + SNARE_DRUM(0x2, Sound.BLOCK_NOTE_BLOCK_SNARE), /** * Sticks are normally played when a note block is on top of a glass * block. */ - STICKS(0x3), + STICKS(0x3, Sound.BLOCK_NOTE_BLOCK_HAT), /** * Bass guitar is normally played when a note block is on top of a wooden * block. */ - BASS_GUITAR(0x4), + BASS_GUITAR(0x4, Sound.BLOCK_NOTE_BLOCK_BASS), /** * Flute is normally played when a note block is on top of a clay block. */ - FLUTE(0x5), + FLUTE(0x5, Sound.BLOCK_NOTE_BLOCK_FLUTE), /** * Bell is normally played when a note block is on top of a gold block. */ - BELL(0x6), + BELL(0x6, Sound.BLOCK_NOTE_BLOCK_BELL), /** * Guitar is normally played when a note block is on top of a woolen block. */ - GUITAR(0x7), + GUITAR(0x7, Sound.BLOCK_NOTE_BLOCK_GUITAR), /** * Chime is normally played when a note block is on top of a packed ice * block. */ - CHIME(0x8), + CHIME(0x8, Sound.BLOCK_NOTE_BLOCK_CHIME), /** * Xylophone is normally played when a note block is on top of a bone block. */ - XYLOPHONE(0x9), + XYLOPHONE(0x9, Sound.BLOCK_NOTE_BLOCK_XYLOPHONE), /** * Iron Xylophone is normally played when a note block is on top of a iron block. */ - IRON_XYLOPHONE(0xA), + IRON_XYLOPHONE(0xA, Sound.BLOCK_NOTE_BLOCK_IRON_XYLOPHONE), /** * Cow Bell is normally played when a note block is on top of a soul sand block. */ - COW_BELL(0xB), + COW_BELL(0xB, Sound.BLOCK_NOTE_BLOCK_COW_BELL), /** * Didgeridoo is normally played when a note block is on top of a pumpkin block. */ - DIDGERIDOO(0xC), + DIDGERIDOO(0xC, Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO), /** * Bit is normally played when a note block is on top of a emerald block. */ - BIT(0xD), + BIT(0xD, Sound.BLOCK_NOTE_BLOCK_BIT), /** * Banjo is normally played when a note block is on top of a hay block. */ - BANJO(0xE), + BANJO(0xE, Sound.BLOCK_NOTE_BLOCK_BANJO), /** * Pling is normally played when a note block is on top of a glowstone block. */ - PLING(0xF), + PLING(0xF, Sound.BLOCK_NOTE_BLOCK_PLING), /** * Zombie is normally played when a Zombie Head is on top of the note block. */ - ZOMBIE, + ZOMBIE(Sound.BLOCK_NOTE_BLOCK_IMITATE_ZOMBIE), /** * Skeleton is normally played when a Skeleton Head is on top of the note block. */ - SKELETON, + SKELETON(Sound.BLOCK_NOTE_BLOCK_IMITATE_SKELETON), /** * Creeper is normally played when a Creeper Head is on top of the note block. */ - CREEPER, + CREEPER(Sound.BLOCK_NOTE_BLOCK_IMITATE_CREEPER), /** * Dragon is normally played when a Dragon Head is on top of the note block. */ - DRAGON, + DRAGON(Sound.BLOCK_NOTE_BLOCK_IMITATE_ENDER_DRAGON), /** * Wither Skeleton is normally played when a Wither Skeleton Head is on top of the note block. */ - WITHER_SKELETON, + WITHER_SKELETON(Sound.BLOCK_NOTE_BLOCK_IMITATE_WITHER_SKELETON), /** * Piglin is normally played when a Piglin Head is on top of the note block. */ - PIGLIN, + PIGLIN(Sound.BLOCK_NOTE_BLOCK_IMITATE_PIGLIN), /** * Custom Sound is normally played when a Player Head with the required data is on top of the note block. */ - CUSTOM_HEAD; + CUSTOM_HEAD(null); private final byte type; + private final Sound sound; private static final Map BY_DATA = Maps.newHashMap(); - private Instrument() { - this(-1); + private Instrument(final Sound sound) { + this(-1, sound); } - private Instrument(final int type) { + private Instrument(final int type, final Sound sound) { this.type = (byte) type; + this.sound = sound; + } + + /** + * Gets the sound associated with this instrument.
+ * Will be null for {@link Instrument#CUSTOM_HEAD} + * + * @return the sound or null + */ + @Nullable + public Sound getSound() { + return this.sound; } /** diff --git a/paper-api/src/main/java/org/bukkit/Note.java b/paper-api/src/main/java/org/bukkit/Note.java index fc3da7ce6f..48aecc9421 100644 --- a/paper-api/src/main/java/org/bukkit/Note.java +++ b/paper-api/src/main/java/org/bukkit/Note.java @@ -118,6 +118,14 @@ public class Note { } } + private static final float[] pitchArray = new float[25]; + static { + for (int i = 0; i <= 24; i++) { + // See https://minecraft.wiki/w/Note_Block#Notes + pitchArray[i] = (float) Math.pow(2, (i - 12) / 12f); + } + } + private final byte note; /** @@ -254,6 +262,16 @@ public class Note { return Tone.getById(note).isSharped(note); } + /** + * Gets the pitch of this note. This is the value used with + * {@link World#playSound} or the /playsound command. + * + * @return the pitch + */ + public float getPitch() { + return pitchArray[this.note]; + } + @Override public int hashCode() { final int prime = 31; diff --git a/paper-api/src/main/java/org/bukkit/World.java b/paper-api/src/main/java/org/bukkit/World.java index ef1ac9cd20..16feb5ef2f 100644 --- a/paper-api/src/main/java/org/bukkit/World.java +++ b/paper-api/src/main/java/org/bukkit/World.java @@ -2109,6 +2109,18 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient */ void setSpawnLimit(@NotNull SpawnCategory spawnCategory, int limit); + /** + * Play a note at the provided Location in the World.
+ * This will work with cake. + *

+ * This method will fail silently when called with {@link Instrument#CUSTOM_HEAD}. + * + * @param loc The location to play the note + * @param instrument The instrument + * @param note The note + */ + void playNote(@NotNull Location loc, @NotNull Instrument instrument, @NotNull Note note); + /** * Play a Sound at the provided Location in the World. *

@@ -2163,6 +2175,38 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient */ void playSound(@NotNull Location location, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch); + /** + * Play a Sound at the provided Location in the World. For sounds with multiple + * variations passing the same seed will always play the same variation. + *

+ * This function will fail silently if Location or Sound are null. + * + * @param location The location to play the sound + * @param sound The sound to play + * @param category the category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + void playSound(@NotNull Location location, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + + /** + * Play a Sound at the provided Location in the World. For sounds with multiple + * variations passing the same seed will always play the same variation. + *

+ * This function will fail silently if Location or Sound are null. No sound will + * be heard by the players if their clients do not have the respective sound for + * the value passed. + * + * @param location The location to play the sound + * @param sound The internal sound name to play + * @param category the category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + void playSound(@NotNull Location location, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + /** * Play a Sound at the location of the provided entity in the World. *

@@ -2213,6 +2257,38 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient */ void playSound(@NotNull Entity entity, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch); + /** + * Play a Sound at the location of the provided entity in the World. For sounds + * with multiple variations passing the same seed will always play the same + * variation. + *

+ * This function will fail silently if Entity or Sound are null. + * + * @param entity The entity to play the sound + * @param sound The sound to play + * @param category The category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + void playSound(@NotNull Entity entity, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + + /** + * Play a Sound at the location of the provided entity in the World. For sounds + * with multiple variations passing the same seed will always play the same + * variation. + *

+ * This function will fail silently if Entity or Sound are null. + * + * @param entity The entity to play the sound + * @param sound The sound to play + * @param category The category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + void playSound(@NotNull Entity entity, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + /** * Get an array containing the names of all the {@link GameRule}s. * diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index de462c239c..3cf31b08c6 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -391,11 +391,10 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM public void setBedSpawnLocation(@Nullable Location location, boolean force); /** - * Play a note for a player at a location. This requires a note block - * at the particular location (as far as the client is concerned). This - * will not work without a note block. This will not work with cake. + * Play a note for the player at a location.
+ * This will work with cake. * - * @param loc The location of a note block. + * @param loc The location to play the note * @param instrument The instrument ID. * @param note The note ID. * @deprecated Magic value @@ -404,11 +403,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM public void playNote(@NotNull Location loc, byte instrument, byte note); /** - * Play a note for a player at a location. This requires a note block - * at the particular location (as far as the client is concerned). This - * will not work without a note block. This will not work with cake. - * - * @param loc The location of a note block + * Play a note for the player at a location.
+ * This will work with cake. + *

+ * This method will fail silently when called with {@link Instrument#CUSTOM_HEAD}. + * @param loc The location to play the note * @param instrument The instrument * @param note The note */ @@ -469,6 +468,38 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM */ public void playSound(@NotNull Location location, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch); + /** + * Play a sound for a player at the location. For sounds with multiple + * variations passing the same seed will always play the same variation. + *

+ * This function will fail silently if Location or Sound are null. + * + * @param location The location to play the sound + * @param sound The sound to play + * @param category The category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + public void playSound(@NotNull Location location, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + + /** + * Play a sound for a player at the location. For sounds with multiple + * variations passing the same seed will always play the same variation. + *

+ * This function will fail silently if Location or Sound are null. No sound + * will be heard by the player if their client does not have the respective + * sound for the value passed. + * + * @param location The location to play the sound + * @param sound The internal sound name to play + * @param category The category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + public void playSound(@NotNull Location location, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + /** * Play a sound for a player at the location of the entity. *

@@ -519,6 +550,36 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM */ public void playSound(@NotNull Entity entity, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch); + /** + * Play a sound for a player at the location of the entity. For sounds with + * multiple variations passing the same seed will always play the same variation. + *

+ * This function will fail silently if Entity or Sound are null. + * + * @param entity The entity to play the sound + * @param sound The sound to play + * @param category The category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + public void playSound(@NotNull Entity entity, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + + /** + * Play a sound for a player at the location of the entity. For sounds with + * multiple variations passing the same seed will always play the same variation. + *

+ * This function will fail silently if Entity or Sound are null. + * + * @param entity The entity to play the sound + * @param sound The sound to play + * @param category The category of the sound + * @param volume The volume of the sound + * @param pitch The pitch of the sound + * @param seed The seed for the sound + */ + public void playSound(@NotNull Entity entity, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch, long seed); + /** * Stop the specified sound from playing. *