Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/main/java/net/asodev/islandutils/IslandUtilsClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.noxcrew.noxesium.network.NoxesiumPackets;
import com.noxcrew.noxesium.network.clientbound.ClientboundMccGameStatePacket;
import com.noxcrew.noxesium.network.clientbound.ClientboundMccServerPacket;
import net.asodev.islandutils.discord.DiscordPresenceUpdator;
import net.asodev.islandutils.modules.DisguiseKeybind;
import net.asodev.islandutils.modules.NoxesiumIntegration;
import net.asodev.islandutils.modules.plobby.PlobbyFeatures;
import net.asodev.islandutils.modules.plobby.PlobbyJoinCodeCopy;
import net.asodev.islandutils.modules.splits.SplitCommands;
import net.asodev.islandutils.modules.splits.SplitManager;
import net.asodev.islandutils.modules.splits.ui.SplitUI;
import net.asodev.islandutils.state.Game;
Expand Down Expand Up @@ -51,13 +49,15 @@ public void onInitializeClient() {
DisguiseKeybind.registerDisguiseInput();
PlobbyFeatures.registerEvents();
IslandUtilsCommand.register();
new SplitCommands();
DiscordPresenceUpdator.init();
PlobbyJoinCodeCopy.register();

if (Utils.isLunarClient()) {
SplitUI.setupFallbackRenderer();
}
new NoxesiumIntegration().init();

}

public static void onJoinMCCI(boolean isProduction) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package net.asodev.islandutils.mixins.network;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestion;
import net.asodev.islandutils.IslandUtilsClient;
import net.asodev.islandutils.IslandUtilsEvents;
import net.asodev.islandutils.discord.DiscordPresenceUpdator;
import net.asodev.islandutils.modules.FriendsInGame;
import net.asodev.islandutils.modules.splits.sob.SobRenderer;
import net.asodev.islandutils.modules.splits.sob.TeamInfo;
import net.asodev.islandutils.options.IslandOptions;
import net.asodev.islandutils.options.IslandSoundCategories;
import net.asodev.islandutils.modules.ClassicAnnouncer;
Expand All @@ -23,7 +23,6 @@
import net.minecraft.client.multiplayer.*;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
Expand All @@ -34,9 +33,11 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.scores.*;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
Expand All @@ -51,22 +52,27 @@

