33import java .lang .reflect .Constructor ;
44import java .lang .reflect .InvocationTargetException ;
55import java .lang .reflect .Method ;
6- import java .util .ArrayList ;
7- import java .util .Collections ;
8- import java .util .HashMap ;
9- import java .util .HashSet ;
10- import java .util .Map ;
11- import java .util .Set ;
12- import java .util .UUID ;
6+ import java .util .*;
137import java .util .concurrent .locks .Lock ;
148import java .util .concurrent .locks .ReentrantLock ;
159
@@ -48,14 +42,16 @@ public abstract class SongPlayer {
4842 protected boolean autoDestroy = false ;
4943 protected boolean destroyed = false ;
5044
51- protected Thread playerThread ;
52-
5345 protected byte volume = 100 ;
5446 protected Fade fadeIn ;
5547 protected Fade fadeOut ;
5648 protected boolean loop = false ;
49+ protected boolean random = false ;
50+
51+ protected Map <Song , Boolean > songQueue = Collections .synchronizedMap (new HashMap <Song , Boolean >()); //True if already played
5752
5853 private final Lock lock = new ReentrantLock ();
54+ private Random rng = new Random ();
5955
6056 protected NoteBlockAPI plugin ;
6157
@@ -68,17 +64,24 @@ public SongPlayer(Song song) {
6864 }
6965
7066 public SongPlayer (Song song , SoundCategory soundCategory ) {
71- //this.song = song;
7267 this (new Playlist (song ), soundCategory );
7368 }
69+
70+ public SongPlayer (Song song , SoundCategory soundCategory , boolean random ) {
71+ this (new Playlist (song ), soundCategory , random );
72+ }
7473
7574 public SongPlayer (Playlist playlist ){
7675 this (playlist , SoundCategory .MASTER );
7776 }
78-
77+
7978 public SongPlayer (Playlist playlist , SoundCategory soundCategory ){
79+ this (playlist , soundCategory , false );
80+ }
81+
82+ public SongPlayer (Playlist playlist , SoundCategory soundCategory , boolean random ){
8083 this .playlist = playlist ;
81- this .song = playlist . get ( actualSong ) ;
84+ this .random = random ;
8285 this .soundCategory = soundCategory ;
8386 plugin = NoteBlockAPI .getAPI ();
8487
@@ -89,10 +92,20 @@ public SongPlayer(Playlist playlist, SoundCategory soundCategory){
8992 fadeOut = new Fade (FadeType .NONE , 60 );
9093 fadeOut .setFadeStart (volume );
9194 fadeOut .setFadeTarget ((byte ) 0 );
92-
95+
96+ if (random ){
97+ checkPlaylistQueue ();
98+ actualSong = rng .nextInt (playlist .getCount ());
99+ }
100+ this .song = playlist .get (actualSong );
101+
93102 start ();
94103 }
95-
104+
105+ /**
106+ * @deprecated
107+ * @param songPlayer
108+ */
96109 SongPlayer (com .xxmicloxx .NoteBlockAPI .SongPlayer songPlayer ){
97110 oldSongPlayer = songPlayer ;
98111 com .xxmicloxx .NoteBlockAPI .Song s = songPlayer .getSong ();
@@ -306,23 +319,60 @@ private void start() {
306319 fadeIn .setFadeDone (0 );
307320 CallUpdate ("fadeDone" , fadeIn .getFadeDone ());
308321 fadeOut .setFadeDone (0 );
309- if (playlist .hasNext (actualSong )){
310- actualSong ++;
311- song = playlist .get (actualSong );
312- CallUpdate ("song" , song );
313- SongNextEvent event = new SongNextEvent (this );
314- plugin .doSync (() -> Bukkit .getPluginManager ().callEvent (event ));
315- continue ;
316- } else {
317- actualSong = 0 ;
318- song = playlist .get (actualSong );
319- CallUpdate ("song" , song );
320- if (loop ){
321- SongLoopEvent event = new SongLoopEvent (this );
322+ if (random ){
323+ songQueue .put (song , true );
324+ checkPlaylistQueue ();
325+ ArrayList <Song > left = new ArrayList <>();
326+ for (Song s : songQueue .keySet ()){
327+ if (!songQueue .get (s )){
328+ left .add (s );
329+ }
330+ }
331+
332+ if (left .size () == 0 ){
333+ left .addAll (songQueue .keySet ());
334+ for (Song s : songQueue .keySet ()) {
335+ songQueue .put (s , false );
336+ }
337+ song = left .get (rng .nextInt (left .size ()));
338+ actualSong = playlist .getIndex (song );
339+ CallUpdate ("song" , song );
340+ if (loop ) {
341+ SongLoopEvent event = new SongLoopEvent (this );
342+ plugin .doSync (() -> Bukkit .getPluginManager ().callEvent (event ));
343+
344+ if (!event .isCancelled ()) {
345+ continue ;
346+ }
347+ }
348+ } else {
349+ song = left .get (rng .nextInt (left .size ()));
350+ actualSong = playlist .getIndex (song );
351+
352+ CallUpdate ("song" , song );
353+ SongNextEvent event = new SongNextEvent (this );
354+ plugin .doSync (() -> Bukkit .getPluginManager ().callEvent (event ));
355+ continue ;
356+ }
357+ } else {
358+ if (playlist .hasNext (actualSong )) {
359+ actualSong ++;
360+ song = playlist .get (actualSong );
361+ CallUpdate ("song" , song );
362+ SongNextEvent event = new SongNextEvent (this );
322363 plugin .doSync (() -> Bukkit .getPluginManager ().callEvent (event ));
323-
324- if (!event .isCancelled ()){
325- continue ;
364+ continue ;
365+ } else {
366+ actualSong = 0 ;
367+ song = playlist .get (actualSong );
368+ CallUpdate ("song" , song );
369+ if (loop ) {
370+ SongLoopEvent event = new SongLoopEvent (this );
371+ plugin .doSync (() -> Bukkit .getPluginManager ().callEvent (event ));
372+
373+ if (!event .isCancelled ()) {
374+ continue ;
375+ }
326376 }
327377 }
328378 }
@@ -369,6 +419,20 @@ private void start() {
369419 }
370420 });
371421 }
422+
423+ private void checkPlaylistQueue (){
424+ for (Song s : songQueue .keySet ()){
425+ if (!playlist .contains (s )){
426+ songQueue .remove (s );
427+ }
428+ }
429+
430+ for (Song s : playlist .getSongList ()){
431+ if (!songQueue .containsKey (s )){
432+ songQueue .put (s , false );
433+ }
434+ }
435+ }
372436
373437 /**
374438 * Returns {@link Fade} for Fade in effect
@@ -688,6 +752,22 @@ public boolean isLoop(){
688752 return loop ;
689753 }
690754
755+ /**
756+ * Sets whether the SongPlayer will choose next song from player randomly
757+ * @param random
758+ */
759+ public void setRandom (boolean random ){
760+ this .random = random ;
761+ }
762+
763+ /**
764+ * Gets whether the SongPlayer will choose next song from player randomly
765+ * @return is random
766+ */
767+ public boolean isRandom (){
768+ return random ;
769+ }
770+
691771 void CallUpdate (String key , Object value ){
692772 try {
693773 Method m = com .xxmicloxx .NoteBlockAPI .SongPlayer .class .getDeclaredMethod ("update" , String .class , Object .class );
0 commit comments