diff --git a/README.MD b/README.MD index 778e346..90324e8 100644 --- a/README.MD +++ b/README.MD @@ -14,28 +14,24 @@ Stereo (2 channels) soundtrack, you'll hear the music everywhere, which is cool There are limitations connected to directly playing media using playSound: -- There is no way to really know what is playing for a player. The best one can do is track any time a song is played - outside the global cycle. -- When a new player joins there are only two ways to make the music play for the player: Either play immediately, and - cut the song short once the playlist switches songs, or play nothing until the playlist switches songs. None of these - are ideal. -- Songs are really only identified by the category and the song id. Stopping the song for one minstrel will also stop - the song if played by any other minstrels at the same time. As songs are only stopped if a song has been played for a - player outside the global cycle, or if volume/pitch is changed and force update is set to true, it shouldn't be too - much of a problem, but if several minstrels play the same song, there may be silent minstrels until the next song - plays. +- There is no way to really know what is playing for a player. The only thing used to track when a song is finished is + the length provided when adding a song. Make sure it's correct. +- There is no way to know if a player has the server resource pack, and thus if they have custom songs. When resource + pack songs play, players that rejected it will hear silence. ## Commands +To make a new minstrel, use `/npc select` to select the NPC, then use `/trait add Minstrel` to add the minstrel trait. + | Command | Arguments | Description | |----------------------|------------------------------------------------------------|-------------------------------------------------------------------------------------------| -| /minstrel addsong | \ \ \ | Adds the specified song to the selected minstrel's playlist | -| /minstrel removesong | \ | Removes the song at the given index from the selected minstrel's playlist | -| /minstrel listsongs | none | Lists all songs in the selected NPC's playlist in the format CATEGORY:identifier:duration | +| /minstrel addSong | \ \ \ | Adds the specified song to the selected minstrel's playlist | +| /minstrel removeSong | \ | Removes the song at the given index from the selected minstrel's playlist | +| /minstrel listSongs | none | Lists all songs in the selected NPC's playlist in the format CATEGORY:identifier:duration | | /minstrel volume | \ \[force update (true/false)] | Displays or sets the volume of the selected minstrel | | /minstrel pitch | \ \[force update (true/false)] | Displays or sets the pitch of the selected minstrel | -### /minstrel addsong +### /minstrel addSong - sound category - The category to use when playing the song. This is used when playing the sound to decide which volume slider can be used to alter the volume. RECORDS is recommended for minstrels. You may also specify "null" as the sound @@ -49,7 +45,7 @@ There are limitations connected to directly playing media using playSound: Example: `/minstrel addsong RECORDS minecraft:music_disc.cat 185` would be used to add the CAT music disc to a playlist. -### /minstrel removesong +### /minstrel removeSong - index - The 0-based index of the song's position in the playlist. Use `/minstrel listsongs` to see the current playlist. diff --git a/pom.xml b/pom.xml index 610399e..6a50ab9 100644 --- a/pom.xml +++ b/pom.xml @@ -63,12 +63,6 @@ org/jetbrains/annotations/** - - - *.MF - *.yml - - @@ -116,13 +110,13 @@ org.spigotmc spigot-api - 1.20.4-R0.1-SNAPSHOT + 1.20.6-R0.1-SNAPSHOT provided net.knarcraft knarlib - 1.2.6 + 1.2.7 compile @@ -142,7 +136,7 @@ org.jetbrains annotations 24.0.1 - provided + compile diff --git a/src/main/java/net/knarcraft/minstrel/MinstrelPlugin.java b/src/main/java/net/knarcraft/minstrel/MinstrelPlugin.java index 8007b4d..e1f5979 100644 --- a/src/main/java/net/knarcraft/minstrel/MinstrelPlugin.java +++ b/src/main/java/net/knarcraft/minstrel/MinstrelPlugin.java @@ -10,6 +10,7 @@ import org.bukkit.Bukkit; import org.bukkit.command.PluginCommand; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -65,6 +66,7 @@ public final class MinstrelPlugin extends JavaPlugin { * * @return

All currently known minstrels

*/ + @NotNull public List getMinstrels() { return new ArrayList<>(knownMinstrels); } @@ -74,6 +76,7 @@ public final class MinstrelPlugin extends JavaPlugin { * * @return

An instance of this plugin

*/ + @NotNull public static MinstrelPlugin getInstance() { return instance; } diff --git a/src/main/java/net/knarcraft/minstrel/command/AddSongCommand.java b/src/main/java/net/knarcraft/minstrel/command/AddSongCommand.java index 2a7ccca..7e57107 100644 --- a/src/main/java/net/knarcraft/minstrel/command/AddSongCommand.java +++ b/src/main/java/net/knarcraft/minstrel/command/AddSongCommand.java @@ -64,7 +64,7 @@ public class AddSongCommand implements CommandExecutor { } Song song = new Song(category, songIdString, duration); playlist.addSong(song); - + sender.sendMessage("New song added"); return true; } diff --git a/src/main/java/net/knarcraft/minstrel/command/ListSongsCommand.java b/src/main/java/net/knarcraft/minstrel/command/ListSongsCommand.java index 81ce1ab..d50cac6 100644 --- a/src/main/java/net/knarcraft/minstrel/command/ListSongsCommand.java +++ b/src/main/java/net/knarcraft/minstrel/command/ListSongsCommand.java @@ -18,7 +18,7 @@ public class ListSongsCommand implements CommandExecutor { * * @param minstrelTrait

The minstrel to run this command on

*/ - public ListSongsCommand(MinstrelTrait minstrelTrait) { + public ListSongsCommand(@NotNull MinstrelTrait minstrelTrait) { this.minstrelTrait = minstrelTrait; } diff --git a/src/main/java/net/knarcraft/minstrel/command/MinstrelCommand.java b/src/main/java/net/knarcraft/minstrel/command/MinstrelCommand.java index 6f6abd6..527c39d 100644 --- a/src/main/java/net/knarcraft/minstrel/command/MinstrelCommand.java +++ b/src/main/java/net/knarcraft/minstrel/command/MinstrelCommand.java @@ -8,7 +8,11 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +/** + * The main command, delegating sub-commands + */ public class MinstrelCommand implements CommandExecutor { @Override @@ -57,11 +61,12 @@ public class MinstrelCommand implements CommandExecutor { * Updates the pitch for a minstrel if possible * * @param minstrelTrait

The minstrel to update the pitch for

- * @param newPitch

The new pitch for the minstrel

+ * @param newPitch

The new pitch for the minstrel, or null to display the current pitch

* @param sender

The sender to send error/success messages to

* @return

True if the pitch was successfully updated

*/ - private boolean updatePitch(MinstrelTrait minstrelTrait, String newPitch, boolean forceRefresh, CommandSender sender) { + private boolean updatePitch(@NotNull MinstrelTrait minstrelTrait, @Nullable String newPitch, boolean forceRefresh, + @NotNull CommandSender sender) { if (newPitch == null) { sender.sendMessage("Current pitch: " + minstrelTrait.getPitch()); return true; diff --git a/src/main/java/net/knarcraft/minstrel/command/MinstrelTabCompleter.java b/src/main/java/net/knarcraft/minstrel/command/MinstrelTabCompleter.java index ea62354..6802a96 100644 --- a/src/main/java/net/knarcraft/minstrel/command/MinstrelTabCompleter.java +++ b/src/main/java/net/knarcraft/minstrel/command/MinstrelTabCompleter.java @@ -16,6 +16,9 @@ import java.util.List; import static net.knarcraft.knarlib.util.TabCompletionHelper.filterMatchingContains; +/** + * The tab-completer for the minstrel command + */ public class MinstrelTabCompleter implements TabCompleter { private final List baseCommands; @@ -25,11 +28,14 @@ public class MinstrelTabCompleter implements TabCompleter { private final List exampleFloats; private final List booleans; + /** + * Instantiates a new minstrel tab completer + */ public MinstrelTabCompleter() { baseCommands = new ArrayList<>(); - baseCommands.add("addsong"); - baseCommands.add("removesong"); - baseCommands.add("listsongs"); + baseCommands.add("addSong"); + baseCommands.add("removeSong"); + baseCommands.add("listSongs"); baseCommands.add("pitch"); baseCommands.add("volume"); soundCategories = new ArrayList<>(); @@ -87,16 +93,17 @@ public class MinstrelTabCompleter implements TabCompleter { * Gets the tab-completions for removing a song * * @param minstrelTrait

The currently selected minstrel

- * @param args

THe arguments given by the user

+ * @param arguments

THe arguments given by the user

* @return

The tab-completion options to display to the user

*/ - private List tabCompleteRemoveSong(MinstrelTrait minstrelTrait, String[] args) { - if (args.length == 2) { + @NotNull + private List tabCompleteRemoveSong(@NotNull MinstrelTrait minstrelTrait, @NotNull String[] arguments) { + if (arguments.length == 2) { List indices = new ArrayList<>(); for (int i = 0; i < minstrelTrait.getPlaylist().getSongs().size(); i++) { indices.add(String.valueOf(i)); } - return filterMatchingContains(indices, args[1]); + return filterMatchingContains(indices, arguments[1]); } else { return empty; } @@ -105,20 +112,21 @@ public class MinstrelTabCompleter implements TabCompleter { /** * Gets the tab-completions for adding a song * - * @param args

The arguments given by the user

+ * @param arguments

The arguments given by the user

* @return

The tab-completion options to display to the user

*/ - private List tabCompleteAddSong(String[] args) { - if (args.length == 2) { - return filterMatchingContains(soundCategories, args[1]); - } else if (args.length == 3) { + @NotNull + private List tabCompleteAddSong(@NotNull String[] arguments) { + if (arguments.length == 2) { + return filterMatchingContains(soundCategories, arguments[1]); + } else if (arguments.length == 3) { List exampleSongNames = new ArrayList<>(); for (Sound sound : Sound.values()) { exampleSongNames.add(sound.getKey().getNamespace() + ":" + sound.getKey().getKey()); } - return filterMatchingContains(exampleSongNames, args[2]); - } else if (args.length == 4) { - return filterMatchingContains(exampleLengths, args[3]); + return filterMatchingContains(exampleSongNames, arguments[2]); + } else if (arguments.length == 4) { + return filterMatchingContains(exampleLengths, arguments[3]); } else { return empty; } diff --git a/src/main/java/net/knarcraft/minstrel/command/RemoveSongCommand.java b/src/main/java/net/knarcraft/minstrel/command/RemoveSongCommand.java index 91c302d..3728f66 100644 --- a/src/main/java/net/knarcraft/minstrel/command/RemoveSongCommand.java +++ b/src/main/java/net/knarcraft/minstrel/command/RemoveSongCommand.java @@ -19,7 +19,7 @@ public class RemoveSongCommand implements CommandExecutor { * * @param minstrelTrait

The minstrel to run this command on

*/ - public RemoveSongCommand(MinstrelTrait minstrelTrait) { + public RemoveSongCommand(@NotNull MinstrelTrait minstrelTrait) { this.minstrelTrait = minstrelTrait; } diff --git a/src/main/java/net/knarcraft/minstrel/listener/MinstrelListener.java b/src/main/java/net/knarcraft/minstrel/listener/MinstrelListener.java index ccb01c0..0498771 100644 --- a/src/main/java/net/knarcraft/minstrel/listener/MinstrelListener.java +++ b/src/main/java/net/knarcraft/minstrel/listener/MinstrelListener.java @@ -11,6 +11,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerMoveEvent; +import org.jetbrains.annotations.NotNull; /** * A listener for minstrel-relate events @@ -18,12 +19,12 @@ import org.bukkit.event.player.PlayerMoveEvent; public class MinstrelListener implements Listener { @EventHandler - public void enterWorldListener(PlayerChangedWorldEvent event) { + public void enterWorldListener(@NotNull PlayerChangedWorldEvent event) { QueueManager.clearQueue(event.getPlayer()); } @EventHandler - public void playerMoveListener(PlayerMoveEvent event) { + public void playerMoveListener(@NotNull PlayerMoveEvent event) { if (event.getTo() == null || event.getFrom().getBlock().equals(event.getTo().getBlock())) { return; } @@ -45,7 +46,7 @@ public class MinstrelListener implements Listener { * @param event

The triggered event

*/ @EventHandler - public void npcDeletionListener(NPCRemoveEvent event) { + public void npcDeletionListener(@NotNull NPCRemoveEvent event) { NPC npc = event.getNPC(); if (npc.hasTrait(MinstrelTrait.class)) { MinstrelTrait minstrelTrait = npc.getTraitNullable(MinstrelTrait.class); diff --git a/src/main/java/net/knarcraft/minstrel/manager/QueueManager.java b/src/main/java/net/knarcraft/minstrel/manager/QueueManager.java index 831ac7b..a9b5c7a 100644 --- a/src/main/java/net/knarcraft/minstrel/manager/QueueManager.java +++ b/src/main/java/net/knarcraft/minstrel/manager/QueueManager.java @@ -4,6 +4,7 @@ import net.knarcraft.minstrel.music.SongEndTime; import net.knarcraft.minstrel.trait.MinstrelTrait; import net.knarcraft.minstrel.util.SoundHelper; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.HashSet; @@ -48,7 +49,7 @@ public class QueueManager { * @param minstrelTrait

The minstrel to check

* @return

True if already queued

*/ - public static boolean isQueued(Player player, MinstrelTrait minstrelTrait) { + public static boolean isQueued(@NotNull Player player, @NotNull MinstrelTrait minstrelTrait) { return queuedMinstrels.get(player) != null && queuedMinstrels.get(player).contains(minstrelTrait); } @@ -57,7 +58,7 @@ public class QueueManager { * * @param songEndTime

The song end time to queue

*/ - public static void queue(SongEndTime songEndTime) { + public static void queue(@NotNull SongEndTime songEndTime) { songEndTimes.add(songEndTime); queuedMinstrels.computeIfAbsent(songEndTime.player(), k -> new HashSet<>()); queuedMinstrels.get(songEndTime.player()).add(songEndTime.minstrelTrait()); @@ -68,7 +69,7 @@ public class QueueManager { * * @param player

The player to clear the song queue for

*/ - public static void clearQueue(Player player) { + public static void clearQueue(@NotNull Player player) { queuedMinstrels.remove(player); songEndTimes.removeIf((songEndTime -> songEndTime.player().equals(player))); } diff --git a/src/main/java/net/knarcraft/minstrel/music/Playlist.java b/src/main/java/net/knarcraft/minstrel/music/Playlist.java index ee2e04c..3edd79d 100644 --- a/src/main/java/net/knarcraft/minstrel/music/Playlist.java +++ b/src/main/java/net/knarcraft/minstrel/music/Playlist.java @@ -4,6 +4,7 @@ import net.knarcraft.minstrel.manager.QueueManager; import net.knarcraft.minstrel.trait.MinstrelTrait; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.HashMap; @@ -23,7 +24,7 @@ public class Playlist { * * @param songs

The songs contained in this playlist

*/ - public Playlist(List songs) { + public Playlist(@NotNull List songs) { this.songs = new ArrayList<>(songs); } @@ -32,6 +33,7 @@ public class Playlist { * * @return

The songs in this playlist

*/ + @NotNull public List getSongs() { return new ArrayList<>(this.songs); } @@ -41,7 +43,7 @@ public class Playlist { * * @param song

The song to add

*/ - public void addSong(Song song) { + public void addSong(@NotNull Song song) { this.songs.add(song); } @@ -59,7 +61,7 @@ public class Playlist { * * @param player

The player to stop the playlist for

*/ - public void stop(Player player) { + public void stop(@NotNull Player player) { Integer currentSong = this.playerCurrentSong.get(player); if (currentSong == null) { return; @@ -93,9 +95,9 @@ public class Playlist { * @param trait

The the minstrel to play this playlist for

* @param player

The player to play to

*/ - public void play(MinstrelTrait trait, Player player) { + public void play(@NotNull MinstrelTrait trait, @NotNull Player player) { //If this playlist is empty, do nothing - if (this.songs.size() < 1) { + if (this.songs.isEmpty()) { return; } @@ -121,6 +123,7 @@ public class Playlist { } @Override + @NotNull public String toString() { StringBuilder builder = new StringBuilder(); for (Song song : this.songs) { diff --git a/src/main/java/net/knarcraft/minstrel/music/Song.java b/src/main/java/net/knarcraft/minstrel/music/Song.java index e3fd9b7..54816c0 100644 --- a/src/main/java/net/knarcraft/minstrel/music/Song.java +++ b/src/main/java/net/knarcraft/minstrel/music/Song.java @@ -4,6 +4,8 @@ import net.knarcraft.minstrel.trait.MinstrelTrait; import org.bukkit.Location; import org.bukkit.SoundCategory; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.HashSet; import java.util.Set; @@ -28,7 +30,7 @@ public class Song { * @param sound

The song to use

* @param durationSeconds

The duration of the song, in seconds

*/ - public Song(SoundCategory category, String sound, int durationSeconds) { + public Song(@Nullable SoundCategory category, @NotNull String sound, int durationSeconds) { this.category = category; this.sound = sound; this.durationSeconds = durationSeconds; @@ -45,7 +47,7 @@ public class Song { * @param volume

The volume to play this song at

* @param pitch

The pitch to play this song at

*/ - public void play(MinstrelTrait trait, Player player, float volume, float pitch) { + public void play(@NotNull MinstrelTrait trait, @NotNull Player player, float volume, float pitch) { playingFor.add(player); play(player, trait.getLocation(), volume, pitch); } @@ -64,7 +66,7 @@ public class Song { * * @param player

The player to stop this song for

*/ - public void stop(Player player) { + public void stop(@NotNull Player player) { //Don't bother stopping if not playing if (!playingFor.contains(player)) { return; @@ -106,6 +108,7 @@ public class Song { * * @return

The category of this song

*/ + @Nullable public SoundCategory getCategory() { return category; } @@ -115,6 +118,7 @@ public class Song { * * @return

The identifier for this song's sound

*/ + @NotNull public String getSound() { return this.sound; } diff --git a/src/main/java/net/knarcraft/minstrel/music/SongEndTime.java b/src/main/java/net/knarcraft/minstrel/music/SongEndTime.java index 235e0e7..a3bf0d6 100644 --- a/src/main/java/net/knarcraft/minstrel/music/SongEndTime.java +++ b/src/main/java/net/knarcraft/minstrel/music/SongEndTime.java @@ -3,6 +3,7 @@ package net.knarcraft.minstrel.music; import net.knarcraft.minstrel.trait.MinstrelTrait; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * A record of the time when a specific song will end @@ -11,10 +12,11 @@ import org.jetbrains.annotations.NotNull; * @param minstrelTrait

The minstrel playing the song

* @param endTime

The time when the song will end

*/ -public record SongEndTime(Player player, MinstrelTrait minstrelTrait, long endTime) implements Comparable { +public record SongEndTime(@NotNull Player player, @NotNull MinstrelTrait minstrelTrait, + long endTime) implements Comparable { @Override - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { if (!(other instanceof SongEndTime songEndTime)) { return false; } diff --git a/src/main/java/net/knarcraft/minstrel/trait/MinstrelTrait.java b/src/main/java/net/knarcraft/minstrel/trait/MinstrelTrait.java index c33e1cd..23ab0da 100644 --- a/src/main/java/net/knarcraft/minstrel/trait/MinstrelTrait.java +++ b/src/main/java/net/knarcraft/minstrel/trait/MinstrelTrait.java @@ -7,6 +7,8 @@ import net.knarcraft.minstrel.music.Playlist; import net.knarcraft.minstrel.music.Song; import org.bukkit.Location; import org.bukkit.SoundCategory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -32,6 +34,7 @@ public class MinstrelTrait extends Trait { * * @return

The location of this minstrel

*/ + @NotNull public Location getLocation() { return this.getNPC().getStoredLocation(); } @@ -42,7 +45,7 @@ public class MinstrelTrait extends Trait { * @param key

The data key used for the config root

*/ @Override - public void load(DataKey key) { + public void load(@NotNull DataKey key) { this.playlist.clear(); for (DataKey songKey : key.getRelative("playlist").getSubKeys()) { String category = songKey.getString("category"); @@ -70,7 +73,7 @@ public class MinstrelTrait extends Trait { * @param key

The data key used for the config root

*/ @Override - public void save(DataKey key) { + public void save(@NotNull DataKey key) { //Saves the songs in the playlist, the volume and the pitch key.setRaw("playlist", null); List songs = this.playlist.getSongs(); @@ -112,6 +115,7 @@ public class MinstrelTrait extends Trait { * * @return

This minstrel's playlist

*/ + @NotNull public Playlist getPlaylist() { return this.playlist; } @@ -143,7 +147,7 @@ public class MinstrelTrait extends Trait { } @Override - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { if (!(other instanceof MinstrelTrait minstrelTrait)) { return false; } diff --git a/src/main/java/net/knarcraft/minstrel/util/SoundHelper.java b/src/main/java/net/knarcraft/minstrel/util/SoundHelper.java index 74017df..cab6ad7 100644 --- a/src/main/java/net/knarcraft/minstrel/util/SoundHelper.java +++ b/src/main/java/net/knarcraft/minstrel/util/SoundHelper.java @@ -2,7 +2,11 @@ package net.knarcraft.minstrel.util; import net.knarcraft.minstrel.trait.MinstrelTrait; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +/** + * A helper class for dealing with sound + */ public class SoundHelper { /** @@ -12,7 +16,7 @@ public class SoundHelper { * @param minstrelTrait

The minstrel to check

* @return

True if the player would hear the minstrel

*/ - public static boolean canHear(Player player, MinstrelTrait minstrelTrait) { + public static boolean canHear(@NotNull Player player, @NotNull MinstrelTrait minstrelTrait) { // Minstrels cannot be heard across worlds! if (player.getLocation().getWorld() != null && minstrelTrait.getLocation().getWorld() != null && !player.getLocation().getWorld().equals(minstrelTrait.getLocation().getWorld())) {