Skip to content

Commit 9ccfaf5

Browse files
committed
More commands
Signed-off-by: Walker Crouse <[email protected]>
1 parent 9de55e4 commit 9ccfaf5

File tree

7 files changed

+388
-77
lines changed

7 files changed

+388
-77
lines changed

out/production/Composer/default.conf

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
debugMode=false

src/main/java/se/walkercrou/composer/Composer.java

+19-14
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import ninja.leaping.configurate.loader.ConfigurationLoader;
77
import org.slf4j.Logger;
88
import org.spongepowered.api.config.DefaultConfig;
9+
import org.spongepowered.api.entity.living.player.Player;
910
import org.spongepowered.api.event.Listener;
1011
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
1112
import org.spongepowered.api.plugin.Plugin;
1213
import se.walkercrou.composer.cmd.ComposerCommands;
1314
import se.walkercrou.composer.cmd.TestCommands;
15+
import se.walkercrou.composer.nbs.MusicPlayer;
1416
import se.walkercrou.composer.nbs.NoteBlockStudioSong;
1517

1618
import java.io.File;
@@ -31,7 +33,7 @@ public class Composer {
3133
@Inject @DefaultConfig(sharedRoot = false) private ConfigurationLoader<CommentedConfigurationNode> configLoader;
3234
private ConfigurationNode config;
3335
private final List<NoteBlockStudioSong> nbsTracks = new ArrayList<>();
34-
private final Map<UUID, Score> nowPlaying = new HashMap<>();
36+
private final Map<UUID, MusicPlayer> musicPlayers = new HashMap<>();
3537

3638
@Listener
3739
public void onGameStarted(GameStartedServerEvent event) {
@@ -42,22 +44,21 @@ public void onGameStarted(GameStartedServerEvent event) {
4244
loadTracks();
4345
}
4446

47+
public MusicPlayer getMusicPlayer(Player player) {
48+
UUID playerId = player.getUniqueId();
49+
MusicPlayer mp = musicPlayers.get(playerId);
50+
if (mp == null)
51+
musicPlayers.put(playerId, mp = new MusicPlayer(this, getNbsTracks()));
52+
return mp;
53+
}
54+
4555
/**
4656
* Returns the currently loaded {@link NoteBlockStudioSong}s.
4757
*
4858
* @return list of tracks
4959
*/
5060
public List<NoteBlockStudioSong> getNbsTracks() {
51-
return nbsTracks;
52-
}
53-
54-
/**
55-
* Returns a map of songs that are playing for players.
56-
*
57-
* @return songs that are playing
58-
*/
59-
public Map<UUID, Score> nowPlaying() {
60-
return nowPlaying;
61+
return Collections.unmodifiableList(nbsTracks);
6162
}
6263

6364
private void loadTracks() {
@@ -71,11 +72,15 @@ private void loadTracks() {
7172
progress(progress);
7273
try (DirectoryStream<Path> stream = Files.newDirectoryStream(file.toPath(), "*.nbs")) {
7374
for (Path path : stream) {
74-
nbsTracks.add(NoteBlockStudioSong.read(path.toFile()));
75-
progress(++progress / total * 100);
75+
try {
76+
nbsTracks.add(NoteBlockStudioSong.read(path.toFile()));
77+
progress(++progress / total * 100);
78+
} catch (IOException e) {
79+
log.error("Could not read file (file is likely malformed): " + path, e);
80+
}
7681
}
7782
} catch (IOException e) {
78-
log.info("An error occurred while loading the tracks.", e);
83+
log.error("An error occurred while loading the tracks.", e);
7984
}
8085

8186
}).start();

src/main/java/se/walkercrou/composer/Layer.java

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.flowpowered.math.vector.Vector3d;
44
import org.spongepowered.api.effect.Viewer;
5+
import org.spongepowered.api.entity.living.player.Player;
56

67
import java.util.ArrayList;
78
import java.util.Arrays;
@@ -42,6 +43,7 @@ protected boolean onStep(Viewer viewer, Vector3d pos, int currentStep, int steps
4243
// play next note
4344
Measure measure = measures.get(currentMeasure - 1);
4445
Note note = measure.getNotes()[noteIndex++];
46+
pos = pos == null && viewer instanceof Player ? ((Player) viewer).getLocation().getPosition() : pos;
4547
note.play(viewer, pos);
4648
hold = (int) (note.getBeatsForTime(time) * stepsPerBeat);
4749
}

src/main/java/se/walkercrou/composer/Score.java

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.flowpowered.math.vector.Vector3d;
44
import org.spongepowered.api.Sponge;
55
import org.spongepowered.api.effect.Viewer;
6+
import org.spongepowered.api.entity.living.player.Player;
67
import org.spongepowered.api.scheduler.Task;
78

89
import java.util.ArrayList;
@@ -122,6 +123,16 @@ public void play(Composer context, Viewer viewer, Vector3d pos) {
122123
.submit(context);
123124
}
124125

126+
/**
127+
* Plays the score for the specified {@link Player} and uses their current location for each note.
128+
*
129+
* @param context plugin
130+
* @param viewer player
131+
*/
132+
public void play(Composer context, Player viewer) {
133+
play(context, viewer, null);
134+
}
135+
125136
/**
126137
* Pauses the song.
127138
*/

src/main/java/se/walkercrou/composer/cmd/ComposerCommands.java

+103-63
Original file line numberDiff line numberDiff line change
@@ -5,105 +5,145 @@
55
import org.spongepowered.api.command.CommandResult;
66
import org.spongepowered.api.command.CommandSource;
77
import org.spongepowered.api.command.args.CommandContext;
8-
import org.spongepowered.api.command.args.GenericArguments;
98
import org.spongepowered.api.command.spec.CommandSpec;
109
import org.spongepowered.api.entity.living.player.Player;
11-
import org.spongepowered.api.service.pagination.PaginationService;
1210
import org.spongepowered.api.text.Text;
13-
import org.spongepowered.api.text.action.TextActions;
14-
import org.spongepowered.api.text.format.TextColors;
1511
import se.walkercrou.composer.Composer;
16-
import se.walkercrou.composer.Score;
17-
import se.walkercrou.composer.nbs.NoteBlockStudioSong;
12+
import se.walkercrou.composer.util.TextUtil;
13+
import se.walkercrou.composer.nbs.MusicPlayer;
1814

19-
import java.util.ArrayList;
20-
import java.util.List;
21-
import java.util.Map;
22-
import java.util.UUID;
15+
import static org.spongepowered.api.command.args.GenericArguments.*;
2316

2417
/**
2518
* Main commands for plugin.
2619
*/
2720
public class ComposerCommands {
2821
private final Composer plugin;
2922
private final CommandSpec list = CommandSpec.builder()
30-
.arguments(GenericArguments.optional(GenericArguments.integer(Text.of("page"))))
23+
.arguments(optional(integer(Text.of("page"))))
3124
.description(Text.of("Lists the currently loaded tracks."))
3225
.executor(this::listTracks)
3326
.build();
34-
private final CommandSpec main = CommandSpec.builder()
27+
private final CommandSpec play = CommandSpec.builder()
28+
.arguments(flags()
29+
.valueFlag(player(Text.of("player")), "p")
30+
.buildWith(integer(Text.of("trackNumber")))
31+
)
32+
.description(Text.of("Plays the specified track."))
33+
.executor(this::playTrack)
34+
.build();
35+
private final CommandSpec pause = CommandSpec.builder()
36+
.arguments(optional(player(Text.of("player"))))
37+
.description(Text.of("Pauses the track that is currently playing."))
38+
.executor(this::pauseTrack)
39+
.build();
40+
private final CommandSpec resume = CommandSpec.builder()
41+
.arguments(optional(player(Text.of("player"))))
42+
.description(Text.of("Resumes playing or starts playing the first track."))
43+
.executor(this::resumeTrack)
44+
.build();
45+
private final CommandSpec shuffle = CommandSpec.builder()
46+
.arguments(optional(player(Text.of("player"))))
47+
.description(Text.of("Shuffles the tracks and starts playing."))
48+
.executor(this::shuffleTracks)
49+
.build();
50+
private final CommandSpec queue = CommandSpec.builder()
51+
.arguments(optional(player(Text.of("player"))))
52+
.description(Text.of("Prints the specified player's play queue."))
53+
.executor(this::printPlayQueue)
54+
.build();
55+
private final CommandSpec next = CommandSpec.builder()
56+
.arguments(optional(player(Text.of("player"))))
57+
.description(Text.of("Starts the next song in the queue."))
58+
.executor(this::nextTrack)
59+
.build();
60+
private final CommandSpec previous = CommandSpec.builder()
61+
.arguments(optional(player(Text.of("player"))))
62+
.description(Text.of("Goes back to the previous song in the queue."))
63+
.executor(this::previousTrack)
64+
.build();
65+
private final CommandSpec base = CommandSpec.builder()
3566
.description(Text.of("Main parent command for plugin."))
67+
.executor(this::listTracks)
3668
.child(list, "list", "list-tracks", "tracks", "track-list")
69+
.child(play, "play", "start", ">")
70+
.child(pause, "pause", "stop", "||")
71+
.child(resume, "resume")
72+
.child(shuffle, "shuffle")
73+
.child(queue, "queue", "order")
74+
.child(next, "next", "skip", ">|")
75+
.child(previous, "previous", "back", "|<")
3776
.build();
3877

3978
public ComposerCommands(Composer plugin) {
4079
this.plugin = plugin;
4180
}
4281

4382
public void register() {
44-
Sponge.getCommandManager().register(plugin, main, "music", "composer");
83+
Sponge.getCommandManager().register(plugin, base, "music", "composer");
4584
}
4685

47-
/**
48-
* Lists the currently loaded tracks.
49-
*
50-
* @param source command source
51-
* @param context command context
52-
* @return result
53-
*/
54-
public CommandResult listTracks(CommandSource source, CommandContext context) throws CommandException {
55-
List<NoteBlockStudioSong> tracks = plugin.getNbsTracks();
56-
List<Text> trackListings = new ArrayList<>(tracks.size());
86+
public CommandResult previousTrack(CommandSource src, CommandContext context) throws CommandException {
87+
Player player = getPlayer(src, context);
88+
plugin.getMusicPlayer(player).previous(player);
89+
return CommandResult.success();
90+
}
5791

58-
final Player player = source instanceof Player ? (Player) source : null;
59-
for (int i = 0; i < tracks.size(); i++) {
60-
final int index = i;
61-
NoteBlockStudioSong track = tracks.get(i);
62-
trackListings.add(trackText(track)
63-
.onClick(TextActions.executeCallback(src -> playSong(player, index)))
64-
.build());
65-
}
92+
public CommandResult nextTrack(CommandSource src, CommandContext context) throws CommandException {
93+
Player player = getPlayer(src, context);
94+
plugin.getMusicPlayer(player).next(player);
95+
return CommandResult.success();
96+
}
97+
98+
public CommandResult printPlayQueue(CommandSource src, CommandContext context) throws CommandException {
99+
Player player = getPlayer(src, context);
100+
TextUtil.trackList(plugin.getMusicPlayer(player).getTracks()).sendTo(src);
101+
return CommandResult.success();
102+
}
66103

67-
if (trackListings.isEmpty())
68-
throw new CommandException(Text.of("There are no tracks currently loaded."));
104+
public CommandResult shuffleTracks(CommandSource src, CommandContext context) throws CommandException {
105+
Player player = getPlayer(src, context);
106+
plugin.getMusicPlayer(player).shuffle(player);
107+
return CommandResult.success();
108+
}
69109

70-
Sponge.getServiceManager().provide(PaginationService.class).get().builder()
71-
.contents(trackListings)
72-
.title(Text.builder("Tracks").color(TextColors.GOLD).build())
73-
.footer(Text.builder("Click a track to play it").color(TextColors.GRAY).build())
74-
.paddingString("-")
75-
.sendTo(source);
110+
public CommandResult resumeTrack(CommandSource src, CommandContext context) throws CommandException {
111+
Player player = getPlayer(src, context);
112+
MusicPlayer mp = plugin.getMusicPlayer(player);
113+
if (mp.isPlaying())
114+
throw new CommandException(Text.of("Music already playing."));
115+
mp.play(player);
116+
return CommandResult.success();
117+
}
76118

119+
public CommandResult pauseTrack(CommandSource src, CommandContext context) throws CommandException {
120+
Player player = getPlayer(src, context);
121+
MusicPlayer mp = plugin.getMusicPlayer(player);
122+
if (!mp.isPlaying())
123+
throw new CommandException(Text.of("No music playing."));
124+
mp.pause();
77125
return CommandResult.success();
78126
}
79127

80-
private Text.Builder trackText(NoteBlockStudioSong track) {
81-
return Text.builder(strOrUnknown(track.name))
82-
.color(TextColors.GREEN)
83-
.append(Text.builder(" by ").color(TextColors.GRAY).build())
84-
.append(Text.builder(strOrUnknown(track.ogAuthor).equals("Unknown")
85-
? strOrUnknown(track.author) : track.ogAuthor)
86-
.color(TextColors.GREEN)
87-
.build());
128+
public CommandResult playTrack(CommandSource src, CommandContext context) throws CommandException {
129+
int trackIndex = context.<Integer>getOne("trackNumber").get() - 1;
130+
Player player = getPlayer(src, context);
131+
plugin.getMusicPlayer(player).play(player, trackIndex);
132+
return CommandResult.success();
88133
}
89134

90-
private String strOrUnknown(String str) {
91-
return str == null || str.isEmpty() ? "Unknown" : str;
135+
public CommandResult listTracks(CommandSource source, CommandContext context) throws CommandException {
136+
TextUtil.trackList(plugin.getNbsTracks()).sendTo(source);
137+
return CommandResult.success();
92138
}
93139

94-
private void playSong(Player player, int index) {
95-
Map<UUID, Score> nowPlaying = plugin.nowPlaying();
96-
UUID id = player.getUniqueId();
97-
Score currentSong = nowPlaying.get(id);
98-
NoteBlockStudioSong track = plugin.getNbsTracks().get(index);
99-
Score newSong = track.toScore().onFinish(() -> nowPlaying.put(id, null));
100-
if (currentSong != null)
101-
currentSong.finish();
102-
newSong.play(plugin, player, player.getLocation().getPosition());
103-
nowPlaying.put(id, newSong);
104-
player.sendMessage(Text.builder("Now playing: ")
105-
.color(TextColors.GOLD)
106-
.append(trackText(track).build())
107-
.build());
140+
private Player getPlayer(CommandSource src, CommandContext context) throws CommandException {
141+
Player player = context.<Player>getOne("player").orElse(null);
142+
if (player == null) {
143+
if (!(src instanceof Player))
144+
throw new CommandException(Text.of("Cannot run command as non-player without player argument."));
145+
player = (Player) src;
146+
}
147+
return player;
108148
}
109149
}

0 commit comments

Comments
 (0)