Completely rehauled SongPlayer's code
This commit is contained in:
parent
2e80d56e09
commit
1da7485578
21 changed files with 1090 additions and 778 deletions
|
@ -1,27 +1,21 @@
|
|||
package com.github.hhhzzzsss.songplayer;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer.Mode;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.BuildingThread;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.Stage;
|
||||
import com.github.hhhzzzsss.songplayer.song.DownloadingThread;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
public class CommandProcessor {
|
||||
public static ArrayList<Command> commands = new ArrayList<>();
|
||||
|
||||
public static void initCommands() {
|
||||
commands.add(new helpCommand());
|
||||
commands.add(new playCommand());
|
||||
commands.add(new playurlCommand());
|
||||
commands.add(new stopCommand());
|
||||
commands.add(new skipCommand());
|
||||
commands.add(new gotoCommand());
|
||||
commands.add(new loopCommand());
|
||||
commands.add(new currentCommand());
|
||||
|
@ -94,67 +88,14 @@ public class CommandProcessor {
|
|||
return "play";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$play <song>";
|
||||
return "$play <song or url>";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Plays a song";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.IDLE) {
|
||||
SongPlayer.addChatMessage("§cCannot do that while building or playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() > 0) {
|
||||
try {
|
||||
SongPlayer.song = Song.getSongFromFile(args);
|
||||
}
|
||||
catch (IOException e) {
|
||||
SongPlayer.addChatMessage("§cCould not find song §4" + args);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
SongPlayer.addChatMessage("§cError getting song: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return true;
|
||||
}
|
||||
|
||||
SongPlayer.stage = new Stage();
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
SongPlayer.mode = Mode.BUILDING;
|
||||
SongPlayer.addChatMessage("§6Starting building.");
|
||||
SongPlayer.song.position = 0;
|
||||
(new BuildingThread()).start();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class playurlCommand extends Command {
|
||||
public String getName() {
|
||||
return "playurl";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$playurl <midi url>";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Plays a song from a direct link to the midi";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.IDLE) {
|
||||
SongPlayer.addChatMessage("§cCannot do that while building or playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() > 0) {
|
||||
SongPlayer.stage = new Stage();
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
SongPlayer.addChatMessage("§6Downloading song from url");
|
||||
SongPlayer.mode = Mode.DOWNLOADING;
|
||||
(new DownloadingThread(args)).start();
|
||||
SongHandler.getInstance().loadSong(args);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -174,18 +115,15 @@ public class CommandProcessor {
|
|||
return "Stops playing";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING && SongPlayer.mode != Mode.BUILDING) {
|
||||
if (SongHandler.getInstance().currentSong == null && SongHandler.getInstance().songQueue.isEmpty()) {
|
||||
SongPlayer.addChatMessage("§6No song is currently playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() == 0) {
|
||||
if (SongPlayer.fakePlayer != null) {
|
||||
SongPlayer.fakePlayer.remove(Entity.RemovalReason.DISCARDED);
|
||||
SongPlayer.fakePlayer = null;
|
||||
}
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
SongPlayer.mode = Mode.IDLE;
|
||||
SongPlayer.song.loop = false;
|
||||
if (SongHandler.getInstance().stage != null) {
|
||||
SongHandler.getInstance().stage.movePlayerToStagePosition();
|
||||
}
|
||||
SongHandler.getInstance().cleanup();
|
||||
SongPlayer.addChatMessage("§6Stopped playing");
|
||||
return true;
|
||||
}
|
||||
|
@ -194,6 +132,31 @@ public class CommandProcessor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class skipCommand extends Command {
|
||||
public String getName() {
|
||||
return "skip";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$skip";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Skips current song";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongHandler.getInstance().currentSong == null) {
|
||||
SongPlayer.addChatMessage("§6No song is currently playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() == 0) {
|
||||
SongHandler.getInstance().currentSong = null;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class gotoCommand extends Command {
|
||||
public String getName() {
|
||||
|
@ -206,7 +169,7 @@ public class CommandProcessor {
|
|||
return "Goes to a specific time in the song";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING) {
|
||||
if (SongHandler.getInstance().currentSong == null) {
|
||||
SongPlayer.addChatMessage("§cNo song is currently playing");
|
||||
return true;
|
||||
}
|
||||
|
@ -218,8 +181,8 @@ public class CommandProcessor {
|
|||
if (timestamp_matcher.matches()) {
|
||||
String minutes = timestamp_matcher.group(1);
|
||||
String seconds = timestamp_matcher.group(2);
|
||||
SongPlayer.song.gotoTime = Integer.parseInt(minutes)*60*1000 + Integer.parseInt(seconds)*1000;
|
||||
System.out.println("set time to " + SongPlayer.song.gotoTime);
|
||||
SongHandler.getInstance().currentSong.setTime(Integer.parseInt(minutes)*60*1000 + Integer.parseInt(seconds)*1000);
|
||||
SongPlayer.addChatMessage("§6Set song time to §3" + minutes + ":" + seconds);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -244,13 +207,13 @@ public class CommandProcessor {
|
|||
return "Toggles song looping";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING) {
|
||||
if (SongHandler.getInstance().currentSong == null) {
|
||||
SongPlayer.addChatMessage("§cNo song is currently playing");
|
||||
return true;
|
||||
}
|
||||
|
||||
SongPlayer.song.loop = !SongPlayer.song.loop;
|
||||
if (SongPlayer.song.loop) {
|
||||
SongHandler.getInstance().currentSong.looping = !SongHandler.getInstance().currentSong.looping;
|
||||
if (SongHandler.getInstance().currentSong.looping) {
|
||||
SongPlayer.addChatMessage("§6Enabled looping");
|
||||
}
|
||||
else {
|
||||
|
@ -271,18 +234,19 @@ public class CommandProcessor {
|
|||
return "Gets the song that is currently playing";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING) {
|
||||
SongPlayer.addChatMessage("§6No song is currently playing");
|
||||
if (SongHandler.getInstance().currentSong == null) {
|
||||
SongPlayer.addChatMessage("§cNo song is currently playing");
|
||||
return true;
|
||||
}
|
||||
Song currentSong = SongHandler.getInstance().currentSong;
|
||||
if (args.length() == 0) {
|
||||
int currTime = (int) (SongPlayer.song.get(SongPlayer.song.position).time/1000);
|
||||
int totTime = (int) (SongPlayer.song.get(SongPlayer.song.size()-1).time/1000);
|
||||
int currTime = (int) (currentSong.time/1000);
|
||||
int totTime = (int) (currentSong.length/1000);
|
||||
int currTimeSeconds = currTime % 60;
|
||||
int totTimeSeconds = totTime % 60;
|
||||
int currTimeMinutes = currTime / 60;
|
||||
int totTimeMinutes = totTime / 60;
|
||||
SongPlayer.addChatMessage(String.format("§6Currently playing %s §3(%d:%02d/%d:%02d)", SongPlayer.song.name, currTimeMinutes, currTimeSeconds, totTimeMinutes, totTimeSeconds));
|
||||
SongPlayer.addChatMessage(String.format("§6Currently playing %s §3(%d:%02d/%d:%02d)", currentSong.name, currTimeMinutes, currTimeSeconds, totTimeMinutes, totTimeSeconds));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -340,7 +304,7 @@ public class CommandProcessor {
|
|||
if (SongPlayer.creativeCommand.startsWith("/")) {
|
||||
SongPlayer.creativeCommand = SongPlayer.creativeCommand.substring(1);
|
||||
}
|
||||
SongPlayer.addChatMessage("§6Set creative command to /" + SongPlayer.creativeCommand);
|
||||
SongPlayer.addChatMessage("§6Set creative command to §3/" + SongPlayer.creativeCommand);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -365,7 +329,7 @@ public class CommandProcessor {
|
|||
if (SongPlayer.survivalCommand.startsWith("/")) {
|
||||
SongPlayer.survivalCommand = SongPlayer.survivalCommand.substring(1);
|
||||
}
|
||||
SongPlayer.addChatMessage("§6Set survival command to /" + SongPlayer.survivalCommand);
|
||||
SongPlayer.addChatMessage("§6Set survival command to §3/" + SongPlayer.survivalCommand);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -388,18 +352,9 @@ public class CommandProcessor {
|
|||
if (args.length() == 0) {
|
||||
SongPlayer.showFakePlayer = !SongPlayer.showFakePlayer;
|
||||
if (SongPlayer.showFakePlayer) {
|
||||
if (SongPlayer.mode == Mode.PLAYING || SongPlayer.mode == Mode.BUILDING) {
|
||||
if (SongPlayer.fakePlayer != null) {
|
||||
SongPlayer.fakePlayer.remove(Entity.RemovalReason.DISCARDED);
|
||||
}
|
||||
SongPlayer.fakePlayer = new FakePlayerEntity();
|
||||
}
|
||||
SongPlayer.addChatMessage("§6Enabled fake player");
|
||||
}
|
||||
else {
|
||||
if (SongPlayer.fakePlayer != null) {
|
||||
SongPlayer.fakePlayer.remove(Entity.RemovalReason.DISCARDED);
|
||||
}
|
||||
SongPlayer.addChatMessage("§6Disabled fake player");
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.github.hhhzzzsss.songplayer;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.Stage;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.network.OtherClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
|
@ -34,8 +36,9 @@ public class FakePlayerEntity extends OtherClientPlayerEntity {
|
|||
}
|
||||
|
||||
public void copyStagePosAndPlayerLook() {
|
||||
if (SongPlayer.stage != null) {
|
||||
refreshPositionAndAngles(SongPlayer.stage.position.getX()+0.5, SongPlayer.stage.position.getY(), SongPlayer.stage.position.getZ()+0.5, player.getYaw(), player.getPitch());
|
||||
Stage stage = SongHandler.getInstance().stage;
|
||||
if (stage != null) {
|
||||
refreshPositionAndAngles(stage.position.getX()+0.5, stage.position.getY(), stage.position.getZ()+0.5, player.getYaw(), player.getPitch());
|
||||
headYaw = player.headYaw;
|
||||
bodyYaw = player.bodyYaw;
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
package com.github.hhhzzzsss.songplayer;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class Freecam {
|
||||
private static Freecam instance = null;
|
||||
public static Freecam getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Freecam();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
boolean enabled = false;
|
||||
|
||||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
private FakePlayerEntity fakePlayer;
|
||||
|
||||
private Freecam() {
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
enabled = true;
|
||||
fakePlayer = new FakePlayerEntity();
|
||||
SongPlayer.addChatMessage("Freecam is enabled");
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
enabled = false;
|
||||
if (fakePlayer != null) {
|
||||
fakePlayer.resetPlayerPosition();
|
||||
fakePlayer.remove(Entity.RemovalReason.DISCARDED);
|
||||
fakePlayer = null;
|
||||
player.setVelocity(Vec3d.ZERO);
|
||||
}
|
||||
SongPlayer.addChatMessage("Freecam is disabled");
|
||||
}
|
||||
|
||||
public void onGameJoin() {
|
||||
enabled = false;
|
||||
fakePlayer = null;
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
if (enabled) {
|
||||
disable();
|
||||
}
|
||||
else {
|
||||
enable();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
}
|
|
@ -6,42 +6,40 @@ import com.github.hhhzzzsss.songplayer.noteblocks.Stage;
|
|||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.text.LiteralTextContent;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class SongPlayer implements ModInitializer {
|
||||
|
||||
public static final MinecraftClient MC = MinecraftClient.getInstance();
|
||||
Freecam freecam;
|
||||
public static final int NOTEBLOCK_BASE_ID = Block.getRawIdFromState(Blocks.NOTE_BLOCK.getDefaultState());
|
||||
|
||||
public static final File SONG_DIR = new File("songs");
|
||||
public static Song song;
|
||||
public static Stage stage;
|
||||
public static boolean showFakePlayer = false;
|
||||
public static FakePlayerEntity fakePlayer;
|
||||
public static String creativeCommand = "/gmc";
|
||||
public static String survivalCommand = "/gms";
|
||||
|
||||
public static enum Mode {
|
||||
IDLE,
|
||||
BUILDING,
|
||||
PLAYING,
|
||||
DOWNLOADING,
|
||||
}
|
||||
public static Mode mode = Mode.IDLE;
|
||||
public static String creativeCommand = "gmc";
|
||||
public static String survivalCommand = "gms";
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
if (!SONG_DIR.exists()) {
|
||||
SONG_DIR.mkdir();
|
||||
}
|
||||
|
||||
freecam = Freecam.getInstance();
|
||||
|
||||
CommandProcessor.initCommands();
|
||||
}
|
||||
|
||||
public static void addChatMessage(String message) {
|
||||
MC.player.sendMessage(Text.of(message), false);
|
||||
}
|
||||
|
||||
public static void removeFakePlayer() {
|
||||
if (fakePlayer != null) {
|
||||
fakePlayer.remove(Entity.RemovalReason.DISCARDED);
|
||||
fakePlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.github.hhhzzzsss.songplayer.mixin;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.Stage;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
@ -26,11 +29,9 @@ public class ClientPlayNetworkHandlerMixin {
|
|||
|
||||
@Inject(at = @At("HEAD"), method = "sendPacket(Lnet/minecraft/network/Packet;)V", cancellable = true)
|
||||
private void onSendPacket(Packet<?> packet, CallbackInfo ci) {
|
||||
/*if (Freecam.getInstance().isEnabled() && packet instanceof PlayerMoveC2SPacket) {
|
||||
ci.cancel();
|
||||
}*/
|
||||
if (SongPlayer.mode != SongPlayer.Mode.IDLE && packet instanceof PlayerMoveC2SPacket) {
|
||||
connection.send(new PlayerMoveC2SPacket.Full(SongPlayer.stage.position.getX()+0.5, SongPlayer.stage.position.getY(), SongPlayer.stage.position.getZ()+0.5, SongPlayer.MC.player.getYaw(), SongPlayer.MC.player.getPitch(), true));
|
||||
Stage stage = SongHandler.getInstance().stage;
|
||||
if (stage != null && packet instanceof PlayerMoveC2SPacket) {
|
||||
connection.send(new PlayerMoveC2SPacket.Full(stage.position.getX()+0.5, stage.position.getY(), stage.position.getZ()+0.5, SongPlayer.MC.player.getYaw(), SongPlayer.MC.player.getPitch(), true));
|
||||
if (SongPlayer.fakePlayer != null) {
|
||||
SongPlayer.fakePlayer.copyStagePosAndPlayerLook();
|
||||
}
|
||||
|
@ -38,16 +39,13 @@ public class ClientPlayNetworkHandlerMixin {
|
|||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "onGameJoin(Lnet/minecraft/network/packet/s2c/play/GameJoinS2CPacket;)V")
|
||||
@Inject(at = @At("TAIL"), method = "onGameJoin(Lnet/minecraft/network/packet/s2c/play/GameJoinS2CPacket;)V")
|
||||
public void onOnGameJoin(GameJoinS2CPacket packet, CallbackInfo ci) {
|
||||
//Freecam.getInstance().onGameJoin();
|
||||
SongPlayer.mode = SongPlayer.Mode.IDLE;
|
||||
SongHandler.getInstance().cleanup();
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "onBlockUpdate(Lnet/minecraft/network/packet/s2c/play/BlockUpdateS2CPacket;)V")
|
||||
public void onOnBlockUpdate(BlockUpdateS2CPacket packet, CallbackInfo ci) {
|
||||
if (SongPlayer.mode == SongPlayer.Mode.PLAYING && SongPlayer.stage.noteblockPositions.contains(packet.getPos())) {
|
||||
SongPlayer.stage.rebuild = true;
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "onPlayerRespawn(Lnet/minecraft/network/packet/s2c/play/PlayerRespawnS2CPacket;)V")
|
||||
public void onOnPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) {
|
||||
SongHandler.getInstance().cleanup();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package com.github.hhhzzzsss.songplayer.mixin;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.Freecam;
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
import net.minecraft.client.Keyboard;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
|
||||
@Mixin(Keyboard.class)
|
||||
public class KeyboardMixin {
|
||||
@Inject(at = @At("HEAD"), method = "onKey(JIIII)V")
|
||||
private void onOnKey(long window, int key, int scancode, int i, int j, CallbackInfo ci) {
|
||||
if (SongPlayer.MC.currentScreen == null && i == GLFW.GLFW_PRESS && InputUtil.fromKeyCode(key, scancode).getTranslationKey().equals("key.keyboard.p")) {
|
||||
Freecam.getInstance().toggle();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.github.hhhzzzsss.songplayer.mixin;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
|
@ -14,13 +15,12 @@ import net.minecraft.util.math.BlockPos;
|
|||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public class MinecraftClientMixin {
|
||||
@Inject(at = @At("HEAD"), method = "doItemUse()V")
|
||||
public void onDoItemUse(CallbackInfo ci) {
|
||||
Type type = SongPlayer.MC.crosshairTarget.getType();
|
||||
if (type == Type.BLOCK) {
|
||||
BlockHitResult blockHitResult = (BlockHitResult) SongPlayer.MC.crosshairTarget;
|
||||
BlockPos pos = blockHitResult.getBlockPos();
|
||||
System.out.println(blockHitResult.getSide() + ": " + pos.getX() + " " + pos.getY() + " " + pos.getZ());
|
||||
@Inject(at = @At("HEAD"), method = "render(Z)V")
|
||||
public void onRender(boolean tick, CallbackInfo ci) {
|
||||
if (SongPlayer.MC.world != null && SongPlayer.MC.player != null && SongPlayer.MC.interactionManager != null) {
|
||||
SongHandler.getInstance().onRenderIngame(tick);
|
||||
} else {
|
||||
SongHandler.getInstance().onNotIngame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
package com.github.hhhzzzsss.songplayer.noteblocks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.FakePlayerEntity;
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.GameMode;
|
||||
|
||||
public class BuildingThread extends Thread {
|
||||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
private final PlayerInventory inventory = SongPlayer.MC.player.getInventory();
|
||||
private final ClientWorld world = SongPlayer.MC.world;
|
||||
private final Stage stage = SongPlayer.stage;
|
||||
private final BlockPos stagePos = SongPlayer.stage.position;
|
||||
private final Song song = SongPlayer.song;
|
||||
private final int NOTEBLOCK_BASE_ID = Block.getRawIdFromState(Blocks.NOTE_BLOCK.getDefaultState());
|
||||
private final String[] instrumentNames = {"harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling"};
|
||||
private boolean[] missingNotes = new boolean[400];
|
||||
|
||||
public void run() {
|
||||
for (int i=0; i<400; i++) {
|
||||
missingNotes[i] = song.requiredNotes[i];
|
||||
}
|
||||
stage.noteblockPositions.clear();
|
||||
ArrayList<BlockPos> unusedNoteblockLocations = new ArrayList<>();
|
||||
for (int dy : new int[] {-1,2}) {
|
||||
for (int dx = -4; dx <= 4; dx++) {
|
||||
for (int dz = -4; dz <= 4; dz++) {
|
||||
if (Math.abs(dx) == 4 && Math.abs(dz) == 4) continue;
|
||||
BlockPos pos = new BlockPos(stagePos.getX()+dx, stagePos.getY()+dy, stagePos.getZ()+dz);
|
||||
BlockState bs = world.getBlockState(pos);
|
||||
int blockId = Block.getRawIdFromState(bs);
|
||||
if (blockId >= NOTEBLOCK_BASE_ID && blockId < NOTEBLOCK_BASE_ID+800) {
|
||||
int noteId = (blockId-NOTEBLOCK_BASE_ID)/2;
|
||||
if (missingNotes[noteId]) {
|
||||
stage.tunedNoteblocks[noteId] = pos;
|
||||
missingNotes[noteId] = false;
|
||||
stage.noteblockPositions.add(pos);
|
||||
}
|
||||
else {
|
||||
unusedNoteblockLocations.add(pos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unusedNoteblockLocations.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int idx = 0;
|
||||
for (int i=0; i<400; i++) {
|
||||
if (idx == unusedNoteblockLocations.size()) {
|
||||
System.out.println("Too many noteblocks!");
|
||||
break;
|
||||
}
|
||||
if (missingNotes[i]) {
|
||||
stage.tunedNoteblocks[i] = unusedNoteblockLocations.get(idx++);
|
||||
stage.noteblockPositions.add(stage.tunedNoteblocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
player.sendCommand(SongPlayer.creativeCommand);
|
||||
try { //delay in case of block updates
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
while (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.CREATIVE) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.BUILDING) {return;}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.getAbilities().allowFlying = true;
|
||||
player.getAbilities().flying = true;
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
if (SongPlayer.showFakePlayer) {
|
||||
if (SongPlayer.fakePlayer != null) {
|
||||
SongPlayer.fakePlayer.remove(Entity.RemovalReason.DISCARDED);
|
||||
}
|
||||
SongPlayer.fakePlayer = new FakePlayerEntity();
|
||||
}
|
||||
|
||||
for (int dy : new int[] {0,1,3}) {
|
||||
for (int dx = -4; dx <= 4; dx++) {
|
||||
for (int dz = -4; dz <= 4; dz++) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.BUILDING) {return;}
|
||||
|
||||
if (Math.abs(dx) == 4 && Math.abs(dz) == 4) continue;
|
||||
int x = stagePos.getX() + dx;
|
||||
int y = stagePos.getY() + dy;
|
||||
int z = stagePos.getZ() + dz;
|
||||
if (Block.getRawIdFromState(world.getBlockState(new BlockPos(x, y, z))) != 0) {
|
||||
SongPlayer.MC.interactionManager.attackBlock(new BlockPos(x, y, z), Direction.UP);
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("done clearing blocks");
|
||||
|
||||
for (int i=0; i<400; i++) if (song.requiredNotes[i]) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.BUILDING) {return;}
|
||||
|
||||
BlockPos p = stage.tunedNoteblocks[i];
|
||||
int blockId = Block.getRawIdFromState(world.getBlockState(p));
|
||||
int currentNoteId = (blockId-NOTEBLOCK_BASE_ID)/2;
|
||||
int desiredNoteId = i;
|
||||
|
||||
if (currentNoteId != desiredNoteId) {
|
||||
holdNoteblock(desiredNoteId);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
if (blockId != 0) {
|
||||
SongPlayer.MC.interactionManager.attackBlock(p, Direction.UP);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
placeBlock(p);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("done placing blocks");
|
||||
|
||||
stage.rebuild = false;
|
||||
SongPlayer.mode = SongPlayer.Mode.PLAYING;
|
||||
SongPlayer.addChatMessage("§6Noteblocks are built. Now playing " + song.name + ".");
|
||||
(new PlayingThread()).start();
|
||||
}
|
||||
|
||||
private void holdNoteblock(int id) {
|
||||
int instrument = id/25;
|
||||
int note = id%25;
|
||||
NbtCompound nbt = new NbtCompound();
|
||||
nbt.putString("id", "minecraft:note_block");
|
||||
nbt.putByte("Count", (byte) 1);
|
||||
NbtCompound tag = new NbtCompound();
|
||||
NbtCompound bsTag = new NbtCompound();
|
||||
bsTag.putString("instrument", instrumentNames[instrument]);
|
||||
bsTag.putString("note", Integer.toString(note));
|
||||
tag.put("BlockStateTag", bsTag);
|
||||
nbt.put("tag", tag);
|
||||
inventory.main.set(inventory.selectedSlot, ItemStack.fromNbt(nbt));
|
||||
SongPlayer.MC.interactionManager.clickCreativeStack(player.getStackInHand(Hand.MAIN_HAND), 36 + inventory.selectedSlot);
|
||||
}
|
||||
|
||||
private void placeBlock(BlockPos p) {
|
||||
double fx = Math.max(0.0, Math.min(1.0, (stage.position.getX() + 0.5 - p.getX())));
|
||||
double fy = Math.max(0.0, Math.min(1.0, (stage.position.getY() + 0.0 - p.getY())));
|
||||
double fz = Math.max(0.0, Math.min(1.0, (stage.position.getZ() + 0.5 - p.getZ())));
|
||||
fx += p.getX();
|
||||
fy += p.getY();
|
||||
fz += p.getZ();
|
||||
SongPlayer.MC.interactionManager.interactBlock(player, Hand.MAIN_HAND, new BlockHitResult(new Vec3d(fx, fy, fz), Direction.UP, p, false));
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
package com.github.hhhzzzsss.songplayer.noteblocks;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.GameMode;
|
||||
|
||||
public class PlayingThread extends Thread{
|
||||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
private final Stage stage = SongPlayer.stage;
|
||||
private final Song song = SongPlayer.song;
|
||||
|
||||
public void run() {
|
||||
player.sendCommand(SongPlayer.survivalCommand);
|
||||
while (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.SURVIVAL) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.PLAYING) {return;}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
stage.rebuild = false;
|
||||
|
||||
player.getAbilities().allowFlying = true;
|
||||
player.getAbilities().flying = true;
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
long songStartTime = System.currentTimeMillis() - song.get(song.position).time;
|
||||
while (song.position < song.size()) {
|
||||
long playTime = System.currentTimeMillis() - songStartTime;
|
||||
while (song.position < song.size() && song.get(song.position).time <= playTime) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.PLAYING) {return;}
|
||||
SongPlayer.MC.interactionManager.attackBlock(stage.tunedNoteblocks[song.get(song.position).note], Direction.UP);
|
||||
SongPlayer.MC.interactionManager.cancelBlockBreaking();
|
||||
song.position++;
|
||||
if (stage.rebuild) {
|
||||
SongPlayer.addChatMessage("§6Stage has been modified. Retuning!");
|
||||
SongPlayer.mode = SongPlayer.Mode.BUILDING;
|
||||
(new BuildingThread()).start();
|
||||
return;
|
||||
}
|
||||
if (song.gotoTime > -1) {
|
||||
for (int i = 0; i < song.size(); i++) {
|
||||
if (song.get(i).time >= song.gotoTime) {
|
||||
song.position = i;
|
||||
song.gotoTime = -1;
|
||||
SongPlayer.addChatMessage("§6Changed song position");
|
||||
(new PlayingThread()).start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
SongPlayer.addChatMessage("§cNot a valid time stamp");
|
||||
song.gotoTime = -1;
|
||||
}
|
||||
}
|
||||
if (song.position < song.size()) {
|
||||
playTime = System.currentTimeMillis() - songStartTime;
|
||||
long sleepTime = playTime - song.get(song.position).time;
|
||||
if (sleepTime > 0) {
|
||||
if (sleepTime > 200) {
|
||||
System.out.println("Big sleep time: " + sleepTime);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(playTime-song.get(song.position).time);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (song.loop) {
|
||||
song.position = 0;
|
||||
songStartTime = System.currentTimeMillis();
|
||||
}
|
||||
else {
|
||||
// Do nothing. While loop condition is false so loop exits.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.getAbilities().allowFlying = true;
|
||||
player.getAbilities().flying = true;
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
if (SongPlayer.fakePlayer != null) {
|
||||
SongPlayer.fakePlayer.remove(Entity.RemovalReason.DISCARDED);
|
||||
SongPlayer.fakePlayer = null;
|
||||
}
|
||||
|
||||
SongPlayer.addChatMessage("§6Finished playing.");
|
||||
SongPlayer.mode = SongPlayer.Mode.IDLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,286 @@
|
|||
package com.github.hhhzzzsss.songplayer.noteblocks;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.FakePlayerEntity;
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.song.Instrument;
|
||||
import com.github.hhhzzzsss.songplayer.song.Note;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
import com.github.hhhzzzsss.songplayer.song.SongLoaderThread;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.GameMode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class SongHandler {
|
||||
private static SongHandler instance = null;
|
||||
public static SongHandler getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new SongHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public SongLoaderThread loaderThread = null;
|
||||
public LinkedList<Song> songQueue = new LinkedList<>();
|
||||
public Song currentSong = null;
|
||||
public Stage stage = null;
|
||||
public boolean building = false;
|
||||
|
||||
public void onRenderIngame(boolean tick) {
|
||||
if (currentSong == null && songQueue.size() > 0) {
|
||||
setSong(songQueue.poll());
|
||||
}
|
||||
if (loaderThread != null && !loaderThread.isAlive()) {
|
||||
if (loaderThread.exception != null) {
|
||||
SongPlayer.addChatMessage("§cFailed to load song: §4" + loaderThread.exception.getMessage());
|
||||
} else {
|
||||
if (currentSong == null) {
|
||||
setSong(loaderThread.song);
|
||||
} else {
|
||||
queueSong(loaderThread.song);
|
||||
}
|
||||
}
|
||||
loaderThread = null;
|
||||
}
|
||||
|
||||
if (currentSong == null) {
|
||||
if (stage != null || SongPlayer.fakePlayer != null) {
|
||||
if (stage != null) {
|
||||
stage.movePlayerToStagePosition();
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (stage == null) {
|
||||
stage = new Stage();
|
||||
stage.movePlayerToStagePosition();
|
||||
}
|
||||
if (SongPlayer.showFakePlayer && SongPlayer.fakePlayer == null) {
|
||||
SongPlayer.fakePlayer = new FakePlayerEntity();
|
||||
SongPlayer.fakePlayer.copyStagePosAndPlayerLook();
|
||||
}
|
||||
if (!SongPlayer.showFakePlayer && SongPlayer.fakePlayer != null) {
|
||||
SongPlayer.removeFakePlayer();
|
||||
}
|
||||
|
||||
checkCommandCache();
|
||||
|
||||
SongPlayer.MC.player.getAbilities().allowFlying = true;
|
||||
if (building) {
|
||||
if (tick) {
|
||||
handleBuilding();
|
||||
}
|
||||
} else {
|
||||
// Check if stage was broken
|
||||
handlePlaying(tick);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSong(String location) {
|
||||
if (loaderThread != null) {
|
||||
SongPlayer.addChatMessage("§cAlready loading a song, cannot load another");
|
||||
} else {
|
||||
try {
|
||||
loaderThread = new SongLoaderThread(location);
|
||||
SongPlayer.addChatMessage("§6Loading §3" + location + "");
|
||||
loaderThread.start();
|
||||
} catch (IOException e) {
|
||||
SongPlayer.addChatMessage("§cFailed to load song: §4" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setSong(Song song) {
|
||||
currentSong = song;
|
||||
building = true;
|
||||
setCreativeIfNeeded();
|
||||
if (stage != null) {
|
||||
stage.movePlayerToStagePosition();
|
||||
}
|
||||
SongPlayer.addChatMessage("§6Building noteblocks");
|
||||
}
|
||||
|
||||
private void queueSong(Song song) {
|
||||
songQueue.add(song);
|
||||
SongPlayer.addChatMessage("§6Added song to queue: §3" + song.name);
|
||||
}
|
||||
|
||||
// Runs every tick
|
||||
private int buildStartDelay = 0;
|
||||
private int buildEndDelay = 0;
|
||||
private int buildCooldown = 0;
|
||||
private void handleBuilding() {
|
||||
if (buildStartDelay > 0) {
|
||||
buildStartDelay--;
|
||||
return;
|
||||
}
|
||||
if (buildCooldown > 0) {
|
||||
buildCooldown--;
|
||||
return;
|
||||
}
|
||||
ClientWorld world = SongPlayer.MC.world;
|
||||
ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
if (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.CREATIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stage.nothingToBuild()) {
|
||||
if (buildEndDelay > 0) {
|
||||
buildEndDelay--;
|
||||
return;
|
||||
} else {
|
||||
stage.checkBuildStatus(currentSong);
|
||||
}
|
||||
}
|
||||
|
||||
if (!stage.requiredBreaks.isEmpty()) {
|
||||
for (int i=0; i<5; i++) {
|
||||
if (stage.requiredBreaks.isEmpty()) break;
|
||||
BlockPos bp = stage.requiredBreaks.poll();
|
||||
SongPlayer.MC.interactionManager.attackBlock(bp, Direction.UP);
|
||||
}
|
||||
buildEndDelay = 40;
|
||||
return;
|
||||
} else if (!stage.missingNotes.isEmpty()) {
|
||||
int desiredNoteId = stage.missingNotes.pollFirst();
|
||||
BlockPos bp = stage.noteblockPositions.get(desiredNoteId);
|
||||
int blockId = Block.getRawIdFromState(world.getBlockState(bp));
|
||||
int currentNoteId = (blockId-SongPlayer.NOTEBLOCK_BASE_ID)/2;
|
||||
if (currentNoteId != desiredNoteId) {
|
||||
holdNoteblock(desiredNoteId);
|
||||
if (blockId != 0) {
|
||||
attackBlock(bp);
|
||||
}
|
||||
placeBlock(bp);
|
||||
}
|
||||
buildCooldown = 4;
|
||||
buildEndDelay = 40;
|
||||
} else {
|
||||
building = false;
|
||||
setSurvivalIfNeeded();
|
||||
stage.movePlayerToStagePosition();
|
||||
SongPlayer.addChatMessage("§6Now playing §3" + currentSong.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Runs every frame
|
||||
private void handlePlaying(boolean tick) {
|
||||
if (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.SURVIVAL) {
|
||||
currentSong.pause();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tick) {
|
||||
stage.checkBuildStatus(currentSong);
|
||||
if (!stage.missingNotes.isEmpty()) {
|
||||
building = true;
|
||||
setCreativeIfNeeded();
|
||||
stage.movePlayerToStagePosition();
|
||||
currentSong.pause();
|
||||
buildStartDelay = 40;
|
||||
System.out.println("Total missing notes: " + stage.missingNotes.size());
|
||||
for (int note : stage.missingNotes) {
|
||||
int pitch = note % 25;
|
||||
int instrumentId = note / 25;
|
||||
System.out.println("Missing note: " + Instrument.getInstrumentFromId(instrumentId).name() + ":" + pitch);
|
||||
}
|
||||
SongPlayer.addChatMessage("§6Stage was altered. Rebuilding!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentSong.play();
|
||||
|
||||
currentSong.advanceTime();
|
||||
while (currentSong.reachedNextNote()) {
|
||||
Note note = currentSong.getNextNote();
|
||||
attackBlock(stage.noteblockPositions.get(note.noteId));
|
||||
}
|
||||
|
||||
if (currentSong.finished()) {
|
||||
currentSong = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
currentSong = null;
|
||||
songQueue.clear();
|
||||
stage = null;
|
||||
SongPlayer.removeFakePlayer();
|
||||
}
|
||||
|
||||
public void onNotIngame() {
|
||||
currentSong = null;
|
||||
songQueue.clear();
|
||||
}
|
||||
|
||||
private long lastCommandTime = System.currentTimeMillis();
|
||||
private String cachedCommand = null;
|
||||
private void sendGamemodeCommand(String command) {
|
||||
cachedCommand = command;
|
||||
}
|
||||
private void checkCommandCache() {
|
||||
if (cachedCommand != null && System.currentTimeMillis() >= lastCommandTime + 1500) {
|
||||
SongPlayer.MC.player.sendCommand(cachedCommand);
|
||||
cachedCommand = null;
|
||||
lastCommandTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
private void setCreativeIfNeeded() {
|
||||
cachedCommand = null;
|
||||
if (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.CREATIVE) {
|
||||
sendGamemodeCommand(SongPlayer.creativeCommand);
|
||||
}
|
||||
}
|
||||
private void setSurvivalIfNeeded() {
|
||||
cachedCommand = null;
|
||||
if (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.SURVIVAL) {
|
||||
sendGamemodeCommand(SongPlayer.survivalCommand);
|
||||
}
|
||||
}
|
||||
|
||||
private final String[] instrumentNames = {"harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling"};
|
||||
private void holdNoteblock(int id) {
|
||||
PlayerInventory inventory = SongPlayer.MC.player.getInventory();
|
||||
int instrument = id/25;
|
||||
int note = id%25;
|
||||
NbtCompound nbt = new NbtCompound();
|
||||
nbt.putString("id", "minecraft:note_block");
|
||||
nbt.putByte("Count", (byte) 1);
|
||||
NbtCompound tag = new NbtCompound();
|
||||
NbtCompound bsTag = new NbtCompound();
|
||||
bsTag.putString("instrument", instrumentNames[instrument]);
|
||||
bsTag.putString("note", Integer.toString(note));
|
||||
tag.put("BlockStateTag", bsTag);
|
||||
nbt.put("tag", tag);
|
||||
inventory.main.set(inventory.selectedSlot, ItemStack.fromNbt(nbt));
|
||||
SongPlayer.MC.interactionManager.clickCreativeStack(SongPlayer.MC.player.getStackInHand(Hand.MAIN_HAND), 36 + inventory.selectedSlot);
|
||||
}
|
||||
private void placeBlock(BlockPos bp) {
|
||||
double fx = Math.max(0.0, Math.min(1.0, (stage.position.getX() + 0.5 - bp.getX())));
|
||||
double fy = Math.max(0.0, Math.min(1.0, (stage.position.getY() + 0.0 - bp.getY())));
|
||||
double fz = Math.max(0.0, Math.min(1.0, (stage.position.getZ() + 0.5 - bp.getZ())));
|
||||
fx += bp.getX();
|
||||
fy += bp.getY();
|
||||
fz += bp.getZ();
|
||||
SongPlayer.MC.interactionManager.interactBlock(SongPlayer.MC.player, Hand.MAIN_HAND, new BlockHitResult(new Vec3d(fx, fy, fz), Direction.UP, bp, false));
|
||||
}
|
||||
private void attackBlock(BlockPos bp) {
|
||||
SongPlayer.MC.interactionManager.attackBlock(bp, Direction.UP);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
package com.github.hhhzzzsss.songplayer.noteblocks;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
@ -12,16 +17,151 @@ public class Stage {
|
|||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
|
||||
public BlockPos position;
|
||||
public BlockPos[] tunedNoteblocks = new BlockPos[400];
|
||||
public HashSet<BlockPos> noteblockPositions = new HashSet<>();
|
||||
// public BlockPos[] tunedNoteblocks = new BlockPos[400];
|
||||
public HashMap<Integer, BlockPos> noteblockPositions = new HashMap<>();
|
||||
public boolean rebuild = false;
|
||||
|
||||
public LinkedList<BlockPos> requiredBreaks = new LinkedList<>();
|
||||
public TreeSet<Integer> missingNotes = new TreeSet<>();
|
||||
|
||||
public Stage() {
|
||||
position = player.getBlockPos();
|
||||
}
|
||||
|
||||
public void movePlayerToStagePosition() {
|
||||
player.getAbilities().allowFlying = true;
|
||||
player.getAbilities().flying = true;
|
||||
player.refreshPositionAndAngles(position.getX() + 0.5, position.getY() + 0.0, position.getZ() + 0.5, player.getYaw(), player.getPitch());
|
||||
player.setVelocity(Vec3d.ZERO);
|
||||
}
|
||||
|
||||
public void checkBuildStatus(Song song) {
|
||||
noteblockPositions.clear();
|
||||
missingNotes.clear();
|
||||
|
||||
// Add all required notes to missingNotes
|
||||
for (int i=0; i<400; i++) {
|
||||
if (song.requiredNotes[i]) {
|
||||
missingNotes.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<BlockPos> noteblockLocations = new ArrayList<>();
|
||||
ArrayList<BlockPos> breakLocations = new ArrayList<>();
|
||||
for (int dx = -4; dx <= 4; dx++) {
|
||||
for (int dz = -4; dz <= 4; dz++) {
|
||||
if (Math.abs(dx) == 4 && Math.abs(dz) == 4) {
|
||||
noteblockLocations.add(new BlockPos(position.getX() + dx, position.getY() + 0, position.getZ() + dz));
|
||||
breakLocations.add(new BlockPos(position.getX() + dx, position.getY() + 1, position.getZ() + dz));
|
||||
} else {
|
||||
noteblockLocations.add(new BlockPos(position.getX() + dx, position.getY() - 1, position.getZ() + dz));
|
||||
noteblockLocations.add(new BlockPos(position.getX() + dx, position.getY() + 2, position.getZ() + dz));
|
||||
breakLocations.add(new BlockPos(position.getX() + dx, position.getY() + 0, position.getZ() + dz));
|
||||
breakLocations.add(new BlockPos(position.getX() + dx, position.getY() + 1, position.getZ() + dz));
|
||||
breakLocations.add(new BlockPos(position.getX() + dx, position.getY() + 3, position.getZ() + dz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sorting noteblock and break locations
|
||||
noteblockLocations.sort((a, b) -> {
|
||||
// First sort by y
|
||||
if (a.getY() < b.getY()) {
|
||||
return -1;
|
||||
} else if (a.getY() > b.getY()) {
|
||||
return 1;
|
||||
}
|
||||
// Then sort by horizontal distance
|
||||
int a_dx = a.getX() - position.getX();
|
||||
int a_dz = a.getZ() - position.getZ();
|
||||
int b_dx = b.getX() - position.getX();
|
||||
int b_dz = b.getZ() - position.getZ();
|
||||
int a_dist = a_dx*a_dx + a_dz*a_dz;
|
||||
int b_dist = b_dx*b_dx + b_dz*b_dz;
|
||||
if (a_dist < b_dist) {
|
||||
return -1;
|
||||
} else if (a_dist > b_dist) {
|
||||
return 1;
|
||||
}
|
||||
// Finally sort by angle
|
||||
double a_angle = Math.atan2(a_dz, a_dx);
|
||||
double b_angle = Math.atan2(b_dz, b_dx);
|
||||
if (a_angle < b_angle) {
|
||||
return -1;
|
||||
} else if (a_angle > b_angle) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
requiredBreaks = breakLocations
|
||||
.stream()
|
||||
.filter((bp) -> Block.getRawIdFromState(SongPlayer.MC.world.getBlockState(bp)) != 0)
|
||||
.sorted((a, b) -> {
|
||||
// First sort by y
|
||||
if (a.getY() < b.getY()) {
|
||||
return -1;
|
||||
} else if (a.getY() > b.getY()) {
|
||||
return 1;
|
||||
}
|
||||
// Then sort by horizontal distance
|
||||
int a_dx = a.getX() - position.getX();
|
||||
int a_dz = a.getZ() - position.getZ();
|
||||
int b_dx = b.getX() - position.getX();
|
||||
int b_dz = b.getZ() - position.getZ();
|
||||
int a_dist = a_dx*a_dx + a_dz*a_dz;
|
||||
int b_dist = b_dx*b_dx + b_dz*b_dz;
|
||||
if (a_dist < b_dist) {
|
||||
return -1;
|
||||
} else if (a_dist > b_dist) {
|
||||
return 1;
|
||||
}
|
||||
// Finally sort by angle
|
||||
double a_angle = Math.atan2(a_dz, a_dx);
|
||||
double b_angle = Math.atan2(b_dz, b_dx);
|
||||
if (a_angle < b_angle) {
|
||||
return -1;
|
||||
} else if (a_angle > b_angle) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toCollection(LinkedList::new));
|
||||
|
||||
// Remove already-existing notes from missingNotes, adding their positions to noteblockPositions, and create a list of unused noteblock locations
|
||||
ArrayList<BlockPos> unusedNoteblockLocations = new ArrayList<>();
|
||||
for (BlockPos nbPos : noteblockLocations) {
|
||||
BlockState bs = SongPlayer.MC.world.getBlockState(nbPos);
|
||||
int blockId = Block.getRawIdFromState(bs);
|
||||
if (blockId >= SongPlayer.NOTEBLOCK_BASE_ID && blockId < SongPlayer.NOTEBLOCK_BASE_ID+800) {
|
||||
int noteId = (blockId-SongPlayer.NOTEBLOCK_BASE_ID)/2;
|
||||
if (missingNotes.contains(noteId)) {
|
||||
// stage.tunedNoteblocks[noteId] = pos;
|
||||
missingNotes.remove(noteId);
|
||||
noteblockPositions.put(noteId, nbPos);
|
||||
}
|
||||
else {
|
||||
unusedNoteblockLocations.add(nbPos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unusedNoteblockLocations.add(nbPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate missing noteblocks into the unused noteblock locations
|
||||
int idx = 0;
|
||||
for (int noteId : missingNotes) {
|
||||
if (idx >= unusedNoteblockLocations.size()) {
|
||||
System.out.println("Too many noteblocks!");
|
||||
break;
|
||||
}
|
||||
noteblockPositions.put(noteId, unusedNoteblockLocations.get(idx++));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean nothingToBuild() {
|
||||
return requiredBreaks.isEmpty() && missingNotes.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public class DownloadUtils {
|
||||
|
||||
private static class DefaultTrustManager implements X509TrustManager {
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DownloadToByteArray(URL url, int maxSize) throws IOException, KeyManagementException, NoSuchAlgorithmException {
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
|
||||
SSLContext.setDefault(ctx);
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(10000);
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0");
|
||||
BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream());
|
||||
ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
byte buf[] = new byte[1024];
|
||||
int n;
|
||||
int tot = 0;
|
||||
while ((n = downloadStream.read(buf)) > 0) {
|
||||
byteArrayStream.write(buf, 0, n);
|
||||
tot += n;
|
||||
if (tot > maxSize) {
|
||||
throw new IOException("File is too large");
|
||||
}
|
||||
if (Thread.interrupted()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return byteArrayStream.toByteArray();
|
||||
} finally {
|
||||
// Closing a ByteArrayInputStream has no effect, so I do not close it.
|
||||
downloadStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream DownloadToInputStream(URL url, int maxSize) throws KeyManagementException, NoSuchAlgorithmException, IOException {
|
||||
return new ByteArrayInputStream(DownloadToByteArray(url, maxSize));
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.BuildingThread;
|
||||
|
||||
public class DownloadingThread extends Thread{
|
||||
|
||||
private String url;
|
||||
public DownloadingThread(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
SongPlayer.song = Song.getSongFromUrl(url);
|
||||
SongPlayer.addChatMessage("§6Finished downloading song");
|
||||
SongPlayer.mode = SongPlayer.Mode.BUILDING;
|
||||
SongPlayer.addChatMessage("§6Starting building.");
|
||||
(new BuildingThread()).start();
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
SongPlayer.addChatMessage("§cError getting song from url: " + e.getMessage());
|
||||
SongPlayer.mode = SongPlayer.Mode.IDLE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
public enum Instrument {
|
||||
HARP(0, 54),
|
||||
BASEDRUM(1, 0),
|
||||
SNARE(2, 0),
|
||||
HAT(3, 0),
|
||||
BASS(4, 30),
|
||||
FLUTE(5, 66),
|
||||
BELL(6, 78),
|
||||
GUITAR(7, 42),
|
||||
CHIME(8, 78),
|
||||
XYLOPHONE(9, 78),
|
||||
IRON_XYLOPHONE(10, 54),
|
||||
COW_BELL(11, 66),
|
||||
DIDGERIDOO(12, 30),
|
||||
BIT(13, 54),
|
||||
BANJO(14, 54),
|
||||
PLING(15, 54);
|
||||
|
||||
public final int instrumentId;
|
||||
public final int offset;
|
||||
|
||||
Instrument(int instrumentId, int offset) {
|
||||
this.instrumentId = instrumentId;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
private static Instrument[] values = values();
|
||||
public static Instrument getInstrumentFromId(int instrumentId) {
|
||||
return values[instrumentId];
|
||||
}
|
||||
}
|
|
@ -1,61 +1,37 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.sound.midi.MetaMessage;
|
||||
import javax.sound.midi.MidiEvent;
|
||||
import javax.sound.midi.MidiMessage;
|
||||
import javax.sound.midi.MidiSystem;
|
||||
import javax.sound.midi.Sequence;
|
||||
import javax.sound.midi.ShortMessage;
|
||||
import javax.sound.midi.Track;
|
||||
import javax.sound.midi.*;
|
||||
|
||||
public class MidiConverter {
|
||||
public static final int SET_INSTRUMENT = 0xC0;
|
||||
public static final int SET_TEMPO = 0x51;
|
||||
public static final int NOTE_ON = 0x90;
|
||||
public static final int NOTE_OFF = 0x80;
|
||||
|
||||
public static int[] instrument_offsets = new int[] {
|
||||
54, //harp
|
||||
0, //basedrum
|
||||
0, //snare
|
||||
0, //hat
|
||||
30, //bass
|
||||
66, //flute
|
||||
78, //bell
|
||||
42, //guitar
|
||||
78, //chime
|
||||
78, //xylophone
|
||||
54, //iron xylophone
|
||||
66, //cow bell
|
||||
30, //didgeridoo
|
||||
54, //bit
|
||||
54, //banjo
|
||||
54, //electric piano
|
||||
};
|
||||
|
||||
public static String fileName = "moskau";
|
||||
public static TreeMap<Long, ArrayList<Integer>> noteMap;
|
||||
public static Song getSongFromUrl(URL url) throws IOException, InvalidMidiDataException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
|
||||
Sequence sequence = MidiSystem.getSequence(DownloadUtils.DownloadToInputStream(url, 5*1024*1024));
|
||||
return getSong(sequence, Paths.get(url.toURI().getPath()).getFileName().toString());
|
||||
}
|
||||
|
||||
public static Song getSongFromFile(File file) throws InvalidMidiDataException, IOException {
|
||||
Sequence sequence = MidiSystem.getSequence(file);
|
||||
return getSong(sequence, file.getName());
|
||||
}
|
||||
|
||||
public static Song getSongFromBytes(byte[] bytes, String name) throws InvalidMidiDataException, IOException {
|
||||
Sequence sequence = MidiSystem.getSequence(new ByteArrayInputStream(bytes));
|
||||
return getSong(sequence, name);
|
||||
}
|
||||
|
||||
public static TreeMap<Long, ArrayList<Integer>> getMidi(BufferedInputStream downloadStream) throws Exception {
|
||||
noteMap = new TreeMap<>();
|
||||
|
||||
Sequence sequence = MidiSystem.getSequence(downloadStream);
|
||||
public static Song getSong(Sequence sequence, String name) {
|
||||
Song song = new Song(name);
|
||||
|
||||
long tpq = sequence.getResolution();
|
||||
|
||||
|
@ -73,18 +49,12 @@ public class MidiConverter {
|
|||
}
|
||||
}
|
||||
|
||||
Collections.sort(tempoEvents, new Comparator<MidiEvent>() {
|
||||
@Override
|
||||
public int compare(MidiEvent a, MidiEvent b) {
|
||||
return (new Long(a.getTick())).compareTo(b.getTick());
|
||||
}
|
||||
});
|
||||
Collections.sort(tempoEvents, (a, b) -> Long.compare(a.getTick(), b.getTick()));
|
||||
|
||||
for (Track track : sequence.getTracks()) {
|
||||
|
||||
long microTime = 0;
|
||||
int[] instrumentIds = new int[16];
|
||||
//int apparent_mpq = (int) (sequence.getMicrosecondLength()/sequence.getTickLength()*tpq);
|
||||
int mpq = 500000;
|
||||
int tempoEventIdx = 0;
|
||||
long prevTick = 0;
|
||||
|
@ -112,100 +82,126 @@ public class MidiConverter {
|
|||
}
|
||||
else if (sm.getCommand() == NOTE_ON) {
|
||||
if (sm.getData2() == 0) continue;
|
||||
int key = sm.getData1();
|
||||
int pitch = sm.getData1();
|
||||
long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
|
||||
Note note;
|
||||
if (sm.getChannel() == 9) {
|
||||
processMidiNote(128, sm.getData1(), microTime);
|
||||
note = getMidiPercussionNote(pitch, microTime);
|
||||
}
|
||||
else {
|
||||
processMidiNote(instrumentIds[sm.getChannel()], sm.getData1(), microTime);
|
||||
note = getMidiInstrumentNote(instrumentIds[sm.getChannel()], pitch, microTime);
|
||||
}
|
||||
if (note != null) {
|
||||
song.add(note);
|
||||
}
|
||||
|
||||
long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (sm.getCommand() == NOTE_OFF) {
|
||||
long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
song.sort();
|
||||
|
||||
downloadStream.close();
|
||||
|
||||
return noteMap;
|
||||
return song;
|
||||
}
|
||||
|
||||
public static void processMidiNote(int midiInstrument, int midiPitch, long microTime) {
|
||||
int minecraftInstrument = -1;
|
||||
public static Note getMidiInstrumentNote(int midiInstrument, int midiPitch, long microTime) {
|
||||
Instrument instrument = null;
|
||||
if ((midiInstrument >= 0 && midiInstrument <= 7) || (midiInstrument >= 24 && midiInstrument <= 31)) { //normal
|
||||
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 0; //piano
|
||||
instrument = Instrument.HARP;
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||
minecraftInstrument = 4; //bass
|
||||
instrument = Instrument.BASS;
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||
minecraftInstrument = 6; //bells
|
||||
instrument = Instrument.BELL;
|
||||
}
|
||||
}
|
||||
else if (midiInstrument >= 8 && midiInstrument <= 15) { //chromatic percussion
|
||||
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 10; //iron xylophone
|
||||
instrument = Instrument.IRON_XYLOPHONE;
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||
minecraftInstrument = 9; //xylophone
|
||||
instrument = Instrument.XYLOPHONE;
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||
minecraftInstrument = 4; //bass
|
||||
instrument = Instrument.BASS;
|
||||
}
|
||||
}
|
||||
else if ((midiInstrument >= 16 && midiInstrument <= 23) || (midiInstrument >= 32 && midiInstrument <= 71) || (midiInstrument >= 80 && midiInstrument <= 111)) { //synth
|
||||
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 13; //bit
|
||||
instrument = Instrument.BIT;
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) { //didgeridoo
|
||||
minecraftInstrument = 12;
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||
instrument = Instrument.DIDGERIDOO;
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) { //bells
|
||||
minecraftInstrument = 6;
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||
instrument = Instrument.BELL;
|
||||
}
|
||||
}
|
||||
else if ((midiInstrument >= 72 && midiInstrument <= 79)) { //woodwind
|
||||
if (midiPitch >= 66 && midiPitch <= 90) {
|
||||
minecraftInstrument = 5; //flute
|
||||
instrument = Instrument.FLUTE;
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) { //didgeridoo
|
||||
minecraftInstrument = 12;
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||
instrument = Instrument.DIDGERIDOO;
|
||||
}
|
||||
else if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 13; //bit
|
||||
instrument = Instrument.BIT;
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) { //bells
|
||||
minecraftInstrument = 6;
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||
instrument = Instrument.BELL;
|
||||
}
|
||||
}
|
||||
else if (midiInstrument == 128) {
|
||||
if (midiPitch == 35 || midiPitch == 36 || midiPitch == 41 || midiPitch == 43 || midiPitch == 45 || midiPitch == 57) {
|
||||
minecraftInstrument = 1; //bass drum
|
||||
}
|
||||
else if (midiPitch == 38 || midiPitch == 39 || midiPitch == 40 || midiPitch == 54 || midiPitch == 69 || midiPitch == 70 || midiPitch == 73 || midiPitch == 74 || midiPitch == 78 || midiPitch == 79) {
|
||||
minecraftInstrument = 2; //snare
|
||||
}
|
||||
else if (midiPitch == 37 || midiPitch == 42 || midiPitch == 44 || midiPitch == 46 || midiPitch == 49 || midiPitch == 51 || midiPitch == 52 || midiPitch == 55 || midiPitch == 57 || midiPitch == 59) {
|
||||
minecraftInstrument = 3; //hat
|
||||
}
|
||||
midiPitch = 0;
|
||||
|
||||
if (instrument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long milliTime = microTime / 1000;
|
||||
if (minecraftInstrument >= 0) {
|
||||
int noteId = (midiPitch-instrument_offsets[minecraftInstrument]) + minecraftInstrument*25;
|
||||
|
||||
if (!noteMap.containsKey(milliTime)) {
|
||||
noteMap.put(milliTime, new ArrayList<Integer>());
|
||||
}
|
||||
if (!noteMap.get(milliTime).contains(noteId)) {
|
||||
noteMap.get(milliTime).add(noteId);
|
||||
}
|
||||
|
||||
int pitch = midiPitch-instrument.offset;
|
||||
int noteId = pitch + instrument.instrumentId*25;
|
||||
long time = microTime / 1000L;
|
||||
|
||||
return new Note(noteId, time);
|
||||
}
|
||||
|
||||
private static Note getMidiPercussionNote(int midiPitch, long microTime) {
|
||||
Instrument instrument = null;
|
||||
if (midiPitch == 35 || midiPitch == 36 || midiPitch == 41 || midiPitch == 43 || midiPitch == 45 || midiPitch == 57) {
|
||||
instrument = Instrument.BASEDRUM;
|
||||
}
|
||||
else if (midiPitch == 38 || midiPitch == 39 || midiPitch == 40 || midiPitch == 54 || midiPitch == 69 || midiPitch == 70 || midiPitch == 73 || midiPitch == 74 || midiPitch == 78 || midiPitch == 79) {
|
||||
instrument = Instrument.SNARE;
|
||||
}
|
||||
else if (midiPitch == 37 || midiPitch == 42 || midiPitch == 44 || midiPitch == 46 || midiPitch == 49 || midiPitch == 51 || midiPitch == 52 || midiPitch == 55 || midiPitch == 57 || midiPitch == 59) {
|
||||
instrument = Instrument.HAT;
|
||||
}
|
||||
|
||||
if (instrument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int pitch = 0;
|
||||
int noteId = pitch + instrument.instrumentId*25;
|
||||
long time = microTime / 1000L;
|
||||
|
||||
return new Note(noteId, time);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class NBSConverter {
|
||||
public static Instrument[] instrumentIndex = new Instrument[] {
|
||||
Instrument.HARP,
|
||||
Instrument.BASS,
|
||||
Instrument.BASEDRUM,
|
||||
Instrument.SNARE,
|
||||
Instrument.HAT,
|
||||
Instrument.GUITAR,
|
||||
Instrument.FLUTE,
|
||||
Instrument.BELL,
|
||||
Instrument.CHIME,
|
||||
Instrument.XYLOPHONE,
|
||||
Instrument.IRON_XYLOPHONE,
|
||||
Instrument.COW_BELL,
|
||||
Instrument.DIDGERIDOO,
|
||||
Instrument.BIT,
|
||||
Instrument.BANJO,
|
||||
Instrument.PLING,
|
||||
};
|
||||
|
||||
private static class NBSNote {
|
||||
public int tick;
|
||||
public short layer;
|
||||
public byte instrument;
|
||||
public byte key;
|
||||
public byte velocity = 100;
|
||||
public byte panning = 100;
|
||||
public short pitch = 0;
|
||||
}
|
||||
|
||||
private static class NBSLayer {
|
||||
public String name;
|
||||
public byte lock = 0;
|
||||
public byte volume;
|
||||
public byte stereo = 100;
|
||||
}
|
||||
|
||||
public static Song getSongFromBytes(byte[] bytes, String fileName) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
short songLength = 0;
|
||||
byte format = 0;
|
||||
byte vanillaInstrumentCount = 0;
|
||||
songLength = buffer.getShort(); // If it's not 0, then it uses the old format
|
||||
if (songLength == 0) {
|
||||
format = buffer.get();
|
||||
}
|
||||
|
||||
if (format >= 1) {
|
||||
vanillaInstrumentCount = buffer.get();
|
||||
}
|
||||
if (format >= 3) {
|
||||
songLength = buffer.getShort();
|
||||
}
|
||||
|
||||
short layerCount = buffer.getShort();
|
||||
String songName = getString(buffer, bytes.length);
|
||||
String songAuthor = getString(buffer, bytes.length);
|
||||
String songOriginalAuthor = getString(buffer, bytes.length);
|
||||
String songDescription = getString(buffer, bytes.length);
|
||||
short tempo = buffer.getShort();
|
||||
byte autoSaving = buffer.get();
|
||||
byte autoSavingDuration = buffer.get();
|
||||
byte timeSignature = buffer.get();
|
||||
int minutesSpent = buffer.getInt();
|
||||
int leftClicks = buffer.getInt();
|
||||
int rightClicks = buffer.getInt();
|
||||
int blocksAdded = buffer.getInt();
|
||||
int blocksRemoved = buffer.getInt();
|
||||
String origFileName = getString(buffer, bytes.length);
|
||||
|
||||
byte loop = 0;
|
||||
byte maxLoopCount = 0;
|
||||
short loopStartTick = 0;
|
||||
if (format >= 4) {
|
||||
loop = buffer.get();
|
||||
maxLoopCount = buffer.get();
|
||||
loopStartTick = buffer.getShort();
|
||||
}
|
||||
|
||||
|
||||
ArrayList<NBSNote> nbsNotes = new ArrayList<>();
|
||||
short tick = -1;
|
||||
while (true) {
|
||||
int tickJumps = buffer.getShort();
|
||||
if (tickJumps == 0) break;
|
||||
tick += tickJumps;
|
||||
|
||||
short layer = -1;
|
||||
while (true) {
|
||||
int layerJumps = buffer.getShort();
|
||||
if (layerJumps == 0) break;
|
||||
layer += layerJumps;
|
||||
NBSNote note = new NBSNote();
|
||||
note.tick = tick;
|
||||
note.layer = layer;
|
||||
note.instrument = buffer.get();
|
||||
note.key = buffer.get();
|
||||
if (format >= 4) {
|
||||
note.velocity = buffer.get();
|
||||
note.panning = buffer.get();
|
||||
note.pitch = buffer.getShort();
|
||||
}
|
||||
nbsNotes.add(note);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<NBSLayer> nbsLayers = new ArrayList<>();
|
||||
if (buffer.hasRemaining()) {
|
||||
for (int i=0; i<layerCount; i++) {
|
||||
NBSLayer layer = new NBSLayer();
|
||||
layer.name = getString(buffer, bytes.length);
|
||||
if (format >= 4) {
|
||||
layer.lock = buffer.get();
|
||||
}
|
||||
layer.volume = buffer.get();
|
||||
if (format >= 2) {
|
||||
layer.stereo = buffer.get();
|
||||
}
|
||||
nbsLayers.add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
Song song = new Song(songName.trim().length() > 0 ? songName : fileName);
|
||||
if (loop > 0) {
|
||||
song.looping = true;
|
||||
song.loopPosition = getMilliTime(loopStartTick, tempo);
|
||||
}
|
||||
for (NBSNote note : nbsNotes) {
|
||||
Instrument instrument;
|
||||
if (note.instrument < instrumentIndex.length) {
|
||||
instrument = instrumentIndex[note.instrument];
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (note.key < 33 || note.key > 57) {
|
||||
continue;
|
||||
}
|
||||
|
||||
byte layerVolume = 100;
|
||||
if (nbsLayers.size() > note.layer) {
|
||||
layerVolume = nbsLayers.get(note.layer).volume;
|
||||
}
|
||||
|
||||
int pitch = note.key-33;
|
||||
int noteId = pitch + instrument.instrumentId*25;
|
||||
song.add(new Note(noteId, getMilliTime(note.tick, tempo)));
|
||||
}
|
||||
|
||||
song.length = song.get(song.size()-1).time + 50;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private static int getMilliTime(int tick, int tempo) {
|
||||
return 1000 * tick * 100 / tempo;
|
||||
}
|
||||
}
|
23
src/main/java/com/github/hhhzzzsss/songplayer/song/Note.java
Normal file
23
src/main/java/com/github/hhhzzzsss/songplayer/song/Note.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
public class Note implements Comparable<Note> {
|
||||
public int noteId;
|
||||
public long time;
|
||||
public Note(int note, long time) {
|
||||
this.noteId = note;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Note other) {
|
||||
if (time < other.time) {
|
||||
return -1;
|
||||
}
|
||||
else if (time > other.time) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
public class NoteEvent {
|
||||
public int note;
|
||||
public long time;
|
||||
public NoteEvent(int note, long time) {
|
||||
this.note = note;
|
||||
this.time = time;
|
||||
}
|
||||
}
|
|
@ -1,145 +1,104 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import java.util.Collections;
|
||||
|
||||
public class Song {
|
||||
public ArrayList<NoteEvent> notes = new ArrayList<>();
|
||||
public ArrayList<Note> notes = new ArrayList<>();
|
||||
public String name;
|
||||
public int position = 0;
|
||||
public int position = 0; // Current note index
|
||||
public boolean[] requiredNotes = new boolean[400];
|
||||
public boolean loop = false;
|
||||
public int gotoTime = -1;
|
||||
public boolean looping = false;
|
||||
public boolean paused = true;
|
||||
public long startTime = 0; // Start time in millis since unix epoch
|
||||
public long length = 0; // Milliseconds in the song
|
||||
public long loopPosition = 0; // Milliseconds into the song to start looping
|
||||
public long time = 0; // Time since start of song
|
||||
|
||||
private Song() {}
|
||||
public Song(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NoteEvent get(int i) {
|
||||
public Note get(int i) {
|
||||
return notes.get(i);
|
||||
}
|
||||
|
||||
public void add(NoteEvent e) {
|
||||
public void add(Note e) {
|
||||
notes.add(e);
|
||||
requiredNotes[e.noteId] = true;
|
||||
}
|
||||
|
||||
|
||||
public void sort() {
|
||||
Collections.sort(notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playing song (does nothing if already playing)
|
||||
*/
|
||||
public void play() {
|
||||
if (paused) {
|
||||
paused = false;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses song (does nothing if already paused)
|
||||
*/
|
||||
public void pause() {
|
||||
if (!paused) {
|
||||
paused = true;
|
||||
advanceTime();
|
||||
}
|
||||
}
|
||||
|
||||
public void setTime(long t) {
|
||||
time = t;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
position = 0;
|
||||
while (reachedNextNote()) {
|
||||
getNextNote();
|
||||
}
|
||||
}
|
||||
|
||||
public void advanceTime() {
|
||||
time = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
|
||||
public boolean reachedNextNote() {
|
||||
if (position < notes.size()) {
|
||||
return notes.get(position).time <= this.time;
|
||||
} else {
|
||||
if (looping) {
|
||||
return notes.get(0).time + length <= this.time;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Note getNextNote() {
|
||||
if (position >= notes.size()) {
|
||||
if (looping) {
|
||||
loop();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return notes.get(position++);
|
||||
}
|
||||
|
||||
public boolean finished() {
|
||||
return time > length;
|
||||
}
|
||||
|
||||
private void loop() {
|
||||
position = 0;
|
||||
startTime += length;
|
||||
time -= length;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return notes.size();
|
||||
}
|
||||
|
||||
public static Song getSongFromFile(String file) throws Exception {
|
||||
Song song = new Song();
|
||||
if (file.contains("/") || file.contains("\\")) throw new FileNotFoundException();
|
||||
File songPath = new File(SongPlayer.SONG_DIR, file);
|
||||
if (!songPath.exists()) {
|
||||
songPath = new File(SongPlayer.SONG_DIR, file + ".txt");
|
||||
}
|
||||
if (!songPath.exists()) {
|
||||
songPath = new File(SongPlayer.SONG_DIR, file + ".mid");
|
||||
}
|
||||
if (!songPath.exists()) {
|
||||
songPath = new File(SongPlayer.SONG_DIR, file + ".midi");
|
||||
}
|
||||
if (!songPath.exists()) throw new FileNotFoundException();
|
||||
boolean isMidi = false;
|
||||
String extension = getExtension(songPath);
|
||||
if (extension.equalsIgnoreCase("mid") || extension.equalsIgnoreCase("midi")) isMidi = true;
|
||||
if (isMidi) {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(songPath));
|
||||
song.notes.clear();
|
||||
TreeMap<Long, ArrayList<Integer>> noteMap = MidiConverter.getMidi(bis);
|
||||
System.out.println(noteMap.size());
|
||||
for (int i=0; i<400; i++) song.requiredNotes[i] = false;
|
||||
for (Map.Entry<Long, ArrayList<Integer>> entry : noteMap.entrySet()) {
|
||||
for (int note : entry.getValue()) {
|
||||
long time = entry.getKey();
|
||||
song.requiredNotes[note] = true;
|
||||
song.add(new NoteEvent(note, time));
|
||||
}
|
||||
}
|
||||
song.name = songPath.getName();
|
||||
return song;
|
||||
}
|
||||
else {
|
||||
song.notes.clear();
|
||||
BufferedReader br = new BufferedReader(new FileReader(songPath));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
String[] split = line.split(" ");
|
||||
long time = Long.parseLong(split[0]);
|
||||
int note = Integer.parseInt(split[1]);
|
||||
song.requiredNotes[note] = true;
|
||||
song.notes.add(new NoteEvent(note, time));
|
||||
}
|
||||
br.close();
|
||||
song.name = songPath.getName();
|
||||
return song;
|
||||
}
|
||||
}
|
||||
|
||||
public static Song getSongFromUrl(String url) throws Exception {
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
|
||||
SSLContext.setDefault(ctx);
|
||||
URLConnection conn = new URL(url).openConnection();
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(5000);
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0");
|
||||
BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream());
|
||||
Song song = new Song();
|
||||
song.notes.clear();
|
||||
TreeMap<Long, ArrayList<Integer>> noteMap = MidiConverter.getMidi(downloadStream);
|
||||
System.out.println(noteMap.size());
|
||||
for (int i=0; i<400; i++) song.requiredNotes[i] = false;
|
||||
for (Map.Entry<Long, ArrayList<Integer>> entry : noteMap.entrySet()) {
|
||||
for (int note : entry.getValue()) {
|
||||
long time = entry.getKey();
|
||||
song.requiredNotes[note] = true;
|
||||
song.add(new NoteEvent(note, time));
|
||||
}
|
||||
}
|
||||
song.name = url.substring(url.lastIndexOf('/')+1, url.length());
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
private static class DefaultTrustManager implements X509TrustManager {
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getExtension(File file) {
|
||||
String name = file.getName();
|
||||
if(name.lastIndexOf(".") != -1 && name.lastIndexOf(".") != 0)
|
||||
return name.substring(name.lastIndexOf(".") + 1);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class SongLoaderThread extends Thread{
|
||||
|
||||
private String location;
|
||||
private File songPath;
|
||||
private URL songUrl;
|
||||
public Exception exception;
|
||||
public Song song;
|
||||
|
||||
private boolean isUrl = false;
|
||||
|
||||
public SongLoaderThread(String location) throws IOException {
|
||||
this.location = location;
|
||||
if (location.startsWith("http://") || location.startsWith("https://")) {
|
||||
isUrl = true;
|
||||
songUrl = new URL(location);
|
||||
}
|
||||
else if (location.contains("/") || location.contains("\\")) {
|
||||
throw new IOException("Invalid characters in song name: " + location);
|
||||
}
|
||||
else if (getSongFile(location).exists()) {
|
||||
songPath = getSongFile(location);
|
||||
}
|
||||
else if (getSongFile(location+".mid").exists()) {
|
||||
songPath = getSongFile(location+".mid");
|
||||
}
|
||||
else if (getSongFile(location+".midi").exists()) {
|
||||
songPath = getSongFile(location+".midi");
|
||||
}
|
||||
else if (getSongFile(location+".nbs").exists()) {
|
||||
songPath = getSongFile(location+".nbs");
|
||||
}
|
||||
else {
|
||||
throw new IOException("Could not find song: " + location);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
byte[] bytes;
|
||||
String name;
|
||||
if (isUrl) {
|
||||
bytes = DownloadUtils.DownloadToByteArray(songUrl, 10*1024*1024);
|
||||
name = Paths.get(songUrl.toURI().getPath()).getFileName().toString();
|
||||
}
|
||||
else {
|
||||
bytes = Files.readAllBytes(songPath.toPath());
|
||||
name = songPath.getName();
|
||||
}
|
||||
|
||||
try {
|
||||
song = MidiConverter.getSongFromBytes(bytes, location);
|
||||
}
|
||||
catch (Exception e) {}
|
||||
|
||||
if (song == null) {
|
||||
try {
|
||||
song = NBSConverter.getSongFromBytes(bytes, name);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (song == null) {
|
||||
throw new IOException("Invalid song format");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
|
||||
private File getSongFile(String name) {
|
||||
return new File(SongPlayer.SONG_DIR, name);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,8 @@
|
|||
],
|
||||
"client": [
|
||||
"ClientPlayerEntityMixin",
|
||||
"ClientPlayNetworkHandlerMixin"
|
||||
"ClientPlayNetworkHandlerMixin",
|
||||
"MinecraftClientMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
Loading…
Reference in a new issue