diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/CommandProcessor.java b/src/main/java/com/github/hhhzzzsss/songplayer/CommandProcessor.java index 9005659..ed4de80 100644 --- a/src/main/java/com/github/hhhzzzsss/songplayer/CommandProcessor.java +++ b/src/main/java/com/github/hhhzzzsss/songplayer/CommandProcessor.java @@ -1,9 +1,10 @@ package com.github.hhhzzzsss.songplayer; -import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler; +import com.github.hhhzzzsss.songplayer.playing.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; @@ -175,20 +176,15 @@ public class CommandProcessor { } if (args.length() > 0) { - Pattern timestamp_pattern = Pattern.compile("(\\d+):(\\d+)"); - Matcher timestamp_matcher = timestamp_pattern.matcher(args); - - if (timestamp_matcher.matches()) { - String minutes = timestamp_matcher.group(1); - String seconds = timestamp_matcher.group(2); - 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 { + try { + long time = Util.parseTime(args); + SongHandler.getInstance().currentSong.setTime(time); + SongPlayer.addChatMessage("§6Set song time to §3" + Util.formatTime(time)); + return true; + } catch (IOException e) { SongPlayer.addChatMessage("§cNot a valid time stamp"); - return true; - } + return false; + } } else { return false; @@ -239,14 +235,10 @@ public class CommandProcessor { return true; } Song currentSong = SongHandler.getInstance().currentSong; + long currentTime = Math.min(currentSong.time, currentSong.length); + long totalTime = currentSong.length; if (args.length() == 0) { - 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)", currentSong.name, currTimeMinutes, currTimeSeconds, totTimeMinutes, totTimeSeconds)); + SongPlayer.addChatMessage(String.format("§6Currently playing %s §3(%s/%s)", Util.formatTime(currentTime), Util.formatTime(totalTime))); return true; } else { diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/FakePlayerEntity.java b/src/main/java/com/github/hhhzzzsss/songplayer/FakePlayerEntity.java index 4dba8ba..a98e8c3 100644 --- a/src/main/java/com/github/hhhzzzsss/songplayer/FakePlayerEntity.java +++ b/src/main/java/com/github/hhhzzzsss/songplayer/FakePlayerEntity.java @@ -1,7 +1,7 @@ package com.github.hhhzzzsss.songplayer; -import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler; -import com.github.hhhzzzsss.songplayer.noteblocks.Stage; +import com.github.hhhzzzsss.songplayer.playing.SongHandler; +import com.github.hhhzzzsss.songplayer.playing.Stage; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.OtherClientPlayerEntity; import net.minecraft.client.world.ClientWorld; diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/SongPlayer.java b/src/main/java/com/github/hhhzzzsss/songplayer/SongPlayer.java index 117c230..4d92b00 100644 --- a/src/main/java/com/github/hhhzzzsss/songplayer/SongPlayer.java +++ b/src/main/java/com/github/hhhzzzsss/songplayer/SongPlayer.java @@ -2,9 +2,6 @@ package com.github.hhhzzzsss.songplayer; import java.io.File; -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; diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/Util.java b/src/main/java/com/github/hhhzzzsss/songplayer/Util.java new file mode 100644 index 0000000..a934ee7 --- /dev/null +++ b/src/main/java/com/github/hhhzzzsss/songplayer/Util.java @@ -0,0 +1,48 @@ +package com.github.hhhzzzsss.songplayer; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Util { + public static String formatTime(long milliseconds) { + long temp = Math.abs(milliseconds); + temp /= 1000; + long seconds = temp % 60; + temp /= 60; + long minutes = temp % 60; + temp /= 60; + long hours = temp; + StringBuilder sb = new StringBuilder(); + if (milliseconds < 0) { + sb.append("-"); + } + if (hours > 0) { + sb.append(String.format("%d:", hours)); + sb.append(String.format("%02d:", minutes)); + } else { + sb.append(String.format("%d:", minutes)); + } + sb.append(String.format("%02d", seconds)); + return sb.toString(); + } + + public static Pattern timePattern = Pattern.compile("(?:(\\d+)?:)(\\d+):(\\d+)"); + public static long parseTime(String timeStr) throws IOException { + Matcher matcher = timePattern.matcher(timeStr); + if (matcher.matches()) { + long time = 0; + String hourString = matcher.group(1); + String minuteString = matcher.group(2); + String secondString = matcher.group(3); + if (hourString != null) { + time += Integer.parseInt(hourString) * 60 * 60 * 1000; + } + time += Integer.parseInt(minuteString) * 60 * 1000; + time += Double.parseDouble(secondString) * 1000.0; + return time; + } else { + throw new IOException("Invalid time pattern"); + } + } +} diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin.java index e87bc75..48087cd 100644 --- a/src/main/java/com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin.java @@ -1,7 +1,7 @@ package com.github.hhhzzzsss.songplayer.mixin; -import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler; -import com.github.hhhzzzsss.songplayer.noteblocks.Stage; +import com.github.hhhzzzsss.songplayer.playing.SongHandler; +import com.github.hhhzzzsss.songplayer.playing.Stage; import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -15,7 +15,6 @@ import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.ClientConnection; import net.minecraft.network.Packet; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; -import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; @Mixin(ClientPlayNetworkHandler.class) diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/mixin/InGameHudMixin.java b/src/main/java/com/github/hhhzzzsss/songplayer/mixin/InGameHudMixin.java new file mode 100644 index 0000000..fba7d00 --- /dev/null +++ b/src/main/java/com/github/hhhzzzsss/songplayer/mixin/InGameHudMixin.java @@ -0,0 +1,33 @@ +package com.github.hhhzzzsss.songplayer.mixin; + +import com.github.hhhzzzsss.songplayer.SongPlayer; +import com.github.hhhzzzsss.songplayer.playing.ProgressDisplay; +import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(InGameHud.class) +public class InGameHudMixin { + @Shadow + private int scaledWidth; + + @Shadow + private int scaledHeight; + + @Shadow + private int heldItemTooltipFade; + + @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;F)V", + at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;enableBlend()V", ordinal = 4)) + private void onRender(MatrixStack matrixStack, float tickDelta, CallbackInfo ci) { + if (SongPlayer.MC.options.debugEnabled) { + return; + } + + ProgressDisplay.getInstance().onRenderHUD(matrixStack, scaledWidth, scaledHeight, heldItemTooltipFade); + } +} diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/mixin/MinecraftClientMixin.java b/src/main/java/com/github/hhhzzzsss/songplayer/mixin/MinecraftClientMixin.java index 30ac073..e8026bf 100644 --- a/src/main/java/com/github/hhhzzzsss/songplayer/mixin/MinecraftClientMixin.java +++ b/src/main/java/com/github/hhhzzzsss/songplayer/mixin/MinecraftClientMixin.java @@ -1,6 +1,7 @@ package com.github.hhhzzzsss.songplayer.mixin; -import com.github.hhhzzzsss.songplayer.noteblocks.SongHandler; +import com.github.hhhzzzsss.songplayer.playing.SongHandler; +import com.github.hhhzzzsss.songplayer.playing.ProgressDisplay; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -9,9 +10,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.github.hhhzzzsss.songplayer.SongPlayer; import net.minecraft.client.MinecraftClient; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult.Type; -import net.minecraft.util.math.BlockPos; @Mixin(MinecraftClient.class) public class MinecraftClientMixin { @@ -23,4 +21,9 @@ public class MinecraftClientMixin { SongHandler.getInstance().onNotIngame(); } } + + @Inject(at = @At("HEAD"), method = "tick()V") + public void onTick(CallbackInfo ci) { + ProgressDisplay.getInstance().onTick(); + } } diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/playing/ProgressDisplay.java b/src/main/java/com/github/hhhzzzsss/songplayer/playing/ProgressDisplay.java new file mode 100644 index 0000000..4f09377 --- /dev/null +++ b/src/main/java/com/github/hhhzzzsss/songplayer/playing/ProgressDisplay.java @@ -0,0 +1,61 @@ +package com.github.hhhzzzsss.songplayer.playing; + +import com.github.hhhzzzsss.songplayer.SongPlayer; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; + +import java.util.Objects; + +public class ProgressDisplay { + private static ProgressDisplay instance = null; + public static ProgressDisplay getInstance() { + if (instance == null) { + instance = new ProgressDisplay(); + } + return instance; + } + private ProgressDisplay() {} + + public MutableText displayText = Text.empty(); + public int fade = 0; + + public void setText(MutableText text) { + displayText = text; + fade = 100; + } + + public void onRenderHUD(MatrixStack matrixStack, int scaledWidth, int scaledHeight, int heldItemTooltipFade) { + if (fade <= 0) { + return; + } + + int textWidth = SongPlayer.MC.textRenderer.getWidth(displayText); + int textX = (scaledWidth - textWidth) / 2; + int textY = scaledHeight - 59; + if (!SongPlayer.MC.interactionManager.hasStatusBars()) { + textY += 14; + } + if (heldItemTooltipFade > 0) { + textY -= 12; + } + + int opacity = (int)((float)this.fade * 256.0F / 10.0F); + if (opacity > 255) { + opacity = 255; + } + + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + Objects.requireNonNull(SongPlayer.MC.textRenderer); + SongPlayer.MC.textRenderer.drawWithShadow(matrixStack, displayText, (float)textX, (float)textY, 16777215 + (opacity << 24)); + RenderSystem.disableBlend(); + } + + public void onTick() { + if (fade > 0) { + fade--; + } + } +} diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/noteblocks/SongHandler.java b/src/main/java/com/github/hhhzzzsss/songplayer/playing/SongHandler.java similarity index 86% rename from src/main/java/com/github/hhhzzzsss/songplayer/noteblocks/SongHandler.java rename to src/main/java/com/github/hhhzzzsss/songplayer/playing/SongHandler.java index f6eb5f1..b4a0555 100644 --- a/src/main/java/com/github/hhhzzzsss/songplayer/noteblocks/SongHandler.java +++ b/src/main/java/com/github/hhhzzzsss/songplayer/playing/SongHandler.java @@ -1,18 +1,17 @@ -package com.github.hhhzzzsss.songplayer.noteblocks; +package com.github.hhhzzzsss.songplayer.playing; 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 com.github.hhhzzzsss.songplayer.Util; +import com.github.hhhzzzsss.songplayer.song.*; 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.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; @@ -31,6 +30,7 @@ public class SongHandler { } return instance; } + private SongHandler() {} public SongLoaderThread loaderThread = null; public LinkedList songQueue = new LinkedList<>(); @@ -124,6 +124,7 @@ public class SongHandler { private int buildEndDelay = 0; private int buildCooldown = 0; private void handleBuilding() { + setBuildProgressDisplay(); if (buildStartDelay > 0) { buildStartDelay--; return; @@ -133,7 +134,6 @@ public class SongHandler { return; } ClientWorld world = SongPlayer.MC.world; - ClientPlayerEntity player = SongPlayer.MC.player; if (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.CREATIVE) { return; } @@ -177,9 +177,19 @@ public class SongHandler { return; } } + private void setBuildProgressDisplay() { + MutableText text = Text.empty() + .append(Text.literal("Building noteblocks | " ).formatted(Formatting.GOLD)) + .append(Text.literal((stage.totalMissingNotes - stage.missingNotes.size()) + "/" + stage.totalMissingNotes).formatted(Formatting.DARK_AQUA)); + ProgressDisplay.getInstance().setText(text); + } // Runs every frame private void handlePlaying(boolean tick) { + if (tick) { + setPlayProgressDisplay(); + } + if (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.SURVIVAL) { currentSong.pause(); return; @@ -217,6 +227,20 @@ public class SongHandler { } } + public void setPlayProgressDisplay() { + long currentTime = Math.min(currentSong.time, currentSong.length); + long totalTime = currentSong.length; + MutableText text = Text.empty() + .append(Text.literal("Now playing " ).formatted(Formatting.GOLD)) + .append(Text.literal(currentSong.name).formatted(Formatting.BLUE)) + .append(Text.literal(" | " ).formatted(Formatting.GOLD)) + .append(Text.literal(String.format("%s/%s", Util.formatTime(currentTime), Util.formatTime(totalTime))).formatted(Formatting.DARK_AQUA)); + if (currentSong.looping) { + text.append(Text.literal(" | Looping enabled" ).formatted(Formatting.GOLD)); + } + ProgressDisplay.getInstance().setText(text); + } + public void cleanup() { currentSong = null; songQueue.clear(); diff --git a/src/main/java/com/github/hhhzzzsss/songplayer/noteblocks/Stage.java b/src/main/java/com/github/hhhzzzsss/songplayer/playing/Stage.java similarity index 95% rename from src/main/java/com/github/hhhzzzsss/songplayer/noteblocks/Stage.java rename to src/main/java/com/github/hhhzzzsss/songplayer/playing/Stage.java index b2395fd..558d47a 100644 --- a/src/main/java/com/github/hhhzzzsss/songplayer/noteblocks/Stage.java +++ b/src/main/java/com/github/hhhzzzsss/songplayer/playing/Stage.java @@ -1,167 +1,170 @@ -package com.github.hhhzzzsss.songplayer.noteblocks; - -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; - -public class Stage { - private final ClientPlayerEntity player = SongPlayer.MC.player; - - public BlockPos position; -// public BlockPos[] tunedNoteblocks = new BlockPos[400]; - public HashMap noteblockPositions = new HashMap<>(); - public boolean rebuild = false; - - public LinkedList requiredBreaks = new LinkedList<>(); - public TreeSet 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 noteblockLocations = new ArrayList<>(); - ArrayList 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 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(); - } -} +package com.github.hhhzzzsss.songplayer.playing; + +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.client.network.ClientPlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class Stage { + private final ClientPlayerEntity player = SongPlayer.MC.player; + + public BlockPos position; +// public BlockPos[] tunedNoteblocks = new BlockPos[400]; + public HashMap noteblockPositions = new HashMap<>(); + public boolean rebuild = false; + + public LinkedList requiredBreaks = new LinkedList<>(); + public TreeSet missingNotes = new TreeSet<>(); + public int totalMissingNotes = 0; + + 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 noteblockLocations = new ArrayList<>(); + ArrayList 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 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++)); + } + + // Set total missing notes + totalMissingNotes = missingNotes.size(); + } + + public boolean nothingToBuild() { + return requiredBreaks.isEmpty() && missingNotes.isEmpty(); + } +} diff --git a/src/main/resources/songplayer.mixins.json b/src/main/resources/songplayer.mixins.json index 1a4d119..d260804 100644 --- a/src/main/resources/songplayer.mixins.json +++ b/src/main/resources/songplayer.mixins.json @@ -8,6 +8,7 @@ "client": [ "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerMixin", + "InGameHudMixin", "MinecraftClientMixin" ], "injectors": {