EpicKnarvik97 05781ff15e Changes song scheduling to hopefully fix a bug
There was an observed bug, where two songs in a playlist were playing at once after a third song was removed.
2022-11-05 13:03:30 +01:00

152 lines
4.8 KiB
Java

package net.knarcraft.minstrel.music;
import net.knarcraft.minstrel.MinstrelPlugin;
import net.knarcraft.minstrel.trait.MinstrelTrait;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Set;
/**
* A representation of a song playable by a minstrel
*
* <p>Note: Any custom song has to be mono to fade out like a normal jukebox. If it's stereo, you'll end up with a
* global song instead.</p>
*/
public class Song {
private final int durationSeconds;
private final SoundCategory category;
private final String sound;
private boolean isPlaying = false;
private final Set<Player> playingFor = new HashSet<>();
/**
* Instantiates a new song
*
* @param category <p>The category the song belongs to</p>
* @param sound <p>The song to use</p>
* @param durationSeconds <p>The duration of the song, in seconds</p>
*/
public Song(SoundCategory category, String sound, int durationSeconds) {
this.category = category;
this.sound = sound;
this.durationSeconds = durationSeconds;
}
/**
* Plays this song at the given minstrel's location, but only for the given player
*
* <p>Volume of 1 means the max volume, which can be heard up to 1 chunk away. Setting it to 2 means it can be
* heard 2 chunks away.</p>
*
* @param trait <p>The minstrel to play this song</p>
* @param player <p>The player to play this song for</p>
* @param volume <p>The volume to play this song at</p>
* @param pitch <p>The pitch to play this song at</p>
*/
public void play(MinstrelTrait trait, Player player, float volume, float pitch) {
playingFor.add(player);
play(player, trait.getLocation(), volume, pitch);
}
/**
* Plays this song at the given minstrel's location
*
* <p>Volume of 1 means the max volume, which can be heard up to 1 chunk away. Setting it to 2 means it can be
* heard 2 chunks away.</p>
*
* @param trait <p>The minstrel to play this song</p>
* @param volume <p>The volume to play this song at</p>
* @param pitch <p>The pitch to play this song at</p>
*/
public void play(MinstrelTrait trait, float volume, float pitch) {
for (Player player : Bukkit.getOnlinePlayers()) {
play(player, trait.getLocation(), volume, pitch);
}
this.isPlaying = true;
//Mark this song as ended, once
Bukkit.getScheduler().runTaskLater(MinstrelPlugin.getInstance(), () -> this.isPlaying = false,
durationSeconds * 20L);
}
/**
* Gets the duration of this song, in seconds
*
* @return <p>The duration of this song</p>
*/
public int getDuration() {
return durationSeconds;
}
/**
* Stops this song for the given player
*
* @param player <p>The player to stop this song for</p>
*/
public void stop(Player player) {
//Don't bother stopping if not playing
if (!playingFor.contains(player) && !isPlaying) {
return;
}
playingFor.remove(player);
if (this.category == null) {
player.stopSound(this.sound);
} else {
player.stopSound(this.sound, this.category);
}
}
/**
* Plays this song for the given player, at the given location
*
* @param player <p>The player to play this song for</p>
* @param location <p>The location to play the song at</p>
* @param volume <p>The volume to play at</p>
* @param pitch <p>The pitch to play at</p>
*/
private void play(Player player, Location location, float volume, float pitch) {
if (this.category == null) {
player.playSound(location, this.sound, volume, pitch);
} else {
player.playSound(location, this.sound, this.category, volume, pitch);
}
}
@Override
public String toString() {
String songString = this.category + ":" + this.sound + ":" + this.durationSeconds;
if (this.isPlaying) {
return ">" + songString;
} else {
return songString;
}
}
/**
* Gets the category of this song
*
* <p>Note: The category is only used to tell which volume slider affects the song volume, and which type of sounds
* may prevent this from playing. RECORDS is preferable for minstrels.</p>
*
* @return <p>The category of this song</p>
*/
public SoundCategory getCategory() {
return category;
}
/**
* Gets the identifier for this song's sound
*
* @return <p>The identifier for this song's sound</p>
*/
public String getSound() {
return this.sound;
}
}