diff --git a/README.md b/README.md index b8e6b94..ee00a3b 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Public edition of FumoUtils. - FumoVoidESP - HighwayHighlighter - ItemESP +- Karaoke - MapHighlighter - QuartzFarmer - RegionFileHighlighter diff --git a/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java b/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java index d4f95cc..4b22afb 100644 --- a/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java +++ b/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java @@ -30,6 +30,7 @@ public void onInitialize() { Modules.get().add(new FumoVoidESP()); Modules.get().add(new HighwayHighlighter()); Modules.get().add(new ItemESP()); + Modules.get().add(new Karaoke()); Modules.get().add(new MapHighlighter()); Modules.get().add(new QuartzFarmer()); Modules.get().add(new RegionFileHighlighter()); diff --git a/src/main/java/moe/kyuunex/fumo_utils/models/LyricsFile.java b/src/main/java/moe/kyuunex/fumo_utils/models/LyricsFile.java new file mode 100644 index 0000000..631b3e3 --- /dev/null +++ b/src/main/java/moe/kyuunex/fumo_utils/models/LyricsFile.java @@ -0,0 +1,38 @@ +package moe.kyuunex.fumo_utils.models; + +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class LyricsFile { + Pattern pattern = Pattern.compile("^\\[(\\d{2}):(\\d{2}\\.\\d{2})\\]\\s*(.*)$"); + public int lastLyric; + + public Dictionary lyrics = new Hashtable<>(); + + public LyricsFile(Scanner object){ + while (object.hasNextLine()) { + String data = object.nextLine(); + ParseLine(data); + } + } + + void ParseLine(String line){ + Matcher matcher = pattern.matcher(line); + + if (matcher.matches()) { + int minutes = Integer.parseInt(matcher.group(1)); + double seconds = Double.parseDouble(matcher.group(2)); + String lyric = matcher.group(3).trim(); + + // Calculate the total timestamp in seconds + double timestamp = (minutes * 60 + seconds) * 20; + + // Add the parsed lyric to the list= + lyrics.put((int)timestamp, lyric); + lastLyric = (int)timestamp; + } + } +} diff --git a/src/main/java/moe/kyuunex/fumo_utils/modules/Karaoke.java b/src/main/java/moe/kyuunex/fumo_utils/modules/Karaoke.java new file mode 100644 index 0000000..85f1992 --- /dev/null +++ b/src/main/java/moe/kyuunex/fumo_utils/modules/Karaoke.java @@ -0,0 +1,106 @@ +package moe.kyuunex.fumo_utils.modules; + +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.settings.*; +import moe.kyuunex.fumo_utils.FumoUtils; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.orbit.EventHandler; +import moe.kyuunex.fumo_utils.models.LyricsFile; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + + +public class Karaoke extends Module { + private final SettingGroup sgGeneral = this.settings.getDefaultGroup(); + private int duration = 0; + private boolean isReady = false; + private Scanner scanner; + private LyricsFile lyricsFile; + + private final Setting lyricsFilePath = sgGeneral.add(new StringSetting.Builder() + .name("lyrics-file-path") + .description("Full path to the lyrics file") + .defaultValue("") + .build() + ); + + private final Setting isUntimed = sgGeneral.add(new BoolSetting.Builder() + .name("is-untimed-file") + .description("Enable for a text file with lyrics each line, with no timestamping. Disable for .lrc") + .defaultValue(false) + .build() + ); + + private final Setting timeBetweenLines = sgGeneral.add(new IntSetting.Builder() + .name("time-between-lines") + .description("Time between lines (in ticks) (for untimed only!)") + .defaultValue(74) + .build() + ); + + private final Setting simulate = sgGeneral.add(new BoolSetting.Builder() + .name("simulate") + .description("Enable to send client side only for preview, disable to send messages to the server") + .defaultValue(false) + .build() + ); + + public Karaoke() { + super(FumoUtils.CATEGORY, "karaoke", "Sing along with your friends on the server."); + } + + @Override + public void onActivate() { + try { + scanner = new Scanner(new File(lyricsFilePath.get())); + if(!isUntimed.get()) lyricsFile = new LyricsFile(scanner); + isReady = true; + info("Karaoke started!"); + } catch (FileNotFoundException e) { + toggle(); + isReady = false; + } + } + + @Override + public void onDeactivate() { + scanner.close(); + isReady = false; + duration = 0; + } + + @EventHandler + private void onTick(TickEvent.Post event) { + if(!isReady) return; + + if(isUntimed.get()) { + if(duration < timeBetweenLines.get()) { + duration += 1; + return; + } + duration = 0; + if(scanner.hasNextLine()) send(scanner.nextLine()); + } else { + if(duration > lyricsFile.lastLyric) { + toggle(); + return; + } + try { + String lyric = lyricsFile.lyrics.get(duration); + if(lyric != null) send(lyric); + } + catch (IndexOutOfBoundsException ignored){} + duration += 1; + } + } + + private void send(String text){ + if(simulate.get()) + info(text); + else + ChatUtils.sendPlayerMsg(text); + } +}