diff --git a/build.gradle b/build.gradle index 4682dd9..369ddc4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.7-SNAPSHOT' + id 'fabric-loom' version '1.8.10' id 'maven-publish' } @@ -26,6 +26,7 @@ repositories { maven { url = "https://maven.isxander.dev/snapshots" } maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url = uri("https://maven.noxcrew.com/public") } + maven { url = uri("https://maven.enginehub.org/repo/") } exclusiveContent { forRepository { maven { @@ -47,17 +48,15 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - modApi("dev.isxander:yet-another-config-lib:3.5.0+1.21-fabric") { + modApi("dev.isxander:yet-another-config-lib:3.6.2+1.21.2-fabric") { exclude(group: "com.twelvemonkeys.common") exclude(group: "com.twelvemonkeys.imageio") } - modApi("com.terraformersmc:modmenu:11.0.2") + modApi("com.terraformersmc:modmenu:12.0.0") implementation include('com.github.JnCrMx:discord-game-sdk4j:v0.5.5') - modApi("com.noxcrew.noxesium:fabric:2.3.2") { - exclude(group: "org.khelekore") - } + modApi("com.noxcrew.noxesium:fabric:2.4.1") } processResources { diff --git a/gradle.properties b/gradle.properties index cd0d95c..bb139bd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,13 +2,13 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.21.1 -yarn_mappings=1.21.1+build.3 -loader_version=0.16.5 +minecraft_version=1.21.3 +yarn_mappings=1.21.3+build.2 +loader_version=0.16.9 # Mod Properties -mod_version=1.6.10 +mod_version=1.7.0 maven_group=net.asodev archives_base_name=islandutils # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.105.0+1.21.1 +fabric_version=0.110.0+1.21.3 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0d18421..9355b41 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +82,12 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +134,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +217,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd3..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/src/main/java/net/asodev/islandutils/IslandUtilsClient.java b/src/main/java/net/asodev/islandutils/IslandUtilsClient.java index 50d2cd7..f94573b 100644 --- a/src/main/java/net/asodev/islandutils/IslandUtilsClient.java +++ b/src/main/java/net/asodev/islandutils/IslandUtilsClient.java @@ -1,10 +1,10 @@ package net.asodev.islandutils; import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.asodev.islandutils.discord.DiscordPresenceUpdator; import net.asodev.islandutils.modules.DisguiseKeybind; import net.asodev.islandutils.modules.NoxesiumIntegration; +import net.asodev.islandutils.modules.music.MusicManager; import net.asodev.islandutils.modules.plobby.PlobbyFeatures; import net.asodev.islandutils.modules.plobby.PlobbyJoinCodeCopy; import net.asodev.islandutils.modules.splits.SplitManager; @@ -13,7 +13,6 @@ import net.asodev.islandutils.state.MccIslandState; import net.asodev.islandutils.util.ChatUtils; import net.asodev.islandutils.util.IslandUtilsCommand; -import net.asodev.islandutils.util.MusicUtil; import net.asodev.islandutils.util.Utils; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; @@ -55,6 +54,7 @@ public void onInitializeClient() { SplitUI.setupFallbackRenderer(); } new NoxesiumIntegration().init(); + MusicManager.init(); } public static void onJoinMCCI(boolean isProduction) { @@ -75,11 +75,4 @@ public static void onJoinMCCI(boolean isProduction) { MccIslandState.setGame(Game.HUB); IslandUtilsEvents.JOIN_MCCI.invoker().onEvent(); } - - public static class Commands { - public static LiteralArgumentBuilder resetMusic = net.minecraft.commands.Commands.literal("resetmusic").executes(ctx -> { - MusicUtil.resetMusic(ctx); - return 1; - }); - } } diff --git a/src/main/java/net/asodev/islandutils/discord/DiscordPresenceUpdator.java b/src/main/java/net/asodev/islandutils/discord/DiscordPresenceUpdator.java index 89d8784..780587c 100644 --- a/src/main/java/net/asodev/islandutils/discord/DiscordPresenceUpdator.java +++ b/src/main/java/net/asodev/islandutils/discord/DiscordPresenceUpdator.java @@ -24,7 +24,7 @@ public class DiscordPresenceUpdator { // dear contributors: // i am sorry. - @Nullable static Activity activity; + @Nullable public static Activity activity; public static UUID timeLeftBossbar = null; public static Instant started; private static boolean bigRatMode = false; @@ -84,8 +84,12 @@ public static void updatePlace(Game game) { activity.assets().setLargeImage(game.name().toLowerCase()); activity.assets().setLargeText(game.getName()); activity.assets().setSmallImage("mcci"); - - if (game != Game.HUB) + + if (game == Game.FISHING) { + FishingPresenceUpdator.updateFishingPlace(); + REMAIN_STATE = null; + ROUND_STATE = null; + } else if (game != Game.HUB) activity.setDetails(I18n.get("islandutils.discordPresence.details.playing", game.getName())); else { activity.setDetails(I18n.get("islandutils.discordPresence.details.inHub")); @@ -184,6 +188,8 @@ public static void updateActivity() { Core core = DiscordPresence.core; if (core == null || !core.isOpen()) return; + activity.timestamps().setStart(started); + if (bigRatMode) { overrideActivityWithBigRat(); } diff --git a/src/main/java/net/asodev/islandutils/discord/FishingPresenceUpdator.java b/src/main/java/net/asodev/islandutils/discord/FishingPresenceUpdator.java new file mode 100644 index 0000000..6eb4c25 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/discord/FishingPresenceUpdator.java @@ -0,0 +1,54 @@ +package net.asodev.islandutils.discord; + +import net.asodev.islandutils.IslandUtilsEvents; +import net.asodev.islandutils.state.Game; +import net.asodev.islandutils.state.MccIslandState; + +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static net.asodev.islandutils.discord.DiscordPresenceUpdator.activity; + +public class FishingPresenceUpdator { + public static List temperatures = List.of("temperate", "tropical", "barren"); + public static Map islandNames = new HashMap<>(); + + static { + islandNames.put("temperate_1", "Verdant Woods"); + islandNames.put("temperate_2", "Floral Forest"); + islandNames.put("temperate_3", "Dark Grove"); + islandNames.put("temperate_grotto", "Sunken Swamp"); + + islandNames.put("tropical_1", "Tropical Overgrowth"); + islandNames.put("tropical_2", "Coral Shores"); + islandNames.put("tropical_3", "Twisted Swamp"); + islandNames.put("tropical_grotto", "Mirrored Oasis"); + + islandNames.put("barren_1", "Ancient Sands"); + islandNames.put("barren_2", "Blazing Canyon"); + islandNames.put("barren_3", "Ashen Wastes"); + islandNames.put("barren_grotto", "Volcanic Springs"); + } + + public static void init() { + } + + public static void updateFishingPlace() { + if (activity == null) return; + + String place = islandNames.get(MccIslandState.getSubType()); + if (place != null) { + activity.setDetails("In the " + place); + activity.assets().setLargeImage(MccIslandState.getSubType().toLowerCase()); + activity.assets().setLargeText(place); + + activity.assets().setSmallImage("fishing"); + activity.assets().setSmallText("Fishing"); + } else { + activity.assets().setLargeImage("fishing"); + activity.assets().setLargeText("Fishing"); + } + } +} diff --git a/src/main/java/net/asodev/islandutils/mixins/FixOffhandSwapMixin.java b/src/main/java/net/asodev/islandutils/mixins/FixOffhandSwapMixin.java deleted file mode 100644 index 07cfd23..0000000 --- a/src/main/java/net/asodev/islandutils/mixins/FixOffhandSwapMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.asodev.islandutils.mixins; - -import net.asodev.islandutils.state.MccIslandState; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResultHolder; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ArmorItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -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.CallbackInfoReturnable; - -@Mixin(ArmorItem.class) -public abstract class FixOffhandSwapMixin { - @Shadow - public abstract EquipmentSlot getEquipmentSlot(); - - @Inject(method = "use", at = @At(value = "HEAD"), cancellable = true) - private void use(Level level, Player player, InteractionHand interactionHand, CallbackInfoReturnable> ci) { - if (!MccIslandState.isOnline()) return; - if (getEquipmentSlot().getType() != EquipmentSlot.Type.HUMANOID_ARMOR) { - ItemStack itemStack = player.getItemInHand(interactionHand); - ci.setReturnValue(InteractionResultHolder.pass(itemStack)); - } - } - -} diff --git a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ChestScreenMixin.java b/src/main/java/net/asodev/islandutils/mixins/cosmetics/ChestScreenMixin.java index ff8ac1b..8e344cf 100644 --- a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ChestScreenMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/cosmetics/ChestScreenMixin.java @@ -7,12 +7,15 @@ import net.asodev.islandutils.modules.cosmetics.CosmeticType; import net.asodev.islandutils.options.IslandOptions; import net.asodev.islandutils.state.MccIslandState; +import net.asodev.islandutils.util.IslandSoundEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; @@ -37,14 +40,12 @@ @Mixin(AbstractContainerScreen.class) public abstract class ChestScreenMixin extends Screen { - private static final ResourceLocation PREVIEW = ResourceLocation.fromNamespaceAndPath("island", "textures/preview.png"); + @Unique private static final ResourceLocation PREVIEW = ResourceLocation.fromNamespaceAndPath("island", "preview"); @Shadow protected Slot hoveredSlot; @Shadow @Final protected AbstractContainerMenu menu; - @Shadow protected abstract List getTooltipFromContainerItem(ItemStack itemStack); - protected ChestScreenMixin(Component component) { super(component); } @@ -65,11 +66,12 @@ private void renderSlot(GuiGraphics guiGraphics, Slot slot, CallbackInfo ci) { if (CosmeticState.hatSlot.preview != null && CosmeticState.hatSlot.preview.matchesSlot(slot)) shouldRender = true; else if (CosmeticState.accessorySlot.preview != null && CosmeticState.accessorySlot.preview.matchesSlot(slot)) shouldRender = true; + else if (CosmeticState.mainHandSlot.preview != null && CosmeticState.mainHandSlot.preview.matchesSlot(slot)) shouldRender = true; guiGraphics.pose().pushPose(); if (shouldRender) { guiGraphics.pose().translate(0.0f, 0.0f, 105f); - guiGraphics.blit(PREVIEW, slot.x-3, slot.y-4, 105, 0, 0, 22, 24, 22, 24); + guiGraphics.blitSprite(RenderType::guiTextured, PREVIEW, slot.x-3, slot.y-4, 22, 24); } guiGraphics.pose().popPose(); } @@ -79,9 +81,10 @@ private void render(GuiGraphics guiGraphics, int i, int j, float f, CallbackInfo if (hoveredSlot != null && hoveredSlot.hasItem()) { ItemStack hoveredItem = hoveredSlot.getItem(); if (IslandOptions.getCosmetics().isShowOnHover()) { - CosmeticType changedType = setHovered(hoveredItem); - if (changedType != CosmeticType.HAT) CosmeticState.hatSlot.hover = null; - if (changedType != CosmeticType.ACCESSORY) CosmeticState.accessorySlot.hover = null; + CosmeticType newType = setHovered(hoveredItem); + if (newType != CosmeticType.HAT) CosmeticState.hatSlot.hover = null; + if (newType != CosmeticType.ACCESSORY) CosmeticState.accessorySlot.hover = null; + if (newType != CosmeticType.MAIN_HAND) CosmeticState.mainHandSlot.hover = null; } if (CosmeticState.isColoredItem(hoveredItem)) { @@ -94,6 +97,7 @@ private void render(GuiGraphics guiGraphics, int i, int j, float f, CallbackInfo } else { CosmeticState.hatSlot.hover = null; CosmeticState.accessorySlot.hover = null; + CosmeticState.mainHandSlot.hover = null; } CosmeticState.hoveredColor = null; } @@ -158,6 +162,7 @@ private void setPreview(ItemStack item) { int hoverCMD = customModelData(item); if (type == CosmeticType.HAT) setOrNotSet(CosmeticState.hatSlot, hoverCMD); else if (type == CosmeticType.ACCESSORY) setOrNotSet(CosmeticState.accessorySlot, hoverCMD); + else if (type == CosmeticType.MAIN_HAND) setOrNotSet(CosmeticState.mainHandSlot, hoverCMD); } @Unique @@ -166,12 +171,14 @@ private void setOrNotSet(Cosmetic cosmetic, int itemCMD) { cosmetic.preview = new CosmeticSlot(hoveredSlot); else cosmetic.preview = null; + this.minecraft.getSoundManager().play(SimpleSoundInstance.forUI(IslandSoundEvents.UI_CLICK_NORMAL, 1f, 1f)); } @Inject(method = "onClose", at = @At("TAIL")) private void onClose(CallbackInfo ci) { CosmeticState.hatSlot = new Cosmetic(CosmeticType.HAT); CosmeticState.accessorySlot = new Cosmetic(CosmeticType.ACCESSORY); + CosmeticState.mainHandSlot = new Cosmetic(CosmeticType.MAIN_HAND); CosmeticState.inspectingPlayer = null; diff --git a/src/main/java/net/asodev/islandutils/mixins/cosmetics/PreviewTutorialMixin.java b/src/main/java/net/asodev/islandutils/mixins/cosmetics/PreviewTutorialMixin.java index e3e48c0..7651972 100644 --- a/src/main/java/net/asodev/islandutils/mixins/cosmetics/PreviewTutorialMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/cosmetics/PreviewTutorialMixin.java @@ -40,7 +40,7 @@ public class PreviewTutorialMixin { at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;addAttributeTooltips(Ljava/util/function/Consumer;Lnet/minecraft/world/entity/player/Player;)V", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILEXCEPTION ) - private void injectedTooltipLines(Item.TooltipContext tooltipContext, @Nullable Player player, TooltipFlag tooltipFlag, CallbackInfoReturnable> cir, List list, MutableComponent mutableComponent, Consumer consumer) { + private void injectedTooltipLines(Item.TooltipContext tooltipContext, @Nullable Player player, TooltipFlag tooltipFlag, CallbackInfoReturnable> cir, List list, Consumer consumer) { if (CosmeticState.getType((ItemStack)(Object)this) == null) return; if (!IslandOptions.getCosmetics().isShowPlayerPreview()) return; list.add(previewComponent); diff --git a/src/main/java/net/asodev/islandutils/mixins/cosmetics/UIMixin.java b/src/main/java/net/asodev/islandutils/mixins/cosmetics/UIMixin.java index dd8db40..b23df65 100644 --- a/src/main/java/net/asodev/islandutils/mixins/cosmetics/UIMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/cosmetics/UIMixin.java @@ -11,6 +11,7 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.ContainerScreen; import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.ChestMenu; @@ -44,26 +45,34 @@ public void renderBg(GuiGraphics guiGraphics, float f, int i, int j, CallbackInf if (player == null) return; if (localPlayer == null) return; + ItemStack defaultMainSlot = null; ItemStack defaultHatSlot = null; ItemStack defaultAccSlot = null; ItemStack hatSlot; ItemStack accSlot; + + Inventory playerInventory = player.getInventory(); if (CosmeticState.inspectingPlayer == null || CosmeticState.inspectingPlayer.getUUID() == Minecraft.getInstance().player.getUUID()) { hatSlot = CosmeticState.hatSlot.getContents().getItem(this.menu); accSlot = CosmeticState.accessorySlot.getContents().getItem(this.menu); + ItemStack mainSlot = CosmeticState.mainHandSlot.getContents().getItem(this.menu); if (isCosmeticMenu) { applyColor(hatSlot); applyColor(accSlot); - defaultHatSlot = player.getInventory().armor.get(3); - defaultAccSlot = player.getInventory().offhand.get(0); - player.getInventory().armor.set(3, hatSlot); - player.getInventory().offhand.set(0, accSlot); + defaultHatSlot = playerInventory.armor.get(3); + playerInventory.armor.set(3, hatSlot); + + defaultAccSlot = playerInventory.offhand.getFirst(); + playerInventory.offhand.set(0, accSlot); + + defaultMainSlot = player.getMainHandItem(); + player.setItemSlot(EquipmentSlot.MAINHAND, mainSlot); } } else { - hatSlot = player.getInventory().armor.get(3); - accSlot = player.getInventory().offhand.get(0); + hatSlot = playerInventory.armor.get(3); + accSlot = playerInventory.offhand.getFirst(); } WalkAnimStateAccessor walkAnim = (WalkAnimStateAccessor) player.walkAnimation; @@ -92,8 +101,9 @@ public void renderBg(GuiGraphics guiGraphics, float f, int i, int j, CallbackInf walkAnim.setSpeed(animSpeed); walkAnim.setSpeedOld(animSpeedOld); player.attackAnim = attackAnim; - if (defaultHatSlot != null) player.getInventory().armor.set(3, defaultHatSlot); - if (defaultAccSlot != null) player.getInventory().offhand.set(0, defaultAccSlot); + if (defaultHatSlot != null) playerInventory.armor.set(3, defaultHatSlot); + if (defaultAccSlot != null) playerInventory.offhand.set(0, defaultAccSlot); + if (defaultMainSlot != null) player.setItemSlot(EquipmentSlot.MAINHAND, defaultMainSlot); // this code is so ugly omfg int itemPos = x+(size / 2) - 18; diff --git a/src/main/java/net/asodev/islandutils/mixins/crafting/RemnantHighlightMixin.java b/src/main/java/net/asodev/islandutils/mixins/crafting/RemnantHighlightMixin.java index 5b17729..6c6dbe1 100644 --- a/src/main/java/net/asodev/islandutils/mixins/crafting/RemnantHighlightMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/crafting/RemnantHighlightMixin.java @@ -6,7 +6,6 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.RenderType; import net.minecraft.network.chat.Component; -import net.minecraft.util.FastColor; import net.minecraft.world.inventory.Slot; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -30,10 +29,9 @@ private void renderSlot(GuiGraphics guiGraphics, Slot slot, CallbackInfo ci) { int x = slot.x; int y = slot.y; - int color = FastColor.ARGB32.color(255, 141, 65, 100); guiGraphics.pose().pushPose(); guiGraphics.pose().translate(0.0f, 0.0f, 105.0f); - guiGraphics.fill(RenderType.gui(), x, y, x + 16, y + 16, 0, color); + guiGraphics.fill(RenderType.gui(), x, y, x + 16, y + 16, 0, 9257316); guiGraphics.pose().popPose(); } diff --git a/src/main/java/net/asodev/islandutils/mixins/discord/JoinMCCIMixin.java b/src/main/java/net/asodev/islandutils/mixins/discord/JoinMCCIMixin.java index 849bcd4..d647817 100644 --- a/src/main/java/net/asodev/islandutils/mixins/discord/JoinMCCIMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/discord/JoinMCCIMixin.java @@ -2,7 +2,7 @@ import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl; import net.minecraft.client.multiplayer.ServerData; -import net.minecraft.network.protocol.login.ClientboundGameProfilePacket; +import net.minecraft.network.protocol.login.ClientboundLoginFinishedPacket; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -16,11 +16,10 @@ @Mixin(ClientHandshakePacketListenerImpl.class) public class JoinMCCIMixin { - @Shadow @Final private @Nullable ServerData serverData; - @Inject(method = "handleGameProfile", at = @At("HEAD")) - private void handleGameProfile(ClientboundGameProfilePacket clientboundGameProfilePacket, CallbackInfo ci) { + @Inject(method = "handleLoginFinished", at = @At("HEAD")) + private void handleGameProfile(ClientboundLoginFinishedPacket clientboundLoginFinishedPacket, CallbackInfo ci) { if (this.serverData == null) return; if (!this.serverData.ip.toLowerCase().contains("mccisland")) return; diff --git a/src/main/java/net/asodev/islandutils/mixins/discord/PlayerTeamMixin.java b/src/main/java/net/asodev/islandutils/mixins/discord/PlayerTeamMixin.java deleted file mode 100644 index b67de73..0000000 --- a/src/main/java/net/asodev/islandutils/mixins/discord/PlayerTeamMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.asodev.islandutils.mixins.discord; - -import net.asodev.islandutils.discord.DiscordPresenceUpdator; -import net.minecraft.network.chat.Component; -import net.minecraft.world.scores.PlayerTeam; -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 java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@Mixin(PlayerTeam.class) -public class PlayerTeamMixin { - - // This isn't called in the PacketListenerMixin because for some reason, sometimes things aren't sent with that packet - // When things are sent all at once, they aren't caught by the packet. - @Inject(method = "setPlayerPrefix", at = @At("TAIL")) - public void addPlayerTeam(Component component, CallbackInfo ci) { - String playerPrefix = component.getString().toUpperCase(); - - final Map scoreboardPatterns = Map.of( - "REMAIN", Pattern.compile("PLAYERS REMAINING: (?([0-9]*/[0-9]*))"), - "ROUND", Pattern.compile("ROUND \\[(?([1-9]*/[1-9]*))]") - ); - - for (Map.Entry entry : scoreboardPatterns.entrySet()) { - Matcher matcher = entry.getValue().matcher(playerPrefix); - if (!matcher.find()) continue; - String value = matcher.group(1); - - switch (entry.getKey()) { - case "REMAIN" -> DiscordPresenceUpdator.remainScoreboardUpdate(value, true); - case "ROUND" -> DiscordPresenceUpdator.roundScoreboardUpdate(value, true); - } - } - } - -} diff --git a/src/main/java/net/asodev/islandutils/mixins/discord/ScoreDisplayMixin.java b/src/main/java/net/asodev/islandutils/mixins/discord/ScoreDisplayMixin.java new file mode 100644 index 0000000..4c8552d --- /dev/null +++ b/src/main/java/net/asodev/islandutils/mixins/discord/ScoreDisplayMixin.java @@ -0,0 +1,52 @@ +package net.asodev.islandutils.mixins.discord; + +import net.asodev.islandutils.discord.DiscordPresenceUpdator; +import net.asodev.islandutils.state.MccIslandState; +import net.minecraft.network.chat.Component; +import net.minecraft.world.scores.Score; +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 java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Mixin(Score.class) +public class ScoreDisplayMixin { + + @Inject(method = "display(Lnet/minecraft/network/chat/Component;)V", at = @At("TAIL")) + public void setScoreDisplay(Component component, CallbackInfo ci) { + String playerPrefix = component.getString(); + + final Map scoreboardPatterns = Map.of( + "REMAIN", Pattern.compile("PLAYERS REMAINING: (?([0-9]*/[0-9]*))"), + "ROUND", Pattern.compile("ROUNDS \\[(?([1-9]*/[1-9]*))]"), + "MAP", Pattern.compile("MAP: (?\\w+(?:,? \\w+)*)"), + "MODIFIER", Pattern.compile("MODIFIER: (?\\w+(?:,? \\w+)*)"), + "COURSE", Pattern.compile("COURSE: (?.*)"), + "LEAP", Pattern.compile("LEAP \\[(?.*/.*)]") + + ); + + for (Map.Entry entry : scoreboardPatterns.entrySet()) { + Matcher matcher = entry.getValue().matcher(playerPrefix); + if (!matcher.find()) continue; + String value = matcher.group(1); + + switch (entry.getKey()) { + case "REMAIN" -> DiscordPresenceUpdator.remainScoreboardUpdate(value, true); + case "ROUND" -> DiscordPresenceUpdator.roundScoreboardUpdate(value, true); + case "MAP" -> MccIslandState.setMap(value.toUpperCase()); // Set our MAP + case "MODIFIER" -> MccIslandState.setModifier(value.toUpperCase()); // Set our MODIFIER + case "COURSE" -> { + DiscordPresenceUpdator.courseScoreboardUpdate(value, true); + MccIslandState.setMap(value); + } + case "LEAP" -> DiscordPresenceUpdator.leapScoreboardUpdate(value, true); + } + } + } + +} diff --git a/src/main/java/net/asodev/islandutils/mixins/network/PacketListenerMixin.java b/src/main/java/net/asodev/islandutils/mixins/network/PacketListenerMixin.java index 405d544..43deab1 100644 --- a/src/main/java/net/asodev/islandutils/mixins/network/PacketListenerMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/network/PacketListenerMixin.java @@ -1,7 +1,6 @@ package net.asodev.islandutils.mixins.network; import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.asodev.islandutils.IslandUtilsClient; import net.asodev.islandutils.IslandUtilsEvents; @@ -10,39 +9,34 @@ import net.asodev.islandutils.modules.FriendsInGame; import net.asodev.islandutils.modules.cosmetics.CosmeticSlot; import net.asodev.islandutils.modules.cosmetics.CosmeticState; +import net.asodev.islandutils.modules.music.MusicManager; import net.asodev.islandutils.modules.splits.LevelTimer; import net.asodev.islandutils.options.IslandOptions; -import net.asodev.islandutils.options.IslandSoundCategories; import net.asodev.islandutils.state.Game; import net.asodev.islandutils.state.MccIslandState; import net.asodev.islandutils.util.ChatUtils; -import net.asodev.islandutils.util.MusicUtil; +import net.asodev.islandutils.util.IslandSoundEvents; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl; -import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.CommonListenerCookie; -import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.Connection; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; -import net.minecraft.network.protocol.PacketUtils; import net.minecraft.network.protocol.game.ClientboundBossEventPacket; import net.minecraft.network.protocol.game.ClientboundCommandSuggestionsPacket; -import net.minecraft.network.protocol.game.ClientboundCommandsPacket; import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; -import net.minecraft.network.protocol.game.ClientboundRespawnPacket; import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.network.protocol.game.ClientboundStopSoundPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; -import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -52,7 +46,6 @@ import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.regex.Matcher; @@ -72,97 +65,30 @@ protected PacketListenerMixin(Minecraft minecraft, Connection connection, Common super(minecraft, connection, commonListenerCookie); } - // Patterns for the Map & Modifier options on scoreboard - final Map scoreboardPatterns = Map.of( - "MAP", Pattern.compile("MAP: (?\\w+(?:,? \\w+)*)"), - "MODIFIER", Pattern.compile("MODIFIER: (?\\w+(?:,? \\w+)*)"), - "COURSE", Pattern.compile("COURSE: (?.*)"), - "LEAP", Pattern.compile("LEAP \\[(?.*/.*)]") - ); - @Inject(method = "handleSetPlayerTeamPacket", at = @At("TAIL")) // Scoreboard lines! - public void handleSetPlayerTeamPacket(ClientboundSetPlayerTeamPacket clientboundSetPlayerTeamPacket, CallbackInfo ci) { - if (!MccIslandState.isOnline()) return; - Optional optional = clientboundSetPlayerTeamPacket.getParameters(); - if (optional.isEmpty()) return; - - ClientboundSetPlayerTeamPacket.Parameters parameters = optional.get(); // Get the team parameters - try { // We do a little exceptioning - Component prefixComponent = parameters.getPlayerPrefix(); // Get the prefix of this team - String playerPrefix = prefixComponent.getString(); // Turn it uppercase - - for (Map.Entry entry : scoreboardPatterns.entrySet()) { // Loop over our scoreboard reg-exes - Matcher matcher = entry.getValue().matcher(playerPrefix); // Match the prefix against the regex - if (!matcher.find()) continue; // If we don't have a subsequence, then go to the next - String value = matcher.group(1); // WE HAVE A MATCH, Get the first Regex group - - switch (entry.getKey()) { - case "MAP" -> MccIslandState.setMap(value); // Set our MAP - case "MODIFIER" -> MccIslandState.setModifier(value); // Set our MODIFIER - case "COURSE" -> { - DiscordPresenceUpdator.courseScoreboardUpdate(value, true); - MccIslandState.setMap(value); - } - case "LEAP" -> DiscordPresenceUpdator.leapScoreboardUpdate(value, true); - } - - ChatUtils.debug("ScoreboardUpdate - Current %s: \"%s\"", entry.getKey(), value); - } - } catch (Exception ignored) {} - } - - @Inject(method = "handleSoundEvent", at = @At("HEAD"), cancellable = true) + @Inject(method = "handleSoundEvent", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/PacketUtils;ensureRunningOnSameThread(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketListener;Lnet/minecraft/util/thread/BlockableEventLoop;)V", shift = At.Shift.AFTER), cancellable = true) public void handleCustomSoundEvent(ClientboundSoundPacket clientboundCustomSoundPacket, CallbackInfo ci) { - PacketUtils.ensureRunningOnSameThread(clientboundCustomSoundPacket, (ClientPacketListener) (Object) this, this.minecraft); if (!MccIslandState.isOnline()) return; - // Get the location of the new sound - // Previously this was obfuscated by noxcrew, but not anymore yayyyyy :D - ResourceLocation soundLoc = clientboundCustomSoundPacket.getSound().value().getLocation(); + ResourceLocation soundLoc = clientboundCustomSoundPacket.getSound().value().location(); + if (!soundLoc.getNamespace().equals("mcc")) return; - if (MccIslandState.getGame() == Game.PARKOUR_WARRIOR_DOJO) { - LevelTimer.onSound(clientboundCustomSoundPacket); + if (soundLoc.getPath().startsWith("music.")) { + ChatUtils.debug("Starting music " + soundLoc); + MusicManager.onMusicSoundPacket(clientboundCustomSoundPacket, this.minecraft); + ci.cancel(); } + } - // If we aren't in a game, don't play music - if (MccIslandState.getGame() != Game.HUB) { - // Use the sound files above to determine what just happened in the game - 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")) { - MusicUtil.stopMusic(false); - } - if (MccIslandState.getGame() == Game.PARKOUR_WARRIOR_SURVIVOR && Objects.equals(soundLoc.getPath(), "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()) { - 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")) { - 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.")) { - // The game ended or is about to end. Stop the music!! - MusicUtil.stopMusic(); - } - } + @Inject(method = "handleStopSoundEvent", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/PacketUtils;ensureRunningOnSameThread(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketListener;Lnet/minecraft/util/thread/BlockableEventLoop;)V", shift = At.Shift.AFTER), cancellable = true) + public void handleStopSoundEvent(ClientboundStopSoundPacket clientboundStopSoundPacket, CallbackInfo ci) { + if (!MccIslandState.isOnline()) return; + ResourceLocation soundLoc = clientboundStopSoundPacket.getName(); + if (soundLoc == null || !soundLoc.getNamespace().equals("mcc")) return; - SoundInstance instance; - // If our sound is music, play in the Core Music slider - if (soundLoc.getPath().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. - } else if (soundLoc.getNamespace().equals("mcc")) { // If it's a MCC sound, we'll just play it in sound effects. - instance = MusicUtil.createSoundInstance(clientboundCustomSoundPacket, IslandSoundCategories.SOUND_EFFECTS); // Make the sound - Minecraft.getInstance().getSoundManager().play(instance); // Play the sound - ci.cancel(); // Minecraft no + if (soundLoc.getPath().startsWith("music.")) { + ChatUtils.debug("Stopping music " + soundLoc); + MusicManager.onMusicStopPacket(clientboundStopSoundPacket, this.minecraft); + ci.cancel(); } } @@ -177,17 +103,6 @@ private void containerContent(ClientboundContainerSetContentPacket clientboundCo CosmeticState.accessorySlot.setOriginal(new CosmeticSlot(player.getInventory().offhand.get(0))); } - @Inject(method = "handleRespawn", at = @At("HEAD")) // Whenever we change worlds - private void handleRespawn(ClientboundRespawnPacket clientboundRespawnPacket, CallbackInfo ci) { - ClientLevel clientLevel = this.minecraft.level; // Get our player - if (clientLevel == null) return; // minecraft is a good game. - - ResourceKey resourceKey = clientboundRespawnPacket.commonPlayerSpawnInfo().dimension(); // Get the key of this world - if (resourceKey != clientLevel.dimension()) { // If we have changed worlds... - MusicUtil.stopMusic(); // ...stop the music - } - } - private static Pattern timerPattern = Pattern.compile("(\\d+:\\d+)"); @Inject(method = "handleBossUpdate", at = @At("HEAD")) // Discord presence, time left private void handleBossUpdate(ClientboundBossEventPacket clientboundBossEventPacket, CallbackInfo ci) { @@ -257,8 +172,7 @@ private void gameOver(ClientboundSetTitleTextPacket clientboundSetTitleTextPacke String title = clientboundSetTitleTextPacket.text().getString().toUpperCase(); // Get the title in upper case if (title.contains("GAME OVER")) { // If we got game over title, play sound - ResourceLocation sound = ResourceLocation.fromNamespaceAndPath("island", "announcer.gameover"); - Minecraft.getInstance().getSoundManager().play(MusicUtil.createSoundInstance(sound)); // Play the sound!! + Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(IslandSoundEvents.ANNOUNCER_GAME_OVER, 1f)); // Play the sound!! } } @@ -276,33 +190,4 @@ private void onChat(ClientboundSystemChatPacket clientboundSystemChatPacket, Cal }); } - // MCCI Commands - @Inject(method = "handleCommands", at = @At("TAIL")) - private void handleCommands(ClientboundCommandsPacket clientboundCommandsPacket, CallbackInfo ci) { - if (!MccIslandState.isOnline()) return; - this.commands.register((LiteralArgumentBuilder)IslandUtilsClient.Commands.resetMusic); - } - - @Inject(method = "sendUnsignedCommand", at = @At("HEAD"), cancellable = true) - private void sendUnsignedCommand(String string, CallbackInfoReturnable cir) { - if (!MccIslandState.isOnline()) return; - if (string.startsWith("resetmusic")) { - executeCommand(); - cir.setReturnValue(true); - } - } - @Inject(method = "sendCommand", at = @At("HEAD"), cancellable = true) - private void sendCommand(String string, CallbackInfo ci) { - if (!MccIslandState.isOnline()) return; - if (string.startsWith("resetmusic")) { - executeCommand(); - ci.cancel(); - } - } - - private static void executeCommand() { - try { IslandUtilsClient.Commands.resetMusic.getCommand().run(null); } - catch (CommandSyntaxException e) { e.printStackTrace(); } - } - } diff --git a/src/main/java/net/asodev/islandutils/mixins/notif/ServerSelectionMixin.java b/src/main/java/net/asodev/islandutils/mixins/notif/ServerSelectionMixin.java index 04974b0..119f014 100644 --- a/src/main/java/net/asodev/islandutils/mixins/notif/ServerSelectionMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/notif/ServerSelectionMixin.java @@ -6,6 +6,7 @@ import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; import net.minecraft.client.gui.screens.multiplayer.ServerSelectionList; import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.client.renderer.RenderType; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; @@ -52,7 +53,7 @@ private void render(GuiGraphics guiGraphics, int index, int y, int x, int ew, in guiGraphics.renderTooltip(Minecraft.getInstance().font, tooltip, Optional.empty(), mouseX, mouseY); } - guiGraphics.blit(NOTIF_TEXTURE, nx, ny, 0, 0, 10, 10, 10, 10); + guiGraphics.blit(RenderType::guiTextured, NOTIF_TEXTURE, nx, ny, 0, 0, 10, 10, 10, 10); } } diff --git a/src/main/java/net/asodev/islandutils/mixins/sounds/SoundOptionsMixin.java b/src/main/java/net/asodev/islandutils/mixins/sounds/SoundOptionsMixin.java deleted file mode 100644 index dd0cb69..0000000 --- a/src/main/java/net/asodev/islandutils/mixins/sounds/SoundOptionsMixin.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.asodev.islandutils.mixins.sounds; - -import net.asodev.islandutils.options.IslandSoundCategories; -import net.asodev.islandutils.state.MccIslandState; -import net.minecraft.client.gui.screens.options.SoundOptionsScreen; -import net.minecraft.sounds.SoundSource; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(SoundOptionsScreen.class) -public class SoundOptionsMixin { - - @Redirect(method = "getAllSoundOptionsExceptMaster", - at = @At(value = "INVOKE", target = "Lnet/minecraft/sounds/SoundSource;values()[Lnet/minecraft/sounds/SoundSource;")) - private SoundSource[] values() { - if (!MccIslandState.isOnline()) { - return IslandSoundCategories.before; - } - return SoundSource.values(); - } - -} diff --git a/src/main/java/net/asodev/islandutils/mixins/sounds/SoundSourceMixin.java b/src/main/java/net/asodev/islandutils/mixins/sounds/SoundSourceMixin.java deleted file mode 100644 index 2820842..0000000 --- a/src/main/java/net/asodev/islandutils/mixins/sounds/SoundSourceMixin.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.asodev.islandutils.mixins.sounds; - -import net.asodev.islandutils.options.IslandSoundCategories; -import net.minecraft.sounds.SoundSource; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.gen.Invoker; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -@Mixin(SoundSource.class) -public class SoundSourceMixin { - - @Invoker("") - private static SoundSource newSoundCategory(String internalName, int internalId, String name) - { - throw new AssertionError(); - } - - @Shadow - @Final - @Mutable - private static SoundSource[] $VALUES; - - @Inject(method = "", at = @At(value = "FIELD", - opcode = Opcodes.PUTSTATIC, - target = "Lnet/minecraft/sounds/SoundSource;$VALUES:[Lnet/minecraft/sounds/SoundSource;", - shift = At.Shift.AFTER)) - private static void addCustomVariants(CallbackInfo ci) - { - IslandSoundCategories.before = $VALUES; - ArrayList categories = new ArrayList<>(Arrays.asList($VALUES)); - - IslandSoundCategories.GAME_MUSIC = addVariant(categories, "GAME_MUSIC"); - IslandSoundCategories.CORE_MUSIC = addVariant(categories, "CORE_MUSIC"); - IslandSoundCategories.SOUND_EFFECTS = addVariant(categories, "SOUND_EFFECTS"); - - $VALUES = categories.toArray(new SoundSource[0]); - } - - private static SoundSource addVariant(ArrayList categories, String name) - { - SoundSource cat = newSoundCategory(name.toUpperCase(Locale.ROOT), - categories.get(categories.size() - 1).ordinal() + 1, - name.toLowerCase(Locale.ROOT)); - categories.add(cat); - return cat; - } - -} diff --git a/src/main/java/net/asodev/islandutils/mixins/ui/FishingUpgradeHighlightMixin.java b/src/main/java/net/asodev/islandutils/mixins/ui/FishingUpgradeHighlightMixin.java new file mode 100644 index 0000000..82dac22 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/mixins/ui/FishingUpgradeHighlightMixin.java @@ -0,0 +1,29 @@ +package net.asodev.islandutils.mixins.ui; + +import net.asodev.islandutils.modules.FishingUpgradeIcon; +import net.asodev.islandutils.options.IslandOptions; +import net.asodev.islandutils.state.Game; +import net.asodev.islandutils.state.MccIslandState; +import net.asodev.islandutils.util.Utils; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.Slot; +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 java.util.List; + +@Mixin(AbstractContainerScreen.class) +public class FishingUpgradeHighlightMixin { + @Inject(method = "renderSlot", at = @At(value = "TAIL")) + private void renderSlot(GuiGraphics guiGraphics, Slot slot, CallbackInfo ci) { + if (!slot.hasItem() || !IslandOptions.getMisc().isShowFishingUpgradeIcon()) return; + if (MccIslandState.getGame() != Game.FISHING) return; + FishingUpgradeIcon.render(slot, guiGraphics); + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/ClassicAnnouncer.java b/src/main/java/net/asodev/islandutils/modules/ClassicAnnouncer.java index 82bb907..df48171 100644 --- a/src/main/java/net/asodev/islandutils/modules/ClassicAnnouncer.java +++ b/src/main/java/net/asodev/islandutils/modules/ClassicAnnouncer.java @@ -2,13 +2,15 @@ import net.asodev.islandutils.options.IslandOptions; import net.asodev.islandutils.util.ChatUtils; -import net.asodev.islandutils.util.MusicUtil; import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import static net.minecraft.network.chat.Component.literal; @@ -47,7 +49,8 @@ public static void handleTrap(ClientboundSetSubtitleTextPacket clientboundSetSub try { ClassicAnnouncer.trap = trap; // Set the trap to the one we just found ResourceLocation sound = ResourceLocation.fromNamespaceAndPath("island", "announcer." + trap); // island:announcer.(trap) -> The sound location - Minecraft.getInstance().getSoundManager().play(MusicUtil.createSoundInstance(sound)); // Play the sound!! + SoundInstance soundInstance = SimpleSoundInstance.forUI(SoundEvent.createVariableRangeEvent(sound), 1f, 1f); + Minecraft.getInstance().getSoundManager().play(soundInstance); // Play the sound!! } catch (Exception e) { e.printStackTrace(); // Something went horribly wrong, probably an invalid character } diff --git a/src/main/java/net/asodev/islandutils/modules/FishingUpgradeIcon.java b/src/main/java/net/asodev/islandutils/modules/FishingUpgradeIcon.java new file mode 100644 index 0000000..e9e9cda --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/FishingUpgradeIcon.java @@ -0,0 +1,29 @@ +package net.asodev.islandutils.modules; + +import net.asodev.islandutils.util.Utils; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.Slot; + +import java.util.List; + +public class FishingUpgradeIcon { + private static final ResourceLocation UPGRADE_ICON_LOCATION = ResourceLocation.fromNamespaceAndPath("island", "upgrade"); + + public static void render(Slot slot, GuiGraphics guiGraphics) { + List lore = Utils.getLores(slot.getItem()); + if (lore == null) return; + boolean canUpgrade = lore.stream().anyMatch(c -> c.getString().contains("Left-Click to Upgrade")); + if (!canUpgrade) return; + + int x = slot.x + 1; + int y = slot.y + 1; + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(0.0F, 0.0F, 400F); + guiGraphics.blitSprite(RenderType::guiTextured, UPGRADE_ICON_LOCATION, x, y, 16, 16); + guiGraphics.pose().popPose(); + } + +} diff --git a/src/main/java/net/asodev/islandutils/modules/NoxesiumIntegration.java b/src/main/java/net/asodev/islandutils/modules/NoxesiumIntegration.java index b39a229..80bff79 100644 --- a/src/main/java/net/asodev/islandutils/modules/NoxesiumIntegration.java +++ b/src/main/java/net/asodev/islandutils/modules/NoxesiumIntegration.java @@ -17,14 +17,11 @@ public void init() { } private void handleServerPacket(ClientboundMccServerPacket packet) { - if (packet.serverType().startsWith("lobby")) { - MccIslandState.setGame(Game.HUB); - } else { - try { - MccIslandState.setGame(Game.fromPacket(packet)); - } catch (Exception e) { - LOGGER.error(e.getMessage()); - } + MccIslandState.setSubType(packet.subType()); + try { + MccIslandState.setGame(Game.fromPacket(packet)); + } catch (Exception e) { + LOGGER.error(e.getMessage()); } } diff --git a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticState.java b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticState.java index 21fb1f8..3b0fc45 100644 --- a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticState.java +++ b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticState.java @@ -32,12 +32,14 @@ public class CosmeticState { public static Cosmetic hatSlot = new Cosmetic(CosmeticType.HAT); public static Cosmetic accessorySlot = new Cosmetic(CosmeticType.ACCESSORY); + public static Cosmetic mainHandSlot = new Cosmetic(CosmeticType.MAIN_HAND); @Nullable public static Integer hoveredColor; public static Cosmetic getCosmeticByType(CosmeticType type) { switch (type) { case HAT -> { return hatSlot; } case ACCESSORY -> { return accessorySlot; } + case MAIN_HAND -> { return mainHandSlot; } } return null; } @@ -77,6 +79,7 @@ public static CosmeticType getType(ItemStack item) { if (path.endsWith(".icon_empty") || path.endsWith(".icon")) return null; if (path.contains("hat.") || path.contains("hair.")) return CosmeticType.HAT; if (path.contains("accessory.")) return CosmeticType.ACCESSORY; + if (path.startsWith("island_lobby.fishing.rods")) return CosmeticType.MAIN_HAND; return null; } diff --git a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticType.java b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticType.java index 0315ee9..c5c5f55 100644 --- a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticType.java +++ b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticType.java @@ -3,6 +3,7 @@ public enum CosmeticType { HAT, - ACCESSORY + ACCESSORY, + MAIN_HAND } diff --git a/src/main/java/net/asodev/islandutils/modules/crafting/CraftingToast.java b/src/main/java/net/asodev/islandutils/modules/crafting/CraftingToast.java index ed232ec..31459c1 100644 --- a/src/main/java/net/asodev/islandutils/modules/crafting/CraftingToast.java +++ b/src/main/java/net/asodev/islandutils/modules/crafting/CraftingToast.java @@ -3,10 +3,12 @@ import net.asodev.islandutils.modules.crafting.state.CraftingItem; import net.asodev.islandutils.util.ChatUtils; import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.toasts.Toast; -import net.minecraft.client.gui.components.toasts.ToastComponent; import net.minecraft.client.resources.language.I18n; +import net.minecraft.client.gui.components.toasts.ToastManager; +import net.minecraft.client.renderer.RenderType; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -14,31 +16,44 @@ import static net.asodev.islandutils.util.Utils.MCC_HUD_FONT; public class CraftingToast implements Toast { - private static ResourceLocation ISLAND_TOASTS_TEXTURE = ResourceLocation.fromNamespaceAndPath("island", "textures/gui/toasts.png"); + private static final ResourceLocation ISLAND_TOASTS_TEXTURE = ResourceLocation.fromNamespaceAndPath("island", "toasts"); + private static final long DISPLAY_TIME = 5000; // 5s ItemStack itemStack; Component displayName; + private Visibility wantedVisibility = Visibility.HIDE; + public CraftingToast(CraftingItem craftingItem) { itemStack = craftingItem.getStack(); displayName = craftingItem.getTitle(); } @Override - public Toast.Visibility render(GuiGraphics guiGraphics, ToastComponent toastComponent, long l) { + public Visibility getWantedVisibility() { + return wantedVisibility; + } + + @Override + public void update(ToastManager toastManager, long l) { + this.wantedVisibility = (l >= DISPLAY_TIME * toastManager.getNotificationDisplayTimeMultiplier()) ? Visibility.HIDE : Visibility.SHOW; + } + + @Override + public void render(GuiGraphics guiGraphics, Font font, long l) { // If mcc:hub font can't render all the symbols in the string // use the default font. Used for localization. Component description = ChatUtils.checkForHudUnsupportedSymbols(I18n.get("islandutils.message.crafting.toastNotif")) ? Component.translatable("islandutils.message.crafting.toastNotif").withStyle(MCC_HUD_FONT.withColor(ChatFormatting.WHITE)) : Component.translatable("islandutils.message.crafting.toastNotif").withStyle(ChatFormatting.WHITE); - - guiGraphics.blit(ISLAND_TOASTS_TEXTURE, 0, 0, 0, 0, this.width(), this.height()); + + + guiGraphics.blitSprite(RenderType::guiTextured, ISLAND_TOASTS_TEXTURE, 0, 0, this.width(), this.height()); int y = 7; - guiGraphics.drawString(toastComponent.getMinecraft().font, description, 30, y, -16777216, false); + guiGraphics.drawString(font, description, 30, y, -16777216, false); y += 5 + 4; - guiGraphics.drawString(toastComponent.getMinecraft().font, displayName, 30, y, -11534256, false); + guiGraphics.drawString(font, displayName, 30, y, -11534256, false); guiGraphics.renderFakeItem(itemStack, 8, 8); - return (double)l >= 5000.0 * toastComponent.getNotificationDisplayTimeMultiplier() ? Toast.Visibility.HIDE : Toast.Visibility.SHOW; } } diff --git a/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItem.java b/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItem.java index d195fe1..b9833f4 100644 --- a/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItem.java +++ b/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItem.java @@ -3,6 +3,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.asodev.islandutils.modules.crafting.CraftingMenuType; +import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; @@ -12,6 +13,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomModelData; +import java.util.Optional; + import static net.asodev.islandutils.util.ChatUtils.iconsFontStyle; public class CraftingItem { @@ -36,6 +39,7 @@ public JsonObject toJson() { object.addProperty("slot", slot); return object; } + public static CraftingItem fromJson(JsonElement element) { JsonObject object = element.getAsJsonObject(); CraftingItem item = new CraftingItem(); @@ -44,9 +48,11 @@ public static CraftingItem fromJson(JsonElement element) { item.setTitle( Component.Serializer.fromJson(jsonTitle, RegistryAccess.EMPTY) ); ResourceLocation typeKey = ResourceLocation.parse(object.get("type").getAsString()); - item.setType( BuiltInRegistries.ITEM.get(typeKey) ); + Holder.Reference itemType = BuiltInRegistries.ITEM.get(typeKey) + .orElseThrow(() -> new IllegalStateException("Item with type " + typeKey + " does not exist.")); + item.setType(itemType.value()); - item.setCustomModelData( object.get("customModelData").getAsInt() ); + item.setCustomModelData( object.get("customModelData").getAsInt()); String craftingTypeString = object.get("craftingMenuType").getAsString(); diff --git a/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItems.java b/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItems.java index a94f0db..74016e2 100644 --- a/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItems.java +++ b/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingItems.java @@ -12,6 +12,7 @@ import net.minecraft.world.item.Items; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.spongepowered.asm.mixin.injection.At; import java.io.File; import java.util.ArrayList; @@ -61,7 +62,13 @@ public static void load() throws Exception { JsonObject object = new Gson().fromJson(string, JsonObject.class); JsonArray array = object.get("items").getAsJsonArray(); - array.forEach(element -> items.add(CraftingItem.fromJson(element))); + array.forEach(element -> { + try { + items.add(CraftingItem.fromJson(element)); + } catch (Exception e) { + logger.error("Failed to load crafting item", e); + } + }); } public static void save() { if (saveQueued) { diff --git a/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingNotifier.java b/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingNotifier.java index ce78e55..bb4a1c7 100644 --- a/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingNotifier.java +++ b/src/main/java/net/asodev/islandutils/modules/crafting/state/CraftingNotifier.java @@ -8,7 +8,7 @@ import net.asodev.islandutils.options.categories.CraftingOptions; import net.asodev.islandutils.state.MccIslandState; import net.asodev.islandutils.util.ChatUtils; -import net.asodev.islandutils.util.MusicUtil; +import net.asodev.islandutils.util.IslandSoundEvents; import net.asodev.islandutils.util.Scheduler; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; @@ -20,7 +20,6 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; -import net.minecraft.resources.ResourceLocation; import org.apache.commons.lang3.time.DurationFormatUtils; import java.util.List; @@ -56,7 +55,7 @@ public void sendNotif(Minecraft client, CraftingItem item) { if (!options.isEnableCraftingNotifs()) return; boolean shouldMakeSound = false; if (options.isToastNotif()) { - client.getToasts().addToast( new CraftingToast(item) ); + client.getToastManager().addToast(new CraftingToast(item)); shouldMakeSound = true; } if (options.isChatNotif()) { @@ -81,7 +80,7 @@ private void sendChatNotif(CraftingItem item) { } private void sendNotifSound() { - SimpleSoundInstance mcc = MusicUtil.createSoundInstance(ResourceLocation.fromNamespaceAndPath("mcc", "ui.achievement_receive")); + SimpleSoundInstance mcc = SimpleSoundInstance.forUI(IslandSoundEvents.UI_ACHIEVEMENT_RECEIVE, 1f, 1f); Scheduler.schedule(5, (mc) -> { mc.getSoundManager().play(mcc); }); diff --git a/src/main/java/net/asodev/islandutils/modules/music/MusicManager.java b/src/main/java/net/asodev/islandutils/modules/music/MusicManager.java new file mode 100644 index 0000000..88a4dbc --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/MusicManager.java @@ -0,0 +1,131 @@ +package net.asodev.islandutils.modules.music; + +import net.asodev.islandutils.mixins.accessors.SoundEngineAccessor; +import net.asodev.islandutils.mixins.accessors.SoundManagerAccessor; +import net.asodev.islandutils.modules.music.modifiers.ClassicHitwMusic; +import net.asodev.islandutils.modules.music.modifiers.HighQualityMusic; +import net.asodev.islandutils.modules.music.modifiers.PreviousDynaballMusic; +import net.asodev.islandutils.modules.music.modifiers.TgttosDomeModifier; +import net.asodev.islandutils.modules.music.modifiers.TgttosDoubleTime; +import net.asodev.islandutils.util.ChatUtils; +import net.asodev.islandutils.util.MCCSoundInstance; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.sounds.ChannelAccess; +import net.minecraft.client.sounds.SoundEngine; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.network.protocol.game.ClientboundStopSoundPacket; +import net.minecraft.resources.ResourceLocation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class MusicManager { + private static final int FADE_DURATION = 20; + private final static List modifiersList = new ArrayList<>(); + private static MCCSoundInstance currentlyPlaying = null; + + private static final List loopingTracks = List.of( + "music.global.parkour_warrior", + "music.global.battle_box", + "music.global.dynaball", + "music.global.hole_in_the_wall", + "music.global.sky_battle", + "music.global.tgttosawaf", + "music.global.overtime_loop_music" + ); + + public static void init() { + addModifier(new TgttosDoubleTime()); + addModifier(new TgttosDomeModifier()); + addModifier(new ClassicHitwMusic()); + addModifier(new PreviousDynaballMusic()); + addModifier(new HighQualityMusic()); + + ClientTickEvents.START_CLIENT_TICK.register((client) -> { + if (currentlyPlaying == null) return; + if (currentlyPlaying.isStopped()) { + client.getSoundManager().stop(currentlyPlaying); + } + }); + } + + private static boolean shouldIgnore(SoundInfo info) { + // ignore tracks that aren't the music tracks we wanna mess with + return !loopingTracks.contains(info.path().getPath()); + } + + public static void onMusicSoundPacket(ClientboundSoundPacket packet, Minecraft minecraft) { + startMusic(SoundInfo.fromPacket(packet)); + } + + public static void startMusic(SoundInfo info) { + if (shouldIgnore(info)) { + Minecraft.getInstance().getSoundManager().play(info.toSoundInstance()); + return; + } + + SoundInfo newSoundInfo = applyModifiers(info) + .withLooping(true); + + if (currentlyPlaying != null) { + if (newSoundInfo.path().equals(currentlyPlaying.location)) { + ChatUtils.debug("Cancelled the playing of " + info.path() + " because it was already playing."); + return; + } + currentlyPlaying.fade(FADE_DURATION); + } + + MCCSoundInstance instance = newSoundInfo.toSoundInstance(); + currentlyPlaying = instance; + Minecraft.getInstance().getSoundManager().play(instance); + } + + public static void onMusicStopPacket(ClientboundStopSoundPacket packet, Minecraft minecraft) { + ResourceLocation name = packet.getName(); + ResourceLocation modifiedName = applyModifiers(SoundInfo.fromLocation(name)).path(); + + SoundManager soundManager = Minecraft.getInstance().getSoundManager(); + for (SoundInstance instance : getActiveSoundInstances()) { + if (instance.getLocation().equals(name) || instance.getLocation().equals(modifiedName)) { + if (instance instanceof MCCSoundInstance mccSound) { + mccSound.fade(FADE_DURATION); + } else { + soundManager.stop(instance); + } + } + } + if (currentlyPlaying != null && currentlyPlaying.getLocation().equals(name)) { + currentlyPlaying = null; + } + } + + public static SoundInfo applyModifiers(SoundInfo info) { + SoundInfo modified = info; + + for (MusicModifier modifier : modifiersList) { + if (!modifier.isEnabled() || !modifier.shouldApply(info.path())) continue; + modified = modifier.apply(modified); + } + return modified; + } + + public static List getModifiers() { + return modifiersList; + } + + private static void addModifier(MusicModifier modifier) { + modifiersList.add(modifier); + } + + private static Set getActiveSoundInstances() { + SoundManager soundManager = Minecraft.getInstance().getSoundManager(); + SoundEngine engine = ((SoundManagerAccessor)soundManager).getSoundEngine(); + Map instanceToChannel = ((SoundEngineAccessor)engine).getInstanceToChannel(); + return instanceToChannel.keySet(); + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/MusicModifier.java b/src/main/java/net/asodev/islandutils/modules/music/MusicModifier.java new file mode 100644 index 0000000..4499579 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/MusicModifier.java @@ -0,0 +1,44 @@ +package net.asodev.islandutils.modules.music; + +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public abstract class MusicModifier { + private boolean isEnabled = defaultOption(); + private final String identifier; + private final Component name; + private final Component desc; + + public MusicModifier(String identifier) { + this.identifier = identifier; + this.name = Component.translatable("islandutils.music_modifier." + identifier); + this.desc = Component.translatableWithFallback("islandutils.music_modifier." + identifier + ".desc", ""); + } + + public abstract SoundInfo apply(SoundInfo info); + public abstract boolean shouldApply(ResourceLocation soundLocation); + + public boolean hasOption() { + return true; + } + public boolean defaultOption() { + return true; + } + + public final boolean isEnabled() { + return isEnabled; + } + public final void setEnabled(boolean enabled) { + isEnabled = enabled; + } + + public final String identifier() { + return identifier; + } + public final Component name() { + return name; + } + public Component desc() { + return desc; + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/SoundInfo.java b/src/main/java/net/asodev/islandutils/modules/music/SoundInfo.java new file mode 100644 index 0000000..8f675e6 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/SoundInfo.java @@ -0,0 +1,49 @@ +package net.asodev.islandutils.modules.music; + +import net.asodev.islandutils.util.MCCSoundInstance; +import net.minecraft.core.Holder; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; + +public record SoundInfo(ResourceLocation path, SoundSource category, double x, double y, double z, float volume, float pitch, long seed, boolean looping) { + + public SoundInfo withPath(ResourceLocation path) { + return new SoundInfo(path, category, x, y, z, volume, pitch, seed, looping); + } + + public SoundInfo withCategory(SoundSource category) { + return new SoundInfo(path, category, x, y, z, volume, pitch, seed, looping); + } + + public SoundInfo withPitch(float pitch) { + return new SoundInfo(path, category, x, y, z, volume, pitch, seed, looping); + } + + public SoundInfo withLooping(boolean looping) { + return new SoundInfo(path, category, x, y, z, volume, pitch, seed, looping); + } + + public static SoundInfo fromLocation(ResourceLocation location) { + return new SoundInfo(location, SoundSource.MASTER, 0.0, 0.0, 0.0, 1f, 1f, 0L, false); + } + public static SoundInfo fromPacket(ClientboundSoundPacket soundPacket) { + return new SoundInfo( + soundPacket.getSound().value().location(), + soundPacket.getSource(), + soundPacket.getX(), + soundPacket.getY(), + soundPacket.getZ(), + soundPacket.getVolume(), + soundPacket.getPitch(), + soundPacket.getSeed(), + false + ); + } + + public MCCSoundInstance toSoundInstance() { + return new MCCSoundInstance(this); + } + +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/TrackMusicModifier.java b/src/main/java/net/asodev/islandutils/modules/music/TrackMusicModifier.java new file mode 100644 index 0000000..23611fd --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/TrackMusicModifier.java @@ -0,0 +1,23 @@ +package net.asodev.islandutils.modules.music; + +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public abstract class TrackMusicModifier extends MusicModifier { + private String trackPath; + + public TrackMusicModifier(String trackPath, String identifier) { + super(identifier); + this.trackPath = trackPath; + } + + @Override + public boolean shouldApply(ResourceLocation soundLocation) { + return soundLocation.getPath().equals(trackPath) && shouldApply1(soundLocation); + } + + public boolean shouldApply1(ResourceLocation soundLocation) { + return true; + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/modifiers/ClassicHitwMusic.java b/src/main/java/net/asodev/islandutils/modules/music/modifiers/ClassicHitwMusic.java new file mode 100644 index 0000000..15a545d --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/modifiers/ClassicHitwMusic.java @@ -0,0 +1,37 @@ +package net.asodev.islandutils.modules.music.modifiers; + +import net.asodev.islandutils.IslandUtils; +import net.asodev.islandutils.modules.music.SoundInfo; +import net.asodev.islandutils.modules.music.TrackMusicModifier; +import net.asodev.islandutils.options.IslandOptions; +import net.asodev.islandutils.state.MccIslandState; +import net.asodev.islandutils.util.ChatUtils; +import net.asodev.islandutils.util.IslandSoundEvents; +import net.minecraft.ChatFormatting; +import net.minecraft.resources.ResourceLocation; + +import static net.minecraft.network.chat.Component.literal; + +public class ClassicHitwMusic extends TrackMusicModifier { + public ClassicHitwMusic(){ + super("music.global.hole_in_the_wall", "classic_hitw.music"); + } + + @Override + public SoundInfo apply(SoundInfo info) { + ChatUtils.send(literal("Now playing: ").withStyle(ChatFormatting.GREEN) + .append(literal("Spacewall - Taylor Grover").withStyle(ChatFormatting.AQUA)) + ); + return info.withPath(IslandSoundEvents.islandSound("island.music.classic_hitw")); + } + + @Override + public boolean hasOption() { + return false; + } + + @Override + public boolean shouldApply1(ResourceLocation soundLocation) { + return IslandOptions.getClassicHITW().isClassicHITWMusic(); + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/modifiers/HighQualityMusic.java b/src/main/java/net/asodev/islandutils/modules/music/modifiers/HighQualityMusic.java new file mode 100644 index 0000000..3cfe820 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/modifiers/HighQualityMusic.java @@ -0,0 +1,41 @@ +package net.asodev.islandutils.modules.music.modifiers; + +import net.asodev.islandutils.modules.music.MusicModifier; +import net.asodev.islandutils.modules.music.SoundInfo; +import net.asodev.islandutils.modules.music.TrackMusicModifier; +import net.asodev.islandutils.state.Game; +import net.asodev.islandutils.util.IslandSoundEvents; +import net.minecraft.resources.ResourceLocation; + +import java.util.Map; + +public class HighQualityMusic extends MusicModifier { + Map replacements = Map.of( + "music.global.parkour_warrior", Game.PARKOUR_WARRIOR_DOJO.getMusicLocation(), + "music.global.battle_box", Game.BATTLE_BOX.getMusicLocation(), + "music.global.hole_in_the_wall", Game.HITW.getMusicLocation(), + "music.global.rocket_spleef", Game.ROCKET_SPLEEF_RUSH.getMusicLocation(), + "music.global.sky_battle", Game.SKY_BATTLE.getMusicLocation(), + "music.global.tgttosawaf", Game.TGTTOS.getMusicLocation() + ); + + public HighQualityMusic(){ + super("global.hq"); + } + + @Override + public SoundInfo apply(SoundInfo info) { + ResourceLocation replacementPath = replacements.get(info.path().getPath()); + return replacementPath != null ? info.withPath(replacementPath) : info; + } + + @Override + public boolean defaultOption() { + return false; + } + + @Override + public boolean shouldApply(ResourceLocation soundLocation) { + return true; + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/modifiers/PreviousDynaballMusic.java b/src/main/java/net/asodev/islandutils/modules/music/modifiers/PreviousDynaballMusic.java new file mode 100644 index 0000000..87ef42f --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/modifiers/PreviousDynaballMusic.java @@ -0,0 +1,23 @@ +package net.asodev.islandutils.modules.music.modifiers; + +import net.asodev.islandutils.modules.music.SoundInfo; +import net.asodev.islandutils.modules.music.TrackMusicModifier; +import net.asodev.islandutils.state.MccIslandState; +import net.asodev.islandutils.util.IslandSoundEvents; +import net.minecraft.resources.ResourceLocation; + +public class PreviousDynaballMusic extends TrackMusicModifier { + public PreviousDynaballMusic(){ + super("music.global.dynaball", "dynaball.old_music"); + } + + @Override + public boolean defaultOption() { + return false; + } + + @Override + public SoundInfo apply(SoundInfo info) { + return info.withPath(IslandSoundEvents.islandSound("island.music.dynaball")); + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/modifiers/TgttosDomeModifier.java b/src/main/java/net/asodev/islandutils/modules/music/modifiers/TgttosDomeModifier.java new file mode 100644 index 0000000..fde6827 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/modifiers/TgttosDomeModifier.java @@ -0,0 +1,23 @@ +package net.asodev.islandutils.modules.music.modifiers; + +import net.asodev.islandutils.modules.music.SoundInfo; +import net.asodev.islandutils.modules.music.TrackMusicModifier; +import net.asodev.islandutils.state.MccIslandState; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public class TgttosDomeModifier extends TrackMusicModifier { + public TgttosDomeModifier(){ + super("music.global.tgttosawaf", "tgttos.dome_modifier"); + } + + @Override + public SoundInfo apply(SoundInfo info) { + return info.withPath(ResourceLocation.fromNamespaceAndPath("island", "island.music.to_the_dome")); + } + + @Override + public boolean shouldApply1(ResourceLocation soundLocation) { + return MccIslandState.getModifier().equals("TO THE DOME"); + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/music/modifiers/TgttosDoubleTime.java b/src/main/java/net/asodev/islandutils/modules/music/modifiers/TgttosDoubleTime.java new file mode 100644 index 0000000..d399317 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/music/modifiers/TgttosDoubleTime.java @@ -0,0 +1,26 @@ +package net.asodev.islandutils.modules.music.modifiers; + +import net.asodev.islandutils.modules.music.MusicModifier; +import net.asodev.islandutils.modules.music.SoundInfo; +import net.asodev.islandutils.modules.music.TrackMusicModifier; +import net.asodev.islandutils.state.MccIslandState; +import net.asodev.islandutils.util.MCCSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public class TgttosDoubleTime extends TrackMusicModifier { + public TgttosDoubleTime(){ + super("music.global.tgttosawaf", "tgttos.double_time"); + } + + @Override + public SoundInfo apply(SoundInfo info) { + return info.withPitch(1.2f); + } + + @Override + public boolean shouldApply1(ResourceLocation soundLocation) { + return MccIslandState.getModifier().equals("DOUBLE TIME"); + } +} diff --git a/src/main/java/net/asodev/islandutils/modules/splits/LevelTimer.java b/src/main/java/net/asodev/islandutils/modules/splits/LevelTimer.java index 7eb40bd..c86cdf5 100644 --- a/src/main/java/net/asodev/islandutils/modules/splits/LevelTimer.java +++ b/src/main/java/net/asodev/islandutils/modules/splits/LevelTimer.java @@ -150,7 +150,7 @@ public Double getSplitImprovement() { public static void onSound(ClientboundSoundPacket clientboundSoundPacket) { if (!IslandOptions.getSplits().isEnablePkwSplits()) return; - ResourceLocation soundLoc = clientboundSoundPacket.getSound().value().getLocation(); + ResourceLocation soundLoc = clientboundSoundPacket.getSound().value().location(); String path = soundLoc.getPath(); boolean isRoundEnd = path.equals("games.global.timer.round_end"); if (path.contains("games.parkour_warrior.mode_swap") || diff --git a/src/main/java/net/asodev/islandutils/modules/splits/ui/DojoSplitUI.java b/src/main/java/net/asodev/islandutils/modules/splits/ui/DojoSplitUI.java index ef59fef..855c9bf 100644 --- a/src/main/java/net/asodev/islandutils/modules/splits/ui/DojoSplitUI.java +++ b/src/main/java/net/asodev/islandutils/modules/splits/ui/DojoSplitUI.java @@ -1,16 +1,18 @@ package net.asodev.islandutils.modules.splits.ui; +import com.mojang.blaze3d.systems.RenderSystem; import net.asodev.islandutils.modules.splits.LevelTimer; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.RenderType; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; public class DojoSplitUI implements SplitUI { - private static final ResourceLocation BAR_TEXTURE = ResourceLocation.fromNamespaceAndPath("island", "textures/gui/pkw_splits.png"); + private static final ResourceLocation BAR_TEXTURE = ResourceLocation.fromNamespaceAndPath("island", "pkw_splits"); private static final int MCC_BAR_WIDTH = 130; public static Style MCC_HUD_STYLE = Style.EMPTY.withFont(ResourceLocation.fromNamespaceAndPath("mcc", "hud")); @@ -24,7 +26,7 @@ public DojoSplitUI(LevelTimer timer) { public void render(GuiGraphics guiGraphics, int bossBars) { int x = (guiGraphics.guiWidth() / 2) - (MCC_BAR_WIDTH / 2); int y = Double.valueOf((bossBars * 18.5)).intValue(); - guiGraphics.blit(BAR_TEXTURE, x, y, 0, 0, this.width(), this.height()); + guiGraphics.blitSprite(RenderType::guiTextured, BAR_TEXTURE, x, y, this.width(), this.height()); renderLevelName(guiGraphics, x, y); renderSplitTime(guiGraphics, x, y); diff --git a/src/main/java/net/asodev/islandutils/options/IslandSoundCategories.java b/src/main/java/net/asodev/islandutils/options/IslandSoundCategories.java deleted file mode 100644 index 94df505..0000000 --- a/src/main/java/net/asodev/islandutils/options/IslandSoundCategories.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.asodev.islandutils.options; - -import net.minecraft.sounds.SoundSource; - -public class IslandSoundCategories { - - public static SoundSource[] before; - - public static SoundSource GAME_MUSIC; - public static SoundSource CORE_MUSIC; - public static SoundSource SOUND_EFFECTS; -} diff --git a/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java b/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java index 7b15a82..a8ac72d 100644 --- a/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java +++ b/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java @@ -18,6 +18,7 @@ public class MiscOptions implements OptionsCategory { boolean showFriendsInLobby = true; boolean silverPreview = true; boolean channelSwitchers = true; + boolean showFishingUpgradeIcon = true; boolean enableConfigButton = true; boolean debugMode = false; @@ -40,6 +41,10 @@ public boolean isEnableConfigButton() { public boolean showChannelSwitchers() { return channelSwitchers; } + public boolean isShowFishingUpgradeIcon() { + return showFishingUpgradeIcon; + } + public boolean isDebugMode() { return debugMode && !Utils.isLunarClient(); } @@ -76,6 +81,12 @@ public ConfigCategory getCategory() { .controller(TickBoxControllerBuilder::create) .binding(defaults.channelSwitchers, () -> channelSwitchers, value -> this.channelSwitchers = value) .build(); + Option fishingUpgradeOption = Option.createBuilder() + .name(Component.translatable("text.autoconfig.islandutils.option.showFishingUpgradeIcon")) + .description(OptionDescription.of(Component.translatable("text.autoconfig.islandutils.option.showFishingUpgradeIcon.@Tooltip"))) + .controller(TickBoxControllerBuilder::create) + .binding(defaults.showFishingUpgradeIcon, () -> showFishingUpgradeIcon, value -> this.showFishingUpgradeIcon = value) + .build(); Option buttonOption = Option.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.option.enableConfigButton")) .description(OptionDescription.of(Component.translatable("text.autoconfig.islandutils.option.enableConfigButton.@Tooltip"))) @@ -101,6 +112,7 @@ public ConfigCategory getCategory() { .build()) .option(silverOption) .option(channelsOption) + .option(fishingUpgradeOption) .option(buttonOption) .group(OptionGroup.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.group.debugOptions")) diff --git a/src/main/java/net/asodev/islandutils/options/categories/MusicOptions.java b/src/main/java/net/asodev/islandutils/options/categories/MusicOptions.java index 32b14a4..33c65c4 100644 --- a/src/main/java/net/asodev/islandutils/options/categories/MusicOptions.java +++ b/src/main/java/net/asodev/islandutils/options/categories/MusicOptions.java @@ -2,132 +2,44 @@ import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.OptionDescription; import dev.isxander.yacl3.api.OptionGroup; import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; +import net.asodev.islandutils.modules.music.MusicManager; +import net.asodev.islandutils.modules.music.MusicModifier; import net.asodev.islandutils.options.saving.Ignore; import net.minecraft.network.chat.Component; +import java.util.ArrayList; +import java.util.List; + public class MusicOptions implements OptionsCategory { @Ignore private static final MusicOptions defaults = new MusicOptions(); - boolean hitwMusic = true; - boolean bbMusic = true; - boolean sbMusic = true; - boolean dynaballMusic = true; - - boolean tgttosMusic = true; - boolean tgttosDoubleTime = true; - boolean tgttosToTheDome = true; - - boolean pkwMusic = true; - boolean pkwsMusic = true; - boolean rsrMusic = true; - - public boolean isHitwMusic() { - return hitwMusic; - } - public boolean isBbMusic() { - return bbMusic; - } - public boolean isSbMusic() { - return sbMusic; - } - public boolean isTgttosMusic() { - return tgttosMusic; - } - public boolean isTgttosDoubleTime() { - return tgttosDoubleTime; - } - public boolean isTgttosToTheDome() { - return tgttosToTheDome; - } - public boolean isPkwMusic() { - return pkwMusic; - } - public boolean isPkwsMusic() { - return pkwsMusic; - } - public boolean isDynaballMusic() { - return dynaballMusic; - } - - public boolean isRsrMusic() { - return rsrMusic; - } @Override public ConfigCategory getCategory() { - Option hitwOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.hitwMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.hitwMusic, () -> hitwMusic, value -> this.hitwMusic = value) - .build(); - Option bbOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.bbMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.bbMusic, () -> bbMusic, value -> this.bbMusic = value) - .build(); - Option sbOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.sbMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.sbMusic, () -> sbMusic, value -> this.sbMusic = value) - .build(); - Option dynaballOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.dynaballMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.dynaballMusic, () -> dynaballMusic, value -> this.dynaballMusic = value) - .build(); - Option rsrOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.rsrMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.rsrMusic, () -> rsrMusic, value -> this.rsrMusic = value) - .build(); - Option tgttosOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.tgttosMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.tgttosMusic, () -> tgttosMusic, value -> this.tgttosMusic = value) - .build(); - Option tgttosDoubleOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.tgttosDoubleTime")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.tgttosDoubleTime, () -> tgttosDoubleTime, value -> this.tgttosDoubleTime = value) - .build(); - Option tgttosToDomeOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.tgttosToTheDome")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.tgttosToTheDome, () -> tgttosToTheDome, value -> this.tgttosToTheDome = value) - .build(); - Option pkwDojoOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.pkwMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.pkwMusic, () -> pkwMusic, value -> this.pkwMusic = value) - .build(); - Option pkwSurviorOption = Option.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.option.pkwsMusic")) - .controller(TickBoxControllerBuilder::create) - .binding(defaults.pkwsMusic, () -> pkwsMusic, value -> this.pkwsMusic = value) - .build(); + List> modifierOptions = new ArrayList<>(); + for (MusicModifier modifier : MusicManager.getModifiers()) { + if (!modifier.hasOption()) continue; + + var option = Option.createBuilder() + .name(modifier.name()) + .description(OptionDescription.of(modifier.desc())) + .controller(TickBoxControllerBuilder::create) + .binding(modifier.defaultOption(), modifier::isEnabled, modifier::setEnabled) + .build(); + modifierOptions.add(option); + } return ConfigCategory.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.category.music")) - .option(hitwOption) - .option(bbOption) - .option(sbOption) - .option(dynaballOption) - .option(rsrOption) - .group(OptionGroup.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.group.tgttos")) - .option(tgttosOption) - .option(tgttosDoubleOption) - .option(tgttosToDomeOption) - .build()) .group(OptionGroup.createBuilder() - .name(Component.translatable("text.autoconfig.islandutils.group.pkw")) - .option(pkwDojoOption) - .option(pkwSurviorOption) + .name(Component.literal(Component.translatable("text.autoconfig.islandutils.group.modifiers"))) + .options(modifierOptions) .build()) .build(); } -} +} \ No newline at end of file diff --git a/src/main/java/net/asodev/islandutils/state/Game.java b/src/main/java/net/asodev/islandutils/state/Game.java index 50fcfcf..74ee858 100644 --- a/src/main/java/net/asodev/islandutils/state/Game.java +++ b/src/main/java/net/asodev/islandutils/state/Game.java @@ -1,6 +1,7 @@ package net.asodev.islandutils.state; import com.noxcrew.noxesium.network.clientbound.ClientboundMccServerPacket; +import net.asodev.islandutils.discord.FishingPresenceUpdator; import net.minecraft.resources.ResourceLocation; import java.util.NoSuchElementException; @@ -8,6 +9,7 @@ public enum Game { HUB("Hub", "", null), + FISHING("Hub", "", null), TGTTOS("TGTTOS", "tgttos", getMusicLocation("tgttos")), HITW("Hole in the Wall", "hole_in_the_wall", getMusicLocation("hitw")), @@ -55,6 +57,13 @@ public static ResourceLocation getMusicLocation(String name) { } public static Game fromPacket(ClientboundMccServerPacket packet) throws NoSuchElementException { + if (packet.serverType().equals("lobby")) { + for (String temperature : FishingPresenceUpdator.temperatures) { + if (packet.subType().startsWith(temperature + "_")) return FISHING; + } + return HUB; + } + for (Game game : values()) { if (game.islandId.equals(packet.associatedGame())) { if (game.subType != null && !game.subType.equals(packet.subType())) diff --git a/src/main/java/net/asodev/islandutils/state/MccIslandState.java b/src/main/java/net/asodev/islandutils/state/MccIslandState.java index a88abfa..a0bb8c8 100644 --- a/src/main/java/net/asodev/islandutils/state/MccIslandState.java +++ b/src/main/java/net/asodev/islandutils/state/MccIslandState.java @@ -13,6 +13,7 @@ public class MccIslandState { private static Game game = Game.HUB; private static String modifier = "INACTIVE"; private static String map = "UNKNOWN"; + private static String subType = ""; public static String getModifier() { return modifier; @@ -77,6 +78,13 @@ public static String getMap() { return map; } + public static String getSubType() { + return subType; + } + public static void setSubType(String subType) { + MccIslandState.subType = subType; + } + public static boolean isOnline() { ServerData currentServer = Minecraft.getInstance().getCurrentServer(); if (currentServer == null) return false; diff --git a/src/main/java/net/asodev/islandutils/util/IslandSoundEvents.java b/src/main/java/net/asodev/islandutils/util/IslandSoundEvents.java new file mode 100644 index 0000000..dc1ae97 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/util/IslandSoundEvents.java @@ -0,0 +1,22 @@ +package net.asodev.islandutils.util; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; + +public class IslandSoundEvents { + public static final SoundEvent UI_CLICK_NORMAL = soundEvent("ui.click_normal"); + public static final SoundEvent UI_ACHIEVEMENT_RECEIVE = soundEvent("ui.achievement_receive"); + public static final SoundEvent ANNOUNCER_GAME_OVER = islandUtilsEvent("announcer.gameover"); + + private static SoundEvent soundEvent(String path) { + return SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath("mcc", path)); + } + + private static SoundEvent islandUtilsEvent(String path) { + return SoundEvent.createVariableRangeEvent(islandSound(path)); + } + + public static ResourceLocation islandSound(String path) { + return ResourceLocation.fromNamespaceAndPath("island", path); + } +} diff --git a/src/main/java/net/asodev/islandutils/util/MCCSoundInstance.java b/src/main/java/net/asodev/islandutils/util/MCCSoundInstance.java index eddd9b6..c1521fa 100644 --- a/src/main/java/net/asodev/islandutils/util/MCCSoundInstance.java +++ b/src/main/java/net/asodev/islandutils/util/MCCSoundInstance.java @@ -1,5 +1,6 @@ package net.asodev.islandutils.util; +import net.asodev.islandutils.modules.music.SoundInfo; import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance; import net.minecraft.client.resources.sounds.SoundInstance; import net.minecraft.resources.ResourceLocation; @@ -11,26 +12,40 @@ public class MCCSoundInstance extends AbstractTickableSoundInstance { - public static ResourceLocation location; + public ResourceLocation location; public float totalVolume; public float totalFadeTicks = 20f; public float fadeTicks = 0f; public boolean isFading = false; - protected MCCSoundInstance(SoundEvent event, SoundSource soundSource, float f,float g, RandomSource randomSource, boolean bl, int i, SoundInstance.Attenuation attenuation, double d, double e, double h, boolean bl2) { - super(event, soundSource, randomSource); - location = event.getLocation(); - this.volume = f; - totalVolume = f; - this.pitch = g; - this.x = d; - this.y = e; - this.z = h; - this.looping = shouldLoop(location); - this.delay = i; - this.attenuation = attenuation; - this.relative = bl2; + public MCCSoundInstance(ResourceLocation location, SoundSource soundSource, float volume,float pitch, RandomSource randomSource, double x, double y, double z) { + super(SoundEvent.createVariableRangeEvent(location), soundSource, randomSource); + this.location = location; + this.volume = volume; + this.totalVolume = volume; + this.pitch = pitch; + this.x = x; + this.y = y; + this.z = z; + this.looping = false; + this.delay = 0; + this.attenuation = Attenuation.NONE; + this.relative = false; + } + + public MCCSoundInstance(SoundInfo soundInfo) { + this( + soundInfo.path(), + soundInfo.category(), + soundInfo.volume(), + soundInfo.pitch(), + RandomSource.create(soundInfo.seed()), + soundInfo.x(), + soundInfo.y(), + soundInfo.z() + ); + this.looping = soundInfo.looping(); } public void fade(float ticks) { @@ -60,14 +75,4 @@ public String toString() { "location=" + location + '}'; } - - static List loopingSounds = List.of( - "island.music.parkour_warrior", - "island.music.classic_hitw", - "island.music.dynaball", - "island.music.rsr" - ); - static boolean shouldLoop(ResourceLocation sound) { - return loopingSounds.contains(sound.getPath()); - } } diff --git a/src/main/java/net/asodev/islandutils/util/MusicUtil.java b/src/main/java/net/asodev/islandutils/util/MusicUtil.java deleted file mode 100644 index 1ecf7c2..0000000 --- a/src/main/java/net/asodev/islandutils/util/MusicUtil.java +++ /dev/null @@ -1,202 +0,0 @@ -package net.asodev.islandutils.util; - -import com.mojang.blaze3d.audio.Listener; -import com.mojang.brigadier.context.CommandContext; -import net.asodev.islandutils.mixins.accessors.SoundEngineAccessor; -import net.asodev.islandutils.mixins.accessors.SoundManagerAccessor; -import net.asodev.islandutils.options.IslandOptions; -import net.asodev.islandutils.options.IslandSoundCategories; -import net.asodev.islandutils.options.categories.MusicOptions; -import net.asodev.islandutils.state.Game; -import net.asodev.islandutils.state.MccIslandState; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.client.resources.sounds.SoundInstance; -import net.minecraft.client.sounds.SoundManager; -import net.minecraft.network.protocol.game.ClientboundSoundPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.RandomSource; -import net.minecraft.world.phys.Vec3; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; - -import static net.minecraft.network.chat.Component.literal; - -public class MusicUtil { - - public static MCCSoundInstance currentlyPlayingSound = null; - - public static void startMusic(ClientboundSoundPacket clientboundSoundPacket) { - startMusic(clientboundSoundPacket, false); - } - public static void startMusic(ClientboundSoundPacket clientboundCustomSoundPacket, boolean bypassOvertimeCheck) { - MusicOptions options = IslandOptions.getMusic(); - switch (MccIslandState.getGame()) { - case HITW -> { if (!options.isHitwMusic()) return; } - case TGTTOS -> { if (!options.isTgttosMusic()) return; } - case BATTLE_BOX -> { if (!options.isBbMusic()) return; } - case SKY_BATTLE -> { if (!options.isSbMusic()) return; } - case PARKOUR_WARRIOR_DOJO -> { if (!options.isPkwMusic()) return; } - case PARKOUR_WARRIOR_SURVIVOR -> { - if (!options.isPkwsMusic()) return; - if (currentlyPlayingSound != null) return; - if (!bypassOvertimeCheck && isOvertimePlaying()) return; - } - case DYNABALL -> { if (!options.isDynaballMusic()) return; } - case ROCKET_SPLEEF_RUSH -> { if (!options.isRsrMusic()) return; } - } - - ResourceLocation location = MccIslandState.getGame().getMusicLocation(); - if (MccIslandState.getGame() == Game.HITW && IslandOptions.getClassicHITW().isClassicHITWMusic()) { - location = ResourceLocation.fromNamespaceAndPath("island","island.music.classic_hitw"); - ChatUtils.send(literal("Now playing: ").withStyle(ChatFormatting.GREEN) - .append(literal("Spacewall - Taylor Grover").withStyle(ChatFormatting.AQUA)) - ); - } - if (location == null) return; - - float pitch = 1f; - if (options.isTgttosDoubleTime() && MccIslandState.getGame() == Game.TGTTOS && - Objects.equals(MccIslandState.getModifier(), "DOUBLE TIME")) { - pitch = 1.2f; - ChatUtils.debug("[MusicUtil] Double Time on TGTTOS active! (Pitch: %s)", pitch); - } - if (options.isTgttosToTheDome() && MccIslandState.getGame() == Game.TGTTOS && - Objects.equals(MccIslandState.getMap(), "TO THE DOME")) { - location = ResourceLocation.fromNamespaceAndPath("island", "island.music.to_the_dome"); - ChatUtils.debug("[MusicUtil] To The Dome on TGTTOS active!"); - } - - ChatUtils.debug("[MusicUtil] Starting: " + location); - stopMusic(); - - MCCSoundInstance instance = new MCCSoundInstance( - SoundEvent.createVariableRangeEvent(location), - IslandSoundCategories.GAME_MUSIC, - clientboundCustomSoundPacket.getVolume(), - pitch, - RandomSource.create(clientboundCustomSoundPacket.getSeed()), - false, - 0, - SoundInstance.Attenuation.LINEAR, - clientboundCustomSoundPacket.getX(), - clientboundCustomSoundPacket.getY(), - clientboundCustomSoundPacket.getZ(), - false); - Minecraft.getInstance().getSoundManager().play(instance); - currentlyPlayingSound = instance; - } - - public static SimpleSoundInstance createSoundInstance(ClientboundSoundPacket clientboundCustomSoundPacket, SoundSource source) { - return new SimpleSoundInstance( - clientboundCustomSoundPacket.getSound().value().getLocation(), - source, - clientboundCustomSoundPacket.getVolume(), - clientboundCustomSoundPacket.getPitch(), - RandomSource.create(clientboundCustomSoundPacket.getSeed()), - false, - 0, - SoundInstance.Attenuation.LINEAR, - clientboundCustomSoundPacket.getX(), - clientboundCustomSoundPacket.getY(), - clientboundCustomSoundPacket.getZ(), - false); - } - public static SimpleSoundInstance createSoundInstance(ResourceLocation resourceLocation) { - Vec3 listenerPosition = getListenerPosition(); - return new SimpleSoundInstance( - resourceLocation, - IslandSoundCategories.SOUND_EFFECTS, - 1f, - 1f, - RandomSource.create(), - false, - 0, - SoundInstance.Attenuation.NONE, - listenerPosition.x, - listenerPosition.y, - listenerPosition.z, - false - ); - } - - private static Vec3 getListenerPosition() { - SoundEngineAccessor soundEngine = (SoundEngineAccessor)((SoundManagerAccessor)Minecraft.getInstance().getSoundManager()).getSoundEngine(); - Listener listener = soundEngine.getListener(); - return listener.getTransform().position(); - } - - public static void stopMusic() { - stopMusic(false); - } - - public static void stopMusic(Boolean instant) { - if (currentlyPlayingSound != null) { - if (!instant) { - currentlyPlayingSound.fade(20); - ChatUtils.debug("[MusicUtil] Fading: " + currentlyPlayingSound); - } else { - currentlyPlayingSound.stopFwd(); - } - currentlyPlayingSound = null; - return; - } - ResourceLocation location = MccIslandState.getGame().getMusicLocation(); - if (location == null) return; - - ChatUtils.debug("[MusicUtil] Stopping: " + location.getPath()); - Minecraft.getInstance().getSoundManager().stop(location, IslandSoundCategories.GAME_MUSIC); - } - - public static void resetMusic(CommandContext ctx) { - if (currentlyPlayingSound == null) { - ChatUtils.send(literal("There is no music currently playing.").withStyle(ChatFormatting.RED)); - return; - } - - ResourceLocation music = currentlyPlayingSound.getLocation(); - float pitch = currentlyPlayingSound.getPitch(); - stopMusic(true); - - Vec3 listenerPosition = getListenerPosition(); - MCCSoundInstance instance = new MCCSoundInstance( - SoundEvent.createVariableRangeEvent(music), - IslandSoundCategories.GAME_MUSIC, - 1f, - pitch, - RandomSource.create(), - false, - 0, - SoundInstance.Attenuation.LINEAR, - listenerPosition.x, - listenerPosition.y, - listenerPosition.z, - false); - currentlyPlayingSound = instance; - Minecraft.getInstance().getSoundManager().play(instance); - ChatUtils.send(literal("Reset your music!").withStyle(ChatFormatting.GREEN)); - } - - public static boolean isMusicPlaying() { - return currentlyPlayingSound != null && !currentlyPlayingSound.isStopped(); - } - public static boolean isOvertimePlaying() { - return isSoundsPlaying("music.global.overtime_intro_music", "music.global.overtime_loop_music"); - } - public static boolean isSoundsPlaying(String ...sounds) { - List soundList = Arrays.stream(sounds).toList(); - SoundManager soundManager = Minecraft.getInstance().getSoundManager(); - SoundEngineAccessor engine = (SoundEngineAccessor)((SoundManagerAccessor)soundManager).getSoundEngine(); - for (SoundInstance soundInstance : engine.getInstanceToChannel().keySet()) { - if (!soundList.contains(soundInstance.getLocation().getPath())) continue; - return true; - } - return false; - } - -} diff --git a/src/main/java/net/asodev/islandutils/util/Sidebar.java b/src/main/java/net/asodev/islandutils/util/Sidebar.java index d5e6d54..277d842 100644 --- a/src/main/java/net/asodev/islandutils/util/Sidebar.java +++ b/src/main/java/net/asodev/islandutils/util/Sidebar.java @@ -4,6 +4,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.scores.DisplaySlot; import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.PlayerScoreEntry; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Scoreboard; import org.jetbrains.annotations.Nullable; @@ -28,11 +29,7 @@ public static List getSidebarLines() { Objective sidebar = getSidebar(scoreboard); if (sidebar == null) return Collections.emptyList(); - return scoreboard.listPlayerScores(sidebar).stream().map((entry) -> { - PlayerTeam playerTeam = scoreboard.getPlayersTeam(entry.owner()); - Component defaultName = entry.ownerName(); - return PlayerTeam.formatNameForTeam(playerTeam, defaultName); - }).collect(Collectors.toList()); + return scoreboard.listPlayerScores(sidebar).stream().map(PlayerScoreEntry::display).collect(Collectors.toList()); } public static int findLine(Predicate predicate) { diff --git a/src/main/resources/assets/island/lang/en_us.json b/src/main/resources/assets/island/lang/en_us.json index 7d95cb3..230df4a 100644 --- a/src/main/resources/assets/island/lang/en_us.json +++ b/src/main/resources/assets/island/lang/en_us.json @@ -12,18 +12,13 @@ "text.autoconfig.islandutils.title": "Island Utils Options", "text.autoconfig.islandutils.category.music": "Music", - "text.autoconfig.islandutils.group.tgttos": "TGTTOS Music", - "text.autoconfig.islandutils.group.pkw": "Parkour Warrior Music", - "text.autoconfig.islandutils.option.tgttosMusic": "TGTTOS Music", - "text.autoconfig.islandutils.option.hitwMusic": "HITW Music", - "text.autoconfig.islandutils.option.bbMusic": "Battle Box Music", - "text.autoconfig.islandutils.option.sbMusic": "Sky Battle Music", - "text.autoconfig.islandutils.option.dynaballMusic": "Dynaball Music", - "text.autoconfig.islandutils.option.rsrMusic": "Rocket Spleef Rush Music", - "text.autoconfig.islandutils.option.pkwMusic": "Parkour Warrior Dojo Music", - "text.autoconfig.islandutils.option.pkwsMusic": "Parkour Warrior Survivor Music", - "text.autoconfig.islandutils.option.tgttosDoubleTime": "TGTTOS Double Time Music", - "text.autoconfig.islandutils.option.tgttosToTheDome": "TGTTOS \"To The Dome!\" Music", + "text.autoconfig.islandutils.group.modifiers": "Modifiers", + "islandutils.music_modifier.tgttos.double_time": "TGTTOS Double Time Music", + "islandutils.music_modifier.tgttos.dome_modifier": "TGTTOS \"To The Dome!\" Music", + "islandutils.music_modifier.dynaball.old_music": "Previous Dynaball Music", + "islandutils.music_modifier.dynaball.old_music.desc": "Replaces Island's new Dynaball music with the music used previously.\n\n (NGS Live) Shoot 'em Up", + "islandutils.music_modifier.global.hq": "High(er) Quality Music", + "islandutils.music_modifier.global.hq.desc": "Replaces Island's downloaded music with high(er) quality versions (does not apply to Hub Music & Dynaball)", "text.autoconfig.islandutils.category.cosmetics": "Cosmetics", "text.autoconfig.islandutils.option.showPlayerPreview": "Show Cosmetic Previews", @@ -85,6 +80,7 @@ "text.autoconfig.islandutils.option.channelSwitchers.@Tooltip": "Shows the chat channel switcher buttons above the chat box", "text.autoconfig.islandutils.option.hideSliders": "Hide Sound Sliders if not Online", "text.autoconfig.islandutils.option.hideSliders.@Tooltip": "Hides the Music Sliders if you're not on MCC Island", + "text.autoconfig.islandutils.option.showFishingUpgradeIcon": "Show fishing upgrade icons", "text.autoconfig.islandutils.category.classic_hitw": "Classic HITW", "text.autoconfig.islandutils.option.classicHITW": "Classic Hole In The Wall Announcer", diff --git a/src/main/resources/assets/island/textures/gui/pkw_splits.png b/src/main/resources/assets/island/textures/gui/pkw_splits.png deleted file mode 100644 index be913a4..0000000 Binary files a/src/main/resources/assets/island/textures/gui/pkw_splits.png and /dev/null differ diff --git a/src/main/resources/assets/island/textures/gui/sprites/pkw_splits.png b/src/main/resources/assets/island/textures/gui/sprites/pkw_splits.png new file mode 100644 index 0000000..41e42d3 Binary files /dev/null and b/src/main/resources/assets/island/textures/gui/sprites/pkw_splits.png differ diff --git a/src/main/resources/assets/island/textures/preview.png b/src/main/resources/assets/island/textures/gui/sprites/preview.png similarity index 100% rename from src/main/resources/assets/island/textures/preview.png rename to src/main/resources/assets/island/textures/gui/sprites/preview.png diff --git a/src/main/resources/assets/island/textures/gui/sprites/toasts.png b/src/main/resources/assets/island/textures/gui/sprites/toasts.png new file mode 100644 index 0000000..65924c4 Binary files /dev/null and b/src/main/resources/assets/island/textures/gui/sprites/toasts.png differ diff --git a/src/main/resources/assets/island/textures/gui/sprites/upgrade.png b/src/main/resources/assets/island/textures/gui/sprites/upgrade.png new file mode 100644 index 0000000..18eb778 Binary files /dev/null and b/src/main/resources/assets/island/textures/gui/sprites/upgrade.png differ diff --git a/src/main/resources/assets/island/textures/gui/toasts.png b/src/main/resources/assets/island/textures/gui/toasts.png deleted file mode 100644 index 1fe19aa..0000000 Binary files a/src/main/resources/assets/island/textures/gui/toasts.png and /dev/null differ diff --git a/src/main/resources/islandutils.mixins.json b/src/main/resources/islandutils.mixins.json index 04c6754..9eb8cd5 100644 --- a/src/main/resources/islandutils.mixins.json +++ b/src/main/resources/islandutils.mixins.json @@ -4,16 +4,14 @@ "package": "net.asodev.islandutils.mixins", "compatibilityLevel": "JAVA_17", "mixins": [ - "FixOffhandSwapMixin", "ItemIDMixin", "accessors.WalkAnimStateAccessor", "cosmetics.ChestScreenMixin", "cosmetics.FontLoaderMixin", "cosmetics.PreviewTutorialMixin", "discord.ConnectionMixin", - "discord.PlayerTeamMixin", + "discord.ScoreDisplayMixin", "resources.PackRepositoryMixin", - "sounds.SoundSourceMixin", "ui.SlotMixin" ], "client": [ @@ -30,10 +28,10 @@ "notif.ServerSelectionMixin", "plobby.PlobbyChestMixin", "resources.MultiplayerJoinMixin", - "sounds.SoundOptionsMixin", "splits.HologramMixin", "ui.ChatScreenMixin", "ui.CommandSuggestionsAccessor", + "ui.FishingUpgradeHighlightMixin", "ui.OptionsMixin", "ui.PauseScreenMixin" ],