Adds command documentation and improves tab-completion
Adds documentation for all commands to the README Adds option to force an update if changing the pitch or volume of a minstrel Adds tab-completions for removeSong, listSongs, volume and pitch commands Adds filtering for tab-completions based on current input
This commit is contained in:
parent
9db2f871c6
commit
9fd25b90f7
42
README.MD
42
README.MD
@ -26,3 +26,45 @@ There are limitations connected to directly playing media using playSound:
|
|||||||
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
|
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, it shouldn't be too much of a problem, but if several minstrels play the same song,
|
player outside the global cycle, 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 may be silent minstrels until the next song plays.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
| Command | Arguments | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| /minstrel addsong | <sound category> <sound identifier> <duration> | Adds the specified song to the selected minstrel's playlist |
|
||||||
|
| /minstrel removesong | <index (0-10000)> | 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 | <new volume (0.01 to 10000)> \[force update (true/false)] | Displays or sets the volume of the selected minstrel |
|
||||||
|
| /minstrel pitch | <new pitch (0.01 to 10000)> \[force update (true/false)] | Displays or sets the pitch of the selected minstrel |
|
||||||
|
|
||||||
|
### /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
|
||||||
|
category. It will then be played without a specific category being specified.
|
||||||
|
- sound identifier - The string used to identify the sound to play. Example: "minecraft:music_disc.cat" identifies the
|
||||||
|
cat music disc. You can also specify music in a resource pack, though nothing can be heard for players without the
|
||||||
|
resource pack.
|
||||||
|
- duration - The duration of the track, in seconds. It's important that this is exact, and not too short, as it's used
|
||||||
|
to decide when to start playing the next track in the playlist. If it's too short, several songs will end up playing
|
||||||
|
at once! Setting it higher than the actual duration can be used to add a pause before the next song is played.
|
||||||
|
|
||||||
|
Example: `/minstrel addsong RECORDS minecraft:music_disc.cat 185` would be used to add the CAT music disc to a playlist.
|
||||||
|
|
||||||
|
### /minstrel removesong
|
||||||
|
|
||||||
|
- index - The 0-based index of the song's position in the playlist. Use `/minstrel listsongs` to see the current
|
||||||
|
playlist.
|
||||||
|
|
||||||
|
Example: `/minstrel removesong 0` removes the first song in the playlist.
|
||||||
|
|
||||||
|
### /minstrel volume
|
||||||
|
|
||||||
|
- new volume - The new volume of the minstrel. Set to 1 for full volume, 0.5 for half volume, etc. If set above 1, the
|
||||||
|
minstrel can be heard from farther away, while the actual volume will be the same as for 1.0 when close to the NPC.
|
||||||
|
- force update - Whether to forcefully stop and start the minstrel's playlist to make the change happen instantly.
|
||||||
|
|
||||||
|
### /minstrel pitch
|
||||||
|
|
||||||
|
- new pitch - The new pitch used by the minstrel. Set to 1 for normal.
|
||||||
|
- force update - Whether to forcefully stop and start the minstrel's playlist to make the change happen instantly.
|
@ -32,11 +32,12 @@ public class MinstrelCommand implements CommandExecutor {
|
|||||||
case "listsongs":
|
case "listsongs":
|
||||||
return new ListSongsCommand(minstrelTrait).onCommand(sender, command, label, args);
|
return new ListSongsCommand(minstrelTrait).onCommand(sender, command, label, args);
|
||||||
case "pitch":
|
case "pitch":
|
||||||
return updatePitch(minstrelTrait, args.length > 1 ? args[1] : null, sender);
|
return updatePitch(minstrelTrait, args.length > 1 ? args[1] : null, args.length > 2 &&
|
||||||
|
Boolean.parseBoolean(args[2]), sender);
|
||||||
case "volume":
|
case "volume":
|
||||||
return updateVolume(minstrelTrait, args.length > 1 ? args[1] : null, sender);
|
return updateVolume(minstrelTrait, args.length > 1 ? args[1] : null, args.length > 2 &&
|
||||||
|
Boolean.parseBoolean(args[2]), sender);
|
||||||
}
|
}
|
||||||
//TODO: Add another argument for volume and pitch for whether to immediately change the volume by restarting the playlist
|
|
||||||
|
|
||||||
/* Sub-commands:
|
/* Sub-commands:
|
||||||
AddSong category identifier duration (remember to run play again)
|
AddSong category identifier duration (remember to run play again)
|
||||||
@ -63,7 +64,7 @@ public class MinstrelCommand implements CommandExecutor {
|
|||||||
* @param sender <p>The sender to send error/success messages to</p>
|
* @param sender <p>The sender to send error/success messages to</p>
|
||||||
* @return <p>True if the pitch was successfully updated</p>
|
* @return <p>True if the pitch was successfully updated</p>
|
||||||
*/
|
*/
|
||||||
private boolean updatePitch(MinstrelTrait minstrelTrait, String newPitch, CommandSender sender) {
|
private boolean updatePitch(MinstrelTrait minstrelTrait, String newPitch, boolean forceRefresh, CommandSender sender) {
|
||||||
if (newPitch == null) {
|
if (newPitch == null) {
|
||||||
sender.sendMessage("Current pitch: " + minstrelTrait.getPitch());
|
sender.sendMessage("Current pitch: " + minstrelTrait.getPitch());
|
||||||
return true;
|
return true;
|
||||||
@ -75,6 +76,10 @@ public class MinstrelCommand implements CommandExecutor {
|
|||||||
sender.sendMessage("The pitch cannot be negative");
|
sender.sendMessage("The pitch cannot be negative");
|
||||||
} else {
|
} else {
|
||||||
minstrelTrait.setPitch(pitch);
|
minstrelTrait.setPitch(pitch);
|
||||||
|
if (forceRefresh) {
|
||||||
|
minstrelTrait.getPlaylist().stop();
|
||||||
|
minstrelTrait.getPlaylist().play(minstrelTrait);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException exception) {
|
} catch (NumberFormatException exception) {
|
||||||
sender.sendMessage("The given pitch is not a number!");
|
sender.sendMessage("The given pitch is not a number!");
|
||||||
@ -92,7 +97,7 @@ public class MinstrelCommand implements CommandExecutor {
|
|||||||
* @param sender <p>The sender to send error/success messages to</p>
|
* @param sender <p>The sender to send error/success messages to</p>
|
||||||
* @return <p>True if the volume was successfully updated</p>
|
* @return <p>True if the volume was successfully updated</p>
|
||||||
*/
|
*/
|
||||||
private boolean updateVolume(MinstrelTrait minstrelTrait, String newVolume, CommandSender sender) {
|
private boolean updateVolume(MinstrelTrait minstrelTrait, String newVolume, boolean forceRefresh, CommandSender sender) {
|
||||||
if (newVolume == null) {
|
if (newVolume == null) {
|
||||||
sender.sendMessage("Current volume: " + minstrelTrait.getVolume());
|
sender.sendMessage("Current volume: " + minstrelTrait.getVolume());
|
||||||
return true;
|
return true;
|
||||||
@ -104,6 +109,10 @@ public class MinstrelCommand implements CommandExecutor {
|
|||||||
sender.sendMessage("The volume must be greater than 0");
|
sender.sendMessage("The volume must be greater than 0");
|
||||||
} else {
|
} else {
|
||||||
minstrelTrait.setVolume(volume);
|
minstrelTrait.setVolume(volume);
|
||||||
|
if (forceRefresh) {
|
||||||
|
minstrelTrait.getPlaylist().stop();
|
||||||
|
minstrelTrait.getPlaylist().play(minstrelTrait);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException exception) {
|
} catch (NumberFormatException exception) {
|
||||||
sender.sendMessage("The given volume is not a number!");
|
sender.sendMessage("The given volume is not a number!");
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package net.knarcraft.minstrel.command;
|
package net.knarcraft.minstrel.command;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.CitizensAPI;
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import net.knarcraft.minstrel.trait.MinstrelTrait;
|
||||||
import org.bukkit.SoundCategory;
|
import org.bukkit.SoundCategory;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -10,10 +13,16 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.knarcraft.minstrel.util.TabCompletionHelper.filterMatchingContains;
|
||||||
|
|
||||||
public class MinstrelTabCompleter implements TabCompleter {
|
public class MinstrelTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
private final List<String> baseCommands;
|
private final List<String> baseCommands;
|
||||||
private final List<String> soundCategories;
|
private final List<String> soundCategories;
|
||||||
|
private final List<String> exampleLengths;
|
||||||
|
private final List<String> empty = new ArrayList<>();
|
||||||
|
private final List<String> exampleFloats;
|
||||||
|
private final List<String> booleans;
|
||||||
|
|
||||||
public MinstrelTabCompleter() {
|
public MinstrelTabCompleter() {
|
||||||
baseCommands = new ArrayList<>();
|
baseCommands = new ArrayList<>();
|
||||||
@ -26,27 +35,91 @@ public class MinstrelTabCompleter implements TabCompleter {
|
|||||||
for (SoundCategory category : SoundCategory.values()) {
|
for (SoundCategory category : SoundCategory.values()) {
|
||||||
soundCategories.add(category.name());
|
soundCategories.add(category.name());
|
||||||
}
|
}
|
||||||
|
exampleLengths = new ArrayList<>();
|
||||||
|
exampleLengths.add("60");
|
||||||
|
exampleLengths.add("90");
|
||||||
|
exampleLengths.add("120");
|
||||||
|
exampleFloats = new ArrayList<>();
|
||||||
|
exampleFloats.add("0.5");
|
||||||
|
exampleFloats.add("1");
|
||||||
|
exampleFloats.add("1.5");
|
||||||
|
booleans = new ArrayList<>();
|
||||||
|
booleans.add("true");
|
||||||
|
booleans.add("false");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||||
@NotNull String[] args) {
|
@NotNull String[] args) {
|
||||||
if (args.length < 2) {
|
NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(sender);
|
||||||
return baseCommands;
|
if (npc == null || !npc.hasTrait(MinstrelTrait.class)) {
|
||||||
|
return empty;
|
||||||
}
|
}
|
||||||
|
MinstrelTrait minstrelTrait = npc.getTraitNullable(MinstrelTrait.class);
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
return filterMatchingContains(baseCommands, args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
switch (args[0].toLowerCase()) {
|
switch (args[0].toLowerCase()) {
|
||||||
case "addsong":
|
case "addsong":
|
||||||
|
return tabCompleteAddSong(args);
|
||||||
|
case "removesong":
|
||||||
|
return tabCompleteRemoveSong(minstrelTrait, args);
|
||||||
|
case "listsongs":
|
||||||
|
return empty;
|
||||||
|
case "volume":
|
||||||
|
case "pitch":
|
||||||
if (args.length == 2) {
|
if (args.length == 2) {
|
||||||
return soundCategories;
|
return exampleFloats;
|
||||||
} else if (args.length == 3) {
|
} else if (args.length == 3) {
|
||||||
List<String> exampleSongNames = new ArrayList<>();
|
return booleans;
|
||||||
exampleSongNames.add("minecraft:records.custom.medieval_3_g_mixolydian");
|
} else {
|
||||||
exampleSongNames.add("minecraft:block.amethyst_block.step");
|
return empty;
|
||||||
return exampleSongNames;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tab-completions for removing a song
|
||||||
|
*
|
||||||
|
* @param minstrelTrait <p>The currently selected minstrel</p>
|
||||||
|
* @param args <p>THe arguments given by the user</p>
|
||||||
|
* @return <p>The tab-completion options to display to the user</p>
|
||||||
|
*/
|
||||||
|
private List<String> tabCompleteRemoveSong(MinstrelTrait minstrelTrait, String[] args) {
|
||||||
|
if (args.length == 2) {
|
||||||
|
List<String> indices = new ArrayList<>();
|
||||||
|
for (int i = 0; i < minstrelTrait.getPlaylist().getSongs().size(); i++) {
|
||||||
|
indices.add(String.valueOf(i));
|
||||||
|
}
|
||||||
|
return filterMatchingContains(indices, args[1]);
|
||||||
|
} else {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tab-completions for adding a song
|
||||||
|
*
|
||||||
|
* @param args <p>The arguments given by the user</p>
|
||||||
|
* @return <p>The tab-completion options to display to the user</p>
|
||||||
|
*/
|
||||||
|
private List<String> tabCompleteAddSong(String[] args) {
|
||||||
|
if (args.length == 2) {
|
||||||
|
return filterMatchingContains(soundCategories, args[1]);
|
||||||
|
} else if (args.length == 3) {
|
||||||
|
List<String> exampleSongNames = new ArrayList<>();
|
||||||
|
exampleSongNames.add("minecraft:records.custom.medieval_3_g_mixolydian");
|
||||||
|
exampleSongNames.add("minecraft:block.amethyst_block.step");
|
||||||
|
return filterMatchingContains(exampleSongNames, args[2]);
|
||||||
|
} else if (args.length == 4) {
|
||||||
|
return filterMatchingContains(exampleLengths, args[3]);
|
||||||
|
} else {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package net.knarcraft.minstrel.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class for tab-completion
|
||||||
|
*/
|
||||||
|
public final class TabCompletionHelper {
|
||||||
|
|
||||||
|
private TabCompletionHelper() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds tab complete values that contain the typed text
|
||||||
|
*
|
||||||
|
* @param values <p>The values to filter</p>
|
||||||
|
* @param typedText <p>The text the player has started typing</p>
|
||||||
|
* @return <p>The given string values that contain the player's typed text</p>
|
||||||
|
*/
|
||||||
|
public static List<String> filterMatchingContains(List<String> values, String typedText) {
|
||||||
|
List<String> configValues = new ArrayList<>();
|
||||||
|
for (String value : values) {
|
||||||
|
if (value.toLowerCase().contains(typedText.toLowerCase())) {
|
||||||
|
configValues.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user