@Mixin(ClientPacketListener.class)
public abstract class PacketListenerMixin extends ClientCommonPacketListenerImpl {

// I should really separate these mixins...

@Shadow private CommandDispatcher<CommandSourceStack> commands;

@Final
@Shadow private Scoreboard scoreboard;

protected PacketListenerMixin(Minecraft minecraft, Connection connection, CommonListenerCookie commonListenerCookie) {
super(minecraft, connection, commonListenerCookie);
}

// Patterns for the Map & Modifier options on scoreboard
@Unique
final Map<String, Pattern> scoreboardPatterns = Map.of(
"MAP", Pattern.compile("MAP: (?<map>\\w+(?:,? \\w+)*)"),
"MODIFIER", Pattern.compile("MODIFIER: (?<modifier>\\w+(?:,? \\w+)*)"),
"COURSE", Pattern.compile("COURSE: (?<course>.*)"),
"LEAP", Pattern.compile("LEAP \\[(?<leap>.*/.*)]")
"LEAP", Pattern.compile("LEAP \\[(?<leap>.*/.*)]"),
"TIME", Pattern.compile("(?<time>\\d{2}:\\d{2}\\.\\d{3})")
);
@Unique private SobRenderer renderer;
@Inject(method = "handleSetPlayerTeamPacket", at = @At("TAIL")) // Scoreboard lines!
public void handleSetPlayerTeamPacket(ClientboundSetPlayerTeamPacket clientboundSetPlayerTeamPacket, CallbackInfo ci) {
if (!MccIslandState.isOnline()) return;
Expand All @@ -91,6 +97,14 @@ public void handleSetPlayerTeamPacket(ClientboundSetPlayerTeamPacket clientbound
MccIslandState.setMap(value);
}
case "LEAP" -> DiscordPresenceUpdator.leapScoreboardUpdate(value, true);
case "TIME" -> {
if (!IslandOptions.getSplits().isShowSumOfBest()) break;
Optional<TeamInfo> info = TeamInfo.fromScoreboard(scoreboard);
info.ifPresent(t -> {
renderer = new SobRenderer(t);
renderer.update();
});
}
}

ChatUtils.debug("ScoreboardUpdate - Current %s: \"%s\"", entry.getKey(), value);
Expand All @@ -106,9 +120,14 @@ public void handleCustomSoundEvent(ClientboundSoundPacket clientboundCustomSound
// Get the location of the new sound
// Previously this was obfuscated by noxcrew, but not anymore yayyyyy :D
ResourceLocation soundLoc = clientboundCustomSoundPacket.getSound().value().getLocation();

String soundPath = soundLoc.getPath();
if (MccIslandState.getGame() == Game.PARKOUR_WARRIOR_DOJO) {
LevelTimer.onSound(clientboundCustomSoundPacket);
if (IslandOptions.getSplits().isShowSumOfBest() &&
(soundPath.contains("games.parkour_warrior.medal_gain")
|| soundPath.contains("games.parkour_warrior.parkour_finish")
|| soundPath.contains("games.parkour_warrior.teleport_scroll")))
renderer.update();
}

// If we aren't in a game, don't play music
Expand All @@ -117,33 +136,33 @@ public void handleCustomSoundEvent(ClientboundSoundPacket clientboundCustomSound
if (MccIslandState.getGame() != Game.BATTLE_BOX) {

// Stop the music if you restart the course or switch game mode in Parkour Warrior
if(soundLoc.getPath().contains("games.parkour_warrior.mode_swap") || soundLoc.getPath().contains("games.parkour_warrior.restart_course")) {
if (soundPath.contains("games.parkour_warrior.mode_swap") || soundPath.contains("games.parkour_warrior.restart_course")) {
MusicUtil.stopMusic(false);
}
if (MccIslandState.getGame() == Game.PARKOUR_WARRIOR_SURVIVOR && Objects.equals(soundLoc.getPath(), "games.global.early_elimination")) {
if (MccIslandState.getGame() == Game.PARKOUR_WARRIOR_SURVIVOR && Objects.equals(soundPath, "games.global.early_elimination")) {
MusicUtil.startMusic(clientboundCustomSoundPacket, true); // The game started. Start the music!!
} else if (Objects.equals(soundLoc.getPath(), "games.global.countdown.go") && !MusicUtil.isMusicPlaying()) {
} else if (Objects.equals(soundPath, "games.global.countdown.go") && !MusicUtil.isMusicPlaying()) {
MusicUtil.startMusic(clientboundCustomSoundPacket); // The game started. Start the music!!
}
} else {
// We're playing battlebox, and the music needs to start early.
if (Objects.equals(soundLoc.getPath(), "music.global.gameintro")) {
if (Objects.equals(soundPath, "music.global.gameintro")) {
MusicUtil.startMusic(clientboundCustomSoundPacket); // Start the music!!
ChatUtils.debug("[PacketListener] Canceling gameintro");
ci.cancel(); // Stop minecraft from minecrafting
return;
}
}
if (Objects.equals(soundLoc.getPath(), "games.global.timer.round_end")
|| soundLoc.getPath().startsWith("music.global.")) {
if (Objects.equals(soundPath, "games.global.timer.round_end")
|| soundPath.startsWith("music.global.")) {
// The game ended or is about to end. Stop the music!!
MusicUtil.stopMusic();
}
}

SoundInstance instance;
// If our sound is music, play in the Core Music slider
if (soundLoc.getPath().contains("music.global")) {
if (soundPath.contains("music.global")) {
instance = MusicUtil.createSoundInstance(clientboundCustomSoundPacket, IslandSoundCategories.CORE_MUSIC); // Create the sound
Minecraft.getInstance().getSoundManager().play(instance); // Play the sound
ci.cancel(); // Stop minecraft from trying.
Expand Down Expand Up @@ -235,6 +254,7 @@ private void titleText(ClientboundSetSubtitleTextPacket clientboundSetSubtitleTe
LevelTimer instance = LevelTimer.getInstance();
if (instance == null) return;
instance.handleSubtitle(clientboundSetSubtitleTextPacket, ci);
if (IslandOptions.getSplits().isShowSumOfBest()) renderer.update();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ public Double getSplit(String level) {
return value / 1000d;
}

public Optional<Split> getRawSplit(String level) {
return Optional.ofNullable(splits.get(level));
}

public Optional<Split> getSplitNoColor(String level) {
List<String> allPossibleLevels = List.of(
String.format("green%s", level),
String.format("yellow%s", level),
String.format("red%s", level)
);
Optional<String> match = allPossibleLevels.stream().filter(s -> splits.containsKey(s)).findFirst();
return match.map(s -> splits.get(s));
}

public JsonObject toJson() {
JsonObject object = new JsonObject();
object.addProperty("name", name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ public class LevelTimer {
private final LevelSplits splits;
private Long lastSplitTimestamp = System.currentTimeMillis();

private String levelName = "M1-1";
private String levelUid = "";
// T - Transition from main to main
// TB - transition from main to bonus
// U - unfinished bonus level time
// R - return to main route
private String levelName = "T0-1";
private String levelUid = "T0-1";

private boolean isBetween = true; // If the player is inbetween levels;
public final SplitsCategory options = IslandOptions.getSplits();
Expand All @@ -53,11 +57,7 @@ public void handleSubtitle(ClientboundSetSubtitleTextPacket subtitle, CallbackIn
if (string.startsWith("[")) {
Matcher matcher = channelTitlePattern.matcher(string);
if (!matcher.find()) return;
// This title is sent 1.5s AFTER the level starts, so we need to compensate
lastSplitTimestamp = System.currentTimeMillis() - 1500;
levelName = matcher.group(1);
isBetween = false;

String nextLevelName = matcher.group(1);
StringBuilder hashString = new StringBuilder();
for (Component sibling : component.getSiblings()) {
TextColor color = sibling.getStyle().getColor();
Expand All @@ -66,6 +66,32 @@ public void handleSubtitle(ClientboundSetSubtitleTextPacket subtitle, CallbackIn
}
}
hashString.append(levelName);
if (levelName.startsWith("T")) {
if (nextLevelName.startsWith("B")) {
String newName;
String newUid;
if (nextLevelName.charAt(1) == '4') { // Finale check
newName = levelName;
String chosenFinale = hashString.toString().split("T")[0];
newUid = String.format("%sT3-4", chosenFinale);
} else { // Transition to bonus route
newName = String.format("TB%c-%c", levelName.charAt(1), levelName.charAt(3));
newUid = newName;
}
levelName = newName;
levelUid = newUid;
}
saveSplit();
}
if (levelName.startsWith("R")) {
if (nextLevelName.startsWith("B")) return; // Prevent race condition
saveSplit();
}
// This title is sent 1.5s AFTER the level starts, so we need to compensate
lastSplitTimestamp = System.currentTimeMillis() - 1500;
levelName = nextLevelName;
isBetween = false;

levelUid = hashString.toString();
ChatUtils.debug("Detected level with id: " + levelUid);
}
Expand Down Expand Up @@ -152,12 +178,12 @@ public static void onSound(ClientboundSoundPacket clientboundSoundPacket) {
ResourceLocation soundLoc = clientboundSoundPacket.getSound().value().getLocation();
String path = soundLoc.getPath();
boolean isRoundEnd = path.equals("games.global.timer.round_end");
LevelTimer currentInstance = getInstance();
if (path.contains("games.parkour_warrior.mode_swap") ||
path.contains("games.parkour_warrior.restart_course") ||
isRoundEnd ||
path.equals("ui.queue_teleport")) {
// Stop split
LevelTimer currentInstance = getInstance();
if (currentInstance != null && isRoundEnd) {
currentInstance.saveSplit();
}
Expand All @@ -170,6 +196,27 @@ public static void onSound(ClientboundSoundPacket clientboundSoundPacket) {
}
setInstance(new LevelTimer(splits));
ChatUtils.debug("LevelTimer - Started timer!");
} else if (path.equals("games.parkour_warrior.medal_gain")
&& currentInstance != null
&& currentInstance.levelName.endsWith("-3")) {
String newLevelName;
if (currentInstance.levelName.startsWith("M")) {
char curLevelName = currentInstance.levelName.charAt(1);
int curLevelInt = Integer.parseInt(String.valueOf(curLevelName));
newLevelName = String.format("T%d-%d", curLevelInt, curLevelInt + 1);
} else {
newLevelName = "R";
}
currentInstance.levelName = newLevelName;
currentInstance.levelUid = newLevelName;
} else if (path.equals("games.parkour_warrior.teleport_scroll")
&& currentInstance != null) {
currentInstance.levelName = "U";
currentInstance.levelUid = "U";
currentInstance.saveSplit();
currentInstance.levelName = "R";
currentInstance.levelUid = "R";
currentInstance.lastSplitTimestamp = System.currentTimeMillis();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.asodev.islandutils.modules.splits;

import net.asodev.islandutils.modules.splits.sob.AdvancedInfo;
import net.asodev.islandutils.modules.splits.sob.SobCalc;
import net.asodev.islandutils.state.Game;
import net.asodev.islandutils.state.MccIslandState;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.minecraft.network.chat.Component;

import java.util.Optional;

public class SplitCommands {
public SplitCommands() {
ClientCommandRegistrationCallback.EVENT.register(((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("showadvancedpath").executes(context -> {
if (MccIslandState.getGame() != Game.PARKOUR_WARRIOR_DOJO) {
context.getSource().sendFeedback(Component.literal("Not in PKWD"));
return 0;
}
LevelSplits splits = SplitManager.getCourseSplits(MccIslandState.getMap());
Optional<AdvancedInfo> advInfo = SobCalc.advancedTime(splits);
if (advInfo.isEmpty()) {
context.getSource().sendFeedback(Component.literal("Could not get advanced path"));
return 0;
}
context.getSource().sendFeedback(Component.literal(advInfo.get().path()));
return 1;
}))));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package net.asodev.islandutils.modules.splits.sob;

public record AdvancedInfo(Long time, String path) {
}
Loading