diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java index 5327deb..3faa915 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java @@ -220,7 +220,7 @@ public class MusicCommand { mergedList.addAll(files); final Component component = Component.translatable("Songs - %s", Component.join(JoinConfiguration.separator(Component.space()), mergedList)).color(NamedTextColor.GREEN); - ((Audience) MinecraftClient.getInstance().player).sendMessage(component); + MinecraftClient.getInstance().player.sendMessage(component); return 1; } diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java b/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java index 72740cc..6e5fbea 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java @@ -5,7 +5,7 @@ import land.chipmunk.chipmunkmod.song.Song; import land.chipmunk.chipmunkmod.song.SongLoaderException; import land.chipmunk.chipmunkmod.song.SongLoaderThread; import land.chipmunk.chipmunkmod.util.MathUtilities; -import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -14,7 +14,6 @@ import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; -import net.minecraft.text.Text; import net.minecraft.util.Identifier; import java.io.File; @@ -55,35 +54,42 @@ public class SongPlayer { // TODO: Less duplicate code public void loadSong (Path location) { + final ClientPlayerEntity player = client.player; + + if (player == null) return; + if (loaderThread != null) { - ((Audience) client.player).sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED)); + player.sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED)); return; } try { - final SongLoaderThread _loaderThread = new SongLoaderThread(location); - ((Audience) client.player).sendMessage(Component.translatable("Loading %s", Component.text(location.getFileName().toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); - _loaderThread.start(); - loaderThread = _loaderThread; + loaderThread = new SongLoaderThread(location); + player.sendMessage(Component.translatable("Loading %s", Component.text(location.getFileName().toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); + loaderThread.start(); } catch (SongLoaderException e) { - ((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED)); + player.sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED)); loaderThread = null; } } public void loadSong (URL location) { + final ClientPlayerEntity player = client.player; + + if (player == null) return; + if (loaderThread != null) { - ((Audience) client.player).sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED)); + player.sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED)); return; } try { final SongLoaderThread _loaderThread = new SongLoaderThread(location); - ((Audience) client.player).sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); + player.sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); _loaderThread.start(); loaderThread = _loaderThread; } catch (SongLoaderException e) { - ((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED)); + player.sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED)); loaderThread = null; } } @@ -101,12 +107,12 @@ public class SongPlayer { return; } - if (loaderThread != null && !loaderThread.isAlive()) { + if (loaderThread != null && !loaderThread.isAlive() && client.player != null) { if (loaderThread.exception != null) { - ((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", loaderThread.exception.message.getString()).color(NamedTextColor.RED)); + client.player.sendMessage(Component.translatable("Failed to load song: %s", loaderThread.exception.message.getString()).color(NamedTextColor.RED)); } else { songQueue.add(loaderThread.song); - ((Audience) client.player).sendMessage(Component.translatable("Added %s to the song queue", Component.empty().append(loaderThread.song.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); + client.player.sendMessage(Component.translatable("Added %s to the song queue", Component.empty().append(loaderThread.song.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); } loaderThread = null; } @@ -115,7 +121,16 @@ public class SongPlayer { if (songQueue.isEmpty()) return; currentSong = songQueue.poll(); - ((Audience) client.player).sendMessage(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); + if (client.player != null) client.player.sendMessage( + Component + .translatable( + "Now playing %s", + Component.empty() + .append(currentSong.name) + .color(NamedTextColor.DARK_GREEN) + ) + .color(NamedTextColor.GREEN) + ); currentSong.play(); } @@ -123,7 +138,7 @@ public class SongPlayer { else ticksUntilPausedActionbar = 20; try { - if (!useCore && actionbar && client.player != null) ((Audience) client.player).sendActionBar(generateActionbar()); + if (!useCore && actionbar && client.player != null) client.player.sendActionBar(generateActionbar()); else if (actionbar) CommandCore.INSTANCE.run("title " + SELECTOR + " actionbar " + GsonComponentSerializer.gson().serialize(generateActionbar())); } catch (Exception e) { e.printStackTrace(); @@ -134,7 +149,7 @@ public class SongPlayer { handlePlaying(); if (currentSong.finished()) { - ((Audience) client.player).sendMessage(Component.translatable("Finished playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); + if (client.player != null) client.player.sendMessage(Component.translatable("Finished playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)); currentSong = null; } } @@ -211,24 +226,37 @@ public class SongPlayer { if (!useCore && client.player != null) { final float floatingPitch = (float) (0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12)))); - final String[] thing = note.instrument.sound.split(":"); - - if (thing[1] == null) return; // idk if this can be null but ill just protect it for now i guess + final String sound = note.instrument.sound; client.submit(() -> client.world.playSound( - client.player.getX(), - client.player.getY(), - client.player.getZ(), - SoundEvent.of(Identifier.of(thing[0], thing[1])), + client.player.getX() + note.position.getX(), + client.player.getY() + note.position.getY(), + client.player.getZ() + note.position.getZ(), + SoundEvent.of(Identifier.of(Key.MINECRAFT_NAMESPACE, sound)), SoundCategory.RECORDS, note.volume, floatingPitch, true )); } else { - final float floatingPitch = MathUtilities.clamp((float) (0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12)))), 0F, 2F); + final double floatingPitch = MathUtilities.clamp(0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12))), 0F, 2F); - CommandCore.INSTANCE.run("execute as " + SELECTOR + " at @s run playsound " + note.instrument.sound + " record @s ~ ~ ~ " + note.volume + " " + floatingPitch); + CommandCore.INSTANCE.run( + String.format( + "execute as %s at @s run playsound %s record @s ^%f ^%f ^%f %f %f", + + SELECTOR, + + note.instrument.sound, + + note.position.getX(), + note.position.getY(), + note.position.getZ(), + + note.volume, + floatingPitch + ) + ); } } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java b/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java index 7162f31..b6e5cd7 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java @@ -34,16 +34,16 @@ public class Instrument { this.id = id; this.name = name; this.offset = offset; - this.sound = "minecraft:block.note_block." + name; + this.sound = "block.note_block." + name; } public static Instrument of(String sound) { return new Instrument(-1, null, 0, sound); } - private static Instrument[] values = {HARP, BASEDRUM, SNARE, HAT, BASS, FLUTE, BELL, GUITAR, CHIME, XYLOPHONE, IRON_XYLOPHONE, COW_BELL, DIDGERIDOO, BIT, BANJO, PLING}; + private static final Instrument[] VALUES = {HARP, BASEDRUM, SNARE, HAT, BASS, FLUTE, BELL, GUITAR, CHIME, XYLOPHONE, IRON_XYLOPHONE, COW_BELL, DIDGERIDOO, BIT, BANJO, PLING}; public static Instrument fromId(int id) { - return values[id]; + return VALUES[id]; } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java b/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java index d8d3c0c..fda950e 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java @@ -1,6 +1,7 @@ package land.chipmunk.chipmunkmod.song; import land.chipmunk.chipmunkmod.util.DownloadUtilities; +import net.minecraft.util.math.Vec3d; import java.io.*; import java.net.*; @@ -143,7 +144,7 @@ public class MidiConverter { float volume = (float) velocity / 127.0f; long time = microTime / 1000L; - return new Note(instrument, pitch, volume, time); + return new Note(instrument, pitch, volume, time, Vec3d.ZERO); } private static Note getMidiPercussionNote(int midiPitch, int velocity, long microTime) { @@ -154,7 +155,7 @@ public class MidiConverter { Instrument instrument = Instrument.fromId(noteId / 25); long time = microTime / 1000L; - return new Note(instrument, pitch, volume, time); + return new Note(instrument, pitch, volume, time, Vec3d.ZERO); } return null; } diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java b/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java index d1e4419..ce8deab 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java @@ -1,5 +1,7 @@ package land.chipmunk.chipmunkmod.song; +import net.minecraft.util.math.Vec3d; + import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -156,15 +158,20 @@ public class NBSConverter { } for (NBSNote note : nbsNotes) { Instrument instrument; - int key = note.key; + double key; if (note.instrument < instrumentIndex.length) { instrument = instrumentIndex[note.instrument]; + + key = (double) ((note.key * 100) + note.pitch) / 100; } else { int index = note.instrument - instrumentIndex.length; + if (index >= customInstruments.size()) continue; + NBSCustomInstrument customInstrument = customInstruments.get(index); instrument = Instrument.of(customInstrument.name); - key += customInstrument.pitch; + + key = (note.key) + (customInstrument.pitch + (double) note.pitch / 100); } byte layerVolume = 100; @@ -172,8 +179,29 @@ public class NBSConverter { layerVolume = nbsLayers.get(note.layer).volume; } - int pitch = key - 33; - song.add(new Note(instrument, pitch, (float) note.velocity * (float) layerVolume / 10000f, getMilliTime(note.tick, tempo))); + while (key < 33) key += 12; + while (key > 57) key -= 12; + + double pitch = key - 33; + + final int layerStereo = Byte.toUnsignedInt(nbsLayers.get(note.layer).stereo); + final int notePanning = Byte.toUnsignedInt(note.panning); + + double value; + + if (layerStereo == 100 && notePanning != 100) value = notePanning; + else if (notePanning == 100 && layerStereo != 100) value = layerStereo; + else value = (double) (layerStereo + notePanning) / 2; + + double x; + + if (value > 100) x = (value - 100) / -100; + else if (value == 100) x = 0; + else x = ((value - 100) * -1) / 100; + + final Vec3d position = new Vec3d(x, 0 ,0); + + song.add(new Note(instrument, pitch, (float) note.velocity * (float) layerVolume / 10000f, getMilliTime(note.tick, tempo), position)); } song.length = song.get(song.size() - 1).time + 50; diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/Note.java b/src/main/java/land/chipmunk/chipmunkmod/song/Note.java index 337d6c8..638eea4 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/Note.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/Note.java @@ -1,31 +1,25 @@ package land.chipmunk.chipmunkmod.song; +import net.minecraft.util.math.Vec3d; + public class Note implements Comparable { public Instrument instrument; - public int pitch; + public double pitch; public float volume; public long time; + public Vec3d position; - public Note(Instrument instrument, int pitch, float volume, long time) { + public Note(Instrument instrument, double pitch, float volume, long time, Vec3d position) { this.instrument = instrument; this.pitch = pitch; this.volume = volume; this.time = time; + this.position = position; } @Override public int compareTo(Note other) { - if (time < other.time) { - return -1; - } else if (time > other.time) { - return 1; - } else { - return 0; - } - } - - public int noteId() { - return pitch + instrument.id * 25; + return Long.compare(time, other.time); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java b/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java index 7790e12..9a95ad8 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java @@ -54,6 +54,7 @@ public class SongLoaderThread extends Thread { try { song = NBSConverter.getSongFromBytes(bytes, name); } catch (Exception e) { + e.printStackTrace(); } }