songplayer music
This commit is contained in:
parent
b35218fef9
commit
364afb0879
3 changed files with 189 additions and 0 deletions
|
@ -79,6 +79,7 @@ public class MusicCommand extends Command {
|
|||
return switch (action) {
|
||||
case "play", "playurl", "playnbs", "playnbsurl" -> play(context);
|
||||
case "playfromitem", "playitem" -> playFromItem(context);
|
||||
case "playsongplayer" -> playSongPlayer(context);
|
||||
case "stop" -> stop(context);
|
||||
case "loop" -> loop(context);
|
||||
case "list" -> list(context);
|
||||
|
@ -256,6 +257,67 @@ public class MusicCommand extends Command {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Component playSongPlayer (CommandContext context) throws CommandException {
|
||||
// dupe codes ??
|
||||
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final CompletableFuture<CompoundTag> future = bot.core.runTracked(
|
||||
"minecraft:data get entity " +
|
||||
UUIDUtilities.selector(context.sender.profile.getId()) +
|
||||
" SelectedItem.tag.SongItemData.SongData"
|
||||
);
|
||||
|
||||
if (future == null) {
|
||||
throw new CommandException(Component.text("There was an error while getting your data"));
|
||||
}
|
||||
|
||||
future.thenApply(tags -> {
|
||||
if (!tags.contains("LastOutput") || !(tags.get("LastOutput") instanceof StringTag)) return tags;
|
||||
|
||||
final StringTag lastOutput = tags.get("LastOutput");
|
||||
|
||||
final Component output = GsonComponentSerializer.gson().deserialize(lastOutput.getValue());
|
||||
|
||||
final List<Component> children = output.children();
|
||||
|
||||
if (
|
||||
!children.isEmpty() &&
|
||||
!children.get(0).children().isEmpty() &&
|
||||
((TranslatableComponent) children.get(0).children().get(0))
|
||||
.key()
|
||||
.equals("arguments.nbtpath.nothing_found")
|
||||
) {
|
||||
context.sendOutput(Component.text("Player has no SongItemData -> SongData NBT tag in the selected item").color(NamedTextColor.RED));
|
||||
return tags;
|
||||
}
|
||||
|
||||
final String value = ComponentUtilities.stringify(((TranslatableComponent) children.get(0)).args().get(1));
|
||||
|
||||
if (!value.startsWith("\"") && !value.endsWith("\"") && !value.startsWith("'") && !value.endsWith("'")) {
|
||||
context.sendOutput(Component.text("NBT is not a string").color(NamedTextColor.RED));
|
||||
return tags;
|
||||
}
|
||||
|
||||
try {
|
||||
bot.music.loadSong(
|
||||
Base64.getDecoder().decode(
|
||||
value
|
||||
.substring(1)
|
||||
.substring(0, value.length() - 2)
|
||||
),
|
||||
context.sender
|
||||
);
|
||||
} catch (IllegalArgumentException e) {
|
||||
context.sendOutput(Component.text("Invalid song data in the selected item").color(NamedTextColor.RED));
|
||||
}
|
||||
|
||||
return tags;
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Component stop (CommandContext context) {
|
||||
final Bot bot = context.bot;
|
||||
bot.music.stopPlaying();
|
||||
|
|
|
@ -25,6 +25,7 @@ public class SongLoaderThread extends Thread {
|
|||
converters.add(new MidiConverter());
|
||||
converters.add(new NBSConverter());
|
||||
converters.add(new TextFileConverter());
|
||||
converters.add(new SongPlayerConverter());
|
||||
}
|
||||
|
||||
public final String fileName;
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package land.chipmunk.chayapak.chomens_bot.song;
|
||||
|
||||
import land.chipmunk.chayapak.chomens_bot.Bot;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
// Author: hhhzzzsss (i ported it from songplayer)
|
||||
public class SongPlayerConverter implements Converter {
|
||||
public static final byte[] FILE_TYPE_SIGNATURE = {-53, 123, -51, -124, -122, -46, -35, 38};
|
||||
public static final long MAX_UNCOMPRESSED_SIZE = 50 * 1024 * 1024;
|
||||
|
||||
@Override
|
||||
public Song getSongFromBytes(byte[] bytes, String fileName, Bot bot) throws Exception {
|
||||
InputStream is = new LimitedSizeInputStream(new GZIPInputStream(new ByteArrayInputStream(bytes)), MAX_UNCOMPRESSED_SIZE);
|
||||
bytes = is.readAllBytes();
|
||||
is.close();
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
for (byte b : FILE_TYPE_SIGNATURE) {
|
||||
if (b != buffer.get()) {
|
||||
throw new IOException("Invalid file type signature");
|
||||
}
|
||||
}
|
||||
|
||||
byte version = buffer.get();
|
||||
// Currently on format version 1
|
||||
if (version != 1) {
|
||||
throw new IOException("Unsupported format version!");
|
||||
}
|
||||
|
||||
long songLength = buffer.getLong();
|
||||
String songName = getString(buffer, bytes.length);
|
||||
int loop = buffer.get() & 0xFF;
|
||||
int loopCount = buffer.get() & 0xFF;
|
||||
long loopPosition = buffer.getLong();
|
||||
|
||||
Song song = new Song(fileName, bot, !songName.trim().isEmpty() ? songName : null, null, null, null, false);
|
||||
song.length = songLength;
|
||||
// song.looping = loop > 0;
|
||||
// song.loopCount = loopCount;
|
||||
song.loopPosition = loopPosition == 0 ? 200 : loopPosition;
|
||||
|
||||
long time = 0;
|
||||
while (true) {
|
||||
int noteId = buffer.getShort();
|
||||
if (noteId >= 0 && noteId < 400) {
|
||||
time += getVarLong(buffer);
|
||||
song.add(new Note(Instrument.fromId(noteId / 25), noteId % 25, noteId % 25, 1, time, -1, 100));
|
||||
}
|
||||
else if ((noteId & 0xFFFF) == 0xFFFF) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
throw new IOException("Song contains invalid note id of " + noteId);
|
||||
}
|
||||
}
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
private static String getString(ByteBuffer buffer, int maxSize) throws IOException {
|
||||
int length = buffer.getInt();
|
||||
if (length > maxSize) {
|
||||
throw new IOException("String is too large");
|
||||
}
|
||||
byte[] arr = new byte[length];
|
||||
buffer.get(arr, 0, length);
|
||||
return new String(arr, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static long getVarLong(ByteBuffer buffer) {
|
||||
long val = 0;
|
||||
long mult = 1;
|
||||
int flag = 1;
|
||||
while (flag != 0) {
|
||||
int b = buffer.get() & 0xFF;
|
||||
val += (b & 0x7F) * mult;
|
||||
mult <<= 7;
|
||||
flag = b >>> 7;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
private static class LimitedSizeInputStream extends InputStream {
|
||||
private final InputStream original;
|
||||
private final long maxSize;
|
||||
private long total;
|
||||
|
||||
public LimitedSizeInputStream(InputStream original, long maxSize) {
|
||||
this.original = original;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int i = original.read();
|
||||
if (i>=0) incrementCounter(1);
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[]) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
int i = original.read(b, off, len);
|
||||
if (i>=0) incrementCounter(i);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void incrementCounter(int size) throws IOException {
|
||||
total += size;
|
||||
if (total>maxSize) throw new IOException("Input stream exceeded maximum size of " + maxSize + " bytes");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue