diff --git a/.gitignore b/.gitignore index bd2d25a030..8ff743604c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,7 @@ bin/ # fabric -run/ \ No newline at end of file +run/ +/commands +/.claude +CLAUDE.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000000..69cf1a59ce --- /dev/null +++ b/TODO.md @@ -0,0 +1,9 @@ +# TODO + +- [x] Port `NewerNewChunks` from Trouser-Streak into the existing `New Chunks` module. + - Source: https://github.com/etianl/Trouser-Streak/blob/main/src/main/java/pwn/noobs/trouserstreak/modules/NewerNewChunks.java + - [x] Keep the current implementation as an **Old** mode. + - [x] Add the Trouser-Streak implementation as a **New** mode. + - [x] Reuse existing settings wherever possible instead of duplicating them. + - [x] Simplify the settings by removing unnecessary options and combining equivalent ones where appropriate. + - [x] Preserve all functionality from both implementations. \ No newline at end of file diff --git a/build.gradle b/build.gradle index b4194542c4..12b9c477ea 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,11 @@ plugins { - id "fabric-loom" version "1.1-SNAPSHOT" + id "net.fabricmc.fabric-loom-remap" version "1.17-SNAPSHOT" id "maven-publish" } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 - -archivesBaseName = project.archives_base_name +base { + archivesName = project.archives_base_name +} version = project.mod_version group = project.maven_group @@ -44,8 +43,10 @@ processResources { } tasks.withType(JavaCompile).configureEach { - // Minecraft 1.18 (1.18-pre2) upwards uses Java 17. - it.options.release = 17 + // Minecraft 1.20.5 (1.20.5-pre1) upwards uses Java 21. + it.options.release = 21 + // ponytail: raised during the 1.21.11 port to see all errors per pass instead of the first 100; revert once green. + it.options.compilerArgs << "-Xmaxerrs" << "10000" } java { @@ -53,11 +54,14 @@ java { // if it is present. // If you remove this line, sources will not be generated. withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } jar { from("LICENSE") { - rename { "${it}-${project.archivesBaseName}"} + rename { "${it}-${project.archives_base_name}"} } } diff --git a/gradle.properties b/gradle.properties index 8121eab11b..dff685eb64 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,9 +5,9 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/use - minecraft_version=1.19.4 - yarn_mappings=1.19.4+build.1 - loader_version=0.14.17 + minecraft_version=1.21.11 + yarn_mappings=1.21.11+build.6 + loader_version=0.19.3 # Mod Properties mod_version = 1.2.6 @@ -15,4 +15,4 @@ org.gradle.parallel=true archives_base_name = bleachhack # Fabric api - # fabric_version = 0.76.0+1.19.4 + # fabric_version = 0.141.4+1.21.11 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6d7cd5de..ab236a62e5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists \ No newline at end of file diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/org/bleachhack/BleachHack.java b/src/main/java/org/bleachhack/BleachHack.java index 87338d1c6b..c6aeff4ae6 100644 --- a/src/main/java/org/bleachhack/BleachHack.java +++ b/src/main/java/org/bleachhack/BleachHack.java @@ -79,7 +79,7 @@ public void onInitialize() { BleachFileHelper.readFriends(); if (Option.GENERAL_CHECK_FOR_UPDATES.getValue()) { - updateJson = BleachOnlineMang.getResourceAsync("update/" + SharedConstants.getGameVersion().getName().replace(' ', '_') + ".json", BodyHandlers.ofString()) + updateJson = BleachOnlineMang.getResourceAsync("update/" + SharedConstants.getGameVersion().name().replace(' ', '_') + ".json", BodyHandlers.ofString()) .thenApply(s -> BleachJsonHelper.parseOrNull(s, JsonObject.class)); } diff --git a/src/main/java/org/bleachhack/command/CommandManager.java b/src/main/java/org/bleachhack/command/CommandManager.java index a467a52c54..c9df33e91a 100644 --- a/src/main/java/org/bleachhack/command/CommandManager.java +++ b/src/main/java/org/bleachhack/command/CommandManager.java @@ -114,7 +114,7 @@ public static void callCommand(String input) { BleachLogger.info( text.styled(style -> style - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, c.getHelpTooltip())))); + .withHoverEvent(new HoverEvent.ShowText(c.getHelpTooltip())))); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/org/bleachhack/command/CommandSuggestor.java b/src/main/java/org/bleachhack/command/CommandSuggestor.java index 6c3211a461..6fb1d77f87 100644 --- a/src/main/java/org/bleachhack/command/CommandSuggestor.java +++ b/src/main/java/org/bleachhack/command/CommandSuggestor.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Locale; import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventKeyPress; @@ -14,10 +15,10 @@ import org.lwjgl.glfw.GLFW; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.screen.ChatScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.network.PlayerListEntry; public class CommandSuggestor { @@ -61,7 +62,9 @@ public void onDrawOverlay(EventRenderInGameHud event) { curText = text; if (text.startsWith(Command.getPrefix())) { - suggestions.addAll(CommandManager.getSuggestionProvider().getSuggestions(text.substring(Command.getPrefix().length()).split(" ", -1))); + String[] typed = text.substring(Command.getPrefix().length()).split(" ", -1); + suggestions.addAll(CommandManager.getSuggestionProvider().getSuggestions(typed)); + addOnlinePlayerSuggestions(typed); } selected = 0; @@ -80,9 +83,6 @@ public void onDrawOverlay(EventRenderInGameHud event) { } if (!suggestions.isEmpty()) { - event.getMatrix().push(); - event.getMatrix().translate(0, 0, 200); - int length = suggestions.stream() .map(s -> MinecraftClient.getInstance().textRenderer.getWidth(s)) .min(Comparator.reverseOrder()).orElse(0); @@ -93,14 +93,12 @@ public void onDrawOverlay(EventRenderInGameHud event) { for (int i = scroll; i < suggestions.size() && i < scroll + 10; i++) { String suggestion = suggestions.get(i); - DrawableHelper.fill(event.getMatrix(), startX, startY, startX + length + 2, startY + 12, 0xd0000000); - MinecraftClient.getInstance().textRenderer.drawWithShadow( - event.getMatrix(), suggestion, startX + 1, startY + 2, i == selected ? 0xffff00: 0xb0b0b0); + event.getMatrix().fill(startX, startY, startX + length + 2, startY + 12, 0xd0000000); + event.getMatrix().drawTextWithShadow(MinecraftClient.getInstance().textRenderer, + suggestion, startX + 1, startY + 2, i == selected ? 0xffff00: 0xb0b0b0); startY += 12; } - - event.getMatrix().pop(); } } } @@ -137,6 +135,28 @@ public void onKeyPressChat(EventKeyPress.InChat event) { } } + // "$friends add "/"$friend add " - CommandSuggestionProvider only knows the + // "" placeholder from the syntax string, so swap it for real, currently-online names. + private void addOnlinePlayerSuggestions(String[] typed) { + if (typed.length != 3 || !typed[1].equalsIgnoreCase("add") + || !(typed[0].equalsIgnoreCase("friends") || typed[0].equalsIgnoreCase("friend")) + || MinecraftClient.getInstance().getNetworkHandler() == null) { + return; + } + + suggestions.removeIf(s -> s.matches("^<.*>$")); + + String prefix = typed[2].toLowerCase(Locale.ENGLISH); + for (PlayerListEntry entry : MinecraftClient.getInstance().getNetworkHandler().getPlayerList()) { + String name = entry.getProfile().name(); + if (name.toLowerCase(Locale.ENGLISH).startsWith(prefix)) { + suggestions.add(name); + } + } + + suggestions.sort(String.CASE_INSENSITIVE_ORDER); + } + private void updateScroll() { if (scroll > selected) { scroll = Math.max(selected, 0); diff --git a/src/main/java/org/bleachhack/command/commands/CmdClickGui.java b/src/main/java/org/bleachhack/command/commands/CmdClickGui.java index 0b9a176664..239a251c5e 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdClickGui.java +++ b/src/main/java/org/bleachhack/command/commands/CmdClickGui.java @@ -23,7 +23,7 @@ public class CmdClickGui extends Command { public CmdClickGui() { - super("clickgui", "Modify the clickgui windows.", "clickgui reset [open/closed] | clickgui length ", CommandCategory.MODULES); + super("clickgui", "Modify the clickgui windows, or change any other setting by name (e.g. \"$clickgui scale 150\").", "clickgui reset [open/closed] | clickgui length | clickgui ", CommandCategory.MODULES); } @Override @@ -71,7 +71,9 @@ public void onCommand(String alias, String[] args) throws Exception { BleachLogger.info("Set the clickgui length to: " + args[1]); } else { - throw new CmdSyntaxException(); + // "reset" and "length" above are this command's own subcommands, anything else falls + // through to the generic module-settings handler (e.g. "clickgui scale 150"). + CmdModuleSettings.applyArgs(ModuleManager.getModule(ClickGui.class), args); } } diff --git a/src/main/java/org/bleachhack/command/commands/CmdEnchant.java b/src/main/java/org/bleachhack/command/commands/CmdEnchant.java index 3098068e44..2ecc228cd3 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdEnchant.java +++ b/src/main/java/org/bleachhack/command/commands/CmdEnchant.java @@ -12,7 +12,12 @@ import java.util.Map; import java.util.Map.Entry; -import net.minecraft.registry.Registries; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ItemEnchantmentsComponent; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.math.NumberUtils; import org.bleachhack.command.Command; @@ -23,8 +28,6 @@ import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.Enchantments; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; import net.minecraft.text.MutableText; import net.minecraft.text.Style; @@ -33,7 +36,9 @@ public class CmdEnchant extends Command { - private static final Map enchantments = new LinkedHashMap<>(); + // 1.21.11 made enchantments a fully data-driven registry (RegistryKey, resolved + // through the world's DynamicRegistryManager) instead of a fixed static Registries.ENCHANTMENT. + private static final Map> enchantments = new LinkedHashMap<>(); static { enchantments.put(new String[] { "aqua_affinity", "aqua" }, Enchantments.AQUA_AFFINITY); @@ -70,7 +75,7 @@ public class CmdEnchant extends Command { enchantments.put(new String[] { "sharpness", "sharp" }, Enchantments.SHARPNESS); enchantments.put(new String[] { "silk_touch", "silk" }, Enchantments.SILK_TOUCH); enchantments.put(new String[] { "smite" }, Enchantments.SMITE); - enchantments.put(new String[] { "sweeping_edge", "sweep" }, Enchantments.SWEEPING); + enchantments.put(new String[] { "sweeping_edge", "sweep" }, Enchantments.SWEEPING_EDGE); enchantments.put(new String[] { "thorns" }, Enchantments.THORNS); enchantments.put(new String[] { "soul_speed", "soul" }, Enchantments.SOUL_SPEED); enchantments.put(new String[] { "unbreaking" }, Enchantments.UNBREAKING); @@ -105,44 +110,40 @@ public void onCommand(String alias, String[] args) throws Exception { } int level = args.length == 1 ? 1 : Integer.parseInt(args[1]); - ItemStack item = mc.player.getInventory().getMainHandStack(); + ItemStack item = mc.player.getMainHandStack(); + Registry registry = mc.world.getRegistryManager().getOrThrow(RegistryKeys.ENCHANTMENT); if (args[0].equalsIgnoreCase("all")) { - for (Enchantment e : Registries.ENCHANTMENT) { - enchant(item, e, level); - } - + registry.streamEntries().forEach(e -> enchant(item, e, level)); return; } int i = NumberUtils.toInt(args[0], -1); if (i != -1) { - enchant(item, Enchantment.byRawId(i), level); + enchant(item, registry.getEntry(i).orElse(null), level); } else { enchant(item, enchantments.entrySet().stream() .filter(e -> ArrayUtils.contains(e.getKey(), args[0])) .map(Entry::getValue) + .map(registry::getOptional) + .filter(java.util.Optional::isPresent) + .map(java.util.Optional::get) .findFirst().orElse(null), level); } } - public void enchant(ItemStack item, Enchantment e, int level) { + public void enchant(ItemStack item, RegistryEntry e, int level) { if (e == null) { throw new CmdSyntaxException("Invalid enchantment!"); } - if (item.getNbt() == null) - item.setNbt(new NbtCompound()); - if (!item.getNbt().contains("Enchantments", 9)) { - item.getNbt().put("Enchantments", new NbtList()); - } - - NbtList listnbt = item.getNbt().getList("Enchantments", 10); - NbtCompound compoundnbt = new NbtCompound(); - compoundnbt.putString("id", String.valueOf(Registries.ENCHANTMENT.getId(e))); - compoundnbt.putInt("lvl", level); - listnbt.add(compoundnbt); + // 1.19.4 stored enchantments as a raw "Enchantments" NBT list; ItemStack has no NBT access at + // all anymore - enchantments are a DataComponentTypes.ENCHANTMENTS component now. + ItemEnchantmentsComponent current = item.getOrDefault(DataComponentTypes.ENCHANTMENTS, ItemEnchantmentsComponent.DEFAULT); + ItemEnchantmentsComponent.Builder builder = new ItemEnchantmentsComponent.Builder(current); + builder.set(e, level); + item.set(DataComponentTypes.ENCHANTMENTS, builder.build()); } } diff --git a/src/main/java/org/bleachhack/command/commands/CmdEntityMenu.java b/src/main/java/org/bleachhack/command/commands/CmdEntityMenu.java index 1f859368af..f8efd60954 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdEntityMenu.java +++ b/src/main/java/org/bleachhack/command/commands/CmdEntityMenu.java @@ -22,12 +22,18 @@ public class CmdEntityMenu extends Command { public CmdEntityMenu() { - super("entitymenu", "Opens the gui to manage the things which appear on the entitymenu interaction screen.", "entitymenu", CommandCategory.MODULES, + super("entitymenu", "Opens the gui to manage the things which appear on the entitymenu interaction screen, or change a setting (e.g. \"$entitymenu playersonly true\", \"$entitymenu reset\").", + "entitymenu | entitymenu reset | entitymenu ", CommandCategory.MODULES, "playermenu", "interactionmenu"); } @Override public void onCommand(String alias, String[] args) throws Exception { + if (args.length > 0) { + CmdModuleSettings.applyArgs(ModuleManager.getModule(EntityMenu.class), args); + return; + } + MutablePairList interactions = ModuleManager.getModule(EntityMenu.class).interactions; BleachQueue.add(() -> mc.setScreen(new EntityMenuEditScreen(interactions))); diff --git a/src/main/java/org/bleachhack/command/commands/CmdEntityStats.java b/src/main/java/org/bleachhack/command/commands/CmdEntityStats.java index e4d72e28bb..76eec6a178 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdEntityStats.java +++ b/src/main/java/org/bleachhack/command/commands/CmdEntityStats.java @@ -60,7 +60,7 @@ public static double round(double value, int places) { } public static double getSpeed(AbstractHorseEntity horse) { - return round(20 * horse.getAttributeValue(EntityAttributes.GENERIC_MOVEMENT_SPEED), 2); + return round(20 * horse.getAttributeValue(EntityAttributes.MOVEMENT_SPEED), 2); } public static double getSpeedLiving(LivingEntity entity) { @@ -68,6 +68,7 @@ public static double getSpeedLiving(LivingEntity entity) { } public static double getJumpHeight(AbstractHorseEntity horse) { - return round(-0.1817584952 * Math.pow(horse.getJumpStrength(), 3) + 3.689713992 * Math.pow(horse.getJumpStrength(), 2) + 2.128599134 * horse.getJumpStrength() - 0.343930367, 3); + double jumpStrength = horse.getAttributeValue(EntityAttributes.JUMP_STRENGTH); + return round(-0.1817584952 * Math.pow(jumpStrength, 3) + 3.689713992 * Math.pow(jumpStrength, 2) + 2.128599134 * jumpStrength - 0.343930367, 3); } } diff --git a/src/main/java/org/bleachhack/command/commands/CmdFriends.java b/src/main/java/org/bleachhack/command/commands/CmdFriends.java index 5940a5a9b7..04947fa134 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdFriends.java +++ b/src/main/java/org/bleachhack/command/commands/CmdFriends.java @@ -22,8 +22,6 @@ import org.bleachhack.util.BleachLogger; import org.bleachhack.util.io.BleachFileHelper; -import java.util.Locale; - public class CmdFriends extends Command { public CmdFriends() { @@ -49,7 +47,7 @@ public void onCommand(String alias, String[] args) throws Exception { throw new CmdSyntaxException("No username selected"); } - BleachHack.friendMang.remove(args[1].toLowerCase(Locale.ENGLISH)); + BleachHack.friendMang.remove(args[1]); BleachLogger.info("Removed \"" + args[1] + "\" from the friend list"); } else if (args[0].equalsIgnoreCase("list")) { if (BleachHack.friendMang.getFriends().isEmpty()) { @@ -70,13 +68,13 @@ public void onCommand(String alias, String[] args) throws Exception { .withColor(BleachLogger.INFO_COLOR))) .append(Text.literal("\u00a7c[Del]") .styled(style -> style - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Remove " + f + " from your friendlist"))) - .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, getPrefix() + "friends remove " + f)))) + .withHoverEvent(new HoverEvent.ShowText(Text.literal("Remove " + f + " from your friendlist"))) + .withClickEvent(new ClickEvent.RunCommand(getPrefix() + "friends remove " + f)))) .append(" ") .append(Text.literal("\u00a73[NameMC]") .styled(style -> style - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Open NameMC page of " + f))) - .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://namemc.com/profile/" + f)))); + .withHoverEvent(new HoverEvent.ShowText(Text.literal("Open NameMC page of " + f))) + .withClickEvent(new ClickEvent.OpenUrl(java.net.URI.create("https://namemc.com/profile/" + f))))); } BleachLogger.info(text); diff --git a/src/main/java/org/bleachhack/command/commands/CmdGive.java b/src/main/java/org/bleachhack/command/commands/CmdGive.java index 56f06f3597..eac50ddd92 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdGive.java +++ b/src/main/java/org/bleachhack/command/commands/CmdGive.java @@ -9,12 +9,19 @@ package org.bleachhack.command.commands; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.serialization.Dynamic; +import net.minecraft.SharedConstants; +import net.minecraft.datafixer.Schemas; +import net.minecraft.datafixer.TypeReferences; import net.minecraft.item.AirBlockItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.StringNbtReader; import net.minecraft.registry.Registries; +import net.minecraft.registry.RegistryOps; import net.minecraft.util.Identifier; import org.apache.commons.lang3.math.NumberUtils; import org.bleachhack.command.Command; @@ -50,7 +57,7 @@ public void onCommand(String alias, String[] args) throws Exception { if (args[1].equalsIgnoreCase("negs")) { long dmg = args.length < 2 ? 0 : NumberUtils.toLong(args[1]); - tag = StringNbtReader.parse( + tag = StringNbtReader.readCompound( "{display:{Name:\"{\\\"text\\\":\\\"Bleach's Negative Items\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},BlockEntityTag:{Items:[{Slot:0b,id:\"minecraft:diamond_sword\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Negative Sword\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Damage:" + (dmg == 0 ? 1981 : dmg) + ",Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:1b,id:\"minecraft:diamond_sword\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Negative Sword\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Damage:" @@ -107,15 +114,15 @@ public void onCommand(String alias, String[] args) throws Exception { + (dmg == 0 ? 1981 : dmg) + ",Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}}]}}"); } else if (args[1].equalsIgnoreCase("stacked")) { - tag = StringNbtReader.parse( + tag = StringNbtReader.readCompound( "{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Items\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},BlockEntityTag:{Items:[{Slot:0b,id:\"minecraft:diamond_helmet\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Helmet\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:1b,id:\"minecraft:diamond_chestplate\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Chestplate\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:2b,id:\"minecraft:diamond_leggings\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Leggings\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:3b,id:\"minecraft:diamond_boots\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Boots\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:4b,id:\"minecraft:diamond_sword\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Sword\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:5b,id:\"minecraft:diamond_shovel\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Shovel\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:6b,id:\"minecraft:diamond_pickaxe\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Pickaxe\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:7b,id:\"minecraft:diamond_axe\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Axe\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:8b,id:\"minecraft:diamond_hoe\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Hoe\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:9b,id:\"minecraft:water_bucket\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Water Bucket\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:10b,id:\"minecraft:lava_bucket\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Lava Buckets\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:11b,id:\"minecraft:milk_bucket\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Milk Buckets\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:12b,id:\"minecraft:bow\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Bows\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:13b,id:\"minecraft:fishing_rod\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Fishing Rods\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},Enchantments:[{id:\"minecraft:vanishing_curse\",lvl:1s}]}},{Slot:14b,id:\"minecraft:writable_book\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Book And Quills\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},pages:[\"\"]}},{Slot:15b,id:\"minecraft:enchanted_book\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Enchanted Books\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:16b,id:\"minecraft:saddle\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Saddles\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:17b,id:\"minecraft:potion\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Bottles\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:18b,id:\"minecraft:music_disc_11\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:19b,id:\"minecraft:music_disc_13\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:20b,id:\"minecraft:music_disc_blocks\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:21b,id:\"minecraft:music_disc_cat\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:22b,id:\"minecraft:music_disc_chirp\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:23b,id:\"minecraft:music_disc_far\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:24b,id:\"minecraft:music_disc_mall\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:25b,id:\"minecraft:music_disc_mellohi\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:26b,id:\"minecraft:music_disc_stal\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Stacked Discs\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}}]}}"); } else if (args[1].equalsIgnoreCase("spawners")) { - tag = StringNbtReader.parse( + tag = StringNbtReader.readCompound( "{display:{Name:\"{\\\"text\\\":\\\"Bleach's Spawners\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},BlockEntityTag:{Items:[{Slot:0b,id:\"minecraft:spawner\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Pig Spawners\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"}}},{Slot:1b,id:\"minecraft:spawner\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Lag Spawners\\\",\\\"color\\\":\\\"dark_red\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},BlockEntityTag:{SpawnCount:32767,SpawnRange:32767,Delay:0,MinSpawnDelay:0,MaxSpawnDelay:0,MaxNearbyEntities:32767,RequiredPlayerRange:32767}}},{Slot:2b,id:\"minecraft:spawner\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Lag Spawners #2\\\",\\\"color\\\":\\\"dark_red\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},BlockEntityTag:{SpawnCount:32767,SpawnRange:32767,Delay:0,MinSpawnDelay:0,MaxSpawnDelay:0,MaxNearbyEntities:32767,RequiredPlayerRange:32767}}},{Slot:3b,id:\"minecraft:spawner\",Count:64b,tag:{display:{Name:\"{\\\"text\\\":\\\"Bleach's Tnt Spawners\\\",\\\"color\\\":\\\"aqua\\\",\\\"bold\\\":true,\\\"italic\\\":true,\\\"underlined\\\":true}\"},BlockEntityTag:{SpawnCount:50,SpawnRange:10,Delay:0,MinSpawnDelay:0,MaxSpawnDelay:0,MaxNearbyEntities:32767,RequiredPlayerRange:32767,SpawnData:{id:\"minecraft:tnt\",Fuse:1}}}},{Slot:4b,id:\"minecraft:spawner\",Count:64b,tag:{display:{Name:'{\"text\":\"Bleach\\'s Boat Spawner\",\"color\":\"aqua\",\"bold\":true,\"italic\":true,\"underlined\":true}'},BlockEntityTag:{SpawnCount:50,SpawnRange:10,SpawnData:{id:\"minecraft:boat\",Glowing:1b,Invulnerable:1b,CustomNameVisible:1b,Type:\"jungle\",CustomName:'{\"text\":\"Bleach_Knight Ontop\",\"color\":\"aqua\",\"bold\":true,\"italic\":true,\"underlined\":true}'}}}}]}}"); } else if (args[1].equalsIgnoreCase("bookban")) { - tag = StringNbtReader.parse( + tag = StringNbtReader.readCompound( "{display:{Name:'{\"text\":\"Bleach\\'s Bookban Shulker\",\"color\":\"aqua\",\"bold\":true,\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:0b,id:\"minecraft:writable_book\",Count:16b,tag:{display:{Name:'{\"text\":\"BLEACHHACK OWNS ALL\",\"color\":\"dark_red\",\"bold\":true}'},pages:[" + getBookbanTag() + "]}},{Slot:1b,id:\"minecraft:writable_book\",Count:16b,tag:{display:{Name:'{\"text\":\"BLEACHHACK OWNS ALL\",\"color\":\"dark_red\",\"bold\":true}'},pages:[" @@ -182,7 +189,7 @@ else if (args[1].equalsIgnoreCase("test")) { for (int i = 0; i < 100; i++) s += "," + r.nextInt(16777215); - tag = StringNbtReader.parse("{BlockEntityTag:{Items:[{Slot:0b,id:\"minecraft:firework_rocket\",Count:1b,tag:{Fireworks:{Explosions:[{Type:0}" + s1 + tag = StringNbtReader.readCompound("{BlockEntityTag:{Items:[{Slot:0b,id:\"minecraft:firework_rocket\",Count:1b,tag:{Fireworks:{Explosions:[{Type:0}" + s1 + "]}}},{Slot:1b,id:\"minecraft:firework_rocket\",Count:64b,tag:{Fireworks:{Flight:127b,Explosions:[{Type:0,Flicker:1b,Trail:1b,Colors:[I;16711680],FadeColors:[I;16711680" + s + "]},{Type:1,Flicker:1b,Trail:1b,Colors:[I;16711680],FadeColors:[I;16711680" + s + "]},{Type:2,Flicker:1b,Trail:1b,Colors:[I;16711680" + s + "],FadeColors:[I;16711680" + s + "]},{Type:3,Flicker:1b,Trail:1b,Colors:[I;16711680" + s + "],FadeColors:[I;16711680" + s @@ -190,29 +197,33 @@ else if (args[1].equalsIgnoreCase("test")) { + "]}]}}},{Slot:2b,id:\"minecraft:lingering_potion\",Count:64b,tag:{display:{Name:'{\"text\":\"Bleach\\'s B R U H M O M E N T Potion\",\"color\":\"aqua\",\"bold\":true,\"italic\":true}'},AttributeModifiers:[{AttributeName:\"generic.maxHealth\",Name:\"generic.maxHealth\",Amount:1,Operation:0,UUIDLeast:338793,UUIDMost:213301}],CustomPotionEffects:[{Id:1b,Amplifier:127b,Duration:32767},{Id:2b,Amplifier:127b,Duration:32767},{Id:3b,Amplifier:127b,Duration:32767},{Id:4b,Amplifier:127b,Duration:32767},{Id:5b,Amplifier:127b,Duration:32767},{Id:6b,Amplifier:127b,Duration:32767},{Id:7b,Amplifier:127b,Duration:32767},{Id:8b,Amplifier:127b,Duration:32767},{Id:9b,Amplifier:127b,Duration:32767},{Id:10b,Amplifier:127b,Duration:32767},{Id:11b,Amplifier:127b,Duration:32767},{Id:12b,Amplifier:127b,Duration:32767},{Id:13b,Amplifier:127b,Duration:32767},{Id:14b,Amplifier:127b,Duration:32767},{Id:15b,Amplifier:127b,Duration:32767},{Id:16b,Amplifier:127b,Duration:32767},{Id:17b,Amplifier:127b,Duration:32767},{Id:18b,Amplifier:127b,Duration:32767},{Id:19b,Amplifier:127b,Duration:32767},{Id:20b,Amplifier:127b,Duration:32767},{Id:21b,Amplifier:127b,Duration:32767},{Id:22b,Amplifier:127b,Duration:32767},{Id:23b,Amplifier:127b,Duration:32767},{Id:24b,Amplifier:127b,Duration:32767},{Id:25b,Amplifier:127b,Duration:32767},{Id:26b,Amplifier:127b,Duration:32767},{Id:27b,Amplifier:127b,Duration:32767},{Id:28b,Amplifier:127b,Duration:32767},{Id:29b,Amplifier:127b,Duration:32767},{Id:30b,Amplifier:127b,Duration:32767},{Id:31b,Amplifier:127b,Duration:32767}],Potion:\"minecraft:leaping\"}},{Slot:3b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:13b,id:\"minecraft:pink_shulker_box\",Count:64b,tag:{display:{Name:'{\"text\":\"nested shulker boxes\",\"color\":\"red\",\"italic\":true,\"underlined\":true}'}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}}]}}},{Slot:4b,id:\"minecraft:chicken_spawn_egg\",Count:1b,tag:{EntityTag:{id:\"minecraft:spawner_minecart\",CustomDisplayTile:1b,Delay:1,MinSpawnDelay:0,MaxSpawnDelay:0,MaxNearbyEntities:1000,RequiredPlayerRange:100,DisplayState:{Name:\"minecraft:acacia_door\",Properties:{half:\"upper\",hinge:\"left\",open:\"true\"}},SpawnData:{id:\"minecraft:minecart\"}}}}]}}"); } else if (args[1].equalsIgnoreCase("eggs")) { - tag = StringNbtReader.parse( + tag = StringNbtReader.readCompound( "{display:{Name:'{\"text\":\"Bleach\\'s Spawn Eggs\",\"color\":\"aqua\",\"bold\":true,\"italic\":true,\"underlined\":true}'},BlockEntityTag:{Items:[{Slot:0b,id:\"minecraft:zombie_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Spawn Giant\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:giant\",Invulnerable:1b,Glowing:1b}}},{Slot:1b,id:\"minecraft:enderman_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Enderman With Cmd block\",\"color\":\"aqua\"}'},EntityTag:{carriedBlockState:{Name:\"minecraft:command_block\",Properties:{conditional:\"true\"}}}}},{Slot:2b,id:\"minecraft:bat_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Cmd minecart (kill @a)\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:command_block_minecart\",Command:\"kill @a\"}}},{Slot:3b,id:\"minecraft:bat_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Spawner minecart (turn particles off)\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:spawner_minecart\",SpawnData:{id:\"minecraft:armor_stand\"}}}},{Slot:4b,id:\"minecraft:cave_spider_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"E G G\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:egg\",NoGravity:1b,Fire:2100000000,Glowing:1b}}},{Slot:5b,id:\"minecraft:stray_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"area_effect_cloud (50 range)\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:area_effect_cloud\",Particle:\"angry_villager\",ReapplicationDelay:1,Radius:50f,RadiusPerTick:0f,RadiusOnUse:0f,Duration:500000,DurationOnUse:0f,Color:16711680,Potion:\"minecraft:strong_swiftness\"}}},{Slot:6b,id:\"minecraft:evoker_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"area_effect_cloud (E X P A N D)\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:area_effect_cloud\",Particle:\"angry_villager\",Radius:1f,RadiusPerTick:10f,RadiusOnUse:1f,Duration:10000}}},{Slot:7b,id:\"minecraft:elder_guardian_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Arrow (End Portal Sound)\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:arrow\",pickup:1b,SoundEvent:\"block.end_portal.spawn\"}}},{Slot:8b,id:\"minecraft:elder_guardian_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Arrow (EG Curse Sound)\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:arrow\",pickup:1b,SoundEvent:\"entity.elder_guardian.curse\"}}},{Slot:9b,id:\"minecraft:drowned_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Big chungus slime\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:slime\",Size:50}}},{Slot:10b,id:\"minecraft:fox_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Invis Armor Stand\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:armor_stand\",Invulnerable:1b,Invisible:1b,PersistenceRequired:1b,ArmorItems:[{},{},{},{id:\"minecraft:spawner\",Count:1b}]}}},{Slot:11b,id:\"minecraft:ghast_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Enderdragon\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:ender_dragon\",DragonPhase:8}}},{Slot:12b,id:\"minecraft:cow_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Lightning\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:lightning_bolt\"}}},{Slot:13b,id:\"minecraft:guardian_spawn_egg\",Count:1b,tag:{EntityTag:{id:\"minecraft:iron_golem\"}}},{Slot:14b,id:\"minecraft:evoker_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"area_effect_cloud (expand slow)\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:area_effect_cloud\",Particle:\"angry_villager\",Radius:1f,RadiusPerTick:10f,RadiusOnUse:1f,Duration:1000000}}},{Slot:15b,id:\"minecraft:bee_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Tnt Minecart\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:tnt_minecart\",TNTFuse:1000000}}},{Slot:16b,id:\"minecraft:bat_spawn_egg\",Count:1b,tag:{display:{Name:'{\"text\":\"Invalid translate name test\",\"color\":\"aqua\"}'},EntityTag:{id:\"minecraft:boat\",CustomNameVisible:1b,Type:\"acacia\",CustomName:'{\"translate\":\"translation.test.invalid\"}'}}}]}}"); } else { BleachLogger.error("Invalid preset!"); return; } + NbtCompound legacyStack = new NbtCompound(); + legacyStack.putString("id", Registries.ITEM.getId(item.getItem()).toString()); + legacyStack.putByte("Count", (byte) 1); + if (args2.equalsIgnoreCase("egg")) { NbtCompound ct = new NbtCompound(); - ct.put("EntityTag", StringNbtReader.parse("{Time:1,id:\"minecraft:falling_block\",BlockState:{Name:\"minecraft:chest\"}}")); + ct.put("EntityTag", StringNbtReader.readCompound("{Time:1,id:\"minecraft:falling_block\",BlockState:{Name:\"minecraft:chest\"}}")); ((NbtCompound) ct.get("EntityTag")).put("TileEntityData", tag.get("BlockEntityTag")); - item.setNbt(ct); + legacyStack.put("tag", ct); } else { - item.setNbt(tag); + legacyStack.put("tag", tag); } - mc.player.getInventory().insertStack(item); + mc.player.getInventory().insertStack(legacyNbtToItemStack(legacyStack)); return; } ItemStack item = new ItemStack( - Registries.ITEM.get(new Identifier("minecraft:" + args[0].toLowerCase(Locale.ENGLISH)))); + Registries.ITEM.get(Identifier.of("minecraft:" + args[0].toLowerCase(Locale.ENGLISH)))); if (item.getItem() instanceof AirBlockItem) throw new CmdSyntaxException(); @@ -223,13 +234,38 @@ else if (args[1].equalsIgnoreCase("eggs")) { item.setDamage(NumberUtils.createNumber(args[2]).intValue()); if (args.length >= 4) try { - item.setNbt(StringNbtReader.parse(args[3])); + NbtCompound legacyStack = new NbtCompound(); + legacyStack.putString("id", Registries.ITEM.getId(item.getItem()).toString()); + legacyStack.putByte("Count", (byte) 1); + legacyStack.put("tag", StringNbtReader.readCompound(args[3])); + + item.applyComponentsFrom(legacyNbtToItemStack(legacyStack).getComponents()); } catch (CommandSyntaxException ignored) { } mc.player.getInventory().insertStack(item); } + // 1.19.4 built modified items via the old raw-NBT ItemStack format ("tag" holding Damage, + // Enchantments, display, BlockEntityTag, EntityTag, ...) and slammed it on with setNbt(). 1.21.11 + // replaced all of that with typed DataComponents and removed setNbt()/getNbt() entirely, so there's + // no direct way to attach a legacy tag to a stack anymore. Instead this rebuilds the old + // pre-componentization {id, Count, tag} shape and runs it through the exact DataFixerUpper pipeline + // vanilla itself uses to upgrade old worlds/structures/schematics - ItemStackComponentizationFix + // (registered against TypeReferences.ITEM_STACK) converts the legacy tag into real components, so + // every preset above works unmodified instead of being hand-rewritten component by component. + private static final int LEGACY_DATA_VERSION = 3337; // 1.19.4 + + private ItemStack legacyNbtToItemStack(NbtCompound legacyStackNbt) { + Dynamic dynamic = new Dynamic<>(NbtOps.INSTANCE, legacyStackNbt); + NbtElement fixed = Schemas.getFixer() + .update(TypeReferences.ITEM_STACK, dynamic, LEGACY_DATA_VERSION, SharedConstants.getGameVersion().dataVersion().id()) + .getValue(); + + RegistryOps registryOps = RegistryOps.of(NbtOps.INSTANCE, mc.world.getRegistryManager()); + return ItemStack.CODEC.parse(registryOps, fixed).result().orElse(ItemStack.EMPTY); + } + private String getBookbanTag() { String book = ""; String page = ""; diff --git a/src/main/java/org/bleachhack/command/commands/CmdHelp.java b/src/main/java/org/bleachhack/command/commands/CmdHelp.java index bc47426599..79a6d6f5a7 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdHelp.java +++ b/src/main/java/org/bleachhack/command/commands/CmdHelp.java @@ -46,7 +46,7 @@ public void onCommand(String alias, String[] args) throws Exception { BleachLogger.noPrefix( text.styled(style -> style - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, c.getHelpTooltip())))); + .withHoverEvent(new HoverEvent.ShowText(c.getHelpTooltip())))); } } diff --git a/src/main/java/org/bleachhack/command/commands/CmdInvPeek.java b/src/main/java/org/bleachhack/command/commands/CmdInvPeek.java index 9a9e5e9f46..bf841612fe 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdInvPeek.java +++ b/src/main/java/org/bleachhack/command/commands/CmdInvPeek.java @@ -8,19 +8,17 @@ */ package org.bleachhack.command.commands; -import net.minecraft.client.gui.DrawableHelper; import org.bleachhack.command.Command; import org.bleachhack.command.CommandCategory; import org.bleachhack.command.exception.CmdSyntaxException; import org.bleachhack.util.BleachLogger; import org.bleachhack.util.BleachQueue; -import com.mojang.blaze3d.systems.RenderSystem; - +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ingame.InventoryScreen; import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.util.math.MatrixStack; public class CmdInvPeek extends Command { @@ -41,16 +39,14 @@ public void onCommand(String alias, String[] args) throws Exception { BleachLogger.info("Opened inventory for " + e.getDisplayName().getString()); mc.setScreen(new InventoryScreen(e) { - public boolean mouseClicked(double mouseX, double mouseY, int button) { + @Override + public boolean mouseClicked(Click click, boolean doubled) { return false; } - protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { - RenderSystem.setShader(GameRenderer::getPositionTexProgram); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, BACKGROUND_TEXTURE); - drawTexture(matrices, x, y, 0, 0, this.backgroundWidth, this.backgroundHeight); - drawEntity(matrices, x + 51, y + 75, 30, (float) (x + 51) - mouseX, (float) (y + 75 - 50) - mouseY, this.client.player); + protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { + context.drawTexture(RenderPipelines.GUI_TEXTURED, BACKGROUND_TEXTURE, x, y, 0.0F, 0.0F, this.backgroundWidth, this.backgroundHeight, 256, 256); + drawEntity(context, x + 26, y + 8, x + 75, y + 78, 30, 0.0625F, mouseX, mouseY, this.client.player); } }); }); diff --git a/src/main/java/org/bleachhack/command/commands/CmdModuleSettings.java b/src/main/java/org/bleachhack/command/commands/CmdModuleSettings.java new file mode 100644 index 0000000000..df5deeffcd --- /dev/null +++ b/src/main/java/org/bleachhack/command/commands/CmdModuleSettings.java @@ -0,0 +1,261 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.command.commands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import net.minecraft.text.HoverEvent; +import net.minecraft.text.Text; + +import org.bleachhack.command.Command; +import org.bleachhack.command.CommandCategory; +import org.bleachhack.command.CommandManager; +import org.bleachhack.command.exception.CmdSyntaxException; +import org.bleachhack.module.Module; +import org.bleachhack.module.ModuleManager; +import org.bleachhack.setting.module.ModuleSetting; +import org.bleachhack.setting.module.SettingMode; +import org.bleachhack.setting.module.SettingSlider; +import org.bleachhack.setting.module.SettingToggle; +import org.bleachhack.util.BleachLogger; + +// One command class, one alias per module - lets "! reset" and +// "! " work for every module without hand-writing a command +// class per module. Aliases are built from whatever's in ModuleManager at load time, which runs +// after modules are loaded (see BleachHack.postInit). Modules that already have their own dedicated +// command (Notebot, Spammer, EntityMenu, ClickGui, ...) are skipped here - see moduleAliases() - and +// that command calls applyArgs() itself instead, so there's only ever one command per module name. +// This class must be last in bleachhack.commands.json so every other command is already loaded by +// the time moduleAliases() checks for existing aliases. +public class CmdModuleSettings extends Command { + + private static final String DISPLAY_SYNTAX = " reset | "; + + public CmdModuleSettings() { + super("modulesettings", "Reset a module's settings, or change one by name (e.g. \"$criticals mode Packet\", \"$criticals reset\").", + DISPLAY_SYNTAX, CommandCategory.MODULES, moduleAliases()); + } + + private static String[] moduleAliases() { + Set reserved = new HashSet<>(); + for (Command c : CommandManager.getCommands()) { + for (String a : c.getAliases()) { + reserved.add(a.toLowerCase(Locale.ENGLISH)); + } + } + + List names = new ArrayList<>(); + for (Module m : ModuleManager.getModules()) { + if (!reserved.contains(m.getName().toLowerCase(Locale.ENGLISH))) { + names.add(m.getName()); + } + } + return names.toArray(new String[0]); + } + + // CommandManager feeds getSyntax() straight into the tab-complete tree, and that tree can only + // match literal words, not the "" placeholder used for the human-readable syntax above. + // So build one literal branch per real module name (lowercase, since the tree's top-level match + // is case-sensitive and every other literal keyword in this command system is lowercase) purely + // to drive suggestions. getHelpTooltip() below keeps showing the readable placeholder version. + @Override + public String getSyntax() { + Set owned = new HashSet<>(); + for (String a : getAliases()) { + owned.add(a.toLowerCase(Locale.ENGLISH)); + } + + StringBuilder sb = new StringBuilder(); + for (Module m : ModuleManager.getModules()) { + String name = m.getName().toLowerCase(Locale.ENGLISH); + if (!owned.contains(name)) { + continue; + } + + sb.append(sb.length() > 0 ? " | " : "").append(name).append(" reset"); + appendSettingSyntax(sb, name, m.getSettings()); + } + return sb.toString(); + } + + // One branch per settable setting, so tab-complete offers the actual names ("$sneak Mode") + // instead of a "" placeholder. Values only get suggested where the set of valid ones is + // known - modes and toggles become [a/b/c] alternatives, sliders stay a free since any + // number in range goes. Setting types applyValue() can't handle are left out entirely. + public static void appendSettingSyntax(StringBuilder sb, String prefix, List> settings) { + for (ModuleSetting setting : settings) { + String name = dashed(setting.getName()); + + if (setting instanceof SettingToggle toggle) { + sb.append(" | ").append(prefix).append(' ').append(name).append(" [on/off]"); + appendSettingSyntax(sb, prefix, toggle.getChildren()); + } else if (setting instanceof SettingMode mode) { + sb.append(" | ").append(prefix).append(' ').append(name).append(" ["); + for (int i = 0; i < mode.modes.length; i++) { + sb.append(i > 0 ? "/" : "").append(dashed(mode.modes[i])); + } + sb.append(']'); + } else if (setting instanceof SettingSlider) { + sb.append(" | ").append(prefix).append(' ').append(name).append(" "); + } + } + } + + // The suggestion tree splits on spaces, and so does the command parser - see sameName(). + private static String dashed(String name) { + return name.replace(' ', '-'); + } + + @Override + public Text getHelpTooltip() { + return Text.literal("§7Category: " + getCategory() + "\n") + .append("Aliases: §f" + getPrefix() + String.join(" §7/§f " + getPrefix(), getAliases()) + "\n").styled(s -> s.withColor(BleachLogger.INFO_COLOR)) + .append("Usage: §f" + DISPLAY_SYNTAX + "\n").styled(s -> s.withColor(BleachLogger.INFO_COLOR)) + .append("Description: §f" + getDescription()).styled(s -> s.withColor(BleachLogger.INFO_COLOR)); + } + + @Override + public void onCommand(String alias, String[] args) throws Exception { + Module module = null; + for (Module m : ModuleManager.getModules()) { + if (m.getName().equalsIgnoreCase(alias)) { + module = m; + break; + } + } + + if (module == null) { + throw new CmdSyntaxException(); + } + + applyArgs(module, args); + } + + // Shared with commands for modules that already have a dedicated command (Notebot, Spammer, + // EntityMenu, ClickGui, ...) so "reset"/" " works there too instead of only + // through this class's own per-module aliases. + public static void applyArgs(Module module, String[] args) throws CmdSyntaxException { + if (args.length == 0) { + throw new CmdSyntaxException(); + } + + if (args[0].equalsIgnoreCase("reset")) { + for (ModuleSetting setting : module.getSettings()) { + resetRecursive(setting); + } + + BleachLogger.info("Reset all settings on §f" + module.getName() + "§r."); + return; + } + + if (args.length < 2) { + throw new CmdSyntaxException(); + } + + ModuleSetting setting = findSetting(module.getSettings(), args[0]); + if (setting == null) { + throw new CmdSyntaxException("No setting named \"" + args[0] + "\" on " + module.getName() + "."); + } + + String value = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); + String result = applyValue(setting, value); + if (result == null) { + throw new CmdSyntaxException("Couldn't set \"" + setting.getName() + "\" to \"" + value + "\"."); + } + + BleachLogger.info("Set §f" + setting.getName() + "§r to §f" + result + "§r."); + } + + private static void resetRecursive(ModuleSetting setting) { + setting.resetValue(); + + if (setting instanceof SettingToggle toggle) { + for (ModuleSetting child : toggle.getChildren()) { + resetRecursive(child); + } + } + } + + // Chat commands split on spaces, so a setting/value name with a space in it (e.g. "XP Bottles") + // can never be typed as-is - accept it dash-separated instead ("xp-bottles") on top of the real name. + private static boolean sameName(String actual, String typed) { + return actual.equalsIgnoreCase(typed) || actual.replace(' ', '-').equalsIgnoreCase(typed); + } + + private static ModuleSetting findSetting(List> settings, String name) { + for (ModuleSetting setting : settings) { + if (sameName(setting.getName(), name)) { + return setting; + } + + if (setting instanceof SettingToggle toggle) { + ModuleSetting found = findSetting(toggle.getChildren(), name); + if (found != null) { + return found; + } + } + } + + return null; + } + + // Only the common, plain-value setting types are supported from chat - Color/BlockList/ + // ItemList/Keybind settings need more structured input than a single command argument can + // give them cleanly, so they're left to the ClickGui. + private static String applyValue(ModuleSetting setting, String value) { + if (setting instanceof SettingToggle toggle) { + boolean state = value.equalsIgnoreCase("true") || value.equalsIgnoreCase("on") || value.equals("1"); + boolean off = value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off") || value.equals("0"); + if (!state && !off) { + return null; + } + + toggle.setValue(state); + return state ? "on" : "off"; + } + + if (setting instanceof SettingMode mode) { + for (int i = 0; i < mode.modes.length; i++) { + if (sameName(mode.modes[i], value)) { + mode.setValue(i); + return mode.modes[i]; + } + } + + try { + int index = Integer.parseInt(value); + if (index >= 0 && index < mode.modes.length) { + mode.setValue(index); + return mode.modes[index]; + } + } catch (NumberFormatException ignored) {} + + return null; + } + + if (setting instanceof SettingSlider slider) { + try { + double parsed = Double.parseDouble(value); + double clamped = Math.max(slider.min, Math.min(slider.max, parsed)); + slider.setValue(clamped); + return String.valueOf(slider.getValue()); + } catch (NumberFormatException e) { + return null; + } + } + + return null; + } + +} diff --git a/src/main/java/org/bleachhack/command/commands/CmdNBT.java b/src/main/java/org/bleachhack/command/commands/CmdNBT.java index 9b5d571ec1..eec1af1591 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdNBT.java +++ b/src/main/java/org/bleachhack/command/commands/CmdNBT.java @@ -17,10 +17,13 @@ import org.bleachhack.util.io.BleachJsonHelper; import net.minecraft.block.entity.BlockEntity; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtHelper; import net.minecraft.nbt.StringNbtReader; +import net.minecraft.predicate.NbtPredicate; import net.minecraft.text.ClickEvent; import net.minecraft.text.HoverEvent; @@ -55,9 +58,9 @@ public void onCommand(String alias, String[] args) throws Exception { Text copy = Text.literal("\u00a7e\u00a7l") .styled(s -> s.withClickEvent( - new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, textNbt.getString())) + new ClickEvent.CopyToClipboard(textNbt.getString())) .withHoverEvent( - new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Copy the nbt of this item to your clipboard")))); + new HoverEvent.ShowText(Text.literal("Copy the nbt of this item to your clipboard")))); BleachLogger.info(Text.literal("\u00a76\u00a7lNBT: ").append(copy).append("\u00a76\n" + textNbt)); } @@ -83,15 +86,18 @@ public void onCommand(String alias, String[] args) throws Exception { } ItemStack item = mc.player.getMainHandStack(); - item.setNbt(StringNbtReader.parse(StringUtils.join(ArrayUtils.subarray(args, 1, args.length), ' '))); - BleachLogger.info("\u00a76Set NBT of " + item.getItem().getName().getString() + " to\n" + BleachJsonHelper.formatJson(item.getNbt().toString())); + // ported: 1.19.4 let you edit the item's whole raw nbt tag; 1.21.11 splits that tag into + // typed components (damage, enchantments, ...) plus a free-form DataComponentTypes.CUSTOM_DATA + // blob (NbtComponent) for anything else, so "nbt set/wipe/get hand" now target that component. + item.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(StringNbtReader.readCompound(StringUtils.join(ArrayUtils.subarray(args, 1, args.length), ' ')))); + BleachLogger.info("\u00a76Set NBT of " + item.getItem().getName().getString() + " to\n" + BleachJsonHelper.formatJson(item.getOrDefault(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT).copyNbt().toString())); } else if (args[0].equalsIgnoreCase("wipe")) { if (!mc.interactionManager.getCurrentGameMode().isCreative()) { BleachLogger.error("You must be in creative mode to wipe NBT!"); return; } - mc.player.getMainHandStack().setNbt(new NbtCompound()); + mc.player.getMainHandStack().remove(DataComponentTypes.CUSTOM_DATA); } else { throw new CmdSyntaxException(); } @@ -99,7 +105,7 @@ public void onCommand(String alias, String[] args) throws Exception { private NbtCompound getNbt(String arg) { if (arg.equalsIgnoreCase("hand")) { - return mc.player.getMainHandStack().getOrCreateNbt(); + return mc.player.getMainHandStack().getOrDefault(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT).copyNbt(); } else if (arg.equalsIgnoreCase("block")) { HitResult target = mc.crosshairTarget; if (target.getType() == HitResult.Type.BLOCK) { @@ -107,7 +113,7 @@ private NbtCompound getNbt(String arg) { BlockEntity be = mc.world.getBlockEntity(pos); if (be != null) { - return be.createNbt(); + return be.createNbt(mc.world.getRegistryManager()); } else { return new NbtCompound(); } @@ -118,7 +124,7 @@ private NbtCompound getNbt(String arg) { } else if (arg.equalsIgnoreCase("entity")) { HitResult target = mc.crosshairTarget; if (target.getType() == HitResult.Type.ENTITY) { - return ((EntityHitResult) target).getEntity().writeNbt(new NbtCompound()); + return NbtPredicate.entityToNbt(((EntityHitResult) target).getEntity()); } BleachLogger.error("Not looking at an entity."); diff --git a/src/main/java/org/bleachhack/command/commands/CmdNotebot.java b/src/main/java/org/bleachhack/command/commands/CmdNotebot.java index 8d7c683aa9..6eb34cd175 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdNotebot.java +++ b/src/main/java/org/bleachhack/command/commands/CmdNotebot.java @@ -11,17 +11,23 @@ import org.bleachhack.command.Command; import org.bleachhack.command.CommandCategory; import org.bleachhack.gui.NotebotScreen; +import org.bleachhack.module.ModuleManager; import org.bleachhack.util.BleachQueue; public class CmdNotebot extends Command { public CmdNotebot() { - super("notebot", "Shows the notebot gui.", "notebot", CommandCategory.MODULES); + super("notebot", "Shows the notebot gui, or change a setting (e.g. \"$notebot loop true\", \"$notebot reset\").", "notebot | notebot reset | notebot ", CommandCategory.MODULES); } @Override public void onCommand(String alias, String[] args) throws Exception { - BleachQueue.add(() -> mc.setScreen(new NotebotScreen())); + if (args.length == 0) { + BleachQueue.add(() -> mc.setScreen(new NotebotScreen())); + return; + } + + CmdModuleSettings.applyArgs(ModuleManager.getModule("Notebot"), args); } } diff --git a/src/main/java/org/bleachhack/command/commands/CmdPeek.java b/src/main/java/org/bleachhack/command/commands/CmdPeek.java index 8c30216be6..4dc280ba92 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdPeek.java +++ b/src/main/java/org/bleachhack/command/commands/CmdPeek.java @@ -19,6 +19,7 @@ import net.minecraft.text.Text; import org.bleachhack.command.Command; import org.bleachhack.command.CommandCategory; +import org.bleachhack.module.ModuleManager; import org.bleachhack.util.BleachLogger; import org.bleachhack.util.BleachQueue; import org.bleachhack.util.ItemContentUtils; @@ -28,12 +29,17 @@ public class CmdPeek extends Command { public CmdPeek() { - super("peek", "Shows whats inside the container you're holder.", "peek", CommandCategory.MISC); + super("peek", "Shows whats inside the container you're holder, or change a setting on the Peek module (e.g. \"$peek books false\", \"$peek reset\").", "peek | peek reset | peek ", CommandCategory.MISC); } @Override public void onCommand(String alias, String[] args) throws Exception { - ItemStack item = mc.player.getInventory().getMainHandStack(); + if (args.length > 0) { + CmdModuleSettings.applyArgs(ModuleManager.getModule("Peek"), args); + return; + } + + ItemStack item = mc.player.getMainHandStack(); if (item.getItem() instanceof BlockItem) { Block block = ((BlockItem) item.getItem()).getBlock(); diff --git a/src/main/java/org/bleachhack/command/commands/CmdRbook.java b/src/main/java/org/bleachhack/command/commands/CmdRbook.java index ec1f1b1b40..f4ac2aedac 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdRbook.java +++ b/src/main/java/org/bleachhack/command/commands/CmdRbook.java @@ -31,7 +31,7 @@ public CmdRbook() { @Override public void onCommand(String alias, String[] args) throws Exception { - ItemStack item = mc.player.getInventory().getMainHandStack(); + ItemStack item = mc.player.getMainHandStack(); if (item.getItem() != Items.WRITABLE_BOOK) { BleachLogger.error("Not Holding A Writable Book!"); @@ -48,7 +48,7 @@ public void onCommand(String alias, String[] args) throws Exception { for (int t = 0; t < pages; t++) textSplit.add(RandomStringUtils.random(pageChars, startChar, endChar, false, false)); - mc.player.networkHandler.sendPacket(new BookUpdateC2SPacket(mc.player.getInventory().selectedSlot, textSplit, Optional.empty())); + mc.player.networkHandler.sendPacket(new BookUpdateC2SPacket(mc.player.getInventory().getSelectedSlot(), textSplit, Optional.empty())); BleachLogger.info("Written book (" + pages + " pages, " + pageChars + " chars/page)"); } diff --git a/src/main/java/org/bleachhack/command/commands/CmdRename.java b/src/main/java/org/bleachhack/command/commands/CmdRename.java index 4212dc5023..bc6ca3df48 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdRename.java +++ b/src/main/java/org/bleachhack/command/commands/CmdRename.java @@ -13,6 +13,7 @@ import org.bleachhack.command.CommandCategory; import org.bleachhack.util.BleachLogger; +import net.minecraft.component.DataComponentTypes; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; @@ -30,9 +31,9 @@ public void onCommand(String alias, String[] args) throws Exception { return; } - ItemStack i = mc.player.getInventory().getMainHandStack(); + ItemStack i = mc.player.getInventory().getSelectedStack(); - i.setCustomName(Text.literal(StringUtils.join(args, ' ').replace("&", "\u00a7").replace("\u00a7\u00a7", "&"))); + i.set(DataComponentTypes.CUSTOM_NAME, Text.literal(StringUtils.join(args, ' ').replace("&", "\u00a7").replace("\u00a7\u00a7", "&"))); BleachLogger.info("Renamed Item"); } diff --git a/src/main/java/org/bleachhack/command/commands/CmdRpc.java b/src/main/java/org/bleachhack/command/commands/CmdRpc.java index bf62bda777..4b15df65a4 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdRpc.java +++ b/src/main/java/org/bleachhack/command/commands/CmdRpc.java @@ -22,7 +22,7 @@ public class CmdRpc extends Command { public CmdRpc() { - super("rpc", "Sets custom discord rpc text.", "rpc [top/bottom] | rpc current", CommandCategory.MODULES, + super("rpc", "Sets custom discord rpc text, or change a setting (e.g. \"$rpc silent true\", \"$rpc reset\").", "rpc [top/bottom] | rpc current | rpc reset | rpc ", CommandCategory.MODULES, "discordrpc"); } @@ -33,22 +33,25 @@ public void onCommand(String alias, String[] args) throws Exception { } DiscordRPC rpc = ModuleManager.getModule(DiscordRPC.class); - String text = StringUtils.join(args, ' ', 1, args.length); - if (args[0].equalsIgnoreCase("top")) { - rpc.setTopText(text); + if (args[0].equalsIgnoreCase("top") || args[0].equalsIgnoreCase("bottom")) { + String text = StringUtils.join(args, ' ', 1, args.length); - BleachLogger.info("Set top RPC text to \"" + text + "\""); - BleachFileHelper.saveMiscSetting("discordRPCTopText", new JsonPrimitive(text)); - } else if (args[0].equalsIgnoreCase("bottom")) { - rpc.setBottomText(text); + if (args[0].equalsIgnoreCase("top")) { + rpc.setTopText(text); - BleachLogger.info("Set bottom RPC text to \"" + text + "\""); - BleachFileHelper.saveMiscSetting("discordRPCBottomText", new JsonPrimitive(text)); + BleachLogger.info("Set top RPC text to \"" + text + "\""); + BleachFileHelper.saveMiscSetting("discordRPCTopText", new JsonPrimitive(text)); + } else { + rpc.setBottomText(text); + + BleachLogger.info("Set bottom RPC text to \"" + text + "\""); + BleachFileHelper.saveMiscSetting("discordRPCBottomText", new JsonPrimitive(text)); + } } else if (args[0].equalsIgnoreCase("current")) { BleachLogger.info("Current RPC status:\n" + rpc.getTopText() + "\n" + rpc.getBottomText()); } else { - throw new CmdSyntaxException(); + CmdModuleSettings.applyArgs(rpc, args); } } diff --git a/src/main/java/org/bleachhack/command/commands/CmdServer.java b/src/main/java/org/bleachhack/command/commands/CmdServer.java index 1139a39bbb..c07e594360 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdServer.java +++ b/src/main/java/org/bleachhack/command/commands/CmdServer.java @@ -10,6 +10,7 @@ import net.minecraft.SharedConstants; import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.command.permission.LeveledPermissionPredicate; import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket; import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket; import net.minecraft.text.ClickEvent; @@ -115,8 +116,8 @@ public void onReadPacket(EventPacket.Read event) { public Text createText(String name, String value) { boolean newlines = value.contains("\n"); return Text.literal("\u00a77" + name + "\u00a7f:" + (newlines ? "\n" : " " ) + "\u00a7a" + value).styled(style -> style - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Click to copy to clipboard"))) - .withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, Formatting.strip(value)))); + .withHoverEvent(new HoverEvent.ShowText(Text.literal("Click to copy to clipboard"))) + .withClickEvent(new ClickEvent.CopyToClipboard(Formatting.strip(value)))); } public void checkForPlugins() { @@ -146,7 +147,7 @@ public String getBrand(boolean singleplayer) { if (singleplayer) return "Integrated Server"; - return mc.player.getServerBrand() != null ? mc.player.getServerBrand() : "Unknown"; + return mc.player.networkHandler.getBrand() != null ? mc.player.networkHandler.getBrand() : "Unknown"; } public String getDay(boolean singleplayer) { @@ -154,7 +155,10 @@ public String getDay(boolean singleplayer) { } public String getDifficulty(boolean singleplayer) { - return StringUtils.capitalize(mc.world.getDifficulty().getName()) + " (Local: " + mc.world.getLocalDifficulty(mc.player.getBlockPos()).getLocalDifficulty() + ")"; + // World.getLocalDifficulty(BlockPos) was removed client-side in 1.21.11 (now ServerWorld-only, + // since it depends on server-only chunk inhabited-time data) - the "(Local: X)" detail can no + // longer be computed from the client, so it's dropped. + return StringUtils.capitalize(mc.world.getDifficulty().getName()); } public String getIP(boolean singleplayer) { @@ -176,13 +180,12 @@ public String getMotd(boolean singleplayer) { } public String getPing(boolean singleplayer) { - PlayerListEntry playerEntry = mc.player.networkHandler.getPlayerListEntry(mc.player.getGameProfile().getId()); + PlayerListEntry playerEntry = mc.player.networkHandler.getPlayerListEntry(mc.player.getGameProfile().id()); return playerEntry == null ? "0" : Integer.toString(playerEntry.getLatency()); } public String getPerms(boolean singleplayer) { - int p = 0; - while (mc.player.hasPermissionLevel(p + 1) && p < 5) p++; + int p = mc.player.getPermissions() instanceof LeveledPermissionPredicate leveled ? leveled.getLevel().getLevel() : 0; return switch (p) { case 0 -> "0 (No Perms)"; @@ -203,8 +206,8 @@ public String getProtocol(boolean singleplayer) { public String getVersion(boolean singleplayer) { if (singleplayer) - return SharedConstants.getGameVersion().getName(); + return SharedConstants.getGameVersion().name(); - return mc.getCurrentServerEntry().version != null ? mc.getCurrentServerEntry().version.getString() : "Unknown (" + SharedConstants.getGameVersion().getName() + ")"; + return mc.getCurrentServerEntry().version != null ? mc.getCurrentServerEntry().version.getString() : "Unknown (" + SharedConstants.getGameVersion().name() + ")"; } } diff --git a/src/main/java/org/bleachhack/command/commands/CmdSkull.java b/src/main/java/org/bleachhack/command/commands/CmdSkull.java index f44a2b096d..13431d5688 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdSkull.java +++ b/src/main/java/org/bleachhack/command/commands/CmdSkull.java @@ -12,20 +12,26 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Random; +import java.util.UUID; import org.bleachhack.command.Command; import org.bleachhack.command.CommandCategory; import org.bleachhack.command.exception.CmdSyntaxException; import org.bleachhack.util.BleachLogger; +import com.google.common.collect.HashMultimap; import com.google.common.io.Resources; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ProfileComponent; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.StringNbtReader; +import net.minecraft.util.Uuids; public class CmdSkull extends Command { @@ -48,7 +54,10 @@ public void onCommand(String alias, String[] args) throws Exception { ItemStack item = new ItemStack(Items.PLAYER_HEAD, 64); Random random = new Random(); - String id = "[I;" + random.nextInt() + "," + random.nextInt() + "," + random.nextInt() + "," + random.nextInt() + "]"; + // ported: 1.19.4 built a "SkullOwner.Id" int-array nbt tag with 4 random ints; 1.21.11 + // stores the owner as a real GameProfile in DataComponentTypes.PROFILE, so the same 4 + // random ints are packed into a UUID via Uuids.toUuid the same way the nbt int-array was. + UUID id = Uuids.toUuid(new int[] {random.nextInt(), random.nextInt(), random.nextInt(), random.nextInt()}); if (args.length < 2) { try { @@ -60,21 +69,25 @@ public void onCommand(String alias, String[] args) throws Exception { Resources.toString(new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + json.get("id").getAsString()), StandardCharsets.UTF_8)) .getAsJsonObject(); - item.setNbt(StringNbtReader.parse("{SkullOwner:{Id:" + id + ",Properties:{textures:[{Value:\"" - + json2.get("properties").getAsJsonArray().get(0).getAsJsonObject().get("value").getAsString() - + "\"}]}}}")); + String value = json2.get("properties").getAsJsonArray().get(0).getAsJsonObject().get("value").getAsString(); + item.set(DataComponentTypes.PROFILE, ProfileComponent.ofStatic(createProfile(id, value))); } catch (Exception e) { e.printStackTrace(); BleachLogger.error("Error getting head! (" + e.getClass().getSimpleName() + ")"); } } else if (args[0].equalsIgnoreCase("img")) { - NbtCompound tag = StringNbtReader.parse( - "{SkullOwner:{Id:" + id + ",Properties:{textures:[{Value:\"" + encodeUrl(args[1]) + "\"}]}}}"); - item.setNbt(tag); - BleachLogger.logger.info(tag); + GameProfile profile = createProfile(id, encodeUrl(args[1])); + item.set(DataComponentTypes.PROFILE, ProfileComponent.ofStatic(profile)); + BleachLogger.logger.info(profile); } - mc.player.getInventory().addPickBlock(item); + mc.player.getInventory().insertStack(item); + } + + private GameProfile createProfile(UUID id, String texturesValue) { + PropertyMap properties = new PropertyMap(HashMultimap.create()); + properties.put("textures", new Property("textures", texturesValue)); + return new GameProfile(id, "", properties); } private String encodeUrl(String url) { diff --git a/src/main/java/org/bleachhack/command/commands/CmdSpammer.java b/src/main/java/org/bleachhack/command/commands/CmdSpammer.java index f192ad1adb..def1d21d90 100644 --- a/src/main/java/org/bleachhack/command/commands/CmdSpammer.java +++ b/src/main/java/org/bleachhack/command/commands/CmdSpammer.java @@ -10,6 +10,7 @@ import org.bleachhack.command.Command; import org.bleachhack.command.CommandCategory; +import org.bleachhack.module.ModuleManager; import org.bleachhack.util.BleachLogger; import org.bleachhack.util.io.BleachFileMang; @@ -18,16 +19,21 @@ public class CmdSpammer extends Command { public CmdSpammer() { - super("spammer", "Opens the spammer file.", "spammer", CommandCategory.MODULES, + super("spammer", "Opens the spammer file, or change a setting (e.g. \"$spammer delay 5\", \"$spammer reset\").", "spammer | spammer reset | spammer ", CommandCategory.MODULES, "editspammer"); } @Override public void onCommand(String alias, String[] args) throws Exception { - BleachFileMang.createFile("spammer.txt"); - Util.getOperatingSystem().open(BleachFileMang.getDir().resolve("spammer.txt").toUri()); + if (args.length == 0) { + BleachFileMang.createFile("spammer.txt"); + Util.getOperatingSystem().open(BleachFileMang.getDir().resolve("spammer.txt").toUri()); - BleachLogger.info("Opened spammer file."); + BleachLogger.info("Opened spammer file."); + return; + } + + CmdModuleSettings.applyArgs(ModuleManager.getModule("Spammer"), args); } } diff --git a/src/main/java/org/bleachhack/command/exception/CmdSyntaxException.java b/src/main/java/org/bleachhack/command/exception/CmdSyntaxException.java index d594d9693e..b8467560a1 100644 --- a/src/main/java/org/bleachhack/command/exception/CmdSyntaxException.java +++ b/src/main/java/org/bleachhack/command/exception/CmdSyntaxException.java @@ -1,16 +1,18 @@ package org.bleachhack.command.exception; -import net.minecraft.command.CommandException; - import net.minecraft.text.Text; import java.io.Serial; -public class CmdSyntaxException extends CommandException { +// net.minecraft.command.CommandException was removed entirely, so this now provides its own +// Text-message storage directly instead of inheriting it. +public class CmdSyntaxException extends RuntimeException { @Serial private static final long serialVersionUID = 7940377774005961331L; + private final Text textMessage; + public CmdSyntaxException() { this("Invalid Syntax!"); } @@ -18,9 +20,14 @@ public CmdSyntaxException() { public CmdSyntaxException(String message) { this(Text.literal(message)); } - + public CmdSyntaxException(Text message) { - super(message); + super(message.getString()); + this.textMessage = message; + } + + public Text getTextMessage() { + return textMessage; } } diff --git a/src/main/java/org/bleachhack/event/events/EventBlockEntityRender.java b/src/main/java/org/bleachhack/event/events/EventBlockEntityRender.java index ac69ca8740..77976c9893 100644 --- a/src/main/java/org/bleachhack/event/events/EventBlockEntityRender.java +++ b/src/main/java/org/bleachhack/event/events/EventBlockEntityRender.java @@ -11,62 +11,36 @@ import org.bleachhack.event.Event; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; public class EventBlockEntityRender extends Event { public static class Single extends EventBlockEntityRender { protected BlockEntity blockEntity; - protected MatrixStack matrices; - protected VertexConsumerProvider vertex; public BlockEntity getBlockEntity() { return blockEntity; } - public MatrixStack getMatrices() { - return matrices; - } - - public VertexConsumerProvider getVertex() { - return vertex; - } - + // 1.21.11: block-entity rendering moved to the RenderState/OrderedRenderCommandQueue + // architecture (see MixinBlockEntityRenderDispatcher notes) - this now fires during + // WorldRenderer's render-state extraction pass, before any MatrixStack/VertexConsumerProvider + // exists for this block entity, so only the block entity itself can be substituted/cancelled. public static class Pre extends Single { - public Pre(BlockEntity blockEntity, MatrixStack matrices, VertexConsumerProvider vertex) { + public Pre(BlockEntity blockEntity) { this.blockEntity = blockEntity; - this.matrices = matrices; - this.vertex = vertex; } public void setBlockEntity(BlockEntity blockEntity) { this.blockEntity = blockEntity; } - - public void setMatrices(MatrixStack matrices) { - this.matrices = matrices; - } - - public void setVertex(VertexConsumerProvider vertex) { - this.vertex = vertex; - } - } - - public static class Post extends Single { - public Post(BlockEntity blockEntity, MatrixStack matrices, VertexConsumerProvider vertexConsumers) { - this.blockEntity = blockEntity; - this.matrices = matrices; - this.vertex = vertexConsumers; - } } } - public static class PreAll extends EventEntityRender { + public static class PreAll extends EventBlockEntityRender { } - public static class PostAll extends EventEntityRender { + public static class PostAll extends EventBlockEntityRender { } } diff --git a/src/main/java/org/bleachhack/event/events/EventEntityRender.java b/src/main/java/org/bleachhack/event/events/EventEntityRender.java index f260929277..1f806d4fa1 100644 --- a/src/main/java/org/bleachhack/event/events/EventEntityRender.java +++ b/src/main/java/org/bleachhack/event/events/EventEntityRender.java @@ -10,7 +10,7 @@ import org.bleachhack.event.Event; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; @@ -19,64 +19,49 @@ public class EventEntityRender extends Event { public static class Single extends EventEntityRender { protected Entity entity; - protected MatrixStack matrices; - protected VertexConsumerProvider vertex; public Entity getEntity() { return entity; } - public MatrixStack getMatrix() { - return matrices; - } - - public VertexConsumerProvider getVertex() { - return vertex; - } - + // 1.21.11: entity rendering no longer takes a MatrixStack/VertexConsumerProvider directly (it + // now builds an EntityRenderState up front and submits draws through an OrderedRenderCommandQueue + // - see task #3/#4 notes), so Pre only supports cancelling a specific entity's render now, at the + // visibility-check stage - nothing ever used getMatrix()/getVertex() on it besides the mixin itself. public static class Pre extends Single { - public Pre(Entity entity, MatrixStack matrices, VertexConsumerProvider vertex) { - this.entity = entity; - this.matrices = matrices; - this.vertex = vertex; - } - - public void setMatrix(MatrixStack matrices) { - this.matrices = matrices; - } - - public void setVertex(VertexConsumerProvider vertex) { - this.vertex = vertex; - } - - public void setEntity(Entity entity) { + public Pre(Entity entity) { this.entity = entity; } } - public static class Post extends Single { + // Label rendering (nametags) still gets a MatrixStack, but the VertexConsumerProvider was + // replaced by an OrderedRenderCommandQueue (submit-based batching instead of direct vertex + // buffers) - and the label Text itself is no longer passed in directly, so it's dropped. + public static class Label extends Single { + + protected MatrixStack matrices; + protected OrderedRenderCommandQueue vertex; - public Post(Entity entity, MatrixStack matrices, VertexConsumerProvider vertex) { + public Label(Entity entity, MatrixStack matrices, OrderedRenderCommandQueue vertex) { this.entity = entity; this.matrices = matrices; this.vertex = vertex; } - } - public static class Label extends Single { + public MatrixStack getMatrix() { + return matrices; + } - public Label(Entity entity, MatrixStack matrices, VertexConsumerProvider vertex) { - this.entity = entity; - this.matrices = matrices; - this.vertex = vertex; + public OrderedRenderCommandQueue getVertex() { + return vertex; } public void setMatrix(MatrixStack matrices) { this.matrices = matrices; } - public void setVertex(VertexConsumerProvider vertex) { + public void setVertex(OrderedRenderCommandQueue vertex) { this.vertex = vertex; } } diff --git a/src/main/java/org/bleachhack/event/events/EventRenderBlock.java b/src/main/java/org/bleachhack/event/events/EventRenderBlock.java index 47b1c688f7..bedc7ec056 100644 --- a/src/main/java/org/bleachhack/event/events/EventRenderBlock.java +++ b/src/main/java/org/bleachhack/event/events/EventRenderBlock.java @@ -11,10 +11,11 @@ import org.bleachhack.event.Event; import net.minecraft.block.BlockState; -import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.BlockRenderLayer; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; public class EventRenderBlock extends Event { @@ -64,10 +65,22 @@ public void setOpaque(boolean opaque) { public static class ShouldDrawSide extends EventRenderBlock { + private final BlockState neighborState; + private final Direction side; private Boolean drawSide; - public ShouldDrawSide(BlockState state) { + public ShouldDrawSide(BlockState state, BlockState neighborState, Direction side) { super(state); + this.neighborState = neighborState; + this.side = side; + } + + public BlockState getNeighborState() { + return neighborState; + } + + public Direction getSide() { + return side; } public Boolean shouldDrawSide() { @@ -103,21 +116,28 @@ public MatrixStack getMatrices() { public VertexConsumer getVertexConsumer() { return vertexConsumer; } + + // 1.21.11 removed BufferBuilder's stateful fixedColor()/BufferVertexConsumer trick (see + // MixinBufferBuilder removal notes) - subscribers now replace the vertex consumer with their + // own wrapping decorator instead, and the caller re-reads getVertexConsumer() after posting. + public void setVertexConsumer(VertexConsumer vertexConsumer) { + this.vertexConsumer = vertexConsumer; + } } public static class Layer extends EventRenderBlock { - private RenderLayer layer; + private BlockRenderLayer layer; public Layer(BlockState state) { super(state); } - public RenderLayer getLayer() { + public BlockRenderLayer getLayer() { return layer; } - public void setLayer(RenderLayer layer) { + public void setLayer(BlockRenderLayer layer) { this.layer = layer; } } diff --git a/src/main/java/org/bleachhack/event/events/EventRenderBlockOutline.java b/src/main/java/org/bleachhack/event/events/EventRenderBlockOutline.java index 659cf7fbb6..fd5603dbe3 100644 --- a/src/main/java/org/bleachhack/event/events/EventRenderBlockOutline.java +++ b/src/main/java/org/bleachhack/event/events/EventRenderBlockOutline.java @@ -10,7 +10,6 @@ import org.bleachhack.event.Event; -import net.minecraft.block.BlockState; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.BlockPos; @@ -20,13 +19,13 @@ public class EventRenderBlockOutline extends Event { private MatrixStack matrices; private VertexConsumer vertexConsumer; private BlockPos pos; - private BlockState state; - public EventRenderBlockOutline(MatrixStack matrices, VertexConsumer vertexConsumer, BlockPos pos, BlockState state) { + // 1.21.11: the BlockState is no longer available at this call site (see task #4 notes - + // WorldRenderer's OutlineRenderState only carries the position + collision/interaction shapes). + public EventRenderBlockOutline(MatrixStack matrices, VertexConsumer vertexConsumer, BlockPos pos) { this.matrices = matrices; this.vertexConsumer = vertexConsumer; this.pos = pos; - this.state = state; } public MatrixStack getMatrices() { @@ -53,13 +52,4 @@ public void setPos(BlockPos pos) { this.pos = pos; } - public BlockState getState() { - return state; - } - - public void setState(BlockState state) { - this.state = state; - } - - } diff --git a/src/main/java/org/bleachhack/event/events/EventRenderCrosshair.java b/src/main/java/org/bleachhack/event/events/EventRenderCrosshair.java index 7cf8478d22..5b7a00f4cf 100644 --- a/src/main/java/org/bleachhack/event/events/EventRenderCrosshair.java +++ b/src/main/java/org/bleachhack/event/events/EventRenderCrosshair.java @@ -10,21 +10,21 @@ import org.bleachhack.event.Event; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public class EventRenderCrosshair extends Event { - private MatrixStack matrices; + private DrawContext matrices; - public EventRenderCrosshair(MatrixStack matrices) { + public EventRenderCrosshair(DrawContext matrices) { this.setMatrices(matrices); } - public MatrixStack getMatrices() { + public DrawContext getMatrices() { return matrices; } - public void setMatrices(MatrixStack matrices) { + public void setMatrices(DrawContext matrices) { this.matrices = matrices; } } diff --git a/src/main/java/org/bleachhack/event/events/EventRenderInGameHud.java b/src/main/java/org/bleachhack/event/events/EventRenderInGameHud.java index b320dedb8e..247f2d3443 100644 --- a/src/main/java/org/bleachhack/event/events/EventRenderInGameHud.java +++ b/src/main/java/org/bleachhack/event/events/EventRenderInGameHud.java @@ -10,17 +10,17 @@ import org.bleachhack.event.Event; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public class EventRenderInGameHud extends Event { - private MatrixStack matrices; + private DrawContext matrices; - public EventRenderInGameHud(MatrixStack matrices) { + public EventRenderInGameHud(DrawContext matrices) { this.matrices = matrices; } - public MatrixStack getMatrix() { + public DrawContext getMatrix() { return matrices; } } diff --git a/src/main/java/org/bleachhack/event/events/EventRenderOverlay.java b/src/main/java/org/bleachhack/event/events/EventRenderOverlay.java index c6281e89f5..c310ee2ec9 100644 --- a/src/main/java/org/bleachhack/event/events/EventRenderOverlay.java +++ b/src/main/java/org/bleachhack/event/events/EventRenderOverlay.java @@ -8,24 +8,24 @@ */ package org.bleachhack.event.events; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import org.bleachhack.event.Event; import net.minecraft.util.Identifier; public class EventRenderOverlay extends Event { - private MatrixStack matrices; + private DrawContext matrices; private Identifier texture; private float opacity; - - public EventRenderOverlay(MatrixStack matrices, Identifier texture, float opacity) { + + public EventRenderOverlay(DrawContext matrices, Identifier texture, float opacity) { this.matrices = matrices; this.texture = texture; this.opacity = opacity; } - public MatrixStack getMatrices() { + public DrawContext getMatrices() { return matrices; } diff --git a/src/main/java/org/bleachhack/event/events/EventRenderScreenBackground.java b/src/main/java/org/bleachhack/event/events/EventRenderScreenBackground.java index 9b88fce3cd..82a5c141ae 100644 --- a/src/main/java/org/bleachhack/event/events/EventRenderScreenBackground.java +++ b/src/main/java/org/bleachhack/event/events/EventRenderScreenBackground.java @@ -10,17 +10,17 @@ import org.bleachhack.event.Event; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public class EventRenderScreenBackground extends Event { - - private MatrixStack matrices; - public EventRenderScreenBackground(MatrixStack matrices) { + private DrawContext matrices; + + public EventRenderScreenBackground(DrawContext matrices) { this.matrices = matrices; } - public MatrixStack getMatrices() { + public DrawContext getMatrices() { return matrices; } } diff --git a/src/main/java/org/bleachhack/event/events/EventSkyRender.java b/src/main/java/org/bleachhack/event/events/EventSkyRender.java deleted file mode 100644 index ce923b5107..0000000000 --- a/src/main/java/org/bleachhack/event/events/EventSkyRender.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). - * Copyright (c) 2021 Bleach and contributors. - * - * This source code is subject to the terms of the GNU General Public - * License, version 3. If a copy of the GPL was not distributed with this - * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt - */ -package org.bleachhack.event.events; - -import org.bleachhack.event.Event; - -import net.minecraft.client.render.DimensionEffects; -import net.minecraft.util.math.Vec3d; - -public class EventSkyRender extends Event { - - public static class Properties extends EventSkyRender { - - private DimensionEffects sky; - - public Properties(DimensionEffects sky) { - this.setSky(sky); - } - - public DimensionEffects getSky() { - return sky; - } - - public void setSky(DimensionEffects sky) { - this.sky = sky; - } - } - - public static class Color extends EventSkyRender { - - private float tickDelta; - private Vec3d color = null; - - public Color(float tickDelta) { - this.tickDelta = tickDelta; - } - - public float getTickDelta() { - return tickDelta; - } - - public void setColor(Vec3d color) { - this.color = color; - } - - public Vec3d getColor() { - return color; - } - - public static class SkyColor extends Color { - - public SkyColor(float tickDelta) { - super(tickDelta); - } - } - - public static class CloudColor extends Color { - - public CloudColor(float tickDelta) { - super(tickDelta); - } - } - - public static class FogColor extends Color { - - public FogColor(float tickDelta) { - super(tickDelta); - } - } - - public static class EndSkyColor extends Color { - - public EndSkyColor(float tickDelta) { - super(tickDelta); - } - } - } -} diff --git a/src/main/java/org/bleachhack/event/events/EventWorldRender.java b/src/main/java/org/bleachhack/event/events/EventWorldRender.java index e34d3d66a7..3758729611 100644 --- a/src/main/java/org/bleachhack/event/events/EventWorldRender.java +++ b/src/main/java/org/bleachhack/event/events/EventWorldRender.java @@ -10,36 +10,29 @@ import org.bleachhack.event.Event; -import net.minecraft.client.util.math.MatrixStack; - public class EventWorldRender extends Event { protected float partialTicks; - protected MatrixStack matrices; - + + // 1.21.11's WorldRenderer.render(...) no longer takes/builds a single top-level MatrixStack (see + // task #4 notes) - nothing subscribed to getMatrices() anyway, so it's dropped rather than faked. public static class Pre extends EventWorldRender { - public Pre(float partialTicks, MatrixStack matrices) { + public Pre(float partialTicks) { this.partialTicks = partialTicks; - this.matrices = matrices; } - + } - + public static class Post extends EventWorldRender { - public Post(float partialTicks, MatrixStack matrices) { + public Post(float partialTicks) { this.partialTicks = partialTicks; - this.matrices = matrices; } - + } public float getPartialTicks() { return partialTicks; } - - public MatrixStack getMatrices() { - return matrices; - } } diff --git a/src/main/java/org/bleachhack/gui/AccountManagerScreen.java b/src/main/java/org/bleachhack/gui/AccountManagerScreen.java index da2eac912e..7a3abeb768 100644 --- a/src/main/java/org/bleachhack/gui/AccountManagerScreen.java +++ b/src/main/java/org/bleachhack/gui/AccountManagerScreen.java @@ -12,16 +12,16 @@ import com.google.gson.JsonParser; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; -import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; -import com.mojang.blaze3d.systems.RenderSystem; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.SharedConstants; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.util.DefaultSkinHelper; -import net.minecraft.client.util.Session; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.session.Session; +import net.minecraft.entity.player.SkinTextures; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.sound.SoundEvents; @@ -41,6 +41,7 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -140,19 +141,19 @@ public void init() { () -> openAddAccWindow(AccountType.MICROSOFT, "Microsoft", new ItemStack(Items.PURPLE_GLAZED_TERRACOTTA)))); } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - this.renderBackground(matrices); - - textRenderer.drawWithShadow(matrices, "Fabric: " + FabricLoader.getInstance().getModContainer("fabricloader").get().getMetadata().getVersion().getFriendlyString(), + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". + matrices.drawTextWithShadow(textRenderer, "Fabric: " + FabricLoader.getInstance().getModContainer("fabricloader").get().getMetadata().getVersion().getFriendlyString(), 4, height - 30, -1); - textRenderer.drawWithShadow(matrices, "Minecraft: " + SharedConstants.getGameVersion().getName(), 4, height - 20, -1); - textRenderer.drawWithShadow(matrices, "Logged in as: \u00a7a" + client.getSession().getUsername(), 4, height - 10, -1); + matrices.drawTextWithShadow(textRenderer, "Minecraft: " + SharedConstants.getGameVersion().name(), 4, height - 20, -1); + matrices.drawTextWithShadow(textRenderer, "Logged in as: \u00a7a" + client.getSession().getUsername(), 4, height - 10, -1); hovered = -1; super.render(matrices, mouseX, mouseY, delta); } - public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mouseY) { + public void onRenderWindow(DrawContext matrices, int window, int mouseX, int mouseY) { super.onRenderWindow(matrices, window, mouseX, mouseY); if (window == 0) { @@ -177,22 +178,22 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou hovered = c; } - fill(matrices, x + listW, y + 12, x + listW + 1, y + h - 1, 0xff606090); + matrices.fill(x + listW, y + 12, x + listW + 1, y + h - 1, 0xff606090); } } - private void drawEntry(MatrixStack matrices, Account acc, int x, int y, int width, int height, int color) { + private void drawEntry(DrawContext matrices, Account acc, int x, int y, int width, int height, int color) { Window.fill(matrices, x, y, x + width, y + height, color); if (acc.bindSkin()) { double pixelSize = (height - 6) / 8d; - DrawableHelper.fill(matrices, + matrices.fill( x + 2, y + 2, x + height - 2, y + height - 2, 0x60d86ceb); - DrawableHelper.drawTexture(matrices, + matrices.drawTexture(RenderPipelines.GUI_TEXTURED, acc.getSkinTexture(), x + 3, y + 3, - (int) (pixelSize * 8), (int) (pixelSize * 8), + (float) (pixelSize * 8), (float) (pixelSize * 8), (int) (pixelSize * 8), (int) (pixelSize * 8), (int) (pixelSize * 64), (int) (pixelSize * 64)); } @@ -200,32 +201,32 @@ private void drawEntry(MatrixStack matrices, Account acc, int x, int y, int widt boolean extendText = acc.bindCape(); if (extendText) { double pixelSize = ((height - 6) / 10d) * 0.625; - DrawableHelper.fill(matrices, + matrices.fill( x + height - 1, y + 2, (int) (x + height + pixelSize * 10 + 1), y + height - 2, 0x60d86ceb); - DrawableHelper.drawTexture(matrices, + matrices.drawTexture(RenderPipelines.GUI_TEXTURED, acc.getCapeTexture(), x + height, y + 3, - (int) Math.ceil(pixelSize), (int) Math.ceil(pixelSize), + (float) Math.ceil(pixelSize), (float) Math.ceil(pixelSize), (int) (pixelSize * 10), (int) (pixelSize * 16), (int) (pixelSize * 64), (int) (pixelSize * 32)); } double pixelSize = ((height - 6) / 10d) * 0.625; - textRenderer.drawWithShadow(matrices, "\u00a77Name: " + acc.username, + matrices.drawTextWithShadow(textRenderer, "\u00a77Name: " + acc.username, extendText ? (int) (x + height + pixelSize * 10 + 3) : x + height, y + 4, -1); - textRenderer.drawWithShadow(matrices, + matrices.drawTextWithShadow(textRenderer, (acc.type == AccountType.NO_AUTH ? "\u00a7eNo Auth" : acc.type == AccountType.MOJANG ? "\u00a7aMojang" : "\u00a7bMicrosoft"), extendText ? (int) (x + height + pixelSize * 10 + 3) : x + height, y + height - 11, -1); if (acc.type != AccountType.NO_AUTH) { - textRenderer.drawWithShadow(matrices, + matrices.drawTextWithShadow(textRenderer, (acc.success == 0 ? "\u00a76?" : acc.success == 1 ? "\u00a7cx" : "\u00a7a+"), x + width - 10, y + height - 11, -1); } } - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(Click click, boolean doubleClick) { if (hovered >= 0 && hovered < accounts.size()) { if (selected >= 0 && selected < accounts.size()) { for (int i = 0; i < textFieldWidgets.size(); i++) { @@ -235,10 +236,10 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { selected = hovered; updateRightside(); - client.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + client.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1.0F)); } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(click, doubleClick); } private void saveAccounts() { @@ -289,7 +290,7 @@ private void openAddAccWindow(AccountType type, String name, ItemStack item) { Account account = new Account(type, 0, null, null, tf.stream().map(t -> t.textField.getText()).toArray(String[]::new)); try { Session session = account.getSesson(); - account.uuid = session.getUuid(); + account.uuid = session.getUuidOrNull().toString(); account.username = session.getUsername(); addAccount(account); getWindow(2).closed = true; @@ -340,17 +341,15 @@ private void addAccount(Account account) { try { Session session = account.getSesson(); - account.uuid = session.getUuid(); + account.uuid = session.getUuidOrNull().toString(); account.username = session.getUsername(); - account.textures.clear(); - client.getSkinProvider().loadSkin(session.getProfile(), (type, identifier, minecraftProfileTexture) -> account.textures.put(type, identifier), true); + GameProfile profile = new GameProfile(session.getUuidOrNull(), account.username); + account.skinTextures = client.getSkinProvider().supplySkinTextures(profile, false); } catch (AuthenticationException ignored) { } } else { GameProfile profile = new GameProfile(UUID.fromString(account.uuid), account.username); - - account.textures.clear(); - client.getSkinProvider().loadSkin(profile, (type, identifier, minecraftProfileTexture) -> account.textures.put(type, identifier), true); + account.skinTextures = client.getSkinProvider().supplySkinTextures(profile, false); } for (int i = 0; i <= accounts.size(); i++) { @@ -372,7 +371,10 @@ private static class Account { // 0 = ?, 1 = no, 2 = yes public int success; - public Map textures = new EnumMap<>(Type.class); + // 1.21.11 replaced the callback-based Type->Identifier skin/cape lookup with a single + // Supplier (see PlayerSkinProvider.supplySkinTextures) - it's backed by the same + // cache internally, so calling .get() fresh each render is cheap and always current. + public Supplier skinTextures; public static Account deserialize(String[] data) { try { @@ -409,9 +411,10 @@ public AuthenticationException login() { Session session = getSesson(); MinecraftClient.getInstance().session = session; - if (!session.getUuid().equals(NO_UUID)) - MinecraftClient.getInstance().getSessionProperties().clear(); - + // 1.19.4 also cleared MinecraftClient's cached session properties here so a switched-to + // real account picked up its skin immediately; getSessionProperties() was removed with no + // direct replacement. This is a minor staleness risk only (skins still resolve normally + // through the skin provider's own cache on the next lookup), not a functional loss. return null; } catch (AuthenticationException e) { return e; @@ -423,22 +426,19 @@ public Session getSesson() throws AuthenticationException { } public boolean bindSkin() { - if (textures.containsKey(Type.SKIN)) { - RenderSystem.setShaderTexture(0, textures.get(Type.SKIN)); - } else { - RenderSystem.setShaderTexture(0, DefaultSkinHelper.getTexture()); - } - return true; } + public Identifier getSkinTexture() { + return skinTextures != null ? skinTextures.get().body().texturePath() : DefaultSkinHelper.getTexture(); + } + public boolean bindCape() { - if (textures.containsKey(Type.CAPE)) { - RenderSystem.setShaderTexture(0, textures.get(Type.CAPE)); - return true; - } + return skinTextures != null && skinTextures.get().cape() != null; + } - return false; + public Identifier getCapeTexture() { + return skinTextures.get().cape().texturePath(); } } @@ -454,9 +454,9 @@ private enum AccountType { if (id.length() == 32) id = id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20); - return new Session(input[0], id, "", Optional.empty(), Optional.empty(), Session.AccountType.MOJANG); + return new Session(input[0], UUID.fromString(id), "", Optional.empty(), Optional.empty()); } catch (Exception e) { - return new Session(input[0], NO_UUID, "", Optional.empty(), Optional.empty(), Session.AccountType.MOJANG); + return new Session(input[0], UUID.fromString(NO_UUID), "", Optional.empty(), Optional.empty()); } }, Pair.of("Username", false)), MOJANG(input -> { diff --git a/src/main/java/org/bleachhack/gui/BleachCreditsScreen.java b/src/main/java/org/bleachhack/gui/BleachCreditsScreen.java index 38de22bf27..f1a0849cd9 100644 --- a/src/main/java/org/bleachhack/gui/BleachCreditsScreen.java +++ b/src/main/java/org/bleachhack/gui/BleachCreditsScreen.java @@ -23,7 +23,7 @@ import com.google.gson.JsonObject; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.HoverEvent; @@ -75,27 +75,27 @@ public void init() { getWindow(0).addWidget(new WindowTextWidget("- Main Developer -", true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 65, 0xe0e0e0)); getWindow(0).addWidget(new WindowTextWidget( - Text.literal("Bleach").styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("\u00a77https://github.com/BleachDev\n\n\u00a7eMain Developer!")))), + Text.literal("Bleach").styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal("\u00a77https://github.com/BleachDev\n\n\u00a7eMain Developer!")))), true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 80, 0x51eff5)); getWindow(0).addWidget(new WindowTextWidget("- Contributors -", true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 100, 0xe0e0e0)); getWindow(0).addWidget(new WindowTextWidget( - Text.literal("LasnikProgram").styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("\u00a77https://github.com/lasnikprogram\n\n\u00a7fMade first version of LogoutSpot, AirPlace, EntityMenu, HoleESP, AutoParkour and Search.")))), + Text.literal("LasnikProgram").styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal("\u00a77https://github.com/lasnikprogram\n\n\u00a7fMade first version of LogoutSpot, AirPlace, EntityMenu, HoleESP, AutoParkour and Search.")))), true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 115, 0x00a0a0)); getWindow(0).addWidget(new WindowTextWidget( - Text.literal("slcoolj").styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("\u00a77https://github.com/slcoolj\n\n\u00a7fMade Criticals, Speedmine OG mode and did the module system rewrite.")))), + Text.literal("slcoolj").styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal("\u00a77https://github.com/slcoolj\n\n\u00a7fMade Criticals, Speedmine OG mode and did the module system rewrite.")))), true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 127, 0x00a0a0)); getWindow(0).addWidget(new WindowTextWidget( - Text.literal("DevScyu").styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("\u00a77https://github.com/DevScyu\n\n\u00a7fMade first version of AutoTool, Trajectories, NoRender, AutoWalk, ElytraReplace, HandProgress and added Login manager encryption.")))), + Text.literal("DevScyu").styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal("\u00a77https://github.com/DevScyu\n\n\u00a7fMade first version of AutoTool, Trajectories, NoRender, AutoWalk, ElytraReplace, HandProgress and added Login manager encryption.")))), true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 139, 0x00a0a0)); getWindow(0).addWidget(new WindowTextWidget( - Text.literal("Bunt3rhund").styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("\u00a77https://github.com/Bunt3rhund\n\n\u00a7fMade first version of Zoom.")))), + Text.literal("Bunt3rhund").styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal("\u00a77https://github.com/Bunt3rhund\n\n\u00a7fMade first version of Zoom.")))), true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 151, 0x00a0a0)); getWindow(0).addWidget(new WindowTextWidget( - Text.literal("MorganAnkan").styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("\u00a77https://github.com/MorganAnkan\n\n\u00a7fMade the title screen text Rgb.")))), + Text.literal("MorganAnkan").styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal("\u00a77https://github.com/MorganAnkan\n\n\u00a7fMade the title screen text Rgb.")))), true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 163, 0x00a0a0)); getWindow(0).addWidget(new WindowTextWidget( - Text.literal("ThePapanoob").styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("\u00a77https://github.com/thepapanoob\n\n\u00a7fAdded Projectiles mode in Killaura.")))), + Text.literal("ThePapanoob").styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal("\u00a77https://github.com/thepapanoob\n\n\u00a7fAdded Projectiles mode in Killaura.")))), true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 175, 0x00a0a0)); getWindow(0).addWidget(new WindowTextWidget("- Donators/Boosters -", true, WindowTextWidget.TextAlign.MIDDLE, w / 2, 195, 0xe0e0e0)); @@ -125,13 +125,12 @@ private Text getBoosterText(ImmutablePair pair) { String[] split = pair.getRight().split("#"); return Text.literal(split[0]).styled(s -> s .withColor(color) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Text.literal(pair.getRight()).styled(s1 -> s1.withColor(color))))); + .withHoverEvent(new HoverEvent.ShowText(Text.literal(pair.getRight()).styled(s1 -> s1.withColor(color))))); } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - this.renderBackground(matrices); - + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". if (!boostersLoaded && boosterList != null) { int scroll = scrollbar.getPageOffset(); init(); @@ -149,9 +148,9 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { super.render(matrices, mouseX, mouseY, delta); } - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - scrollbar.moveScrollbar((int) -amount * 7); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + scrollbar.moveScrollbar((int) -verticalAmount * 7); - return super.mouseScrolled(mouseX, mouseY, amount); + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } } diff --git a/src/main/java/org/bleachhack/gui/BleachOptionsScreen.java b/src/main/java/org/bleachhack/gui/BleachOptionsScreen.java index d44d01d120..40039292dd 100644 --- a/src/main/java/org/bleachhack/gui/BleachOptionsScreen.java +++ b/src/main/java/org/bleachhack/gui/BleachOptionsScreen.java @@ -17,7 +17,7 @@ import org.bleachhack.setting.option.Option; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.HoverEvent; @@ -84,7 +84,7 @@ private int addCategory(int window, int x, int y, String name, Option... entr // Name text (at the end because of... reasons) getWindow(window).addWidget(new WindowTextWidget( - Text.literal(entry.getName()).styled(s -> s.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(entry.getTooltip())))), + Text.literal(entry.getName()).styled(s -> s.withHoverEvent(new HoverEvent.ShowText(Text.literal(entry.getTooltip())))), true, x - 107, y, 0xffffff)); @@ -95,9 +95,9 @@ private int addCategory(int window, int x, int y, String name, Option... entr } @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - this.renderBackground(matrices); - + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". int offset = scrollbar.getOffsetSinceRender(); for (WindowWidget widget: getWindow(0).getWidgets()) { if (!(widget instanceof WindowScrollbarWidget)) { @@ -110,10 +110,10 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - scrollbar.moveScrollbar((int) -amount * 7); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + scrollbar.moveScrollbar((int) -verticalAmount * 7); - return super.mouseScrolled(mouseX, mouseY, amount); + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } @Override diff --git a/src/main/java/org/bleachhack/gui/BleachTitleScreen.java b/src/main/java/org/bleachhack/gui/BleachTitleScreen.java index 7a0b96104b..39dde0d100 100644 --- a/src/main/java/org/bleachhack/gui/BleachTitleScreen.java +++ b/src/main/java/org/bleachhack/gui/BleachTitleScreen.java @@ -18,7 +18,7 @@ import net.minecraft.client.gui.screen.world.SelectWorldScreen; import net.minecraft.client.realms.gui.screen.RealmsMainScreen; import net.minecraft.client.resource.language.I18n; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -144,15 +144,15 @@ public void init() { } @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - this.renderBackground(matrices); - + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". int copyWidth = this.textRenderer.getWidth("Copyright Mojang AB. Do not distribute!") + 2; - textRenderer.drawWithShadow(matrices, "Copyright Mojang AB. Do not distribute!", width - copyWidth, height - 10, -1); - textRenderer.drawWithShadow(matrices, "Fabric: " + FabricLoader.getInstance().getModContainer("fabricloader").get().getMetadata().getVersion().getFriendlyString(), + matrices.drawTextWithShadow(textRenderer, "Copyright Mojang AB. Do not distribute!", width - copyWidth, height - 10, -1); + matrices.drawTextWithShadow(textRenderer, "Fabric: " + FabricLoader.getInstance().getModContainer("fabricloader").get().getMetadata().getVersion().getFriendlyString(), 4, height - 30, -1); - textRenderer.drawWithShadow(matrices, "Minecraft: " + SharedConstants.getGameVersion().getName(), 4, height - 20, -1); - textRenderer.drawWithShadow(matrices, "Logged in as: \u00a7a" + client.getSession().getUsername(), 4, height - 10, -1); + matrices.drawTextWithShadow(textRenderer, "Minecraft: " + SharedConstants.getGameVersion().name(), 4, height - 20, -1); + matrices.drawTextWithShadow(textRenderer, "Logged in as: \u00a7a" + client.getSession().getUsername(), 4, height - 10, -1); super.render(matrices, mouseX, mouseY, delta); diff --git a/src/main/java/org/bleachhack/gui/EntityMenuEditScreen.java b/src/main/java/org/bleachhack/gui/EntityMenuEditScreen.java index 0e4ca70736..96303e7014 100644 --- a/src/main/java/org/bleachhack/gui/EntityMenuEditScreen.java +++ b/src/main/java/org/bleachhack/gui/EntityMenuEditScreen.java @@ -18,8 +18,11 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.input.CharInput; +import net.minecraft.client.input.KeyInput; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; @@ -70,14 +73,15 @@ public void init() { } @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - renderBackground(matrices); + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". super.render(matrices, mouseX, mouseY, delta); } @SuppressWarnings("unchecked") @Override - public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mouseY) { + public void onRenderWindow(DrawContext matrices, int window, int mouseX, int mouseY) { super.onRenderWindow(matrices, window, mouseX, mouseY); if (window == 0) { @@ -94,14 +98,14 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou insertStartString = null; int seperator = (int) (x + w / 3.25); - fill(matrices, seperator, y, seperator + 1, y + h, 0xff606090); + matrices.fill(seperator, y, seperator + 1, y + h, 0xff606090); - textRenderer.drawWithShadow(matrices, "Interactions:", x + 6, y + 5, 0xffffff); + matrices.drawTextWithShadow(textRenderer, "Interactions:", x + 6, y + 5, 0xffffff); boolean mouseOverAdd = mouseX >= seperator - 16 && mouseX <= seperator - 3 && mouseY >= y + 3 && mouseY <= y + 15; Window.fill(matrices, seperator - 16, y + 3, seperator - 3, y + 15, mouseOverAdd ? 0x4fb070f0 : 0x60606090); - textRenderer.drawWithShadow(matrices, "\u00a7a+", seperator - 12, y + 5, 0xffffff); + matrices.drawTextWithShadow(textRenderer, "\u00a7a+", seperator - 12, y + 5, 0xffffff); if (mouseOverAdd) { addEntry = true; @@ -117,7 +121,7 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou Window.fill(matrices, x + 3, y + 17, seperator - 2, y + 33, mouseOver ? 0x4fb070f0 : 0x50606090); - drawCenteredTextWithShadow(matrices, textRenderer, + matrices.drawCenteredTextWithShadow(textRenderer, "\u00a7a\u00a7l^", x + (seperator - x) / 2, y + 21, 0xffffff); entries++; @@ -131,7 +135,7 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou Window.fill(matrices, x + 3, y + 17 + (maxEntries * 17), seperator - 2, y + 33 + (maxEntries * 17), mouseOver ? 0x4fb070f0 : 0x50606090); - drawCenteredTextWithShadow(matrices, textRenderer, + matrices.drawCenteredTextWithShadow(textRenderer, "\u00a7a\u00a7lv", x + (seperator - x) / 2, y + 21 + (maxEntries * 17), 0xffffff); maxEntries--; @@ -152,7 +156,7 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou Window.fill(matrices, x + 3, curY, seperator - 2, curY + 16, entry.equals(selectedEntry) ? 0x4f90f090 : mouseOver ? 0x4fb070f0 : 0x50606090); - drawCenteredTextWithShadow(matrices, textRenderer, + matrices.drawCenteredTextWithShadow(textRenderer, textRenderer.trimToWidth(entry, seperator - x - 6), x + (seperator - x) / 2, curY + 4, 0xffffff); if (mouseOver) { @@ -166,19 +170,19 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou } if (selectedEntry != null) { - textRenderer.drawWithShadow(matrices, "Name:", seperator + 8, y + 5, 0xffffff); + matrices.drawTextWithShadow(textRenderer, "Name:", seperator + 8, y + 5, 0xffffff); editNameField.setX(seperator + 8); editNameField.setY(y + 18); editNameField.setWidth(w - (seperator - x) - 16); - editNameField.render(matrices, mouseX, mouseY, client.getTickDelta()); + editNameField.render(matrices, mouseX, mouseY, client.getRenderTickCounter().getTickProgress(true)); - textRenderer.drawWithShadow(matrices, "Value:", seperator + 8, y + 45, 0xffffff); + matrices.drawTextWithShadow(textRenderer, "Value:", seperator + 8, y + 45, 0xffffff); editValueField.setX(seperator + 8); editValueField.setY(y + 57); editValueField.setWidth(w - (seperator - x) - 16); - editValueField.render(matrices, mouseX, mouseY, client.getTickDelta()); + editValueField.render(matrices, mouseX, mouseY, client.getRenderTickCounter().getTickProgress(true)); if (!selectedEntry.equals(editNameField.getText()) && !interactions.containsKey(editNameField.getText())) { MutablePair pair = interactions.getPair(selectedEntry); @@ -190,7 +194,7 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou interactions.getPair(selectedEntry).setRight(editValueField.getText()); } - textRenderer.drawWithShadow(matrices, "Insert:", seperator + 8, y + 85, 0xffffff); + matrices.drawTextWithShadow(textRenderer, "Insert:", seperator + 8, y + 85, 0xffffff); int line = 0; int curX = 0; @@ -203,8 +207,8 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou } boolean mouseOverInsert = mouseX >= seperator + 7 + curX && mouseX <= seperator + 10 + curX + textLen && mouseY >= y + 97 + line * 14 && mouseY <= y + 108 + line * 14; - fill(matrices, seperator + 7 + curX, y + 97 + line * 14, seperator + 10 + curX + textLen, y + 108 + line * 14, mouseOverInsert ? 0x9f6060b0 : 0x9f8070b0); - textRenderer.drawWithShadow(matrices, insert, seperator + 9 + curX, y + 99 + line * 14, 0xffffff); + matrices.fill(seperator + 7 + curX, y + 97 + line * 14, seperator + 10 + curX + textLen, y + 108 + line * 14, mouseOverInsert ? 0x9f6060b0 : 0x9f8070b0); + matrices.drawTextWithShadow(textRenderer, insert, seperator + 9 + curX, y + 99 + line * 14, 0xffffff); if (mouseOverInsert) { insertString = insert; @@ -213,7 +217,7 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou curX += textLen + 7; } - textRenderer.drawWithShadow(matrices, "Mode:", seperator + 8, y + 120 + line * 14, 0xffffff); + matrices.drawTextWithShadow(textRenderer, "Mode:", seperator + 8, y + 120 + line * 14, 0xffffff); int startY = y + 132 + line * 14; line = 0; @@ -227,8 +231,8 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou } boolean mouseOverInsert = mouseX >= seperator + 7 + curX && mouseX <= seperator + 10 + curX + textLen && mouseY >= startY + line * 14 && mouseY <= startY + 11 + line * 14; - fill(matrices, seperator + 7 + curX, startY + line * 14, seperator + 10 + curX + textLen, startY + 11 + line * 14, mouseOverInsert ? 0x9f6060b0 : 0x9f8070b0); - textRenderer.drawWithShadow(matrices, pair.getLeft(), seperator + 9 + curX, startY + 2 + line * 14, 0xffffff); + matrices.fill(seperator + 7 + curX, startY + line * 14, seperator + 10 + curX + textLen, startY + 11 + line * 14, mouseOverInsert ? 0x9f6060b0 : 0x9f8070b0); + matrices.drawTextWithShadow(textRenderer, pair.getLeft(), seperator + 9 + curX, startY + 2 + line * 14, 0xffffff); if (mouseOverInsert) { insertStartString = pair.getRight(); @@ -239,7 +243,7 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou boolean mouseOverDelete = mouseX >= x + w - 70 && mouseX <= x + w - 5 && mouseY >= y + h - 22 && mouseY <= y + h - 4; Window.fill(matrices, x + w - 70, y + h - 22, x + w - 5, y + h - 4, 0x60e05050, 0x60c07070, mouseOverDelete ? 0x20e05050 : 0x10e07070); - drawCenteredTextWithShadow(matrices, textRenderer, "Delete", x + w - 37, y + h - 17, 0xf0f0f0); + matrices.drawCenteredTextWithShadow(textRenderer, "Delete", x + w - 37, y + h - 17, 0xf0f0f0); if (mouseOverDelete) { deleteEntry = selectedEntry; @@ -261,9 +265,9 @@ public void close() { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - editNameField.mouseClicked(mouseX, mouseY, button); - editValueField.mouseClicked(mouseX, mouseY, button); + public boolean mouseClicked(Click click, boolean doubleClick) { + editNameField.mouseClicked(click, doubleClick); + editValueField.mouseClicked(click, doubleClick); if (hoverEntry != null && interactions.containsKey(hoverEntry)) { selectedEntry = hoverEntry; @@ -308,29 +312,23 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { insertString = null; } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(click, doubleClick); } @Override - public void tick() { - editNameField.tick(); - editValueField.tick(); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - if (editNameField.isFocused()) editNameField.charTyped(chr, modifiers); - if (editValueField.isFocused()) editValueField.charTyped(chr, modifiers); + public boolean charTyped(CharInput input) { + if (editNameField.isFocused()) editNameField.charTyped(input); + if (editValueField.isFocused()) editValueField.charTyped(input); - return super.charTyped(chr, modifiers); + return super.charTyped(input); } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (editNameField.isFocused()) editNameField.keyPressed(keyCode, scanCode, modifiers); - if (editValueField.isFocused()) editValueField.keyPressed(keyCode, scanCode, modifiers); + public boolean keyPressed(KeyInput input) { + if (editNameField.isFocused()) editNameField.keyPressed(input); + if (editValueField.isFocused()) editValueField.keyPressed(input); - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(input); } @Override diff --git a/src/main/java/org/bleachhack/gui/EntityMenuScreen.java b/src/main/java/org/bleachhack/gui/EntityMenuScreen.java index 725bbdb17c..92f9a87a90 100644 --- a/src/main/java/org/bleachhack/gui/EntityMenuScreen.java +++ b/src/main/java/org/bleachhack/gui/EntityMenuScreen.java @@ -8,18 +8,17 @@ */ package org.bleachhack.gui; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ChatScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.InventoryScreen; import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.InputUtil; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.LivingEntity; import net.minecraft.text.Text; +import net.minecraft.util.Identifier; import net.minecraft.util.Util; import net.minecraft.util.math.Direction.Axis; import net.minecraft.util.math.MathHelper; @@ -62,7 +61,7 @@ private void cursorMode(int mode) { double y = this.client.getWindow().getHeight() / 2d; KeyBinding.unpressAll(); - InputUtil.setCursorParameters(this.client.getWindow().getHandle(), GLFW.GLFW_CURSOR_HIDDEN, x, y); + InputUtil.setCursorParameters(this.client.getWindow(), GLFW.GLFW_CURSOR_HIDDEN, x, y); } public void tick() { @@ -82,14 +81,14 @@ public void close() { String message = ModuleManager.getModule(EntityMenu.class) .interactions.getValue(focusedString) .replaceAll("%name%", entity.getDisplayName().getString()) - .replaceAll("%uuid%", entity.getEntityName()) + .replaceAll("%uuid%", entity.getUuidAsString()) .replaceAll("%health%", String.valueOf((int) entity.getHealth())) .replaceAll("%x%", coordFormat.format(entity.getX())) .replaceAll("%y%", coordFormat.format(entity.getY())) .replaceAll("%z%", coordFormat.format(entity.getZ())); if (message.startsWith(">suggest ")) { - client.setScreen(new ChatScreen(message.substring(9))); + client.setScreen(new ChatScreen(message.substring(9), false)); } else if (message.startsWith(">url ")) { try { Util.getOperatingSystem().open(new URI(message.substring(5))); @@ -112,34 +111,32 @@ public boolean shouldPause() { return false; } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - // Draw entity - RenderSystem.setShader(GameRenderer::getPositionTexProgram); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, InventoryScreen.BACKGROUND_TEXTURE); + // The crosshair used vanilla's GUI icon atlas via an implicit bound-texture draw + a manual + // inverting blend function; both moved into RenderPipelines.CROSSHAIR + a dedicated texture + // Identifier (see InGameHud's own crosshair render code), so the manual GlStateManager blend + // setup is no longer needed - the pipeline bakes it in. + private static final Identifier CROSSHAIR_TEXTURE = Identifier.ofVanilla("hud/crosshair"); + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Draw entity int entitySize = (int) (120 / Boxes.getCornerLength(entity.getBoundingBox())); int entityHeight = entitySize / 2 - (int) (10 / Boxes.getAxisLength(entity.getBoundingBox(), Axis.Y)); + int cx = width / 2; + int cy = height / 2 + entityHeight; InventoryScreen.drawEntity(matrices, - width / 2, height / 2 + entityHeight, - entitySize, - (float) (width / 2) - mouseX, (float) (height / 2 + entityHeight - 45) - mouseY, + cx - entitySize, cy - entitySize, cx + entitySize, cy + entitySize, + entitySize, 0.0625f, mouseX, mouseY, entity); // Fake crosshair - RenderSystem.setShaderTexture(0, GUI_ICONS_TEXTURE); - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate( - GlStateManager.SrcFactor.ONE_MINUS_DST_COLOR, GlStateManager.DstFactor.ONE_MINUS_SRC_COLOR, - GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO); - drawTexture(matrices, crosshairX - 8, crosshairY - 8, 0, 0, 15, 15); + matrices.drawGuiTexture(RenderPipelines.CROSSHAIR, CROSSHAIR_TEXTURE, crosshairX - 8, crosshairY - 8, 15, 15); drawDots(matrices, (int) (Math.min(height, width) / 2 * 0.75), mouseX, mouseY); - matrices.push(); - matrices.scale(2.5f, 2.5f, 1f); - drawCenteredTextWithShadow(matrices, textRenderer, entity.getDisplayName().getString() /*"Interaction Screen"*/, width / 5, 5, 0xFFFFFFFF); - matrices.pop(); + matrices.getMatrices().pushMatrix(); + matrices.getMatrices().scale(2.5f, 2.5f); + matrices.drawCenteredTextWithShadow(textRenderer, entity.getDisplayName().getString() /*"Interaction Screen"*/, width / 5, 5, 0xFFFFFFFF); + matrices.getMatrices().popMatrix(); Vector2 center = new Vector2(width / 2, height / 2); Vector2 mouse = new Vector2(mouseX, mouseY).subtract(center).normalize(); @@ -158,7 +155,7 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { super.render(matrices, mouseX, mouseY, delta); } - private void drawDots(MatrixStack matrices, int radius, int mouseX, int mouseY) { + private void drawDots(DrawContext matrices, int radius, int mouseX, int mouseY) { MutablePairList map = ModuleManager.getModule(EntityMenu.class).interactions; List pointList = new ArrayList<>(); String[] cache = new String[map.size()]; @@ -194,40 +191,40 @@ private void drawDots(MatrixStack matrices, int radius, int mouseX, int mouseY) } } - private void drawRect(MatrixStack matrices, int startX, int startY, int width, int height, int colorInner,int colorOuter) { - drawHorizontalLine(matrices, startX, startX + width, startY, colorOuter); - drawHorizontalLine(matrices, startX, startX + width, startY + height, colorOuter); - drawVerticalLine(matrices, startX, startY, startY + height, colorOuter); - drawVerticalLine(matrices, startX + width, startY, startY + height, colorOuter); - fill(matrices, startX + 1, startY + 1, startX + width, startY + height, colorInner); + private void drawRect(DrawContext matrices, int startX, int startY, int width, int height, int colorInner,int colorOuter) { + matrices.drawHorizontalLine(startX, startX + width, startY, colorOuter); + matrices.drawHorizontalLine(startX, startX + width, startY + height, colorOuter); + matrices.drawVerticalLine(startX, startY, startY + height, colorOuter); + matrices.drawVerticalLine(startX + width, startY, startY + height, colorOuter); + matrices.fill(startX + 1, startY + 1, startX + width, startY + height, colorInner); } - private void drawTextField(MatrixStack matrices, int x, int y, String text) { + private void drawTextField(DrawContext matrices, int x, int y, String text) { if (x >= width / 2) { drawRect(matrices, x + 10, y - 8, textRenderer.getWidth(text) + 3, 15, 0x80808080, 0xFF000000); - drawTextWithShadow(matrices, textRenderer, text, x + 12, y - 4, 0xFFFFFFFF); + matrices.drawTextWithShadow(textRenderer, text, x + 12, y - 4, 0xFFFFFFFF); } else { drawRect(matrices, x - 14 - textRenderer.getWidth(text), y - 8, textRenderer.getWidth(text) + 3, 15, 0x80808080, 0xFF000000); - drawTextWithShadow(matrices, textRenderer, text, x - 12 - textRenderer.getWidth(text), y - 4, 0xFFFFFFFF); + matrices.drawTextWithShadow(textRenderer, text, x - 12 - textRenderer.getWidth(text), y - 4, 0xFFFFFFFF); } } // Literally drawing it in code - private void drawDot(MatrixStack matrices, int centerX, int centerY, int colorInner) { + private void drawDot(DrawContext matrices, int centerX, int centerY, int colorInner) { // Black background - fill(matrices, centerX - 1, centerY - 5, centerX + 2, centerY + 6, 0xff000000); - fill(matrices, centerX - 3, centerY - 4, centerX + 4, centerY + 5, 0xff000000); - fill(matrices, centerX - 4, centerY - 3, centerX + 5, centerY + 4, 0xff000000); - fill(matrices, centerX - 5, centerY - 1, centerX + 6, centerY + 2, 0xff000000); + matrices.fill(centerX - 1, centerY - 5, centerX + 2, centerY + 6, 0xff000000); + matrices.fill(centerX - 3, centerY - 4, centerX + 4, centerY + 5, 0xff000000); + matrices.fill(centerX - 4, centerY - 3, centerX + 5, centerY + 4, 0xff000000); + matrices.fill(centerX - 5, centerY - 1, centerX + 6, centerY + 2, 0xff000000); // Fill - fill(matrices, centerX - 1, centerY - 4, centerX + 2, centerY + 5, colorInner); - fill(matrices, centerX - 3, centerY - 3, centerX + 4, centerY + 4, colorInner); - fill(matrices, centerX - 4, centerY - 1, centerX + 5, centerY + 2, colorInner); + matrices.fill(centerX - 1, centerY - 4, centerX + 2, centerY + 5, colorInner); + matrices.fill(centerX - 3, centerY - 3, centerX + 4, centerY + 4, colorInner); + matrices.fill(centerX - 4, centerY - 1, centerX + 5, centerY + 2, colorInner); // Light overlay - fill(matrices, centerX - 1, centerY - 3, centerX + 1, centerY - 2, 0x80ffffff); - fill(matrices, centerX - 2, centerY - 2, centerX - 1, centerY - 1, 0x80ffffff); + matrices.fill(centerX - 1, centerY - 3, centerX + 1, centerY - 2, 0x80ffffff); + matrices.fill(centerX - 2, centerY - 2, centerX - 1, centerY - 1, 0x80ffffff); //fill(matrix, centerX - 3, centerY - 1, centerX - 2, centerY, 0x80ffffff); } } diff --git a/src/main/java/org/bleachhack/gui/FriendManagerScreen.java b/src/main/java/org/bleachhack/gui/FriendManagerScreen.java new file mode 100644 index 0000000000..c63d8f01e7 --- /dev/null +++ b/src/main/java/org/bleachhack/gui/FriendManagerScreen.java @@ -0,0 +1,185 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.gui; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +import org.bleachhack.BleachHack; +import org.bleachhack.gui.window.Window; +import org.bleachhack.gui.window.WindowScreen; +import org.bleachhack.gui.window.widget.WindowButtonWidget; +import org.bleachhack.gui.window.widget.WindowScrollbarWidget; +import org.bleachhack.gui.window.widget.WindowTextFieldWidget; +import org.bleachhack.gui.window.widget.WindowTextWidget; +import org.bleachhack.util.BleachLogger; +import org.bleachhack.util.io.BleachFileHelper; + +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.NativeImageBackedTexture; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class FriendManagerScreen extends WindowScreen { + + private static final int LIST_TOP = 52; + private static final int ROW_HEIGHT = 16; + private static final int HEAD_SIZE = 16; + + // keyed by friend name, shared across screen instances so re-opening this screen doesn't + // re-fetch heads it already resolved. mc-heads.net renders a head straight from a username - + // no UUID lookup step needed (Mojang's own username->UUID API turned out unreliable here). + private static final Map HEAD_CACHE = new ConcurrentHashMap<>(); + private static final Set HEAD_LOOKUPS_IN_FLIGHT = ConcurrentHashMap.newKeySet(); + + private int hovered = -1; + + private WindowScrollbarWidget scrollbar; + private WindowTextFieldWidget addField; + private List friends = new ArrayList<>(); + + public FriendManagerScreen() { + super(Text.literal("Friends")); + } + + public void init() { + super.init(); + + friends = new ArrayList<>(BleachHack.friendMang.getFriends()); + friends.forEach(this::loadHead); + + Window mainWindow = addWindow(new Window( + width / 8, height / 8, width - width / 8, height - height / 8, "Friends", new ItemStack(Items.PLAYER_HEAD))); + + int w = mainWindow.x2 - mainWindow.x1; + int h = mainWindow.y2 - mainWindow.y1; + + mainWindow.addWidget(new WindowTextWidget("Add a friend by name:", true, 6, 17, 0xf0f0f0)); + + addField = mainWindow.addWidget(new WindowTextFieldWidget(6, 28, w - 80, 18, "")); + mainWindow.addWidget(new WindowButtonWidget(w - 72, 28, w - 3, 46, "\u00a7aAdd", this::addFriend)); + + scrollbar = mainWindow.addWidget(new WindowScrollbarWidget(w - 11, LIST_TOP, friends.size() * ROW_HEIGHT - 1, h - LIST_TOP - 1, 0)); + } + + private void addFriend() { + String name = addField.textField.getText().trim(); + if (!name.isEmpty()) { + BleachHack.friendMang.add(name); + BleachFileHelper.SCHEDULE_SAVE_FRIENDS.set(true); + addField.textField.setText(""); + refreshList(); + } + } + + private void removeFriend(String name) { + BleachHack.friendMang.remove(name); + BleachFileHelper.SCHEDULE_SAVE_FRIENDS.set(true); + refreshList(); + } + + private void refreshList() { + friends = new ArrayList<>(BleachHack.friendMang.getFriends()); + friends.forEach(this::loadHead); + scrollbar.setTotalHeight(friends.size() * ROW_HEIGHT - 1); + } + + // Fetches a ready-made head render directly by username (no UUID lookup at all) and uploads it + // as a GPU texture. Runs off the render thread since it's a blocking HTTP call. + private void loadHead(String name) { + if (HEAD_CACHE.containsKey(name) || !HEAD_LOOKUPS_IN_FLIGHT.add(name)) { + return; + } + + CompletableFuture.runAsync(() -> { + try (InputStream in = URI.create("https://mc-heads.net/avatar/" + name + "/" + HEAD_SIZE + ".png").toURL().openStream()) { + NativeImage image = NativeImage.read(in); + Identifier id = Identifier.of("bleachhack", "friendhead/" + name.toLowerCase().replaceAll("[^a-z0-9_.-]", "_")); + + client.execute(() -> { + client.getTextureManager().registerTexture(id, new NativeImageBackedTexture(() -> "friend head " + name, image)); + HEAD_CACHE.put(name, id); + }); + } catch (IOException e) { + BleachLogger.logger.warn("Couldn't fetch head for friend \"" + name + "\"", e); + } finally { + HEAD_LOOKUPS_IN_FLIGHT.remove(name); + } + }); + } + + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + hovered = -1; + + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". + super.render(matrices, mouseX, mouseY, delta); + + if (friends.isEmpty()) { + Window w = getWindow(0); + matrices.drawCenteredTextWithShadow(textRenderer, "No friends added yet", (w.x1 + w.x2) / 2, w.y1 + LIST_TOP + 8, 0xa0a0a0); + } + } + + public void onRenderWindow(DrawContext matrices, int window, int mouseX, int mouseY) { + super.onRenderWindow(matrices, window, mouseX, mouseY); + + if (window != 0) return; + + Window win = getWindow(0); + int x = win.x1; + int y = win.y1; + int w = win.x2 - x; + int h = win.y2 - y; + + for (int i = 0; i < friends.size(); i++) { + String name = friends.get(i); + int curY = y + LIST_TOP + i * ROW_HEIGHT - scrollbar.getPageOffset(); + + if (curY + ROW_HEIGHT > y + h || curY < y + LIST_TOP - 1) + continue; + + Window.fill(matrices, x + 2, curY + 1, x + w - 12, curY + ROW_HEIGHT - 1, i % 2 == 0 ? 0x40606090 : 0x30606090); + + Identifier head = HEAD_CACHE.get(name); + if (head != null) { + matrices.drawTexture(RenderPipelines.GUI_TEXTURED, head, x + 4, curY + 2, 0, 0, 12, 12, 12, 12); + } + + matrices.drawTextWithShadow(textRenderer, name, x + 4 + ROW_HEIGHT - 4 + 4, curY + 4, -1); + + boolean removeHover = win.selected && mouseX >= x + w - 64 && mouseX <= x + w - 14 && mouseY >= curY && mouseY <= curY + ROW_HEIGHT - 1; + matrices.drawTextWithShadow(textRenderer, removeHover ? "\u00a7l\u00a7cRemove" : "\u00a7cRemove", x + w - 62, curY + 4, -1); + + if (removeHover) + hovered = i; + } + } + + public boolean mouseClicked(Click click, boolean doubleClick) { + if (hovered >= 0 && hovered < friends.size()) { + removeFriend(friends.get(hovered)); + hovered = -1; + } + + return super.mouseClicked(click, doubleClick); + } +} diff --git a/src/main/java/org/bleachhack/gui/NotebotScreen.java b/src/main/java/org/bleachhack/gui/NotebotScreen.java index d604b2e0f5..5c75b526b2 100644 --- a/src/main/java/org/bleachhack/gui/NotebotScreen.java +++ b/src/main/java/org/bleachhack/gui/NotebotScreen.java @@ -8,9 +8,9 @@ */ package org.bleachhack.gui; -import net.minecraft.block.enums.Instrument; -import net.minecraft.client.render.DiffuseLighting; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.block.enums.NoteBlockInstrument; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; @@ -71,12 +71,13 @@ public void init() { Util.getOperatingSystem().open(URI.create("https://www.youtube.com/watch?v=Z6O80jItoAk")))); } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - renderBackground(matrices); + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". super.render(matrices, mouseX, mouseY, delta); } - public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mouseY) { + public void onRenderWindow(DrawContext matrices, int window, int mouseX, int mouseY) { super.onRenderWindow(matrices, window, mouseX, mouseY); if (window == 0) { @@ -89,10 +90,10 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou for (int i = y + 20; i < y + h - 27; i += 10) pageEntries++; - drawCenteredTextWithShadow(matrices, textRenderer, "Page " + (page + 1), x + 55, y + 5, 0xc0c0ff); + matrices.drawCenteredTextWithShadow(textRenderer, "Page " + (page + 1), x + 55, y + 5, 0xc0c0ff); fillButton(matrices, x + 10, y + h - 13, x + 99, y + h - 3, 0xff3a3a3a, 0xff353535, mouseX, mouseY); - drawCenteredTextWithShadow(matrices, textRenderer, "Download Songs..", x + 55, y + h - 12, 0xc0dfdf); + matrices.drawCenteredTextWithShadow(textRenderer, "Download Songs..", x + 55, y + h - 12, 0xc0dfdf); Song nbSong = ModuleManager.getModule(Notebot.class).song; int c = 0, c1 = -1; @@ -106,33 +107,31 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou fillButton(matrices, x + 5, y + 15 + c * 10, x + 105, y + 25 + c * 10, nbSong != null && s.equals(nbSong.filename) ? 0xf0408040 : entry != null && s.equals(entry.filename) ? 0xf0202020 : 0xf0404040, 0xf0303030, mouseX, mouseY); - drawCenteredTextWithShadow(matrices, textRenderer, textRenderer.trimToWidth(s, 100), x + 55, y + 16 + c * 10, -1); + matrices.drawCenteredTextWithShadow(textRenderer, textRenderer.trimToWidth(s, 100), x + 55, y + 16 + c * 10, -1); c++; } if (entry != null) { int textX = x + w - w / 4; - drawCenteredTextWithShadow(matrices, textRenderer, entry.name, textX, y + 8, 0xffffff); - drawCenteredTextWithShadow(matrices, textRenderer, "By: " + entry.author, textX, y + 18, 0xb0b0b0); + matrices.drawCenteredTextWithShadow(textRenderer, entry.name, textX, y + 8, 0xffffff); + matrices.drawCenteredTextWithShadow(textRenderer, "By: " + entry.author, textX, y + 18, 0xb0b0b0); - drawCenteredTextWithShadow(matrices, textRenderer, "Format: \u00a7a" + entry.format, textX, y + 35, 0xb0b0b0); - drawCenteredTextWithShadow(matrices, textRenderer, "Length: \u00a7f" + entry.length / 20 + "s", textX, y + 45, 0xb0b0b0); + matrices.drawCenteredTextWithShadow(textRenderer, "Format: \u00a7a" + entry.format, textX, y + 35, 0xb0b0b0); + matrices.drawCenteredTextWithShadow(textRenderer, "Length: \u00a7f" + entry.length / 20 + "s", textX, y + 45, 0xb0b0b0); //drawCenteredText(matrices, textRenderer, "Notes: \u00a7f" + entry.notes.size(), textX, y + 55, 0xb0b0b0); - drawCenteredTextWithShadow(matrices, textRenderer, "Noteblocks: ", textX, y + 62, 0x80f080); + matrices.drawCenteredTextWithShadow(textRenderer, "Noteblocks: ", textX, y + 62, 0x80f080); int c2 = 0; - for (Entry e : NotebotUtils.INSTRUMENT_TO_ITEM.entrySet()) { + for (Entry e : NotebotUtils.INSTRUMENT_TO_ITEM.entrySet()) { int count = (int) entry.requirements.stream().filter(n -> n.instrument == e.getKey().ordinal()).count(); if (count != 0) { // itemRenderer.zOffset = 500 - c2 * 20; - drawCenteredTextWithShadow(matrices, textRenderer, StringUtils.capitalize(e.getKey().asString()) + " x" + count, + matrices.drawCenteredTextWithShadow(textRenderer, StringUtils.capitalize(e.getKey().asString()) + " x" + count, textX, y + 74 + c2 * 10, 0x50f050); - DiffuseLighting.enableGuiDepthLighting(); - itemRenderer.renderGuiItemIcon(matrices, e.getValue(), textX + 55, y + 70 + c2 * 10); - DiffuseLighting.disableGuiDepthLighting(); + matrices.drawItem(e.getValue(), textX + 55, y + 70 + c2 * 10); c2++; } @@ -143,11 +142,11 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou fillButton(matrices, x + w - w / 4 - w / 8, y + h - 27, x + w - w / 4 + w / 8, y + h - 17, 0xff303080, 0xff202070, mouseX, mouseY); int pixels = (int) Math.round(MathHelper.clamp((w / 4d) * ((double) playTick / (double) entry.length), 0, w / 4d)); - fill(matrices, x + w - w / 4 - w / 8, y + h - 27, (x + w - w / 4 - w / 8) + pixels, y + h - 17, 0x507050ff); + matrices.fill( x + w - w / 4 - w / 8, y + h - 27, (x + w - w / 4 - w / 8) + pixels, y + h - 17, 0x507050ff); - drawCenteredTextWithShadow(matrices, textRenderer, "Delete", (int) (x + w - w / 2.8), y + h - 14, 0xff0000); - drawCenteredTextWithShadow(matrices, textRenderer, "Select", x + w - w / 8, y + h - 14, 0x00ff00); - drawCenteredTextWithShadow(matrices, textRenderer, playing ? "Previewing.." : "Preview", x + w - w / 4, y + h - 26, 0x6060ff); + matrices.drawCenteredTextWithShadow(textRenderer, "Delete", (int) (x + w - w / 2.8), y + h - 14, 0xff0000); + matrices.drawCenteredTextWithShadow(textRenderer, "Select", x + w - w / 8, y + h - 14, 0x00ff00); + matrices.drawCenteredTextWithShadow(textRenderer, playing ? "Previewing.." : "Preview", x + w - w / 4, y + h - 26, 0x6060ff); } } } @@ -164,7 +163,10 @@ public boolean shouldPause() { return false; } - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(Click click, boolean doubleClick) { + double mouseX = click.x(); + double mouseY = click.y(); + if (!getWindow(0).closed) { int x = getWindow(0).x1; int y = getWindow(0).y1 + 10; @@ -212,10 +214,10 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(click, doubleClick); } - private void fillButton(MatrixStack matrices, int x1, int y1, int x2, int y2, int color, int colorHover, int mouseX, int mouseY) { - fill(matrices, x1, y1, x2, y2, (mouseX > x1 && mouseX < x2 && mouseY > y1 && mouseY < y2 ? colorHover : color)); + private void fillButton(DrawContext matrices, int x1, int y1, int x2, int y2, int color, int colorHover, int mouseX, int mouseY) { + matrices.fill( x1, y1, x2, y2, (mouseX > x1 && mouseX < x2 && mouseY > y1 && mouseY < y2 ? colorHover : color)); } } diff --git a/src/main/java/org/bleachhack/gui/ProtocolScreen.java b/src/main/java/org/bleachhack/gui/ProtocolScreen.java index e769d5b8ac..d913115a29 100644 --- a/src/main/java/org/bleachhack/gui/ProtocolScreen.java +++ b/src/main/java/org/bleachhack/gui/ProtocolScreen.java @@ -11,20 +11,27 @@ import net.minecraft.resource.ResourceType; import org.apache.commons.lang3.math.NumberUtils; -import net.minecraft.MinecraftVersion; import net.minecraft.SharedConstants; import net.minecraft.client.ClientBrandRetriever; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; - public class ProtocolScreen extends Screen { - + public static String BRAND = null; + // 1.21.11: SharedConstants.getGameVersion() returns an immutable GameVersion record - there are no + // mutable MinecraftVersion fields left to overwrite globally. Instead of faking the client's whole + // internal notion of its own version, this now only rewrites the actual outgoing handshake packet's + // protocolVersion (see MixinClientConnection) - a more faithful implementation of the feature's own + // stated intent ("only changes what the client says to servers") than the 1.19.4 approach was. + // There's no working equivalent left for spoofing the reported data pack version specifically (it's + // not part of any packet a server can observe), so that field stays display-only. + public static Integer PROTOCOL = null; + private TextFieldWidget versionField; private TextFieldWidget protocolField; // int private TextFieldWidget packVerField; // int @@ -41,14 +48,7 @@ public void init() { super.init(); addButton = addDrawableChild(ButtonWidget.builder(Text.literal("Done"), button -> { - int i = Integer.parseInt(protocolField.getText()); - int i1 = Integer.parseInt(packVerField.getText()); - - MinecraftVersion version = (MinecraftVersion) SharedConstants.getGameVersion(); - version.name = versionField.getText(); - // version.releaseTarget = versionField.getText(); - version.protocolVersion = i; - version.dataPackVersion = i1; + PROTOCOL = Integer.parseInt(protocolField.getText()); BRAND = brandField.getText(); close(); @@ -58,19 +58,19 @@ public void init() { button -> close()).position(width / 2 - 100, height / 2 + 73).size(196, 20).build()); versionField = addDrawableChild(new TextFieldWidget(textRenderer, width / 2 - 98, height / 2 - 60, 196, 18, Text.empty())); - versionField.setText(SharedConstants.getGameVersion().getName()); + versionField.setText(SharedConstants.getGameVersion().name()); protocolField = addDrawableChild(new TextFieldWidget(textRenderer, width / 2 - 98, height / 2 - 35, 196, 18, Text.empty())); - protocolField.setText(Integer.toString(SharedConstants.getProtocolVersion())); + protocolField.setText(Integer.toString(PROTOCOL != null ? PROTOCOL : SharedConstants.getProtocolVersion())); protocolField.setChangedListener(text -> updateAddButton()); packVerField = addDrawableChild(new TextFieldWidget(textRenderer, width / 2 - 98, height / 2 - 10, 196, 18, Text.empty())); - packVerField.setText(Integer.toString(SharedConstants.getGameVersion().getResourceVersion(ResourceType.CLIENT_RESOURCES))); + packVerField.setText(Integer.toString(SharedConstants.getGameVersion().packVersion(ResourceType.CLIENT_RESOURCES).major())); packVerField.setChangedListener(text -> updateAddButton()); - + brandField = addDrawableChild(new TextFieldWidget(textRenderer, width / 2 - 98, height / 2 + 15, 128, 18, Text.empty())); - brandField.setText(ClientBrandRetriever.getClientModName()); - + brandField.setText(BRAND != null ? BRAND : ClientBrandRetriever.getClientModName()); + addDrawableChild(ButtonWidget.builder(Text.literal("V"), button -> brandField.setText("vanilla")).position(width / 2 + 33, height / 2 + 14).size(20, 20).build()); addDrawableChild(ButtonWidget.builder(Text.literal("Fa"), @@ -79,32 +79,24 @@ public void init() { button -> brandField.setText("forge")).position(width / 2 + 79, height / 2 + 14).size(20, 20).build()); } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - renderBackground(matrices); - drawCenteredTextWithShadow(matrices, textRenderer, "NOTE: This will not make the game compatible with other versions", width / 2, 5, 0xaaaaaa); - drawCenteredTextWithShadow(matrices, textRenderer, "It will only change what the client says it is to servers.", width / 2, 15, 0xaaaaaa); + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". + context.drawCenteredTextWithShadow(textRenderer, "NOTE: This will not make the game compatible with other versions", width / 2, 5, 0xaaaaaa); + context.drawCenteredTextWithShadow(textRenderer, "It will only change what the client says it is to servers.", width / 2, 15, 0xaaaaaa); - drawTextWithShadow(matrices, textRenderer, "Version:", width / 2 - 103 - textRenderer.getWidth("Version:"), height / 2 - 55, 0xaaaaaa); - drawTextWithShadow(matrices, textRenderer, "Protocol:", width / 2 - 103 - textRenderer.getWidth("Protocol:"), height / 2 - 30, 0xaaaaaa); - drawTextWithShadow(matrices, textRenderer, "Pack Ver:", width / 2 - 103 - textRenderer.getWidth("Pack Ver:"), height / 2 - 5, 0xaaaaaa); - drawTextWithShadow(matrices, textRenderer, "Brand:", width / 2 - 103 - textRenderer.getWidth("Brand:"), height / 2 + 20, 0xaaaaaa); + context.drawTextWithShadow(textRenderer, "Version:", width / 2 - 103 - textRenderer.getWidth("Version:"), height / 2 - 55, 0xaaaaaa); + context.drawTextWithShadow(textRenderer, "Protocol:", width / 2 - 103 - textRenderer.getWidth("Protocol:"), height / 2 - 30, 0xaaaaaa); + context.drawTextWithShadow(textRenderer, "Pack Ver:", width / 2 - 103 - textRenderer.getWidth("Pack Ver:"), height / 2 - 5, 0xaaaaaa); + context.drawTextWithShadow(textRenderer, "Brand:", width / 2 - 103 - textRenderer.getWidth("Brand:"), height / 2 + 20, 0xaaaaaa); - super.render(matrices, mouseX, mouseY, delta); + super.render(context, mouseX, mouseY, delta); } public void close() { client.setScreen(parent); } - public void tick() { - versionField.tick(); - protocolField.tick(); - packVerField.tick(); - brandField.tick(); - - super.tick(); - } - private void updateAddButton() { addButton.active = NumberUtils.isDigits(protocolField.getText()) && NumberUtils.isDigits(packVerField.getText()); } diff --git a/src/main/java/org/bleachhack/gui/UpdateScreen.java b/src/main/java/org/bleachhack/gui/UpdateScreen.java index 987bb31311..d450eb66a4 100644 --- a/src/main/java/org/bleachhack/gui/UpdateScreen.java +++ b/src/main/java/org/bleachhack/gui/UpdateScreen.java @@ -12,7 +12,7 @@ import com.google.gson.JsonObject; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -170,9 +170,9 @@ public void init() { } @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - this.renderBackground(matrices); - + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". int offset = scrollbar.getOffsetSinceRender(); int wh = getWindow(0).y2 - getWindow(0).y1; for (WindowWidget widget: changelogWidgets) { @@ -185,10 +185,10 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - scrollbar.moveScrollbar((int) -amount * 7); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + scrollbar.moveScrollbar((int) -verticalAmount * 7); - return super.mouseScrolled(mouseX, mouseY, amount); + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } @Override diff --git a/src/main/java/org/bleachhack/gui/clickgui/ClickGuiScreen.java b/src/main/java/org/bleachhack/gui/clickgui/ClickGuiScreen.java index 14ecb11a81..f225578460 100644 --- a/src/main/java/org/bleachhack/gui/clickgui/ClickGuiScreen.java +++ b/src/main/java/org/bleachhack/gui/clickgui/ClickGuiScreen.java @@ -14,14 +14,17 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.ArrayUtils; +import org.bleachhack.gui.FriendManagerScreen; import org.bleachhack.gui.clickgui.window.ClickGuiWindow; import org.bleachhack.gui.clickgui.window.ClickGuiWindow.Tooltip; import org.bleachhack.gui.window.Window; import org.bleachhack.gui.window.WindowScreen; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.input.KeyInput; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; @@ -51,29 +54,45 @@ public boolean shouldPause() { return false; } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - this.renderBackground(matrices); + // Overridden by ModuleClickGuiScreen to make the "Scale" setting apply; the UI clickgui + // leaves this at 1 (unchanged behavior). Only the window/content area is scaled - the + // Modules/UI switcher bar below always draws and hit-tests in real screen pixels. + public float getScale() { + return 1f; + } + + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". + float scale = getScale(); + int vMouseX = (int) (mouseX / scale); + int vMouseY = (int) (mouseY / scale); + int vWidth = (int) (width / scale); for (Window w : getWindows()) { if (w instanceof ClickGuiWindow) { - ((ClickGuiWindow) w).updateKeys(mouseX, mouseY, keyDown, lmDown, rmDown, lmHeld, mwScroll); + ((ClickGuiWindow) w).updateKeys(vMouseX, vMouseY, keyDown, lmDown, rmDown, lmHeld, mwScroll); } } - super.render(matrices, mouseX, mouseY, delta); + if (scale != 1f) { + matrices.getMatrices().pushMatrix(); + matrices.getMatrices().scale(scale, scale); + } - matrices.push(); - matrices.translate(0, 0, 250); + super.render(matrices, vMouseX, vMouseY, delta); for (Window w : getWindows()) { if (w instanceof ClickGuiWindow) { Tooltip tooltip = ((ClickGuiWindow) w).getTooltip(); if (tooltip != null) { - int tooltipY = tooltip.y; - String[] split = tooltip.text.split("\n", -1 /* Adding -1 makes it keep empty splits */); ArrayUtils.reverse(split); + + List> segments = new ArrayList<>(); + int maxLineWidth = 0; + for (String s: split) { /* Match lines to end of words after it reaches 22 characters long */ Matcher mat = Pattern.compile(".{1,22}\\b\\W*").matcher(s); @@ -86,13 +105,33 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { if (lines.isEmpty()) lines.add(s); + for (String line: lines) + maxLineWidth = Math.max(maxLineWidth, textRenderer.getWidth(line)); + + segments.add(lines); + } + + // Flip the tooltip to the left of its anchor point instead of letting it run off the + // right edge of the screen (tooltip.x is normally just right of the setting row). + int boxX = tooltip.x; + if (boxX + maxLineWidth + 3 > vWidth) { + boxX = Math.max(0, tooltip.x - maxLineWidth - 9); + } + + // The tooltip is drawn growing upward from its anchor - a long description near + // the top of the screen would otherwise have its first lines pushed off the top + // edge and become unreadable. Shift the whole thing down just enough to keep its + // topmost line on screen instead. + int totalHeight = segments.stream().mapToInt(List::size).sum() * 10; + int tooltipY = Math.max(tooltip.y, totalHeight); + for (List lines: segments) { int start = tooltipY - lines.size() * 10; for (int l = 0; l < lines.size(); l++) { - fill(matrices, tooltip.x, start + (l * 10) - 1, - tooltip.x + textRenderer.getWidth(lines.get(l)) + 3, + matrices.fill(boxX, start + (l * 10) - 1, + boxX + textRenderer.getWidth(lines.get(l)) + 3, start + (l * 10) + 9, 0xff000000); - textRenderer.drawWithShadow(matrices, lines.get(l), tooltip.x + 2, start + (l * 10), -1); + matrices.drawTextWithShadow(textRenderer, lines.get(l), boxX + 2, start + (l * 10), -1); } tooltipY -= lines.size() * 10; @@ -100,37 +139,49 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { } } } - + + if (scale != 1f) { + matrices.getMatrices().popMatrix(); + } + Window.fill(matrices, width / 2 - 50, -1, width / 2 - 2, 12, mouseX >= width / 2 - 50 && mouseX <= width / 2 - 2 && mouseY >= 0 && mouseY <= 12 ? 0x60b070f0 : 0x60606090); Window.fill(matrices, width / 2 + 2, -1, width / 2 + 50, 12, mouseX >= width / 2 + 2 && mouseX <= width / 2 + 50 && mouseY >= 0 && mouseY <= 12 ? 0x60b070f0 : 0x60606090); + Window.fill(matrices, width / 2 + 54, -1, width / 2 + 106, 12, + mouseX >= width / 2 + 54 && mouseX <= width / 2 + 106 && mouseY >= 0 && mouseY <= 12 ? 0x60b070f0 : 0x60606090); + + matrices.drawCenteredTextWithShadow(textRenderer, "Modules", width / 2 - 26, 2, 0xf0f0f0); + matrices.drawCenteredTextWithShadow(textRenderer, "UI", width / 2 + 26, 2, 0xf0f0f0); + matrices.drawCenteredTextWithShadow(textRenderer, "Friends", width / 2 + 80, 2, 0xf0f0f0); - drawCenteredTextWithShadow(matrices, textRenderer, "Modules", width / 2 - 26, 2, 0xf0f0f0); - drawCenteredTextWithShadow(matrices, textRenderer, "UI", width / 2 + 26, 2, 0xf0f0f0); - if (warningOpacity > 3) { - drawCenteredTextWithShadow(matrices, textRenderer, "UI not available on the main menu!", width / 2, 17, + matrices.drawCenteredTextWithShadow(textRenderer, "UI not available on the main menu!", width / 2, 17, warningOpacity > 255 ? 0xd14a3b : (warningOpacity << 24) | 0xd14a3b); warningOpacity -= 3; } - matrices.pop(); - lmDown = false; rmDown = false; keyDown = -1; mwScroll = 0; } - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(Click click, boolean doubleClick) { + double mouseX = click.x(); + double mouseY = click.y(); + int button = click.button(); + if (button == 0) { if (mouseX >= width / 2 - 50 && mouseX <= width / 2 - 2 && mouseY >= 0 && mouseY <= 12) { - client.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1f)); + client.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1f)); tryOpen(ModuleClickGuiScreen.INSTANCE); } else if (mouseX >= width / 2 + 2 && mouseX <= width / 2 + 50 && mouseY >= 0 && mouseY <= 12) { - client.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1f)); + client.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1f)); tryOpen(UIClickGuiScreen.INSTANCE); + } else if (mouseX >= width / 2 + 54 && mouseX <= width / 2 + 106 && mouseY >= 0 && mouseY <= 12) { + client.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1f)); + client.setScreen(new FriendManagerScreen()); } else { lmDown = true; lmHeld = true; @@ -139,23 +190,30 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { rmDown = true; } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(scaleClick(click), doubleClick); } - public boolean mouseReleased(double mouseX, double mouseY, int button) { - if (button == 0) + public boolean mouseReleased(Click click) { + if (click.button() == 0) lmHeld = false; - return super.mouseReleased(mouseX, mouseY, button); + return super.mouseReleased(scaleClick(click)); + } + + // Windows are laid out/hit-tested in unscaled ("virtual") coordinates - convert real clicks + // into that space so hit-testing lines up with what render() draws under getScale(). + private Click scaleClick(Click click) { + float scale = getScale(); + return scale == 1f ? click : new Click(click.x() / scale, click.y() / scale, click.buttonInfo()); } - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - keyDown = keyCode; - return super.keyPressed(keyCode, scanCode, modifiers); + public boolean keyPressed(KeyInput input) { + keyDown = input.key(); + return super.keyPressed(input); } - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - mwScroll = (int) amount; - return super.mouseScrolled(mouseX, mouseY, amount); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + mwScroll = (int) verticalAmount; + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } private void tryOpen(Screen screen) { diff --git a/src/main/java/org/bleachhack/gui/clickgui/ModuleClickGuiScreen.java b/src/main/java/org/bleachhack/gui/clickgui/ModuleClickGuiScreen.java index 573938e921..710c41ee6c 100644 --- a/src/main/java/org/bleachhack/gui/clickgui/ModuleClickGuiScreen.java +++ b/src/main/java/org/bleachhack/gui/clickgui/ModuleClickGuiScreen.java @@ -22,12 +22,15 @@ import org.bleachhack.module.ModuleCategory; import org.bleachhack.module.ModuleManager; import org.bleachhack.module.mods.ClickGui; +import org.bleachhack.setting.module.SettingToggle; import org.bleachhack.util.io.BleachFileHelper; import net.minecraft.SharedConstants; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.input.KeyInput; import net.minecraft.text.Text; +import org.lwjgl.glfw.GLFW; public class ModuleClickGuiScreen extends ClickGuiScreen { @@ -36,6 +39,11 @@ public class ModuleClickGuiScreen extends ClickGuiScreen { private TextFieldWidget searchField; + // True while the search bar is only open because Ctrl+F opened it, i.e. the "Search bar" setting + // itself is off. It gets closed again as soon as the search is over (field loses focus / gui + // closes) instead of staying open, which would silently flip the setting on. + private boolean temporarySearch; + public ModuleClickGuiScreen() { super(Text.literal("ClickGui")); } @@ -50,13 +58,88 @@ public void init() { addDrawableChild(searchField); } + @Override + public boolean keyPressed(KeyInput input) { + if (input.key() == GLFW.GLFW_KEY_F && (input.modifiers() & GLFW.GLFW_MOD_CONTROL) != 0) { + // Ctrl+F always means "let me search", never "hide the search bar" - so show it if it's + // hidden and jump straight into typing either way. Focus has to be set on the screen + // (not just the widget) or charTyped() is never routed to the field and typing is eaten. + SettingToggle searchBar = ModuleManager.getModule(ClickGui.class).getSetting(1).asToggle(); + if (!searchBar.getState()) { + searchBar.setValue(true); + temporarySearch = true; + } + + searchField.visible = true; + setFocused(searchField); + searchField.setFocused(true); + return true; + } + + return super.keyPressed(input); + } + + private void endTemporarySearch() { + temporarySearch = false; + searchField.setText(""); + searchField.visible = false; + ModuleManager.getModule(ClickGui.class).getSetting(1).asToggle().setValue(false); + + for (Window w : getWindows()) { + if (w instanceof ModuleWindow) { + ((ModuleWindow) w).setSearchedModule(new HashSet<>()); + } + } + } + + @Override + public void removed() { + if (temporarySearch) { + endTemporarySearch(); + } + + super.removed(); + } + + @Override + public float getScale() { + ClickGui clickGui = ModuleManager.getModule(ClickGui.class); + + float manual = clickGui.getSetting(3).asSlider().getValueInt() / 100f; + return clickGui.getSetting(4).asToggle().getState() ? computeAutoFitScale() * manual : manual; + } + + // Minecraft's GUI Scale changes how many virtual pixels fit on screen, which otherwise makes + // the clickgui visibly bigger/smaller as you change it (same virtual size, different real + // size). Countering that 1:1 keeps the clickgui's real on-screen size constant regardless of + // GUI Scale - 2 is the reference factor (matches the manual Scale slider's 100% default on a + // typical GUI Scale of 2). + private float computeAutoFitScale() { + int factor = Math.max(1, client.getWindow().getScaleFactor()); + return Math.max(0.5f, Math.min(2f, 2f / factor)); + } + public void initWindows() { int len = ModuleManager.getModule(ClickGui.class).getSetting(0).asSlider().getValueInt(); - - int y = 50; + + // Wrap into a new column instead of running the category tabs off the bottom of the + // screen - windows are user-draggable and their positions get saved, so a scroll offset + // that keeps repositioning them every frame would fight (and undo) that. + int screenHeight = (int) (client.getWindow().getScaledHeight() / Math.max(getScale(), 0.01f)); + int maxRows = Math.max(1, (screenHeight - 50) / 16); + + int col = 0; + int row = 0; for (ModuleCategory c: ModuleCategory.values()) { - addWindow(new ModuleWindow(ModuleManager.getModulesInCat(c), 30, y, len, StringUtils.capitalize(c.name().toLowerCase()), c.getItem())); - y += 16; + int x = 30 + col * (len + 10); + int y = 50 + row * 16; + addWindow(new ModuleWindow(ModuleManager.getModulesInCat(c), x, y, len, StringUtils.capitalize(c.name().toLowerCase()), c.getItem())); + + row++; + if (row >= maxRows) { + row = 0; + col++; + } } for (Window w: getWindows()) { @@ -66,10 +149,16 @@ public void initWindows() { } } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { BleachFileHelper.SCHEDULE_SAVE_CLICKGUI.set(true); ClickGui clickGui = ModuleManager.getModule(ClickGui.class); + // Clicking anything else (a module, a window) unfocuses the field - that's the search being + // over, so a Ctrl+F-opened bar goes away again. + if (temporarySearch && !searchField.isFocused()) { + endTemporarySearch(); + } + searchField.visible = clickGui.getSetting(1).asToggle().getState(); if (clickGui.getSetting(1).asToggle().getState()) { @@ -100,12 +189,12 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { super.render(matrices, mouseX, mouseY, delta); - textRenderer.draw(matrices, "BleachHack-" + BleachHack.VERSION + "-" + SharedConstants.getGameVersion().getName(), 3, 3, 0x305090); - textRenderer.draw(matrices, "BleachHack-" + BleachHack.VERSION + "-" + SharedConstants.getGameVersion().getName(), 2, 2, 0x6090d0); + matrices.drawText(textRenderer, "BleachHack-" + BleachHack.VERSION + "-" + SharedConstants.getGameVersion().name(), 3, 3, 0x305090, false); + matrices.drawText(textRenderer, "BleachHack-" + BleachHack.VERSION + "-" + SharedConstants.getGameVersion().name(), 2, 2, 0x6090d0, false); if (clickGui.getSetting(2).asToggle().getState()) { - textRenderer.drawWithShadow(matrices, "Current prefix is: \"" + Command.getPrefix() + "\" (" + Command.getPrefix() + "help)", 2, height - 20, 0x99ff99); - textRenderer.drawWithShadow(matrices, "Use " + Command.getPrefix() + "clickgui to reset the clickgui", 2, height - 10, 0x9999ff); + matrices.drawTextWithShadow(textRenderer, "Current prefix is: \"" + Command.getPrefix() + "\" (" + Command.getPrefix() + "help)", 2, height - 20, 0x99ff99); + matrices.drawTextWithShadow(textRenderer, "Use " + Command.getPrefix() + "clickgui to reset the clickgui", 2, height - 10, 0x9999ff); } } } diff --git a/src/main/java/org/bleachhack/gui/clickgui/UIClickGuiScreen.java b/src/main/java/org/bleachhack/gui/clickgui/UIClickGuiScreen.java index 8ab1e6ceca..7b106089bd 100644 --- a/src/main/java/org/bleachhack/gui/clickgui/UIClickGuiScreen.java +++ b/src/main/java/org/bleachhack/gui/clickgui/UIClickGuiScreen.java @@ -17,7 +17,7 @@ import org.bleachhack.module.mods.UI; import org.bleachhack.util.io.BleachFileHelper; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; @@ -48,7 +48,7 @@ public void init() { 200, 200, 75, "Render", new ItemStack(Items.YELLOW_STAINED_GLASS))); } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { BleachFileHelper.SCHEDULE_SAVE_UI.set(true); uiContainer.updatePositions(width, height); diff --git a/src/main/java/org/bleachhack/gui/clickgui/window/ClickGuiWindow.java b/src/main/java/org/bleachhack/gui/clickgui/window/ClickGuiWindow.java index 955c341f30..2dfe7fe5bc 100644 --- a/src/main/java/org/bleachhack/gui/clickgui/window/ClickGuiWindow.java +++ b/src/main/java/org/bleachhack/gui/clickgui/window/ClickGuiWindow.java @@ -12,9 +12,8 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; import net.minecraft.sound.SoundEvents; @@ -41,28 +40,28 @@ public boolean shouldClose(int mouseX, int mouseY) { return false; } - protected void drawBackground(MatrixStack matrices, int mouseX, int mouseY, TextRenderer textRend) { + protected void drawBackground(DrawContext matrices, int mouseX, int mouseY, TextRenderer textRend) { /* background */ - DrawableHelper.fill(matrices, x1, y1 + 1, x1 + 1, y2 - 1, 0xff6060b0); + matrices.fill(x1, y1 + 1, x1 + 1, y2 - 1, 0xff6060b0); horizontalGradient(matrices, x1 + 1, y1, x2 - 1, y1 + 1, 0xff6060b0, 0xff8070b0); - DrawableHelper.fill(matrices, x2 - 1, y1 + 1, x2, y2 - 1, 0xff8070b0); + matrices.fill(x2 - 1, y1 + 1, x2, y2 - 1, 0xff8070b0); horizontalGradient(matrices, x1 + 1, y2 - 1, x2 - 1, y2, 0xff6060b0, 0xff8070b0); - DrawableHelper.fill(matrices, x1 + 1, y1 + 12, x2 - 1, y2 - 1, 0x90606090); + matrices.fill(x1 + 1, y1 + 12, x2 - 1, y2 - 1, 0x90606090); /* title bar */ horizontalGradient(matrices, x1 + 1, y1 + 1, x2 - 1, y1 + 12, 0xff6060b0, 0xff8070b0); /* +/- text */ - textRend.draw(matrices, hiding ? "+" : "_", x2 - 10, y1 + (hiding ? 4 : 2), 0x000000); - textRend.draw(matrices, hiding ? "+" : "_", x2 - 11, y1 + (hiding ? 3 : 1), 0xffffff); + matrices.drawText(textRend, hiding ? "+" : "_", x2 - 10, y1 + (hiding ? 4 : 2), 0x000000, false); + matrices.drawText(textRend, hiding ? "+" : "_", x2 - 11, y1 + (hiding ? 3 : 1), 0xffffff, false); } - public void render(MatrixStack matrices, int mouseX, int mouseY) { + public void render(DrawContext matrices, int mouseX, int mouseY) { super.render(matrices, mouseX, mouseY); if (rmDown && mouseOver(x1, y1, x1 + (x2 - x1), y1 + 13)) { - mc.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + mc.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1.0F)); hiding = !hiding; } } diff --git a/src/main/java/org/bleachhack/gui/clickgui/window/ModuleWindow.java b/src/main/java/org/bleachhack/gui/clickgui/window/ModuleWindow.java index 2b0c6c3fa2..3d21fdcc08 100644 --- a/src/main/java/org/bleachhack/gui/clickgui/window/ModuleWindow.java +++ b/src/main/java/org/bleachhack/gui/clickgui/window/ModuleWindow.java @@ -14,15 +14,15 @@ import java.util.Map.Entry; import java.util.Set; +import org.bleachhack.gui.clickgui.ModuleClickGuiScreen; import org.bleachhack.module.Module; import org.bleachhack.module.ModuleManager; import org.bleachhack.module.mods.ClickGui; import org.bleachhack.setting.module.ModuleSetting; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; import net.minecraft.sound.SoundEvents; @@ -37,6 +37,9 @@ public class ModuleWindow extends ClickGuiWindow { private Tooltip tooltip = null; + // how far the module list is scrolled down, in pixels; clamped to [0, content height - visible height] + private int scrollOffset = 0; + public ModuleWindow(List mods, int x1, int y1, int len, String title, ItemStack icon) { super(x1, y1, x1 + len, 0, title, icon); @@ -49,12 +52,25 @@ public ModuleWindow(List mods, int x1, int y1, int len, String title, It y2 = getHeight(); } - public void render(MatrixStack matrices, int mouseX, int mouseY) { + public void render(DrawContext matrices, int mouseX, int mouseY) { tooltip = null; int x = x1 + 1; int y = y1 + 13; x2 = x + len + 1; - y2 = hiding ? y1 + 13 : y1 + 13 + getHeight(); + + int contentHeight = getHeight(); + // leave a small margin so the window never quite touches the bottom of the screen; the + // clickgui's own content scale (ModuleClickGuiScreen's "Scale" setting) shrinks/grows how + // many real screen pixels one virtual (content-space) pixel covers + int screenHeight = (int) (mc.getWindow().getScaledHeight() / ModuleClickGuiScreen.INSTANCE.getScale()); + int visibleHeight = hiding ? 0 : Math.min(contentHeight, Math.max(12, screenHeight - y - 4)); + y2 = hiding ? y1 + 13 : y1 + 13 + visibleHeight; + + boolean scrollable = !hiding && contentHeight > visibleHeight; + if (scrollable && mwScroll != 0 && mouseOver(x1, y1, x2, y2)) { + scrollOffset -= mwScroll * 12; + } + scrollOffset = Math.max(0, Math.min(scrollOffset, Math.max(0, contentHeight - visibleHeight))); super.render(matrices, mouseX, mouseY); @@ -62,30 +78,36 @@ public void render(MatrixStack matrices, int mouseX, int mouseY) { TextRenderer textRend = mc.textRenderer; - int curY = 0; + if (scrollable) { + matrices.enableScissor(x, y, x + len, y + visibleHeight); + } + + int curY = -scrollOffset; for (Entry m : mods.entrySet()) { - if (mouseOver(x, y + curY, x + len, y + 12 + curY)) { - DrawableHelper.fill(matrices, x, y + curY, x + len, y + 12 + curY, 0x70303070); - } + if (curY + 12 > 0 && curY < visibleHeight) { + if (mouseOver(x, y + curY, x + len, y + 12 + curY)) { + matrices.fill(x, y + curY, x + len, y + 12 + curY, 0x70303070); + } - // If they match: Module gets marked red - if (searchedModules != null && searchedModules.contains(m.getKey()) && ModuleManager.getModule(ClickGui.class).getSetting(1).asToggle().getState()) { - DrawableHelper.fill(matrices, x, y + curY, x + len, y + 12 + curY, 0x50ff0000); - } + // If they match: Module gets marked red + if (searchedModules != null && searchedModules.contains(m.getKey()) && ModuleManager.getModule(ClickGui.class).getSetting(1).asToggle().getState()) { + matrices.fill(x, y + curY, x + len, y + 12 + curY, 0x50ff0000); + } - textRend.drawWithShadow(matrices, textRend.trimToWidth(m.getKey().getName(), len), - x + 2, y + 2 + curY, m.getKey().isEnabled() ? 0x70efe0 : 0xc0c0c0); + matrices.drawTextWithShadow(textRend, textRend.trimToWidth(m.getKey().getName(), len), + x + 2, y + 2 + curY, m.getKey().isEnabled() ? 0x70efe0 : 0xc0c0c0); - // Set which module settings show on - if (mouseOver(x, y + curY, x + len, y + 12 + curY)) { - tooltip = new Tooltip(x + len + 2, y + curY, m.getKey().getDesc()); + // Set which module settings show on + if (mouseOver(x, y + curY, x + len, y + 12 + curY)) { + tooltip = new Tooltip(x + len + 2, y + curY, m.getKey().getDesc()); - if (lmDown) - m.getKey().toggle(); - if (rmDown) - mods.replace(m.getKey(), !m.getValue()); - if (lmDown || rmDown) - mc.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + if (lmDown) + m.getKey().toggle(); + if (rmDown) + mods.replace(m.getKey(), !m.getValue()); + if (lmDown || rmDown) + mc.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + } } curY += 12; @@ -93,18 +115,30 @@ public void render(MatrixStack matrices, int mouseX, int mouseY) { // draw settings if (m.getValue()) { for (ModuleSetting s : m.getKey().getSettings()) { - s.render(this, matrices, x + 1, y + curY, len - 1); - - if (!s.getTooltip().isEmpty() && mouseOver(x + 2, y + curY, x + len, y + s.getHeight(len) + curY)) { - tooltip = s.getTooltip(this, x + 1, y + curY, len - 1); + if (!s.isVisible()) { + continue; } - DrawableHelper.fill(matrices, x + 1, y + curY, x + 2, y + curY + s.getHeight(len), 0xff8070b0); + int settingHeight = s.getHeight(len); + + if (curY + settingHeight > 0 && curY < visibleHeight) { + s.render(this, matrices, x + 1, y + curY, len - 1); - curY += s.getHeight(len); + if (!s.getTooltip().isEmpty() && mouseOver(x + 2, y + curY, x + len, y + settingHeight + curY)) { + tooltip = s.getTooltip(this, x + 1, y + curY, len - 1); + } + + matrices.fill(x + 1, y + curY, x + 2, y + curY + settingHeight, 0xff8070b0); + } + + curY += settingHeight; } } } + + if (scrollable) { + matrices.disableScissor(); + } } public Tooltip getTooltip() { @@ -126,7 +160,9 @@ public int getHeight() { if (e.getValue()) { for (ModuleSetting s : e.getKey().getSettings()) { - h += s.getHeight(len); + if (s.isVisible()) { + h += s.getHeight(len); + } } } } diff --git a/src/main/java/org/bleachhack/gui/clickgui/window/UIContainer.java b/src/main/java/org/bleachhack/gui/clickgui/window/UIContainer.java index 41162b91a2..5260a5b8ec 100644 --- a/src/main/java/org/bleachhack/gui/clickgui/window/UIContainer.java +++ b/src/main/java/org/bleachhack/gui/clickgui/window/UIContainer.java @@ -7,7 +7,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ChatScreen; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public class UIContainer { @@ -16,7 +16,7 @@ public class UIContainer { public UIContainer() { } - public void render(MatrixStack matrices) { + public void render(DrawContext matrices) { for (UIWindow w: windows.values()) { if (!w.shouldClose()) { w.renderUI(matrices); diff --git a/src/main/java/org/bleachhack/gui/clickgui/window/UIWindow.java b/src/main/java/org/bleachhack/gui/clickgui/window/UIWindow.java index 928b59062a..488bec83cc 100644 --- a/src/main/java/org/bleachhack/gui/clickgui/window/UIWindow.java +++ b/src/main/java/org/bleachhack/gui/clickgui/window/UIWindow.java @@ -14,11 +14,12 @@ import org.apache.logging.log4j.util.TriConsumer; +import org.lwjgl.glfw.GLFW; + import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; // this is worse than dispenser32k // gonna have no idea what any of this does in 2 weeks @@ -28,11 +29,11 @@ public class UIWindow extends ClickGuiWindow { private BooleanSupplier enabledSupplier; private Supplier sizeSupplier; - private TriConsumer renderConsumer; + private TriConsumer renderConsumer; private UIContainer parentContainer; - public UIWindow(Position pos, UIContainer parentContainer, BooleanSupplier enabledSupplier, Supplier sizeSupplier, TriConsumer renderConsumer) { + public UIWindow(Position pos, UIContainer parentContainer, BooleanSupplier enabledSupplier, Supplier sizeSupplier, TriConsumer renderConsumer) { super(0, 0, 0, 0, "", null); this.position = pos; @@ -46,7 +47,7 @@ public int[] getSize() { return sizeSupplier.get(); } - public void renderUI(MatrixStack matrices) { + public void renderUI(DrawContext matrices) { renderConsumer.accept(matrices, x1, y1); } @@ -67,7 +68,20 @@ public void detachFromOthers(boolean detachFromConstants) { position.getAttachments().keySet().removeIf(id -> detachFromConstants || id.length() > 1); } - public void render(MatrixStack matrices, int mouseX, int mouseY) { + public void render(DrawContext matrices, int mouseX, int mouseY) { + // Long-standing bug (present since 1.19.4, not a port regression): dragging one of these + // windows and releasing the mouse sometimes leaves it glued to the cursor forever, because + // this window's drag-follow logic below re-derives x1/y1 (and re-saves them as a new + // percentage-based Position) from the live mouse position every frame while dragging==true, + // with nothing else ever reading it back to notice the button was actually released. The + // plain ModuleWindow drag path doesn't have this self-perpetuating loop, which is why only + // this "UI positioning" window type ever gets stuck. Rather than rely solely on + // mouseReleased() (which should already clear dragging, but evidently doesn't always land), + // double check the real GLFW button state here and self-heal if it's already up. + if (dragging && GLFW.glfwGetMouseButton(mc.getWindow().getHandle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_RELEASE) { + dragging = false; + } + // Handling of attaching/detaching when dragging int sens = 5; if (dragging) { @@ -176,7 +190,7 @@ public void render(MatrixStack matrices, int mouseX, int mouseY) { renderUI(matrices); } - protected void drawBackground(MatrixStack matrices, int mouseX, int mouseY, TextRenderer textRend) { + protected void drawBackground(DrawContext matrices, int mouseX, int mouseY, TextRenderer textRend) { // background /*DrawableHelper.fill(matrices, x1, y1 + 1, x1 + 1, y2 - 1, 0xff6060b0); horizontalGradient(matrices, x1 + 1, y1, x2 - 1, y1 + 1, 0xff6060b0, 0xff8070b0); @@ -195,7 +209,7 @@ protected void drawBackground(MatrixStack matrices, int mouseX, int mouseY, Text (position.getAttachments().containsValue(0) ? 0xff60b060 : 0xff6060b0), (position.getAttachments().containsValue(0) ? 0xff80c060 : 0xff8070b0));*/ - DrawableHelper.fill(matrices, x1, y1, x2, y2, 0x90606090); + matrices.fill(x1, y1, x2, y2, 0x90606090); } public void mouseClicked(double mouseX, double mouseY, int button) { diff --git a/src/main/java/org/bleachhack/gui/effect/ParticleManager.java b/src/main/java/org/bleachhack/gui/effect/ParticleManager.java index 3842644374..17a522fafe 100644 --- a/src/main/java/org/bleachhack/gui/effect/ParticleManager.java +++ b/src/main/java/org/bleachhack/gui/effect/ParticleManager.java @@ -11,8 +11,7 @@ import java.util.ArrayList; import java.util.List; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public class ParticleManager { @@ -22,7 +21,7 @@ public void addParticle(int x, int y) { particles.add(new Particle(x, y)); } - public void renderParticles(MatrixStack matrices) { + public void renderParticles(DrawContext matrices) { List tempParts = new ArrayList<>(); for (Particle p : particles) { @@ -35,7 +34,7 @@ public void renderParticles(MatrixStack matrices) { for (Particle p : particles) { for (int[] p1 : p.getParticles()) { - DrawableHelper.fill(matrices, p1[0], p1[1], p1[0] + 1, p1[1] + 1, 0xffffc0e0); + matrices.fill(p1[0], p1[1], p1[0] + 1, p1[1] + 1, 0xffffc0e0); } } } diff --git a/src/main/java/org/bleachhack/gui/window/Window.java b/src/main/java/org/bleachhack/gui/window/Window.java index 637564303a..180739d413 100644 --- a/src/main/java/org/bleachhack/gui/window/Window.java +++ b/src/main/java/org/bleachhack/gui/window/Window.java @@ -14,21 +14,13 @@ import org.bleachhack.gui.window.widget.WindowWidget; -import com.mojang.blaze3d.systems.RenderSystem; - import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.DiffuseLighting; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.util.math.ColorHelper; public class Window { @@ -72,7 +64,7 @@ public T addWidget(T widget) { return widget; } - public void render(MatrixStack matrices, int mouseX, int mouseY) { + public void render(DrawContext context, int mouseX, int mouseY) { TextRenderer textRend = MinecraftClient.getInstance().textRenderer; if (dragging) { @@ -82,11 +74,11 @@ public void render(MatrixStack matrices, int mouseX, int mouseY) { y1 = Math.max(0, mouseY - dragOffY); } - drawBackground(matrices, mouseX, mouseY, textRend); + drawBackground(context, mouseX, mouseY, textRend); for (WindowWidget w : widgets) { if (w.shouldRender(x1, y1, x2, y2)) { - w.render(matrices, x1, y1, mouseX, mouseY); + w.render(context, x1, y1, mouseX, mouseY); } } @@ -94,41 +86,38 @@ public void render(MatrixStack matrices, int mouseX, int mouseY) { /* window icon */ if (icon != null) { - RenderSystem.getModelViewStack().push(); - RenderSystem.getModelViewStack().translate(x1 + (blockItem ? 3 : 2), y1 + 2, 0); - RenderSystem.getModelViewStack().scale(0.6f, 0.6f, 1f); + context.getMatrices().pushMatrix(); + context.getMatrices().translate(x1 + (blockItem ? 3 : 2), y1 + 2); + context.getMatrices().scale(0.6f, 0.6f); - DiffuseLighting.enableGuiDepthLighting(); - MinecraftClient.getInstance().getItemRenderer().renderInGuiWithOverrides(matrices, icon, 0, 0); - DiffuseLighting.disableGuiDepthLighting(); + context.drawItem(icon, 0, 0); - RenderSystem.getModelViewStack().pop(); - RenderSystem.applyModelViewMatrix(); + context.getMatrices().popMatrix(); } /* window title */ - textRend.drawWithShadow(matrices, title, + context.drawTextWithShadow(textRend, title, x1 + (icon == null || icon.getItem() == Items.AIR ? 4 : (blockItem ? 15 : 14)), y1 + 3, -1); } - protected void drawBackground(MatrixStack matrices, int mouseX, int mouseY, TextRenderer textRend) { + protected void drawBackground(DrawContext context, int mouseX, int mouseY, TextRenderer textRend) { /* background */ - DrawableHelper.fill(matrices, x1, y1 + 1, x1 + 1, y2 - 1, 0xff6060b0); - horizontalGradient(matrices, x1 + 1, y1, x2 - 1, y1 + 1, 0xff6060b0, 0xff8070b0); - DrawableHelper.fill(matrices, x2 - 1, y1 + 1, x2, y2 - 1, 0xff8070b0); - horizontalGradient(matrices, x1 + 1, y2 - 1, x2 - 1, y2, 0xff6060b0, 0xff8070b0); + context.fill(x1, y1 + 1, x1 + 1, y2 - 1, 0xff6060b0); + horizontalGradient(context, x1 + 1, y1, x2 - 1, y1 + 1, 0xff6060b0, 0xff8070b0); + context.fill(x2 - 1, y1 + 1, x2, y2 - 1, 0xff8070b0); + horizontalGradient(context, x1 + 1, y2 - 1, x2 - 1, y2, 0xff6060b0, 0xff8070b0); - DrawableHelper.fill(matrices, x1 + 1, y1 + 12, x2 - 1, y2 - 1, 0x90606090); + context.fill(x1 + 1, y1 + 12, x2 - 1, y2 - 1, 0x90606090); /* title bar */ - horizontalGradient(matrices, x1 + 1, y1 + 1, x2 - 1, y1 + 12, (selected ? 0xff6060b0 : 0xff606060), (selected ? 0xff8070b0 : 0xffa0a0a0)); + horizontalGradient(context, x1 + 1, y1 + 1, x2 - 1, y1 + 12, (selected ? 0xff6060b0 : 0xff606060), (selected ? 0xff8070b0 : 0xffa0a0a0)); /* buttons */ - textRend.draw(matrices, "x", x2 - 10, y1 + 3, 0); - textRend.draw(matrices, "x", x2 - 11, y1 + 2, -1); + context.drawText(textRend, "x", x2 - 10, y1 + 3, 0, false); + context.drawText(textRend, "x", x2 - 11, y1 + 2, -1, false); - textRend.draw(matrices, "_", x2 - 21, y1 + 2, 0); - textRend.draw(matrices, "_", x2 - 22, y1 + 1, -1); + context.drawText(textRend, "_", x2 - 21, y1 + 2, 0, false); + context.drawText(textRend, "_", x2 - 22, y1 + 1, -1, false); } public boolean shouldClose(int mouseX, int mouseY) { @@ -187,65 +176,40 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { } } - public static void fill(MatrixStack matrices, int x1, int y1, int x2, int y2) { - fill(matrices, x1, y1, x2, y2, 0xff6060b0, 0xff8070b0, 0x00000000); - } - - public static void fill(MatrixStack matrices, int x1, int y1, int x2, int y2, int fill) { - fill(matrices, x1, y1, x2, y2, 0xff6060b0, 0xff8070b0, fill); - } - - public static void fill(MatrixStack matrices, int x1, int y1, int x2, int y2, int colTop, int colBot, int colFill) { - DrawableHelper.fill(matrices, x1, y1 + 1, x1 + 1, y2 - 1, colTop); - DrawableHelper.fill(matrices, x1 + 1, y1, x2 - 1, y1 + 1, colTop); - DrawableHelper.fill(matrices, x2 - 1, y1 + 1, x2, y2 - 1, colBot); - DrawableHelper.fill(matrices, x1 + 1, y2 - 1, x2 - 1, y2, colBot); - DrawableHelper.fill(matrices, x1 + 1, y1 + 1, x2 - 1, y2 - 1, colFill); - } - - public static void horizontalGradient(MatrixStack matrices, int x1, int y1, int x2, int y2, int color1, int color2) { - float alpha1 = (color1 >> 24 & 255) / 255.0F; - float red1 = (color1 >> 16 & 255) / 255.0F; - float green1 = (color1 >> 8 & 255) / 255.0F; - float blue1 = (color1 & 255) / 255.0F; - float alpha2 = (color2 >> 24 & 255) / 255.0F; - float red2 = (color2 >> 16 & 255) / 255.0F; - float green2 = (color2 >> 8 & 255) / 255.0F; - float blue2 = (color2 & 255) / 255.0F; - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); - bufferBuilder.vertex(x1, y1, 0).color(red1, green1, blue1, alpha1).next(); - bufferBuilder.vertex(x1, y2, 0).color(red1, green1, blue1, alpha1).next(); - bufferBuilder.vertex(x2, y2, 0).color(red2, green2, blue2, alpha2).next(); - bufferBuilder.vertex(x2, y1, 0).color(red2, green2, blue2, alpha2).next(); - tessellator.draw(); - RenderSystem.disableBlend(); - } - - public static void verticalGradient(MatrixStack matrices, int x1, int y1, int x2, int y2, int color1, int color2) { - float alpha1 = (color1 >> 24 & 255) / 255.0F; - float red1 = (color1 >> 16 & 255) / 255.0F; - float green1 = (color1 >> 8 & 255) / 255.0F; - float blue1 = (color1 & 255) / 255.0F; - float alpha2 = (color2 >> 24 & 255) / 255.0F; - float red2 = (color2 >> 16 & 255) / 255.0F; - float green2 = (color2 >> 8 & 255) / 255.0F; - float blue2 = (color2 & 255) / 255.0F; - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); - bufferBuilder.vertex(x2, y1, 0).color(red1, green1, blue1, alpha1).next(); - bufferBuilder.vertex(x1, y1, 0).color(red1, green1, blue1, alpha1).next(); - bufferBuilder.vertex(x1, y2, 0).color(red2, green2, blue2, alpha2).next(); - bufferBuilder.vertex(x2, y2, 0).color(red2, green2, blue2, alpha2).next(); - tessellator.draw(); - RenderSystem.disableBlend(); + public static void fill(DrawContext context, int x1, int y1, int x2, int y2) { + fill(context, x1, y1, x2, y2, 0xff6060b0, 0xff8070b0, 0x00000000); + } + + public static void fill(DrawContext context, int x1, int y1, int x2, int y2, int fill) { + fill(context, x1, y1, x2, y2, 0xff6060b0, 0xff8070b0, fill); + } + + public static void fill(DrawContext context, int x1, int y1, int x2, int y2, int colTop, int colBot, int colFill) { + context.fill(x1, y1 + 1, x1 + 1, y2 - 1, colTop); + context.fill(x1 + 1, y1, x2 - 1, y1 + 1, colTop); + context.fill(x2 - 1, y1 + 1, x2, y2 - 1, colBot); + context.fill(x1 + 1, y2 - 1, x2 - 1, y2, colBot); + context.fill(x1 + 1, y1 + 1, x2 - 1, y2 - 1, colFill); + } + + // 1.21.11's DrawContext.fillGradient(...) only interpolates vertically (top row always gets + // colorStart, bottom row colorEnd - see ColoredQuadGuiElementRenderState), with no horizontal + // equivalent. This reimplements a left-to-right gradient as a column-by-column fill using only + // the stable public DrawContext.fill/ColorHelper.lerp API, rather than authoring a custom + // GuiElementRenderState against DrawContext's internal (and likely still-shifting) render queue. + public static void horizontalGradient(DrawContext context, int x1, int y1, int x2, int y2, int color1, int color2) { + int width = x2 - x1; + if (width <= 0) { + return; + } + + for (int i = 0; i < width; i++) { + float t = width <= 1 ? 0f : (float) i / (width - 1); + context.fill(x1 + i, y1, x1 + i + 1, y2, ColorHelper.lerp(t, color1, color2)); + } + } + + public static void verticalGradient(DrawContext context, int x1, int y1, int x2, int y2, int color1, int color2) { + context.fillGradient(x1, y1, x2, y2, color1, color2); } } diff --git a/src/main/java/org/bleachhack/gui/window/WindowManagerScreen.java b/src/main/java/org/bleachhack/gui/window/WindowManagerScreen.java index d8fcff3fdc..c18f16a3c0 100644 --- a/src/main/java/org/bleachhack/gui/window/WindowManagerScreen.java +++ b/src/main/java/org/bleachhack/gui/window/WindowManagerScreen.java @@ -11,10 +11,11 @@ import java.util.List; import org.apache.commons.lang3.tuple.Triple; import org.bleachhack.gui.window.widget.WindowButtonWidget; -import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.input.CharInput; +import net.minecraft.client.input.KeyInput; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; @@ -53,7 +54,9 @@ public void selectWindow(int s) { remove(t.getLeft()); } - getSelectedScreen().init(client, width, height - 16); + // 1.21.11's Screen.init(int,int) is final and no longer takes a MinecraftClient (client is set + // in the Screen constructor now). + getSelectedScreen().init(width, height - 16); addDrawable(getSelectedScreen()); ((List) children()).add(getSelectedScreen()); } @@ -79,21 +82,21 @@ public void tick() { // Children also don't take keyboard input brueh @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - getSelectedScreen().keyPressed(keyCode, scanCode, modifiers); - return super.keyPressed(keyCode, scanCode, modifiers); + public boolean keyPressed(KeyInput input) { + getSelectedScreen().keyPressed(input); + return super.keyPressed(input); } @Override - public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - getSelectedScreen().keyReleased(keyCode, scanCode, modifiers); - return super.keyReleased(keyCode, scanCode, modifiers); + public boolean keyReleased(KeyInput input) { + getSelectedScreen().keyReleased(input); + return super.keyReleased(input); } @Override - public boolean charTyped(char chr, int modifiers) { - getSelectedScreen().charTyped(chr, modifiers); - return super.charTyped(chr, modifiers); + public boolean charTyped(CharInput input) { + getSelectedScreen().charTyped(input); + return super.charTyped(input); } private static class WindowTabButtonWidget extends WindowButtonWidget { @@ -106,7 +109,7 @@ public WindowTabButtonWidget(int x1, int y1, int x2, int y2, String text, ItemSt } @Override - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { int bx1 = windowX + x1; int by1 = windowY + y1; int bx2 = windowX + x2; @@ -117,15 +120,17 @@ public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, i colorTop, colorBottom, isInBounds(windowX, windowY, mouseX, mouseY) ? colorHoverFill : colorFill); - RenderSystem.getModelViewStack().push(); - RenderSystem.getModelViewStack().scale(0.7f, 0.7f, 1f); + // ItemRenderer.renderGuiItemIcon was removed - DrawContext.drawItem is the modern + // GUI-icon entry point and manages its own render state, so this uses DrawContext's own + // 2D matrix stack for the 0.7x scale instead of the old global model-view matrix trick. + matrices.getMatrices().pushMatrix(); + matrices.getMatrices().scale(0.7f, 0.7f); - mc.getItemRenderer().renderGuiItemIcon(matrices, item, (int) ((bx1 + 2) / 0.7), (int) ((by1 - 6 + (by2 - by1) / 2.0) / 0.7)); + matrices.drawItem(item, (int) ((bx1 + 2) / 0.7), (int) ((by1 - 6 + (by2 - by1) / 2.0) / 0.7)); - RenderSystem.getModelViewStack().pop(); - RenderSystem.applyModelViewMatrix(); + matrices.getMatrices().popMatrix(); - mc.textRenderer.drawWithShadow(matrices, text, bx1 + 16, by1 + (by2 - by1) / 2 - 4, -1); + matrices.drawTextWithShadow(mc.textRenderer, text, bx1 + 16, by1 + (by2 - by1) / 2 - 4, -1); } } } diff --git a/src/main/java/org/bleachhack/gui/window/WindowScreen.java b/src/main/java/org/bleachhack/gui/window/WindowScreen.java index e36d145415..040da4958b 100644 --- a/src/main/java/org/bleachhack/gui/window/WindowScreen.java +++ b/src/main/java/org/bleachhack/gui/window/WindowScreen.java @@ -15,21 +15,17 @@ import org.bleachhack.gui.window.widget.WindowWidget; -import com.mojang.blaze3d.systems.RenderSystem; - import it.unimi.dsi.fastutil.ints.Int2IntMap.Entry; import it.unimi.dsi.fastutil.ints.Int2IntRBTreeMap; import it.unimi.dsi.fastutil.ints.Int2IntSortedMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntCollection; import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.input.CharInput; +import net.minecraft.client.input.KeyInput; import net.minecraft.text.Text; public abstract class WindowScreen extends Screen { @@ -127,9 +123,9 @@ public void init() { } @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { super.render(matrices, mouseX, mouseY, delta); - + for (WindowWidget w : globalWidgets) { w.render(matrices, 0, 0, mouseX, mouseY); } @@ -157,7 +153,7 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { if (autoClose && close) this.close(); } - public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mouseY) { + public void onRenderWindow(DrawContext matrices, int window, int mouseX, int mouseY) { if (!windows.get(window).closed) { windows.get(window).render(matrices, mouseX, mouseY); } @@ -188,7 +184,11 @@ public void selectWindow(int window) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(Click click, boolean doubleClick) { + double mouseX = click.x(); + double mouseY = click.y(); + int button = click.button(); + /* Handle what window will be selected when clicking */ for (int wi: getWindowsFrontToBack()) { Window w = getWindow(wi); @@ -213,15 +213,15 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } } catch (ConcurrentModificationException ignored) {} - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(click, doubleClick); } @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { + public boolean mouseReleased(Click click) { for (Window w : windows) - w.mouseReleased(mouseX, mouseY, button); + w.mouseReleased(click.x(), click.y(), click.button()); - return super.mouseReleased(mouseX, mouseY, button); + return super.mouseReleased(click); } @Override @@ -233,43 +233,18 @@ public void tick() { } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + public boolean keyPressed(KeyInput input) { for (Window w : windows) - w.keyPressed(keyCode, scanCode, modifiers); + w.keyPressed(input.key(), input.scancode(), input.modifiers()); - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(input); } @Override - public boolean charTyped(char chr, int modifiers) { + public boolean charTyped(CharInput input) { for (Window w : windows) - w.charTyped(chr, modifiers); + w.charTyped((char) input.codepoint(), input.modifiers()); - return super.charTyped(chr, modifiers); - } - - @Override - public void renderBackgroundTexture(MatrixStack matrices) { - int colorOffset = (int) ((System.currentTimeMillis() / 75) % 100); - if (colorOffset > 50) - colorOffset = 50 - (colorOffset - 50); - - // smooth - colorOffset = (int) (-(Math.cos(Math.PI * (colorOffset / 50d)) - 1) / 2 * 50); - - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); - bufferBuilder.vertex(width, 0, 0).color(30, 20, 80, 255).next(); - bufferBuilder.vertex(0, 0, 0).color(30 + colorOffset / 3, 20, 80, 255).next(); - bufferBuilder.vertex(0, height + 16, 0).color(90, 54, 159, 255).next(); - bufferBuilder.vertex(width, height + 16, 0).color(105 + colorOffset, 54, 189, 255).next(); - tessellator.draw(); - - RenderSystem.disableBlend(); + return super.charTyped(input); } } diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowBoxWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowBoxWidget.java index f2c3ef65ac..6a1be75eb8 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowBoxWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowBoxWidget.java @@ -2,7 +2,7 @@ import org.bleachhack.gui.window.Window; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public class WindowBoxWidget extends WindowWidget { @@ -32,7 +32,7 @@ public WindowBoxWidget(int x1, int y1, int x2, int y2, int top, int bottom, int } @Override - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { super.render(matrices, windowX, windowY, mouseX, mouseY); Window.fill(matrices, windowX + x1, windowY + y1, windowX + x2, windowY + y2, diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowButtonWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowButtonWidget.java index 42eb7ffa31..1a2d0c4929 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowButtonWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowButtonWidget.java @@ -3,8 +3,8 @@ import org.bleachhack.gui.window.Window; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; public class WindowButtonWidget extends WindowWidget { @@ -36,7 +36,7 @@ public WindowButtonWidget(int x1, int y1, int x2, int y2, int colorTop, int colo } @Override - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { super.render(matrices, windowX, windowY, mouseX, mouseY); int bx1 = windowX + x1; @@ -49,8 +49,8 @@ public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, i colorTop, colorBottom, isInBounds(windowX, windowY, mouseX, mouseY) ? colorHoverFill : colorFill); - mc.textRenderer.drawWithShadow( - matrices, text, bx1 + (bx2 - bx1) / 2 - mc.textRenderer.getWidth(text) / 2, by1 + (by2 - by1) / 2 - 4, -1); + matrices.drawTextWithShadow( + mc.textRenderer, text, bx1 + (bx2 - bx1) / 2 - mc.textRenderer.getWidth(text) / 2, by1 + (by2 - by1) / 2 - 4, -1); } @Override @@ -59,7 +59,7 @@ public void mouseClicked(int windowX, int windowY, int mouseX, int mouseY, int b if (isInBounds(windowX, windowY, mouseX, mouseY)) { action.run(); - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1.0F)); } } } diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowCheckboxWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowCheckboxWidget.java index 257416c64f..d56f3772bd 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowCheckboxWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowCheckboxWidget.java @@ -4,8 +4,8 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; @@ -26,7 +26,7 @@ public WindowCheckboxWidget(int x, int y, Text text, boolean pressed) { } @Override - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { super.render(matrices, windowX, windowY, mouseX, mouseY); TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; @@ -38,11 +38,11 @@ public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, i Window.fill(matrices, x, y, x + 11, y + 11, color); if (checked) { - textRenderer.draw(matrices, "\u2714", x + 2, y + 2, 0xffeeff); + matrices.drawText(textRenderer, "\u2714", x + 2, y + 2, 0xffeeff, false); //fill(matrix, x + 3, y + 3, x + 7, y + 7, 0xffffffff); } - textRenderer.drawWithShadow(matrices, text, x + 15, y + 2, 0xc0c0c0); + matrices.drawTextWithShadow(textRenderer, text, x + 15, y + 2, 0xc0c0c0); } @Override @@ -51,7 +51,7 @@ public void mouseClicked(int windowX, int windowY, int mouseX, int mouseY, int b if (mouseX >= windowX + x1 && mouseX <= windowX + x1 + 10 && mouseY >= windowY + y1 && mouseY <= windowY + y1 + 10) { checked = !checked; - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK, 1.0F)); } } } diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowPassTextFieldWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowPassTextFieldWidget.java index da413a2815..99954bc128 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowPassTextFieldWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowPassTextFieldWidget.java @@ -16,10 +16,14 @@ public WindowPassTextFieldWidget(int x, int y, int width, int height, String tex } private TextRenderer createTextRenderer() { - return new TextRenderer(mc.textRenderer.fontStorageAccessor, false) { + // 1.21.11: fontStorageAccessor (a Function) was replaced by the "fonts" field + // (TextRenderer$GlyphsProvider, widened via accesswidener - see task #3 notes), and the + // constructor dropped its second boolean argument. draw(...) also changed shape: void return, + // no trailing rightToLeft parameter. + return new TextRenderer(mc.textRenderer.fonts) { @Override - public int draw(String text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextLayerType textLayerType, int backgroundColor, int light, boolean rightToLeft) { - return super.draw(hide(text), x, y, color, shadow, matrix, vertexConsumers, textLayerType, backgroundColor, light, rightToLeft); + public void draw(String text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextLayerType textLayerType, int backgroundColor, int light) { + super.draw(hide(text), x, y, color, shadow, matrix, vertexConsumers, textLayerType, backgroundColor, light); } @Override @@ -36,7 +40,7 @@ private String hide(String text) { if (text != textField.getText()) // literal equal becasue dabruh return text; - return new String(new char[textField.getText().length()]).replace('\0', '\u2022'); + return new String(new char[textField.getText().length()]).replace('\0', '•'); } }; } diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowScrollbarWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowScrollbarWidget.java index f8590957d3..bc0bd7107d 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowScrollbarWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowScrollbarWidget.java @@ -2,8 +2,7 @@ import org.bleachhack.gui.window.Window; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.util.math.MathHelper; public class WindowScrollbarWidget extends WindowWidget { @@ -26,7 +25,7 @@ public WindowScrollbarWidget(int x, int y, int totalHeight, int pageHeight, int } @Override - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { super.render(matrices, windowX, windowY, mouseX, mouseY); int[] pos = getCurrentPos(windowX, windowY); @@ -40,9 +39,9 @@ public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, i int middleY = pos[1] + (int) (pos[3] / 2d); - DrawableHelper.fill(matrices, pos[0] + 3, middleY - 3, pos[0] + 7, middleY - 2, 0xff7060ff); - DrawableHelper.fill(matrices, pos[0] + 3, middleY, pos[0] + 7, middleY + 1, 0xff7060ff); - DrawableHelper.fill(matrices, pos[0] + 3, middleY + 3, pos[0] + 7, middleY + 4, 0xff7060ff); + matrices.fill(pos[0] + 3, middleY - 3, pos[0] + 7, middleY - 2, 0xff7060ff); + matrices.fill(pos[0] + 3, middleY, pos[0] + 7, middleY + 1, 0xff7060ff); + matrices.fill(pos[0] + 3, middleY + 3, pos[0] + 7, middleY + 4, 0xff7060ff); if (buttonDown) { moveScrollbar(mouseY - lastY); diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowTextFieldWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowTextFieldWidget.java index 4065d29f28..4bbc97c747 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowTextFieldWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowTextFieldWidget.java @@ -1,8 +1,12 @@ package org.bleachhack.gui.window.widget; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.input.CharInput; +import net.minecraft.client.input.KeyInput; +import net.minecraft.client.input.MouseInput; import net.minecraft.text.Text; @@ -22,10 +26,10 @@ protected WindowTextFieldWidget(int x, int y, int width, int height) { } @Override - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { textField.setX(windowX + x1); textField.setY(windowY + y1); - textField.render(matrices, mouseX, mouseY, MinecraftClient.getInstance().getTickDelta()); + textField.render(matrices, mouseX, mouseY, MinecraftClient.getInstance().getRenderTickCounter().getTickProgress(true)); super.render(matrices, windowX, windowY, mouseX, mouseY); } @@ -34,27 +38,28 @@ public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, i public void mouseClicked(int windowX, int windowY, int mouseX, int mouseY, int button) { super.mouseClicked(windowX, windowY, mouseX, mouseY, button); - textField.mouseClicked(mouseX, mouseY, button); - } - - @Override - public void tick() { - super.tick(); + // 1.21.11 bundles mouse click info into a Click record and adds a "double click" flag we + // don't track at this call site - matches the old always-false-equivalent single-click behavior. + textField.mouseClicked(new Click(mouseX, mouseY, new MouseInput(button, 0)), false); - textField.tick(); + // TextFieldWidget.onClick() only moves the cursor now - it used to also grab keyboard focus + // itself, but that moved to the vanilla Screen/ParentElement click dispatch, which this custom + // Window/WindowWidget system never goes through. Without this, clicking a field positions the + // cursor but charTyped()/keyPressed() silently no-op since isFocused() stays false. + textField.setFocused(textField.isMouseOver(mouseX, mouseY)); } @Override public void charTyped(char chr, int modifiers) { super.charTyped(chr, modifiers); - textField.charTyped(chr, modifiers); + textField.charTyped(new CharInput(chr, modifiers)); } @Override public void keyPressed(int keyCode, int scanCode, int modifiers) { super.keyPressed(keyCode, scanCode, modifiers); - textField.keyPressed(keyCode, scanCode, modifiers); + textField.keyPressed(new KeyInput(keyCode, scanCode, modifiers)); } } diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowTextWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowTextWidget.java index 6f3cb49358..a255fe250c 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowTextWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowTextWidget.java @@ -1,12 +1,6 @@ package org.bleachhack.gui.window.widget; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.util.math.RotationAxis; -import org.bleachhack.mixin.AccessorScreen; - -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.text.Text; @@ -53,31 +47,23 @@ public WindowTextWidget(Text text, boolean shadow, TextAlign align, float scale, this.rotation = rotation; } + // Style hover-tooltip support (e.g. hovering a clickable/hoverable text component) was dropped: + // Screen.renderTextHoverEffect(...) was removed in 1.21.11 with no replacement method, and + // reimplementing its show_text/show_item/show_entity handling from scratch was out of scope here. @Override - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { super.render(matrices, windowX, windowY, mouseX, mouseY); float offset = mc.textRenderer.getWidth(text) * align.offset * scale; - matrices.push(); - matrices.scale(scale, scale, 1f); - matrices.translate((windowX + x1 - offset) / scale, (windowY + y1) / scale, 0); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(rotation)); - - VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); - mc.textRenderer.draw(text, 0, 0, color, shadow, matrices.peek().getPositionMatrix(), immediate, TextRenderer.TextLayerType.NORMAL, 0, 0xf000f0); - immediate.draw(); - - if (text.getStyle() != null && mc.currentScreen != null - && mouseX >= windowX + x1 - offset && mouseX <= windowX + x2 - offset && mouseY >= windowY + y1 && mouseY <= windowY + y2) { - matrices.push(); - matrices.translate(0, 0, 250); - ((AccessorScreen) mc.currentScreen).callRenderTextHoverEffect( - matrices, text.getStyle(), mouseX - (windowX + x1 - (int) offset), mouseY - (windowY + y1)); - matrices.pop(); - } + matrices.getMatrices().pushMatrix(); + matrices.getMatrices().scale(scale, scale); + matrices.getMatrices().translate((windowX + x1 - offset) / scale, (windowY + y1) / scale); + matrices.getMatrices().rotate((float) Math.toRadians(rotation)); + + matrices.drawText(mc.textRenderer, text, 0, 0, color, shadow); - matrices.pop(); + matrices.getMatrices().popMatrix(); } public Text getText() { diff --git a/src/main/java/org/bleachhack/gui/window/widget/WindowWidget.java b/src/main/java/org/bleachhack/gui/window/widget/WindowWidget.java index a98075aa42..041edd8e8a 100644 --- a/src/main/java/org/bleachhack/gui/window/widget/WindowWidget.java +++ b/src/main/java/org/bleachhack/gui/window/widget/WindowWidget.java @@ -1,7 +1,7 @@ package org.bleachhack.gui.window.widget; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public abstract class WindowWidget { @@ -28,7 +28,7 @@ public WindowWidget(int x1, int y1, int x2, int y2) { this.y2 = y2; } - public void render(MatrixStack matrices, int windowX, int windowY, int mouseX, int mouseY) { + public void render(DrawContext matrices, int windowX, int windowY, int mouseX, int mouseY) { if (renderEvent != null) { renderEvent.accept(this, matrices, windowX, windowY); } @@ -89,7 +89,7 @@ public WindowWidget withReleaseEvent(MouseEvent event) { @FunctionalInterface public interface RenderEvent { - void accept(WindowWidget widget, MatrixStack matrices, int wx, int wy); + void accept(WindowWidget widget, DrawContext matrices, int wx, int wy); } @FunctionalInterface diff --git a/src/main/java/org/bleachhack/mixin/AccessorFrustum.java b/src/main/java/org/bleachhack/mixin/AccessorFrustum.java index 28cd7b114a..be0815e67e 100644 --- a/src/main/java/org/bleachhack/mixin/AccessorFrustum.java +++ b/src/main/java/org/bleachhack/mixin/AccessorFrustum.java @@ -24,21 +24,21 @@ public interface AccessorFrustum { @Accessor public abstract void setFrustumIntersection(FrustumIntersection vector4f); - @Accessor + @Accessor("x") public abstract double getX(); - - @Accessor + + @Accessor("x") public abstract void setX(double x); - - @Accessor + + @Accessor("y") public abstract double getY(); - - @Accessor + + @Accessor("y") public abstract void setY(double y); - - @Accessor + + @Accessor("z") public abstract double getZ(); - - @Accessor + + @Accessor("z") public abstract void setZ(double z); } diff --git a/src/main/java/org/bleachhack/mixin/AccessorScreen.java b/src/main/java/org/bleachhack/mixin/AccessorScreen.java index ba89569a38..130dd1f0d9 100644 --- a/src/main/java/org/bleachhack/mixin/AccessorScreen.java +++ b/src/main/java/org/bleachhack/mixin/AccessorScreen.java @@ -12,22 +12,17 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import org.spongepowered.asm.mixin.gen.Invoker; import net.minecraft.client.gui.Drawable; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Style; +// setDrawables() dropped: Screen.drawables is `final` in 1.21.11 (an @Accessor setter can't be +// generated for a final field) and nothing in this codebase used the setter anyway. +// callRenderTextHoverEffect() dropped: Screen.renderTextHoverEffect(...) was removed entirely with +// no replacement method - see WindowTextWidget notes. @Mixin(Screen.class) public interface AccessorScreen { @Accessor public abstract List getDrawables(); - - @Accessor - public abstract void setDrawables(List drawables); - - @Invoker - public abstract void callRenderTextHoverEffect(MatrixStack matrices, Style style, int x, int y); } diff --git a/src/main/java/org/bleachhack/mixin/AccessorWorldRenderer.java b/src/main/java/org/bleachhack/mixin/AccessorWorldRenderer.java deleted file mode 100644 index 4d38b9ec18..0000000000 --- a/src/main/java/org/bleachhack/mixin/AccessorWorldRenderer.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). - * Copyright (c) 2021 Bleach and contributors. - * - * This source code is subject to the terms of the GNU General Public - * License, version 3. If a copy of the GPL was not distributed with this - * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt - */ -package org.bleachhack.mixin; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import net.minecraft.client.render.Frustum; -import net.minecraft.client.render.WorldRenderer; - -@Mixin(WorldRenderer.class) -public interface AccessorWorldRenderer { - - @Accessor - public abstract Frustum getFrustum(); - - @Accessor - public abstract void setFrustum(Frustum frustum); -} diff --git a/src/main/java/org/bleachhack/mixin/BlockedServersMixin.java b/src/main/java/org/bleachhack/mixin/BlockedServersMixin.java new file mode 100644 index 0000000000..5ce2a3040b --- /dev/null +++ b/src/main/java/org/bleachhack/mixin/BlockedServersMixin.java @@ -0,0 +1,16 @@ +package org.bleachhack.mixin; + +import com.mojang.patchy.BlockedServers; +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.CallbackInfoReturnable; + +@Mixin(BlockedServers.class) +public class BlockedServersMixin { + + @Inject(method = "isBlockedServerHostName", at = @At("RETURN"), cancellable = true, remap = false) + public void isBlockedServerHostName(String server, CallbackInfoReturnable cir) { + cir.setReturnValue(false); + } +} diff --git a/src/main/java/org/bleachhack/mixin/MixinBackgroundRenderer.java b/src/main/java/org/bleachhack/mixin/MixinBackgroundRenderer.java deleted file mode 100644 index 863c3fbdf9..0000000000 --- a/src/main/java/org/bleachhack/mixin/MixinBackgroundRenderer.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). - * Copyright (c) 2021 Bleach and contributors. - * - * This source code is subject to the terms of the GNU General Public - * License, version 3. If a copy of the GPL was not distributed with this - * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt - */ -package org.bleachhack.mixin; - -import org.bleachhack.module.ModuleManager; -import org.bleachhack.module.mods.NoRender; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import net.minecraft.client.render.BackgroundRenderer; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.effect.StatusEffect; -import net.minecraft.entity.effect.StatusEffects; - -@Mixin(BackgroundRenderer.class) -public class MixinBackgroundRenderer { - - @Redirect(method = { - "render(Lnet/minecraft/client/render/Camera;FLnet/minecraft/client/world/ClientWorld;IF)V", - "applyFog(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/BackgroundRenderer$FogType;FZ)V"}, - at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;hasStatusEffect(Lnet/minecraft/entity/effect/StatusEffect;)Z")) - private static boolean hasStatusEffect(LivingEntity entity, StatusEffect effect) { - if (effect == StatusEffects.BLINDNESS && ModuleManager.getModule(NoRender.class).isOverlayToggled(0)) { - return false; - } - - return entity.hasStatusEffect(effect); - } -} diff --git a/src/main/java/org/bleachhack/mixin/MixinBeaconScreen.java b/src/main/java/org/bleachhack/mixin/MixinBeaconScreen.java index 3153a93c22..75fc59842d 100644 --- a/src/main/java/org/bleachhack/mixin/MixinBeaconScreen.java +++ b/src/main/java/org/bleachhack/mixin/MixinBeaconScreen.java @@ -15,11 +15,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.client.gui.Drawable; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ingame.BeaconScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.screen.BeaconScreenHandler; @@ -41,7 +41,7 @@ private void init(CallbackInfo callback) { } @Inject(method = "render", at = @At("HEAD")) - private void render(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo callback) { + private void render(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo callback) { if (unlocked) { for (Drawable b: ((AccessorScreen) this).getDrawables()) { if (b instanceof ClickableWidget) { diff --git a/src/main/java/org/bleachhack/mixin/MixinBlock.java b/src/main/java/org/bleachhack/mixin/MixinBlock.java index bd16599fa0..322ae2fae3 100644 --- a/src/main/java/org/bleachhack/mixin/MixinBlock.java +++ b/src/main/java/org/bleachhack/mixin/MixinBlock.java @@ -17,16 +17,14 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockView; @Mixin(Block.class) public class MixinBlock { @Inject(method = "shouldDrawSide", at = @At("HEAD"), cancellable = true) - private static void shouldDrawSide(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos blockPos, CallbackInfoReturnable callback) { - EventRenderBlock.ShouldDrawSide event = new EventRenderBlock.ShouldDrawSide(state); + private static void shouldDrawSide(BlockState state, BlockState neighborState, Direction side, CallbackInfoReturnable callback) { + EventRenderBlock.ShouldDrawSide event = new EventRenderBlock.ShouldDrawSide(state, neighborState, side); BleachHack.eventBus.post(event); if (event.shouldDrawSide() != null) diff --git a/src/main/java/org/bleachhack/mixin/MixinBlockCollisionSpliterator.java b/src/main/java/org/bleachhack/mixin/MixinBlockCollisionSpliterator.java index 3d13be842f..49bec8fe32 100644 --- a/src/main/java/org/bleachhack/mixin/MixinBlockCollisionSpliterator.java +++ b/src/main/java/org/bleachhack/mixin/MixinBlockCollisionSpliterator.java @@ -20,14 +20,18 @@ import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.BlockCollisionSpliterator; -import net.minecraft.world.BlockView; +import net.minecraft.world.CollisionView; +// 1.19.4 called blockState.getCollisionShape(world, pos, context) directly. 1.21.11 flipped that +// around - computeNext() now calls this.context.getCollisionShape(blockState, world, pos), i.e. the +// ShapeContext owns the call instead of BlockState (same net effect, since ShapeContext's +// implementation still just delegates to the block state internally). @Mixin(BlockCollisionSpliterator.class) public class MixinBlockCollisionSpliterator { - @Redirect(method = "computeNext", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;getCollisionShape(Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/ShapeContext;)Lnet/minecraft/util/shape/VoxelShape;")) - private VoxelShape computeNext_getCollisionShape(BlockState blockState, BlockView world, BlockPos pos, ShapeContext context) { - VoxelShape shape = blockState.getCollisionShape(world, pos, context); + @Redirect(method = "computeNext", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/ShapeContext;getCollisionShape(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/CollisionView;Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/util/shape/VoxelShape;")) + private VoxelShape computeNext_getCollisionShape(ShapeContext context, BlockState blockState, CollisionView world, BlockPos pos) { + VoxelShape shape = context.getCollisionShape(blockState, world, pos); EventBlockShape event = new EventBlockShape((BlockState) blockState, pos, shape); BleachHack.eventBus.post(event); diff --git a/src/main/java/org/bleachhack/mixin/MixinBlockEntityRenderDispatcher.java b/src/main/java/org/bleachhack/mixin/MixinBlockEntityRenderDispatcher.java index 1541a116b5..1640862c09 100644 --- a/src/main/java/org/bleachhack/mixin/MixinBlockEntityRenderDispatcher.java +++ b/src/main/java/org/bleachhack/mixin/MixinBlockEntityRenderDispatcher.java @@ -11,37 +11,35 @@ import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventBlockEntityRender; 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.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; -import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.render.block.entity.BlockEntityRenderManager; +import net.minecraft.client.render.block.entity.state.BlockEntityRenderState; +import net.minecraft.client.render.command.ModelCommandRenderer; -@Mixin(BlockEntityRenderDispatcher.class) +// 1.21.11 moved block-entity rendering to the same RenderState/OrderedRenderCommandQueue +// architecture as entities (see MixinWorldRenderer's entity-render notes) - BlockEntityRenderDispatcher +// (renamed BlockEntityRenderManager) no longer has a render(...) call taking a VertexConsumerProvider +// to wrap. The hook moved to WorldRenderer's per-block-entity render-state extraction call instead, +// which still lets NoRender substitute/cancel a specific block entity's render before it happens. +@Mixin(WorldRenderer.class) public class MixinBlockEntityRenderDispatcher { - @Shadow private static void render(BlockEntityRenderer renderer, T blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers) {} - - @SuppressWarnings("unchecked") - @Redirect(method = "*" /* lambda moment*/, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/entity/BlockEntityRenderDispatcher;render(Lnet/minecraft/client/render/block/entity/BlockEntityRenderer;Lnet/minecraft/block/entity/BlockEntity;FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;)V")) - private static void render_render(BlockEntityRenderer renderer, T blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers) { - EventBlockEntityRender.Single.Pre event = new EventBlockEntityRender.Single.Pre(blockEntity, matrices, vertexConsumers); + @Redirect(method = "fillBlockEntityRenderStates", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/entity/BlockEntityRenderManager;" + + "getRenderState(Lnet/minecraft/block/entity/BlockEntity;FLnet/minecraft/client/render/command/ModelCommandRenderer$CrumblingOverlayCommand;)" + + "Lnet/minecraft/client/render/block/entity/state/BlockEntityRenderState;")) + private BlockEntityRenderState getRenderState(BlockEntityRenderManager manager, BlockEntity blockEntity, float tickProgress, + ModelCommandRenderer.CrumblingOverlayCommand crumblingOverlay) { + EventBlockEntityRender.Single.Pre event = new EventBlockEntityRender.Single.Pre(blockEntity); BleachHack.eventBus.post(event); - if (!event.isCancelled()) { - render(renderer, (T) event.getBlockEntity(), tickDelta, event.getMatrices(), event.getVertex()); + if (event.isCancelled()) { + return null; } - } - - @Inject(method = "render(Lnet/minecraft/client/render/block/entity/BlockEntityRenderer;Lnet/minecraft/block/entity/BlockEntity;FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;)V", at = @At("RETURN")) - private static void render(BlockEntityRenderer renderer, T blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, CallbackInfo ci) { - EventBlockEntityRender.Single.Post event = new EventBlockEntityRender.Single.Post(blockEntity, matrices, vertexConsumers); - BleachHack.eventBus.post(event); + + return manager.getRenderState(event.getBlockEntity(), tickProgress, crumblingOverlay); } } diff --git a/src/main/java/org/bleachhack/mixin/MixinBufferBuilder.java b/src/main/java/org/bleachhack/mixin/MixinBufferBuilder.java deleted file mode 100644 index b31d0ddb3a..0000000000 --- a/src/main/java/org/bleachhack/mixin/MixinBufferBuilder.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bleachhack.mixin; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.Redirect; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.BufferVertexConsumer; -import net.minecraft.client.render.FixedColorVertexConsumer; - -/** - * BufferBuilder patch that allows the color to be temporarily fixed even when the VertexFormatElement isn't COLOR - */ -@Mixin(value = BufferBuilder.class, priority = 1010 /* TODO: iris compatibility */) -public abstract class MixinBufferBuilder extends FixedColorVertexConsumer implements BufferVertexConsumer { - - @Redirect(method = { "color", "vertex" }, at = @At(value = "FIELD", target = "*:Z", ordinal = 0, remap = false)) - private boolean redirect_colorFixed(BufferBuilder self) { - return false; - } - - @ModifyVariable(method = "color", at = @At("HEAD"), ordinal = 0, argsOnly = true) - private int color_modifyColor1(int red) { - return colorFixed && fixedRed != -1 ? fixedRed : red; - } - - @ModifyVariable(method = "color", at = @At("HEAD"), ordinal = 1, argsOnly = true) - private int color_modifyColor2(int green) { - return colorFixed && fixedGreen != -1 ? fixedGreen : green; - } - - @ModifyVariable(method = "color", at = @At("HEAD"), ordinal = 2, argsOnly = true) - private int color_modifyColor3(int blue) { - return colorFixed && fixedBlue != -1 ? fixedBlue : blue; - } - - @ModifyVariable(method = "color", at = @At("HEAD"), ordinal = 3, argsOnly = true) - private int color_modifyColor4(int alpha) { - return colorFixed && fixedAlpha != -1 ? fixedAlpha : alpha; - } - - @ModifyVariable(method = "vertex", at = @At("HEAD"), ordinal = 3, argsOnly = true) - private float vertex_modifyColor1(float red) { - return colorFixed && fixedRed != -1 ? fixedRed / 255f : red; - } - - @ModifyVariable(method = "vertex", at = @At("HEAD"), ordinal = 4, argsOnly = true) - private float vertex_modifyColor2(float green) { - return colorFixed && fixedGreen != -1 ? fixedGreen / 255f : green; - } - - @ModifyVariable(method = "vertex", at = @At("HEAD"), ordinal = 5, argsOnly = true) - private float vertex_modifyColor3(float blue) { - return colorFixed && fixedBlue != -1 ? fixedBlue / 255f : blue; - } - - @ModifyVariable(method = "vertex", at = @At("HEAD"), ordinal = 6, argsOnly = true) - private float vertex_modifyColor4(float alpha) { - return colorFixed && fixedAlpha != -1 ? fixedAlpha / 255f : alpha; - } -} diff --git a/src/main/java/org/bleachhack/mixin/MixinCamera.java b/src/main/java/org/bleachhack/mixin/MixinCamera.java index cd8d3004c1..a3c844ef40 100644 --- a/src/main/java/org/bleachhack/mixin/MixinCamera.java +++ b/src/main/java/org/bleachhack/mixin/MixinCamera.java @@ -20,14 +20,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.render.Camera; -import net.minecraft.client.render.CameraSubmersionType; +import net.minecraft.block.enums.CameraSubmersionType; @Mixin(Camera.class) public class MixinCamera { @Unique private boolean bypassCameraClip; - @Shadow private double clipToSpace(double desiredCameraDistance) { return 0; } + @Shadow private float clipToSpace(float desiredCameraDistance) { return 0; } @Inject(method = "getSubmersionType", at = @At("HEAD"), cancellable = true) private void getSubmergedFluidState(CallbackInfoReturnable ci) { @@ -37,7 +37,7 @@ private void getSubmergedFluidState(CallbackInfoReturnable } @Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true) - private void onClipToSpace(double desiredCameraDistance, CallbackInfoReturnable info) { + private void onClipToSpace(float desiredCameraDistance, CallbackInfoReturnable info) { if (bypassCameraClip) { bypassCameraClip = false; } else { @@ -46,10 +46,10 @@ private void onClipToSpace(double desiredCameraDistance, CallbackInfoReturnable< if (betterCamera.isEnabled()) { if (betterCamera.getSetting(0).asToggle().getState()) { info.setReturnValue(betterCamera.getSetting(1).asToggle().getState() - ? betterCamera.getSetting(1).asToggle().getChild(0).asSlider().getValue() : desiredCameraDistance); + ? betterCamera.getSetting(1).asToggle().getChild(0).asSlider().getValueFloat() : desiredCameraDistance); } else if (betterCamera.getSetting(1).asToggle().getState()) { bypassCameraClip = true; - info.setReturnValue(clipToSpace(betterCamera.getSetting(1).asToggle().getChild(0).asSlider().getValue())); + info.setReturnValue(clipToSpace(betterCamera.getSetting(1).asToggle().getChild(0).asSlider().getValueFloat())); } } } diff --git a/src/main/java/org/bleachhack/mixin/MixinChatScreen.java b/src/main/java/org/bleachhack/mixin/MixinChatScreen.java index e062be96b7..d993024092 100644 --- a/src/main/java/org/bleachhack/mixin/MixinChatScreen.java +++ b/src/main/java/org/bleachhack/mixin/MixinChatScreen.java @@ -16,13 +16,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.gui.screen.ChatScreen; +import net.minecraft.client.input.KeyInput; @Mixin(ChatScreen.class) public class MixinChatScreen { @Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true) - private void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable callback) { - EventKeyPress.InChat event = new EventKeyPress.InChat(keyCode, scanCode, modifiers); + private void keyPressed(KeyInput input, CallbackInfoReturnable callback) { + EventKeyPress.InChat event = new EventKeyPress.InChat(input.key(), input.scancode(), input.modifiers()); BleachHack.eventBus.post(event); if (event.isCancelled()) { diff --git a/src/main/java/org/bleachhack/mixin/MixinChunkRebuildTask.java b/src/main/java/org/bleachhack/mixin/MixinChunkRebuildTask.java index 55ee836fb1..4c81135df9 100644 --- a/src/main/java/org/bleachhack/mixin/MixinChunkRebuildTask.java +++ b/src/main/java/org/bleachhack/mixin/MixinChunkRebuildTask.java @@ -8,159 +8,171 @@ */ package org.bleachhack.mixin; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Objects; -import java.util.Random; -import java.util.Set; -import java.util.stream.Stream; - -import it.unimi.dsi.fastutil.objects.ReferenceArraySet; -import org.bleachhack.BleachHack; -import org.bleachhack.event.events.EventRenderBlock; -import org.bleachhack.event.events.EventRenderFluid; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Coerce; -import org.spongepowered.asm.mixin.injection.Redirect; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.mojang.blaze3d.systems.VertexSorter; +import com.mojang.blaze3d.vertex.VertexFormat; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.BlockRenderLayer; +import net.minecraft.client.render.BlockRenderLayers; import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.BuiltBuffer; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.block.BlockModelRenderer; import net.minecraft.client.render.block.BlockRenderManager; -import net.minecraft.client.render.chunk.BlockBufferBuilderStorage; +import net.minecraft.client.render.block.entity.BlockEntityRenderManager; +import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.render.chunk.BlockBufferAllocatorStorage; import net.minecraft.client.render.chunk.ChunkBuilder; -import net.minecraft.client.render.chunk.ChunkBuilder.ChunkData; import net.minecraft.client.render.chunk.ChunkOcclusionDataBuilder; import net.minecraft.client.render.chunk.ChunkRendererRegion; +import net.minecraft.client.render.chunk.SectionBuilder; +import net.minecraft.client.render.model.BlockModelPart; +import net.minecraft.client.util.BufferAllocator; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.fluid.FluidState; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.util.math.random.Random; + +import org.bleachhack.BleachHack; +import org.bleachhack.event.events.EventRenderBlock; +import org.bleachhack.event.events.EventRenderFluid; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; /** * Blocks are still tesselated even if they're transparent because Minecraft's * rendering engine is poop. + * + * 1.21.11 moved the entire per-block/per-fluid tesselation loop this mixin used to override out of + * RebuildTask itself and into a new standalone SectionBuilder class (SectionBuilder.build(...)) - + * the redirect target moved accordingly, but the loop body is otherwise a straight port (matched + * line-for-line against SectionBuilder's real decompiled source) with our event hooks re-inserted. */ @Mixin(ChunkBuilder.BuiltChunk.RebuildTask.class) public class MixinChunkRebuildTask { - @Unique private static boolean OPTIFABRIC_INSTALLED = FabricLoader.getInstance().isModLoaded("optifabric"); - - @Shadow private /* outer */ ChunkBuilder.BuiltChunk field_20839; - @Shadow private ChunkRendererRegion region; - - @Shadow private void addBlockEntity(ChunkBuilder.BuiltChunk.RebuildTask.RenderData renderData, E blockEntity) {} - @Shadow private ChunkBuilder.BuiltChunk.RebuildTask.RenderData render(float cameraX, float cameraY, float cameraZ, BlockBufferBuilderStorage buffers) { return null; } - - // i have gone past the point of insanity - @Redirect(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/chunk/ChunkBuilder$BuiltChunk$RebuildTask;render(FFFLnet/minecraft/client/render/chunk/BlockBufferBuilderStorage;)Lnet/minecraft/client/render/chunk/ChunkBuilder$BuiltChunk$RebuildTask$RenderData;")) - private ChunkBuilder.BuiltChunk.RebuildTask.RenderData run_render(@Coerce Object thisObject, float cameraX, float cameraY, float cameraZ, BlockBufferBuilderStorage buffers) { - return OPTIFABRIC_INSTALLED - ? render(cameraX, cameraY, cameraZ, buffers) : newRender(cameraX, cameraY, cameraZ, buffers); + @Unique private static final boolean OPTIFABRIC_INSTALLED = FabricLoader.getInstance().isModLoaded("optifabric"); + + @Redirect(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/chunk/SectionBuilder;build(" + + "Lnet/minecraft/util/math/ChunkSectionPos;Lnet/minecraft/client/render/chunk/ChunkRendererRegion;" + + "Lcom/mojang/blaze3d/systems/VertexSorter;Lnet/minecraft/client/render/chunk/BlockBufferAllocatorStorage;" + + ")Lnet/minecraft/client/render/chunk/SectionBuilder$RenderData;")) + private SectionBuilder.RenderData run_build(SectionBuilder sectionBuilder, ChunkSectionPos sectionPos, ChunkRendererRegion region, + VertexSorter vertexSorter, BlockBufferAllocatorStorage allocatorStorage) { + return OPTIFABRIC_INSTALLED + ? sectionBuilder.build(sectionPos, region, vertexSorter, allocatorStorage) + : build(sectionPos, region, vertexSorter, allocatorStorage); } - private ChunkBuilder.BuiltChunk.RebuildTask.RenderData newRender(float cameraX, float cameraY, float cameraZ, BlockBufferBuilderStorage buffers) { - ChunkBuilder.BuiltChunk.RebuildTask.RenderData renderData = new ChunkBuilder.BuiltChunk.RebuildTask.RenderData(); - BlockPos blockPos = field_20839.getOrigin().toImmutable(); - BlockPos blockPos2 = blockPos.add(15, 15, 15); - ChunkOcclusionDataBuilder chunkOcclusionDataBuilder = new ChunkOcclusionDataBuilder(); - ChunkRendererRegion chunkRendererRegion = this.region; - this.region = null; - MatrixStack matrixStack = new MatrixStack(); - if (chunkRendererRegion != null) { - BlockModelRenderer.enableBrightnessCache(); - Set set = new ReferenceArraySet(RenderLayer.getBlockLayers().size()); - net.minecraft.util.math.random.Random random = net.minecraft.util.math.random.Random.create(); - BlockRenderManager blockRenderManager = MinecraftClient.getInstance().getBlockRenderManager(); - Iterator var15 = BlockPos.iterate(blockPos, blockPos2).iterator(); - - while(var15.hasNext()) { - BlockPos blockPos3 = (BlockPos)var15.next(); - BlockState blockState = chunkRendererRegion.getBlockState(blockPos3); - if (blockState.isOpaqueFullCube(chunkRendererRegion, blockPos3)) { - chunkOcclusionDataBuilder.markClosed(blockPos3); - } + private SectionBuilder.RenderData build(ChunkSectionPos sectionPos, ChunkRendererRegion region, VertexSorter vertexSorter, + BlockBufferAllocatorStorage allocatorStorage) { + SectionBuilder.RenderData renderData = new SectionBuilder.RenderData(); + BlockPos min = sectionPos.getMinPos(); + BlockPos max = min.add(15, 15, 15); + ChunkOcclusionDataBuilder occlusionDataBuilder = new ChunkOcclusionDataBuilder(); + MatrixStack matrices = new MatrixStack(); + BlockModelRenderer.enableBrightnessCache(); + Map buffersByLayer = new EnumMap<>(BlockRenderLayer.class); + Random random = Random.create(); + List parts = new ObjectArrayList<>(); + BlockRenderManager blockRenderManager = MinecraftClient.getInstance().getBlockRenderManager(); + BlockEntityRenderManager blockEntityRenderManager = MinecraftClient.getInstance().getBlockEntityRenderDispatcher(); + + for (BlockPos pos : BlockPos.iterate(min, max)) { + BlockState blockState = region.getBlockState(pos); + if (blockState.isOpaqueFullCube()) { + occlusionDataBuilder.markClosed(pos); + } - if (blockState.hasBlockEntity()) { - BlockEntity blockEntity = chunkRendererRegion.getBlockEntity(blockPos3); - if (blockEntity != null) { - this.addBlockEntity(renderData, blockEntity); - } + if (blockState.hasBlockEntity()) { + BlockEntity blockEntity = region.getBlockEntity(pos); + if (blockEntity != null) { + addBlockEntity(blockEntityRenderManager, renderData, blockEntity); } + } - BlockState blockState2 = chunkRendererRegion.getBlockState(blockPos3); - FluidState fluidState = blockState2.getFluidState(); - RenderLayer renderLayer; - BufferBuilder bufferBuilder; - if (!fluidState.isEmpty()) { - renderLayer = RenderLayers.getFluidLayer(fluidState); - bufferBuilder = buffers.get(renderLayer); - - EventRenderFluid event = new EventRenderFluid(fluidState, blockPos3, bufferBuilder); - BleachHack.eventBus.post(event); - - if (event.isCancelled()) - continue; + FluidState fluidState = blockState.getFluidState(); + if (!fluidState.isEmpty()) { + BlockRenderLayer layer = BlockRenderLayers.getFluidLayer(fluidState); + BufferBuilder bufferBuilder = beginBufferBuilding(buffersByLayer, allocatorStorage, layer); - if (set.add(renderLayer)) { - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL); - } + EventRenderFluid event = new EventRenderFluid(fluidState, pos, bufferBuilder); + BleachHack.eventBus.post(event); - blockRenderManager.renderFluid(blockPos3, chunkRendererRegion, bufferBuilder, blockState2, fluidState); + if (!event.isCancelled()) { + blockRenderManager.renderFluid(pos, region, event.getVertexConsumer(), blockState, fluidState); } + } - if (blockState.getRenderType() != BlockRenderType.INVISIBLE) { - renderLayer = RenderLayers.getBlockLayer(blockState); - bufferBuilder = buffers.get(renderLayer); - if (set.add(renderLayer)) { - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL); - } - - EventRenderBlock.Tesselate event = new EventRenderBlock.Tesselate(blockState, blockPos3, matrixStack, bufferBuilder); - BleachHack.eventBus.post(event); + // Kept 1.19.4's broader "!= INVISIBLE" check rather than vanilla's new narrower + // "== MODEL" one, so blocks that only vanilla would skip still get tesselated. + if (blockState.getRenderType() != BlockRenderType.INVISIBLE) { + BlockRenderLayer layer = BlockRenderLayers.getBlockLayer(blockState); + BufferBuilder bufferBuilder = beginBufferBuilding(buffersByLayer, allocatorStorage, layer); - if (event.isCancelled()) - continue; + EventRenderBlock.Tesselate event = new EventRenderBlock.Tesselate(blockState, pos, matrices, bufferBuilder); + BleachHack.eventBus.post(event); - matrixStack.push(); - matrixStack.translate((double)(blockPos3.getX() & 15), (double)(blockPos3.getY() & 15), (double)(blockPos3.getZ() & 15)); - blockRenderManager.renderBlock(blockState, blockPos3, chunkRendererRegion, matrixStack, bufferBuilder, true, random); - matrixStack.pop(); + if (event.isCancelled()) { + continue; } - } - if (set.contains(RenderLayer.getTranslucent())) { - BufferBuilder bufferBuilder2 = buffers.get(RenderLayer.getTranslucent()); - if (!bufferBuilder2.isBatchEmpty()) { - bufferBuilder2.sortFrom(cameraX - (float)blockPos.getX(), cameraY - (float)blockPos.getY(), cameraZ - (float)blockPos.getZ()); - renderData.translucencySortingData = bufferBuilder2.getSortingData(); - } - } + random.setSeed(blockState.getRenderingSeed(pos)); + blockRenderManager.getModel(blockState).addParts(random, parts); - var15 = set.iterator(); + matrices.push(); + matrices.translate(ChunkSectionPos.getLocalCoord(pos.getX()), ChunkSectionPos.getLocalCoord(pos.getY()), ChunkSectionPos.getLocalCoord(pos.getZ())); + blockRenderManager.renderBlock(blockState, pos, region, matrices, event.getVertexConsumer(), true, parts); + matrices.pop(); + parts.clear(); + } + } - while(var15.hasNext()) { - RenderLayer renderLayer2 = (RenderLayer)var15.next(); - BufferBuilder.BuiltBuffer builtBuffer = buffers.get(renderLayer2).endNullable(); - if (builtBuffer != null) { - renderData.field_39081.put(renderLayer2, builtBuffer); + for (Entry entry : buffersByLayer.entrySet()) { + BlockRenderLayer layer = entry.getKey(); + BuiltBuffer builtBuffer = entry.getValue().endNullable(); + if (builtBuffer != null) { + if (layer == BlockRenderLayer.TRANSLUCENT) { + renderData.translucencySortingData = builtBuffer.sortQuads(allocatorStorage.get(layer), vertexSorter); } - } - BlockModelRenderer.disableBrightnessCache(); + renderData.buffers.put(layer, builtBuffer); + } } - renderData.chunkOcclusionData = chunkOcclusionDataBuilder.build(); + BlockModelRenderer.disableBrightnessCache(); + renderData.chunkOcclusionData = occlusionDataBuilder.build(); return renderData; } + + private BufferBuilder beginBufferBuilding(Map builders, BlockBufferAllocatorStorage allocatorStorage, BlockRenderLayer layer) { + BufferBuilder bufferBuilder = builders.get(layer); + if (bufferBuilder == null) { + BufferAllocator bufferAllocator = allocatorStorage.get(layer); + bufferBuilder = new BufferBuilder(bufferAllocator, VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL); + builders.put(layer, bufferBuilder); + } + + return bufferBuilder; + } + + private void addBlockEntity(BlockEntityRenderManager dispatcher, SectionBuilder.RenderData data, E blockEntity) { + BlockEntityRenderer renderer = dispatcher.get(blockEntity); + if (renderer != null && !renderer.rendersOutsideBoundingBox()) { + data.blockEntities.add(blockEntity); + } + } } diff --git a/src/main/java/org/bleachhack/mixin/MixinChunkSkylightProvider.java b/src/main/java/org/bleachhack/mixin/MixinChunkSkylightProvider.java index 650d891d92..63d6a47a33 100644 --- a/src/main/java/org/bleachhack/mixin/MixinChunkSkylightProvider.java +++ b/src/main/java/org/bleachhack/mixin/MixinChunkSkylightProvider.java @@ -13,17 +13,31 @@ 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.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.world.chunk.light.ChunkSkyLightProvider; +// 1.19.4 hooked recalculateLevel(long, long, int) - a small helper that computed the new light level +// for one neighboring position - and forced it to return 0 to short-circuit skylight math for the +// "Skylight" lag-reduction toggle. That helper is gone: the light engine was rewritten and its logic +// is now fully inlined into propagateLightIncrease/propagateLightDecrease directly (no separable +// "compute the level" call left to override). Cancelling both of those outright instead - skipping +// skylight propagation entirely - achieves the same goal (and more thoroughly, since it skips the +// surrounding queueing work too, not just the level computation). @Mixin(ChunkSkyLightProvider.class) public class MixinChunkSkylightProvider { - @Inject(method = "recalculateLevel", at = @At("HEAD"), cancellable = true) - private void recalculateLevel(long id, long excludedId, int maxLevel, CallbackInfoReturnable ci) { + @Inject(method = "propagateLightIncrease", at = @At("HEAD"), cancellable = true) + private void propagateLightIncrease(long blockPos, long packed, int lightLevel, CallbackInfo ci) { if (ModuleManager.getModule(NoRender.class).isWorldToggled(4)) { - ci.setReturnValue(0); + ci.cancel(); + } + } + + @Inject(method = "propagateLightDecrease", at = @At("HEAD"), cancellable = true) + private void propagateLightDecrease(long blockPos, long packed, CallbackInfo ci) { + if (ModuleManager.getModule(NoRender.class).isWorldToggled(4)) { + ci.cancel(); } } } diff --git a/src/main/java/org/bleachhack/mixin/MixinClientConnection.java b/src/main/java/org/bleachhack/mixin/MixinClientConnection.java index edd77ceb36..202db2cf31 100644 --- a/src/main/java/org/bleachhack/mixin/MixinClientConnection.java +++ b/src/main/java/org/bleachhack/mixin/MixinClientConnection.java @@ -8,25 +8,25 @@ */ package org.bleachhack.mixin; -import net.minecraft.network.PacketCallbacks; import org.bleachhack.BleachHack; import org.bleachhack.command.Command; import org.bleachhack.command.CommandManager; import org.bleachhack.event.events.EventPacket; +import org.bleachhack.gui.ProtocolScreen; 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.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; import net.minecraft.network.ClientConnection; import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket; import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; -import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; @Mixin(ClientConnection.class) public class MixinClientConnection { @@ -45,8 +45,21 @@ private void channelRead0(ChannelHandlerContext channelHandlerContext, Packet } } - @Inject(method = "send(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;)V", at = @At("HEAD"), cancellable = true) - private void send(Packet packet, PacketCallbacks packetCallback, CallbackInfo callback) { + // 1.19.4 spoofed the reported protocol version by mutating MinecraftVersion's fields globally (gone - + // GameVersion is an immutable record now, see ProtocolScreen notes). This is actually a more faithful + // implementation of the feature's own stated intent ("only changes what the client says to servers") + // than the old approach was: it only rewrites the actual outgoing handshake packet, not global state. + @ModifyVariable(method = "send(Lnet/minecraft/network/packet/Packet;Lio/netty/channel/ChannelFutureListener;)V", at = @At("HEAD"), argsOnly = true) + private Packet send_spoofProtocolVersion(Packet packet) { + if (packet instanceof HandshakeC2SPacket handshake && ProtocolScreen.PROTOCOL != null) { + return new HandshakeC2SPacket(ProtocolScreen.PROTOCOL, handshake.address(), handshake.port(), handshake.intendedState()); + } + + return packet; + } + + @Inject(method = "send(Lnet/minecraft/network/packet/Packet;Lio/netty/channel/ChannelFutureListener;)V", at = @At("HEAD"), cancellable = true) + private void send(Packet packet, ChannelFutureListener listener, CallbackInfo callback) { if (packet instanceof ChatMessageC2SPacket) { if (!CommandManager.allowNextMsg) { ChatMessageC2SPacket pack = (ChatMessageC2SPacket) packet; diff --git a/src/main/java/org/bleachhack/mixin/MixinClientPlayerEntity.java b/src/main/java/org/bleachhack/mixin/MixinClientPlayerEntity.java index 98c837312d..91e506a163 100644 --- a/src/main/java/org/bleachhack/mixin/MixinClientPlayerEntity.java +++ b/src/main/java/org/bleachhack/mixin/MixinClientPlayerEntity.java @@ -96,7 +96,7 @@ private void pushOutOfBlocks(double x, double d, CallbackInfo ci) { } } - @Redirect(method = "updateNausea", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;closeHandledScreen()V", ordinal = 0), + @Redirect(method = "tickNausea", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;closeHandledScreen()V", ordinal = 0), require = 0 /* TODO: inertia compatibility */) private void updateNausea_closeHandledScreen(ClientPlayerEntity player) { if (!ModuleManager.getModule(BetterPortal.class).isEnabled() @@ -105,7 +105,7 @@ private void updateNausea_closeHandledScreen(ClientPlayerEntity player) { } } - @Redirect(method = "updateNausea", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setScreen(Lnet/minecraft/client/gui/screen/Screen;)V", ordinal = 0), + @Redirect(method = "tickNausea", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setScreen(Lnet/minecraft/client/gui/screen/Screen;)V", ordinal = 0), require = 0 /* TODO: inertia compatibility */) private void updateNausea_setScreen(MinecraftClient client, Screen screen) { if (!ModuleManager.getModule(BetterPortal.class).isEnabled() diff --git a/src/main/java/org/bleachhack/mixin/MixinClientPlayerInteractionManager.java b/src/main/java/org/bleachhack/mixin/MixinClientPlayerInteractionManager.java index ca1c260063..8a59c21da6 100644 --- a/src/main/java/org/bleachhack/mixin/MixinClientPlayerInteractionManager.java +++ b/src/main/java/org/bleachhack/mixin/MixinClientPlayerInteractionManager.java @@ -11,7 +11,6 @@ import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventBlockBreakCooldown; import org.bleachhack.event.events.EventInteract; -import org.bleachhack.event.events.EventReach; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -100,11 +99,7 @@ private void interactItem(PlayerEntity player, Hand hand, CallbackInfoReturnable } } - @Inject(method = "getReachDistance", at = @At("RETURN"), cancellable = true) - private void getReachDistance(CallbackInfoReturnable callback) { - EventReach event = new EventReach(callback.getReturnValueF()); - BleachHack.eventBus.post(event); - - callback.setReturnValue(event.getReach()); - } + // getReachDistance() no longer exists - reach is now attribute-based + // (EntityAttributes.BLOCK_INTERACTION_RANGE/ENTITY_INTERACTION_RANGE on PlayerEntity); see + // MixinPlayerEntity for the direct replacement of this hook. } diff --git a/src/main/java/org/bleachhack/mixin/MixinClientWorld.java b/src/main/java/org/bleachhack/mixin/MixinClientWorld.java index a56b68df98..a3c24041ff 100644 --- a/src/main/java/org/bleachhack/mixin/MixinClientWorld.java +++ b/src/main/java/org/bleachhack/mixin/MixinClientWorld.java @@ -9,28 +9,21 @@ package org.bleachhack.mixin; import org.bleachhack.BleachHack; -import org.bleachhack.event.events.EventSkyRender; import org.bleachhack.event.events.EventTick; import org.bleachhack.util.BleachQueue; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.DimensionEffects; import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.Vec3d; +// 1.21.11 removed ClientWorld.getSkyColor/getCloudsColor/getDimensionEffects entirely, replaced by a +// generic EnvironmentAttributes system (see Ambience.java notes) - those hooks had no direct +// equivalent to move to and were dropped from this mixin; tickEntities is unaffected. @Mixin(ClientWorld.class) public class MixinClientWorld { - @Shadow @Final private DimensionEffects dimensionEffects; - @Inject(method = "tickEntities", at = @At("HEAD"), cancellable = true) private void tickEntities(CallbackInfo info) { BleachQueue.nextQueue(); @@ -40,40 +33,4 @@ private void tickEntities(CallbackInfo info) { if (event.isCancelled()) info.cancel(); } - - @Inject(method = "getSkyColor", at = @At("HEAD"), cancellable = true) - public void getSkyColor(Vec3d cameraPos, float tickDelta, CallbackInfoReturnable ci) { - EventSkyRender.Color.SkyColor event = new EventSkyRender.Color.SkyColor(tickDelta); - BleachHack.eventBus.post(event); - - if (event.isCancelled()) { - ci.setReturnValue(Vec3d.ZERO); - } else if (event.getColor() != null) { - ci.setReturnValue(event.getColor()); - } - } - - @Inject(method = "getCloudsColor", at = @At("HEAD"), cancellable = true) - private void getCloudsColor(float f, CallbackInfoReturnable ci) { - EventSkyRender.Color.CloudColor event = new EventSkyRender.Color.CloudColor(f); - BleachHack.eventBus.post(event); - - if (event.isCancelled()) { - ci.setReturnValue(Vec3d.ZERO); - } else if (event.getColor() != null) { - ci.setReturnValue(event.getColor()); - } - } - - @Overwrite - public DimensionEffects getDimensionEffects() { - if (MinecraftClient.getInstance().world == null) { - return dimensionEffects; - } - - EventSkyRender.Properties event = new EventSkyRender.Properties(dimensionEffects); - BleachHack.eventBus.post(event); - - return event.getSky(); - } } diff --git a/src/main/java/org/bleachhack/mixin/MixinDimensionEffects.java b/src/main/java/org/bleachhack/mixin/MixinDimensionEffects.java deleted file mode 100644 index 8e9bb770ce..0000000000 --- a/src/main/java/org/bleachhack/mixin/MixinDimensionEffects.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). - * Copyright (c) 2021 Bleach and contributors. - * - * This source code is subject to the terms of the GNU General Public - * License, version 3. If a copy of the GPL was not distributed with this - * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt - */ -package org.bleachhack.mixin; - -import org.bleachhack.BleachHack; -import org.bleachhack.event.events.EventSkyRender; -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.CallbackInfoReturnable; - -import net.minecraft.client.render.DimensionEffects; - -@Mixin(DimensionEffects.class) -public class MixinDimensionEffects { - - @Inject(method = "getFogColorOverride", at = @At("HEAD"), cancellable = true) - private void getFogColorOverride(float skyAngle, float tickDelta, CallbackInfoReturnable ci) { - EventSkyRender.Color.FogColor event = new EventSkyRender.Color.FogColor(tickDelta); - BleachHack.eventBus.post(event); - - if (event.isCancelled()) { - ci.setReturnValue(null); - } else if (event.getColor() != null) { - ci.setReturnValue(new float[] { (float) event.getColor().x, (float) event.getColor().y, (float) event.getColor().z, 1f }); - } - } -} diff --git a/src/main/java/org/bleachhack/mixin/MixinDrawContext.java b/src/main/java/org/bleachhack/mixin/MixinDrawContext.java new file mode 100644 index 0000000000..838bb458ca --- /dev/null +++ b/src/main/java/org/bleachhack/mixin/MixinDrawContext.java @@ -0,0 +1,63 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.mixin; + +import java.util.List; + +import org.bleachhack.BleachHack; +import org.bleachhack.event.events.EventRenderTooltip; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.gui.tooltip.TooltipPositioner; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; + +// 1.19.4 hooked Screen#renderTooltipFromComponents(MatrixStack, ...) to intercept tooltip draws. +// 1.21.11 removed that method entirely - tooltip drawing moved into DrawContext itself and is now +// deferred (queued via DrawContext#drawTooltip, actually drawn later by drawDeferredElements()), with +// DrawContext#drawTooltipImmediately(...) as the single real draw routine every tooltip path funnels +// through. That's the equivalent hook point now. +@Mixin(DrawContext.class) +public class MixinDrawContext { + + @Unique private boolean skipTooltip; + + @Shadow + public void drawTooltipImmediately(TextRenderer textRenderer, List components, int x, int y, + TooltipPositioner positioner, Identifier texture) {} + + @Inject(method = "drawTooltipImmediately", at = @At("HEAD"), cancellable = true) + private void drawTooltipImmediately(TextRenderer textRenderer, List components, int x, int y, + TooltipPositioner positioner, Identifier texture, CallbackInfo callback) { + if (skipTooltip) { + skipTooltip = false; + return; + } + + EventRenderTooltip event = new EventRenderTooltip(MinecraftClient.getInstance().currentScreen, new MatrixStack(), components, x, y, x, y); + BleachHack.eventBus.post(event); + + callback.cancel(); + if (event.isCancelled()) { + return; + } + + skipTooltip = true; + drawTooltipImmediately(textRenderer, event.getComponents(), event.getX(), event.getY(), positioner, texture); + } +} diff --git a/src/main/java/org/bleachhack/mixin/MixinDrawContextTextAlpha.java b/src/main/java/org/bleachhack/mixin/MixinDrawContextTextAlpha.java new file mode 100644 index 0000000000..39fe17fbf0 --- /dev/null +++ b/src/main/java/org/bleachhack/mixin/MixinDrawContextTextAlpha.java @@ -0,0 +1,33 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import net.minecraft.client.gui.DrawContext; + +// 1.19.4's TextRenderer ran every color through a "tweakTransparency" step before drawing: if the +// alpha byte's top 6 bits were all zero (i.e. the caller passed a bare RGB literal like 0x70efe0 with +// no alpha, which is how BleachHack's whole GUI codebase writes text colors), it forced full opacity +// (color | 0xFF000000) instead of treating it as see-through. 1.21.11's DrawContext.drawText dropped +// that normalization and instead just silently skips the draw entirely when alpha == 0 +// ("if (ColorHelper.getAlpha(color) != 0) { ... }") - so every bare-RGB text color across the mod +// (module list entries, Options/Credits/Accounts screens, tooltips, ...) went invisible instead of +// throwing, since nothing else changed shape. Restoring the exact 1.19.4 normalization here fixes all +// of those call sites at once instead of auditing and rewriting ~100 individual color literals. +@Mixin(DrawContext.class) +public class MixinDrawContextTextAlpha { + + @ModifyVariable(method = "drawText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/OrderedText;IIIZ)V", at = @At("HEAD"), ordinal = 2, argsOnly = true) + private int tweakTransparency(int color) { + return (color & 0xFC000000) == 0 ? color | 0xFF000000 : color; + } +} diff --git a/src/main/java/org/bleachhack/mixin/MixinEntityRenderDispatcher.java b/src/main/java/org/bleachhack/mixin/MixinEntityRenderDispatcher.java deleted file mode 100644 index 3070be268b..0000000000 --- a/src/main/java/org/bleachhack/mixin/MixinEntityRenderDispatcher.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). - * Copyright (c) 2021 Bleach and contributors. - * - * This source code is subject to the terms of the GNU General Public - * License, version 3. If a copy of the GPL was not distributed with this - * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt - */ -package org.bleachhack.mixin; - -import org.bleachhack.BleachHack; -import org.bleachhack.event.events.EventEntityRender; -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 net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.EntityRenderDispatcher; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; - -@Mixin(EntityRenderDispatcher.class) -public class MixinEntityRenderDispatcher { - - @Inject(method = "render", at = @At("RETURN")) - private void render_render(E entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { - EventEntityRender.Single.Post event = new EventEntityRender.Single.Post(entity, matrices, vertexConsumers); - BleachHack.eventBus.post(event); - } -} diff --git a/src/main/java/org/bleachhack/mixin/MixinEntityRenderer.java b/src/main/java/org/bleachhack/mixin/MixinEntityRenderer.java index 570cc7e984..5e04eefe04 100644 --- a/src/main/java/org/bleachhack/mixin/MixinEntityRenderer.java +++ b/src/main/java/org/bleachhack/mixin/MixinEntityRenderer.java @@ -8,25 +8,55 @@ */ package org.bleachhack.mixin; +import java.util.Map; +import java.util.WeakHashMap; + import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventEntityRender; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.state.CameraRenderState; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; -import net.minecraft.text.Text; +// 1.21.11 decoupled entity rendering from the live Entity - renderLabelIfPresent(and render(...)) +// now only get a snapshotted EntityRenderState (S), which doesn't carry a reference back to the +// Entity it was built from. Modules (Nametags) still need the real Entity for instanceof checks, so +// this stashes the entity<->state association from updateRenderState (which still runs with both) +// into a per-renderer weak map, keyed by state identity, and looks it up again at render time. +// +// ESP's "Shader" mode used to hijack this same hook to set EntityRenderState.outlineColor, piggy- +// backing on vanilla's own Glowing-effect framebuffer/shader - that's gone now (see +// util.render.ShaderEspRenderer), since ESP shouldn't share machinery with real Glowing potion +// effects/team glow, and doing so meant the result could never look like more than vanilla's built-in +// glow. ShaderEspRenderer renders its own separate silhouette pass entirely from ESP's own +// onWorldRender, independent of this mixin. @Mixin(EntityRenderer.class) -public abstract class MixinEntityRenderer { +public abstract class MixinEntityRenderer { + + @Unique + private final Map bleachhack$stateToEntity = new WeakHashMap<>(); + + @Inject(method = "updateRenderState", at = @At("RETURN")) + private void updateRenderState(T entity, S state, float tickDelta, CallbackInfo ci) { + bleachhack$stateToEntity.put(state, entity); + } @Inject(method = "renderLabelIfPresent", at = @At("HEAD"), cancellable = true) - private void renderLabelIfPresent(T entity, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo info) { - EventEntityRender.Single.Label event = new EventEntityRender.Single.Label(entity, matrices, vertexConsumers); + private void renderLabelIfPresent(S state, MatrixStack matrices, OrderedRenderCommandQueue queue, CameraRenderState cameraState, CallbackInfo info) { + Entity entity = bleachhack$stateToEntity.get(state); + if (entity == null) { + return; + } + + EventEntityRender.Single.Label event = new EventEntityRender.Single.Label(entity, matrices, queue); BleachHack.eventBus.post(event); if (event.isCancelled()) { diff --git a/src/main/java/org/bleachhack/mixin/MixinGameRenderer.java b/src/main/java/org/bleachhack/mixin/MixinGameRenderer.java index 632df80d33..371c487238 100644 --- a/src/main/java/org/bleachhack/mixin/MixinGameRenderer.java +++ b/src/main/java/org/bleachhack/mixin/MixinGameRenderer.java @@ -8,30 +8,45 @@ */ package org.bleachhack.mixin; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gl.PostEffectProcessor; +import net.minecraft.client.render.DefaultFramebufferSet; +import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.util.memory.ObjectPool; import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventRenderShader; import org.bleachhack.module.ModuleManager; import org.bleachhack.module.mods.NoRender; +import org.bleachhack.module.mods.Zoom; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.mojang.blaze3d.systems.RenderSystem; - +import net.minecraft.client.render.Camera; import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; @Mixin(GameRenderer.class) public class MixinGameRenderer { - @Shadow private PostEffectProcessor postProcessor; + @Shadow private MinecraftClient client; + @Shadow private Identifier postProcessorId; + @Shadow private boolean postProcessorEnabled; + @Shadow private ObjectPool pool; + + // 1.21.11 replaced GameRenderer's `postProcessor` field (a live PostEffectProcessor instance) with + // a lazily-loaded `postProcessorId`/`postProcessorEnabled` pair, so there's no single field read left + // to redirect. This flag lets us suppress vanilla's own render call for exactly one frame after we've + // already rendered our own (possibly substituted) effect, instead of double-rendering it. + private boolean bleachhack_renderedCustomEffect; @Inject(method = "tiltViewWhenHurt", at = @At("HEAD"), cancellable = true) private void onTiltViewWhenHurt(MatrixStack matrixStack, float f, CallbackInfo ci) { @@ -57,18 +72,45 @@ private float nauseaWobble(float delta, float first, float second) { return MathHelper.lerp(delta, first, second); } - @Redirect(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/GameRenderer;postProcessor:Lnet/minecraft/client/gl/PostEffectProcessor;", ordinal = 0)) - private PostEffectProcessor render_Shader(GameRenderer renderer, float tickDelta) { - EventRenderShader event = new EventRenderShader(postProcessor); + // Zoom - Meteor's own Zoom module divides the *computed* per-frame FOV via its GetFovEvent + // instead of overwriting GameOptions' persisted FOV value (which is what BleachHack's Zoom used + // to do, and which visibly reset the options-screen FOV to "Normal" instead of actually zooming, + // since only vanilla's own read of that same option elsewhere applied any zoom at all). Doing the + // same here - this method already recomputes the effective FOV fresh every call - means Zoom + // needs no persisted option and nothing to restore for FOV specifically. + @Inject(method = "getFov", at = @At("RETURN"), cancellable = true) + private void bleachhack_zoomFov(Camera camera, float tickProgress, boolean changingFov, CallbackInfoReturnable cir) { + Zoom zoom = ModuleManager.getModule(Zoom.class); + if (zoom.isEnabled()) { + cir.setReturnValue(cir.getReturnValueF() / zoom.getScale()); + } + } + + @Inject(method = "render", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/render/WorldRenderer;drawEntityOutlinesFramebuffer()V", shift = At.Shift.AFTER)) + private void render_Shader(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) { + PostEffectProcessor current = postProcessorId != null + ? client.getShaderLoader().loadPostEffect(postProcessorId, DefaultFramebufferSet.MAIN_ONLY) + : null; + + EventRenderShader event = new EventRenderShader(current); BleachHack.eventBus.post(event); + bleachhack_renderedCustomEffect = event.getEffect() != null; + if (event.getEffect() != null) { - RenderSystem.disableBlend(); - RenderSystem.disableDepthTest(); - RenderSystem.resetTextureMatrix(); - event.getEffect().render(tickDelta); + event.getEffect().render(client.getFramebuffer(), pool); + } + } + + @Redirect(method = "render", at = @At(value = "FIELD", + target = "Lnet/minecraft/client/render/GameRenderer;postProcessorEnabled:Z")) + private boolean render_suppressVanillaShaderDoubleRender(GameRenderer renderer) { + if (bleachhack_renderedCustomEffect) { + bleachhack_renderedCustomEffect = false; + return false; } - return null; + return postProcessorEnabled; } } diff --git a/src/main/java/org/bleachhack/mixin/MixinInGameHud.java b/src/main/java/org/bleachhack/mixin/MixinInGameHud.java index 40c42bb067..baed998b6f 100644 --- a/src/main/java/org/bleachhack/mixin/MixinInGameHud.java +++ b/src/main/java/org/bleachhack/mixin/MixinInGameHud.java @@ -19,8 +19,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.render.RenderTickCounter; import net.minecraft.util.Identifier; @Mixin(InGameHud.class) @@ -29,12 +30,13 @@ public class MixinInGameHud { @Unique private boolean bypassRenderOverlay = false; @Unique private boolean bypassRenderCrosshair = false; - @Shadow private void renderOverlay(MatrixStack matrices, Identifier texture, float opacity) {} - @Shadow private void renderCrosshair(MatrixStack matrices) {} + @Shadow private void renderOverlay(DrawContext matrices, Identifier texture, float opacity) {} + // 1.21.11 added a RenderTickCounter parameter to renderCrosshair that wasn't there before. + @Shadow private void renderCrosshair(DrawContext matrices, RenderTickCounter tickCounter) {} @Inject(method = "render", at = @At("RETURN"), cancellable = true) - private void render(MatrixStack matrixStack, float tickDelta, CallbackInfo info) { - EventRenderInGameHud event = new EventRenderInGameHud(matrixStack); + private void render(DrawContext drawContext, RenderTickCounter tickCounter, CallbackInfo info) { + EventRenderInGameHud event = new EventRenderInGameHud(drawContext); BleachHack.eventBus.post(event); if (event.isCancelled()) { @@ -43,7 +45,7 @@ private void render(MatrixStack matrixStack, float tickDelta, CallbackInfo info) } @Inject(method = "renderOverlay", at = @At("HEAD"), cancellable = true) - private void renderOverlay(MatrixStack matrices, Identifier texture, float opacity, CallbackInfo ci) { + private void renderOverlay(DrawContext matrices, Identifier texture, float opacity, CallbackInfo ci) { if (!bypassRenderOverlay) { EventRenderOverlay event = new EventRenderOverlay(matrices, texture, opacity); BleachHack.eventBus.post(event); @@ -60,14 +62,14 @@ private void renderOverlay(MatrixStack matrices, Identifier texture, float opaci @Inject(method = "renderCrosshair", at = @At("HEAD"), cancellable = true) - private void renderCrosshair(MatrixStack matrices, CallbackInfo callback) { + private void renderCrosshair(DrawContext matrices, RenderTickCounter tickCounter, CallbackInfo callback) { if (!bypassRenderCrosshair) { EventRenderCrosshair event = new EventRenderCrosshair(matrices); BleachHack.eventBus.post(event); if (!event.isCancelled()) { bypassRenderCrosshair = true; - renderCrosshair(event.getMatrices()); + renderCrosshair(event.getMatrices(), tickCounter); bypassRenderCrosshair = false; } diff --git a/src/main/java/org/bleachhack/mixin/MixinInGameOverlayRenderer.java b/src/main/java/org/bleachhack/mixin/MixinInGameOverlayRenderer.java index ce5dc2f143..8ccccdfce5 100644 --- a/src/main/java/org/bleachhack/mixin/MixinInGameOverlayRenderer.java +++ b/src/main/java/org/bleachhack/mixin/MixinInGameOverlayRenderer.java @@ -17,20 +17,22 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.hud.InGameOverlayRenderer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.math.MatrixStack; @Mixin(InGameOverlayRenderer.class) public class MixinInGameOverlayRenderer { @Inject(method = "renderFireOverlay", at = @At("HEAD"), cancellable = true) - private static void onRenderFireOverlay(MinecraftClient minecraftClient, MatrixStack matrixStack, CallbackInfo ci) { + private static void onRenderFireOverlay(MatrixStack matrixStack, VertexConsumerProvider vertexConsumers, Sprite sprite, CallbackInfo ci) { if (ModuleManager.getModule(NoRender.class).isOverlayToggled(1)) { ci.cancel(); } } @Inject(method = "renderUnderwaterOverlay", at = @At("HEAD"), cancellable = true) - private static void onRenderUnderwaterOverlay(MinecraftClient minecraftClient, MatrixStack matrixStack, CallbackInfo ci) { + private static void onRenderUnderwaterOverlay(MinecraftClient minecraftClient, MatrixStack matrixStack, VertexConsumerProvider vertexConsumers, CallbackInfo ci) { if (ModuleManager.getModule(NoRender.class).isOverlayToggled(3)) { ci.cancel(); } diff --git a/src/main/java/org/bleachhack/mixin/MixinJsonEffectShaderProgram.java b/src/main/java/org/bleachhack/mixin/MixinJsonEffectShaderProgram.java deleted file mode 100644 index fb1a2fbb22..0000000000 --- a/src/main/java/org/bleachhack/mixin/MixinJsonEffectShaderProgram.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). - * Copyright (c) 2021 Bleach and contributors. - * - * This source code is subject to the terms of the GNU General Public - * License, version 3. If a copy of the GPL was not distributed with this - * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt - */ -package org.bleachhack.mixin; - -import net.minecraft.client.gl.JsonEffectShaderProgram; -import net.minecraft.client.gl.ShaderStage; -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.ModifyArgs; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; - -import org.spongepowered.asm.mixin.injection.invoke.arg.Args; - -// Tweaks to the json effect shader class to make it compatible with OpenResourceManager -@Mixin(JsonEffectShaderProgram.class) -public class MixinJsonEffectShaderProgram { - - // Patch for Architectury - @Inject(method = "mojangPls(Lnet/minecraft/util/Identifier;Ljava/lang/String;)Lnet/minecraft/util/Identifier;", at = @At("HEAD"), cancellable = true, require = 0) - private static void mojangPls(Identifier id, String ext, CallbackInfoReturnable callback) { - callback.setReturnValue( - "__url__".equals(id.getNamespace()) ? id : new Identifier(id.getNamespace(), "shaders/program/" + id.getPath() + ext)); - } - - @ModifyArgs(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Identifier;(Ljava/lang/String;)V")) - private void init_identifier(Args args, ResourceManager resourceManager, String name) { - args.set(0, replaceIdentifier(args.get(0), name)); - } - - @ModifyArgs(method = "loadEffect", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Identifier;(Ljava/lang/String;)V")) - private static void loadEffect_identifier(Args args, ResourceManager resourceManager, ShaderStage.Type type, String name) { - args.set(0, replaceIdentifier(args.get(0), name)); - } - - private static String replaceIdentifier(String string, String name) { - String[] split = name.split(":"); - if (split.length > 1) { - if ("__url__".equals(split[0])) - return name; - - return split[0] + ":" + string.replace(name, split[1]); - } - - return string; - } -} diff --git a/src/main/java/org/bleachhack/mixin/MixinKeyboard.java b/src/main/java/org/bleachhack/mixin/MixinKeyboard.java index 7d3b96439c..ec5ba2a93e 100644 --- a/src/main/java/org/bleachhack/mixin/MixinKeyboard.java +++ b/src/main/java/org/bleachhack/mixin/MixinKeyboard.java @@ -21,14 +21,22 @@ import net.minecraft.client.Keyboard; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ChatScreen; +import net.minecraft.client.input.KeyInput; +import net.minecraft.client.util.InputUtil; @Mixin(Keyboard.class) public class MixinKeyboard { + // onKey's signature changed from (long, int key, int scanCode, int action, int modifiers) to + // (long, int action, KeyInput input) - key/scanCode/modifiers moved into the KeyInput record. + // The old second injection point (an InputUtil.isKeyPressed call, ordinal 5, inside the F3-debug-key + // handling block near the top of the method) no longer exists - 1.21.11's onKey only calls + // isKeyPressed once (ordinal 0, for the debug crash key). Both hooks just need to run early/ + // unconditionally before Minecraft's own key handling can consume the key, so both are HEAD now. @Inject(method = "onKey", at = @At("HEAD"), cancellable = true) - private void onKeyEvent(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo callbackInfo) { - if (key >= 0) { - EventKeyPress.Global event = new EventKeyPress.Global(key, scanCode, action, modifiers); + private void onKeyEvent(long windowPointer, int action, KeyInput input, CallbackInfo callbackInfo) { + if (input.key() >= 0) { + EventKeyPress.Global event = new EventKeyPress.Global(input.key(), input.scancode(), action, input.modifiers()); BleachHack.eventBus.post(event); if (event.isCancelled()) { @@ -36,17 +44,30 @@ private void onKeyEvent(long windowPointer, int key, int scanCode, int action, i } } } - - @Inject(method = "onKey", at = @At(value = "INVOKE", target = "net/minecraft/client/util/InputUtil.isKeyPressed(JI)Z", ordinal = 5), cancellable = true) - private void onKeyEvent_1(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo callbackInfo) { - if (Option.CHAT_QUICK_PREFIX.getValue() && Command.getPrefix().length() == 1 && key == Command.getPrefix().charAt(0)) { - MinecraftClient.getInstance().setScreen(new ChatScreen(Command.getPrefix())); + + @Inject(method = "onKey", at = @At("HEAD"), cancellable = true) + private void onKeyEvent_1(long windowPointer, int action, KeyInput input, CallbackInfo callbackInfo) { + // Module keybinds (handleKey) and the quick-prefix chat trigger must only fire once per actual + // press - @At("HEAD") means this now runs for press/release/repeat alike, unlike the old + // isKeyPressed-ordinal anchor point which happened to only ever run within a press-gated block. + if (action != InputUtil.GLFW_PRESS) { + return; + } + + // Module keybinds (and the quick-prefix chat trigger) should only fire while actually + // playing - not while typing in chat, a sign, ClickGui's search bar, or any other screen. + if (MinecraftClient.getInstance().currentScreen != null) { + return; + } + + if (Option.CHAT_QUICK_PREFIX.getValue() && Command.getPrefix().length() == 1 && input.key() == Command.getPrefix().charAt(0)) { + MinecraftClient.getInstance().setScreen(new ChatScreen(Command.getPrefix(), false)); } - ModuleManager.handleKey(key); + ModuleManager.handleKey(input.key()); - if (key >= 0) { - EventKeyPress.InWorld event = new EventKeyPress.InWorld(key, scanCode); + if (input.key() >= 0) { + EventKeyPress.InWorld event = new EventKeyPress.InWorld(input.key(), input.scancode()); BleachHack.eventBus.post(event); if (event.isCancelled()) { diff --git a/src/main/java/org/bleachhack/mixin/MixinLivingEntity.java b/src/main/java/org/bleachhack/mixin/MixinLivingEntity.java index 809267d56f..66d8923f56 100644 --- a/src/main/java/org/bleachhack/mixin/MixinLivingEntity.java +++ b/src/main/java/org/bleachhack/mixin/MixinLivingEntity.java @@ -20,6 +20,7 @@ import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.damage.DamageSource; +import net.minecraft.server.world.ServerWorld; import net.minecraft.world.World; @Mixin(LivingEntity.class) @@ -40,7 +41,7 @@ private void takeKnockback_setVelocity(LivingEntity entity, double x, double y, } @Inject(method = "damage", at = @At("HEAD"), cancellable = true) - private void damage(DamageSource source, float amount, CallbackInfoReturnable callbackInfo) { + private void damage(ServerWorld world, DamageSource source, float amount, CallbackInfoReturnable callbackInfo) { EventDamage.Normal event = new EventDamage.Normal(source, amount); BleachHack.eventBus.post(event); diff --git a/src/main/java/org/bleachhack/mixin/MixinMapRenderer.java b/src/main/java/org/bleachhack/mixin/MixinMapRenderer.java index 11d51d3100..1526dbc33b 100644 --- a/src/main/java/org/bleachhack/mixin/MixinMapRenderer.java +++ b/src/main/java/org/bleachhack/mixin/MixinMapRenderer.java @@ -15,16 +15,16 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.minecraft.client.render.MapRenderState; import net.minecraft.client.render.MapRenderer; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.map.MapState; @Mixin(MapRenderer.class) public class MixinMapRenderer { @Inject(method = "draw", at = @At("HEAD"), cancellable = true) - private void draw(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int id, MapState state, boolean hidePlayerIcons, int light, CallbackInfo ci) { + private void draw(MapRenderState state, MatrixStack matrices, OrderedRenderCommandQueue queue, boolean hidePlayerIcons, int light, CallbackInfo ci) { if (ModuleManager.getModule(NoRender.class).isWorldToggled(3)) { ci.cancel(); } diff --git a/src/main/java/org/bleachhack/mixin/MixinLlamaPigStriderEntity.java b/src/main/java/org/bleachhack/mixin/MixinMobEntity.java similarity index 52% rename from src/main/java/org/bleachhack/mixin/MixinLlamaPigStriderEntity.java rename to src/main/java/org/bleachhack/mixin/MixinMobEntity.java index 17f14b2d66..7cc530e26d 100644 --- a/src/main/java/org/bleachhack/mixin/MixinLlamaPigStriderEntity.java +++ b/src/main/java/org/bleachhack/mixin/MixinMobEntity.java @@ -8,8 +8,6 @@ */ package org.bleachhack.mixin; -import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.AbstractHorseEntity; import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventEntityControl; import org.spongepowered.asm.mixin.Mixin; @@ -17,23 +15,19 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.passive.AnimalEntity; -import net.minecraft.entity.passive.LlamaEntity; -import net.minecraft.entity.passive.PigEntity; -import net.minecraft.entity.passive.StriderEntity; -import net.minecraft.world.World; +import net.minecraft.entity.mob.MobEntity; -@Mixin({AbstractHorseEntity.class, PigEntity.class, StriderEntity.class}) -public abstract class MixinLlamaPigStriderEntity extends AnimalEntity { +// 1.19.4 hooked isSaddled() on AbstractHorseEntity/PigEntity/StriderEntity individually (each had its +// own copy). 1.21.11 consolidated it into a single hasSaddleEquipped() on the shared MobEntity base +// class (just checks the SADDLE equipment slot) - Mixin can't inject an inherited-but-not-overridden +// method into 3 separate leaf classes that don't each redeclare it, so this hooks the one real +// declaration on MobEntity instead. Harmless for non-rideable mobs since the default check +// (isWearing(EquipmentSlot.SADDLE)) is already always false for them. +@Mixin(MobEntity.class) +public abstract class MixinMobEntity { - private MixinLlamaPigStriderEntity(EntityType entityType, World world) { - super(entityType, world); - } - - @Inject(method = "isSaddled", at = @At("HEAD"), cancellable = true) - private void isSaddled(CallbackInfoReturnable info) { + @Inject(method = "hasSaddleEquipped", at = @At("HEAD"), cancellable = true) + private void hasSaddleEquipped(CallbackInfoReturnable info) { EventEntityControl event = new EventEntityControl(); BleachHack.eventBus.post(event); @@ -41,4 +35,4 @@ private void isSaddled(CallbackInfoReturnable info) { info.setReturnValue(event.canBeControlled()); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/bleachhack/mixin/MixinPacketByteBuf.java b/src/main/java/org/bleachhack/mixin/MixinPacketByteBuf.java index 91a3a2762b..3daba32e68 100644 --- a/src/main/java/org/bleachhack/mixin/MixinPacketByteBuf.java +++ b/src/main/java/org/bleachhack/mixin/MixinPacketByteBuf.java @@ -6,14 +6,19 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; -import net.minecraft.nbt.NbtTagSizeTracker; +import net.minecraft.nbt.NbtSizeTracker; import net.minecraft.network.PacketByteBuf; @Mixin(PacketByteBuf.class) public class MixinPacketByteBuf { - @ModifyArg(method = "readNbt", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketByteBuf;readNbt(Lnet/minecraft/nbt/NbtTagSizeTracker;)Lnet/minecraft/nbt/NbtCompound;")) - private NbtTagSizeTracker increaseLimit(NbtTagSizeTracker in) { - return ModuleManager.getModule(AntiChunkBan.class).isEnabled() ? NbtTagSizeTracker.EMPTY : in; + // readNbt() -> readNbt(ByteBuf) -> readNbt(ByteBuf, NbtSizeTracker.forPacket()) - the no-arg + // instance method used to call the NbtSizeTracker-taking overload directly, but it now goes + // through the static readNbt(ByteBuf) first, which is where the (now hardcoded) size tracker + // argument is actually passed, so that's the real interception point. + @ModifyArg(method = "readNbt(Lio/netty/buffer/ByteBuf;)Lnet/minecraft/nbt/NbtCompound;", + at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketByteBuf;readNbt(Lio/netty/buffer/ByteBuf;Lnet/minecraft/nbt/NbtSizeTracker;)Lnet/minecraft/nbt/NbtElement;")) + private static NbtSizeTracker increaseLimit(NbtSizeTracker in) { + return ModuleManager.getModule(AntiChunkBan.class).isEnabled() ? NbtSizeTracker.ofUnlimitedBytes() : in; } } diff --git a/src/main/java/org/bleachhack/mixin/MixinPacketInflater.java b/src/main/java/org/bleachhack/mixin/MixinPacketInflater.java index 71f1de4aa8..317c6689cc 100644 --- a/src/main/java/org/bleachhack/mixin/MixinPacketInflater.java +++ b/src/main/java/org/bleachhack/mixin/MixinPacketInflater.java @@ -16,7 +16,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.DecoderException; import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketInflater; +import net.minecraft.network.handler.PacketInflater; @Mixin(PacketInflater.class) public class MixinPacketInflater { diff --git a/src/main/java/org/bleachhack/mixin/MixinPlayerEntity.java b/src/main/java/org/bleachhack/mixin/MixinPlayerEntity.java index c85529d855..f45177dae3 100644 --- a/src/main/java/org/bleachhack/mixin/MixinPlayerEntity.java +++ b/src/main/java/org/bleachhack/mixin/MixinPlayerEntity.java @@ -9,6 +9,8 @@ package org.bleachhack.mixin; import net.minecraft.registry.tag.FluidTags; +import org.bleachhack.BleachHack; +import org.bleachhack.event.events.EventReach; import org.bleachhack.module.Module; import org.bleachhack.module.ModuleManager; import org.bleachhack.module.mods.SpeedMine; @@ -19,14 +21,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.block.BlockState; -import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.effect.StatusEffectUtil; import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.ItemStack; import net.minecraft.world.World; @Mixin(PlayerEntity.class) @@ -38,18 +39,19 @@ private MixinPlayerEntity(EntityType entityType, World w super(entityType, world); } + // 1.19.4 read the Efficiency/AquaAffinity enchantments directly via EnchantmentHelper - both are + // gone (enchantments are data-component-driven now) and their effects are pre-baked into two + // generic attributes (MINING_EFFICIENCY, SUBMERGED_MINING_SPEED) instead. This is a straight port + // of PlayerEntity's real 1.21.11 getBlockBreakingSpeed body with BleachHack's toggle overrides + // re-inserted at the same points as 1.19.4. @Inject(method = "getBlockBreakingSpeed", at = @At("HEAD"), cancellable = true) private void getBlockBreakingSpeed(BlockState block, CallbackInfoReturnable ci) { Module speedMine = ModuleManager.getModule(SpeedMine.class); if (speedMine.isEnabled()) { - float breakingSpeed = inventory.getBlockBreakingSpeed(block); + float breakingSpeed = this.inventory.getSelectedStack().getMiningSpeedMultiplier(block); if (breakingSpeed > 1.0F) { - int eff = EnchantmentHelper.getEfficiency(this); - ItemStack itemStack_1 = this.getMainHandStack(); - if (eff > 0 && !itemStack_1.isEmpty()) { - breakingSpeed += eff * eff + 1; - } + breakingSpeed += (float) this.getAttributeValue(EntityAttributes.MINING_EFFICIENCY); } if (StatusEffectUtil.hasHaste(this)) { @@ -78,12 +80,14 @@ private void getBlockBreakingSpeed(BlockState block, CallbackInfoReturnable ci) { + EventReach event = new EventReach((float) (double) ci.getReturnValueD()); + BleachHack.eventBus.post(event); + ci.setReturnValue((double) event.getReach()); + } + + @Inject(method = "getEntityInteractionRange", at = @At("RETURN"), cancellable = true) + private void getEntityInteractionRange(CallbackInfoReturnable ci) { + EventReach event = new EventReach((float) (double) ci.getReturnValueD()); + BleachHack.eventBus.post(event); + ci.setReturnValue((double) event.getReach()); + } } diff --git a/src/main/java/org/bleachhack/mixin/MixinPlayerListHud.java b/src/main/java/org/bleachhack/mixin/MixinPlayerListHud.java index b7dab095a0..90a122cae8 100644 --- a/src/main/java/org/bleachhack/mixin/MixinPlayerListHud.java +++ b/src/main/java/org/bleachhack/mixin/MixinPlayerListHud.java @@ -24,7 +24,7 @@ public class MixinPlayerListHud { @Inject(method = "getPlayerName", at = @At("RETURN"), cancellable = true) private void getPlayerName(PlayerListEntry entry, CallbackInfoReturnable callback) { - if (Option.PLAYERLIST_SHOW_FRIENDS.getValue() && BleachHack.friendMang.has(entry.getProfile().getName())) { + if (Option.PLAYERLIST_SHOW_FRIENDS.getValue() && BleachHack.friendMang.has(entry.getProfile().name())) { callback.setReturnValue(((MutableText) callback.getReturnValue()).styled(s -> s.withColor(Formatting.AQUA))); } } diff --git a/src/main/java/org/bleachhack/mixin/MixinRenderLayers.java b/src/main/java/org/bleachhack/mixin/MixinRenderLayers.java index 0b2ef6128e..1ba348fd3b 100644 --- a/src/main/java/org/bleachhack/mixin/MixinRenderLayers.java +++ b/src/main/java/org/bleachhack/mixin/MixinRenderLayers.java @@ -1,8 +1,8 @@ package org.bleachhack.mixin; import net.minecraft.block.BlockState; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.BlockRenderLayer; +import net.minecraft.client.render.BlockRenderLayers; import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventRenderBlock; @@ -11,11 +11,15 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(RenderLayers.class) +// 1.21.11 split block-layer resolution into a lightweight BlockRenderLayers/BlockRenderLayer enum used +// specifically by chunk section building (see MixinChunkRebuildTask), separate from the old +// RenderLayers.getBlockLayer(...) -> full RenderLayer used elsewhere. The actual chunk-render call site +// Xray needs to override moved to BlockRenderLayers, so the hook moved with it. +@Mixin(BlockRenderLayers.class) public class MixinRenderLayers { @Inject(method = "getBlockLayer", at = @At("HEAD"), cancellable = true) - private static void getBlockLayer(BlockState state, CallbackInfoReturnable callback) { + private static void getBlockLayer(BlockState state, CallbackInfoReturnable callback) { EventRenderBlock.Layer event = new EventRenderBlock.Layer(state); BleachHack.eventBus.post(event); diff --git a/src/main/java/org/bleachhack/mixin/MixinRenderTickCounter.java b/src/main/java/org/bleachhack/mixin/MixinRenderTickCounter.java index 1501589c0b..a096249c4e 100644 --- a/src/main/java/org/bleachhack/mixin/MixinRenderTickCounter.java +++ b/src/main/java/org/bleachhack/mixin/MixinRenderTickCounter.java @@ -18,23 +18,25 @@ import net.minecraft.client.render.RenderTickCounter; -@Mixin(RenderTickCounter.class) +// 1.21.11 turned RenderTickCounter into an interface; the fields this mixin needs (renamed too) now +// live on its actual implementation, RenderTickCounter$Dynamic, so the mixin target moved there. +@Mixin(RenderTickCounter.Dynamic.class) public class MixinRenderTickCounter { - @Shadow private float lastFrameDuration; - @Shadow private float tickDelta; - @Shadow private long prevTimeMillis; + @Shadow private float dynamicDeltaTicks; + @Shadow private float tickProgress; + @Shadow private long lastTimeMillis; @Shadow private float tickTime; - @Inject(method = "beginRenderTick", at = @At("HEAD"), cancellable = true) + @Inject(method = "beginRenderTick(J)I", at = @At("HEAD"), cancellable = true) private void beginRenderTick(long timeMillis, CallbackInfoReturnable ci) { if (ModuleManager.getModule(Timer.class).isEnabled()) { - this.lastFrameDuration = (float) (((timeMillis - this.prevTimeMillis) / this.tickTime) + this.dynamicDeltaTicks = (float) (((timeMillis - this.lastTimeMillis) / this.tickTime) * ModuleManager.getModule(Timer.class).getSetting(0).asSlider().getValue()); - this.prevTimeMillis = timeMillis; - this.tickDelta += this.lastFrameDuration; - int i = (int) this.tickDelta; - this.tickDelta -= i; + this.lastTimeMillis = timeMillis; + this.tickProgress += this.dynamicDeltaTicks; + int i = (int) this.tickProgress; + this.tickProgress -= i; ci.setReturnValue(i); } diff --git a/src/main/java/org/bleachhack/mixin/MixinScreen.java b/src/main/java/org/bleachhack/mixin/MixinScreen.java index a4ad9aa8e2..7e5389fd40 100644 --- a/src/main/java/org/bleachhack/mixin/MixinScreen.java +++ b/src/main/java/org/bleachhack/mixin/MixinScreen.java @@ -8,61 +8,26 @@ */ package org.bleachhack.mixin; -import java.util.List; - -import net.minecraft.client.gui.tooltip.TooltipPositioner; +import net.minecraft.client.gui.DrawContext; import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventRenderScreenBackground; -import org.bleachhack.event.events.EventRenderTooltip; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.tooltip.TooltipComponent; -import net.minecraft.client.util.math.MatrixStack; @Mixin(Screen.class) public class MixinScreen { - @Unique private int lastMX; - @Unique private int lastMY; - - @Unique private boolean skipTooltip; - - @Shadow private void renderTooltipFromComponents(MatrixStack matrices, List components, int x, int y, TooltipPositioner positioner) {} - - @Inject(method = "render", at = @At("HEAD")) - private void render(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo callback) { - lastMX = mouseX; - lastMY = mouseY; - } - - @Inject(method = "renderTooltipFromComponents", at = @At("HEAD"), cancellable = true) - private void renderTooltipFromComponents(MatrixStack matrices, List components, int x, int y, TooltipPositioner positioner, CallbackInfo callback) { - if (skipTooltip) { - skipTooltip = false; - return; - } - - EventRenderTooltip event = new EventRenderTooltip((Screen) (Object) this, matrices, components, x, y, lastMX, lastMY); - BleachHack.eventBus.post(event); - - callback.cancel(); - if (event.isCancelled()) { - return; - } - - skipTooltip = true; - renderTooltipFromComponents(event.getMatrix(), event.getComponents(), event.getX(), event.getY(), positioner); - } + // Tooltip rendering (renderTooltipFromComponents) moved to MixinDrawContext - 1.21.11 moved the + // actual draw call from Screen into DrawContext.drawTooltipImmediately, deferred via + // DrawContext.drawDeferredElements() instead of being called straight from Screen#render. - @Inject(method = "renderBackground(Lnet/minecraft/client/util/math/MatrixStack;)V", at = @At("HEAD"), cancellable = true) - private void renderBackground(MatrixStack matrices, CallbackInfo callback) { - EventRenderScreenBackground event = new EventRenderScreenBackground(matrices); + @Inject(method = "renderBackground(Lnet/minecraft/client/gui/DrawContext;IIF)V", at = @At("HEAD"), cancellable = true) + private void renderBackground(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo callback) { + EventRenderScreenBackground event = new EventRenderScreenBackground(context); BleachHack.eventBus.post(event); if (event.isCancelled()) { diff --git a/src/main/java/org/bleachhack/mixin/MixinShader.java b/src/main/java/org/bleachhack/mixin/MixinShader.java deleted file mode 100644 index 609e432138..0000000000 --- a/src/main/java/org/bleachhack/mixin/MixinShader.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). - * Copyright (c) 2021 Bleach and contributors. - * - * This source code is subject to the terms of the GNU General Public - * License, version 3. If a copy of the GPL was not distributed with this - * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt - */ -package org.bleachhack.mixin; - -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.gl.ShaderStage; -import org.spongepowered.asm.mixin.Final; -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.ModifyArg; -import org.spongepowered.asm.mixin.injection.ModifyArgs; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.Redirect; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.resource.ResourceFactory; -import net.minecraft.util.Identifier; - -import org.spongepowered.asm.mixin.injection.invoke.arg.Args; - -// Tweaks to the shader class to make it compatible with OpenResourceManager -@Mixin(value = ShaderProgram.class, priority = 1100) -public class MixinShader { - - @Shadow @Final private String name; - - @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Identifier;(Ljava/lang/String;)V"), allow = 1) - private String modifyProgramId(String id) { - return replaceIdentifier(id, name); - } - - @ModifyVariable(method = "loadShader", at = @At("STORE"), ordinal = 1) - private static String modifyStageId(String id, ResourceFactory factory, ShaderStage.Type type, String name) { - return replaceIdentifier(id, name); - } - - private static String replaceIdentifier(String id, String name) { - String[] split = name.split(":"); - if (split.length > 1 && id.indexOf('/') < id.indexOf(':')) { - if ("__url__".equals(split[0])) - return name; - - return split[0] + ":" + id.replace(name, split[1]); - } - - return id; - } -} diff --git a/src/main/java/org/bleachhack/mixin/MixinSkyRendering.java b/src/main/java/org/bleachhack/mixin/MixinSkyRendering.java new file mode 100644 index 0000000000..94e7448d8c --- /dev/null +++ b/src/main/java/org/bleachhack/mixin/MixinSkyRendering.java @@ -0,0 +1,51 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.mixin; + +import org.bleachhack.module.ModuleManager; +import org.bleachhack.module.mods.Ambience; +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 net.minecraft.client.render.Camera; +import net.minecraft.client.render.SkyRendering; +import net.minecraft.client.render.state.SkyRenderState; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.world.dimension.DimensionType; + +// 1.21.11 replaced the old DimensionEffects.getSkyColor() override point with a generic +// EnvironmentAttributes system read once per frame in SkyRendering.updateRenderState() - this is +// the one place that value ends up, so overwriting it here after the vanilla computation is +// simpler than modeling Ambience's override as another attribute source. +@Mixin(SkyRendering.class) +public class MixinSkyRendering { + + @Inject(method = "updateRenderState", at = @At("TAIL")) + private void updateRenderState(ClientWorld world, float tickProgress, Camera camera, SkyRenderState state, CallbackInfo info) { + Ambience ambience = ModuleManager.getModule(Ambience.class); + if (!ambience.isEnabled()) { + return; + } + + // End Skybox wins over Sky Color - Ambience.getSkyColorOverride() already returns null while + // it's active, since the End's own skybox rendering doesn't read skyColor at all. + DimensionType.Skybox skybox = ambience.getSkyboxOverride(); + if (skybox != null) { + state.skybox = skybox; + return; + } + + Integer color = ambience.getSkyColorOverride(); + if (color != null) { + state.skyColor = color; + } + } +} diff --git a/src/main/java/org/bleachhack/mixin/MixinSoundSystem.java b/src/main/java/org/bleachhack/mixin/MixinSoundSystem.java index 0c11d5e2b3..0cfa3131a6 100644 --- a/src/main/java/org/bleachhack/mixin/MixinSoundSystem.java +++ b/src/main/java/org/bleachhack/mixin/MixinSoundSystem.java @@ -14,6 +14,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.sound.Sound; import net.minecraft.client.sound.SoundInstance; @@ -23,13 +24,14 @@ @Mixin(SoundSystem.class) public class MixinSoundSystem { - @Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true) - private void play(SoundInstance soundInstance, CallbackInfo ci) { + // play(SoundInstance) now returns a SoundSystem.PlayResult instead of void. + @Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)Lnet/minecraft/client/sound/SoundSystem$PlayResult;", at = @At("HEAD"), cancellable = true) + private void play(SoundInstance soundInstance, CallbackInfoReturnable ci) { EventSoundPlay.Normal event = new EventSoundPlay.Normal(soundInstance); BleachHack.eventBus.post(event); if (event.isCancelled()) { - ci.cancel(); + ci.setReturnValue(SoundSystem.PlayResult.NOT_STARTED); } } diff --git a/src/main/java/org/bleachhack/mixin/MixinStatusEffectFogModifier.java b/src/main/java/org/bleachhack/mixin/MixinStatusEffectFogModifier.java new file mode 100644 index 0000000000..4ae84919a2 --- /dev/null +++ b/src/main/java/org/bleachhack/mixin/MixinStatusEffectFogModifier.java @@ -0,0 +1,38 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.mixin; + +import org.bleachhack.module.ModuleManager; +import org.bleachhack.module.mods.NoRender; +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.CallbackInfoReturnable; + +import net.minecraft.block.enums.CameraSubmersionType; +import net.minecraft.client.render.fog.StatusEffectFogModifier; +import net.minecraft.entity.Entity; +import net.minecraft.entity.effect.StatusEffects; + +// 1.21.11 removed BackgroundRenderer entirely and split fog application into per-effect FogModifier +// classes (net.minecraft.client.render.fog). The blindness "should this fog apply" check that used to +// live inline in BackgroundRenderer now lives in StatusEffectFogModifier.shouldApply, shared by every +// status-effect-driven fog modifier (blindness, darkness, ...) - only suppress it for blindness itself. +@Mixin(StatusEffectFogModifier.class) +public class MixinStatusEffectFogModifier { + + @Inject(method = "shouldApply", at = @At("HEAD"), cancellable = true) + private void shouldApply(CameraSubmersionType submersionType, Entity entity, CallbackInfoReturnable cir) { + StatusEffectFogModifier self = (StatusEffectFogModifier) (Object) this; + + if (self.getStatusEffect() == StatusEffects.BLINDNESS && ModuleManager.getModule(NoRender.class).isOverlayToggled(0)) { + cir.setReturnValue(false); + } + } +} diff --git a/src/main/java/org/bleachhack/mixin/MixinSharedConstants.java b/src/main/java/org/bleachhack/mixin/MixinStringHelper.java similarity index 70% rename from src/main/java/org/bleachhack/mixin/MixinSharedConstants.java rename to src/main/java/org/bleachhack/mixin/MixinStringHelper.java index 4ea6cdaef9..364c33f849 100644 --- a/src/main/java/org/bleachhack/mixin/MixinSharedConstants.java +++ b/src/main/java/org/bleachhack/mixin/MixinStringHelper.java @@ -14,13 +14,16 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; -import net.minecraft.SharedConstants; +import net.minecraft.util.StringHelper; -@Mixin(SharedConstants.class) -public class MixinSharedConstants { +// isValidChar moved from SharedConstants to StringHelper in 1.21.11 (and its param went from char to +// an int codepoint, since typed-character input is now represented as a codepoint via CharInput - +// see CharInput#isValidChar, which delegates straight into this method). +@Mixin(StringHelper.class) +public class MixinStringHelper { @Overwrite - public static boolean isValidChar(char chr) { + public static boolean isValidChar(int chr) { Module noKeyBlock = ModuleManager.getModule(NoKeyBlock.class); if (!noKeyBlock.isEnabled()) { diff --git a/src/main/java/org/bleachhack/mixin/MixinTitleScreen.java b/src/main/java/org/bleachhack/mixin/MixinTitleScreen.java index 6ed98f6aea..4a53284222 100644 --- a/src/main/java/org/bleachhack/mixin/MixinTitleScreen.java +++ b/src/main/java/org/bleachhack/mixin/MixinTitleScreen.java @@ -14,6 +14,7 @@ import org.bleachhack.gui.BleachCreditsScreen; import org.bleachhack.gui.BleachOptionsScreen; import org.bleachhack.gui.BleachTitleScreen; +import org.bleachhack.gui.FriendManagerScreen; import org.bleachhack.gui.UpdateScreen; import org.bleachhack.gui.clickgui.ModuleClickGuiScreen; import org.bleachhack.gui.window.WindowManagerScreen; @@ -31,6 +32,7 @@ import com.google.gson.JsonPrimitive; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.input.KeyInput; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.client.gui.widget.ButtonWidget; @@ -68,14 +70,15 @@ private void init(CallbackInfo info) { Triple.of(new AccountManagerScreen(), "Accounts", new ItemStack(Items.PAPER)), Triple.of(ModuleClickGuiScreen.INSTANCE, "ClickGui", new ItemStack(Items.TOTEM_OF_UNDYING)), Triple.of(new BleachOptionsScreen(null), "Options", new ItemStack(Items.REDSTONE)), + Triple.of(new FriendManagerScreen(), "Friends", new ItemStack(Items.PLAYER_HEAD)), Triple.of(new BleachCreditsScreen(), "Credits", new ItemStack(Items.DRAGON_HEAD))) { - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == ModuleManager.getModule(ClickGui.class).getKey()) { + public boolean keyPressed(KeyInput input) { + if (input.key() == ModuleManager.getModule(ClickGui.class).getKey()) { selectWindow(2); } - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(input); } }); } else { diff --git a/src/main/java/org/bleachhack/mixin/MixinWorldRenderer.java b/src/main/java/org/bleachhack/mixin/MixinWorldRenderer.java index b407c270c0..ced317bf59 100644 --- a/src/main/java/org/bleachhack/mixin/MixinWorldRenderer.java +++ b/src/main/java/org/bleachhack/mixin/MixinWorldRenderer.java @@ -8,46 +8,46 @@ */ package org.bleachhack.mixin; -import net.fabricmc.loader.api.FabricLoader; import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventBlockEntityRender; import org.bleachhack.event.events.EventEntityRender; import org.bleachhack.event.events.EventRenderBlockOutline; -import org.bleachhack.event.events.EventSkyRender; import org.bleachhack.event.events.EventWorldRender; -import org.bleachhack.util.BleachLogger; -import org.joml.Matrix4f; -import org.lwjgl.opengl.GL11; +import org.bleachhack.util.render.FrustumUtils; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gl.Framebuffer; import net.minecraft.client.render.Camera; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.LightmapTextureManager; +import net.minecraft.client.render.Frustum; +import net.minecraft.client.render.RenderTickCounter; import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.EntityRenderManager; +import net.minecraft.client.render.state.OutlineRenderState; +import net.minecraft.client.render.state.WorldRenderState; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.memory.ObjectAllocator; import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.profiler.Profiler; +import org.joml.Matrix4f; +import org.joml.Vector4f; @Mixin(WorldRenderer.class) public class MixinWorldRenderer { - @Shadow private void drawBlockOutline(MatrixStack matrices, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos blockPos, BlockState blockState) {} + @Shadow private void drawBlockOutline(MatrixStack matrices, VertexConsumer vertexConsumer, double x, double y, double z, + OutlineRenderState state, int color, float lineWidth) {} - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V")) + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V"), require = 0) private void render_swap(Profiler profiler, String string) { profiler.swap(string); @@ -62,9 +62,10 @@ private void render_swap(Profiler profiler, String string) { } @Inject(method = "render", at = @At("HEAD"), cancellable = true) - private void render_head(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, - LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo callback) { - EventWorldRender.Pre event = new EventWorldRender.Pre(tickDelta, matrices); + private void render_head(ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, + Matrix4f positionMatrix, Matrix4f basicProjectionMatrix, Matrix4f projectionMatrix, GpuBufferSlice fogBuffer, Vector4f fogColor, + boolean renderSky, CallbackInfo callback) { + EventWorldRender.Pre event = new EventWorldRender.Pre(tickCounter.getTickProgress(false)); BleachHack.eventBus.post(event); if (event.isCancelled()) { @@ -73,52 +74,44 @@ private void render_head(MatrixStack matrices, float tickDelta, long limitTime, } @Inject(method = "render", at = @At("RETURN")) - private void render_return(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, - LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo callback) { - RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, MinecraftClient.IS_SYSTEM_MAC); - EventWorldRender.Post event = new EventWorldRender.Post(tickDelta, matrices); - BleachHack.eventBus.post(event); + private void render_return(ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, + Matrix4f positionMatrix, Matrix4f basicProjectionMatrix, Matrix4f projectionMatrix, GpuBufferSlice fogBuffer, Vector4f fogColor, + boolean renderSky, CallbackInfo callback) { + // RenderSystem.clear(int, boolean) no longer exists - depth clearing now goes through the + // GPU command encoder directly. + Framebuffer framebuffer = MinecraftClient.getInstance().getFramebuffer(); + RenderSystem.getDevice().createCommandEncoder().clearDepthTexture(framebuffer.getDepthAttachment(), 1.0); + BleachHack.eventBus.post(new EventWorldRender.Post(tickCounter.getTickProgress(false))); } - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;drawBlockOutline(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;Lnet/minecraft/entity/Entity;DDDLnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V")) - private void render_drawBlockOutline(WorldRenderer worldRenderer, MatrixStack matrices, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos blockPos, BlockState blockState) { - EventRenderBlockOutline event = new EventRenderBlockOutline(matrices, vertexConsumer, blockPos, blockState); - BleachHack.eventBus.post(event); - - if (!event.isCancelled()) { - drawBlockOutline(event.getMatrices(), event.getVertexConsumer(), entity, d, e, f, event.getPos(), event.getState()); - } + @Inject(method = "fillEntityRenderStates", at = @At("HEAD")) + private void fillEntityRenderStates_head(Camera camera, Frustum frustum, RenderTickCounter tickCounter, WorldRenderState state, CallbackInfo callback) { + FrustumUtils.setCurrentFrustum(frustum); } - @Unique - private static boolean SODIUM_INSTALLED = FabricLoader.getInstance().isModLoaded("sodium"); + @Redirect(method = "fillEntityRenderStates", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/render/entity/EntityRenderManager;shouldRender(Lnet/minecraft/entity/Entity;Lnet/minecraft/client/render/Frustum;DDD)Z")) + private boolean fillEntityRenderStates_shouldRender(EntityRenderManager manager, E entity, Frustum frustum, double x, double y, double z) { + if (!manager.shouldRender(entity, frustum, x, y, z)) { + return false; + } - @Redirect(method = "renderEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/EntityRenderDispatcher;render(Lnet/minecraft/entity/Entity;DDDFFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V")) - private void renderEntity_render(EntityRenderDispatcher dispatcher, E entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) { - EventEntityRender.Single.Pre event = new EventEntityRender.Single.Pre(entity, matrices, vertexConsumers); + EventEntityRender.Single.Pre event = new EventEntityRender.Single.Pre(entity); BleachHack.eventBus.post(event); - if (!event.isCancelled()) { - try { - dispatcher.render(event.getEntity(), x, y, z, yaw, tickDelta, event.getMatrix(), SODIUM_INSTALLED ? vertexConsumers : event.getVertex(), light); - } catch (Exception e) { - BleachLogger.error("Disabling Entity Rendering Mixin, another mod conflicting?"); - e.printStackTrace(); - SODIUM_INSTALLED = true; - } - } + return !event.isCancelled(); } - @Redirect(method = "renderEndSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/VertexConsumer;color(IIII)Lnet/minecraft/client/render/VertexConsumer;")) - private VertexConsumer renderEndSky_color(VertexConsumer vertexConsumer, int red, int green, int blue, int alpha) { - EventSkyRender.Color.EndSkyColor event = new EventSkyRender.Color.EndSkyColor(1f); + @Redirect(method = "renderTargetBlockOutline", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/render/WorldRenderer;drawBlockOutline(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;DDDLnet/minecraft/client/render/state/OutlineRenderState;IF)V"), + require = 0) + private void render_drawBlockOutline(WorldRenderer worldRenderer, MatrixStack matrices, VertexConsumer vertexConsumer, double x, double y, double z, + OutlineRenderState state, int color, float lineWidth) { + EventRenderBlockOutline event = new EventRenderBlockOutline(matrices, vertexConsumer, state.pos()); BleachHack.eventBus.post(event); - if (event.getColor() != null) { - return vertexConsumer.color( - (int) (event.getColor().x * 255), (int) (event.getColor().y * 255), (int) (event.getColor().z * 255), (int) alpha); - } else { - return vertexConsumer.color(red, green, blue, alpha); + if (!event.isCancelled()) { + drawBlockOutline(event.getMatrices(), event.getVertexConsumer(), x, y, z, state, color, lineWidth); } } diff --git a/src/main/java/org/bleachhack/module/ModuleManager.java b/src/main/java/org/bleachhack/module/ModuleManager.java index dc11ef9a95..047809718e 100644 --- a/src/main/java/org/bleachhack/module/ModuleManager.java +++ b/src/main/java/org/bleachhack/module/ModuleManager.java @@ -81,7 +81,7 @@ public static List getModulesInCat(ModuleCategory cat) { } public static void handleKey(int key) { - if (!InputUtil.isKeyPressed(MinecraftClient.getInstance().getWindow().getHandle(), GLFW.GLFW_KEY_F3)) { + if (!InputUtil.isKeyPressed(MinecraftClient.getInstance().getWindow(), GLFW.GLFW_KEY_F3)) { for (Module m: getModules()) { if (m.getKey() == key) { m.toggle(); diff --git a/src/main/java/org/bleachhack/module/mods/AirPlace.java b/src/main/java/org/bleachhack/module/mods/AirPlace.java index 45bbd7736f..2af3ca321b 100644 --- a/src/main/java/org/bleachhack/module/mods/AirPlace.java +++ b/src/main/java/org/bleachhack/module/mods/AirPlace.java @@ -35,11 +35,21 @@ public class AirPlace extends Module { private boolean pressed; public AirPlace() { + this(new SettingMode("Render", "Box+Fill", "Box", "Fill").withDesc("The rendering method.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Render mode + // setting as a constructor parameter first lets the predicates below capture that local + // variable instead, even though it's nested inside Highlight's children. + private AirPlace(SettingMode renderMode) { super("AirPlace", KEY_UNBOUND, ModuleCategory.WORLD, "Allows you to place blocks in thin air.", new SettingToggle("Highlight", true).withDesc("Renders an overlay where it will place the block.").withChildren( - new SettingMode("Render", "Box+Fill", "Box", "Fill").withDesc("The rendering method."), - new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The width/thickness of the box lines."), - new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill."), + renderMode, + new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The width/thickness of the box lines.") + .visibleWhen(() -> renderMode.getMode() != 2), + new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill.") + .visibleWhen(() -> renderMode.getMode() != 1), new SettingColor("Color", 128, 128, 128).withDesc("The color of the highlight.")), new SettingMode("Mode", "Multi", "Single").withDesc("Whether to place a block once per click or multiple blocks if the button is held down.")); } @@ -91,6 +101,6 @@ public void onWorldRender(EventWorldRender.Post event) { private boolean canPlaceAtCrosshair() { return mc.crosshairTarget instanceof BlockHitResult - && mc.world.getBlockState(((BlockHitResult) mc.crosshairTarget).getBlockPos()).getMaterial().isReplaceable(); + && mc.world.getBlockState(((BlockHitResult) mc.crosshairTarget).getBlockPos()).isReplaceable(); } } diff --git a/src/main/java/org/bleachhack/module/mods/Ambience.java b/src/main/java/org/bleachhack/module/mods/Ambience.java index f460097273..a42bb0f46e 100644 --- a/src/main/java/org/bleachhack/module/mods/Ambience.java +++ b/src/main/java/org/bleachhack/module/mods/Ambience.java @@ -10,7 +10,6 @@ import org.bleachhack.event.events.EventBiomeColor; import org.bleachhack.event.events.EventPacket; -import org.bleachhack.event.events.EventSkyRender; import org.bleachhack.event.events.EventTick; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; @@ -20,22 +19,30 @@ import org.bleachhack.setting.module.SettingSlider; import org.bleachhack.setting.module.SettingToggle; -import net.minecraft.client.render.DimensionEffects; -import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; +import net.minecraft.network.packet.s2c.common.DisconnectS2CPacket; import net.minecraft.network.packet.s2c.play.GameStateChangeS2CPacket; import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; public class Ambience extends Module { private final WeatherManager weatherManager = new WeatherManager(); public Ambience() { + this(new SettingMode("Weather", "Clear", "Rain").withDesc("What weather to use.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Weather mode + // setting as a constructor parameter first lets the predicate below capture that local + // variable instead, even though it's nested inside Weather's children. + private Ambience(SettingMode weatherMode) { super("Ambience", KEY_UNBOUND, ModuleCategory.WORLD, "Changes the world ambience.", new SettingToggle("Weather", true).withDesc("Changes the world weather.").withChildren( - new SettingMode("Weather", "Clear", "Rain").withDesc("What weather to use."), - new SettingSlider("Rain", 0, 2, 0, 2).withDesc("How much it should rain in rain mode.")), + weatherMode, + new SettingSlider("Rain", 0, 2, 0, 2).withDesc("How much it should rain in rain mode.") + .visibleWhen(() -> weatherMode.getMode() == 1)), new SettingToggle("Time", false).withDesc("Changes the world time.").withChildren( new SettingSlider("Time", 0, 24000, 12500, 0).withDesc("What time to set the world to.")), new SettingToggle("Overworld", true).withDesc("Changes the overworld ambience-").withChildren( @@ -64,10 +71,26 @@ public Ambience() { new SettingColor("Color", 128, 255, 128).withDesc("The color of the water.")))); } + @Override + public void onEnable(boolean inWorld) { + super.onEnable(inWorld); + + if (inWorld) { + // Grass/foliage/water color are baked into each chunk's mesh at build time, not looked + // up live every frame - already-built chunks keep whatever color they had before this + // toggled on until something rebuilds them, which makes the override look like it only + // works in "some" chunks (whichever happen to rebuild afterward). Forcing every loaded + // chunk to rebuild now makes it apply everywhere immediately, matching Xray's onEnable. + mc.worldRenderer.reload(); + } + } + @Override public void onDisable(boolean inWorld) { - if (inWorld) + if (inWorld) { weatherManager.applyWeather(mc.world); + mc.worldRenderer.reload(); + } weatherManager.reset(); @@ -78,8 +101,8 @@ public void onDisable(boolean inWorld) { public void onTick(EventTick event) { if (getSetting(0).asToggle().getState()) { if (!weatherManager.isActive()) { - weatherManager.setRain(mc.world.getRainGradient(mc.getTickDelta())); - weatherManager.setThunder(mc.world.getThunderGradient(mc.getTickDelta())); + weatherManager.setRain(mc.world.getRainGradient(mc.getRenderTickCounter().getTickProgress(true))); + weatherManager.setThunder(mc.world.getThunderGradient(mc.getRenderTickCounter().getTickProgress(true))); } if (getSetting(0).asToggle().getChild(0).asMode().getMode() == 0) { @@ -95,7 +118,7 @@ public void onTick(EventTick event) { } if (getSetting(1).asToggle().getState()) { - mc.world.setTimeOfDay(getSetting(1).asToggle().getChild(0).asSlider().getValueLong()); + mc.world.getLevelProperties().setTimeOfDay(getSetting(1).asToggle().getChild(0).asSlider().getValueLong()); } } @@ -132,37 +155,49 @@ public void onBiomeColor(EventBiomeColor event) { } } - @BleachSubscribe - public void onSkyColor(EventSkyRender.Color event) { - if (getCurrentDimSetting().getState() && getCurrentDimSetting().getChild(0).asToggle().getState()) { - int[] color = getCurrentDimSetting().getChild(0).asToggle().getChild(1).asColor().getRGBArray(); - event.setColor(new Vec3d(color[0] / 255d, color[1] / 255d, color[2] / 255d)); - } + // 1.21.11 replaced the old per-property DimensionEffects subclassing model (getSkyColor/ + // getCloudsColor/getDimensionEffects/getFogColorOverride) with a generic, position/biome-weighted + // EnvironmentAttributes system (World.getEnvironmentAttributes().getAttributeValue(...)). The old + // ClientWorld/DimensionEffects mixins that fired these hooks had to be removed since their target + // methods no longer exist. Sky color and skybox choice are now overridden directly at render time + // instead, from MixinSkyRendering (see getSkyColorOverride()/getSkyboxOverride()) rather than + // through the attribute system itself - SkyRendering.updateRenderState() is the single place that + // reads SKY_COLOR_VISUAL and the dimension's skybox type into the render state, so overwriting + // them there after the fact is simpler than modeling our override as another + // EnvironmentAttributeFunction. End Skybox forces DimensionType.Skybox.END regardless of the + // current dimension and disables the Sky Color override while active, since the End's own skybox + // rendering doesn't use skyColor at all. + + private SettingToggle getCurrentDimSetting() { + return getSetting(mc.world.getRegistryKey() == World.END ? 4 : mc.world.getRegistryKey() == World.NETHER ? 3 : 2).asToggle(); } - @BleachSubscribe - public void onSkyProperties(EventSkyRender.Properties event) { - if (getCurrentDimSetting().getState() && getCurrentDimSetting().getChild(0).asToggle().getState() - && getCurrentDimSetting().getChild(0).asToggle().getChild(0).asToggle().getState()) { - event.setSky(new DimensionEffects(event.getSky().getCloudsHeight(), false, DimensionEffects.SkyType.END, true, false) { - - public Vec3d adjustFogColor(Vec3d color, float sunHeight) { - return color.multiply(0.15000000596046448D); - } - - public boolean useThickFog(int camouseX, int camouseY) { - return false; - } - - public float[] getFogColorOverride(float skyAngle, float tickDelta) { - return null; - } - }); + // Used by MixinSkyRendering; null means "don't override". + public Integer getSkyColorOverride() { + if (mc.world == null || isEndSkyboxActive()) { + return null; + } + + SettingToggle skyColor = getCurrentDimSetting().getChild(0).asToggle(); + if (!getCurrentDimSetting().getState() || !skyColor.getState()) { + return null; } + + return skyColor.getChild(1).asColor().getRGB(); } - private SettingToggle getCurrentDimSetting() { - return getSetting(mc.world.getRegistryKey() == World.END ? 4 : mc.world.getRegistryKey() == World.NETHER ? 3 : 2).asToggle(); + // Used by MixinSkyRendering; null means "don't override". + public DimensionType.Skybox getSkyboxOverride() { + return isEndSkyboxActive() ? DimensionType.Skybox.END : null; + } + + private boolean isEndSkyboxActive() { + if (mc.world == null) { + return false; + } + + SettingToggle skyColor = getCurrentDimSetting().getChild(0).asToggle(); + return getCurrentDimSetting().getState() && skyColor.getState() && skyColor.getChild(0).asToggle().getState(); } private static class WeatherManager { @@ -195,7 +230,7 @@ public void applyWeather(World world) { } public boolean isActive() { - return rain >= 0f || thunder >= 1f; + return rain >= 0f || thunder >= 0f; } } } diff --git a/src/main/java/org/bleachhack/module/mods/AntiHunger.java b/src/main/java/org/bleachhack/module/mods/AntiHunger.java index e38737726e..e6fb6d77e4 100644 --- a/src/main/java/org/bleachhack/module/mods/AntiHunger.java +++ b/src/main/java/org/bleachhack/module/mods/AntiHunger.java @@ -9,28 +9,80 @@ package org.bleachhack.module.mods; import org.bleachhack.event.events.EventPacket; +import org.bleachhack.event.events.EventSendMovementPackets; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; import org.bleachhack.module.ModuleCategory; +import org.bleachhack.setting.module.SettingMode; import org.bleachhack.setting.module.SettingToggle; +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; public class AntiHunger extends Module { + // legacy (pre-1.21.11 BleachHack) implementation state private boolean bool = false; + // meteor-style implementation state + private boolean lastOnGround = false; + private boolean ignorePacket = false; + public AntiHunger() { + this(new SettingMode("Mode", "Old", "New").withDesc("Old is the original 1.19.4 behavior, New is a Meteor-style implementation.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicates below capture that local variable instead. + private AntiHunger(SettingMode mode) { super("AntiHunger", KEY_UNBOUND, ModuleCategory.PLAYER, "Minimizes the amount of hunger you use (Also makes you slide).", - new SettingToggle("Relaxed", false).withDesc("Only activates every other ticks, might fix getting fly kicked.")); + mode, + new SettingToggle("Relaxed", false).withDesc("Only activates every other tick, might fix getting fly kicked.") + .visibleWhen(() -> mode.getMode() == 0), + new SettingToggle("Sprint Spoof", true).withDesc("Cancels sprint start packets.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("OnGround Spoof", true).withDesc("Spoofs the onGround flag while standing still on the ground.") + .visibleWhen(() -> mode.getMode() == 1)); + } + + @Override + public void onEnable(boolean inWorld) { + super.onEnable(inWorld); + bool = false; + ignorePacket = false; + + if (inWorld) { + lastOnGround = mc.player.isOnGround(); + } + } + + @BleachSubscribe + public void onSendMovementPackets(EventSendMovementPackets event) { + if (getSetting(0).asMode().getMode() != 1) { + return; + } + + if (mc.player.isOnGround() && !lastOnGround && getSetting(3).asToggle().getState()) { + // let one real packet through so landing still registers (keeps fall damage working) + ignorePacket = true; + } + + lastOnGround = mc.player.isOnGround(); } @BleachSubscribe public void onSendPacket(EventPacket.Send event) { + if (getSetting(0).asMode().getMode() == 1) { + onMeteorPacket(event); + } else { + onLegacyPacket(event); + } + } + + private void onLegacyPacket(EventPacket.Send event) { if (event.getPacket() instanceof PlayerMoveC2SPacket) { - if (mc.player.getVelocity().y != 0 && !mc.options.jumpKey.isPressed() && (!bool || !getSetting(0).asToggle().getState())) { - // if (((PlayerMoveC2SPacket) event.getPacket()).isOnGround()) - // event.setCancelled(true); + if (mc.player.getVelocity().y != 0 && !mc.options.jumpKey.isPressed() && (!bool || !getSetting(1).asToggle().getState())) { boolean onGround = mc.player.fallDistance >= 0.1f; mc.player.setOnGround(onGround); ((PlayerMoveC2SPacket) event.getPacket()).onGround = onGround; @@ -41,4 +93,26 @@ public void onSendPacket(EventPacket.Send event) { } } + private void onMeteorPacket(EventPacket.Send event) { + if (ignorePacket && event.getPacket() instanceof PlayerMoveC2SPacket) { + ignorePacket = false; + return; + } + + if (mc.player.hasVehicle() || mc.player.isTouchingWater() || mc.player.isSubmergedInWater()) { + return; + } + + if (event.getPacket() instanceof ClientCommandC2SPacket packet && getSetting(2).asToggle().getState()) { + if (packet.getMode() == ClientCommandC2SPacket.Mode.START_SPRINTING) { + event.setCancelled(true); + } + } + + if (event.getPacket() instanceof PlayerMoveC2SPacket packet && getSetting(3).asToggle().getState() + && mc.player.isOnGround() && mc.player.fallDistance <= 0.0 && !mc.interactionManager.isBreakingBlock()) { + packet.onGround = false; + } + } + } diff --git a/src/main/java/org/bleachhack/module/mods/AntiVoid.java b/src/main/java/org/bleachhack/module/mods/AntiVoid.java index dcd1803997..ef61fb65a3 100644 --- a/src/main/java/org/bleachhack/module/mods/AntiVoid.java +++ b/src/main/java/org/bleachhack/module/mods/AntiVoid.java @@ -40,7 +40,7 @@ public void onTick(EventTick event) { mc.player.setOnGround(true); break; case 2: - for (int i = mc.world.getBottomY() + 3; i < mc.world.getTopY() + 1; i++) { + for (int i = mc.world.getBottomY() + 3; i <= mc.world.getTopYInclusive() + 1; i++) { if (!WorldUtils.doesBoxCollide(mc.player.getBoundingBox().offset(0, -mc.player.getY() + i, 0))) { mc.player.updatePosition(mc.player.getX(), i, mc.player.getZ()); break; diff --git a/src/main/java/org/bleachhack/module/mods/ArrowJuke.java b/src/main/java/org/bleachhack/module/mods/ArrowJuke.java index b77160c74b..a91f306a26 100644 --- a/src/main/java/org/bleachhack/module/mods/ArrowJuke.java +++ b/src/main/java/org/bleachhack/module/mods/ArrowJuke.java @@ -74,7 +74,7 @@ public void onTick(EventTick envent) { } else { mc.player.updatePosition(mc.player.getX() + vel.x, mc.player.getY() + vel.y, mc.player.getZ() + vel.z); mc.player.networkHandler.sendPacket( - new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY(), mc.player.getZ(), false)); + new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY(), mc.player.getZ(), false, mc.player.horizontalCollision)); } return; diff --git a/src/main/java/org/bleachhack/module/mods/AutoArmor.java b/src/main/java/org/bleachhack/module/mods/AutoArmor.java index 689d7c7284..f471c12f03 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoArmor.java +++ b/src/main/java/org/bleachhack/module/mods/AutoArmor.java @@ -20,15 +20,16 @@ import org.bleachhack.setting.module.SettingToggle; import org.bleachhack.util.BleachQueue; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.EquippableComponent; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.enchantment.ProtectionEnchantment; +import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.EquipmentSlot; -import net.minecraft.item.ArmorItem; -import net.minecraft.item.ElytraItem; +import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.item.ToolItem; +import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; import net.minecraft.screen.slot.SlotActionType; @@ -76,9 +77,8 @@ public void onTick(EventTick event) { if (mc.player.getInventory().getStack(s).isEmpty()) { mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, armorSlot, 1, SlotActionType.QUICK_MOVE, mc.player); return; - } else if (!(mc.player.getInventory().getStack(s).getItem() instanceof ToolItem) - && !(mc.player.getInventory().getStack(s).getItem() instanceof ArmorItem) - && !(mc.player.getInventory().getStack(s).getItem() instanceof ElytraItem) + } else if (!mc.player.getInventory().getStack(s).contains(DataComponentTypes.TOOL) + && !mc.player.getInventory().getStack(s).contains(DataComponentTypes.EQUIPPABLE) && mc.player.getInventory().getStack(s).getItem() != Items.TOTEM_OF_UNDYING && forceMoveSlot == -1) { forceMoveSlot = s; } @@ -104,8 +104,8 @@ public void onTick(EventTick event) { int prot = getProtection(mc.player.getInventory().getStack(s)); if (prot > 0) { - EquipmentSlot slot = (mc.player.getInventory().getStack(s).getItem() instanceof ElytraItem - ? EquipmentSlot.CHEST : ((ArmorItem) mc.player.getInventory().getStack(s).getItem()).getSlotType()); + EquipmentSlot slot = mc.player.getInventory().getStack(s).isOf(Items.ELYTRA) + ? EquipmentSlot.CHEST : mc.player.getInventory().getStack(s).get(DataComponentTypes.EQUIPPABLE).slot(); for (Entry e: armorMap.entrySet()) { if (e.getKey() == slot) { @@ -121,8 +121,8 @@ public void onTick(EventTick event) { for (Entry e: armorMap.entrySet()) { if (e.getValue()[2] != -1) { if (e.getValue()[1] == -1 && e.getValue()[2] < 9) { - if (e.getValue()[2] != mc.player.getInventory().selectedSlot) { - mc.player.getInventory().selectedSlot = e.getValue()[2]; + if (e.getValue()[2] != mc.player.getInventory().getSelectedSlot()) { + mc.player.getInventory().setSelectedSlot(e.getValue()[2]); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(e.getValue()[2])); } @@ -145,11 +145,11 @@ public void onTick(EventTick event) { } private int getProtection(ItemStack is) { - if (is.getItem() instanceof ArmorItem || is.getItem() == Items.ELYTRA) { + if (is.contains(DataComponentTypes.EQUIPPABLE) || is.getItem() == Items.ELYTRA) { int prot = 0; - if (is.getItem() instanceof ElytraItem) { - if (!ElytraItem.isUsable(is)) + if (is.isOf(Items.ELYTRA)) { + if (is.getDamage() >= is.getMaxDamage() - 1) return 0; if (getSetting(1).asToggle().getState()) { @@ -162,13 +162,24 @@ private int getProtection(ItemStack is) { } if (is.hasEnchantments()) { - for (Entry e: EnchantmentHelper.get(is).entrySet()) { - if (e.getKey() instanceof ProtectionEnchantment) - prot += e.getValue(); + for (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry> e: EnchantmentHelper.getEnchantments(is).getEnchantmentEntries()) { + if (e.getKey().matchesKey(Enchantments.PROTECTION) || e.getKey().matchesKey(Enchantments.FIRE_PROTECTION) + || e.getKey().matchesKey(Enchantments.BLAST_PROTECTION) || e.getKey().matchesKey(Enchantments.PROJECTILE_PROTECTION) + || e.getKey().matchesKey(Enchantments.FEATHER_FALLING)) + prot += e.getIntValue(); } } - return (is.getItem() instanceof ArmorItem ? ((ArmorItem) is.getItem()).getProtection() : 0) + prot; + int[] baseArmor = { 0 }; + EquippableComponent equip = is.get(DataComponentTypes.EQUIPPABLE); + if (equip != null && equip.slot().isArmorSlot()) { + is.applyAttributeModifiers(equip.slot(), (attr, mod) -> { + if (attr.matches(EntityAttributes.ARMOR)) + baseArmor[0] = (int) mod.value(); + }); + } + + return baseArmor[0] + prot; } else if (!is.isEmpty()) { return 0; } diff --git a/src/main/java/org/bleachhack/module/mods/AutoBedrockBreak.java b/src/main/java/org/bleachhack/module/mods/AutoBedrockBreak.java index 21f5e591a6..423d7d5494 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoBedrockBreak.java +++ b/src/main/java/org/bleachhack/module/mods/AutoBedrockBreak.java @@ -51,7 +51,7 @@ public void onTick(EventTick event) { if (pos != null) { switch (step) { case 0: - if (!mc.world.isSpaceEmpty(new Box(pos.up(), pos.add(1, 8, 1)))) { + if (!mc.world.isSpaceEmpty(new Box(Vec3d.of(pos.up()), Vec3d.of(pos.add(1, 8, 1))))) { reset(); BleachLogger.info("Not enough empty space to break this block!"); } else if (InventoryUtils.getSlot(true, i -> mc.player.getInventory().getStack(i).getItem() == Items.PISTON) == -1) { @@ -72,7 +72,7 @@ public void onTick(EventTick event) { break; case 1: - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.Full(mc.player.getX(), mc.player.getY(), mc.player.getZ(), mc.player.getYaw(), 90, mc.player.isOnGround())); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.Full(mc.player.getX(), mc.player.getY(), mc.player.getZ(), mc.player.getYaw(), 90, mc.player.isOnGround(), mc.player.horizontalCollision)); // mc.player.setPitch(90) "its jank either way" step++; @@ -115,7 +115,7 @@ public void onTick(EventTick event) { } if (step >= 82) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.Full(mc.player.getX(), mc.player.getY(), mc.player.getZ(), mc.player.getYaw(), -90, mc.player.isOnGround())); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.Full(mc.player.getX(), mc.player.getY(), mc.player.getZ(), mc.player.getYaw(), -90, mc.player.isOnGround(), mc.player.horizontalCollision)); // mc.player.setPitch(-90) "its jank either way" } diff --git a/src/main/java/org/bleachhack/module/mods/AutoBuild.java b/src/main/java/org/bleachhack/module/mods/AutoBuild.java index d90bf23a2c..bb5f2698b5 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoBuild.java +++ b/src/main/java/org/bleachhack/module/mods/AutoBuild.java @@ -162,8 +162,8 @@ public void onDisable(boolean inWorld) { @BleachSubscribe public void onTick(EventTick event) { if (!active) { - ray = (BlockHitResult) mc.player.raycast(40, mc.getTickDelta(), false); - Direction dir = ray.getSide().getAxis() == Axis.Y ? Direction.fromRotation(mc.player.getYaw()) : ray.getSide(); + ray = (BlockHitResult) mc.player.raycast(40, mc.getRenderTickCounter().getTickProgress(true), false); + Direction dir = ray.getSide().getAxis() == Axis.Y ? Direction.fromHorizontalDegrees(mc.player.getYaw()) : ray.getSide(); current = OperationList.create(BLUEPRINTS.get(getSetting(0).asMode().getMode()), ray.getBlockPos().offset(ray.getSide()), dir); diff --git a/src/main/java/org/bleachhack/module/mods/AutoCraft.java b/src/main/java/org/bleachhack/module/mods/AutoCraft.java index 4d39c8336b..7d093f731a 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoCraft.java +++ b/src/main/java/org/bleachhack/module/mods/AutoCraft.java @@ -2,7 +2,6 @@ import java.util.List; -import net.minecraft.registry.DynamicRegistryManager; import org.bleachhack.event.events.EventTick; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; @@ -14,9 +13,12 @@ import net.minecraft.client.gui.screen.recipebook.RecipeResultCollection; import net.minecraft.item.Item; -import net.minecraft.recipe.Recipe; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.RecipeDisplayEntry; +import net.minecraft.recipe.display.SlotDisplayContexts; import net.minecraft.screen.CraftingScreenHandler; import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.util.context.ContextParameterMap; public class AutoCraft extends Module { @@ -67,10 +69,20 @@ public void onTick(EventTick event) { boolean craftAll = getSetting(1).asToggle().getState(); boolean drop = getSetting(2).asToggle().getState(); + ContextParameterMap context = SlotDisplayContexts.createParameters(mc.world); + for (RecipeResultCollection recipeResultCollection : recipeResultCollectionList) { - for (Recipe recipe : recipeResultCollection.getRecipes(true)) { - if (getSetting(0).asList(Item.class).contains(recipe.getOutput(DynamicRegistryManager.EMPTY).getItem())) { - mc.interactionManager.clickRecipe(currentScreenHandler.syncId, recipe, craftAll); + for (RecipeDisplayEntry recipe : recipeResultCollection.filter(RecipeResultCollection.RecipeFilterMode.CRAFTABLE)) { + boolean matches = false; + for (ItemStack stack : recipe.getStacks(context)) { + if (getSetting(0).asList(Item.class).contains(stack.getItem())) { + matches = true; + break; + } + } + + if (matches) { + mc.interactionManager.clickRecipe(currentScreenHandler.syncId, recipe.id(), craftAll); mc.interactionManager.clickSlot(currentScreenHandler.syncId, 0, 0, drop ? SlotActionType.THROW : SlotActionType.QUICK_MOVE, mc.player); diff --git a/src/main/java/org/bleachhack/module/mods/AutoEXP.java b/src/main/java/org/bleachhack/module/mods/AutoEXP.java index d355c9d0f3..9d9360ec97 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoEXP.java +++ b/src/main/java/org/bleachhack/module/mods/AutoEXP.java @@ -30,6 +30,7 @@ import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -92,8 +93,8 @@ public void onTick(EventTick event) { } if (slot >= 46) { - if (slot - 46 != mc.player.getInventory().selectedSlot) { - mc.player.getInventory().selectedSlot = slot - 46; + if (slot - 46 != mc.player.getInventory().getSelectedSlot()) { + mc.player.getInventory().setSelectedSlot(slot - 46); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(slot - 46)); } @@ -106,7 +107,7 @@ public void onTick(EventTick event) { } for (int i = 5; i <= 8; i++) { - if (i != slot && EnchantmentHelper.getLevel(Enchantments.MENDING, mc.player.currentScreenHandler.getSlot(i).getStack()) != 0) { + if (i != slot && EnchantmentHelper.getLevel(mc.world.getRegistryManager().getEntryOrThrow(Enchantments.MENDING), mc.player.currentScreenHandler.getSlot(i).getStack()) != 0) { for (int j = 1; j <= 4; j++) { ItemStack craftingStack = mc.player.currentScreenHandler.getSlot(j).getStack(); if (!craftingStack.isDamageable()) { @@ -122,8 +123,8 @@ public void onTick(EventTick event) { } if (slot > 8 && slot < 45) { - if (slot - 36 != mc.player.getInventory().selectedSlot) { - mc.player.getInventory().selectedSlot = slot - 36; + if (slot - 36 != mc.player.getInventory().getSelectedSlot()) { + mc.player.getInventory().setSelectedSlot(slot - 36); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(slot - 36)); } @@ -138,12 +139,14 @@ public void onTick(EventTick event) { int toThrow = Math.min(getSetting(5).asSlider().getValueInt(), xpNeeded); if (toThrow != 0) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.LookAndOnGround(mc.player.getYaw(), 90, mc.player.isOnGround())); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.LookAndOnGround(mc.player.getYaw(), 90, mc.player.isOnGround(), mc.player.horizontalCollision)); for (int t = 0; t < toThrow; t++) { if (InventoryUtils.selectSlot(false, i -> mc.player.getInventory().getStack(i).getItem() == Items.EXPERIENCE_BOTTLE) == Hand.MAIN_HAND) { // Trying to use without bruh - mc.player.networkHandler.sendPacket(new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0)); - ItemStack itemStack2 = mc.player.getMainHandStack().use(mc.world, mc.player, Hand.MAIN_HAND).getValue(); + mc.player.networkHandler.sendPacket(new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, mc.player.getYaw(), mc.player.getPitch())); + ActionResult useResult = mc.player.getMainHandStack().use(mc.world, mc.player, Hand.MAIN_HAND); + ItemStack itemStack2 = useResult instanceof ActionResult.Success success && success.getNewHandStack() != null + ? success.getNewHandStack() : mc.player.getMainHandStack(); if (itemStack2 != mc.player.getMainHandStack()) { mc.player.setStackInHand(Hand.MAIN_HAND, itemStack2); } @@ -166,7 +169,7 @@ public void onTick(EventTick event) { } if (getSetting(1).asToggle().getState()) - slots.add(36 + mc.player.getInventory().selectedSlot); + slots.add(36 + mc.player.getInventory().getSelectedSlot()); if (getSetting(2).asToggle().getState()) slots.add(45); diff --git a/src/main/java/org/bleachhack/module/mods/AutoEat.java b/src/main/java/org/bleachhack/module/mods/AutoEat.java index c11fa166f7..50824efe8f 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoEat.java +++ b/src/main/java/org/bleachhack/module/mods/AutoEat.java @@ -16,9 +16,13 @@ import org.bleachhack.setting.module.SettingToggle; import org.bleachhack.util.InventoryUtils; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ConsumableComponent; +import net.minecraft.component.type.FoodComponent; +import net.minecraft.component.type.FoodComponents; import net.minecraft.entity.effect.StatusEffectCategory; -import net.minecraft.item.FoodComponent; -import net.minecraft.item.FoodComponents; +import net.minecraft.item.ItemStack; +import net.minecraft.item.consume.ApplyEffectsConsumeEffect; import net.minecraft.util.Hand; public class AutoEat extends Module { @@ -67,18 +71,19 @@ private void startEating() { int slot = -1; int hunger = -1; for (int s: InventoryUtils.getInventorySlots(true)) { - FoodComponent food = mc.player.getInventory().getStack(s).getItem().getFoodComponent(); + ItemStack stack = mc.player.getInventory().getStack(s); + FoodComponent food = stack.get(DataComponentTypes.FOOD); if (food == null) continue; int h = preferGapples && (food == FoodComponents.GOLDEN_APPLE || food == FoodComponents.ENCHANTED_GOLDEN_APPLE) - ? Integer.MAX_VALUE : food.getHunger(); + ? Integer.MAX_VALUE : food.nutrition(); if (h <= hunger || (!gapples && (food == FoodComponents.GOLDEN_APPLE || food == FoodComponents.ENCHANTED_GOLDEN_APPLE)) || (!chorus && food == FoodComponents.CHORUS_FRUIT) - || (!poison && isPoisonous(food))) + || (!poison && isPoisonous(stack))) continue; slot = s; @@ -86,7 +91,7 @@ private void startEating() { } if (hunger != -1) { - if (slot == mc.player.getInventory().selectedSlot || slot == 40) { + if (slot == mc.player.getInventory().getSelectedSlot() || slot == 40) { mc.options.useKey.setPressed(true); mc.interactionManager.interactItem(mc.player, slot == 40 ? Hand.OFF_HAND : Hand.MAIN_HAND); eating = true; @@ -96,7 +101,12 @@ private void startEating() { } } - private boolean isPoisonous(FoodComponent food) { - return food.getStatusEffects().stream().anyMatch(e -> e.getFirst().getEffectType().getCategory() == StatusEffectCategory.HARMFUL); + private boolean isPoisonous(ItemStack stack) { + ConsumableComponent consumable = stack.get(DataComponentTypes.CONSUMABLE); + + return consumable != null && consumable.onConsumeEffects().stream() + .filter(e -> e instanceof ApplyEffectsConsumeEffect) + .flatMap(e -> ((ApplyEffectsConsumeEffect) e).effects().stream()) + .anyMatch(e -> e.getEffectType().value().getCategory() == StatusEffectCategory.HARMFUL); } } diff --git a/src/main/java/org/bleachhack/module/mods/AutoFarm.java b/src/main/java/org/bleachhack/module/mods/AutoFarm.java index ef71727b60..64d2188b34 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoFarm.java +++ b/src/main/java/org/bleachhack/module/mods/AutoFarm.java @@ -128,7 +128,7 @@ public void onTick(EventTick event) { if (harvestSetting.getState()) { if ((harvestSetting.getChild(0).asToggle().getState() && block instanceof CropBlock && ((CropBlock) block).isMature(state)) - || (harvestSetting.getChild(1).asToggle().getState() && block instanceof GourdBlock) + || (harvestSetting.getChild(1).asToggle().getState() && (block == Blocks.MELON || block == Blocks.PUMPKIN)) || (harvestSetting.getChild(2).asToggle().getState() && block instanceof NetherWartBlock && state.get(NetherWartBlock.AGE) >= 3) || (harvestSetting.getChild(3).asToggle().getState() && block instanceof CocoaBlock && state.get(CocoaBlock.AGE) >= 2) || (harvestSetting.getChild(4).asToggle().getState() && block instanceof SweetBerryBushBlock && state.get(SweetBerryBushBlock.AGE) >= 3) diff --git a/src/main/java/org/bleachhack/module/mods/AutoFish.java b/src/main/java/org/bleachhack/module/mods/AutoFish.java index d4300f9d41..84533c3e8f 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoFish.java +++ b/src/main/java/org/bleachhack/module/mods/AutoFish.java @@ -12,6 +12,7 @@ import org.bleachhack.setting.module.SettingMode; import org.bleachhack.util.InventoryUtils; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.projectile.FishingBobberEntity; import net.minecraft.item.ItemStack; @@ -78,7 +79,7 @@ private int getBestRodSlot() { if (is.getItem() != Items.FISHING_ROD) return -1; - return EnchantmentHelper.get(is).values().stream().mapToInt(Integer::intValue).sum(); + return EnchantmentHelper.getEnchantments(is).getEnchantmentEntries().stream().mapToInt(Object2IntMap.Entry::getIntValue).sum(); })); if (mc.player.getInventory().getStack(slot).getItem() == Items.FISHING_ROD) { diff --git a/src/main/java/org/bleachhack/module/mods/AutoGrind.java b/src/main/java/org/bleachhack/module/mods/AutoGrind.java index 50b4eb4105..9dbaaebbbc 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoGrind.java +++ b/src/main/java/org/bleachhack/module/mods/AutoGrind.java @@ -78,19 +78,15 @@ private void doGrind(GrindstoneScreenHandler handler, int destinationSlot) { } private int getEnchantCount(ItemStack stack) { - // get the number of entries from EnchantmentHelper.get(stack) - return EnchantmentHelper.get(stack).size(); + // get the number of entries from EnchantmentHelper.getEnchantments(stack) + return EnchantmentHelper.getEnchantments(stack).getSize(); } private int getCurseCount(ItemStack stack) { // needed as EnchantmentHelper's curse checks are bugged for Enchanted Books int curses = 0; - if (EnchantmentHelper.get(stack).containsKey(Enchantments.BINDING_CURSE)) { - curses += EnchantmentHelper.get(stack).get(Enchantments.BINDING_CURSE); - } - if (EnchantmentHelper.get(stack).containsKey(Enchantments.VANISHING_CURSE)) { - curses += EnchantmentHelper.get(stack).get(Enchantments.VANISHING_CURSE); - } + curses += EnchantmentHelper.getEnchantments(stack).getLevel(mc.world.getRegistryManager().getEntryOrThrow(Enchantments.BINDING_CURSE)); + curses += EnchantmentHelper.getEnchantments(stack).getLevel(mc.world.getRegistryManager().getEntryOrThrow(Enchantments.VANISHING_CURSE)); return curses; } } diff --git a/src/main/java/org/bleachhack/module/mods/AutoParkour.java b/src/main/java/org/bleachhack/module/mods/AutoParkour.java index d0fcdce7ff..1700ea1882 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoParkour.java +++ b/src/main/java/org/bleachhack/module/mods/AutoParkour.java @@ -73,15 +73,15 @@ public void onTick(EventTick event) { } if (getSetting(1).asToggle().getState()) { - Vec3d lookVec = mc.player.getPos().add(new Vec3d(0, 0, 3.5).rotateY(-(float) Math.toRadians(mc.player.getYaw()))); + Vec3d lookVec = mc.player.getEntityPos().add(new Vec3d(0, 0, 3.5).rotateY(-(float) Math.toRadians(mc.player.getYaw()))); BlockPos nearestPos = BlockPos.streamOutwards(mc.player.getBlockPos().down(), 4, 1, 4) .map(BlockPos::toImmutable) - .filter(pos -> (mc.world.isTopSolid(pos, mc.player) && !mc.world.getBlockCollisions(mc.player, new Box(pos.up(), pos.add(1, 3, 1))).iterator().hasNext()) + .filter(pos -> (mc.world.isTopSolid(pos, mc.player) && !mc.world.getBlockCollisions(mc.player, new Box(Vec3d.of(pos.up()), Vec3d.of(pos.add(1, 3, 1)))).iterator().hasNext()) || mc.world.getBlockState(pos).getBlock() instanceof LadderBlock || mc.world.getBlockState(pos.up()).getBlock() instanceof LadderBlock) - .filter(pos -> mc.player.getPos().distanceTo(Vec3d.of(pos).add(0.5, 1, 0.5)) >= 1) - .filter(pos -> mc.player.getPos().distanceTo(Vec3d.of(pos).add(0.5, 1, 0.5)) <= 4.5 /* ? */) + .filter(pos -> mc.player.getEntityPos().distanceTo(Vec3d.of(pos).add(0.5, 1, 0.5)) >= 1) + .filter(pos -> mc.player.getEntityPos().distanceTo(Vec3d.of(pos).add(0.5, 1, 0.5)) <= 4.5 /* ? */) .sorted(Comparator.comparing(pos -> pos.getSquaredDistance(lookVec))) .findFirst().orElse(null); diff --git a/src/main/java/org/bleachhack/module/mods/AutoReconnect.java b/src/main/java/org/bleachhack/module/mods/AutoReconnect.java index ecece159b3..9d27dba7d0 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoReconnect.java +++ b/src/main/java/org/bleachhack/module/mods/AutoReconnect.java @@ -16,14 +16,15 @@ import org.bleachhack.setting.module.SettingSlider; import org.bleachhack.setting.module.SettingToggle; -import net.minecraft.client.gui.screen.ConnectScreen; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.DisconnectedScreen; import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.client.gui.screen.multiplayer.ConnectScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.MultilineTextWidget; import net.minecraft.client.network.ServerAddress; import net.minecraft.client.network.ServerInfo; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket; import net.minecraft.text.Text; @@ -51,7 +52,7 @@ public void onOpenScreen(EventOpenScreen event) { public void sendPacket(EventPacket.Send event) { if (event.getPacket() instanceof HandshakeC2SPacket) { HandshakeC2SPacket packet = (HandshakeC2SPacket) event.getPacket(); - server = new ServerInfo("Server", packet.getAddress() + ":" + packet.getPort(), false); + server = new ServerInfo("Server", packet.address() + ":" + packet.port(), ServerInfo.ServerType.OTHER); } } @@ -62,18 +63,19 @@ public class NewDisconnectScreen extends DisconnectedScreen { private ButtonWidget reconnectButton; public NewDisconnectScreen(DisconnectedScreen screen) { - super(screen.parent, screen.getTitle(), screen.reason); + super(screen.parent, screen.getTitle(), screen.info); } public void init() { super.init(); reconnectTime = System.currentTimeMillis(); - int buttonH = Math.min(height / 2 + this.reasonHeight / 2 + 9, height - 30); + int reasonHeight = new MultilineTextWidget(this.info.reason(), this.textRenderer).setMaxWidth(this.width - 50).getHeight(); + int buttonH = Math.min(height / 2 + reasonHeight / 2 + 9, height - 30); addDrawableChild(ButtonWidget.builder(Text.literal("Reconnect"), button -> { if (server != null) - ConnectScreen.connect(new MultiplayerScreen(new TitleScreen()), client, ServerAddress.parse(server.address), server); + ConnectScreen.connect(new MultiplayerScreen(new TitleScreen()), client, ServerAddress.parse(server.address), server, false, null); }).position(width / 2 - 100, buttonH + 22).size(200, 20).build()); reconnectButton = addDrawableChild(ButtonWidget.builder(Text.empty(), button -> { getSetting(0).asToggle().setValue(!getSetting(0).asToggle().getState()); @@ -81,7 +83,7 @@ public void init() { }).position(width / 2 - 100, buttonH + 44).size(200, 20).build()); } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { super.render(matrices, mouseX, mouseY, delta); int startTime = (int) (getSetting(0).asToggle().getChild(0).asSlider().getValue() * 1000); @@ -92,7 +94,7 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { if (reconnectTime + startTime < System.currentTimeMillis() && getSetting(0).asToggle().getState()) { if (server != null) - ConnectScreen.connect(new MultiplayerScreen(new TitleScreen()), client, ServerAddress.parse(server.address), server); + ConnectScreen.connect(new MultiplayerScreen(new TitleScreen()), client, ServerAddress.parse(server.address), server, false, null); } } diff --git a/src/main/java/org/bleachhack/module/mods/AutoSign.java b/src/main/java/org/bleachhack/module/mods/AutoSign.java index 1203644505..290e30dfae 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoSign.java +++ b/src/main/java/org/bleachhack/module/mods/AutoSign.java @@ -66,8 +66,9 @@ public void onOpenScreen(EventOpenScreen event) { } } - SignBlockEntity sign = ((SignEditScreen) event.getScreen()).blockEntity; - mc.player.networkHandler.sendPacket(new UpdateSignC2SPacket(sign.getPos(), text[0], text[1], text[2], text[3])); + SignEditScreen screen = (SignEditScreen) event.getScreen(); + SignBlockEntity sign = screen.blockEntity; + mc.player.networkHandler.sendPacket(new UpdateSignC2SPacket(sign.getPos(), screen.front, text[0], text[1], text[2], text[3])); } } } diff --git a/src/main/java/org/bleachhack/module/mods/AutoSteal.java b/src/main/java/org/bleachhack/module/mods/AutoSteal.java index 85a2d1fd97..f75571eb0a 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoSteal.java +++ b/src/main/java/org/bleachhack/module/mods/AutoSteal.java @@ -115,7 +115,7 @@ public void onTick(EventTick event) { boolean openSlot = InventoryUtils.getSlot(false, j -> mc.player.getInventory().getStack(j).isEmpty() || (mc.player.getInventory().getStack(j).isStackable() && mc.player.getInventory().getStack(j).getCount() < mc.player.getInventory().getStack(j).getMaxCount() - && currentItems.get(fi).isItemEqual(mc.player.getInventory().getStack(j)))) != 1; + && ItemStack.areItemsEqual(currentItems.get(fi), mc.player.getInventory().getStack(j)))) != 1; if (openSlot) { mc.interactionManager.clickSlot(currentSyncId, i, 0, SlotActionType.QUICK_MOVE, mc.player); @@ -234,15 +234,15 @@ public void onReadPacket(EventPacket.Read event) { if (event.getPacket() instanceof InventoryS2CPacket) { InventoryS2CPacket packet = (InventoryS2CPacket) event.getPacket(); - if ((lastOpen - currentTime >= 2 || currentItems == null) && packet.getContents().size() == 63 || packet.getContents().size() == 90) { - currentItems = packet.getContents().subList(0, packet.getContents().size() - 36); + if ((currentTime - lastOpen >= 2 || currentItems == null) && (packet.contents().size() == 63 || packet.contents().size() == 90)) { + currentItems = new ArrayList<>(packet.contents().subList(0, packet.contents().size() - 36)); //currentSyncId = -1; } } else if (currentItems != null && event.getPacket() instanceof ScreenHandlerSlotUpdateS2CPacket) { ScreenHandlerSlotUpdateS2CPacket packet = (ScreenHandlerSlotUpdateS2CPacket) event.getPacket(); if (packet.getSyncId() == currentSyncId && packet.getSlot() >= 0 && packet.getSlot() < currentItems.size()) { - currentItems.set(packet.getSlot(), packet.getItemStack()); + currentItems.set(packet.getSlot(), packet.getStack()); } } } diff --git a/src/main/java/org/bleachhack/module/mods/AutoTool.java b/src/main/java/org/bleachhack/module/mods/AutoTool.java index 7fc0951a7f..c31fd0f353 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoTool.java +++ b/src/main/java/org/bleachhack/module/mods/AutoTool.java @@ -20,10 +20,10 @@ import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.Enchantments; import net.minecraft.item.ItemStack; -import net.minecraft.item.SwordItem; import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action; import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; +import net.minecraft.registry.tag.ItemTags; import net.minecraft.screen.slot.SlotActionType; import net.minecraft.util.math.BlockPos; @@ -50,18 +50,18 @@ public void onPacketSend(EventPacket.Send event) { queueSlot = -1; - lastSlot = mc.player.getInventory().selectedSlot; + lastSlot = mc.player.getInventory().getSelectedSlot(); int slot = getBestSlot(p.getPos()); - if (slot != mc.player.getInventory().selectedSlot) { + if (slot != mc.player.getInventory().getSelectedSlot()) { if (slot < 9) { - mc.player.getInventory().selectedSlot = slot; + mc.player.getInventory().setSelectedSlot(slot); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(slot)); } else if (mc.player.playerScreenHandler == mc.player.currentScreenHandler) { - boolean itemInHand = !mc.player.getInventory().getMainHandStack().isEmpty(); + boolean itemInHand = !mc.player.getMainHandStack().isEmpty(); mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, slot, 0, SlotActionType.PICKUP, mc.player); - mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, 36 + mc.player.getInventory().selectedSlot, 0, SlotActionType.PICKUP, mc.player); + mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, 36 + mc.player.getInventory().getSelectedSlot(), 0, SlotActionType.PICKUP, mc.player); if (itemInHand) mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, slot, 0, SlotActionType.PICKUP, mc.player); @@ -71,9 +71,9 @@ public void onPacketSend(EventPacket.Send event) { if (getSetting(1).asToggle().getState()) { ItemStack handSlot = mc.player.getMainHandStack(); if (getSetting(0).asToggle().getState() && handSlot.isDamageable() && handSlot.getMaxDamage() - handSlot.getDamage() < 2 - && queueSlot == mc.player.getInventory().selectedSlot) { - queueSlot = mc.player.getInventory().selectedSlot == 0 ? 1 : mc.player.getInventory().selectedSlot - 1; - } else if (lastSlot >= 0 && lastSlot <= 8 && lastSlot != mc.player.getInventory().selectedSlot) { + && queueSlot == mc.player.getInventory().getSelectedSlot()) { + queueSlot = mc.player.getInventory().getSelectedSlot() == 0 ? 1 : mc.player.getInventory().getSelectedSlot() - 1; + } else if (lastSlot >= 0 && lastSlot <= 8 && lastSlot != mc.player.getInventory().getSelectedSlot()) { queueSlot = lastSlot; } } @@ -84,7 +84,7 @@ public void onPacketSend(EventPacket.Send event) { @BleachSubscribe public void onTick(EventTick event) { if (queueSlot != -1) { - mc.player.getInventory().selectedSlot = queueSlot; + mc.player.getInventory().setSelectedSlot(queueSlot); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(queueSlot)); queueSlot = -1; } @@ -93,7 +93,7 @@ public void onTick(EventTick event) { private int getBestSlot(BlockPos pos) { BlockState state = mc.world.getBlockState(pos); - int bestSlot = mc.player.getInventory().selectedSlot; + int bestSlot = mc.player.getInventory().getSelectedSlot(); ItemStack handSlot = mc.player.getInventory().getStack(bestSlot); if (getSetting(0).asToggle().getState() && handSlot.isDamageable() && handSlot.getMaxDamage() - handSlot.getDamage() < 2) { @@ -101,12 +101,12 @@ private int getBestSlot(BlockPos pos) { } if (state.isAir()) - return mc.player.getInventory().selectedSlot; + return mc.player.getInventory().getSelectedSlot(); float bestSpeed = getMiningSpeed(mc.player.getInventory().getStack(bestSlot), state); for (int slot = 0; slot < 36; slot++) { - if (slot == mc.player.getInventory().selectedSlot || slot == bestSlot) + if (slot == mc.player.getInventory().getSelectedSlot() || slot == bestSlot) continue; ItemStack stack = mc.player.getInventory().getStack(slot); @@ -119,7 +119,7 @@ private int getBestSlot(BlockPos pos) { || (getSetting(2).asToggle().getState() && speed == bestSpeed && !stack.isDamageable() && mc.player.getInventory().getStack(bestSlot).isDamageable() - && EnchantmentHelper.getLevel(Enchantments.SILK_TOUCH, mc.player.getInventory().getStack(bestSlot)) == 0)) { + && EnchantmentHelper.getLevel(mc.world.getRegistryManager().getEntryOrThrow(Enchantments.SILK_TOUCH), mc.player.getInventory().getStack(bestSlot)) == 0)) { bestSpeed = speed; bestSlot = slot; } @@ -129,14 +129,14 @@ private int getBestSlot(BlockPos pos) { } private float getMiningSpeed(ItemStack stack, BlockState state) { - if ((state.getBlock() == Blocks.BAMBOO || state.getBlock() == Blocks.BAMBOO_SAPLING) && stack.getItem() instanceof SwordItem) { + if ((state.getBlock() == Blocks.BAMBOO || state.getBlock() == Blocks.BAMBOO_SAPLING) && stack.isIn(ItemTags.SWORDS)) { return Integer.MAX_VALUE; } float speed = stack.getMiningSpeedMultiplier(state); if (speed > 1) { - int efficiency = EnchantmentHelper.getLevel(Enchantments.EFFICIENCY, stack); + int efficiency = EnchantmentHelper.getLevel(mc.world.getRegistryManager().getEntryOrThrow(Enchantments.EFFICIENCY), stack); if (efficiency > 0 && !stack.isEmpty()) speed += efficiency * efficiency + 1; } diff --git a/src/main/java/org/bleachhack/module/mods/AutoTotem.java b/src/main/java/org/bleachhack/module/mods/AutoTotem.java index f0b0dfdd9e..6eaf18e921 100644 --- a/src/main/java/org/bleachhack/module/mods/AutoTotem.java +++ b/src/main/java/org/bleachhack/module/mods/AutoTotem.java @@ -71,8 +71,8 @@ public void onTick(EventTick event) { // If the player is in another inventory, atleast check the hotbar for anything to swap for (int i = 0; i < 9; i++) { if (mc.player.getInventory().getStack(i).getItem() == Items.TOTEM_OF_UNDYING) { - if (i != mc.player.getInventory().selectedSlot) { - mc.player.getInventory().selectedSlot = i; + if (i != mc.player.getInventory().getSelectedSlot()) { + mc.player.getInventory().setSelectedSlot(i); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(i)); } diff --git a/src/main/java/org/bleachhack/module/mods/BetterPortal.java b/src/main/java/org/bleachhack/module/mods/BetterPortal.java index ef981caa26..325add5466 100644 --- a/src/main/java/org/bleachhack/module/mods/BetterPortal.java +++ b/src/main/java/org/bleachhack/module/mods/BetterPortal.java @@ -35,8 +35,8 @@ public BetterPortal() { public void onClientMove(EventClientMove event) { if (getSetting(1).asToggle().getState()) { if (WorldUtils.doesBoxTouchBlock(mc.player.getBoundingBox(), Blocks.NETHER_PORTAL)) { - mc.player.lastNauseaStrength = -1f; - mc.player.nextNauseaStrength = -1f; + mc.player.lastNauseaIntensity = -1f; + mc.player.nauseaIntensity = -1f; } } } diff --git a/src/main/java/org/bleachhack/module/mods/BlockHighlight.java b/src/main/java/org/bleachhack/module/mods/BlockHighlight.java index 06b5ba4ad4..c193fd6320 100644 --- a/src/main/java/org/bleachhack/module/mods/BlockHighlight.java +++ b/src/main/java/org/bleachhack/module/mods/BlockHighlight.java @@ -1,8 +1,5 @@ package org.bleachhack.module.mods; -import java.io.IOException; - -import net.minecraft.client.gl.PostEffectProcessor; import org.bleachhack.event.events.EventRenderBlockOutline; import org.bleachhack.event.events.EventWorldRender; import org.bleachhack.eventbus.BleachSubscribe; @@ -11,58 +8,34 @@ import org.bleachhack.setting.module.SettingColor; import org.bleachhack.setting.module.SettingMode; import org.bleachhack.setting.module.SettingSlider; -import org.bleachhack.util.BleachLogger; import org.bleachhack.util.render.Renderer; import org.bleachhack.util.render.color.QuadColor; -import org.bleachhack.util.shader.BleachCoreShaders; -import org.bleachhack.util.shader.ColorVertexConsumerProvider; -import org.bleachhack.util.shader.ShaderEffectWrapper; - -import com.google.gson.JsonSyntaxException; import net.minecraft.block.BlockState; -import net.minecraft.block.Material; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.client.render.OverlayTexture; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.random.Random; -import org.bleachhack.util.shader.ShaderLoader; public class BlockHighlight extends Module { - private ShaderEffectWrapper shader; - private ColorVertexConsumerProvider colorVertexer; - public BlockHighlight() { - super("BlockHighlight", KEY_UNBOUND, ModuleCategory.RENDER, "Highlights blocks that you're looking at.", - new SettingMode("Render", "Shader", "Box").withDesc("The Render mode."), - new SettingSlider("ShaderFill", 1, 255, 50, 0).withDesc("How opaque the fill on shader mode should be."), - new SettingSlider("Box", 0, 5, 2, 1).withDesc("How thick the box outline should be."), - new SettingSlider("BoxFill", 0, 255, 50, 0).withDesc("How opaque the fill on box mode should be."), - new SettingColor("Color", 0, 128, 128).withDesc("The color of the highlight.")); + this(new SettingMode("Render", "Shader", "Box").withDesc("The Render mode.")); } - @Override - public void onEnable(boolean inWorld) { - super.onEnable(inWorld); - - try { - shader = new ShaderEffectWrapper( - ShaderLoader.loadEffect(mc.getFramebuffer(), new Identifier("bleachhack", "shaders/post/entity_outline.json"))); - - colorVertexer = new ColorVertexConsumerProvider(shader.getFramebuffer("main"), BleachCoreShaders::getColorOverlayShader); - } catch (JsonSyntaxException | IOException e) { - e.printStackTrace(); - setEnabled(false); - } + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Render mode + // setting as a constructor parameter first lets the predicates below capture that local + // variable instead. + private BlockHighlight(SettingMode renderMode) { + super("BlockHighlight", KEY_UNBOUND, ModuleCategory.RENDER, "Highlights blocks that you're looking at.", + renderMode, + new SettingSlider("ShaderFill", 1, 255, 50, 0).withDesc("How opaque the fill on shader mode should be.") + .visibleWhen(() -> renderMode.getMode() == 0), + new SettingSlider("Box", 0, 5, 2, 1).withDesc("How thick the box outline should be.") + .visibleWhen(() -> renderMode.getMode() == 1), + new SettingSlider("BoxFill", 0, 255, 50, 0).withDesc("How opaque the fill on box mode should be.") + .visibleWhen(() -> renderMode.getMode() == 1), + new SettingColor("Color", 0, 128, 128).withDesc("The color of the highlight.")); } @BleachSubscribe @@ -80,42 +53,21 @@ public void onWorldRender(EventWorldRender.Post event) { BlockPos pos = ((BlockHitResult) mc.crosshairTarget).getBlockPos(); BlockState state = mc.world.getBlockState(pos); - if (state.getMaterial() == Material.AIR || !mc.world.getWorldBorder().contains(pos)) + if (state.isAir() || !mc.world.getWorldBorder().contains(pos)) return; int[] color = this.getSetting(4).asColor().getRGBArray(); - if (mode == 0) { - shader.prepare(); - shader.clearFramebuffer("main"); + Box box = state.getOutlineShape(mc.world, pos).getBoundingBox().offset(pos); - Vec3d offset = state.getModelOffset(mc.world, pos); - MatrixStack matrices = Renderer.matrixFrom(pos.getX() + offset.x, pos.getY() + offset.y, pos.getZ() + offset.z); - - BlockEntity be = mc.world.getBlockEntity(pos); - BlockEntityRenderer renderer = be != null ? mc.getBlockEntityRenderDispatcher().get(be) : null; - try { - if (renderer != null) { - renderer.render(be, mc.getTickDelta(), matrices, - colorVertexer.createSingleProvider(mc.getBufferBuilders().getEntityVertexConsumers(), color[0], color[1], color[2], getSetting(1).asSlider().getValueInt()), - LightmapTextureManager.MAX_LIGHT_COORDINATE, OverlayTexture.DEFAULT_UV); - } else { - mc.getBlockRenderManager().getModelRenderer().renderFlat( - mc.world, mc.getBlockRenderManager().getModel(state), state, pos, matrices, - colorVertexer.createSingleProvider(mc.getBufferBuilders().getEntityVertexConsumers(), color[0], color[1], color[2], getSetting(1).asSlider().getValueInt()).getBuffer(RenderLayers.getMovingBlockLayer(state)), - false, Random.create(0), 0L, OverlayTexture.DEFAULT_UV); - } - } catch (Exception e) { - BleachLogger.error("Disabling BlockHighlight, another mod conflicting with shader mode?"); - e.printStackTrace(); - setEnabled(false); - return; - } + if (mode == 0) { + // 1.21.11: BlockEntityRenderer no longer takes a VertexConsumerProvider we can wrap to draw + // a silhouette-shaped highlight (see task #3 notes) - "Shader" mode now draws a through-walls + // flat-colored bounding box instead, same as 1.19.4's "Box" mode but ignoring depth test. + int fill = getSetting(1).asSlider().getValueInt(); - colorVertexer.draw(); - shader.render(); - shader.drawFramebufferToMain("main"); + if (fill != 0) + Renderer.drawBoxFillThroughWalls(box, QuadColor.single(color[0], color[1], color[2], fill)); } else { - Box box = state.getOutlineShape(mc.world, pos).getBoundingBox().offset(pos); float width = getSetting(2).asSlider().getValueFloat(); int fill = getSetting(3).asSlider().getValueInt(); diff --git a/src/main/java/org/bleachhack/module/mods/BookCrash.java b/src/main/java/org/bleachhack/module/mods/BookCrash.java index bb04c21bf3..47a17b7518 100644 --- a/src/main/java/org/bleachhack/module/mods/BookCrash.java +++ b/src/main/java/org/bleachhack/module/mods/BookCrash.java @@ -8,6 +8,8 @@ */ package org.bleachhack.module.mods; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -23,16 +25,18 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.WritableBookContentComponent; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; -import net.minecraft.nbt.NbtString; import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket; import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket; import net.minecraft.network.packet.c2s.play.UpdateSignC2SPacket; -import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; +import net.minecraft.network.packet.s2c.common.DisconnectS2CPacket; import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.screen.sync.ComponentChangesHash; +import net.minecraft.screen.sync.ItemStackHash; +import net.minecraft.text.RawFilteredPair; import net.minecraft.util.math.BlockPos; /* Rebranded queueskip exploit. credit > https://www.youtube.com/watch?v=-BA4ABlFJuc */ @@ -41,12 +45,21 @@ public class BookCrash extends Module { private int delay = 0; public BookCrash() { + this(new SettingMode("Mode", "Jessica", "Raion", "Sign").withDesc("What method to use.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicates below capture that local variable instead. + private BookCrash(SettingMode mode) { super("BookCrash", KEY_UNBOUND, ModuleCategory.EXPLOITS, "Abuses book and quill/sign packets to remotely kick people.", - new SettingMode("Mode", "Jessica", "Raion", "Sign").withDesc("What method to use."), + mode, new SettingSlider("Uses", 1, 20, 5, 0).withDesc("How many uses per tick."), new SettingSlider("Delay", 0, 5, 0, 0).withDesc("How many ticks to wait between uses."), - new SettingMode("Fill", "Ascii", "0xFFFF", "Random", "Old").withDesc("How to fill the book."), - new SettingSlider("Pages", 1, 100, 50, 0).withDesc("How many pages to fill."), + new SettingMode("Fill", "Ascii", "0xFFFF", "Random", "Old").withDesc("How to fill the book.") + .visibleWhen(() -> mode.getMode() != 2), + new SettingSlider("Pages", 1, 100, 50, 0).withDesc("How many pages to fill.") + .visibleWhen(() -> mode.getMode() != 2), new SettingToggle("Auto-Off", true).withDesc("Automatically turns the modules off when you disconnect.")); } @@ -57,10 +70,6 @@ public void onTick(EventTick event) { return; ItemStack bookObj = new ItemStack(Items.WRITABLE_BOOK); - NbtList list = new NbtList(); - NbtCompound tag = new NbtCompound(); - String author = "Bleach"; - String title = "\n Bleachhack Owns All \n"; String size = ""; int pages = Math.min(getSetting(4).asSlider().getValueInt(), 100); @@ -82,28 +91,33 @@ public void onTick(EventTick event) { String text = "bh ontop"; Random rand = new Random(); for (int i = 0; i < getSetting(1).asSlider().getValue(); i++) { + // ported: UpdateSignC2SPacket gained a "front" side flag since signs can now have + // text on both sides; true keeps the previous (only) sign side behaviour. mc.player.networkHandler.sendPacket(new UpdateSignC2SPacket( - new BlockPos(rand.nextInt(29999999), rand.nextInt(29999999), rand.nextInt(29999999)), text, text, text, text)); + new BlockPos(rand.nextInt(29999999), rand.nextInt(29999999), rand.nextInt(29999999)), true, text, text, text, text)); } } else { + // ported: 1.19.4 wrote pages as a raw nbt string list ("author"/"title" were also written + // to the tag even though WRITABLE_BOOK never reads them); 1.21.11 stores pages as a + // WritableBookContentComponent, which is all a writable book ever actually used. + List> list = new ArrayList<>(); for (int i = 0; i < pages; i++) { - NbtString tString = NbtString.of(size); - list.add(tString); + list.add(RawFilteredPair.of(size)); } - tag.putString("author", author); - tag.putString("title", title); - tag.put("pages", list); - - bookObj.setSubNbt("pages", list); - bookObj.setNbt(tag); + bookObj.set(DataComponentTypes.WRITABLE_BOOK_CONTENT, new WritableBookContentComponent(list)); for (int i = 0; i < getSetting(1).asSlider().getValue(); i++) { if (getSetting(0).asMode().getMode() == 0) { - Int2ObjectMap map = new Int2ObjectOpenHashMap<>(1); - map.put(0, bookObj); - - mc.player.networkHandler.sendPacket(new ClickSlotC2SPacket(0, 0, 0, 0, SlotActionType.PICKUP, bookObj, map)); + // ported: ClickSlotC2SPacket no longer carries raw ItemStacks, only server-verifiable + // ItemStackHash values (anti-cheat hashing added after 1.19.4); build them the same + // way ClientPlayerInteractionManager.clickSlot does. + ComponentChangesHash.ComponentHasher hasher = mc.player.networkHandler.getComponentHasher(); + ItemStackHash bookHash = ItemStackHash.fromItemStack(bookObj, hasher); + Int2ObjectMap map = new Int2ObjectOpenHashMap<>(1); + map.put(0, bookHash); + + mc.player.networkHandler.sendPacket(new ClickSlotC2SPacket(0, 0, (short) 0, (byte) 0, SlotActionType.PICKUP, map, bookHash)); } else { mc.player.networkHandler.sendPacket(new CreativeInventoryActionC2SPacket(0, bookObj)); } diff --git a/src/main/java/org/bleachhack/module/mods/BowBot.java b/src/main/java/org/bleachhack/module/mods/BowBot.java index 58d150313d..7486429449 100644 --- a/src/main/java/org/bleachhack/module/mods/BowBot.java +++ b/src/main/java/org/bleachhack/module/mods/BowBot.java @@ -53,7 +53,7 @@ public void onTick(EventTick event) { if (getSetting(0).asToggle().getState()) { if (mc.player.getMainHandStack().getItem() == Items.CROSSBOW - && (float) mc.player.getItemUseTime() / (float) CrossbowItem.getPullTime(mc.player.getMainHandStack()) >= 1f) { + && (float) mc.player.getItemUseTime() / (float) CrossbowItem.getPullTime(mc.player.getMainHandStack(), mc.player) >= 1f) { mc.player.stopUsingItem(); mc.player.networkHandler.sendPacket(new PlayerActionC2SPacket(Action.RELEASE_USE_ITEM, BlockPos.ORIGIN, Direction.UP)); mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND); @@ -85,7 +85,7 @@ public void onTick(EventTick event) { velocity = Math.min(1f, (velocity * velocity + velocity * 2) / 3); // set position to aim at - Vec3d newTargetVec = target.getPos().add(target.getVelocity()); + Vec3d newTargetVec = target.getEntityPos().add(target.getVelocity()); double d = mc.player.getEyePos().distanceTo(target.getBoundingBox().offset(target.getVelocity()).getCenter()); double x = newTargetVec.x + (newTargetVec.x - target.getX()) * d - mc.player.getX(); double y = newTargetVec.y + (newTargetVec.y - target.getY()) * d + target.getHeight() * 0.5 - mc.player.getY() - mc.player.getEyeHeight(mc.player.getPose()); diff --git a/src/main/java/org/bleachhack/module/mods/ClickGui.java b/src/main/java/org/bleachhack/module/mods/ClickGui.java index 865a6d4913..bf3737094a 100644 --- a/src/main/java/org/bleachhack/module/mods/ClickGui.java +++ b/src/main/java/org/bleachhack/module/mods/ClickGui.java @@ -23,7 +23,9 @@ public ClickGui() { super("ClickGui", GLFW.GLFW_KEY_RIGHT_SHIFT, ModuleCategory.RENDER, "Draws the clickgui.", new SettingSlider("Length", 70, 85, 75, 0).withDesc("The length of each window."), new SettingToggle("Search bar", true).withDesc("Shows a search bar."), - new SettingToggle("Help", true).withDesc("Shows the help text.")); + new SettingToggle("Help", true).withDesc("Shows the help text."), + new SettingSlider("Scale", 50, 200, 100, 0).withDesc("Scales the whole clickgui on top of Auto Fit, in percent."), + new SettingToggle("Auto Fit", true).withDesc("Keeps the clickgui the same real size regardless of your Minecraft GUI Scale. Scale still applies on top of this.")); } @Override diff --git a/src/main/java/org/bleachhack/module/mods/ClickTp.java b/src/main/java/org/bleachhack/module/mods/ClickTp.java index a8e19cc98c..b000a99807 100644 --- a/src/main/java/org/bleachhack/module/mods/ClickTp.java +++ b/src/main/java/org/bleachhack/module/mods/ClickTp.java @@ -65,13 +65,13 @@ public void onWorldRender(EventWorldRender.Post event) { @BleachSubscribe public void onTick(EventTick event) { - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_LEFT_SHIFT)) { + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_LEFT_SHIFT)) { pos = null; dir = null; return; } - BlockHitResult hit = (BlockHitResult) mc.player.raycast(100, mc.getTickDelta(), getSetting(1).asToggle().getState()); + BlockHitResult hit = (BlockHitResult) mc.player.raycast(100, mc.getRenderTickCounter().getTickProgress(true), getSetting(1).asToggle().getState()); boolean miss = hit.getType() == Type.MISS && !getSetting(0).asToggle().getState(); @@ -86,11 +86,11 @@ public void onTick(EventTick event) { if (getSetting(2).asToggle().getState()) { mc.player.updatePosition(mc.player.getX(), tpPos.y, mc.player.getZ()); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), tpPos.y, mc.player.getZ(), false)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), tpPos.y, mc.player.getZ(), false, mc.player.horizontalCollision)); } mc.player.updatePosition(tpPos.x, tpPos.y, tpPos.z); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(tpPos.x, tpPos.y, tpPos.z, false)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(tpPos.x, tpPos.y, tpPos.z, false, mc.player.horizontalCollision)); } else if (GLFW.glfwGetMouseButton(mc.getWindow().getHandle(), GLFW.GLFW_MOUSE_BUTTON_RIGHT) == 0) { antiSpamClick = false; } diff --git a/src/main/java/org/bleachhack/module/mods/Criticals.java b/src/main/java/org/bleachhack/module/mods/Criticals.java index 3be107c282..3e4afe4bd4 100644 --- a/src/main/java/org/bleachhack/module/mods/Criticals.java +++ b/src/main/java/org/bleachhack/module/mods/Criticals.java @@ -30,7 +30,9 @@ public class Criticals extends Module { public Criticals() { super("Criticals", KEY_UNBOUND, ModuleCategory.COMBAT, "Attempts to force Critical hits on entities you hit.", - new SettingMode("Mode", "MiniJump", "FullJump").withDesc("Criticals mode, MiniJump does the smallest posible jump, FullJump simulates a full jump.")); + new SettingMode("Mode", "MiniJump", "FullJump", "Packet", "UpdatedNCP", "OldNCP").withDesc( + "Criticals mode. MiniJump/FullJump fake a (mini/full) jump, Packet/UpdatedNCP/OldNCP (from Meteor) " + + "spoof a tiny, near-invisible height change tuned to different anticheat detection thresholds.")); } @BleachSubscribe @@ -60,15 +62,31 @@ private void sendCritPackets() { double x = mc.player.getX(); double y = mc.player.getY(); double z = mc.player.getZ(); - if (getSetting(0).asMode().getMode() == 0) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.0633, z, false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y, z, false)); - } else { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.42, z, false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.65, z, false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.72, z, false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.53, z, false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.32, z, false)); + switch (getSetting(0).asMode().getMode()) { + case 0 -> { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.0633, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y, z, false, mc.player.horizontalCollision)); + } + case 1 -> { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.42, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.65, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.72, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.53, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.32, z, false, mc.player.horizontalCollision)); + } + case 2 -> { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.0625, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y, z, false, mc.player.horizontalCollision)); + } + case 3 -> { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.0000008, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y, z, false, mc.player.horizontalCollision)); + } + case 4 -> { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.11, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.1100013579, z, false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y + 0.0000013579, z, false, mc.player.horizontalCollision)); + } } } diff --git a/src/main/java/org/bleachhack/module/mods/CrystalAura.java b/src/main/java/org/bleachhack/module/mods/CrystalAura.java index f6748c1267..6ee8ab1704 100644 --- a/src/main/java/org/bleachhack/module/mods/CrystalAura.java +++ b/src/main/java/org/bleachhack/module/mods/CrystalAura.java @@ -9,12 +9,14 @@ package org.bleachhack.module.mods; import com.google.common.collect.Streams; +import net.minecraft.component.DataComponentTypes; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.decoration.EndCrystalEntity; import net.minecraft.entity.effect.StatusEffects; import net.minecraft.item.Items; +import net.minecraft.text.Text; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; @@ -32,6 +34,7 @@ import org.bleachhack.setting.module.SettingToggle; import org.bleachhack.util.InventoryUtils; import org.bleachhack.util.render.Renderer; +import org.bleachhack.util.render.WorldRenderer; import org.bleachhack.util.render.color.QuadColor; import org.bleachhack.util.world.DamageUtils; import org.bleachhack.util.world.EntityUtils; @@ -39,15 +42,40 @@ import java.util.*; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; // i am morbidly obese public class CrystalAura extends Module { private BlockPos render = null; + private float renderDamage = 0; private int breakCooldown = 0; private int placeCooldown = 0; - private Map blacklist = new HashMap<>(); + + // ConcurrentHashMap since the Support search thread reads this (via getCrystalPoses) while the + // main thread ticks it down at the same time. + private Map blacklist = new ConcurrentHashMap<>(); + + // Support: places an obsidian block via the same item-use-cooldown desync AirPlace exploits, + // then waits supportDelay ticks (so the server has time to register it) before placing the + // crystal on top. pendingSupport = "still trying to get the block down", supportDelay = + // "block's down, waiting out the delay". + private Set pendingSupport = new HashSet<>(); + private Map supportDelay = new HashMap<>(); + private int supportCooldown = 0; + + // Support treats every replaceable block in range as a candidate, not just existing obsidian/ + // bedrock, so the scan + per-candidate explosion damage math gets a lot bigger than the normal + // path and was blocking the render thread long enough to lag. Only used while Support is on - + // the normal path stays synchronous since it's cheap enough not to need this. + private ExecutorService searchExecutor; + private final AtomicBoolean searching = new AtomicBoolean(false); + private volatile Map cachedPlaceBlocks = new LinkedHashMap<>(); + private volatile Map cachedPlaceDamage = new HashMap<>(); public CrystalAura() { super("CrystalAura", KEY_UNBOUND, ModuleCategory.COMBAT, "Automatically does crystalpvp for you.", @@ -70,16 +98,40 @@ public CrystalAura() { new SettingSlider("MinRatio", 0.5, 6, 2, 1).withDesc("Minimum damage ratio to place a crystal at (Target dmg/Player dmg)."), new SettingSlider("CPT", 1, 10, 2, 0).withDesc("How many crystals to place per tick."), new SettingSlider("Cooldown", 0, 10, 0, 0).withDesc("How many ticks to wait before placing the next batch of crystals."), - new SettingColor("Place Color", 178, 178, 255).withDesc("The color of the block you're placing crystals on.")), + new SettingColor("Place Color", 178, 178, 255).withDesc("The color of the block you're placing crystals on."), + new SettingToggle("Support", false).withDesc("Places an obsidian support block (using the same trick as AirPlace) when a good spot has no solid block to place the crystal on.").withChildren( + new SettingSlider("Support Delay", 0, 10, 2, 0).withDesc("Ticks to wait after placing the support block before placing the crystal on it."))), + new SettingToggle("Render Damage", true).withDesc("Shows the expected damage above the last block you placed a crystal on."), new SettingToggle("SameTick", false).withDesc("Enables exploding and placing crystals at the same tick."), new SettingRotate(false).withDesc("Rotates to crystals."), new SettingSlider("Range", 0, 6, 4.5, 2).withDesc("Range to place and attack crystals.")); } + @Override + public void onEnable(boolean inWorld) { + searchExecutor = Executors.newSingleThreadExecutor(); + super.onEnable(inWorld); + } + + @Override + public void onDisable(boolean inWorld) { + if (searchExecutor != null) { + searchExecutor.shutdownNow(); + searchExecutor = null; + } + searching.set(false); + cachedPlaceBlocks = new LinkedHashMap<>(); + cachedPlaceDamage = new HashMap<>(); + pendingSupport.clear(); + supportDelay.clear(); + super.onDisable(inWorld); + } + @BleachSubscribe public void onTick(EventTick event) { breakCooldown = Math.max(0, breakCooldown - 1); placeCooldown = Math.max(0, placeCooldown - 1); + supportCooldown = Math.max(0, supportCooldown - 1); for (Entry e : new HashMap<>(blacklist).entrySet()) { if (e.getValue() > 0) { @@ -89,7 +141,13 @@ public void onTick(EventTick event) { } } - if (mc.player.isUsingItem() && mc.player.getMainHandStack().isFood()) { + for (Entry e : new HashMap<>(supportDelay).entrySet()) { + if (e.getValue() > 0) { + supportDelay.replace(e.getKey(), e.getValue() - 1); + } + } + + if (mc.player.isUsingItem() && mc.player.getMainHandStack().contains(DataComponentTypes.FOOD)) { return; } @@ -117,20 +175,20 @@ public void onTick(EventTick event) { if (explodeToggle.getState() && !nearestCrystals.isEmpty() && breakCooldown <= 0) { boolean end = false; for (EndCrystalEntity c : nearestCrystals) { - if (mc.player.distanceTo(c) > getSetting(7).asSlider().getValue() - || mc.world.getOtherEntities(null, new Box(c.getPos(), c.getPos()).expand(7), targets::contains).isEmpty()) + if (mc.player.distanceTo(c) > getSetting(8).asSlider().getValue() + || mc.world.getOtherEntities(null, new Box(c.getEntityPos(), c.getEntityPos()).expand(7), targets::contains).isEmpty()) continue; - float damage = DamageUtils.getExplosionDamage(c.getPos(), 6f, mc.player); + float damage = DamageUtils.getExplosionDamage(c.getEntityPos(), 6f, mc.player); if (DamageUtils.willGoBelowHealth(mc.player, damage, explodeToggle.getChild(4).asSlider().getValueFloat())) continue; - int oldSlot = mc.player.getInventory().selectedSlot; + int oldSlot = mc.player.getInventory().getSelectedSlot(); if (explodeToggle.getChild(0).asToggle().getState() && mc.player.hasStatusEffect(StatusEffects.WEAKNESS)) { InventoryUtils.selectSlot(false, true, Comparator.comparing(i -> DamageUtils.getItemAttackDamage(mc.player.getInventory().getStack(i)))); } - if (getSetting(6).asRotate().getState()) { + if (getSetting(7).asRotate().getState()) { Vec3d eyeVec = mc.player.getEyePos(); Vec3d v = new Vec3d(c.getX(), c.getY() + 0.5, c.getZ()); for (Direction d : Direction.values()) { @@ -140,7 +198,7 @@ public void onTick(EventTick event) { } } - WorldUtils.facePosAuto(v.x, v.y, v.z, getSetting(6).asRotate()); + WorldUtils.facePosAuto(v.x, v.y, v.z, getSetting(7).asRotate()); } mc.interactionManager.attackEntity(mc.player, c); @@ -158,7 +216,7 @@ public void onTick(EventTick event) { breakCooldown = explodeToggle.getChild(3).asSlider().getValueInt() + 1; - if (!getSetting(5).asToggle().getState() && end) { + if (!getSetting(6).asToggle().getState() && end) { return; } } @@ -167,7 +225,7 @@ public void onTick(EventTick event) { SettingToggle placeToggle = getSetting(4).asToggle(); if (placeToggle.getState() && placeCooldown <= 0) { int crystalSlot = !placeToggle.getChild(0).asToggle().getState() - ? (mc.player.getMainHandStack().getItem() == Items.END_CRYSTAL ? mc.player.getInventory().selectedSlot + ? (mc.player.getMainHandStack().getItem() == Items.END_CRYSTAL ? mc.player.getInventory().getSelectedSlot() : mc.player.getOffHandStack().getItem() == Items.END_CRYSTAL ? 40 : -1) : InventoryUtils.getSlot(true, i -> mc.player.getInventory().getStack(i).getItem() == Items.END_CRYSTAL); @@ -176,39 +234,70 @@ public void onTick(EventTick event) { return; } - Map placeBlocks = new LinkedHashMap<>(); - - for (Vec3d v : getCrystalPoses()) { - float playerDamg = DamageUtils.getExplosionDamage(v, 6f, mc.player); - - if (DamageUtils.willKill(mc.player, playerDamg)) - continue; - - for (LivingEntity e : targets) { - float targetDamg = DamageUtils.getExplosionDamage(v, 6f, e); - if (DamageUtils.willPop(mc.player, playerDamg) && !DamageUtils.willPopOrKill(e, targetDamg)) { - continue; - } - - if (targetDamg >= placeToggle.getChild(4).asSlider().getValue()) { - float ratio = playerDamg == 0 ? targetDamg : targetDamg / playerDamg; - - if (ratio > placeToggle.getChild(5).asSlider().getValue()) { - placeBlocks.put(BlockPos.ofFloored(v).down(), ratio); + boolean supportOn = placeToggle.getChild(9).asToggle().getState(); + double minDmg = placeToggle.getChild(4).asSlider().getValue(); + double minRatio = placeToggle.getChild(5).asSlider().getValue(); + + Map placeBlocks; + Map placeDamage; + + if (supportOn) { + // Support turns most of the range into a candidate (any replaceable block, not just + // existing obsidian/bedrock), so the scan + per-candidate explosion damage math is + // heavy enough to lag the render thread. Run it in the background instead and place + // off whatever the last completed scan found - one scan in flight at a time, so scans + // don't pile up faster than they finish. + if (searchExecutor != null && searching.compareAndSet(false, true)) { + searchExecutor.submit(() -> { + try { + ScoreResult result = scoreCandidates(targets, minDmg, minRatio); + cachedPlaceBlocks = result.blocks(); + cachedPlaceDamage = result.damage(); + } catch (Exception ex) { + // World/entity state can shift mid-scan since it's read off-thread while + // the game keeps ticking - just drop this cycle's result and retry next. + } finally { + searching.set(false); } - } + }); } - } - placeBlocks = placeBlocks.entrySet().stream() - .sorted((b1, b2) -> Float.compare(b2.getValue(), b1.getValue())) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (x, y) -> y, LinkedHashMap::new)); + placeBlocks = cachedPlaceBlocks; + placeDamage = cachedPlaceDamage; + } else { + ScoreResult result = scoreCandidates(targets, minDmg, minRatio); + placeBlocks = result.blocks(); + placeDamage = result.damage(); + } - int oldSlot = mc.player.getInventory().selectedSlot; + int oldSlot = mc.player.getInventory().getSelectedSlot(); int places = 0; for (Entry e : placeBlocks.entrySet()) { BlockPos block = e.getKey(); + // One support block per tick, max - placing several in the same tick is exactly the + // kind of burst that gets them rubberbanded/invalidated server-side. + if (supportOn && !isSolidBase(block)) { + if (supportCooldown <= 0) { + placeSupportBlock(block); + supportCooldown = 1; + } + pendingSupport.add(block); + continue; + } + + if (pendingSupport.remove(block)) { + // Even at a Support Delay of 0, the support block and the crystal still can't + // land in the same tick without looking like the same burst - one tick minimum. + int delay = Math.max(1, placeToggle.getChild(9).asToggle().getChild(0).asSlider().getValueInt()); + supportDelay.put(block, delay); + } + + if (supportDelay.getOrDefault(block, 0) > 0) { + continue; + } + supportDelay.remove(block); + Vec3d eyeVec = mc.player.getEyePos(); Vec3d vec = Vec3d.ofCenter(block, 1); @@ -231,13 +320,14 @@ public void onTick(EventTick event) { if (placeToggle.getChild(2).asToggle().getState()) blacklist.put(block, 4); - if (getSetting(6).asRotate().getState()) { - WorldUtils.facePosAuto(vec.x, vec.y, vec.z, getSetting(6).asRotate()); + if (getSetting(7).asRotate().getState()) { + WorldUtils.facePosAuto(vec.x, vec.y, vec.z, getSetting(7).asRotate()); } Hand hand = InventoryUtils.selectSlot(crystalSlot); render = block; + renderDamage = placeDamage.getOrDefault(block, 0f); mc.interactionManager.interactBlock(mc.player, hand, new BlockHitResult(vec, dir, block, false)); places++; @@ -257,22 +347,79 @@ public void onTick(EventTick event) { } } + private record ScoreResult(Map blocks, Map damage) {} + + // Read-only (world/entity queries + math, no packets/rotation/inventory changes) so it's safe + // to run off the main thread for Support. + private ScoreResult scoreCandidates(List targets, double minDmg, double minRatio) { + Map placeBlocks = new LinkedHashMap<>(); + Map placeDamage = new HashMap<>(); + + for (Vec3d v : getCrystalPoses()) { + float playerDamg = DamageUtils.getExplosionDamage(v, 6f, mc.player); + + if (DamageUtils.willKill(mc.player, playerDamg)) + continue; + + for (LivingEntity e : targets) { + float targetDamg = DamageUtils.getExplosionDamage(v, 6f, e); + if (DamageUtils.willPop(mc.player, playerDamg) && !DamageUtils.willPopOrKill(e, targetDamg)) { + continue; + } + + if (targetDamg >= minDmg) { + float ratio = playerDamg == 0 ? targetDamg : targetDamg / playerDamg; + + if (ratio > minRatio) { + BlockPos pos = BlockPos.ofFloored(v).down(); + placeBlocks.put(pos, ratio); + placeDamage.merge(pos, targetDamg, Math::max); + } + } + } + } + + Map sorted = placeBlocks.entrySet().stream() + .sorted((b1, b2) -> Float.compare(b2.getValue(), b1.getValue())) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (x, y) -> y, LinkedHashMap::new)); + + return new ScoreResult(sorted, placeDamage); + } + @BleachSubscribe public void onRenderWorld(EventWorldRender.Post event) { if (this.render != null) { int[] col = getSetting(4).asToggle().getChild(8).asColor().getRGBArray(); Renderer.drawBoxBoth(render, QuadColor.single(col[0], col[1], col[2], 100), 2.5f); + + if (getSetting(5).asToggle().getState()) { + WorldRenderer.drawText(Text.literal(String.format("%.1f", renderDamage)), + render.getX() + 0.5, render.getY() + 1.3, render.getZ() + 0.5, 1.5, true); + } } } public Set getCrystalPoses() { Set poses = new HashSet<>(); - int range = (int) Math.floor(getSetting(7).asSlider().getValue()); - for (int x = -range; x <= range; x++) { - for (int y = -range; y <= range; y++) { - for (int z = -range; z <= range; z++) { - BlockPos basePos = BlockPos.ofFloored(mc.player.getEyePos()).add(x, y, z); + double range = getSetting(8).asSlider().getValue(); + int intRange = (int) Math.floor(range); + Vec3d playerPos = mc.player.getEntityPos(); + BlockPos eyeBlock = BlockPos.ofFloored(mc.player.getEyePos()); + + for (int x = -intRange; x <= intRange; x++) { + for (int y = -intRange; y <= intRange; y++) { + for (int z = -intRange; z <= intRange; z++) { + BlockPos basePos = eyeBlock.add(x, y, z); + Vec3d pos = Vec3d.of(basePos).add(0.5, 1, 0.5); + + // Cheapest check first - the loop bounds are a cube, but the real limit is a + // sphere, so this alone skips the corners before any world/entity lookups run. + // That corner waste barely mattered against the old obsidian/bedrock-only check + // (it exits just as fast), but Support treats most of the cube as a candidate, + // so skipping it early here matters a lot more now. + if (playerPos.distanceTo(pos) > range + 0.25) + continue; if (!canPlace(basePos) || (blacklist.containsKey(basePos) && getSetting(4).asToggle().getChild(2).asToggle().getState())) continue; @@ -291,8 +438,7 @@ public Set getCrystalPoses() { } } - if (mc.player.getPos().distanceTo(Vec3d.of(basePos).add(0.5, 1, 0.5)) <= getSetting(7).asSlider().getValue() + 0.25) - poses.add(Vec3d.of(basePos).add(0.5, 1, 0.5)); + poses.add(pos); } } } @@ -300,17 +446,61 @@ public Set getCrystalPoses() { return poses; } - private boolean canPlace(BlockPos basePos) { + private boolean isSolidBase(BlockPos basePos) { BlockState baseState = mc.world.getBlockState(basePos); + return baseState.getBlock() == Blocks.BEDROCK || baseState.getBlock() == Blocks.OBSIDIAN; + } - if (baseState.getBlock() != Blocks.BEDROCK && baseState.getBlock() != Blocks.OBSIDIAN) - return false; + private boolean canPlace(BlockPos basePos) { + if (!isSolidBase(basePos)) { + boolean supportOn = getSetting(4).asToggle().getChild(9).asToggle().getState(); + if (!supportOn || !mc.world.getBlockState(basePos).isReplaceable()) + return false; + } boolean oldPlace = getSetting(4).asToggle().getChild(1).asToggle().getState(); BlockPos placePos = basePos.up(); if (!mc.world.isAir(placePos) || (oldPlace && !mc.world.isAir(placePos.up()))) return false; - return mc.world.getOtherEntities(null, new Box(placePos, placePos.up(oldPlace ? 2 : 1))).isEmpty(); + return mc.world.getOtherEntities(null, new Box(Vec3d.of(placePos), Vec3d.of(placePos.up(oldPlace ? 2 : 1)))).isEmpty(); + } + + // Meteor's AirPlace doesn't rely on any cooldown/timing trick - it just builds its own + // BlockHitResult and feeds it straight into the normal interact call, instead of the crosshair + // raycast (which reports MISS on a replaceable block and would otherwise stop vanilla from + // ever attempting a placement there). CrystalAura's own crystal placement already does exactly + // that for solid blocks, so the support block just needs the same call aimed at the air spot. + private void placeSupportBlock(BlockPos pos) { + int obsidianSlot = InventoryUtils.getSlot(true, i -> mc.player.getInventory().getStack(i).getItem() == Items.OBSIDIAN); + if (obsidianSlot == -1) { + return; + } + + Hand hand = InventoryUtils.selectSlot(obsidianSlot); + Vec3d eyeVec = mc.player.getEyePos(); + + // Prefer aiming at a real solid neighbor's face when one happens to be there, purely so the + // resulting hitResult/rotation looks legitimate - falls back to aiming straight at the + // empty spot itself, which vanilla places into directly since it's replaceable. + BlockPos clickedPos = pos; + Direction side = Direction.UP; + Vec3d vec = Vec3d.ofCenter(pos); + + for (Direction d : Direction.values()) { + BlockPos neighbor = pos.offset(d); + if (!mc.world.getBlockState(neighbor).isSolidBlock(mc.world, neighbor)) { + continue; + } + + Vec3d vd = WorldUtils.getLegitLookPos(neighbor, d.getOpposite(), true, 5); + if (vd != null && eyeVec.distanceTo(vd) <= eyeVec.distanceTo(vec)) { + vec = vd; + side = d.getOpposite(); + clickedPos = neighbor; + } + } + + mc.interactionManager.interactBlock(mc.player, hand, new BlockHitResult(vec, side, clickedPos, false)); } } diff --git a/src/main/java/org/bleachhack/module/mods/DeathExplorer.java b/src/main/java/org/bleachhack/module/mods/DeathExplorer.java index 9859ae13db..b03cb56f3e 100644 --- a/src/main/java/org/bleachhack/module/mods/DeathExplorer.java +++ b/src/main/java/org/bleachhack/module/mods/DeathExplorer.java @@ -34,7 +34,7 @@ public DeathExplorer() { public void onDisable(boolean inWorld) { if (dead && inWorld) { mc.player.setHealth(0f); - mc.setScreen(new DeathScreen(null, mc.world.getLevelProperties().isHardcore())); + mc.setScreen(new DeathScreen(null, mc.world.getLevelProperties().isHardcore(), mc.player)); } dead = false; @@ -54,7 +54,7 @@ public void onTick(EventTick event) { public void onRenderInGameHud(EventRenderInGameHud event) { if (getSetting(0).asToggle().getState()) { int length = mc.textRenderer.getWidth("You are in dead"); - mc.textRenderer.drawWithShadow(event.getMatrix(), "You are dead", mc.getWindow().getScaledWidth() / 2 - length / 2, 10, 0xcc4040); + event.getMatrix().drawTextWithShadow(mc.textRenderer, "You are dead", mc.getWindow().getScaledWidth() / 2 - length / 2, 10, 0xcc4040); } } diff --git a/src/main/java/org/bleachhack/module/mods/DiscordRPC.java b/src/main/java/org/bleachhack/module/mods/DiscordRPC.java index 4bfc5b3543..9d1683e040 100644 --- a/src/main/java/org/bleachhack/module/mods/DiscordRPC.java +++ b/src/main/java/org/bleachhack/module/mods/DiscordRPC.java @@ -112,22 +112,22 @@ public void onTick(EventTick event) { if (tick % 40 == 0) { RichPresence.Builder builder = new RichPresence.Builder() - .setLargeImage(silent ? "mc" : "bh", silent ? "Minecraft " + SharedConstants.getGameVersion().getName() : "BleachHack " + BleachHack.VERSION); + .setLargeImage(silent ? "mc" : "bh", silent ? "Minecraft " + SharedConstants.getGameVersion().name() : "BleachHack " + BleachHack.VERSION); // Top text builder.setDetails(switch (getSetting(0).asMode().getMode()) { case 0 ->"Playing " + (mc.getCurrentServerEntry() == null ? "Singleplayer" : mc.getCurrentServerEntry().address); case 1 -> mc.getCurrentServerEntry() == null ? "Singleplayer" : mc.getCurrentServerEntry().address; case 2 -> mc.getCurrentServerEntry() == null ? "Singleplayer" : "Multiplayer"; - case 3 -> mc.player.getEntityName() + " Ontop!"; - case 4 -> "Minecraft " + SharedConstants.getGameVersion().getName(); - case 5 -> mc.player.getEntityName(); + case 3 -> mc.player.getName().getString() + " Ontop!"; + case 4 -> "Minecraft " + SharedConstants.getGameVersion().name(); + case 5 -> mc.player.getName().getString(); case 6 -> "<- bad client"; default -> customText1; }); // Bottom text - ItemStack currentItem = mc.player.getInventory().getMainHandStack(); + ItemStack currentItem = mc.player.getMainHandStack(); String customName = StringUtils.strip(currentItem.getName().getString()); if (customName.length() > 25) { @@ -137,11 +137,11 @@ public void onTick(EventTick event) { String name = currentItem.getItem().getName().getString(); String itemName = currentItem.isEmpty() ? "Nothing" : (currentItem.getCount() > 1 ? currentItem.getCount() + " " : "") - + (currentItem.hasCustomName() ? customName : name); + + (currentItem.getCustomName() != null ? customName : name); builder.setState(switch (getSetting(1).asMode().getMode()) { case 0 -> (int) mc.player.getHealth() + " hp - Holding " + itemName; - case 1 -> mc.player.getEntityName() + " - " + (int) mc.player.getHealth() + " hp"; + case 1 -> mc.player.getName().getString() + " - " + (int) mc.player.getHealth() + " hp"; case 2 -> "Holding " + itemName; case 3 -> (int) mc.player.getHealth() + " hp - At " + mc.player.getBlockPos().toShortString(); case 4 -> "At " + mc.player.getBlockPos().toShortString(); diff --git a/src/main/java/org/bleachhack/module/mods/ESP.java b/src/main/java/org/bleachhack/module/mods/ESP.java index b884761783..8eaf331bf0 100644 --- a/src/main/java/org/bleachhack/module/mods/ESP.java +++ b/src/main/java/org/bleachhack/module/mods/ESP.java @@ -8,10 +8,7 @@ */ package org.bleachhack.module.mods; -import java.io.IOException; - import org.bleachhack.BleachHack; -import org.bleachhack.event.events.EventEntityRender; import org.bleachhack.event.events.EventWorldRender; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; @@ -21,15 +18,11 @@ import org.bleachhack.setting.module.SettingSlider; import org.bleachhack.setting.module.SettingToggle; import org.bleachhack.util.render.Renderer; +import org.bleachhack.util.render.ShaderEspRenderer; +import org.bleachhack.util.render.WireframeEntityRenderer; import org.bleachhack.util.render.color.QuadColor; -import org.bleachhack.util.shader.BleachCoreShaders; -import org.bleachhack.util.shader.ColorVertexConsumerProvider; -import org.bleachhack.util.shader.ShaderEffectWrapper; -import org.bleachhack.util.shader.ShaderLoader; import org.bleachhack.util.world.EntityUtils; -import com.google.gson.JsonSyntaxException; - import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.decoration.ArmorStandEntity; @@ -38,19 +31,27 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.BoatEntity; -import net.minecraft.util.Identifier; -public class ESP extends Module { +import java.util.LinkedHashMap; +import java.util.Map; - private ShaderEffectWrapper shader; - private ColorVertexConsumerProvider colorVertexer; +public class ESP extends Module { public ESP() { + this(new SettingMode("Render", "Shader", "Box", "Wireframe").withDesc("The Render mode.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Render mode + // setting as a constructor parameter first lets the predicates below capture that local + // variable instead. + private ESP(SettingMode renderMode) { super("ESP", KEY_UNBOUND, ModuleCategory.RENDER, "Highlights Entities in the world.", - new SettingMode("Render", "Shader", "Box").withDesc("The Render mode."), - new SettingSlider("ShaderFill", 1, 255, 50, 0).withDesc("How opaque the fill on shader mode should be."), - new SettingSlider("Box", 0, 5, 2, 1).withDesc("How thick the box outline should be."), - new SettingSlider("BoxFill", 0, 255, 50, 0).withDesc("How opaque the fill on box mode should be."), + renderMode, + new SettingSlider("Box", 0, 5, 2, 1).withDesc("How thick the box/wireframe outline should be.") + .visibleWhen(() -> renderMode.getMode() != 0), + new SettingSlider("BoxFill", 0, 255, 50, 0).withDesc("How opaque the fill on box/wireframe mode should be.") + .visibleWhen(() -> renderMode.getMode() != 0), new SettingToggle("Players", true).withDesc("Highlights Players.").withChildren( new SettingColor("Player Color", 255, 75, 75).withDesc("Outline color for players."), @@ -73,77 +74,71 @@ public ESP() { new SettingToggle("Armorstands", false).withDesc("Highlights armor stands.").withChildren( new SettingColor("Color", 160, 150, 50).withDesc("Outline color for armor stands."))); - - try { - shader = new ShaderEffectWrapper( - ShaderLoader.loadEffect(mc.getFramebuffer(), new Identifier("bleachhack", "shaders/post/entity_outline.json"))); - - colorVertexer = new ColorVertexConsumerProvider(shader.getFramebuffer("main"), BleachCoreShaders::getColorOverlayShader); - } catch (JsonSyntaxException | IOException e) { - throw new RuntimeException("Failed to initialize ESP Shader! loaded too early?", e); - } } @BleachSubscribe - public void onWorldRender(EventWorldRender.Pre event) { - shader.prepare(); - shader.clearFramebuffer("main"); - } - - @BleachSubscribe - public void onEntityRender(EventEntityRender.Single.Pre event) { - if (getSetting(0).asMode().getMode() != 0) - return; + public void onWorldRender(EventWorldRender.Post event) { + int mode = getSetting(0).asMode().getMode(); + float tickDelta = mc.getRenderTickCounter().getTickProgress(true); - int[] color = getColor(event.getEntity()); + if (mode == 0) { + // Shader - a real silhouette-framebuffer + Meteor glow shader, independent of vanilla's + // own Glowing-effect outline (see ShaderEspRenderer). + Map matched = new LinkedHashMap<>(); + for (Entity e: mc.world.getEntities()) { + int[] color = getColor(e); + if (color != null) { + matched.put(e, color); + } + } - if (color != null) { - event.setVertex(colorVertexer.createDualProvider(event.getVertex(), color[0], color[1], color[2], getSetting(1).asSlider().getValueInt())); + ShaderEspRenderer.render(matched, tickDelta); + return; } - } - @BleachSubscribe - public void onWorldRender(EventWorldRender.Post event) { - if (getSetting(0).asMode().getMode() == 0) { - colorVertexer.draw(); - shader.render(); - shader.drawFramebufferToMain("main"); - } else { - float width = getSetting(2).asSlider().getValueFloat(); - int fill = getSetting(3).asSlider().getValueInt(); + float width = getSetting(1).asSlider().getValueFloat(); + int fill = getSetting(2).asSlider().getValueInt(); - for (Entity e: mc.world.getEntities()) { - int[] color = getColor(e); + for (Entity e: mc.world.getEntities()) { + int[] color = getColor(e); - if (color != null) { - if (width != 0) - Renderer.drawBoxOutline(e.getBoundingBox(), QuadColor.single(color[0], color[1], color[2], 255), width); + if (color == null) { + continue; + } - if (fill != 0) - Renderer.drawBoxFill(e.getBoundingBox(), QuadColor.single(color[0], color[1], color[2], fill)); - } + if (mode == 2) { + // Wireframe - Meteor draws the entity's actual posed model as a wireframe here instead + // of a bounding box (see WireframeEntityRenderer), reusing the same width/fill sliders. + WireframeEntityRenderer.render(e, tickDelta, color[0], color[1], color[2], fill, width); + continue; } + + if (width != 0) + Renderer.drawBoxOutline(e.getBoundingBox(), QuadColor.single(color[0], color[1], color[2], 255), width); + + if (fill != 0) + Renderer.drawBoxFill(e.getBoundingBox(), QuadColor.single(color[0], color[1], color[2], fill)); } } - private int[] getColor(Entity e) { + public int[] getColor(Entity e) { if (e == mc.player) return null; - if (e instanceof PlayerEntity && getSetting(4).asToggle().getState()) { - return getSetting(4).asToggle().getChild(BleachHack.friendMang.has(e) ? 1 : 0).asColor().getRGBArray(); - } else if (e instanceof Monster && getSetting(5).asToggle().getState()) { + if (e instanceof PlayerEntity && getSetting(3).asToggle().getState()) { + return getSetting(3).asToggle().getChild(BleachHack.friendMang.has(e) ? 1 : 0).asColor().getRGBArray(); + } else if (e instanceof Monster && getSetting(4).asToggle().getState()) { + return getSetting(4).asToggle().getChild(0).asColor().getRGBArray(); + } else if (EntityUtils.isAnimal(e) && getSetting(5).asToggle().getState()) { return getSetting(5).asToggle().getChild(0).asColor().getRGBArray(); - } else if (EntityUtils.isAnimal(e) && getSetting(6).asToggle().getState()) { + } else if (e instanceof ItemEntity && getSetting(6).asToggle().getState()) { return getSetting(6).asToggle().getChild(0).asColor().getRGBArray(); - } else if (e instanceof ItemEntity && getSetting(7).asToggle().getState()) { + } else if (e instanceof EndCrystalEntity && getSetting(7).asToggle().getState()) { return getSetting(7).asToggle().getChild(0).asColor().getRGBArray(); - } else if (e instanceof EndCrystalEntity && getSetting(8).asToggle().getState()) { + } else if ((e instanceof BoatEntity || e instanceof AbstractMinecartEntity) && getSetting(8).asToggle().getState()) { return getSetting(8).asToggle().getChild(0).asColor().getRGBArray(); - } else if ((e instanceof BoatEntity || e instanceof AbstractMinecartEntity) && getSetting(9).asToggle().getState()) { + } else if (e instanceof ArmorStandEntity && getSetting(9).asToggle().getState()) { return getSetting(9).asToggle().getChild(0).asColor().getRGBArray(); - } else if (e instanceof ArmorStandEntity && getSetting(10).asToggle().getState()) { - return getSetting(10).asToggle().getChild(0).asColor().getRGBArray(); } return null; diff --git a/src/main/java/org/bleachhack/module/mods/ElytraFly.java b/src/main/java/org/bleachhack/module/mods/ElytraFly.java index 4752353353..82fc120643 100644 --- a/src/main/java/org/bleachhack/module/mods/ElytraFly.java +++ b/src/main/java/org/bleachhack/module/mods/ElytraFly.java @@ -19,6 +19,7 @@ import org.bleachhack.setting.module.SettingMode; import org.bleachhack.setting.module.SettingSlider; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.item.Items; import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket.Mode; @@ -30,18 +31,29 @@ public class ElytraFly extends Module { public ElytraFly() { + this(new SettingMode("Mode", "AutoBoost", "Boost", "Control", "BruhFly", "Pak\u00e8tFly").withDesc("Elytrafly mode.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicates below capture that local variable instead. + private ElytraFly(SettingMode mode) { super("ElytraFly", KEY_UNBOUND, ModuleCategory.MOVEMENT, "Improves the elytra.", - new SettingMode("Mode", "AutoBoost", "Boost", "Control", "BruhFly", "Pak\u00e8tFly").withDesc("Elytrafly mode."), - new SettingSlider("Boost", 0, 0.15, 0.05, 2).withDesc("Boost speed."), - new SettingSlider("MaxBoost", 0, 5, 2.5, 1).withDesc("Max boost speed."), - new SettingSlider("Speed", 0, 5, 0.8, 2).withDesc("Speed for all the other modes."), - new SettingSlider("Packets", 1, 10, 2, 0).withDesc("How many packets to send in packet mode.")); + mode, + new SettingSlider("Boost", 0, 0.15, 0.05, 2).withDesc("Boost speed.") + .visibleWhen(() -> mode.getMode() <= 1), + new SettingSlider("MaxBoost", 0, 5, 2.5, 1).withDesc("Max boost speed.") + .visibleWhen(() -> mode.getMode() <= 1), + new SettingSlider("Speed", 0, 5, 0.8, 2).withDesc("Speed for all the other modes.") + .visibleWhen(() -> mode.getMode() >= 2), + new SettingSlider("Packets", 1, 10, 2, 0).withDesc("How many packets to send in packet mode.") + .visibleWhen(() -> mode.getMode() == 4)); } @BleachSubscribe public void onClientMove(EventClientMove event) { /* Cancel the retarded auto elytra movement */ - if (getSetting(0).asMode().getMode() == 2 && mc.player.isFallFlying()) { + if (getSetting(0).asMode().getMode() == 2 && mc.player.isGliding()) { if (!mc.options.jumpKey.isPressed() && !mc.options.sneakKey.isPressed()) { event.setVec(new Vec3d(event.getVec().x, 0, event.getVec().z)); } @@ -64,7 +76,7 @@ public void onTick(EventTick event) { switch (getSetting(0).asMode().getMode()) { case 0: - if (mc.player.isFallFlying() && currentVel <= getSetting(2).asSlider().getValue()) { + if (mc.player.isGliding() && currentVel <= getSetting(2).asSlider().getValue()) { if (mc.options.backKey.isPressed()) { mc.player.addVelocity(MathHelper.sin(radianYaw) * boost, 0, MathHelper.cos(radianYaw) * -boost); } else if (mc.player.getPitch() > 0) { @@ -74,7 +86,7 @@ public void onTick(EventTick event) { break; case 1: - if (mc.player.isFallFlying() && currentVel <= getSetting(2).asSlider().getValue()) { + if (mc.player.isGliding() && currentVel <= getSetting(2).asSlider().getValue()) { if (mc.options.forwardKey.isPressed()) { mc.player.addVelocity(MathHelper.sin(radianYaw) * -boost, 0, MathHelper.cos(radianYaw) * boost); } else if (mc.options.backKey.isPressed()) { @@ -84,7 +96,7 @@ public void onTick(EventTick event) { break; case 2: - if (mc.player.isFallFlying()) { + if (mc.player.isGliding()) { if (mc.options.backKey.isPressed()) vec3d = vec3d.negate(); if (mc.options.leftKey.isPressed()) vec3d = vec3d.rotateY((float) Math.toRadians(90)); else if (mc.options.rightKey.isPressed()) vec3d = vec3d.rotateY(-(float) Math.toRadians(90)); @@ -92,7 +104,7 @@ public void onTick(EventTick event) { if (mc.options.sneakKey.isPressed()) vec3d = vec3d.add(0, -getSetting(3).asSlider().getValue(), 0); mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( - mc.player.getX() + vec3d.x, mc.player.getY() - 0.01, mc.player.getZ() + vec3d.z, false)); + mc.player.getX() + vec3d.x, mc.player.getY() - 0.01, mc.player.getZ() + vec3d.z, false, false)); mc.player.setVelocity(vec3d.x, vec3d.y, vec3d.z); } @@ -103,7 +115,7 @@ public void onTick(EventTick event) { mc.player.setVelocity(vec3d); mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, Mode.START_FALL_FLYING)); mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( - mc.player.getX() + vec3d.x, mc.player.getY() + vec3d.y, mc.player.getZ() + vec3d.z, true)); + mc.player.getX() + vec3d.x, mc.player.getY() + vec3d.y, mc.player.getZ() + vec3d.z, true, false)); } break; @@ -116,14 +128,14 @@ public void onTick(EventTick event) { mc.player.getX() + vec3d.x * randMult, mc.player.getY(), mc.player.getZ() + vec3d.z * randMult, - false)); + false, false)); for (int i = 0; i < 6; i++) { mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( mc.player.getX() + vec3d.x * (randMult + i), mc.player.getY() - 0.0001, mc.player.getZ() + vec3d.z * (randMult + i), - true)); + true, false)); } } } @@ -149,10 +161,10 @@ public void onMovement(EventClientMove event) { @BleachSubscribe public void onReadPacket(EventPacket.Read event) { if (getSetting(0).asMode().getMode() == 4 && shouldPacketFly() && event.getPacket() instanceof PlayerPositionLookS2CPacket) { + // 1.19.4 had direct yaw/pitch float fields; 1.21.11 merged them into a nested EntityPosition + // record ("change" field) - widened mutable via accesswidener, replaced via withRotation(...). PlayerPositionLookS2CPacket p = (PlayerPositionLookS2CPacket) event.getPacket(); - - p.yaw = mc.player.getYaw(); - p.pitch = mc.player.getPitch(); + p.change = p.change().withRotation(mc.player.getYaw(), mc.player.getPitch()); } } @@ -167,7 +179,7 @@ public void onSendPacket(EventPacket.Send event) { if (event.getPacket() instanceof PlayerMoveC2SPacket.Full) { event.setCancelled(true); PlayerMoveC2SPacket p = (PlayerMoveC2SPacket) event.getPacket(); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(p.getX(0), p.getY(0), p.getZ(0), p.isOnGround())); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(p.getX(0), p.getY(0), p.getZ(0), p.isOnGround(), false)); } } } @@ -175,6 +187,6 @@ public void onSendPacket(EventPacket.Send event) { private boolean shouldPacketFly() { return !mc.player.isOnGround() && !mc.options.sneakKey.isPressed() - && mc.player.getInventory().getArmorStack(2).getItem() == Items.ELYTRA; + && mc.player.getEquippedStack(EquipmentSlot.CHEST).getItem() == Items.ELYTRA; } } diff --git a/src/main/java/org/bleachhack/module/mods/ElytraReplace.java b/src/main/java/org/bleachhack/module/mods/ElytraReplace.java index 6d412b502b..dfcff9d4c6 100644 --- a/src/main/java/org/bleachhack/module/mods/ElytraReplace.java +++ b/src/main/java/org/bleachhack/module/mods/ElytraReplace.java @@ -13,7 +13,6 @@ import org.bleachhack.module.Module; import org.bleachhack.module.ModuleCategory; -import net.minecraft.item.ElytraItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.screen.slot.SlotActionType; @@ -33,13 +32,13 @@ public void onTick(EventTick event) { int chestSlot = 38; ItemStack chest = mc.player.getInventory().getStack(chestSlot); - if (chest.getItem() instanceof ElytraItem && chest.getDamage() == (Items.ELYTRA.getMaxDamage() - 1)) { + if (chest.isOf(Items.ELYTRA) && chest.getDamage() == (chest.getMaxDamage() - 1)) { // search inventory for elytra Integer elytraSlot = null; for (int slot = 0; slot < 36; slot++) { ItemStack stack = mc.player.getInventory().getStack(slot); - if (stack.getItem() instanceof ElytraItem && stack.getDamage() != (Items.ELYTRA.getMaxDamage() - 1)) { + if (stack.isOf(Items.ELYTRA) && stack.getDamage() != (stack.getMaxDamage() - 1)) { elytraSlot = slot; break; } diff --git a/src/main/java/org/bleachhack/module/mods/EntityControl.java b/src/main/java/org/bleachhack/module/mods/EntityControl.java index e38ca8c285..e8cb2db746 100644 --- a/src/main/java/org/bleachhack/module/mods/EntityControl.java +++ b/src/main/java/org/bleachhack/module/mods/EntityControl.java @@ -101,8 +101,8 @@ public void onTick(EventTick event) { } if (getSetting(3).asToggle().getState()) { - BlockPos p = BlockPos.ofFloored(e.getPos()); - if (!mc.world.getBlockState(p.down()).getMaterial().isReplaceable() && e.fallDistance > 0.01) { + BlockPos p = BlockPos.ofFloored(e.getEntityPos()); + if (!mc.world.getBlockState(p.down()).isReplaceable() && e.fallDistance > 0.01) { e.setVelocity(e.getVelocity().x, -1, e.getVelocity().z); } } @@ -143,7 +143,7 @@ && getSetting(6).asToggle().getChild(2).asToggle().getState()) { @BleachSubscribe public void onReadPacket(EventPacket.Read event) { - if (getSetting(7).asToggle().getState() && mc.player != null && mc.player.hasVehicle() && !mc.player.input.sneaking + if (getSetting(7).asToggle().getState() && mc.player != null && mc.player.hasVehicle() && !mc.player.input.playerInput.sneak() && (event.getPacket() instanceof PlayerPositionLookS2CPacket || event.getPacket() instanceof EntityPassengersSetS2CPacket)) { event.setCancelled(true); } diff --git a/src/main/java/org/bleachhack/module/mods/FastUse.java b/src/main/java/org/bleachhack/module/mods/FastUse.java index a5e9afbecb..1d55d0a027 100644 --- a/src/main/java/org/bleachhack/module/mods/FastUse.java +++ b/src/main/java/org/bleachhack/module/mods/FastUse.java @@ -30,9 +30,17 @@ public class FastUse extends Module { Items.ENDER_EYE, Items.ENDER_PEARL, Items.SPLASH_POTION, Items.LINGERING_POTION); public FastUse() { + this(new SettingMode("Mode", "Single", "Multi").withDesc("Whether to throw once per tick or multiple times.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicate below capture that local variable instead. + private FastUse(SettingMode mode) { super("FastUse", KEY_UNBOUND, ModuleCategory.PLAYER, "Allows you to use items faster.", - new SettingMode("Mode", "Single", "Multi").withDesc("Whether to throw once per tick or multiple times."), - new SettingSlider("Multi", 1, 100, 20, 0).withDesc("How many items to use per tick if on multi mode."), + mode, + new SettingSlider("Multi", 1, 100, 20, 0).withDesc("How many items to use per tick if on multi mode.") + .visibleWhen(() -> mode.getMode() == 1), new SettingToggle("Throwables Only", true).withDesc("Only uses throwables.").withChildren( new SettingToggle("XP Only", false).withDesc("Only uses XP bottles."))); } diff --git a/src/main/java/org/bleachhack/module/mods/Flight.java b/src/main/java/org/bleachhack/module/mods/Flight.java index 7aff2fcf69..817e7dbfd2 100644 --- a/src/main/java/org/bleachhack/module/mods/Flight.java +++ b/src/main/java/org/bleachhack/module/mods/Flight.java @@ -45,8 +45,8 @@ public void onTick(EventTick event) { float speed = getSetting(1).asSlider().getValueFloat(); if (mc.player.age % 20 == 0 && getSetting(2).asMode().getMode() == 3 && !(getSetting(0).asMode().getMode() == 1)) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() - 0.069, mc.player.getZ(), false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getZ() + 0.069, mc.player.getZ(), true)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() - 0.069, mc.player.getZ(), false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 0.069, mc.player.getZ(), true, mc.player.horizontalCollision)); } if (getSetting(0).asMode().getMode() == 0) { @@ -54,15 +54,15 @@ public void onTick(EventTick event) { if (getSetting(2).asMode().getMode() == 1 && mc.player.age % 20 == 0 - && mc.world.getBlockState(BlockPos.ofFloored(mc.player.getPos().add(0, -0.069, 0))).getMaterial().isReplaceable()) { + && mc.world.getBlockState(BlockPos.ofFloored(mc.player.getEntityPos().add(0, -0.069, 0))).isReplaceable()) { antiKickVel = antiKickVel.add(0, -0.069, 0); } else if (getSetting(2).asMode().getMode() == 2) { if (mc.player.age % 40 == 0) { - if (mc.world.getBlockState(BlockPos.ofFloored(mc.player.getPos().add(0, 0.15, 0))).getMaterial().isReplaceable()) { + if (mc.world.getBlockState(BlockPos.ofFloored(mc.player.getEntityPos().add(0, 0.15, 0))).isReplaceable()) { antiKickVel = antiKickVel.add(0, 0.15, 0); } } else if (mc.player.age % 20 == 0) { - if (mc.world.getBlockState(BlockPos.ofFloored(mc.player.getPos().add(0, -0.15, 0))).getMaterial().isReplaceable()) { + if (mc.world.getBlockState(BlockPos.ofFloored(mc.player.getEntityPos().add(0, -0.15, 0))).isReplaceable()) { antiKickVel = antiKickVel.add(0, -0.15, 0); } } @@ -91,14 +91,18 @@ public void onTick(EventTick event) { return; mc.player.setVelocity(mc.player.getVelocity().x, speed / 3, mc.player.getVelocity().z); } else if (getSetting(0).asMode().getMode() == 2) { - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), InputUtil.fromTranslationKey(mc.options.jumpKey.getBoundKeyTranslationKey()).getCode())) { + if (InputUtil.isKeyPressed(mc.getWindow(), InputUtil.fromTranslationKey(mc.options.jumpKey.getBoundKeyTranslationKey()).getCode())) { mc.player.jump(); } else { - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), InputUtil.fromTranslationKey(mc.options.jumpKey.getBoundKeyTranslationKey()).getCode())) { + if (InputUtil.isKeyPressed(mc.getWindow(), InputUtil.fromTranslationKey(mc.options.jumpKey.getBoundKeyTranslationKey()).getCode())) { mc.player.updatePosition(mc.player.getX(), mc.player.getY() - speed / 10f, mc.player.getZ()); } } } + + // Keep the client's fall distance at zero the whole time you're flying, in every mode - + // otherwise descending (even slowly) racks up fall damage the moment you touch down. + mc.player.fallDistance = 0; } @BleachSubscribe diff --git a/src/main/java/org/bleachhack/module/mods/Ghosthand.java b/src/main/java/org/bleachhack/module/mods/Ghosthand.java index 34837e662f..a2f893363b 100644 --- a/src/main/java/org/bleachhack/module/mods/Ghosthand.java +++ b/src/main/java/org/bleachhack/module/mods/Ghosthand.java @@ -36,7 +36,7 @@ public void onTick(EventTick event) { return; // Return if we are looking at any block entities - BlockPos lookingPos = BlockPos.ofFloored(mc.player.raycast(4.25, mc.getTickDelta(), false).getPos()); + BlockPos lookingPos = BlockPos.ofFloored(mc.player.raycast(4.25, mc.getRenderTickCounter().getTickProgress(true), false).getPos()); for (BlockEntity b : WorldUtils.getBlockEntities()) { if (lookingPos.equals(b.getPos())) { return; @@ -50,7 +50,7 @@ public void onTick(EventTick event) { .rotateY(-(float) Math.toRadians(mc.player.getYaw())); for (int i = 1; i < 50; i++) { - BlockPos curPos = BlockPos.ofFloored(mc.player.getCameraPosVec(mc.getTickDelta()).add(nextPos.multiply(i))); + BlockPos curPos = BlockPos.ofFloored(mc.player.getCameraPosVec(mc.getRenderTickCounter().getTickProgress(true)).add(nextPos.multiply(i))); if (!posList.contains(curPos)) { posList.add(curPos); diff --git a/src/main/java/org/bleachhack/module/mods/HoleESP.java b/src/main/java/org/bleachhack/module/mods/HoleESP.java index 3c27d522ec..482396127d 100644 --- a/src/main/java/org/bleachhack/module/mods/HoleESP.java +++ b/src/main/java/org/bleachhack/module/mods/HoleESP.java @@ -12,6 +12,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; import org.apache.commons.lang3.ArrayUtils; import org.bleachhack.event.events.EventTick; import org.bleachhack.event.events.EventWorldRender; @@ -37,16 +38,29 @@ public class HoleESP extends Module { private Map holes = new HashMap<>(); public HoleESP() { + this(new SettingMode("Render", "Box+Fill", "Box", "Fill").withDesc("The rendering method."), + new SettingMode("Render", "GlowUp", "GlowDown", "Box+Fill", "Box", "Fill").withDesc("The rendering method.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the two Render mode + // settings as constructor parameters first lets the predicates below capture those local + // variables instead, even though they're nested inside RenderBottom's/RenderSides' children. + private HoleESP(SettingMode bottomRenderMode, SettingMode sideRenderMode) { super("HoleESP", KEY_UNBOUND, ModuleCategory.RENDER, "Highlights safe and not so safe holes. Used for Crystalpvp.", new SettingSlider("Radius", 1, 20, 10, 0).withDesc("Radius in which holes are getting searched."), new SettingToggle("RenderBottom", true).withDesc("Render the bottom of holes.").withChildren( - new SettingMode("Render", "Box+Fill", "Box", "Fill").withDesc("The rendering method."), - new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The thickness of the box lines."), - new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill.")), + bottomRenderMode, + new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The thickness of the box lines.") + .visibleWhen(() -> bottomRenderMode.getMode() != 2), + new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill.") + .visibleWhen(() -> bottomRenderMode.getMode() != 1)), new SettingToggle("RenderSides", true).withDesc("Render the sides of holes.").withChildren( - new SettingMode("Render", "GlowUp", "GlowDown", "Box+Fill", "Box", "Fill").withDesc("The rendering method."), - new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The thickness of the box lines."), - new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill/glow"), + sideRenderMode, + new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The thickness of the box lines.") + .visibleWhen(() -> sideRenderMode.getMode() == 2 || sideRenderMode.getMode() == 3), + new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill/glow") + .visibleWhen(() -> sideRenderMode.getMode() != 3), new SettingSlider("Height", 0.1, 8, 1, 1).withDesc("The height to render the sides.")), new SettingToggle("Bedrock", true).withDesc("Shows holes with full bedrock.").withChildren( new SettingColor("Color", 0, 255, 0).withDesc("Color for bedrock holes.")), @@ -141,20 +155,20 @@ public void onRender(EventWorldRender.Post event) { CardinalDirection gradientDir = sideMode == 0 ? CardinalDirection.NORTH : CardinalDirection.SOUTH; holes.forEach((pos, color) -> - Renderer.drawBoxFill(new Box(pos, pos.add(1, 0, 1)).stretch(0, height, 0), + Renderer.drawBoxFill(new Box(Vec3d.of(pos), Vec3d.of(pos.add(1, 0, 1))).stretch(0, height, 0), QuadColor.gradient( color[0], color[1], color[2], alpha, color[0], color[1], color[2], 0, gradientDir), excludeDirs)); } else { if (sideMode == 2 || sideMode == 4) { holes.forEach((pos, color) -> - Renderer.drawBoxFill(new Box(pos, pos.add(1, 0, 1)).stretch(0, height, 0), + Renderer.drawBoxFill(new Box(Vec3d.of(pos), Vec3d.of(pos.add(1, 0, 1))).stretch(0, height, 0), QuadColor.single(color[0], color[1], color[2], alpha), excludeDirs)); } if (sideMode == 2 || sideMode == 3) { holes.forEach((pos, color) -> - Renderer.drawBoxOutline(new Box(pos, pos.add(1, 0, 1)).stretch(0, height, 0), + Renderer.drawBoxOutline(new Box(Vec3d.of(pos), Vec3d.of(pos.add(1, 0, 1))).stretch(0, height, 0), QuadColor.single(color[0], color[1], color[2], 255), getSetting(2).asToggle().getChild(1).asSlider().getValueFloat(), excludeDirs)); } } diff --git a/src/main/java/org/bleachhack/module/mods/InfiniteReach.java b/src/main/java/org/bleachhack/module/mods/InfiniteReach.java new file mode 100644 index 0000000000..7dc2fbcd85 --- /dev/null +++ b/src/main/java/org/bleachhack/module/mods/InfiniteReach.java @@ -0,0 +1,237 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.module.mods; + +import org.bleachhack.event.events.EventTick; +import org.bleachhack.event.events.EventWorldRender; +import org.bleachhack.eventbus.BleachSubscribe; +import org.bleachhack.module.Module; +import org.bleachhack.module.ModuleCategory; +import org.bleachhack.setting.module.SettingColor; +import org.bleachhack.setting.module.SettingMode; +import org.bleachhack.setting.module.SettingSlider; +import org.bleachhack.setting.module.SettingToggle; +import org.bleachhack.util.render.Renderer; +import org.bleachhack.util.render.color.QuadColor; +import org.bleachhack.util.world.WorldUtils; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.projectile.ProjectileUtil; +import net.minecraft.item.Items; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RaycastContext; + +/** + * Ported from Trouser-Streak's InfiniteReach (https://github.com/etianl/Trouser-Streak). + */ +public class InfiniteReach extends Module { + + private int cooldown; + private Entity hoveredTarget; + private BlockHitResult hoveredBlock; + + public InfiniteReach() { + this(new SettingMode("Mode", "Vanilla", "Paper").withDesc("Vanilla: reach capped at 22 blocks. Paper: a much longer reach is often possible."), + new SettingToggle("Auto Calculate Packets", true).withDesc("Scales the spam packet count based on the clip distance instead of using a fixed amount.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the settings other + // settings react to as constructor parameters first lets the predicates below capture those + // local variables instead. + private InfiniteReach(SettingMode compatMode, SettingToggle autoPackets) { + super("InfiniteReach", KEY_UNBOUND, ModuleCategory.EXPLOITS, "Attacks/mines far beyond normal reach by teleporting there and back for a single packet.", + compatMode, + new SettingSlider("Distance", 1, 22, 22, 0).withDesc("How far away you can attack/mine.") + .visibleWhen(() -> compatMode.getMode() == 0), + new SettingSlider("Distance", 1, 99, 59, 0).withDesc("How far away you can attack/mine.") + .visibleWhen(() -> compatMode.getMode() == 1), + new SettingToggle("Clip Up", true).withDesc("Paper only: hops above yourself and the target before landing on it, instead of a straight teleport - also works as a Mace Smash and routes around obstacles.") + .visibleWhen(() -> compatMode.getMode() == 1), + autoPackets, + new SettingSlider("Packets", 1, 17, 4, 0).withDesc("Fixed spam packet count, used when Auto Calculate Packets is off.") + .visibleWhen(() -> !autoPackets.getState()), + new SettingSlider("Delay", 1, 20, 5, 0).withDesc("Ticks to wait between attacks/mines."), + new SettingToggle("Only With Mace", false).withDesc("Only reach-attacks while holding a Mace and the target isn't blocking."), + new SettingToggle("Swing Arm", true).withDesc("Swings your hand on your screen for visual feedback."), + new SettingToggle("Raycast", false).withDesc("Only attacks/mines if you can see the target - defeats the point of reaching through walls, so off by default."), + new SettingToggle("Highlight", true).withDesc("Draws an outline around whatever you're currently targeting.").withChildren( + new SettingColor("Color", 255, 60, 60))); + } + + private double getMaxDistance() { + return getSetting(0).asMode().getMode() == 0 ? getSetting(1).asSlider().getValue() : getSetting(2).asSlider().getValue(); + } + + @Override + public void onDisable(boolean inWorld) { + hoveredTarget = null; + hoveredBlock = null; + super.onDisable(inWorld); + } + + @BleachSubscribe + public void onTick(EventTick event) { + double maxDistance = getMaxDistance(); + + Vec3d eyePos = mc.player.getEyePos(); + Vec3d look = mc.player.getRotationVec(1f); + Vec3d endVec = eyePos.add(look.multiply(maxDistance)); + + EntityHitResult entityHit = ProjectileUtil.raycast(mc.player, eyePos, endVec, + mc.player.getBoundingBox().stretch(look.multiply(maxDistance)).expand(1), + e -> e.isAlive() && e.isAttackable() && !e.isInvulnerable() && e != mc.player, + maxDistance * maxDistance); + + hoveredTarget = entityHit != null ? entityHit.getEntity() : null; + hoveredBlock = null; + + if (hoveredTarget == null) { + BlockHitResult blockHit = (BlockHitResult) mc.world.raycast(new RaycastContext(eyePos, endVec, + RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)); + + if (!mc.world.getBlockState(blockHit.getBlockPos()).isAir()) { + hoveredBlock = blockHit; + } + } + + if (cooldown > 0) { + cooldown--; + return; + } + + boolean attacking = mc.options.attackKey.isPressed(); + boolean using = mc.options.useKey.isPressed(); + if (!attacking && !using) { + return; + } + + if (hoveredTarget instanceof LivingEntity target) { + if (getSetting(7).asToggle().getState() + && (mc.player.getMainHandStack().getItem() != Items.MACE || target.isBlocking())) { + return; + } + + if (getSetting(9).asToggle().getState() && !mc.player.canSee(target)) { + return; + } + + attackEntity(target, attacking); + cooldown = getSetting(6).asSlider().getValueInt(); + } else if (hoveredBlock != null && attacking) { + attackBlock(hoveredBlock); + cooldown = getSetting(6).asSlider().getValueInt(); + } + } + + private void attackEntity(LivingEntity target, boolean attacking) { + Vec3d home = mc.player.getEntityPos(); + double distance = home.distanceTo(target.getEntityPos()); + + Vec3d landing = target.getEntityPos(); + if (WorldUtils.isTeleportUnsafe(mc.player, landing)) { + landing = WorldUtils.findSafeOffset(mc.player, landing, 0.4, 0); + } + + spamStatusPackets(distance); + + // Clip Up: hop above yourself and above the target before landing, instead of teleporting + // straight there - this both routes around anything blocking a direct line to the target + // and, since you land as if falling, doubles as a Mace Smash. + boolean clipUp = getSetting(0).asMode().getMode() == 1 && getSetting(3).asToggle().getState(); + if (clipUp) { + Vec3d aboveSelf = home.add(0, distance, 0); + Vec3d aboveTarget = landing.add(0, distance, 0); + if (!WorldUtils.isTeleportUnsafe(mc.player, aboveSelf) && !WorldUtils.isTeleportUnsafe(mc.player, aboveTarget)) { + WorldUtils.sendTeleport(aboveSelf); + WorldUtils.sendTeleport(aboveTarget); + } + } + + WorldUtils.sendTeleport(landing); + + if (attacking) { + mc.player.networkHandler.sendPacket(PlayerInteractEntityC2SPacket.attack(target, mc.player.isSneaking())); + } else { + mc.player.networkHandler.sendPacket(PlayerInteractEntityC2SPacket.interact(target, mc.player.isSneaking(), Hand.MAIN_HAND)); + } + + if (getSetting(8).asToggle().getState()) { + mc.player.networkHandler.sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + mc.player.swingHand(Hand.MAIN_HAND); + } + + if (clipUp) { + WorldUtils.sendTeleport(landing.add(0, distance, 0).add(0, 0.01, 0)); + WorldUtils.sendTeleport(home.add(0, distance, 0).add(0, 0.01, 0)); + } + + WorldUtils.sendTeleport(home); + WorldUtils.sendTeleport(WorldUtils.findSafeOffset(mc.player, home, 0.05, 0.01)); + } + + private void attackBlock(BlockHitResult blockHit) { + Vec3d home = mc.player.getEntityPos(); + BlockPos pos = blockHit.getBlockPos(); + double distance = home.distanceTo(Vec3d.ofCenter(pos)); + + Vec3d landing = WorldUtils.findSafeOffset(mc.player, Vec3d.ofCenter(pos), 0.4, 0); + + spamStatusPackets(distance); + WorldUtils.sendTeleport(landing); + + mc.player.networkHandler.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, pos, blockHit.getSide())); + mc.player.networkHandler.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, pos, blockHit.getSide())); + + if (getSetting(8).asToggle().getState()) { + mc.player.networkHandler.sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + mc.player.swingHand(Hand.MAIN_HAND); + } + + WorldUtils.sendTeleport(home); + WorldUtils.sendTeleport(WorldUtils.findSafeOffset(mc.player, home, 0.05, 0.01)); + } + + // Auto Calculate Packets scales the spam count with the actual clip distance - a longer clip + // is a bigger, more suspicious jump and needs more "you're grounded" spam beforehand. + private void spamStatusPackets(double distance) { + int count = getSetting(4).asToggle().getState() + ? Math.min(17, Math.max(1, (int) Math.ceil(distance / 5.0))) + : getSetting(5).asSlider().getValueInt(); + + for (int i = 0; i < count; i++) { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(false, mc.player.horizontalCollision)); + } + } + + @BleachSubscribe + public void onWorldRender(EventWorldRender.Post event) { + if (!getSetting(10).asToggle().getState()) { + return; + } + + int[] rgb = getSetting(10).asToggle().getChild(0).asColor().getRGBArray(); + + if (hoveredTarget != null) { + Renderer.drawBoxOutline(hoveredTarget.getBoundingBox(), QuadColor.single(rgb[0], rgb[1], rgb[2], 255), 2f); + } else if (hoveredBlock != null) { + Renderer.drawBoxOutline(hoveredBlock.getBlockPos(), QuadColor.single(rgb[0], rgb[1], rgb[2], 255), 2f); + } + } + +} diff --git a/src/main/java/org/bleachhack/module/mods/Jesus.java b/src/main/java/org/bleachhack/module/mods/Jesus.java index c746e18a6a..6a13796ac4 100644 --- a/src/main/java/org/bleachhack/module/mods/Jesus.java +++ b/src/main/java/org/bleachhack/module/mods/Jesus.java @@ -35,13 +35,13 @@ public void onTick(EventTick event) { if (e.isSneaking() || e.fallDistance > 3f) return; - if (isSubmerged(e.getPos().add(0, 0.3, 0))) { + if (isSubmerged(e.getEntityPos().add(0, 0.3, 0))) { e.setVelocity(e.getVelocity().x, 0.08, e.getVelocity().z); - } else if (isSubmerged(e.getPos().add(0, 0.1, 0))) { + } else if (isSubmerged(e.getEntityPos().add(0, 0.1, 0))) { e.setVelocity(e.getVelocity().x, 0.05, e.getVelocity().z); - } else if (isSubmerged(e.getPos().add(0, 0.05, 0))) { + } else if (isSubmerged(e.getEntityPos().add(0, 0.05, 0))) { e.setVelocity(e.getVelocity().x, 0.01, e.getVelocity().z); - } else if (isSubmerged(e.getPos())) { + } else if (isSubmerged(e.getEntityPos())) { e.setVelocity(e.getVelocity().x, -0.005, e.getVelocity().z); e.setOnGround(true); } diff --git a/src/main/java/org/bleachhack/module/mods/Killaura.java b/src/main/java/org/bleachhack/module/mods/Killaura.java index 4e4da441b3..b46ccd2afe 100644 --- a/src/main/java/org/bleachhack/module/mods/Killaura.java +++ b/src/main/java/org/bleachhack/module/mods/Killaura.java @@ -72,7 +72,7 @@ public void onTick(EventTick event) { int reqDelay = (int) Math.rint(20 / getSetting(12).asSlider().getValue()); boolean cooldownDone = getSetting(10).asToggle().getState() - ? mc.player.getAttackCooldownProgress(mc.getTickDelta()) == 1.0f + ? mc.player.getAttackCooldownProgress(mc.getRenderTickCounter().getTickProgress(true)) == 1.0f : (delay > reqDelay || reqDelay == 0); if (cooldownDone) { diff --git a/src/main/java/org/bleachhack/module/mods/LogoutSpot.java b/src/main/java/org/bleachhack/module/mods/LogoutSpot.java index deeeaa2586..ddaf9657e4 100644 --- a/src/main/java/org/bleachhack/module/mods/LogoutSpot.java +++ b/src/main/java/org/bleachhack/module/mods/LogoutSpot.java @@ -139,9 +139,9 @@ public void onPostEntityRender(EventEntityRender.PostAll event) { if (getSetting(1).asToggle().getState()) { PlayerCopyEntity player = playerPair.getLeft(); - Vec3d rVec = new Vec3d(player.lastRenderX + (player.getX() - player.lastRenderX) * mc.getTickDelta(), - player.lastRenderY + (player.getY() - player.lastRenderY) * mc.getTickDelta() + player.getHeight(), - player.lastRenderZ + (player.getZ() - player.lastRenderZ) * mc.getTickDelta()); + Vec3d rVec = new Vec3d(player.lastRenderX + (player.getX() - player.lastRenderX) * mc.getRenderTickCounter().getTickProgress(true), + player.lastRenderY + (player.getY() - player.lastRenderY) * mc.getRenderTickCounter().getTickProgress(true) + player.getHeight(), + player.lastRenderZ + (player.getZ() - player.lastRenderZ) * mc.getRenderTickCounter().getTickProgress(true)); Vec3d offset = new Vec3d(0, 0, 0.45 + mc.textRenderer.getWidth(player.getDisplayName().getString()) / 90d) .rotateY((float) -Math.toRadians(mc.player.getYaw() + 90)); diff --git a/src/main/java/org/bleachhack/module/mods/MaceKill.java b/src/main/java/org/bleachhack/module/mods/MaceKill.java new file mode 100644 index 0000000000..6a3daf6b75 --- /dev/null +++ b/src/main/java/org/bleachhack/module/mods/MaceKill.java @@ -0,0 +1,179 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.module.mods; + +import org.bleachhack.event.events.EventPacket; +import org.bleachhack.event.events.EventTick; +import org.bleachhack.eventbus.BleachSubscribe; +import org.bleachhack.module.Module; +import org.bleachhack.module.ModuleCategory; +import org.bleachhack.setting.module.SettingSlider; +import org.bleachhack.setting.module.SettingToggle; +import org.bleachhack.util.PlayerInteractEntityC2SUtils; +import org.bleachhack.util.PlayerInteractEntityC2SUtils.InteractType; +import org.bleachhack.util.world.WorldUtils; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.Items; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.Hand; +import net.minecraft.util.math.Vec3d; + +/** + * Ported from Trouser-Streak's MaceKill (https://github.com/etianl/Trouser-Streak). + */ +public class MaceKill extends Module { + + private boolean sendingAttack; + + // Queued follow-up attacks for Totem Bypass - hitting all of them back to back in the same + // tick doesn't out-damage a totem's invulnerability frames, so the rest are spaced out with a + // real tick delay between each. + private LivingEntity queuedTarget; + private int queuedAttacksLeft; + private double queuedHeight; + private int queuedDelay; + + public MaceKill() { + this(new SettingToggle("Auto Calculate Packets", true).withDesc("Scales the spam packet count based on the fall height instead of using a fixed amount.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Auto Calculate + // Packets toggle as a constructor parameter first lets the manual Packets slider below capture + // that local variable instead. + private MaceKill(SettingToggle autoPackets) { + super("MaceKill", KEY_UNBOUND, ModuleCategory.EXPLOITS, + "Fakes a fall right before hitting so your Mace lands a full smash attack, risk-free - can also chain hits to bypass totems.", + new SettingSlider("Fall Height", 1, 169, 22, 0).withDesc("How many blocks to fake-fall from before attacking."), + autoPackets, + new SettingSlider("Packets", 1, 17, 4, 0).withDesc("Fixed spam packet count, used when Auto Calculate Packets is off.") + .visibleWhen(() -> !autoPackets.getState()), + new SettingToggle("Totem Bypass", false).withDesc("Chains several smash attacks, each from a bit higher, to out-damage a totem's regeneration.").withChildren( + new SettingSlider("Attacks", 1, 3, 3, 0).withDesc("How many extra attacks to chain after the first."), + new SettingSlider("Height +", 1, 100, 9, 0).withDesc("How much extra fall height to add for each chained attack."), + new SettingSlider("Bypass Delay", 0, 20, 4, 0).withDesc("Ticks to wait between chained attacks - all at once doesn't beat a totem's invulnerability window.")), + new SettingToggle("Skip If Blocked", true).withDesc("Don't attack if the target is shielding or can't take damage."), + new SettingToggle("Swing Arm", true).withDesc("Swings your hand on your screen for visual feedback."), + new SettingToggle("Raycast", true).withDesc("Only attacks if you can see the target.")); + } + + @BleachSubscribe + public void onSendPacket(EventPacket.Send event) { + if (sendingAttack || !(event.getPacket() instanceof PlayerInteractEntityC2SPacket packet)) { + return; + } + + if (PlayerInteractEntityC2SUtils.getInteractType(packet) != InteractType.ATTACK + || mc.player.getMainHandStack().getItem() != Items.MACE + || mc.player.hasVehicle()) { + return; + } + + if (!(PlayerInteractEntityC2SUtils.getEntity(packet) instanceof LivingEntity target) || !target.isAlive()) { + return; + } + + if (getSetting(4).asToggle().getState() && (target.isBlocking() || target.isInvulnerable())) { + return; + } + + if (getSetting(6).asToggle().getState() && !mc.player.canSee(target)) { + return; + } + + event.setCancelled(true); + + boolean totemBypass = getSetting(3).asToggle().getState(); + double height = getSetting(0).asSlider().getValue(); + + smash(target, height); + + if (totemBypass) { + queuedTarget = target; + queuedAttacksLeft = getSetting(3).asToggle().getChild(0).asSlider().getValueInt() - 1; + queuedHeight = height + getSetting(3).asToggle().getChild(1).asSlider().getValue(); + queuedDelay = getSetting(3).asToggle().getChild(2).asSlider().getValueInt(); + } + } + + @BleachSubscribe + public void onTick(EventTick event) { + if (queuedAttacksLeft <= 0 || queuedTarget == null) { + return; + } + + if (!queuedTarget.isAlive()) { + queuedAttacksLeft = 0; + queuedTarget = null; + return; + } + + if (queuedDelay-- > 0) { + return; + } + + smash(queuedTarget, queuedHeight); + + queuedAttacksLeft--; + queuedHeight += getSetting(3).asToggle().getChild(1).asSlider().getValue(); + queuedDelay = getSetting(3).asToggle().getChild(2).asSlider().getValueInt(); + + if (queuedAttacksLeft <= 0) { + queuedTarget = null; + } + } + + @Override + public void onDisable(boolean inWorld) { + queuedTarget = null; + queuedAttacksLeft = 0; + super.onDisable(inWorld); + } + + private void smash(LivingEntity target, double height) { + Vec3d home = mc.player.getEntityPos(); + + sendingAttack = true; + try { + spamStatusPackets(height); + + WorldUtils.sendTeleport(home.add(0, height, 0)); + WorldUtils.sendTeleport(home); + + if (getSetting(5).asToggle().getState()) { + mc.player.networkHandler.sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + mc.player.swingHand(Hand.MAIN_HAND); + } + + mc.player.networkHandler.sendPacket(PlayerInteractEntityC2SPacket.attack(target, mc.player.isSneaking())); + + WorldUtils.sendTeleport(WorldUtils.findSafeOffset(mc.player, home, 0.05, 0.01)); + } finally { + sendingAttack = false; + } + } + + // Auto Calculate Packets scales the spam count with the fake fall's height: taller (more + // suspicious/further) fakes need more "you're grounded" spam beforehand to keep the server's + // movement-distance tracking from flagging the sudden teleport. + private void spamStatusPackets(double height) { + int count = getSetting(1).asToggle().getState() + ? Math.min(17, Math.max(1, (int) Math.ceil(height / 6.0))) + : getSetting(2).asSlider().getValueInt(); + + for (int i = 0; i < count; i++) { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(false, mc.player.horizontalCollision)); + } + } + +} diff --git a/src/main/java/org/bleachhack/module/mods/Nametags.java b/src/main/java/org/bleachhack/module/mods/Nametags.java index 9c2520adf7..c51e38f7b1 100644 --- a/src/main/java/org/bleachhack/module/mods/Nametags.java +++ b/src/main/java/org/bleachhack/module/mods/Nametags.java @@ -19,7 +19,9 @@ import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.LazyEntityReference; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.mob.Monster; @@ -163,19 +165,19 @@ public void onWorldRender(EventWorldRender.Post event) { continue; } - Vec3d rPos = entity.getPos().subtract(Renderer.getInterpolationOffset(entity)).add(0, entity.getHeight() + 0.25, 0); + Vec3d rPos = entity.getEntityPos().subtract(Renderer.getInterpolationOffset(entity)).add(0, entity.getHeight() + 0.25, 0); if (entity instanceof PlayerEntity && getSetting(1).asToggle().getState()) { - double scale = Math.max(getSetting(1).asToggle().getChild(0).asSlider().getValue() * (mc.cameraEntity.distanceTo(entity) / 20), 1); + double scale = Math.max(getSetting(1).asToggle().getChild(0).asSlider().getValue() * (mc.getCameraEntity().distanceTo(entity) / 20), 1); List lines = getPlayerLines((PlayerEntity) entity); drawLines(rPos.x, rPos.y, rPos.z, scale, lines); if (getSetting(1).asToggle().getChild(1).asToggle().getState()) { - drawItems(rPos.x, rPos.y + (lines.size() + 1) * 0.25 * scale, rPos.z, scale, getMainEquipment(entity)); + drawItems(rPos.x, rPos.y + (lines.size() + 1) * 0.25 * scale, rPos.z, scale, getMainEquipment((LivingEntity) entity)); } } else if (EntityUtils.isAnimal(entity) && getSetting(2).asToggle().getState()) { - double scale = Math.max(getSetting(2).asToggle().getChild(0).asSlider().getValue() * (mc.cameraEntity.distanceTo(entity) / 20), 1); + double scale = Math.max(getSetting(2).asToggle().getChild(0).asSlider().getValue() * (mc.getCameraEntity().distanceTo(entity) / 20), 1); List lines = getAnimalLines((LivingEntity) entity); drawLines(rPos.x, rPos.y, rPos.z, scale, lines); @@ -184,23 +186,23 @@ public void onWorldRender(EventWorldRender.Post event) { drawItems(rPos.x, rPos.y + (lines.size() + 1) * 0.25 * scale, rPos.z, scale, List.of(((FoxEntity) entity).getMainHandStack())); } } else if (entity instanceof Monster && getSetting(3).asToggle().getState()) { - double scale = Math.max(getSetting(3).asToggle().getChild(0).asSlider().getValue() * (mc.cameraEntity.distanceTo(entity) / 20), 1); + double scale = Math.max(getSetting(3).asToggle().getChild(0).asSlider().getValue() * (mc.getCameraEntity().distanceTo(entity) / 20), 1); List lines = getMobLines((LivingEntity) entity); drawLines(rPos.x, rPos.y, rPos.z, scale, lines); if (getSetting(3).asToggle().getChild(1).asToggle().getState()) { - drawItems(rPos.x, rPos.y + (lines.size() + 1) * 0.25 * scale, rPos.z, scale, getMainEquipment(entity)); + drawItems(rPos.x, rPos.y + (lines.size() + 1) * 0.25 * scale, rPos.z, scale, getMainEquipment((LivingEntity) entity)); } } else if (entity instanceof ItemEntity && getSetting(4).asToggle().getState()) { - double scale = Math.max(getSetting(4).asToggle().getChild(0).asSlider().getValue() * (mc.cameraEntity.distanceTo(entity) / 20), 1); + double scale = Math.max(getSetting(4).asToggle().getChild(0).asSlider().getValue() * (mc.getCameraEntity().distanceTo(entity) / 20), 1); List lines = getItemLines((ItemEntity) entity); drawLines(rPos.x, rPos.y, rPos.z, scale, lines); } else if (entity instanceof ArmorStandEntity && getSetting(5).asToggle().getState()) { - double scale = Math.max(getSetting(5).asToggle().getChild(0).asSlider().getValue() * (mc.cameraEntity.distanceTo(entity) / 20), 1); + double scale = Math.max(getSetting(5).asToggle().getChild(0).asSlider().getValue() * (mc.getCameraEntity().distanceTo(entity) / 20), 1); - drawItems(rPos.x, rPos.y + 0.25 * scale, rPos.z, scale, getMainEquipment(entity)); + drawItems(rPos.x, rPos.y + 0.25 * scale, rPos.z, scale, getMainEquipment((LivingEntity) entity)); } } } @@ -233,24 +235,29 @@ private void drawItem(double x, double y, double z, double offX, double offY, do x, y, z, (offX - w) * scale, (offY - 0.07) * scale, scale * 1.75, false); int c = 0; - for (Entry m : EnchantmentHelper.get(item).entrySet()) { - String text = I18n.translate(m.getKey().getName(2).getString()); + for (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry> m + : EnchantmentHelper.getEnchantments(item).getEnchantmentEntries()) { + String text = Enchantment.getName(m.getKey(), m.getIntValue()).getString(); if (text.isEmpty()) continue; text = text.replaceFirst("Curse of (.)", "C$1"); - String subText = text.substring(0, Math.min(text.length(), 2)) + m.getValue(); + String subText = text.substring(0, Math.min(text.length(), 2)) + m.getIntValue(); - WorldRenderer.drawText(Text.literal(subText).styled(s -> s.withColor(TextColor.fromRgb(m.getKey().isCursed() ? 0xff5050 : 0xffb0e0))), + WorldRenderer.drawText(Text.literal(subText).styled(s -> s.withColor(TextColor.fromRgb( + m.getKey().isIn(net.minecraft.registry.tag.EnchantmentTags.CURSE) ? 0xff5050 : 0xffb0e0))), x, y, z, (offX + 0.02) * scale, (offY + 0.75 - c * 0.34) * scale, scale * 1.4, false); c--; } } - private List getMainEquipment(Entity e) { - List list = Lists.newArrayList(e.getItemsEquipped()); + private List getMainEquipment(LivingEntity e) { + List list = Lists.newArrayList( + e.getEquippedStack(EquipmentSlot.MAINHAND), e.getEquippedStack(EquipmentSlot.OFFHAND), + e.getEquippedStack(EquipmentSlot.FEET), e.getEquippedStack(EquipmentSlot.LEGS), + e.getEquippedStack(EquipmentSlot.CHEST), e.getEquippedStack(EquipmentSlot.HEAD)); list.add(list.remove(1)); return list; } @@ -259,7 +266,7 @@ public List getPlayerLines(PlayerEntity player) { List lines = new ArrayList<>(); List mainText = new ArrayList<>(); - PlayerListEntry playerEntry = mc.player.networkHandler.getPlayerListEntry(player.getGameProfile().getId()); + PlayerListEntry playerEntry = mc.player.networkHandler.getPlayerListEntry(player.getGameProfile().id()); if (getSetting(1).asToggle().getChild(4).asToggle().getState() && playerEntry != null) { // Ping mainText.add(Text.literal(playerEntry.getLatency() + "ms").formatted(Formatting.GRAY)); @@ -294,8 +301,9 @@ public List getAnimalLines(LivingEntity animal) { boolean tame = animal instanceof AbstractHorseEntity ? ((AbstractHorseEntity) animal).isTame() : ((TameableEntity) animal).isTamed(); - UUID ownerUUID = animal instanceof AbstractHorseEntity - ? ((AbstractHorseEntity) animal).getOwnerUuid() : ((TameableEntity) animal).getOwnerUuid(); + LazyEntityReference ownerRef = animal instanceof AbstractHorseEntity + ? ((AbstractHorseEntity) animal).getOwnerReference() : ((TameableEntity) animal).getOwnerReference(); + UUID ownerUUID = ownerRef == null ? null : ownerRef.getUuid(); if (getSetting(2).asToggle().getChild(4).asToggle().getState() && !animal.isBaby() && (getSetting(2).asToggle().getChild(4).asToggle().getChild(0).asMode().getMode() != 1 || tame)) { @@ -306,30 +314,32 @@ public List getAnimalLines(LivingEntity animal) { if (uuidCache.containsKey(ownerUUID)) { lines.add(0, Text.literal("Owner: " + uuidCache.get(ownerUUID)).formatted(Formatting.GREEN)); } else if (failedUUIDs.contains(ownerUUID)) { - lines.add(0, Text.literal("Owner: " + Formatting.GRAY + "Invalid UUID!").formatted(Formatting.GREEN)); + lines.add(0, Text.literal("Owner: ").formatted(Formatting.GREEN) + .append(Text.literal("Invalid UUID!").formatted(Formatting.GRAY))); } else { // Try to see if the owner is online on the server before calling the mojang api Optional owner = mc.player.networkHandler.getPlayerList().stream() .map(PlayerListEntry::getProfile) - .filter(profile -> profile != null && ownerUUID.equals(profile.getId()) && profile.getName() != null) + .filter(profile -> profile != null && ownerUUID.equals(profile.id()) && profile.name() != null) .findFirst(); if (owner.isPresent()) { - uuidCache.put(ownerUUID, owner.get().getName()); + uuidCache.put(ownerUUID, owner.get().name()); } else if (!uuidQueue.contains(ownerUUID) && !uuidFutures.containsKey(ownerUUID)) { uuidQueue.add(ownerUUID); } - lines.add(0, Text.literal("Owner: " + Formatting.GRAY + "Loading...").formatted(Formatting.GREEN)); + lines.add(0, Text.literal("Owner: ").formatted(Formatting.GREEN) + .append(Text.literal("Loading...").formatted(Formatting.GRAY))); } } if (getSetting(2).asToggle().getChild(6).asToggle().getState() && animal instanceof AbstractHorseEntity) { AbstractHorseEntity he = (AbstractHorseEntity) animal; - lines.add(0, Text.literal( - CmdEntityStats.getSpeed(he) + " m/s" + Formatting.GRAY + " | " + Formatting.RESET + CmdEntityStats.getJumpHeight(he) + " Jump") - .formatted(Formatting.GREEN)); + lines.add(0, Text.literal(CmdEntityStats.getSpeed(he) + " m/s").formatted(Formatting.GREEN) + .append(Text.literal(" | ").formatted(Formatting.GRAY)) + .append(Text.literal(CmdEntityStats.getJumpHeight(he) + " Jump").formatted(Formatting.GREEN))); } } @@ -385,7 +395,8 @@ public List getItemLines(ItemEntity item) { .append(Text.literal("\"").formatted(Formatting.GOLD))); } - lines.add(((MutableText) item.getName()).formatted(Formatting.GOLD).append(getSetting(4).asToggle().getChild(2).asToggle().getState() ? Formatting.YELLOW + " [x" + item.getStack().getCount() + "]" : "")); + lines.add(((MutableText) item.getName()).formatted(Formatting.GOLD).append(getSetting(4).asToggle().getChild(2).asToggle().getState() + ? Text.literal(" [x" + item.getStack().getCount() + "]").formatted(Formatting.YELLOW) : Text.empty())); return lines; } @@ -396,26 +407,25 @@ private Text getHealthText(LivingEntity e) { if (getSetting(0).asMode().getMode() == 0) { return Text.literal(Integer.toString(totalHealth)).styled(s -> s.withColor(getHealthColor(e))); } else if (getSetting(0).asMode().getMode() == 1) { - return Text.literal(Integer.toString(totalHealth) + Formatting.GREEN + "/" + (int) e.getMaxHealth()).styled(s -> s.withColor(getHealthColor(e))); + return Text.literal(Integer.toString(totalHealth) + "/" + (int) e.getMaxHealth()).styled(s -> s.withColor(getHealthColor(e))); } else if (getSetting(0).asMode().getMode() == 2) { - // Health bar - String health = ""; - - // - Add Green Normal Health - health += Formatting.GREEN + StringUtils.repeat('|', (int) e.getHealth()); + // Health bar - built as a proper Text tree (rather than concatenating raw Formatting + // codes into one literal string) since the world-space text renderer doesn't parse + // embedded section-sign codes in plain string content, only explicit component styling. + MutableText health = Text.literal(StringUtils.repeat('|', (int) e.getHealth())).formatted(Formatting.GREEN); // - Add Yellow Absorption Health - health += Formatting.YELLOW + StringUtils.repeat('|', (int) Math.min(e.getAbsorptionAmount(), e.getMaxHealth() - e.getHealth())); + health.append(Text.literal(StringUtils.repeat('|', (int) Math.min(e.getAbsorptionAmount(), e.getMaxHealth() - e.getHealth()))).formatted(Formatting.YELLOW)); // - Add Red Empty Health (Remove Based on absorption amount) - health += Formatting.RED + StringUtils.repeat('|', (int) e.getMaxHealth() - totalHealth); + health.append(Text.literal(StringUtils.repeat('|', (int) e.getMaxHealth() - totalHealth)).formatted(Formatting.RED)); // - Add "+??" to the end if the entity has extra hearts if (totalHealth > (int) e.getMaxHealth()) { - health += Formatting.YELLOW + " +" + (totalHealth - (int) e.getMaxHealth()); + health.append(Text.literal(" +" + (totalHealth - (int) e.getMaxHealth())).formatted(Formatting.YELLOW)); } - return Text.literal(health); + return health; } else { return Text.literal((int) (totalHealth / e.getMaxHealth() * 100) + "%").styled(s -> s.withColor(getHealthColor(e))); } diff --git a/src/main/java/org/bleachhack/module/mods/NewChunks.java b/src/main/java/org/bleachhack/module/mods/NewChunks.java index a2cd5f5429..c0ee1888d2 100644 --- a/src/main/java/org/bleachhack/module/mods/NewChunks.java +++ b/src/main/java/org/bleachhack/module/mods/NewChunks.java @@ -8,80 +8,167 @@ */ package org.bleachhack.module.mods; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.fluid.FluidState; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.WorldSavePath; import net.minecraft.util.math.Box; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeKeys; +import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.Palette; +import net.minecraft.world.chunk.PalettedContainer; +import net.minecraft.world.chunk.WorldChunk; +import org.bleachhack.event.events.EventTick; import org.bleachhack.event.events.EventWorldRender; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; import org.bleachhack.module.ModuleCategory; import org.bleachhack.setting.module.SettingColor; +import org.bleachhack.setting.module.SettingButton; +import org.bleachhack.setting.module.SettingMode; import org.bleachhack.setting.module.SettingSlider; import org.bleachhack.setting.module.SettingToggle; +import org.bleachhack.util.io.BleachFileMang; import org.bleachhack.util.render.Renderer; import org.bleachhack.util.render.color.QuadColor; import org.bleachhack.util.world.ChunkProcessor; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; +/** + * New mode ported from Trouser-Streak's NewerNewChunks (https://github.com/etianl/Trouser-Streak). + * Simplified from the original: one shared alarm (not five per-category ones), one "Old Generation" + * toggle covering all three dimensions (not three), a single combined save file per dimension + * instead of five, and no GUI double-confirm/auto-reload timer for clearing data - a plain button. + */ public class NewChunks extends Module { private static final Direction[] SKIP_DIRS = new Direction[] { Direction.DOWN, Direction.EAST, Direction.NORTH, Direction.WEST, Direction.SOUTH }; private static final Direction[] SEARCH_DIRS = new Direction[] { Direction.EAST, Direction.NORTH, Direction.WEST, Direction.SOUTH, Direction.UP }; - + private final Set newChunks = Collections.synchronizedSet(new HashSet<>()); private final Set oldChunks = Collections.synchronizedSet(new HashSet<>()); - + + // New mode only + private final Set beingUpdatedChunks = Collections.synchronizedSet(new HashSet<>()); + private final Set oldGenerationChunks = Collections.synchronizedSet(new HashSet<>()); + private final Set blockExploitChunks = Collections.synchronizedSet(new HashSet<>()); + private RegistryKey lastDimension; + private int alarmRingsLeft; + private int alarmDelay; + + private static final Set ORE_BLOCKS = Set.of( + Blocks.COAL_ORE, Blocks.DEEPSLATE_COAL_ORE, Blocks.COPPER_ORE, Blocks.DEEPSLATE_COPPER_ORE, + Blocks.IRON_ORE, Blocks.DEEPSLATE_IRON_ORE, Blocks.GOLD_ORE, Blocks.DEEPSLATE_GOLD_ORE, + Blocks.LAPIS_ORE, Blocks.DEEPSLATE_LAPIS_ORE, Blocks.DIAMOND_ORE, Blocks.DEEPSLATE_DIAMOND_ORE, + Blocks.REDSTONE_ORE, Blocks.DEEPSLATE_REDSTONE_ORE, Blocks.EMERALD_ORE, Blocks.DEEPSLATE_EMERALD_ORE); + private static final Set NEW_OVERWORLD_BLOCKS = Set.of( + Blocks.DEEPSLATE, Blocks.AMETHYST_BLOCK, Blocks.BUDDING_AMETHYST, Blocks.AZALEA, Blocks.FLOWERING_AZALEA, + Blocks.BIG_DRIPLEAF, Blocks.BIG_DRIPLEAF_STEM, Blocks.SMALL_DRIPLEAF, Blocks.CAVE_VINES, Blocks.CAVE_VINES_PLANT, + Blocks.SPORE_BLOSSOM, Blocks.COPPER_ORE, Blocks.DEEPSLATE_COPPER_ORE, Blocks.DEEPSLATE_IRON_ORE, + Blocks.DEEPSLATE_COAL_ORE, Blocks.DEEPSLATE_REDSTONE_ORE, Blocks.DEEPSLATE_EMERALD_ORE, Blocks.DEEPSLATE_GOLD_ORE, + Blocks.DEEPSLATE_LAPIS_ORE, Blocks.DEEPSLATE_DIAMOND_ORE, Blocks.GLOW_LICHEN, Blocks.RAW_COPPER_BLOCK, + Blocks.RAW_IRON_BLOCK, Blocks.DRIPSTONE_BLOCK, Blocks.MOSS_BLOCK, Blocks.MOSS_CARPET, Blocks.POINTED_DRIPSTONE, + Blocks.SMOOTH_BASALT, Blocks.TUFF, Blocks.CALCITE, Blocks.HANGING_ROOTS, Blocks.ROOTED_DIRT, + Blocks.AZALEA_LEAVES, Blocks.FLOWERING_AZALEA_LEAVES, Blocks.POWDER_SNOW); + private static final Set NEW_NETHER_BLOCKS = Set.of( + Blocks.ANCIENT_DEBRIS, Blocks.BASALT, Blocks.BLACKSTONE, Blocks.GILDED_BLACKSTONE, Blocks.POLISHED_BLACKSTONE_BRICKS, + Blocks.CRIMSON_STEM, Blocks.CRIMSON_NYLIUM, Blocks.NETHER_GOLD_ORE, Blocks.WARPED_NYLIUM, Blocks.WARPED_STEM, + Blocks.TWISTING_VINES, Blocks.WEEPING_VINES, Blocks.BONE_BLOCK, Blocks.IRON_CHAIN, Blocks.OBSIDIAN, + Blocks.CRYING_OBSIDIAN, Blocks.SOUL_SOIL, Blocks.SOUL_FIRE); + private ChunkProcessor processor = new ChunkProcessor(1, (cp, chunk) -> { - if (!newChunks.contains(cp) && mc.world.getChunkManager().getChunk(cp.x, cp.z) == null) { - for (int x = 0; x < 16; x++) { - for (int y = mc.world.getBottomY(); y < mc.world.getTopY(); y++) { - for (int z = 0; z < 16; z++) { - FluidState fluid = chunk.getFluidState(x, y, z); - - if (!fluid.isEmpty() && !fluid.isStill()) { - oldChunks.add(cp); - return; - } - } - } - } + if (getSetting(0).asMode().getMode() == 0) { + oldModeLoadChunk(cp, chunk); + } else { + newModeLoadChunk(cp, chunk); } }, null, (pos, state) -> { - if (!state.getFluidState().isEmpty() && !state.getFluidState().isStill()) { - ChunkPos cpos = new ChunkPos(pos); - for (Direction dir: SEARCH_DIRS) { - if (mc.world.getBlockState(pos.offset(dir)).getFluidState().isStill() && !oldChunks.contains(cpos)) { - newChunks.add(cpos); - return; - } - } + if (getSetting(0).asMode().getMode() == 0) { + oldModeUpdateBlock(pos, state); + } else { + newModeUpdateBlock(pos, state); } }); public NewChunks() { - super("NewChunks", KEY_UNBOUND, ModuleCategory.WORLD, "Detects completely new chunks using certain traits of them.", + this(new SettingMode("Mode", "Old", "New").withDesc("Old: the original flowing-liquid heuristic. New: Trouser-Streak's chunk-palette scanning, with more detection methods and detail.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicates below capture that local variable instead. + private NewChunks(SettingMode mode) { + super("NewChunks", KEY_UNBOUND, ModuleCategory.WORLD, "Detects new and old chunks.", + mode, new SettingSlider("Y-Offset", -100, 100, 0, 0).withDesc("The offset from the bottom of the world to render the squares at."), new SettingToggle("Remove", true).withDesc("Removes the cached chunks when disabling the module."), - new SettingToggle("Fill", true).withDesc("Fills in the newchunks.").withChildren( + new SettingToggle("Fill", true).withDesc("Fills in the chunks.").withChildren( new SettingSlider("Opacity", 0.01, 1, 0.3, 2).withDesc("The opacity of the fill.")), new SettingToggle("NewChunks", true).withDesc("Shows all the chunks that are (most likely) completely new.").withChildren( new SettingColor("Color", 200, 150, 215).withDesc("The color of NewChunks.")), new SettingToggle("OldChunks", false).withDesc("Shows all the chunks that have (most likely) been loaded before.").withChildren( - new SettingColor("Color", 230, 50, 50).withDesc("The color of OldChunks."))); + new SettingColor("Color", 230, 50, 50).withDesc("The color of OldChunks.")), + new SettingToggle("BeingUpdated", false).withDesc("New mode only: chunks currently being upgraded from an old version.").withChildren( + new SettingColor("Color", 255, 210, 0).withDesc("The color of BeingUpdated chunks.")) + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("OldGeneration", false).withDesc("New mode only: chunks that were generated in an old version.").withChildren( + new SettingColor("Color", 190, 255, 0).withDesc("The color of OldGeneration chunks.")) + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("BlockExploit", false).withDesc("New mode only: chunks flagged via a block-update packet - may possibly be old, see Block Update Exploit below.").withChildren( + new SettingColor("Color", 0, 0, 255).withDesc("The color of BlockExploit chunks.")) + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Palette Exploit", true).withDesc("New mode only: detects new/being-updated chunks by scanning the order of chunk section block palettes.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Liquid Exploit", false).withDesc("New mode only: estimates chunks based on flowing liquids.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Block Update Exploit", false).withDesc("New mode only: estimates chunks based on block-update packets. May possibly be old.").withChildren( + new SettingToggle("Fold Into Old", false).withDesc("Shows BlockExploit chunks as OldChunks instead of their own category.")) + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Old Generation Detector", true).withDesc("New mode only: marks chunks as old-generation if they're missing blocks added after their dimension's last major terrain update.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Being Updated Detector", true).withDesc("New mode only: marks chunks as being-updated if they're currently being upgraded from an old version.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingSlider("Render Distance", 6, 128, 32, 0).withDesc("New mode only: how many chunks away to render detected chunks.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Save Data", true).withDesc("New mode only: saves detected chunks to a file, per server/world and dimension.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Load Data", true).withDesc("New mode only: loads previously saved chunks when entering a dimension.") + .visibleWhen(() -> mode.getMode() == 1), + // Can't use this::clearSavedData here - "this" isn't allowed in a super(...) argument + // list until the super constructor returns. Routing through the static module lookup + // instead avoids capturing "this" directly. + new SettingButton("Clear Saved Chunk Data", () -> org.bleachhack.module.ModuleManager.getModule(NewChunks.class).clearSavedData()).withDesc("New mode only: deletes the saved chunk data for the current dimension and clears the cache.") + .visibleWhen(() -> mode.getMode() == 1), + new SettingToggle("Alarm", false).withDesc("New mode only: plays a sound when a new chunk is detected.").withChildren( + new SettingSlider("Volume", 0, 1, 1, 2).withDesc("The volume of the alarm."), + new SettingSlider("Pitch", 0.5, 2, 1, 2).withDesc("The pitch of the alarm.")) + .visibleWhen(() -> mode.getMode() == 1)); } - + @Override public void onDisable(boolean inWorld) { - if (getSetting(1).asToggle().getState()) { - newChunks.clear(); - oldChunks.clear(); + if (getSetting(2).asToggle().getState()) { + clearAll(); } processor.stop(); @@ -92,55 +179,408 @@ public void onDisable(boolean inWorld) { public void onEnable(boolean inWorld) { super.onEnable(inWorld); processor.start(); + lastDimension = null; + alarmRingsLeft = 0; + } + + @BleachSubscribe + public void onTick(EventTick event) { + if (getSetting(0).asMode().getMode() != 1 || mc.world == null) { + return; + } + + // Reload the saved data whenever the dimension changes, instead of Trouser-Streak's + // screen-open/leave-world tracking - simpler, and covers the same "just entered a new + // dimension" case. + RegistryKey dim = mc.world.getRegistryKey(); + if (dim != lastDimension) { + lastDimension = dim; + clearAll(); + if (getSetting(16).asToggle().getState()) { + loadSavedData(); + } + } + + if (alarmRingsLeft > 0) { + if (alarmDelay <= 0) { + playAlarm(); + alarmDelay = 10; + alarmRingsLeft--; + } else { + alarmDelay--; + } + } + } + + private void clearAll() { + newChunks.clear(); + oldChunks.clear(); + beingUpdatedChunks.clear(); + oldGenerationChunks.clear(); + blockExploitChunks.clear(); + } + + private void clearSavedData() { + clearAll(); + if (mc.world != null) { + try { + Files.deleteIfExists(saveFilePath()); + } catch (IOException e) { + e.printStackTrace(); + } + } } @BleachSubscribe public void onWorldRender(EventWorldRender.Post event) { - int renderY = mc.world.getBottomY() + getSetting(0).asSlider().getValueInt(); - int opacity = (int) (getSetting(2).asToggle().getChild(0).asSlider().getValueFloat() * 255); - - if (getSetting(3).asToggle().getState()) { - int[] color = getSetting(3).asToggle().getChild(0).asColor().getRGBArray(); - QuadColor outlineColor = QuadColor.single(color[0], color[1], color[2], 255); - QuadColor fillColor = QuadColor.single(color[0], color[1], color[2], opacity); - - synchronized (newChunks) { - for (ChunkPos c: newChunks) { - if (mc.getCameraEntity().getBlockPos().isWithinDistance(c.getStartPos(), 1024)) { - Box box = new Box( - c.getStartX(), renderY, c.getStartZ(), - c.getStartX() + 16, renderY, c.getStartZ() + 16); - - if (getSetting(2).asToggle().getState()) { - Renderer.drawBoxFill(box, fillColor, SKIP_DIRS); - } - - Renderer.drawBoxOutline(box, outlineColor, 2f, SKIP_DIRS); + int renderY = mc.world.getBottomY() + getSetting(1).asSlider().getValueInt(); + int opacity = (int) (getSetting(3).asToggle().getChild(0).asSlider().getValueFloat() * 255); + boolean newMode = getSetting(0).asMode().getMode() == 1; + double maxDist = newMode ? getSetting(14).asSlider().getValue() * 16 : 1024; + + renderSet(event, newChunks, getSetting(4), renderY, opacity, maxDist); + renderSet(event, oldChunks, getSetting(5), renderY, opacity, maxDist); + + if (newMode) { + renderSet(event, beingUpdatedChunks, getSetting(6), renderY, opacity, maxDist); + renderSet(event, oldGenerationChunks, getSetting(7), renderY, opacity, maxDist); + renderSet(event, blockExploitChunks, getSetting(8), renderY, opacity, maxDist); + } + } + + private void renderSet(EventWorldRender.Post event, Set chunks, org.bleachhack.setting.module.ModuleSetting toggleSetting, int renderY, int opacity, double maxDist) { + if (!toggleSetting.asToggle().getState()) { + return; + } + + int[] color = toggleSetting.asToggle().getChild(0).asColor().getRGBArray(); + QuadColor outlineColor = QuadColor.single(color[0], color[1], color[2], 255); + QuadColor fillColor = QuadColor.single(color[0], color[1], color[2], opacity); + + synchronized (chunks) { + for (ChunkPos c : chunks) { + if (mc.getCameraEntity().getBlockPos().isWithinDistance(c.getStartPos(), maxDist)) { + Box box = new Box( + c.getStartX(), renderY, c.getStartZ(), + c.getStartX() + 16, renderY, c.getStartZ() + 16); + + if (getSetting(3).asToggle().getState()) { + Renderer.drawBoxFill(box, fillColor, SKIP_DIRS); } + + Renderer.drawBoxOutline(box, outlineColor, 2f, SKIP_DIRS); } } } + } - if (getSetting(4).asToggle().getState()) { - int[] color = getSetting(4).asToggle().getChild(0).asColor().getRGBArray(); - QuadColor outlineColor = QuadColor.single(color[0], color[1], color[2], 255); - QuadColor fillColor = QuadColor.single(color[0], color[1], color[2], opacity); + // ===================== Old mode (unchanged from before the New mode port) ===================== - synchronized (oldChunks) { - for (ChunkPos c: oldChunks) { - if (mc.getCameraEntity().getBlockPos().isWithinDistance(c.getStartPos(), 1024)) { - Box box = new Box( - c.getStartX(), renderY, c.getStartZ(), - c.getStartX() + 16, renderY, c.getStartZ() + 16); + private void oldModeLoadChunk(ChunkPos cp, WorldChunk chunk) { + if (!newChunks.contains(cp) && mc.world.getChunkManager().getChunk(cp.x, cp.z) == null) { + for (int x = 0; x < 16; x++) { + for (int y = mc.world.getBottomY(); y <= mc.world.getTopYInclusive(); y++) { + for (int z = 0; z < 16; z++) { + FluidState fluid = chunk.getFluidState(x, y, z); - if (getSetting(2).asToggle().getState()) { - Renderer.drawBoxFill(box, fillColor, SKIP_DIRS); + if (!fluid.isEmpty() && !fluid.isStill()) { + oldChunks.add(cp); + return; } - - Renderer.drawBoxOutline(box, outlineColor, 2f, SKIP_DIRS); } } } } } + + private void oldModeUpdateBlock(net.minecraft.util.math.BlockPos pos, BlockState state) { + if (!state.getFluidState().isEmpty() && !state.getFluidState().isStill()) { + ChunkPos cpos = new ChunkPos(pos); + for (Direction dir : SEARCH_DIRS) { + if (mc.world.getBlockState(pos.offset(dir)).getFluidState().isStill() && !oldChunks.contains(cpos)) { + newChunks.add(cpos); + return; + } + } + } + } + + // ===================== New mode (ported from Trouser-Streak's NewerNewChunks) ===================== + + private void newModeUpdateBlock(net.minecraft.util.math.BlockPos pos, BlockState state) { + ChunkPos cpos = new ChunkPos(pos); + if (alreadyClassified(cpos)) { + return; + } + + if (getSetting(11).asToggle().getState()) { + boolean foldIntoOld = getSetting(11).asToggle().getChild(0).asToggle().getState(); + addChunk(foldIntoOld ? oldChunks : blockExploitChunks, cpos, false); + } + + if (getSetting(10).asToggle().getState() && !state.getFluidState().isEmpty() && !state.getFluidState().isStill()) { + for (Direction dir : SEARCH_DIRS) { + if (mc.world.getBlockState(pos.offset(dir)).getFluidState().isStill()) { + blockExploitChunks.remove(cpos); + addChunk(newChunks, cpos, true); + return; + } + } + } + } + + private void newModeLoadChunk(ChunkPos cp, WorldChunk chunk) { + if (alreadyClassified(cp) || mc.world == null) { + return; + } + + RegistryKey dim = mc.world.getRegistryKey(); + ChunkSection[] sections = chunk.getSectionArray(); + + boolean isOldGeneration = getSetting(12).asToggle().getState() && detectOldGeneration(sections, dim); + + if (getSetting(9).asToggle().getState()) { + scanPalette(cp, sections, dim, isOldGeneration); + } else if (isOldGeneration) { + addChunk(oldGenerationChunks, cp, false); + } + } + + // Marks a chunk as generated in an old version if it's missing the blocks added to its + // dimension's terrain generation since - checked via hasAny() over each section's palette + // instead of Trouser-Streak's per-block x/y/z loop, since a palette entry only needs to exist + // once in a section to prove the block is (or isn't) there. + private boolean detectOldGeneration(ChunkSection[] sections, RegistryKey dim) { + if (dim == World.OVERWORLD) { + boolean foundOre = false; + boolean foundNewBlock = false; + for (int i = 0; i < Math.min(sections.length, 17); i++) { + ChunkSection section = sections[i]; + if (section == null || section.isEmpty()) { + continue; + } + + PalettedContainer states = section.getBlockStateContainer(); + if (!foundOre && states.hasAny(s -> ORE_BLOCKS.contains(s.getBlock()))) { + foundOre = true; + } + if ((i > 4) && !foundNewBlock && states.hasAny(s -> NEW_OVERWORLD_BLOCKS.contains(s.getBlock()))) { + foundNewBlock = true; + } + } + return foundOre && !foundNewBlock; + } else if (dim == World.NETHER) { + for (int i = 0; i < Math.min(sections.length, 8); i++) { + ChunkSection section = sections[i]; + if (section != null && !section.isEmpty() + && section.getBlockStateContainer().hasAny(s -> NEW_NETHER_BLOCKS.contains(s.getBlock()))) { + return false; + } + } + return true; + } else if (dim == World.END) { + ChunkSection section = sections.length > 0 ? sections[0] : null; + return section != null && section.getBiomeContainer() instanceof PalettedContainer> biomes + && biomes.hasAny(b -> b.matchesKey(BiomeKeys.THE_END)); + } + + return false; + } + + // Trouser-Streak's "PaletteExploit" - a section's block palette gets its distinct entries + // appended in the order they're first read while decoding chunk NBT, which differs + // consistently enough between a freshly-generated section and a previously-explored one + // (loaded from disk, with player-made changes) to use as a heuristic. Needs the "data" field + // widened (see bleachhack.accesswidener) since PalettedContainer has no public accessor for + // the palette itself, only aggregate queries. + private void scanPalette(ChunkPos pos, ChunkSection[] sections, RegistryKey dim, boolean isOldGeneration) { + boolean isNether = dim == World.NETHER; + boolean isEnd = dim == World.END; + + boolean firstSectionAppearsNew = false; + boolean isNewChunk = false; + boolean chunkIsBeingUpdated = false; + int loops = 0; + int newChunkQuantifier = 0; + int oldChunkQuantifier = 0; + + try { + for (ChunkSection section : sections) { + if (section == null || section.isEmpty()) { + continue; + } + + int isNewSection = 0; + int isBeingUpdatedSection = 0; + + Palette palette = section.getBlockStateContainer().data.palette(); + int paletteSize = palette.getSize(); + + for (int i = 0; i < paletteSize; i++) { + BlockState entry = palette.get(i); + if (i == 0 && loops == 0 && entry.getBlock() == Blocks.AIR && !isEnd) { + firstSectionAppearsNew = true; + } + if (i == 0 && entry.getBlock() == Blocks.AIR && !isNether && !isEnd) { + isNewSection++; + } + if (i == 1 && (entry.getBlock() == Blocks.WATER || entry.getBlock() == Blocks.STONE + || entry.getBlock() == Blocks.GRASS_BLOCK || entry.getBlock() == Blocks.SNOW_BLOCK) && !isNether && !isEnd) { + isNewSection++; + } + if (i == 2 && (entry.getBlock() == Blocks.SNOW_BLOCK || entry.getBlock() == Blocks.DIRT + || entry.getBlock() == Blocks.POWDER_SNOW) && !isNether && !isEnd) { + isNewSection++; + } + if (loops == 4 && entry.getBlock() == Blocks.BEDROCK && !isNether && !isEnd + && getSetting(13).asToggle().getState()) { + chunkIsBeingUpdated = true; + } + if (entry.getBlock() == Blocks.AIR && (isNether || isEnd)) { + isBeingUpdatedSection++; + } + } + + if (isBeingUpdatedSection >= 2) { + oldChunkQuantifier++; + } + if (isNewSection >= 2) { + newChunkQuantifier++; + } + + loops++; + } + + if (loops > 0) { + if (getSetting(13).asToggle().getState() && (isNether || isEnd)) { + if (((double) oldChunkQuantifier / loops) * 100 >= 25) { + chunkIsBeingUpdated = true; + } + } else if (!isNether && !isEnd) { + if (((double) newChunkQuantifier / loops) * 100 >= 51) { + isNewChunk = true; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + if (firstSectionAppearsNew) { + isNewChunk = true; + } + + boolean notOldGeneration = isEnd ? isNewChunk : !isOldGeneration; + + if (isNewChunk && !chunkIsBeingUpdated && notOldGeneration) { + addChunk(newChunks, pos, true); + } else if (!isNewChunk && !chunkIsBeingUpdated && isOldGeneration) { + addChunk(oldGenerationChunks, pos, false); + } else if (chunkIsBeingUpdated) { + addChunk(beingUpdatedChunks, pos, false); + } else if (getSetting(9).asToggle().getState()) { + addChunk(oldChunks, pos, false); + } + } + + private boolean alreadyClassified(ChunkPos pos) { + return newChunks.contains(pos) || oldChunks.contains(pos) || beingUpdatedChunks.contains(pos) + || oldGenerationChunks.contains(pos) || blockExploitChunks.contains(pos); + } + + private void addChunk(Set set, ChunkPos pos, boolean ringAlarm) { + if (alreadyClassified(pos)) { + return; + } + + set.add(pos); + + if (ringAlarm && getSetting(18).asToggle().getState()) { + alarmRingsLeft = 1; + alarmDelay = 0; + } + + if (getSetting(15).asToggle().getState()) { + saveChunk(set, pos); + } + } + + private void playAlarm() { + if (mc.player == null || mc.world == null) { + return; + } + + float volume = getSetting(18).asToggle().getChild(0).asSlider().getValueFloat(); + float pitch = getSetting(18).asToggle().getChild(1).asSlider().getValueFloat(); + mc.world.playSoundClient(SoundEvents.BLOCK_BELL_USE, SoundCategory.PLAYERS, volume, pitch); + } + + // ===================== Persistence (New mode) - one file per dimension instead of Trouser- ===================== + // ===================== Streak's five, tagged per line by category. ===================== + + private Path saveFilePath() { + String server = mc.isIntegratedServerRunning() && mc.getServer() != null + ? mc.getServer().getSavePath(WorldSavePath.ROOT).getFileName().toString() + : mc.getCurrentServerEntry() != null ? mc.getCurrentServerEntry().address : "unknown"; + String dim = mc.world.getRegistryKey().getValue().toString(); + + String safeServer = server.replaceAll("[^a-zA-Z0-9._-]", "_"); + String safeDim = dim.replaceAll("[^a-zA-Z0-9._-]", "_"); + + return BleachFileMang.getDir().resolve("NewChunks").resolve(safeServer).resolve(safeDim + ".txt"); + } + + private String tagFor(Set set) { + if (set == newChunks) return "NEW"; + if (set == oldChunks) return "OLD"; + if (set == beingUpdatedChunks) return "UPDATING"; + if (set == oldGenerationChunks) return "OLDGEN"; + return "EXPLOIT"; + } + + private void saveChunk(Set set, ChunkPos pos) { + try { + Path path = saveFilePath(); + Files.createDirectories(path.getParent()); + String line = tagFor(set) + "," + pos.x + "," + pos.z + System.lineSeparator(); + Files.write(path, line.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.APPEND); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void loadSavedData() { + try { + Path path = saveFilePath(); + if (!Files.exists(path)) { + return; + } + + List lines = Files.readAllLines(path); + for (String line : lines) { + if (line == null || line.isBlank()) { + continue; + } + + String[] parts = line.split(","); + if (parts.length != 3) { + continue; + } + + try { + ChunkPos pos = new ChunkPos(Integer.parseInt(parts[1].trim()), Integer.parseInt(parts[2].trim())); + switch (parts[0].trim()) { + case "NEW" -> newChunks.add(pos); + case "OLD" -> oldChunks.add(pos); + case "UPDATING" -> beingUpdatedChunks.add(pos); + case "OLDGEN" -> oldGenerationChunks.add(pos); + case "EXPLOIT" -> blockExploitChunks.add(pos); + default -> {} + } + } catch (NumberFormatException ignored) {} + } + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/org/bleachhack/module/mods/NoRender.java b/src/main/java/org/bleachhack/module/mods/NoRender.java index 8b681a2c3c..55b943eecc 100644 --- a/src/main/java/org/bleachhack/module/mods/NoRender.java +++ b/src/main/java/org/bleachhack/module/mods/NoRender.java @@ -27,8 +27,9 @@ import com.google.gson.JsonElement; import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.block.entity.SignText; import net.minecraft.client.particle.CampfireSmokeParticle; -import net.minecraft.client.particle.ElderGuardianAppearanceParticle; +import net.minecraft.client.particle.ElderGuardianParticle; import net.minecraft.client.particle.ExplosionLargeParticle; import net.minecraft.client.particle.FireworksSparkParticle.FireworkParticle; import net.minecraft.entity.ExperienceOrbEntity; @@ -157,9 +158,11 @@ public void onSignRender(EventBlockEntityRender.Single.Pre event) { sign.setWorld(mc.world); if (signSetting.getChild(0).asMode().getMode() == 2) { + SignText text = sign.getFrontText(); for (int i = 0; i < 4; i++) { - sign.setTextOnRow(i, signText[i]); + text = text.withMessage(i, signText[i]); } + sign.setText(text, true); } event.setBlockEntity(sign); @@ -169,7 +172,7 @@ public void onSignRender(EventBlockEntityRender.Single.Pre event) { @BleachSubscribe public void onParticle(EventParticle.Normal event) { - if ((isWorldToggled(2) && event.getParticle() instanceof ElderGuardianAppearanceParticle) + if ((isWorldToggled(2) && event.getParticle() instanceof ElderGuardianParticle) || (isParticleToggled(0) && event.getParticle() instanceof CampfireSmokeParticle) || (isParticleToggled(1) && event.getParticle() instanceof ExplosionLargeParticle && Math.abs(event.getParticle().getBoundingBox().hashCode()) % 101 >= getParticleChild(1).getChild(0).asSlider().getValueInt()) || (isParticleToggled(2) && event.getParticle() instanceof FireworkParticle)) { diff --git a/src/main/java/org/bleachhack/module/mods/NoSlow.java b/src/main/java/org/bleachhack/module/mods/NoSlow.java index 72c383a4d8..bbd6ebccd5 100644 --- a/src/main/java/org/bleachhack/module/mods/NoSlow.java +++ b/src/main/java/org/bleachhack/module/mods/NoSlow.java @@ -84,7 +84,7 @@ public void onClientMove(EventClientMove event) { /* Slime Block */ if (getSetting(2).asToggle().getState() - && mc.world.getBlockState(BlockPos.ofFloored(mc.player.getPos().add(0, -0.01, 0))).getBlock() == Blocks.SLIME_BLOCK && mc.player.isOnGround()) { + && mc.world.getBlockState(BlockPos.ofFloored(mc.player.getEntityPos().add(0, -0.01, 0))).getBlock() == Blocks.SLIME_BLOCK && mc.player.isOnGround()) { double d = Math.abs(mc.player.getVelocity().y); if (d < 0.1D && !mc.player.bypassesSteppingEffects()) { double e = 1 / (0.4D + d * 0.2D); @@ -114,12 +114,12 @@ public void onTick(EventTick event) { for (KeyBinding k : new KeyBinding[] { mc.options.forwardKey, mc.options.backKey, mc.options.leftKey, mc.options.rightKey, mc.options.jumpKey, mc.options.sprintKey }) { - k.setPressed(InputUtil.isKeyPressed(mc.getWindow().getHandle(), + k.setPressed(InputUtil.isKeyPressed(mc.getWindow(), InputUtil.fromTranslationKey(k.getBoundKeyTranslationKey()).getCode())); } if (getSetting(6).asToggle().asToggle().getChild(0).asToggle().getState()) { - mc.options.sneakKey.setPressed(InputUtil.isKeyPressed(mc.getWindow().getHandle(), + mc.options.sneakKey.setPressed(InputUtil.isKeyPressed(mc.getWindow(), InputUtil.fromTranslationKey(mc.options.sneakKey.getBoundKeyTranslationKey()).getCode())); } @@ -143,13 +143,13 @@ && shouldInvMove(mc.currentScreen)) { float amount = (System.currentTimeMillis() - lastTime) / 10f; lastTime = System.currentTimeMillis(); - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_LEFT)) + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_LEFT)) yaw -= amount; - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_RIGHT)) + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_RIGHT)) yaw += amount; - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_UP)) + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_UP)) pitch -= amount; - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_DOWN)) + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_DOWN)) pitch += amount; if (getSetting(6).asToggle().asToggle().getChild(2).asToggle().asToggle().getChild(1).asToggle().getState()) { diff --git a/src/main/java/org/bleachhack/module/mods/NoVelocity.java b/src/main/java/org/bleachhack/module/mods/NoVelocity.java index a5177992c1..b015846aac 100644 --- a/src/main/java/org/bleachhack/module/mods/NoVelocity.java +++ b/src/main/java/org/bleachhack/module/mods/NoVelocity.java @@ -18,6 +18,7 @@ import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket; +import net.minecraft.util.math.Vec3d; /** * @author sl First Module utilizing EventBus! @@ -53,28 +54,32 @@ public void readPacket(EventPacket.Read event) { return; if (event.getPacket() instanceof EntityVelocityUpdateS2CPacket && getSetting(0).asToggle().getState()) { + // 1.19.4 stored velocity as 3 separate ints scaled by 8000 (the raw network encoding); + // 1.21.11 merged them into one plain Vec3d already in real blocks/tick, matching + // mc.player.getVelocity() directly - no more manual *8000/8000d conversion needed. EntityVelocityUpdateS2CPacket packet = (EntityVelocityUpdateS2CPacket) event.getPacket(); - if (packet.getId() == mc.player.getId()) { + if (packet.getEntityId() == mc.player.getId()) { double velXZ = getSetting(0).asToggle().getChild(0).asSlider().getValue() / 100; double velY = getSetting(0).asToggle().getChild(1).asSlider().getValue() / 100; - - double pvelX = (packet.getVelocityX() / 8000d - mc.player.getVelocity().x) * velXZ; - double pvelY = (packet.getVelocityY() / 8000d - mc.player.getVelocity().y) * velY; - double pvelZ = (packet.getVelocityZ() / 8000d - mc.player.getVelocity().z) * velXZ; - packet.velocityX = (int) (pvelX * 8000 + mc.player.getVelocity().x * 8000); - packet.velocityY = (int) (pvelY * 8000 + mc.player.getVelocity().y * 8000); - packet.velocityZ = (int) (pvelZ * 8000 + mc.player.getVelocity().z * 8000); + Vec3d current = mc.player.getVelocity(); + Vec3d packetVel = packet.getVelocity(); + + double pvelX = (packetVel.x - current.x) * velXZ; + double pvelY = (packetVel.y - current.y) * velY; + double pvelZ = (packetVel.z - current.z) * velXZ; + + packet.velocity = new Vec3d(pvelX + current.x, pvelY + current.y, pvelZ + current.z); } } else if (event.getPacket() instanceof ExplosionS2CPacket && getSetting(1).asToggle().getState()) { + // 1.19.4 had separate playerVelocityX/Y/Z float fields; 1.21.11 merged them into one + // Optional - ExplosionS2CPacket is now a record, widened mutable via accesswidener. ExplosionS2CPacket packet = (ExplosionS2CPacket) event.getPacket(); double velXZ = getSetting(1).asToggle().getChild(0).asSlider().getValue() / 100; double velY = getSetting(1).asToggle().getChild(1).asSlider().getValue() / 100; - - packet.playerVelocityX = (float) (packet.getPlayerVelocityX() * velXZ); - packet.playerVelocityY = (float) (packet.getPlayerVelocityY() * velY); - packet.playerVelocityZ = (float) (packet.getPlayerVelocityZ() * velXZ); + + packet.playerKnockback = packet.playerKnockback().map(v -> new Vec3d(v.x * velXZ, v.y * velY, v.z * velXZ)); } } diff --git a/src/main/java/org/bleachhack/module/mods/Nofall.java b/src/main/java/org/bleachhack/module/mods/Nofall.java index 7b2498150b..406d730a92 100644 --- a/src/main/java/org/bleachhack/module/mods/Nofall.java +++ b/src/main/java/org/bleachhack/module/mods/Nofall.java @@ -8,6 +8,7 @@ */ package org.bleachhack.module.mods; +import org.bleachhack.event.events.EventPacket; import org.bleachhack.event.events.EventTick; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; @@ -21,23 +22,32 @@ public class Nofall extends Module { public Nofall() { super("Nofall", KEY_UNBOUND, ModuleCategory.PLAYER, "Prevents you from taking fall damage.", - new SettingMode("Mode", "Simple", "Packet").withDesc("What Nofall mode to use.")); + new SettingMode("Mode", "Simple", "Packet", "NoGround").withDesc( + "What Nofall mode to use. NoGround never reports being on the ground to the server " + + "(client-side movement/jumping is unaffected), so it never sees you land.")); + } + + @BleachSubscribe + public void onSendPacket(EventPacket.Send event) { + if (getSetting(0).asMode().getMode() == 2 && event.getPacket() instanceof PlayerMoveC2SPacket packet) { + packet.onGround = false; + } } @BleachSubscribe public void onTick(EventTick event) { if (mc.player.fallDistance > 2.5f && getSetting(0).asMode().getMode() == 0) { - if (mc.player.isFallFlying()) + if (mc.player.isGliding()) return; - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(true)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(true, mc.player.horizontalCollision)); } if (mc.player.fallDistance > 2.5f && getSetting(0).asMode().getMode() == 1 && mc.world.getBlockState(mc.player.getBlockPos().add( 0, (int) (-1.5 + (mc.player.getVelocity().y * 0.1)), 0)).getBlock() != Blocks.AIR) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(false)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(false, mc.player.horizontalCollision)); mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( - mc.player.getX(), mc.player.getY() - 420.69, mc.player.getZ(), true)); + mc.player.getX(), mc.player.getY() - 420.69, mc.player.getZ(), true, mc.player.horizontalCollision)); mc.player.fallDistance = 0; } } diff --git a/src/main/java/org/bleachhack/module/mods/Notebot.java b/src/main/java/org/bleachhack/module/mods/Notebot.java index 08cdcf4e31..9fd3a10c67 100644 --- a/src/main/java/org/bleachhack/module/mods/Notebot.java +++ b/src/main/java/org/bleachhack/module/mods/Notebot.java @@ -9,7 +9,7 @@ package org.bleachhack.module.mods; import net.minecraft.block.NoteBlock; -import net.minecraft.block.enums.Instrument; +import net.minecraft.block.enums.NoteBlockInstrument; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; @@ -203,9 +203,9 @@ public void onTick(EventTick event) { } } - public Instrument getInstrument(BlockPos pos) { + public NoteBlockInstrument getInstrument(BlockPos pos) { if (!isNoteblock(pos)) - return Instrument.HARP; + return NoteBlockInstrument.HARP; return mc.world.getBlockState(pos).get(NoteBlock.INSTRUMENT); } diff --git a/src/main/java/org/bleachhack/module/mods/Nuker.java b/src/main/java/org/bleachhack/module/mods/Nuker.java index 9e6961a622..e524fb10cf 100644 --- a/src/main/java/org/bleachhack/module/mods/Nuker.java +++ b/src/main/java/org/bleachhack/module/mods/Nuker.java @@ -92,7 +92,7 @@ public void onTick(EventTick event) { double distTo = getSetting(3).asMode().getMode() == 0 ? MathHelper.absMax(MathHelper.absMax(mc.player.getX() - (pos.getX() + 0.5), mc.player.getEyeY() - (pos.getY() + 0.5)), mc.player.getZ() - (pos.getZ() + 0.5)) - : mc.player.getPos().distanceTo(Vec3d.ofCenter(pos)); + : mc.player.getEntityPos().distanceTo(Vec3d.ofCenter(pos)); BlockState state = mc.world.getBlockState(pos); if (distTo - 0.5 > getSetting(4).asSlider().getValue() || state.isAir() || state.getBlock() instanceof FluidBlock) @@ -179,7 +179,7 @@ public void onWorldRender(EventWorldRender.Post event) { } if (getSetting(12).asToggle().getState()) { - Vec3d pos = mc.player.getPos().subtract(Renderer.getInterpolationOffset(mc.player)); + Vec3d pos = mc.player.getEntityPos().subtract(Renderer.getInterpolationOffset(mc.player)); double range = getSetting(4).asSlider().getValue(); int color = 0xff000000 | getSetting(12).asToggle().getChild(1).asColor().getRGB(); float width = getSetting(12).asToggle().getChild(0).asSlider().getValueFloat(); @@ -237,7 +237,7 @@ private Pair getBlockAngle(BlockPos pos) { private Comparator getBlockOrderComparator() { // Comparator that moves the block under the player to last // so it doesn't mine itself down without clearing everything above first - Comparator keepBlockUnderComparator = Comparator.comparing(BlockPos.ofFloored(mc.player.getPos().add(0, -0.8, 0))::equals); + Comparator keepBlockUnderComparator = Comparator.comparing(BlockPos.ofFloored(mc.player.getEntityPos().add(0, -0.8, 0))::equals); Comparator distComparator = Comparator.comparingDouble(b -> mc.player.getEyePos().distanceTo(Vec3d.ofCenter(b))); Comparator hardnessComparator = Comparator.comparing(b -> mc.world.getBlockState(b).getHardness(mc.world, b)); diff --git a/src/main/java/org/bleachhack/module/mods/OffhandCrash.java b/src/main/java/org/bleachhack/module/mods/OffhandCrash.java index 296061b91b..679278dd33 100644 --- a/src/main/java/org/bleachhack/module/mods/OffhandCrash.java +++ b/src/main/java/org/bleachhack/module/mods/OffhandCrash.java @@ -34,7 +34,7 @@ public void onTick(EventTick event) { for (int i = 0; i < getSetting(0).asSlider().getValue(); i++) { mc.player.networkHandler.sendPacket(new PlayerActionC2SPacket(Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); if (getSetting(1).asToggle().getState()) - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(true)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(true, mc.player.horizontalCollision)); } } } diff --git a/src/main/java/org/bleachhack/module/mods/PacketFly.java b/src/main/java/org/bleachhack/module/mods/PacketFly.java index 6cfb7353ff..cae86d3c63 100644 --- a/src/main/java/org/bleachhack/module/mods/PacketFly.java +++ b/src/main/java/org/bleachhack/module/mods/PacketFly.java @@ -46,27 +46,39 @@ public void onEnable(boolean inWorld) { super.onEnable(inWorld); - cachedPos = mc.player.getRootVehicle().getPos(); + cachedPos = mc.player.getRootVehicle().getEntityPos(); } @BleachSubscribe public void onMovementPackets(EventSendMovementPackets event) { + // Packet mode moves via real velocity/collision (see onTick) and relies on Minecraft's own + // sendMovementPackets to report the resulting position, so it must not be cancelled here. + if (getSetting(0).asMode().getMode() == 1) { + return; + } + mc.player.setVelocity(Vec3d.ZERO); event.setCancelled(true); } @BleachSubscribe public void onClientMove(EventClientMove event) { + // Packet mode needs real, collision-resolved movement to actually go anywhere - only Phase + // mode (which repositions the entity directly every tick) needs vanilla movement suppressed. + if (getSetting(0).asMode().getMode() == 1) { + return; + } + event.setCancelled(true); } @BleachSubscribe public void onReadPacket(EventPacket.Read event) { if (event.getPacket() instanceof PlayerPositionLookS2CPacket) { + // 1.21.11 merged yaw/pitch into a nested EntityPosition record ("change" field) - widened + // mutable via accesswidener, replaced via withRotation(...). PlayerPositionLookS2CPacket p = (PlayerPositionLookS2CPacket) event.getPacket(); - - p.yaw = mc.player.getYaw(); - p.pitch = mc.player.getPitch(); + p.change = p.change().withRotation(mc.player.getYaw(), mc.player.getPitch()); if (getSetting(4).asToggle().getState()) { event.setCancelled(true); @@ -77,6 +89,13 @@ public void onReadPacket(EventPacket.Read event) { @BleachSubscribe public void onSendPacket(EventPacket.Send event) { + // Only Phase mode hand-crafts its own position packets every tick and wants the automatic + // ones suppressed/simplified; Packet mode needs the normal Full packets (with real look data) + // to go out untouched. + if (getSetting(0).asMode().getMode() != 0) { + return; + } + if (event.getPacket() instanceof PlayerMoveC2SPacket.LookAndOnGround) { event.setCancelled(true); return; @@ -85,7 +104,7 @@ public void onSendPacket(EventPacket.Send event) { if (event.getPacket() instanceof PlayerMoveC2SPacket.Full) { event.setCancelled(true); PlayerMoveC2SPacket p = (PlayerMoveC2SPacket) event.getPacket(); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(p.getX(0), p.getY(0), p.getZ(0), p.isOnGround())); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(p.getX(0), p.getY(0), p.getZ(0), p.isOnGround(), false)); } } @@ -101,22 +120,24 @@ public void onTick(EventTick event) { Vec3d forward = new Vec3d(0, 0, hspeed).rotateY(-(float) Math.toRadians(mc.player.getYaw())); Vec3d moveVec = Vec3d.ZERO; - if (mc.player.input.pressingForward) { + // 1.21.11 replaced Input's individual pressingForward/jumping/... booleans with a single + // PlayerInput record (input.playerInput). + if (mc.player.input.playerInput.forward()) { moveVec = moveVec.add(forward); } - if (mc.player.input.pressingBack) { + if (mc.player.input.playerInput.backward()) { moveVec = moveVec.add(forward.negate()); } - if (mc.player.input.jumping) { + if (mc.player.input.playerInput.jump()) { moveVec = moveVec.add(0, vspeed, 0); } - if (mc.player.input.sneaking) { + if (mc.player.input.playerInput.sneak()) { moveVec = moveVec.add(0, -vspeed, 0); } - if (mc.player.input.pressingLeft) { + if (mc.player.input.playerInput.left()) { moveVec = moveVec.add(forward.rotateY((float) Math.toRadians(90))); } - if (mc.player.input.pressingRight) { + if (mc.player.input.playerInput.right()) { moveVec = moveVec.add(forward.rotateY((float) -Math.toRadians(90))); } @@ -132,34 +153,24 @@ public void onTick(EventTick event) { //target.noClip = true; target.updatePositionAndAngles(cachedPos.x, cachedPos.y, cachedPos.z, mc.player.getYaw(), mc.player.getPitch()); if (target != mc.player) { - mc.player.networkHandler.sendPacket(new VehicleMoveC2SPacket(target)); + mc.player.networkHandler.sendPacket(VehicleMoveC2SPacket.fromVehicle(target)); } else { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(cachedPos.x, cachedPos.y, cachedPos.z, false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(cachedPos.x, cachedPos.y - 0.01, cachedPos.z, true)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(cachedPos.x, cachedPos.y, cachedPos.z, false, false)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(cachedPos.x, cachedPos.y - 0.01, cachedPos.z, true, false)); } } else if (getSetting(0).asMode().getMode() == 1) { - //moveVec = Vec3d.ZERO; - /*if (mc.player.headYaw != mc.player.yaw) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.LookOnly( - mc.player.headYaw, mc.player.pitch, mc.player.isOnGround())); - return; - }*/ - - /*if (mc.options.jumpKey.isPressed()) - mouseY = 0.062; - if (mc.options.sneakKey.isPressed()) - mouseY = -0.062;*/ - + // Packet mode: rather than hand-crafting position packets from an origin that never + // advances (the old code recomputed moveVec from the player's real, unmoved position + // every tick, so it never actually went anywhere), drive real velocity/collision like + // Flight's Static mode does and let Minecraft's normal movement-packet code report the + // resulting position - this also means it respects collision (no wall clipping) and + // looks like ordinary movement to the server, unlike Phase's raw teleport packets. if (timer > getSetting(3).asSlider().getValue()) { - moveVec = new Vec3d(0, -vspeed, 0); + moveVec = moveVec.add(0, -vspeed, 0); timer = 0; } - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( - mc.player.getX() + moveVec.x, mc.player.getY() + moveVec.y, mc.player.getZ() + moveVec.z, false)); - - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( - mc.player.getX() + moveVec.x, mc.player.getY() - 420.69, mc.player.getZ() + moveVec.z, true)); + mc.player.setVelocity(moveVec); } } diff --git a/src/main/java/org/bleachhack/module/mods/Peek.java b/src/main/java/org/bleachhack/module/mods/Peek.java index a13777d698..5cfa02440b 100644 --- a/src/main/java/org/bleachhack/module/mods/Peek.java +++ b/src/main/java/org/bleachhack/module/mods/Peek.java @@ -20,42 +20,59 @@ import org.bleachhack.setting.module.SettingToggle; import org.bleachhack.util.ItemContentUtils; -import com.mojang.blaze3d.systems.RenderSystem; - import net.minecraft.block.AbstractFurnaceBlock; import net.minecraft.block.BarrelBlock; import net.minecraft.block.Block; +import net.minecraft.block.BlockState; import net.minecraft.block.ChestBlock; import net.minecraft.block.DispenserBlock; import net.minecraft.block.HopperBlock; import net.minecraft.block.ShulkerBoxBlock; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.screen.ingame.BookScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.tooltip.TooltipComponent; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.BufferRenderer; -import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.model.Model; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.render.DiffuseLighting; +import net.minecraft.client.render.MapRenderState; +import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.RenderLayers; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.render.block.MovingBlockRenderState; +import net.minecraft.client.render.command.ModelCommandRenderer; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; +import net.minecraft.client.render.command.RenderCommandQueue; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.item.ItemRenderState; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.render.state.CameraRenderState; +import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.MapIdComponent; import net.minecraft.item.BlockItem; import net.minecraft.item.FilledMapItem; +import net.minecraft.item.ItemDisplayContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.map.MapState; import net.minecraft.screen.slot.Slot; +import net.minecraft.text.OrderedText; import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import net.minecraft.util.math.Vec3d; import org.joml.Matrix4f; +import org.joml.Quaternionf; public class Peek extends Module { - private static final RenderLayer MAP_BACKGROUND_CHECKERBOARD = RenderLayer.getText(new Identifier("textures/map/map_background_checkerboard.png")); + private static final RenderLayer MAP_BACKGROUND_CHECKERBOARD = RenderLayers.text(Identifier.ofVanilla("textures/map/map_background_checkerboard.png")); + private static final int FULL_LIGHT = 0xF000F0; private List> pages; private int slotX = -1; @@ -141,6 +158,9 @@ public List drawShulkerToolTip(MatrixStack matrices, Slot slot int count = block instanceof HopperBlock || block instanceof DispenserBlock || block instanceof AbstractFurnaceBlock ? 18 : 0; + VertexConsumerProvider.Immediate immediate = mc.getBufferBuilders().getEntityVertexConsumers(); + OrderedRenderCommandQueue queue = new ImmediateRenderCommandQueue(immediate); + for (ItemStack i : items) { if (count > 26) { break; @@ -149,13 +169,12 @@ public List drawShulkerToolTip(MatrixStack matrices, Slot slot int x = mouseX + 11 + 17 * (count % 9); int y = realY - 67 + 17 * (count / 9); - // mc.getItemRenderer().zOffset = 400; - mc.getItemRenderer().renderInGuiWithOverrides(matrices, i, x, y); - mc.getItemRenderer().renderGuiItemOverlay(matrices, mc.textRenderer, i, x, y, null); - // mc.getItemRenderer().zOffset = 300; + drawItemIcon(matrices, immediate, queue, i, x, y); count++; } + immediate.draw(); + if (mode == 1) { return Arrays.asList(TooltipComponent.of(slot.getStack().getName().asOrderedText())); } else if (mode == 2) { @@ -189,15 +208,9 @@ public void drawBookToolTip(MatrixStack matrices, Slot slot, int mouseX, int mou shown = false; } - RenderSystem.setShader(GameRenderer::getPositionTexProgram); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, BookScreen.BOOK_TEXTURE); - DrawableHelper.drawTexture( - matrices, - mouseX, mouseY - 143, 0, - 0, 0, - 134, 134, - 179, 179); + VertexConsumerProvider.Immediate immediate = mc.getBufferBuilders().getEntityVertexConsumers(); + + drawTexturedQuad(matrices, immediate, BookScreen.BOOK_TEXTURE, mouseX, mouseY - 143, 0, 0, 134, 134, 179, 179); Text pageIndexText = Text.translatable("book.pageIndicator", pageCount + 1, pages.size()); int pageIndexLength = mc.textRenderer.getWidth(pageIndexText); @@ -205,28 +218,28 @@ public void drawBookToolTip(MatrixStack matrices, Slot slot, int mouseX, int mou matrices.push(); matrices.scale(0.7f, 0.7f, 1f); + Matrix4f textMatrix = matrices.peek().getPositionMatrix(); + mc.textRenderer.draw( - matrices, pageIndexText, (mouseX + 123 - pageIndexLength) * 1.43f, (mouseY - 133) * 1.43f, - 0x000000); + 0x000000, false, textMatrix, immediate, TextRenderer.TextLayerType.NORMAL, 0, FULL_LIGHT); int count = 0; for (String s : pages.get(pageCount)) { mc.textRenderer.draw( - matrices, s, (mouseX + 24) * 1.43f, (mouseY - 123 + count * 7) * 1.43f, - 0x000000); + 0x000000, false, textMatrix, immediate, TextRenderer.TextLayerType.NORMAL, 0, FULL_LIGHT); count++; } matrices.pop(); - + immediate.draw(); } public void drawMapToolTip(MatrixStack matrices, Slot slot, int mouseX, int mouseY) { @@ -234,10 +247,10 @@ public void drawMapToolTip(MatrixStack matrices, Slot slot, int mouseX, int mous return; } - Integer id = FilledMapItem.getMapId(slot.getStack()); - MapState mapState = FilledMapItem.getMapState(id, mc.world); + MapIdComponent mapId = slot.getStack().get(DataComponentTypes.MAP_ID); + MapState mapState = FilledMapItem.getMapState(slot.getStack(), mc.world); - if (mapState == null) { + if (mapId == null || mapState == null) { return; } @@ -247,21 +260,91 @@ public void drawMapToolTip(MatrixStack matrices, Slot slot, int mouseX, int mous matrices.translate(mouseX + 14, mouseY - 18 - 135 * scale, 0); matrices.scale(scale, scale, 0.0078125f); - VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); + VertexConsumerProvider.Immediate immediate = mc.getBufferBuilders().getEntityVertexConsumers(); VertexConsumer backgroundVertexer = immediate.getBuffer(MAP_BACKGROUND_CHECKERBOARD); Matrix4f matrix4f = matrices.peek().getPositionMatrix(); - backgroundVertexer.vertex(matrix4f, -7f, 135f, -10f).color(255, 255, 255, 255).texture(0f, 1f).light(0xf000f0).next(); - backgroundVertexer.vertex(matrix4f, 135f, 135f, -10f).color(255, 255, 255, 255).texture(1f, 1f).light(0xf000f0).next(); - backgroundVertexer.vertex(matrix4f, 135f, -7f, -10f).color(255, 255, 255, 255).texture(1f, 0f).light(0xf000f0).next(); - backgroundVertexer.vertex(matrix4f, -7f, -7f, -10f).color(255, 255, 255, 255).texture(0f, 0f).light(0xf000f0).next(); - - mc.gameRenderer.getMapRenderer().draw(matrices, immediate, id, mapState, false, 0xf000f0); + backgroundVertexer.vertex(matrix4f, -7f, 135f, -10f).color(255, 255, 255, 255).texture(0f, 1f).light(FULL_LIGHT); + backgroundVertexer.vertex(matrix4f, 135f, 135f, -10f).color(255, 255, 255, 255).texture(1f, 1f).light(FULL_LIGHT); + backgroundVertexer.vertex(matrix4f, 135f, -7f, -10f).color(255, 255, 255, 255).texture(1f, 0f).light(FULL_LIGHT); + backgroundVertexer.vertex(matrix4f, -7f, -7f, -10f).color(255, 255, 255, 255).texture(0f, 0f).light(FULL_LIGHT); + + MapRenderState renderState = new MapRenderState(); + mc.getMapRenderer().update(mapId, mapState, renderState); + mc.getMapRenderer().draw(renderState, matrices, new ImmediateRenderCommandQueue(immediate), false, FULL_LIGHT); immediate.draw(); matrices.pop(); } + /** + * Renders a single item's icon (baked model) plus its durability/count overlay at the given + * screen position, mirroring what {@code DrawContext.drawItem}/{@code drawStackOverlay} do + * internally, but immediately (since this tooltip preview has no DrawContext of its own to + * queue into - it only has the raw MatrixStack handed to it by EventRenderTooltip). + */ + private void drawItemIcon(MatrixStack matrices, VertexConsumerProvider.Immediate immediate, OrderedRenderCommandQueue queue, ItemStack stack, int x, int y) { + if (stack.isEmpty()) { + return; + } + + ItemRenderState state = new ItemRenderState(); + mc.getItemModelManager().clearAndUpdate(state, stack, ItemDisplayContext.GUI, mc.world, null, 0); + + matrices.push(); + matrices.translate(x + 8.0F, y + 8.0F, 0.0F); + matrices.scale(16.0F, -16.0F, 16.0F); + mc.gameRenderer.getDiffuseLighting().setShaderLights(state.isSideLit() ? DiffuseLighting.Type.ITEMS_3D : DiffuseLighting.Type.ITEMS_FLAT); + state.render(matrices, queue, FULL_LIGHT, OverlayTexture.DEFAULT_UV, 0); + matrices.pop(); + + drawItemOverlay(matrices, immediate, stack, x, y); + } + + private void drawItemOverlay(MatrixStack matrices, VertexConsumerProvider.Immediate immediate, ItemStack stack, int x, int y) { + if (stack.isItemBarVisible()) { + int i = x + 2; + int j = y + 13; + fillRect(matrices, immediate, i, j, i + 13, j + 2, 0xFF000000); + fillRect(matrices, immediate, i, j, i + stack.getItemBarStep(), j + 1, 0xFF000000 | stack.getItemBarColor()); + } + + if (stack.getCount() != 1) { + String string = String.valueOf(stack.getCount()); + mc.textRenderer.draw( + string, + x + 19 - 2 - mc.textRenderer.getWidth(string), + y + 6 + 3, + 0xFFFFFFFF, true, matrices.peek().getPositionMatrix(), immediate, TextRenderer.TextLayerType.NORMAL, 0, FULL_LIGHT); + } + } + + private void drawTexturedQuad(MatrixStack matrices, VertexConsumerProvider vertexConsumers, Identifier texture, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight) { + VertexConsumer consumer = vertexConsumers.getBuffer(RenderLayers.text(texture)); + Matrix4f matrix = matrices.peek().getPositionMatrix(); + float u0 = (float) u / textureWidth; + float u1 = (float) (u + width) / textureWidth; + float v0 = (float) v / textureHeight; + float v1 = (float) (v + height) / textureHeight; + consumer.vertex(matrix, x, y + height, 0).color(255, 255, 255, 255).texture(u0, v1).light(FULL_LIGHT); + consumer.vertex(matrix, x + width, y + height, 0).color(255, 255, 255, 255).texture(u1, v1).light(FULL_LIGHT); + consumer.vertex(matrix, x + width, y, 0).color(255, 255, 255, 255).texture(u1, v0).light(FULL_LIGHT); + consumer.vertex(matrix, x, y, 0).color(255, 255, 255, 255).texture(u0, v0).light(FULL_LIGHT); + } + + private void fillRect(MatrixStack matrices, VertexConsumerProvider vertexConsumers, float x1, float y1, float x2, float y2, int color) { + VertexConsumer consumer = vertexConsumers.getBuffer(RenderLayers.debugQuads()); + Matrix4f matrix = matrices.peek().getPositionMatrix(); + float a = (color >> 24 & 255) / 255.0F; + float r = (color >> 16 & 255) / 255.0F; + float g = (color >> 8 & 255) / 255.0F; + float b = (color & 255) / 255.0F; + consumer.vertex(matrix, x2, y1, 0).color(r, g, b, a); + consumer.vertex(matrix, x1, y1, 0).color(r, g, b, a); + consumer.vertex(matrix, x1, y2, 0).color(r, g, b, a); + consumer.vertex(matrix, x2, y2, 0).color(r, g, b, a); + } + private void renderTooltipBox(MatrixStack matrices, int x1, int y1, int x2, int y2, boolean wrap) { int xStart = x1 + 12; int yStart = y1 - 12; @@ -272,29 +355,24 @@ private void renderTooltipBox(MatrixStack matrices, int x1, int y1, int x2, int yStart = mc.currentScreen.height - y2 - 6; } - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); - + VertexConsumerProvider.Immediate immediate = mc.getBufferBuilders().getEntityVertexConsumers(); Matrix4f matrix4f = matrices.peek().getPositionMatrix(); - fillGradient(matrix4f, bufferBuilder, xStart - 3, yStart - 4, xStart + x2 + 3, yStart - 3, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, xStart - 3, yStart + y2 + 3, xStart + x2 + 3, yStart + y2 + 4, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, xStart - 3, yStart - 3, xStart + x2 + 3, yStart + y2 + 3, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, xStart - 4, yStart - 3, xStart - 3, yStart + y2 + 3, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, xStart + x2 + 3, yStart - 3, xStart + x2 + 4, yStart + y2 + 3, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, xStart - 3, yStart - 3 + 1, xStart - 3 + 1, yStart + y2 + 3 - 1, 1347420415, 1344798847); - fillGradient(matrix4f, bufferBuilder, xStart + x2 + 2, yStart - 3 + 1, xStart + x2 + 3, yStart + y2 + 3 - 1, 1347420415, 1344798847); - fillGradient(matrix4f, bufferBuilder, xStart - 3, yStart - 3, xStart + x2 + 3, yStart - 3 + 1, 1347420415, 1347420415); - fillGradient(matrix4f, bufferBuilder, xStart - 3, yStart + y2 + 2, xStart + x2 + 3, yStart + y2 + 3, 1344798847, 1344798847); - - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); - RenderSystem.disableBlend(); + + fillGradient(matrix4f, immediate, xStart - 3, yStart - 4, xStart + x2 + 3, yStart - 3, -267386864, -267386864); + fillGradient(matrix4f, immediate, xStart - 3, yStart + y2 + 3, xStart + x2 + 3, yStart + y2 + 4, -267386864, -267386864); + fillGradient(matrix4f, immediate, xStart - 3, yStart - 3, xStart + x2 + 3, yStart + y2 + 3, -267386864, -267386864); + fillGradient(matrix4f, immediate, xStart - 4, yStart - 3, xStart - 3, yStart + y2 + 3, -267386864, -267386864); + fillGradient(matrix4f, immediate, xStart + x2 + 3, yStart - 3, xStart + x2 + 4, yStart + y2 + 3, -267386864, -267386864); + fillGradient(matrix4f, immediate, xStart - 3, yStart - 3 + 1, xStart - 3 + 1, yStart + y2 + 3 - 1, 1347420415, 1344798847); + fillGradient(matrix4f, immediate, xStart + x2 + 2, yStart - 3 + 1, xStart + x2 + 3, yStart + y2 + 3 - 1, 1347420415, 1344798847); + fillGradient(matrix4f, immediate, xStart - 3, yStart - 3, xStart + x2 + 3, yStart - 3 + 1, 1347420415, 1347420415); + fillGradient(matrix4f, immediate, xStart - 3, yStart + y2 + 2, xStart + x2 + 3, yStart + y2 + 3, 1344798847, 1344798847); + + immediate.draw(); } - private void fillGradient(Matrix4f matrices, BufferBuilder bufferBuilder, int xStart, int yStart, int xEnd, int yEnd, int colorStart, int colorEnd) { + private void fillGradient(Matrix4f matrix, VertexConsumerProvider vertexConsumers, int xStart, int yStart, int xEnd, int yEnd, int colorStart, int colorEnd) { + VertexConsumer consumer = vertexConsumers.getBuffer(RenderLayers.debugQuads()); float f = (float)(colorStart >> 24 & 255) / 255.0F; float g = (float)(colorStart >> 16 & 255) / 255.0F; float h = (float)(colorStart >> 8 & 255) / 255.0F; @@ -303,9 +381,92 @@ private void fillGradient(Matrix4f matrices, BufferBuilder bufferBuilder, int xS float k = (float)(colorEnd >> 16 & 255) / 255.0F; float l = (float)(colorEnd >> 8 & 255) / 255.0F; float m = (float)(colorEnd & 255) / 255.0F; - bufferBuilder.vertex(matrices, (float) xEnd, (float) yStart, 0f).color(g, h, i, f).next(); - bufferBuilder.vertex(matrices, (float) xStart, (float) yStart, 0f).color(g, h, i, f).next(); - bufferBuilder.vertex(matrices, (float) xStart, (float) yEnd, 0f).color(k, l, m, j).next(); - bufferBuilder.vertex(matrices, (float) xEnd, (float) yEnd, 0f).color(k, l, m, j).next(); + consumer.vertex(matrix, (float) xEnd, (float) yStart, 0f).color(g, h, i, f); + consumer.vertex(matrix, (float) xStart, (float) yStart, 0f).color(g, h, i, f); + consumer.vertex(matrix, (float) xStart, (float) yEnd, 0f).color(k, l, m, j); + consumer.vertex(matrix, (float) xEnd, (float) yEnd, 0f).color(k, l, m, j); + } + + /** + * Minimal {@link OrderedRenderCommandQueue} that renders {@code submitItem}/{@code submitCustom} + * (and the {@code submitText} used by the map decoration labels) immediately into a + * {@link VertexConsumerProvider}, instead of batching them like the real engine-owned queue does. + * + * 1.21.11 moved item/map rendering behind this batching-command-queue abstraction, which is only + * ever handed out by the frame's GUI/world renderer - there is no public API to render a single + * item model or map "right now" outside of that pass anymore. This tiny adapter reconstructs just + * enough of it (submitItem + submitCustom + submitText, which is all plain items and maps need) + * to keep this floating preview working. Other command kinds (special item models such as player + * heads/banners/shields, block models, entities, ...) are left as no-ops - ported: BleachHack's + * container/map preview never rendered those anyway, and reproducing the full batching renderer + * just for this tooltip isn't worth it. + */ + private static class ImmediateRenderCommandQueue implements OrderedRenderCommandQueue { + private final VertexConsumerProvider vertexConsumers; + + private ImmediateRenderCommandQueue(VertexConsumerProvider vertexConsumers) { + this.vertexConsumers = vertexConsumers; + } + + @Override + public RenderCommandQueue getBatchingQueue(int order) { + return this; + } + + @Override + public void submitItem(MatrixStack matrices, ItemDisplayContext displayContext, int light, int overlay, int outlineColors, int[] tintLayers, List quads, RenderLayer renderLayer, ItemRenderState.Glint glintType) { + ItemRenderer.renderItem(displayContext, matrices, vertexConsumers, light, overlay, tintLayers, quads, renderLayer, glintType); + } + + @Override + public void submitCustom(MatrixStack matrices, RenderLayer renderLayer, OrderedRenderCommandQueue.Custom customRenderer) { + customRenderer.render(matrices.peek(), vertexConsumers.getBuffer(renderLayer)); + } + + @Override + public void submitCustom(OrderedRenderCommandQueue.LayeredCustom customRenderer) { + // not supported by this lightweight immediate-mode adapter, see class javadoc + } + + @Override + public void submitText(MatrixStack matrices, float x, float y, OrderedText text, boolean dropShadow, TextRenderer.TextLayerType layerType, int light, int color, int backgroundColor, int outlineColor) { + mc.textRenderer.draw(text, x, y, color, dropShadow, matrices.peek().getPositionMatrix(), vertexConsumers, layerType, backgroundColor, light); + } + + @Override + public void submitShadowPieces(MatrixStack matrices, float shadowRadius, List shadowPieces) { + } + + @Override + public void submitLabel(MatrixStack matrices, Vec3d nameLabelPos, int y, Text label, boolean notSneaking, int light, double squaredDistanceToCamera, CameraRenderState cameraState) { + } + + @Override + public void submitFire(MatrixStack matrices, EntityRenderState renderState, Quaternionf rotation) { + } + + @Override + public void submitLeash(MatrixStack matrices, EntityRenderState.LeashData leashData) { + } + + @Override + public void submitModel(Model model, S state, MatrixStack matrices, RenderLayer renderLayer, int light, int overlay, int tintedColor, Sprite sprite, int outlineColor, ModelCommandRenderer.CrumblingOverlayCommand crumblingOverlay) { + } + + @Override + public void submitModelPart(ModelPart part, MatrixStack matrices, RenderLayer renderLayer, int light, int overlay, Sprite sprite, boolean sheeted, boolean hasGlint, int tintedColor, ModelCommandRenderer.CrumblingOverlayCommand crumblingOverlay, int i) { + } + + @Override + public void submitBlock(MatrixStack matrices, BlockState state, int light, int overlay, int outlineColor) { + } + + @Override + public void submitMovingBlock(MatrixStack matrices, MovingBlockRenderState state) { + } + + @Override + public void submitBlockStateModel(MatrixStack matrices, RenderLayer renderLayer, BlockStateModel model, float r, float g, float b, int light, int overlay, int outlineColor) { + } } } diff --git a/src/main/java/org/bleachhack/module/mods/PlayerCrash.java b/src/main/java/org/bleachhack/module/mods/PlayerCrash.java index 89df9ab5da..935f5cfb9e 100644 --- a/src/main/java/org/bleachhack/module/mods/PlayerCrash.java +++ b/src/main/java/org/bleachhack/module/mods/PlayerCrash.java @@ -14,7 +14,7 @@ import org.bleachhack.module.ModuleCategory; import org.bleachhack.setting.module.SettingSlider; -import net.minecraft.network.packet.c2s.play.KeepAliveC2SPacket; +import net.minecraft.network.packet.c2s.common.KeepAliveC2SPacket; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; public class PlayerCrash extends Module { @@ -27,7 +27,7 @@ public PlayerCrash() { @BleachSubscribe public void onTick(EventTick event) { for (int i = 0; i < getSetting(0).asSlider().getValue(); i++) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(Math.random() >= 0.5)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(Math.random() >= 0.5, mc.player.horizontalCollision)); mc.player.networkHandler.sendPacket(new KeepAliveC2SPacket((int) (Math.random() * 8))); } } diff --git a/src/main/java/org/bleachhack/module/mods/ProjectileLauncher.java b/src/main/java/org/bleachhack/module/mods/ProjectileLauncher.java new file mode 100644 index 0000000000..78300f18e2 --- /dev/null +++ b/src/main/java/org/bleachhack/module/mods/ProjectileLauncher.java @@ -0,0 +1,229 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.module.mods; + +import org.bleachhack.event.events.EventPacket; +import org.bleachhack.event.events.EventTick; +import org.bleachhack.eventbus.BleachSubscribe; +import org.bleachhack.module.Module; +import org.bleachhack.module.ModuleCategory; +import org.bleachhack.module.ModuleManager; +import org.bleachhack.setting.module.SettingItemList; +import org.bleachhack.setting.module.SettingMode; +import org.bleachhack.setting.module.SettingSlider; +import org.bleachhack.setting.module.SettingToggle; +import org.bleachhack.util.world.WorldUtils; + +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; + +/** + * Ported from Trouser-Streak's ProjectileLauncher (https://github.com/etianl/Trouser-Streak). + */ +public class ProjectileLauncher extends Module { + + private boolean sendingItemUse; + private boolean chargingBow; + private int bowChargeTicks; + + public ProjectileLauncher() { + this(new SettingToggle("Legacy Mode", false).withDesc("An older jitter-based technique that costs hunger instead of teleporting. Doesn't work on most servers - only worth trying on old Paper versions where the teleport trick fails."), + new SettingMode("Mode", "Vanilla", "Paper").withDesc("Vanilla: reach capped at 22 blocks. Paper: a much longer reach is often possible."), + new SettingToggle("Auto Calculate Packets", true).withDesc("Scales the spam packet count based on the clip distance instead of using a fixed amount.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the toggles other + // settings react to as constructor parameters first lets the predicates below capture those + // local variables instead. + private ProjectileLauncher(SettingToggle legacyMode, SettingMode compatMode, SettingToggle autoPackets) { + super("ProjectileLauncher", KEY_UNBOUND, ModuleCategory.EXPLOITS, + "Teleports away and back when you use a throwable/bow, so it launches from further away.", + legacyMode, + new SettingSlider("Multiplier", 1, 300, 90, 0).withDesc("Legacy Mode only: higher makes it more likely to work, but costs more hunger.") + .visibleWhen(legacyMode::getState), + new SettingMode("Direction", "Back", "Forward").withDesc("Teleport behind you (opposite your look direction) or ahead of you before using the item.") + .visibleWhen(() -> !legacyMode.getState()), + compatMode.visibleWhen(() -> !legacyMode.getState()), + new SettingSlider("Distance", 1, 22, 21, 0).withDesc("How far to teleport before using the item.") + .visibleWhen(() -> !legacyMode.getState() && compatMode.getMode() == 0), + new SettingSlider("Distance", 1, 199, 149, 0).withDesc("How far to teleport before using the item.") + .visibleWhen(() -> !legacyMode.getState() && compatMode.getMode() == 1), + new SettingSlider("Min Distance", 0.5, 21, 2, 1).withDesc("Only teleport if at least this much clear space is available.") + .visibleWhen(() -> !legacyMode.getState()), + autoPackets.visibleWhen(() -> !legacyMode.getState()), + new SettingSlider("Packets", 1, 17, 4, 0).withDesc("Fixed spam packet count, used when Auto Calculate Packets is off.") + .visibleWhen(() -> !legacyMode.getState() && !autoPackets.getState()), + new SettingItemList("Items", "Edit Projectile Items", + Items.ENDER_PEARL, Items.SPLASH_POTION, Items.LINGERING_POTION, Items.EXPERIENCE_BOTTLE, + Items.SNOWBALL, Items.EGG, Items.WIND_CHARGE).withDesc("Which throwable items this applies to."), + new SettingToggle("Bow Machinegun", true).withDesc("Automatically releases your bow/trident as soon as it's charged enough.").withChildren( + new SettingSlider("Charge Ticks", 4, 60, 20, 0).withDesc("How many ticks to charge before auto-releasing."))); + } + + private double getMaxDistance() { + return getSetting(3).asMode().getMode() == 0 ? getSetting(4).asSlider().getValue() : getSetting(5).asSlider().getValue(); + } + + @Override + public void onDisable(boolean inWorld) { + chargingBow = false; + bowChargeTicks = 0; + super.onDisable(inWorld); + } + + @BleachSubscribe + public void onTick(EventTick event) { + if (!getSetting(10).asToggle().getState()) { + return; + } + + boolean holdingBow = mc.player.getMainHandStack().getItem() == Items.BOW + || mc.player.getMainHandStack().getItem() == Items.TRIDENT + || mc.player.getOffHandStack().getItem() == Items.BOW + || mc.player.getOffHandStack().getItem() == Items.TRIDENT; + + if (!holdingBow || !chargingBow) { + bowChargeTicks = 0; + return; + } + + if (++bowChargeTicks >= getSetting(10).asToggle().getChild(0).asSlider().getValueInt()) { + mc.player.networkHandler.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.RELEASE_USE_ITEM, BlockPos.ORIGIN, Direction.DOWN)); + bowChargeTicks = 0; + chargingBow = false; + } + } + + @BleachSubscribe + public void onSendPacket(EventPacket.Send event) { + if (sendingItemUse) { + return; + } + + if (event.getPacket() instanceof PlayerInteractItemC2SPacket packet) { + Item item = (packet.getHand() == Hand.MAIN_HAND ? mc.player.getMainHandStack() : mc.player.getOffHandStack()).getItem(); + + if (getSetting(9).asList(Item.class).contains(item)) { + if (getSetting(0).asToggle().getState()) { + sendLegacyPackets(); + } else { + event.setCancelled(true); + launch(packet); + } + } else if (item == Items.BOW || item == Items.TRIDENT) { + chargingBow = true; + } + return; + } + + if (chargingBow && event.getPacket() instanceof PlayerActionC2SPacket packet + && packet.getAction() == PlayerActionC2SPacket.Action.RELEASE_USE_ITEM) { + chargingBow = false; + + if (getSetting(0).asToggle().getState()) { + sendLegacyPackets(); + } else { + event.setCancelled(true); + launch(packet); + } + } + } + + // Legacy Mode: instead of teleporting, spam tiny sub-pixel Y jitters while sprinting. On some + // old Paper versions this desyncs the server's own movement/hunger tracking enough that the + // projectile still launches with extra distance - it doesn't intercept or cancel the real + // item-use packet, it just fires this burst right before it goes out normally. + private void sendLegacyPackets() { + AntiHunger antiHunger = ModuleManager.getModule(AntiHunger.class); + boolean antiHungerWasEnabled = antiHunger.isEnabled(); + if (antiHungerWasEnabled) { + antiHunger.toggle(); + } + + mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_SPRINTING)); + + int count = getSetting(1).asSlider().getValueInt(); + for (int i = 0; i < count; i++) { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + mc.player.getX(), mc.player.getY() - 0.000000001, mc.player.getZ(), true, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + mc.player.getX(), mc.player.getY() + 0.000000001, mc.player.getZ(), false, mc.player.horizontalCollision)); + } + + if (!mc.player.isSprinting()) { + mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.STOP_SPRINTING)); + } + + if (antiHungerWasEnabled) { + antiHunger.toggle(); + } + } + + private void launch(Packet useItemPacket) { + Vec3d home = mc.player.getEntityPos(); + Vec3d look = mc.player.getRotationVec(1f); + Vec3d direction = getSetting(2).asMode().getMode() == 0 ? look.negate() : look; + + double maxDistance = getMaxDistance(); + double minDistance = getSetting(6).asSlider().getValue(); + + Vec3d target = findFurthestSafePos(home, direction, maxDistance, minDistance); + if (target == null) { + // try the opposite direction before giving up + target = findFurthestSafePos(home, direction.negate(), maxDistance, minDistance); + } + if (target == null) { + mc.player.networkHandler.sendPacket(useItemPacket); + return; + } + + spamStatusPackets(home.distanceTo(target)); + + WorldUtils.sendTeleport(target); + sendingItemUse = true; + mc.player.networkHandler.sendPacket(useItemPacket); + sendingItemUse = false; + + WorldUtils.sendTeleport(home); + WorldUtils.sendTeleport(WorldUtils.findSafeOffset(mc.player, home, 0.05, 0.001)); + } + + private Vec3d findFurthestSafePos(Vec3d start, Vec3d direction, double maxDistance, double minDistance) { + for (double dist = maxDistance; dist >= minDistance; dist -= 0.5) { + Vec3d candidate = start.add(direction.multiply(dist)); + if (!WorldUtils.isTeleportUnsafe(mc.player, candidate)) { + return candidate; + } + } + return null; + } + + // Auto Calculate Packets scales the spam count with the actual clip distance - a longer clip + // is a bigger, more suspicious jump and needs more "you're grounded" spam beforehand. + private void spamStatusPackets(double distance) { + int count = getSetting(7).asToggle().getState() + ? Math.min(17, Math.max(1, (int) Math.ceil(distance / 5.0))) + : getSetting(8).asSlider().getValueInt(); + + for (int i = 0; i < count; i++) { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(false, mc.player.horizontalCollision)); + } + } + +} diff --git a/src/main/java/org/bleachhack/module/mods/RotationSnap.java b/src/main/java/org/bleachhack/module/mods/RotationSnap.java index ca607a3060..ee860d6361 100644 --- a/src/main/java/org/bleachhack/module/mods/RotationSnap.java +++ b/src/main/java/org/bleachhack/module/mods/RotationSnap.java @@ -45,31 +45,31 @@ public void onTick(EventTick event) { int yAngle = yMode == 0 ? 45 : yMode == 1 ? 30 : yMode == 2 ? 15 : 90; int pAngle = pMode == 0 ? 45 : pMode == 1 ? 30 : pMode == 2 ? 15 : 90; - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_LEFT) && !lDown) { + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_LEFT) && !lDown) { mc.player.setYaw(mc.player.getYaw() - yAngle); lDown = true; - } else if (!InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_LEFT)) { + } else if (!InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_LEFT)) { lDown = false; } - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_RIGHT) && !rDown) { + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_RIGHT) && !rDown) { mc.player.setYaw(mc.player.getYaw() + yAngle); rDown = true; - } else if (!InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_RIGHT)) { + } else if (!InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_RIGHT)) { rDown = false; } - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_UP) && !uDown) { + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_UP) && !uDown) { mc.player.setPitch(MathHelper.clamp(mc.player.getPitch() - pAngle, -90, 90)); uDown = true; - } else if (!InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_UP)) { + } else if (!InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_UP)) { uDown = false; } - if (InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_DOWN) && !dDown) { + if (InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_DOWN) && !dDown) { mc.player.setPitch(MathHelper.clamp(mc.player.getPitch() + pAngle, -90, 90)); dDown = true; - } else if (!InputUtil.isKeyPressed(mc.getWindow().getHandle(), GLFW.GLFW_KEY_DOWN)) { + } else if (!InputUtil.isKeyPressed(mc.getWindow(), GLFW.GLFW_KEY_DOWN)) { dDown = false; } } diff --git a/src/main/java/org/bleachhack/module/mods/Scaffold.java b/src/main/java/org/bleachhack/module/mods/Scaffold.java index 31d93436bf..cc53e85fc6 100644 --- a/src/main/java/org/bleachhack/module/mods/Scaffold.java +++ b/src/main/java/org/bleachhack/module/mods/Scaffold.java @@ -38,7 +38,7 @@ public class Scaffold extends Module { private Set renderBlocks = new LinkedHashSet<>(); public Scaffold() { - super("Scaffold", KEY_UNBOUND, ModuleCategory.WORLD, "Places blocks under you", + super("Scaffold", KEY_UNBOUND, ModuleCategory.WORLD, "Places blocks under you.", new SettingMode("Area", "Normal", "3x3", "5x5", "7x7").withDesc("How big of an area to scaffold."), new SettingSlider("BPT", 1, 10, 2, 0).withDesc("Blocks Per Tick, how many blocks to place per tick."), new SettingSlider("Range", 0, 1, 0.3, 1).withDesc("How far to place ahead of you in Normal mode."), @@ -90,7 +90,7 @@ public void onTick(EventTick event) { double range = getSetting(2).asSlider().getValue(); int mode = getSetting(0).asMode().getMode(); - Vec3d placeVec = mc.player.getPos().add(0, -0.85, 0); + Vec3d placeVec = mc.player.getEntityPos().add(0, -0.85, 0); Set blocks = mode == 0 ? Sets.newHashSet( BlockPos.ofFloored(placeVec), @@ -101,10 +101,10 @@ public void onTick(EventTick event) { : getSpiral(mode, BlockPos.ofFloored(placeVec)); if (getSetting(6).asToggle().getState() - && InputUtil.isKeyPressed(mc.getWindow().getHandle(), InputUtil.fromTranslationKey(mc.options.jumpKey.getBoundKeyTranslationKey()).getCode())) { + && InputUtil.isKeyPressed(mc.getWindow(), InputUtil.fromTranslationKey(mc.options.jumpKey.getBoundKeyTranslationKey()).getCode())) { - if (mc.world.getBlockState(mc.player.getBlockPos().down()).getMaterial().isReplaceable() - && !mc.world.getBlockState(mc.player.getBlockPos().down(2)).getMaterial().isReplaceable() + if (mc.world.getBlockState(mc.player.getBlockPos().down()).isReplaceable() + && !mc.world.getBlockState(mc.player.getBlockPos().down(2)).isReplaceable() && mc.player.getVelocity().y > 0) { mc.player.setVelocity(mc.player.getVelocity().x, -0.1, mc.player.getVelocity().z); diff --git a/src/main/java/org/bleachhack/module/mods/Search.java b/src/main/java/org/bleachhack/module/mods/Search.java index fb38c7c43f..f7fd6098c2 100644 --- a/src/main/java/org/bleachhack/module/mods/Search.java +++ b/src/main/java/org/bleachhack/module/mods/Search.java @@ -13,7 +13,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; +import net.minecraft.network.packet.s2c.common.DisconnectS2CPacket; import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; import net.minecraft.util.math.BlockPos; @@ -62,7 +62,7 @@ public class Search extends Module { SettingList list = getSetting(5).asList(Block.class); for (int x = 0; x < 16; x++) { - for (int y = mc.world.getBottomY(); y < mc.world.getTopY(); y++) { + for (int y = mc.world.getBottomY(); y <= mc.world.getTopYInclusive(); y++) { for (int z = 0; z < 16; z++) { BlockPos pos = new BlockPos(cp.getStartX() + x, y, cp.getStartZ() + z); BlockState state = chunk.getBlockState(pos); @@ -80,7 +80,7 @@ public class Search extends Module { if (be != null) { logBuilder .append(" BlockEntity") - .append(be.createNbt().asString()); + .append(be.createNbt(mc.world.getRegistryManager()).asString()); } logBuilder.append('\n'); @@ -113,10 +113,20 @@ public class Search extends Module { private int oldViewDistance = -1; public Search() { + this(new SettingMode("Render", "Box+Fill", "Box", "Fill").withDesc("The rendering method.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Render mode + // setting as a constructor parameter first lets the predicates below capture that local + // variable instead. + private Search(SettingMode renderMode) { super("Search", KEY_UNBOUND, ModuleCategory.RENDER, "Highlights certain blocks.", - new SettingMode("Render", "Box+Fill", "Box", "Fill").withDesc("The rendering method."), - new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The thickness of the box lines."), - new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill."), + renderMode, + new SettingSlider("Box", 0.1, 4, 2, 1).withDesc("The thickness of the box lines.") + .visibleWhen(() -> renderMode.getMode() != 2), + new SettingSlider("Fill", 0, 1, 0.3, 2).withDesc("The opacity of the fill.") + .visibleWhen(() -> renderMode.getMode() != 1), new SettingToggle("Tracers", false).withDesc("Renders a line from the player to all found blocks.").withChildren( new SettingSlider("Width", 0.1, 5, 1.5, 1).withDesc("Thickness of the tracers."), new SettingSlider("Opacity", 0, 1, 0.75, 2).withDesc("Opacity of the tracers.")), @@ -211,7 +221,7 @@ public void onRender(EventWorldRender.Post event) { Vec3d lookVec = new Vec3d(0, 0, 75) .rotateX(-(float) Math.toRadians(mc.gameRenderer.getCamera().getPitch())) .rotateY(-(float) Math.toRadians(mc.gameRenderer.getCamera().getYaw())) - .add(mc.cameraEntity.getEyePos()); + .add(mc.getCameraEntity().getEyePos()); Renderer.drawLine( lookVec.x, lookVec.y, lookVec.z, diff --git a/src/main/java/org/bleachhack/module/mods/ShaderRender.java b/src/main/java/org/bleachhack/module/mods/ShaderRender.java index 32965fb052..9024c33a32 100644 --- a/src/main/java/org/bleachhack/module/mods/ShaderRender.java +++ b/src/main/java/org/bleachhack/module/mods/ShaderRender.java @@ -8,65 +8,69 @@ */ package org.bleachhack.module.mods; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; +import java.util.Set; import net.minecraft.client.gl.PostEffectProcessor; +import net.minecraft.client.render.DefaultFramebufferSet; import org.bleachhack.event.events.EventRenderShader; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; import org.bleachhack.module.ModuleCategory; import org.bleachhack.setting.module.SettingMode; -import com.google.gson.JsonSyntaxException; - import net.minecraft.util.Identifier; public class ShaderRender extends Module { - private Identifier lastId = null; - private PostEffectProcessor lastShader = null; - private int lastWidth; - private int lastHeight; + // 1.21.11 removed most of the old "Super Secret Settings" post-effect shaders from the vanilla + // jar - Invert/Creeper/Spider are the only 3 of the original 24 modes that still ship as real + // assets/minecraft/post_effect/json files. The rest have been ported from Minecraft 1.19.4's + // own (Mojang) GLSL/JSON assets against the new post-effect pipeline - see + // src/main/resources/assets/bleachhack/{post_effect,shaders/post}. Art/Flip/NTSC/Outline/ + // Phosphor are still missing (multi-pass chains with frame-feedback targets or a custom vertex + // shader - not ported yet). Wobble crashed the client with "Buffer already closed" during a + // later, unrelated renderBlur() call and was pulled without a confirmed root cause - possibly + // the same issue as Blur below, possibly something else; not re-added without being able to + // verify it. + // + // Blur is its own bleachhack:blur post_effect (reusing vanilla's box_blur.fsh) instead of + // vanilla's minecraft:blur - GameRenderer.renderBlur() (menu/inventory background blur) loads + // that exact ID too, and ShaderLoader caches processors by ID, so this mixin's per-frame + // render() call and vanilla's own renderBlur() call were driving the *same* PostEffectProcessor + // instance through two different render() overloads. That's what was actually crashing, not + // blur's own shader logic. + private static final Set VANILLA_STILL_AVAILABLE = Set.of("invert", "creeper", "spider"); + private static final Set PORTED = Set.of("notch", "fxaa", "bumpy", "blobs", "blobs2", "pencil", "vibrant", + "deconverge", "scanline", "sobel", "bits", "desaturate", "green", "antialias", "blur"); - private List shaders = new ArrayList<>(); + private String lastMode = null; + private PostEffectProcessor lastShader = null; public ShaderRender() { - super("ShaderRender", KEY_UNBOUND, ModuleCategory.RENDER, "1.7 Super secret settings.", + super("ShaderRender", KEY_UNBOUND, ModuleCategory.RENDER, "Applies a full-screen shader effect to the game (Minecraft's old vanilla shader packs).", new SettingMode("Shader", "Notch", "FXAA", "Art", "Bumpy", "Blobs", "Blobs2", "Pencil", "Vibrant", "Deconverge", "Flip", "Invert", "NTSC", "Outline", "Phosphor", "Scanline", "Sobel", "Bits", "Desaturate", "Green", "Blur", "Wobble", "Antialias", "Creeper", "Spider").withDesc("Shader to use.")); - - for (String s: getSetting(0).asMode().modes) { - if (s.equals("Vibrant")) { - shaders.add(new Identifier("shaders/post/color_convolve.json")); - } else if (s.equals("Scanline")) { - shaders.add(new Identifier("shaders/post/scan_pincushion.json")); - } else { - shaders.add(new Identifier("shaders/post/" + s.toLowerCase(Locale.ENGLISH) + ".json")); - } - } } @BleachSubscribe public void onWorldRender(EventRenderShader event) { - if (lastShader == null || lastWidth != mc.getWindow().getFramebufferWidth() || lastHeight != mc.getWindow().getFramebufferHeight() - || !shaders.get(getSetting(0).asMode().getMode()).equals(lastId)) { - lastId = shaders.get(getSetting(0).asMode().getMode()); - lastWidth = mc.getWindow().getFramebufferWidth(); - lastHeight = mc.getWindow().getFramebufferHeight(); + String[] modes = getSetting(0).asMode().modes; + String mode = modes[getSetting(0).asMode().getMode()].toLowerCase(Locale.ENGLISH); + + if (!mode.equals(lastMode)) { + lastMode = mode; - try { - if (lastShader != null) { - lastShader.close(); - } + if (lastShader != null) { + lastShader.close(); + lastShader = null; + } - lastShader = new PostEffectProcessor(mc.getTextureManager(), mc.getResourceManager(), mc.getFramebuffer(), lastId); - lastShader.setupDimensions(mc.getWindow().getFramebufferWidth(), mc.getWindow().getFramebufferHeight()); - } catch (JsonSyntaxException | IOException e) { - e.printStackTrace(); + if (VANILLA_STILL_AVAILABLE.contains(mode)) { + lastShader = mc.getShaderLoader().loadPostEffect(Identifier.of("minecraft", mode), DefaultFramebufferSet.MAIN_ONLY); + } else if (PORTED.contains(mode)) { + lastShader = mc.getShaderLoader().loadPostEffect(Identifier.of("bleachhack", mode), DefaultFramebufferSet.MAIN_ONLY); } } diff --git a/src/main/java/org/bleachhack/module/mods/Sneak.java b/src/main/java/org/bleachhack/module/mods/Sneak.java index 6d742d17a9..0480dc1262 100644 --- a/src/main/java/org/bleachhack/module/mods/Sneak.java +++ b/src/main/java/org/bleachhack/module/mods/Sneak.java @@ -7,12 +7,11 @@ import org.bleachhack.module.ModuleCategory; import org.bleachhack.setting.module.SettingMode; -import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInputC2SPacket; +import net.minecraft.util.PlayerInput; public class Sneak extends Module { - private boolean packetSent; - public Sneak() { super("Sneak", KEY_UNBOUND, ModuleCategory.MOVEMENT, "Makes you automatically sneak.", new SettingMode("Mode", "Legit", "Packet").withDesc("Mode for sneaking (Only other players will see u sneaking with packet mode).")); @@ -20,43 +19,27 @@ public Sneak() { @Override public void onDisable(boolean inWorld) { - packetSent = false; mc.options.sneakKey.setPressed(false); - if (inWorld) - mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY)); - super.onDisable(inWorld); } - @Override - public void onEnable(boolean inWorld) { - super.onEnable(inWorld); - - if (getSetting(0).asMode().getMode() == 1) { - if (inWorld) - mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY)); - - packetSent = true; - } - } - @BleachSubscribe public void onTick(EventTick event) { if (getSetting(0).asMode().getMode() == 0) { mc.options.sneakKey.setPressed(true); - } else if (getSetting(0).asMode().getMode() == 1 && !packetSent) { - mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY)); - packetSent = true; } } + // ported: 1.19.4 toggled sneaking server-side via a discrete ClientCommandC2SPacket press/release + // command. That packet mode was removed; sneak is now one field of the continuous per-tick + // PlayerInputC2SPacket, so "packet mode" now works by rewriting that field on every outgoing + // packet instead of sending/cancelling a one-off command. @BleachSubscribe public void onSendPacket(EventPacket.Send event) { - if (event.getPacket() instanceof ClientCommandC2SPacket) { - ClientCommandC2SPacket p = (ClientCommandC2SPacket) event.getPacket(); - if (p.getMode() == ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY) - event.setCancelled(true); + if (getSetting(0).asMode().getMode() == 1 && event.getPacket() instanceof PlayerInputC2SPacket p && !p.input().sneak()) { + PlayerInput i = p.input(); + event.setPacket(new PlayerInputC2SPacket(new PlayerInput(i.forward(), i.backward(), i.left(), i.right(), i.jump(), true, i.sprint()))); } } } diff --git a/src/main/java/org/bleachhack/module/mods/Solidify.java b/src/main/java/org/bleachhack/module/mods/Solidify.java index bd8094377f..4f99633cc3 100644 --- a/src/main/java/org/bleachhack/module/mods/Solidify.java +++ b/src/main/java/org/bleachhack/module/mods/Solidify.java @@ -68,8 +68,8 @@ public void onSendPacket(EventPacket.Send event) { if (getSetting(7).asToggle().getState()) { if (event.getPacket() instanceof VehicleMoveC2SPacket) { VehicleMoveC2SPacket packet = (VehicleMoveC2SPacket) event.getPacket(); - if (!mc.world.getChunkManager().isChunkLoaded((int) packet.getX() >> 4, (int) packet.getZ() >> 4)) { - mc.player.getVehicle().updatePosition(mc.player.getVehicle().prevX, mc.player.getVehicle().prevY, mc.player.getVehicle().prevZ); + if (!mc.world.getChunkManager().isChunkLoaded((int) packet.position().getX() >> 4, (int) packet.position().getZ() >> 4)) { + mc.player.getVehicle().updatePosition(mc.player.getVehicle().lastX, mc.player.getVehicle().lastY, mc.player.getVehicle().lastZ); event.setCancelled(true); } } else if (event.getPacket() instanceof PlayerMoveC2SPacket) { diff --git a/src/main/java/org/bleachhack/module/mods/SpearKill.java b/src/main/java/org/bleachhack/module/mods/SpearKill.java new file mode 100644 index 0000000000..bba878c6e3 --- /dev/null +++ b/src/main/java/org/bleachhack/module/mods/SpearKill.java @@ -0,0 +1,262 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.module.mods; + +import org.bleachhack.BleachHack; +import org.bleachhack.event.events.EventPacket; +import org.bleachhack.event.events.EventTick; +import org.bleachhack.eventbus.BleachSubscribe; +import org.bleachhack.module.Module; +import org.bleachhack.module.ModuleCategory; +import org.bleachhack.setting.module.SettingMode; +import org.bleachhack.setting.module.SettingSlider; +import org.bleachhack.setting.module.SettingToggle; +import org.bleachhack.util.world.WorldUtils; + +import net.minecraft.component.DataComponentTypes; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.ProjectileUtil; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.math.Vec3d; + +/** + * Ported from Trouser-Streak's SpearKill (https://github.com/etianl/Trouser-Streak). Vanilla's + * Spear deals bonus "kinetic" damage the longer you hold high speed toward your target while + * charging a thrust - Lunge boosts your real velocity to build that speed reliably, Blink instead + * withholds your movement packets while charging and releases them as one large jump when close + * enough, so the server only ever sees you already there. + */ +public class SpearKill extends Module { + + private Entity target; + private boolean charging; + private boolean holdingPackets; + private Vec3d blinkStart; + private boolean aboveFirstPhase; + private Vec3d abovePos; + private int blinkLungeTicks; + + public SpearKill() { + this(new SettingMode("Mode", "Lunge", "Blink").withDesc("How to reach charging speed. Lunge: push you toward the target with real velocity. Blink: hold your movement back, then release it all as one jump."), + new SettingMode("Direction", "Direct", "Above", "Auto").withDesc("Direct: lunge straight at the target. Above: lunge to a point over the target first, then stab down. Auto: try Above, but use Direct if the spot above (or the way down) is blocked."), + new SettingToggle("Blink+Lunge", false).withDesc("Also push you toward the target with velocity while charging in Blink mode.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the settings other + // settings react to as constructor parameters first lets the predicates below capture those + // local variables instead. + private SpearKill(SettingMode mode, SettingMode lungeDirection, SettingToggle blinkLunge) { + super("SpearKill", KEY_UNBOUND, ModuleCategory.EXPLOITS, + "Helps you reach the speed vanilla's Spear needs for a charged hit.", + mode, + new SettingSlider("Max Range", 1, 512, 256, 0).withDesc("How far away a target can be and still get locked onto."), + new SettingToggle("Ignore Friends", true).withDesc("Never targets players on your friend list."), + + new SettingSlider("Strength", 0.1, 10, 5, 1).withDesc("How fast to push you toward the target.") + .visibleWhen(() -> mode.getMode() == 0 || blinkLunge.getState()), + new SettingToggle("Stop On Target", true).withDesc("Stops pushing you once you've reached the target.").withChildren( + new SettingSlider("Stop Dist", 0, 10, 2, 1).withDesc("How close to the target counts as \"reached\".")) + .visibleWhen(() -> mode.getMode() == 0), + lungeDirection.visibleWhen(() -> mode.getMode() == 0), + new SettingSlider("Height", 1, 30, 6, 1).withDesc("How many blocks above the target to aim for first (Above/Auto only).") + .visibleWhen(() -> mode.getMode() == 0 && lungeDirection.getMode() != 0), + new SettingSlider("Trigger", 0.5, 10, 2, 1).withDesc("How close to the point above the target before switching to a direct lunge.") + .visibleWhen(() -> mode.getMode() == 0 && lungeDirection.getMode() != 0), + new SettingToggle("Validate Path", true).withDesc("Auto only: makes sure the spot above the target and the way down are actually clear before committing to it.") + .visibleWhen(() -> mode.getMode() == 0 && lungeDirection.getMode() == 2), + + new SettingSlider("Flush", 1, 10, 3, 1).withDesc("How close to the target before releasing your held movement.") + .visibleWhen(() -> mode.getMode() == 1), + blinkLunge.visibleWhen(() -> mode.getMode() == 1), + new SettingSlider("Lunge Delay", 1, 30, 15, 0).withDesc("How many ticks to charge before the Blink+Lunge push kicks in.") + .visibleWhen(() -> mode.getMode() == 1 && blinkLunge.getState()), + new SettingToggle("Raycast", true).withDesc("Only locks onto targets you can see.")); + } + + @Override + public void onDisable(boolean inWorld) { + if (charging && getSetting(0).asMode().getMode() == 1) { + flush(); + } + + reset(); + super.onDisable(inWorld); + } + + private void reset() { + target = null; + charging = false; + holdingPackets = false; + blinkStart = null; + aboveFirstPhase = false; + abovePos = null; + blinkLungeTicks = 0; + } + + @BleachSubscribe + public void onTick(EventTick event) { + boolean nowCharging = mc.player.isUsingItem() && mc.player.getActiveItem().contains(DataComponentTypes.KINETIC_WEAPON); + + if (nowCharging && target == null) { + target = findTarget(); + } + + if (!nowCharging && charging) { + if (getSetting(0).asMode().getMode() == 1) { + flush(); + } + reset(); + } + charging = nowCharging; + + if (!charging || target == null || !target.isAlive()) { + return; + } + + rotateToTarget(); + + if (getSetting(0).asMode().getMode() == 0) { + lunge(); + } else { + blink(); + } + } + + private void lunge() { + double stopDistance = getSetting(4).asToggle().getState() ? getSetting(4).asToggle().getChild(0).asSlider().getValue() : -1; + if (stopDistance >= 0 && mc.player.getBoundingBox().expand(stopDistance).intersects(target.getBoundingBox())) { + mc.player.setVelocity(Vec3d.ZERO); + target = null; + return; + } + + mc.player.setSprinting(true); + mc.player.setVelocity(lungeDirectionVec().multiply(getSetting(3).asSlider().getValue())); + } + + // Straight-at-target by default; FromAbove/Auto first aim for a point above the target and + // only switch to a direct approach once close to that point (or, for Auto, if the above + // position/path turns out to be blocked). + private Vec3d lungeDirectionVec() { + Vec3d playerPos = mc.player.getEntityPos(); + Vec3d targetCenter = target.getBoundingBox().getCenter(); + int mode = getSetting(5).asMode().getMode(); + + if (mode == 0) { + return targetCenter.subtract(playerPos).normalize(); + } + + if (!aboveFirstPhase || abovePos == null) { + abovePos = new Vec3d(targetCenter.x, targetCenter.y + getSetting(6).asSlider().getValue(), targetCenter.z); + aboveFirstPhase = true; + } + + if (mode == 2 && getSetting(8).asToggle().getState() && !isAbovePathClear(abovePos, targetCenter)) { + aboveFirstPhase = false; + return targetCenter.subtract(playerPos).normalize(); + } + + if (playerPos.distanceTo(abovePos) < getSetting(7).asSlider().getValue()) { + aboveFirstPhase = false; + return targetCenter.subtract(playerPos).normalize(); + } + + return abovePos.subtract(playerPos).normalize(); + } + + private boolean isAbovePathClear(Vec3d above, Vec3d targetCenter) { + if (WorldUtils.isTeleportUnsafe(mc.player, above)) { + return false; + } + + int steps = Math.max(10, (int) (above.distanceTo(targetCenter) * 2.5)); + for (int i = 1; i < steps; i++) { + if (WorldUtils.isTeleportUnsafe(mc.player, above.lerp(targetCenter, i / (double) steps))) { + return false; + } + } + + return true; + } + + private void blink() { + holdingPackets = true; + + if (blinkStart == null) { + blinkStart = mc.player.getEntityPos(); + } + + if (getSetting(10).asToggle().getState() && ++blinkLungeTicks >= getSetting(11).asSlider().getValueInt()) { + mc.player.setSprinting(true); + mc.player.setVelocity(target.getBoundingBox().getCenter().subtract(mc.player.getEntityPos()).normalize().multiply(getSetting(3).asSlider().getValue())); + } + + if (mc.player.getEntityPos().distanceTo(target.getEntityPos()) <= getSetting(9).asSlider().getValue()) { + flush(); + blinkStart = mc.player.getEntityPos(); + blinkLungeTicks = 0; + } + } + + // Unlike the other three ported modules, Blink's flush doesn't need a spam-packet burst first - + // the original just sends the withheld start/end positions directly as one jump. + private void flush() { + if (!holdingPackets || blinkStart == null) { + return; + } + + WorldUtils.sendTeleport(blinkStart); + WorldUtils.sendTeleport(mc.player.getEntityPos()); + holdingPackets = false; + } + + @BleachSubscribe + public void onSendPacket(EventPacket.Send event) { + if (charging && holdingPackets && getSetting(0).asMode().getMode() == 1 && event.getPacket() instanceof PlayerMoveC2SPacket) { + event.setCancelled(true); + } + } + + private void rotateToTarget() { + Vec3d toTarget = target.getBoundingBox().getCenter().subtract(mc.player.getEyePos()).normalize(); + float yaw = (float) (Math.toDegrees(Math.atan2(toTarget.z, toTarget.x)) - 90); + float pitch = (float) -Math.toDegrees(Math.asin(toTarget.y)); + mc.player.setYaw(yaw); + mc.player.setPitch(pitch); + } + + private Entity findTarget() { + double maxRange = getSetting(1).asSlider().getValue(); + Vec3d eyePos = mc.player.getEyePos(); + Vec3d look = mc.player.getRotationVec(1f); + + EntityHitResult hit = ProjectileUtil.raycast(mc.player, eyePos, eyePos.add(look.multiply(maxRange)), + mc.player.getBoundingBox().stretch(look.multiply(maxRange)).expand(1), + this::isValidTarget, maxRange * maxRange); + + return hit != null ? hit.getEntity() : null; + } + + private boolean isValidTarget(Entity e) { + if (!(e instanceof LivingEntity) || !e.isAlive() || e == mc.player) { + return false; + } + + if (getSetting(2).asToggle().getState() && e instanceof PlayerEntity && BleachHack.friendMang.has(e)) { + return false; + } + + return !getSetting(12).asToggle().getState() || mc.player.canSee(e); + } + +} diff --git a/src/main/java/org/bleachhack/module/mods/Speed.java b/src/main/java/org/bleachhack/module/mods/Speed.java index 401bb123a8..65210455dc 100644 --- a/src/main/java/org/bleachhack/module/mods/Speed.java +++ b/src/main/java/org/bleachhack/module/mods/Speed.java @@ -25,12 +25,23 @@ public class Speed extends Module { private boolean jumping; public Speed() { + this(new SettingMode("Mode", "StrafeHop", "Strafe", "OnGround", "MiniHop", "Bhop").withDesc("Speed mode.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicates below capture that local variable instead. + private Speed(SettingMode mode) { super("Speed", KEY_UNBOUND, ModuleCategory.MOVEMENT, "Allows you to go faster, what did you expect?", - new SettingMode("Mode", "StrafeHop", "Strafe", "OnGround", "MiniHop", "Bhop").withDesc("Speed mode."), - new SettingSlider("Strafe", 0.15, 0.55, 0.27, 2).withDesc("Strafe speed."), - new SettingSlider("OnGround", 0.1, 10, 2, 1).withDesc("OnGround speed."), - new SettingSlider("MiniHop", 0.1, 10, 2, 1).withDesc("MiniHop speed."), - new SettingSlider("Bhop", 0.1, 10, 2, 1).withDesc("Bhop speed."), + mode, + new SettingSlider("Strafe", 0.15, 0.55, 0.27, 2).withDesc("Strafe speed.") + .visibleWhen(() -> mode.getMode() <= 1), + new SettingSlider("OnGround", 0.1, 10, 2, 1).withDesc("OnGround speed.") + .visibleWhen(() -> mode.getMode() == 2), + new SettingSlider("MiniHop", 0.1, 10, 2, 1).withDesc("MiniHop speed.") + .visibleWhen(() -> mode.getMode() == 3), + new SettingSlider("Bhop", 0.1, 10, 2, 1).withDesc("Bhop speed.") + .visibleWhen(() -> mode.getMode() == 4), new SettingToggle("NoInertia", false).withDesc("Prevents you from moving forcefully.")); } @@ -66,9 +77,9 @@ public void onTick(EventTick event) { double speeds = 0.85 + getSetting(2).asSlider().getValue() / 30; - if (jumping && mc.player.getY() >= mc.player.prevY + 0.399994D) { + if (jumping && mc.player.getY() >= mc.player.lastY + 0.399994D) { mc.player.setVelocity(mc.player.getVelocity().x, -0.9, mc.player.getVelocity().z); - mc.player.setPos(mc.player.getX(), mc.player.prevY, mc.player.getZ()); + mc.player.setPos(mc.player.getX(), mc.player.lastY, mc.player.getZ()); jumping = false; } @@ -80,7 +91,7 @@ public void onTick(EventTick event) { // 1.0379 } - if (jumping && mc.player.getY() >= mc.player.prevY + 0.399994D) { + if (jumping && mc.player.getY() >= mc.player.lastY + 0.399994D) { mc.player.setVelocity(mc.player.getVelocity().x, -100, mc.player.getVelocity().z); jumping = false; } @@ -98,7 +109,7 @@ public void onTick(EventTick event) { mc.player.jump(); } else if (mc.player.getVelocity().y > 0) { mc.player.setVelocity(mc.player.getVelocity().x * speeds, -1, mc.player.getVelocity().z * speeds); - mc.player.input.movementSideways += 1.5F; + mc.player.sidewaysSpeed += 1.5F; } /* Bhop */ diff --git a/src/main/java/org/bleachhack/module/mods/SpeedMine.java b/src/main/java/org/bleachhack/module/mods/SpeedMine.java index 9f88d77eeb..f95b15e948 100644 --- a/src/main/java/org/bleachhack/module/mods/SpeedMine.java +++ b/src/main/java/org/bleachhack/module/mods/SpeedMine.java @@ -23,11 +23,20 @@ public class SpeedMine extends Module { public SpeedMine() { + this(new SettingMode("Mode", "Haste", "OG").withDesc("SpeedMine Mode.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicates below capture that local variable instead. + private SpeedMine(SettingMode mode) { super("SpeedMine", KEY_UNBOUND, ModuleCategory.EXPLOITS, "Allows you to break blocks faster.", - new SettingMode("Mode", "Haste", "OG").withDesc("SpeedMine Mode."), - new SettingSlider("HasteLvl", 1, 3, 1, 0).withDesc("Haste Level."), + mode, + new SettingSlider("HasteLvl", 1, 3, 1, 0).withDesc("Haste Level.") + .visibleWhen(() -> mode.getMode() == 0), new SettingSlider("Cooldown", 0, 4, 1, 0).withDesc("Cooldown between mining blocks (in ticks)."), - new SettingSlider("Multiplier", 1, 3, 1.3, 1).withDesc("OG Mode multiplier."), + new SettingSlider("Multiplier", 1, 3, 1.3, 1).withDesc("OG Mode multiplier.") + .visibleWhen(() -> mode.getMode() == 1), new SettingToggle("AntiFatigue", true).withDesc("Removes the fatigue effect."), new SettingToggle("AntiOffGround", true).withDesc("Removing mining slowness from being offground.")); } diff --git a/src/main/java/org/bleachhack/module/mods/Sprint.java b/src/main/java/org/bleachhack/module/mods/Sprint.java index bd86182c08..e84950b014 100644 --- a/src/main/java/org/bleachhack/module/mods/Sprint.java +++ b/src/main/java/org/bleachhack/module/mods/Sprint.java @@ -27,8 +27,8 @@ public void onTick(EventTick event) { return; mc.player.setSprinting( - mc.player.input.movementForward > 0 && - (mc.player.input.movementSideways != 0 ||mc.player.input.movementForward > 0) && + mc.player.input.playerInput.forward() && + (mc.player.input.playerInput.left() || mc.player.input.playerInput.right() || mc.player.input.playerInput.forward()) && !mc.player.isSneaking()); } } diff --git a/src/main/java/org/bleachhack/module/mods/Step.java b/src/main/java/org/bleachhack/module/mods/Step.java index 3002c707e9..8d919132fd 100644 --- a/src/main/java/org/bleachhack/module/mods/Step.java +++ b/src/main/java/org/bleachhack/module/mods/Step.java @@ -19,6 +19,7 @@ import org.bleachhack.setting.module.SettingSlider; import org.bleachhack.setting.module.SettingToggle; +import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; import net.minecraft.util.math.Box; @@ -29,9 +30,17 @@ public class Step extends Module { private Deque queue = new ArrayDeque<>(); public Step() { + this(new SettingMode("Mode", "Packet", "Vanilla", "Spider", "Jump").withDesc("Step mode.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Mode setting as + // a constructor parameter first lets the predicate below capture that local variable instead. + private Step(SettingMode mode) { super("Step", KEY_UNBOUND, ModuleCategory.MOVEMENT, "Allows you to Run up blocks like stairs.", - new SettingMode("Mode", "Packet", "Vanilla", "Spider", "Jump").withDesc("Step mode."), - new SettingSlider("Height", 0.1, 20, 2, 1).withDesc("How high to be able to step (Vanilla only)."), + mode, + new SettingSlider("Height", 0.1, 20, 2, 1).withDesc("How high to be able to step (Vanilla only).") + .visibleWhen(() -> mode.getMode() == 1), new SettingToggle("Cooldown", false).withDesc("Adds a cooldown between stepping to prevent rubberbanding.").withChildren( new SettingSlider("Amount", 0.01, 1, 0.1, 2).withDesc("How long the cooldown is (in seconds)."))); } @@ -39,14 +48,15 @@ public Step() { @Override public void onDisable(boolean inWorld) { if (inWorld) - mc.player.setStepHeight(0.5F); + mc.player.getAttributeInstance(EntityAttributes.STEP_HEIGHT).setBaseValue(0.5); super.onDisable(inWorld); } @BleachSubscribe public void onTick(EventTick event) { - mc.player.setStepHeight(getSetting(0).asMode().getMode() == 1 ? getSetting(1).asSlider().getValueFloat() : 0.5f); + mc.player.getAttributeInstance(EntityAttributes.STEP_HEIGHT).setBaseValue( + getSetting(0).asMode().getMode() == 1 ? getSetting(1).asSlider().getValue() : 0.5); if (!mc.player.horizontalCollision) { queue.clear(); @@ -58,9 +68,9 @@ public void onTick(EventTick event) { } } - if (!mc.world.getBlockState(mc.player.getBlockPos().add(0, (int) (mc.player.getHeight() + 1), 0)).getMaterial().isReplaceable() - || mc.player.input.jumping - || !(mc.player.input.pressingForward || mc.player.input.pressingBack || mc.player.input.pressingLeft || mc.player.input.pressingRight)) { + if (!mc.world.getBlockState(mc.player.getBlockPos().add(0, (int) (mc.player.getHeight() + 1), 0)).isReplaceable() + || mc.player.input.playerInput.jump() + || !(mc.player.input.playerInput.forward() || mc.player.input.playerInput.backward() || mc.player.input.playerInput.left() || mc.player.input.playerInput.right())) { return; } @@ -71,20 +81,20 @@ public void onTick(EventTick event) { if (getSetting(0).asMode().getMode() == 0 && mc.player.horizontalCollision && mc.player.isOnGround()) { if (!isTouchingWall(mc.player.getBoundingBox().offset(0, 1, 0)) || !isTouchingWall(mc.player.getBoundingBox().offset(0, 1.5, 0))) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 0.42, mc.player.getZ(), false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 0.75, mc.player.getZ(), false)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 0.42, mc.player.getZ(), false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 0.75, mc.player.getZ(), false, mc.player.horizontalCollision)); if (isTouchingWall(mc.player.getBoundingBox().offset(0, 1, 0)) && !isTouchingWall(mc.player.getBoundingBox().offset(0, 1.5, 0))) { - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1, mc.player.getZ(), false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1.15, mc.player.getZ(), false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1.24, mc.player.getZ(), false)); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1.15, mc.player.getZ(), true)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1, mc.player.getZ(), false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1.15, mc.player.getZ(), false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1.24, mc.player.getZ(), false, mc.player.horizontalCollision)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY() + 1.15, mc.player.getZ(), true, mc.player.horizontalCollision)); mc.player.updatePosition(mc.player.getX(), mc.player.getY() + 1.0, mc.player.getZ()); } else { mc.player.updatePosition(mc.player.getX(), mc.player.getY() + 1, mc.player.getZ()); } - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(true)); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(true, mc.player.horizontalCollision)); lastStep = mc.player.age; } } else if (getSetting(0).asMode().getMode() == 2) { diff --git a/src/main/java/org/bleachhack/module/mods/StorageESP.java b/src/main/java/org/bleachhack/module/mods/StorageESP.java index 74dde0ea3a..0e7c401f8d 100644 --- a/src/main/java/org/bleachhack/module/mods/StorageESP.java +++ b/src/main/java/org/bleachhack/module/mods/StorageESP.java @@ -8,30 +8,20 @@ */ package org.bleachhack.module.mods; -import com.google.gson.JsonSyntaxException; -import net.minecraft.block.BlockState; import net.minecraft.block.ChestBlock; import net.minecraft.block.entity.*; import net.minecraft.block.enums.ChestType; -import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.client.render.OverlayTexture; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ItemFrameEntity; import net.minecraft.entity.vehicle.ChestMinecartEntity; import net.minecraft.entity.vehicle.FurnaceMinecartEntity; import net.minecraft.entity.vehicle.HopperMinecartEntity; import net.minecraft.item.Items; -import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction.Axis; -import net.minecraft.util.math.random.Random; -import org.bleachhack.event.events.EventEntityRender; import org.bleachhack.event.events.EventWorldRender; import org.bleachhack.eventbus.BleachSubscribe; import org.bleachhack.module.Module; @@ -39,31 +29,33 @@ import org.bleachhack.setting.module.SettingMode; import org.bleachhack.setting.module.SettingSlider; import org.bleachhack.setting.module.SettingToggle; -import org.bleachhack.util.BleachLogger; import org.bleachhack.util.Boxes; import org.bleachhack.util.render.Renderer; import org.bleachhack.util.render.color.QuadColor; -import org.bleachhack.util.shader.BleachCoreShaders; -import org.bleachhack.util.shader.ColorVertexConsumerProvider; -import org.bleachhack.util.shader.ShaderEffectWrapper; -import org.bleachhack.util.shader.ShaderLoader; import org.bleachhack.util.world.WorldUtils; -import java.io.IOException; import java.util.HashSet; import java.util.Set; public class StorageESP extends Module { - private ShaderEffectWrapper shader; - private ColorVertexConsumerProvider colorVertexer; - public StorageESP() { + this(new SettingMode("Render", "Shader", "Box").withDesc("The Render mode.")); + } + + // A visibleWhen(...) predicate can't call an instance method like getSetting(0) - "this" isn't + // allowed yet in a super(...) argument list, even inside a lambda. Building the Render mode + // setting as a constructor parameter first lets the predicates below capture that local + // variable instead. + private StorageESP(SettingMode renderMode) { super("StorageESP", KEY_UNBOUND, ModuleCategory.RENDER, "Highlights storage containers in the world.", - new SettingMode("Render", "Shader", "Box").withDesc("The Render mode."), - new SettingSlider("ShaderFill", 1, 255, 50, 0).withDesc("How opaque the fill on shader mode should be."), - new SettingSlider("Box", 0, 5, 2, 1).withDesc("How thick the box outline should be."), - new SettingSlider("BoxFill", 0, 255, 50, 0).withDesc("How opaque the fill on box mode should be."), + renderMode, + new SettingSlider("ShaderFill", 1, 255, 50, 0).withDesc("How opaque the fill on shader mode should be.") + .visibleWhen(() -> renderMode.getMode() == 0), + new SettingSlider("Box", 0, 5, 2, 1).withDesc("How thick the box outline should be.") + .visibleWhen(() -> renderMode.getMode() == 1), + new SettingSlider("BoxFill", 0, 255, 50, 0).withDesc("How opaque the fill on box mode should be.") + .visibleWhen(() -> renderMode.getMode() == 1), new SettingToggle("Chests", true).withDesc("Highlights chests/barrels."), new SettingToggle("Enderchests", true).withDesc("Highlights enderchests."), @@ -76,113 +68,61 @@ public StorageESP() { new SettingToggle("FurnaceCarts", true).withDesc("Highlights furnaces in minecarts."), new SettingToggle("HopperCarts", true).withDesc("Highlights hoppers in minecarts."), new SettingToggle("Itemframes", true).withDesc("Highlights item frames.")); - - try { - shader = new ShaderEffectWrapper( - ShaderLoader.loadEffect(mc.getFramebuffer(), new Identifier("bleachhack", "shaders/post/entity_outline.json"))); - - colorVertexer = new ColorVertexConsumerProvider(shader.getFramebuffer("main"), BleachCoreShaders::getColorOverlayShader); - } catch (JsonSyntaxException | IOException e) { - throw new RuntimeException("Failed to initialize StorageESP Shader! loaded too early?", e); - } - } - - @BleachSubscribe - public void onWorldRender(EventWorldRender.Pre event) { - shader.prepare(); - shader.clearFramebuffer("main"); - } - - @BleachSubscribe - public void onEntityRender(EventEntityRender.Single.Pre event) { - if (getSetting(0).asMode().getMode() != 0) - return; - - int[] color = getColorForEntity(event.getEntity()); - - if (color != null) { - event.setVertex(colorVertexer.createDualProvider(event.getVertex(), color[0], color[1], color[2], getSetting(1).asSlider().getValueInt())); - } } @BleachSubscribe public void onWorldRender(EventWorldRender.Post event) { - if (getSetting(0).asMode().getMode() == 0) { - // Manually render blockentities because of culling - for (BlockEntity be: WorldUtils.getBlockEntities()) { - int[] color = getColorForBlock(be); - - if (color != null) { - BlockEntityRenderer renderer = mc.getBlockEntityRenderDispatcher().get(be); - MatrixStack matrices = Renderer.matrixFrom(be.getPos().getX(), be.getPos().getY(), be.getPos().getZ()); - try { - if (renderer != null) { - renderer.render(be, mc.getTickDelta(), matrices, - colorVertexer.createSingleProvider(mc.getBufferBuilders().getEntityVertexConsumers(), color[0], color[1], color[2], getSetting(1).asSlider().getValueInt()), - LightmapTextureManager.MAX_LIGHT_COORDINATE, OverlayTexture.DEFAULT_UV); - } else { - BlockState state = be.getCachedState(); - mc.getBlockRenderManager().getModelRenderer().renderFlat(mc.world, - mc.getBlockRenderManager().getModel(state), state, be.getPos(), matrices, - colorVertexer.createSingleProvider(mc.getBufferBuilders().getEntityVertexConsumers(), color[0], color[1], color[2], getSetting(1).asSlider().getValueInt()).getBuffer(RenderLayers.getMovingBlockLayer(state)), - false, Random.create(0L), 0L, OverlayTexture.DEFAULT_UV); - } - } catch (Exception e) { - BleachLogger.error("Disabling StorageESP, another mod conflicting with shader mode?"); - e.printStackTrace(); - setEnabled(false); - return; - } - } + // 1.21.11: block/entity renderers no longer take a VertexConsumerProvider we can wrap to draw + // a silhouette-shaped highlight (see task #3 notes) - "Shader" mode now draws a through-walls + // flat-colored bounding box instead, same shape as 1.19.4's "Box" mode but ignoring depth test. + boolean throughWalls = getSetting(0).asMode().getMode() == 0; + float width = throughWalls ? 0 : getSetting(2).asSlider().getValueFloat(); + int fill = throughWalls ? getSetting(1).asSlider().getValueInt() : getSetting(3).asSlider().getValueInt(); + + for (Entity e: mc.world.getEntities()) { + int[] color = getColorForEntity(e); + Box box = e.getBoundingBox(); + + if (e instanceof ItemFrameEntity && ((ItemFrameEntity) e).getHeldItemStack().getItem() == Items.FILLED_MAP) { + Axis axis = e.getHorizontalFacing().getAxis(); + box = box.expand(axis == Axis.X ? 0 : 0.125, axis == Axis.Y ? 0 : 0.125, axis == Axis.Z ? 0 : 0.125); } - colorVertexer.draw(); - shader.render(); - shader.drawFramebufferToMain("main"); - } else { - float width = getSetting(2).asSlider().getValueFloat(); - int fill = getSetting(3).asSlider().getValueInt(); - - for (Entity e: mc.world.getEntities()) { - int[] color = getColorForEntity(e); - Box box = e.getBoundingBox(); + if (color != null) { + drawHighlight(box, color, throughWalls, width, fill); + } + } - if (e instanceof ItemFrameEntity && ((ItemFrameEntity) e).getHeldItemStack().getItem() == Items.FILLED_MAP) { - Axis axis = e.getHorizontalFacing().getAxis(); - box = box.expand(axis == Axis.X ? 0 : 0.125, axis == Axis.Y ? 0 : 0.125, axis == Axis.Z ? 0 : 0.125); - } + Set skip = new HashSet<>(); + for (BlockEntity be: WorldUtils.getBlockEntities()) { + if (skip.contains(be.getPos())) + continue; - if (color != null) { - if (width != 0) - Renderer.drawBoxOutline(box, QuadColor.single(color[0], color[1], color[2], 255), width); + int[] color = getColorForBlock(be); + Box box = be.getCachedState().getOutlineShape(mc.world, be.getPos()).getBoundingBox().offset(be.getPos()); - if (fill != 0) - Renderer.drawBoxFill(box, QuadColor.single(color[0], color[1], color[2], fill)); - } + Direction dir = getChestDirection(be); + if (dir != null) { + box = Boxes.stretch(box, dir, 0.94); + skip.add(be.getPos().offset(dir)); } - Set skip = new HashSet<>(); - for (BlockEntity be: WorldUtils.getBlockEntities()) { - if (skip.contains(be.getPos())) - continue; - - int[] color = getColorForBlock(be); - Box box = be.getCachedState().getOutlineShape(mc.world, be.getPos()).getBoundingBox().offset(be.getPos()); - - Direction dir = getChestDirection(be); - if (dir != null) { - box = Boxes.stretch(box, dir, 0.94); - skip.add(be.getPos().offset(dir)); - } + if (color != null) { + drawHighlight(box, color, throughWalls, width, fill); + } + } + } - if (color != null) { - if (width != 0) - Renderer.drawBoxOutline(box, QuadColor.single(color[0], color[1], color[2], 255), width); + private void drawHighlight(Box box, int[] color, boolean throughWalls, float width, int fill) { + if (throughWalls) { + if (fill != 0) + Renderer.drawBoxFillThroughWalls(box, QuadColor.single(color[0], color[1], color[2], fill)); + } else { + if (width != 0) + Renderer.drawBoxOutline(box, QuadColor.single(color[0], color[1], color[2], 255), width); - if (fill != 0) - Renderer.drawBoxFill(box, QuadColor.single(color[0], color[1], color[2], fill)); - } - } + if (fill != 0) + Renderer.drawBoxFill(box, QuadColor.single(color[0], color[1], color[2], fill)); } } diff --git a/src/main/java/org/bleachhack/module/mods/Surround.java b/src/main/java/org/bleachhack/module/mods/Surround.java index e4a62128bd..cfc0ca19c9 100644 --- a/src/main/java/org/bleachhack/module/mods/Surround.java +++ b/src/main/java/org/bleachhack/module/mods/Surround.java @@ -60,7 +60,7 @@ public void onEnable(boolean inWorld) { if (getSetting(3).asToggle().getState()) { Vec3d centerPos = Vec3d.ofBottomCenter(mc.player.getBlockPos()); mc.player.updatePosition(centerPos.x, centerPos.y, centerPos.z); - mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(centerPos.x, centerPos.y, centerPos.z, mc.player.isOnGround())); + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(centerPos.x, centerPos.y, centerPos.z, mc.player.isOnGround(), mc.player.horizontalCollision)); } place(); @@ -99,7 +99,7 @@ private void place() { BlockPos.ofFloored(box.maxX + 1, box.minY, box.minZ), BlockPos.ofFloored(box.maxX, box.minY, box.minZ - 1), BlockPos.ofFloored(box.minX - 1, box.minY, box.maxZ), BlockPos.ofFloored(box.minX, box.minY, box.maxZ + 1), BlockPos.ofFloored(box.maxX + 1, box.minY, box.maxZ), BlockPos.ofFloored(box.maxX, box.minY, box.maxZ + 1)); - placePoses.removeIf(pos -> !mc.world.getBlockState(pos).getMaterial().isReplaceable()); + placePoses.removeIf(pos -> !mc.world.getBlockState(pos).isReplaceable()); if (placePoses.isEmpty()) { return; diff --git a/src/main/java/org/bleachhack/module/mods/Tracers.java b/src/main/java/org/bleachhack/module/mods/Tracers.java index 76857480b7..4c3be4f6e4 100644 --- a/src/main/java/org/bleachhack/module/mods/Tracers.java +++ b/src/main/java/org/bleachhack/module/mods/Tracers.java @@ -69,11 +69,11 @@ public void onRender(EventWorldRender.Post event) { int[] col = getColor(e); if (col != null) { - Vec3d vec = e.getPos().subtract(Renderer.getInterpolationOffset(e)); + Vec3d vec = e.getEntityPos().subtract(Renderer.getInterpolationOffset(e)); Vec3d vec2 = new Vec3d(0, 0, 75) .rotateX(-(float) Math.toRadians(mc.gameRenderer.getCamera().getPitch())) .rotateY(-(float) Math.toRadians(mc.gameRenderer.getCamera().getYaw())) - .add(mc.cameraEntity.getEyePos()); + .add(mc.getCameraEntity().getEyePos()); LineColor lineColor = LineColor.single(col[0], col[1], col[2], opacity); Renderer.drawLine(vec2.x, vec2.y, vec2.z, vec.x, vec.y, vec.z, lineColor, width); diff --git a/src/main/java/org/bleachhack/module/mods/Trail.java b/src/main/java/org/bleachhack/module/mods/Trail.java index dbdcd13ad6..8e5a16adaa 100644 --- a/src/main/java/org/bleachhack/module/mods/Trail.java +++ b/src/main/java/org/bleachhack/module/mods/Trail.java @@ -59,11 +59,11 @@ public void onTick(EventTick event) { } if (trails.isEmpty() || lastVec == null) { - lastVec = mc.player.getPos().add(0, 0.1, 0); - trails.put(mc.player.getPos(), lastVec); - } else if (mc.player.getPos().add(0, 0.1, 0).distanceTo(lastVec) > 0.15) { - trails.put(lastVec, mc.player.getPos().add(0, 0.1, 0)); - lastVec = mc.player.getPos().add(0, 0.1, 0); + lastVec = mc.player.getEntityPos().add(0, 0.1, 0); + trails.put(mc.player.getEntityPos(), lastVec); + } else if (mc.player.getEntityPos().add(0, 0.1, 0).distanceTo(lastVec) > 0.15) { + trails.put(lastVec, mc.player.getEntityPos().add(0, 0.1, 0)); + lastVec = mc.player.getEntityPos().add(0, 0.1, 0); } } diff --git a/src/main/java/org/bleachhack/module/mods/UI.java b/src/main/java/org/bleachhack/module/mods/UI.java index 0b2367991b..6940907a9b 100644 --- a/src/main/java/org/bleachhack/module/mods/UI.java +++ b/src/main/java/org/bleachhack/module/mods/UI.java @@ -8,12 +8,11 @@ */ package org.bleachhack.module.mods; -import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.network.PlayerListEntry; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket; @@ -22,7 +21,6 @@ import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import org.apache.commons.lang3.math.NumberUtils; import org.bleachhack.BleachHack; import org.bleachhack.event.events.EventPacket; import org.bleachhack.event.events.EventRenderInGameHud; @@ -106,49 +104,49 @@ public UI() { new UIWindow(new Position("l", 1, "b", 0), container, () -> getSetting(3).asToggle().getState(), () -> new int[] { mc.textRenderer.getWidth(coordsText) + 2, 10 }, - (ms, x, y) -> mc.textRenderer.drawWithShadow(ms, coordsText, x + 1, y + 1, 0xa0a0a0)) + (ms, x, y) -> ms.drawTextWithShadow(mc.textRenderer, coordsText, x + 1, y + 1, 0xa0a0a0)) ); container.windows.put("fps", new UIWindow(new Position("l", 1, "coords", 0), container, () -> getSetting(1).asToggle().getState(), () -> new int[] { mc.textRenderer.getWidth(fpsText) + 2, 10 }, - (ms, x, y) -> mc.textRenderer.drawWithShadow(ms, fpsText, x + 1, y + 1, 0xa0a0a0)) + (ms, x, y) -> ms.drawTextWithShadow(mc.textRenderer, fpsText, x + 1, y + 1, 0xa0a0a0)) ); container.windows.put("ping", new UIWindow(new Position("l", 1, "fps", 0), container, () -> getSetting(2).asToggle().getState(), () -> new int[] { mc.textRenderer.getWidth(pingText) + 2, 10 }, - (ms, x, y) -> mc.textRenderer.drawWithShadow(ms, pingText, x + 1, y + 1, 0xa0a0a0)) + (ms, x, y) -> ms.drawTextWithShadow(mc.textRenderer, pingText, x + 1, y + 1, 0xa0a0a0)) ); container.windows.put("tps", new UIWindow(new Position("l", 1, "ping", 0), container, () -> getSetting(4).asToggle().getState(), () -> new int[] { mc.textRenderer.getWidth(tpsText) + 2, 10 }, - (ms, x, y) -> mc.textRenderer.drawWithShadow(ms, tpsText, x + 1, y + 1, 0xa0a0a0)) + (ms, x, y) -> ms.drawTextWithShadow(mc.textRenderer, tpsText, x + 1, y + 1, 0xa0a0a0)) ); container.windows.put("durability", new UIWindow(new Position(0.2, 0.9), container, () -> getSetting(5).asToggle().getState(), () -> new int[] { mc.textRenderer.getWidth(durabilityText) + 2, 10 }, - (ms, x, y) -> mc.textRenderer.drawWithShadow(ms, durabilityText, x + 1, y + 1, 0xa0a0a0)) + (ms, x, y) -> ms.drawTextWithShadow(mc.textRenderer, durabilityText, x + 1, y + 1, 0xa0a0a0)) ); container.windows.put("server", new UIWindow(new Position(0.2, 0.85, "durability", 0), container, () -> getSetting(6).asToggle().getState(), () -> new int[] { mc.textRenderer.getWidth(serverText) + 2, 10 }, - (ms, x, y) -> mc.textRenderer.drawWithShadow(ms, serverText, x + 1, y + 1, 0xa0a0a0)) + (ms, x, y) -> ms.drawTextWithShadow(mc.textRenderer, serverText, x + 1, y + 1, 0xa0a0a0)) ); container.windows.put("timestamp", new UIWindow(new Position(0.2, 0.8, "server", 0), container, () -> getSetting(7).asToggle().getState(), () -> new int[] { mc.textRenderer.getWidth(timestampText) + 2, 10 }, - (ms, x, y) -> mc.textRenderer.drawWithShadow(ms, timestampText, x + 1, y + 1, 0xa0a0a0)) + (ms, x, y) -> ms.drawTextWithShadow(mc.textRenderer, timestampText, x + 1, y + 1, 0xa0a0a0)) ); // Players @@ -211,7 +209,7 @@ public void onTick(EventTick event) { .append(colorText(Integer.toString(fps), Math.min(fps, 120) / 360f)); // Ping - PlayerListEntry playerEntry = mc.player.networkHandler.getPlayerListEntry(mc.player.getGameProfile().getId()); + PlayerListEntry playerEntry = mc.player.networkHandler.getPlayerListEntry(mc.player.getGameProfile().id()); int ping = playerEntry == null ? 0 : playerEntry.getLatency(); pingText = Text.literal("Ping: ") .append(colorText(Integer.toString(ping), (800 - MathHelper.clamp(ping, 0, 800)) / 2400f)); @@ -219,8 +217,8 @@ public void onTick(EventTick event) { // Coords boolean nether = mc.world.getRegistryKey().getValue().getPath().contains("nether"); BlockPos pos = mc.player.getBlockPos(); - BlockPos pos2 = nether ? BlockPos.ofFloored(mc.player.getPos().multiply(8, 1, 8)) - : BlockPos.ofFloored(mc.player.getPos().multiply(0.125, 1, 0.125)); + BlockPos pos2 = nether ? BlockPos.ofFloored(mc.player.getEntityPos().multiply(8, 1, 8)) + : BlockPos.ofFloored(mc.player.getEntityPos().multiply(0.125, 1, 0.125)); coordsText = Text.literal("XYZ: ") .append(Text.literal(pos.getX() + " " + pos.getY() + " " + pos.getZ()).styled(s -> s.withColor(nether ? 0xb02020 : 0x40f0f0))) @@ -239,8 +237,9 @@ public void onTick(EventTick event) { // Durability ItemStack mainhand = mc.player.getMainHandStack(); if (mainhand.isDamageable()) { - int durability = mainhand.getOrCreateNbt().contains("dmg") - ? NumberUtils.toInt(mainhand.getOrCreateNbt().get("dmg").asString()) : mainhand.getMaxDamage() - mainhand.getDamage(); + // 1.19.4 read the raw "dmg" NBT tag as a fallback; ItemStack has no raw NBT access at all + // anymore (data components replaced it), and getDamage() was already the normal path here. + int durability = mainhand.getMaxDamage() - mainhand.getDamage(); durabilityText = Text.literal("Durability: ") .append(colorText(Integer.toString(durability), (float) durability / mainhand.getMaxDamage() / 3f % 1f)); @@ -285,7 +284,7 @@ public int[] getModuleListSize() { return new int[] { mc.textRenderer.getWidth(moduleListText.get(0)) + inner + outer, moduleListText.size() * 10 }; } - public void drawModuleList(MatrixStack matrices, int x, int y) { + public void drawModuleList(DrawContext matrices, int x, int y) { if (moduleListText.isEmpty()) return; int arrayCount = 0; @@ -301,18 +300,18 @@ public void drawModuleList(MatrixStack matrices, int x, int y) { int outerX = rightAlign ? textStart - 3 : textStart + mc.textRenderer.getWidth(t) + 1; if (fill) { - DrawableHelper.fill(matrices, rightAlign ? textStart - 2 : startX, y + arrayCount * 10, rightAlign ? startX : outerX, y + 10 + arrayCount * 10, 0x70003030); + matrices.fill(rightAlign ? textStart - 2 : startX, y + arrayCount * 10, rightAlign ? startX : outerX, y + 10 + arrayCount * 10, 0x70003030); } if (inner) { - DrawableHelper.fill(matrices, rightAlign ? startX - 1 : startX, y + arrayCount * 10, rightAlign ? startX : startX + 1, y + 10 + arrayCount * 10, color); + matrices.fill(rightAlign ? startX - 1 : startX, y + arrayCount * 10, rightAlign ? startX : startX + 1, y + 10 + arrayCount * 10, color); } if (outer) { - DrawableHelper.fill(matrices, outerX, y + arrayCount * 10, outerX + 1, y + 10 + arrayCount * 10, color); + matrices.fill(outerX, y + arrayCount * 10, outerX + 1, y + 10 + arrayCount * 10, color); } - mc.textRenderer.drawWithShadow(matrices, t, textStart, y + 1 + arrayCount * 10, color); + matrices.drawTextWithShadow(mc.textRenderer, t, textStart, y + 1 + arrayCount * 10, color); arrayCount++; } } @@ -335,8 +334,8 @@ public int[] getPlayerSize() { return new int[] { nameLengths.get(0) + 2, nameLengths.size() * 10 + 1 }; } - public void drawPlayerList(MatrixStack matrices, int x, int y) { - mc.textRenderer.drawWithShadow(matrices, "Players:", x + 1, y + 1, 0xff0000); + public void drawPlayerList(DrawContext matrices, int x, int y) { + matrices.drawTextWithShadow(mc.textRenderer, "Players:", x + 1, y + 1, 0xff0000); int count = 1; for (Entity e : mc.world.getPlayers().stream() @@ -356,7 +355,7 @@ public void drawPlayerList(MatrixStack matrices, int x, int y) { ((255 - (int) Math.min(dist * 2.1, 255) & 0xFF) << 16) | (((int) Math.min(dist * 4.28, 255) & 0xFF) << 8); - mc.textRenderer.drawWithShadow(matrices, text, x + 1, y + 1 + count * 10, playerColor); + matrices.drawTextWithShadow(mc.textRenderer, text, x + 1, y + 1 + count * 10, playerColor); count++; } } @@ -367,17 +366,17 @@ public int[] getLagMeterSize() { return new int[] { 144, 10 }; } - public void drawLagMeter(MatrixStack matrices, int x, int y) { + public void drawLagMeter(DrawContext matrices, int x, int y) { long time = System.currentTimeMillis(); if (time - lastPacket > 500) { String text = "Server Lagging For: " + String.format(Locale.ENGLISH, "%.2f", (time - lastPacket) / 1000d) + "s"; int xd = x + 72 - mc.textRenderer.getWidth(text) / 2; switch (getSetting(10).asToggle().getChild(0).asMode().getMode()) { - case 0 -> mc.textRenderer.drawWithShadow(matrices, text, xd, y + 1 + Math.min((time - lastPacket - 1200) / 20, 0), 0xd0d0d0); - case 1 -> mc.textRenderer.drawWithShadow(matrices, text, xd, y + 1, + case 0 -> matrices.drawTextWithShadow(mc.textRenderer, text, xd, (int) (y + 1 + Math.min((time - lastPacket - 1200) / 20, 0)), 0xd0d0d0); + case 1 -> matrices.drawTextWithShadow(mc.textRenderer, text, xd, y + 1, (MathHelper.clamp((int) (time - lastPacket - 500) / 3, 5, 255) << 24) | 0xd0d0d0); - case 2 -> mc.textRenderer.drawWithShadow(matrices, text, xd, y + 1, 0xd0d0d0); + case 2 -> matrices.drawTextWithShadow(mc.textRenderer, text, xd, y + 1, 0xd0d0d0); } } } @@ -389,59 +388,60 @@ public int[] getArmorSize() { return new int[] { vertical ? 18 : 74, vertical ? 62 : 16 }; } - public void drawArmor(MatrixStack matrices, int x, int y) { + // 1.19.4 indexed PlayerInventory.armor (a plain 4-slot list); that field is gone, replaced by the + // EntityEquipment system, so armor is now read per-slot via getEquippedStack(EquipmentSlot). + private static final EquipmentSlot[] ARMOR_SLOTS = { EquipmentSlot.FEET, EquipmentSlot.LEGS, EquipmentSlot.CHEST, EquipmentSlot.HEAD }; + + public void drawArmor(DrawContext matrices, int x, int y) { boolean vertical = getSetting(9).asToggle().getChild(0).asToggle().getState(); - for (int count = 0; count < mc.player.getInventory().armor.size(); count++) { - ItemStack is = mc.player.getInventory().armor.get(count); + for (int count = 0; count < ARMOR_SLOTS.length; count++) { + ItemStack is = mc.player.getEquippedStack(ARMOR_SLOTS[count]); if (is.isEmpty()) continue; int curX = vertical ? x : x + count * 19; int curY = vertical ? y + 47 - count * 16 : y; - RenderSystem.enableDepthTest(); - mc.getItemRenderer().renderInGuiWithOverrides(matrices, is, curX, curY); + matrices.drawItem(is, curX, curY); int durcolor = is.isDamageable() ? 0xff000000 | MathHelper.hsvToRgb((float) (is.getMaxDamage() - is.getDamage()) / is.getMaxDamage() / 3.0F, 1.0F, 1.0F) : 0; - matrices.push(); - matrices.translate(0, 0, /*mc.getItemRenderer().zOffset +*/ 200); - + // 1.19.4 nudged these overlays forward on the Z axis so they draw above the item icon. + // DrawContext's 2D matrix stack has no Z axis; its GUI queue instead layers strictly by + // submission order, and these are already submitted after drawItem() above. if (is.getCount() > 1) { - matrices.push(); + matrices.getMatrices().pushMatrix(); String s = Integer.toString(is.getCount()); - matrices.translate(curX + 19 - mc.textRenderer.getWidth(s), curY + 9, 0); - matrices.scale(0.85f, 0.85f, 1f); + matrices.getMatrices().translate(curX + 19 - mc.textRenderer.getWidth(s), curY + 9); + matrices.getMatrices().scale(0.85f, 0.85f); - mc.textRenderer.drawWithShadow(matrices, s, 0, 0, 0xffffff); - matrices.pop(); + matrices.drawTextWithShadow(mc.textRenderer, s, 0, 0, 0xffffff); + matrices.getMatrices().popMatrix(); } if (is.isDamageable()) { int mode = getSetting(9).asToggle().getChild(1).asMode().getMode(); if (mode == 0) { - matrices.push(); - matrices.scale(0.75f, 0.75f, 1f); + matrices.getMatrices().pushMatrix(); + matrices.getMatrices().scale(0.75f, 0.75f); String dur = Integer.toString(is.getMaxDamage() - is.getDamage()); - mc.textRenderer.drawWithShadow( - matrices, dur, (curX + 7 - mc.textRenderer.getWidth(dur) * 1.333f / 4) * 1.333f, (curY - (vertical ? 2 : 3)) * 1.333f, durcolor); + matrices.drawTextWithShadow(mc.textRenderer, + dur, (int) ((curX + 7 - mc.textRenderer.getWidth(dur) * 1.333f / 4) * 1.333f), (int) ((curY - (vertical ? 2 : 3)) * 1.333f), durcolor); - matrices.pop(); + matrices.getMatrices().popMatrix(); } else if (mode == 1) { int barLength = Math.round(13.0F - is.getDamage() * 13.0F / is.getMaxDamage()); - DrawableHelper.fill(matrices, curX + 2, curY + 13, curX + 15, curY + 15, 0xff000000); - DrawableHelper.fill(matrices, curX + 2, curY + 13, curX + 2 + barLength, curY + 14, durcolor); + matrices.fill(curX + 2, curY + 13, curX + 15, curY + 15, 0xff000000); + matrices.fill(curX + 2, curY + 13, curX + 2 + barLength, curY + 14, durcolor); } else { int barLength = Math.round(12.0F - is.getDamage() * 12.0F / is.getMaxDamage()); - DrawableHelper.fill(matrices, curX + 15, curY + 2, curX + 17, curY + 14, 0xff000000); - DrawableHelper.fill(matrices, curX + 15, curY + 2, curX + 16, curY + 2 + barLength, durcolor); + matrices.fill(curX + 15, curY + 2, curX + 17, curY + 14, 0xff000000); + matrices.fill(curX + 15, curY + 2, curX + 16, curY + 2 + barLength, durcolor); } } - - matrices.pop(); } } @@ -451,23 +451,18 @@ public int[] getInventorySize() { return new int[] { 155, 53 }; } - public void drawInventory(MatrixStack matrices, int x, int y) { + public void drawInventory(DrawContext matrices, int x, int y) { if (getSetting(11).asToggle().getState()) { - DrawableHelper.fill(matrices, x + 155, y, x, y + 53, + matrices.fill(x + 155, y, x, y + 53, (getSetting(11).asToggle().getChild(0).asSlider().getValueInt() << 24) | 0x212120); - matrices.push(); for (int i = 0; i < 27; i++) { ItemStack itemStack = mc.player.getInventory().getStack(i + 9); int offsetX = x + 1 + (i % 9) * 17; int offsetY = y + 1 + (i / 9) * 17; - mc.getItemRenderer().renderInGuiWithOverrides(matrices, itemStack, offsetX, offsetY); - mc.getItemRenderer().renderGuiItemOverlay(matrices, mc.textRenderer, itemStack, offsetX, offsetY); + matrices.drawItem(itemStack, offsetX, offsetY); + matrices.drawStackOverlay(mc.textRenderer, itemStack, offsetX, offsetY); } - - //mc.getItemRenderer().zOffset = 0.0F; - RenderSystem.enableDepthTest(); - matrices.pop(); } } diff --git a/src/main/java/org/bleachhack/module/mods/Xray.java b/src/main/java/org/bleachhack/module/mods/Xray.java index f78ff4fd92..848b7f77e1 100644 --- a/src/main/java/org/bleachhack/module/mods/Xray.java +++ b/src/main/java/org/bleachhack/module/mods/Xray.java @@ -23,16 +23,17 @@ import net.minecraft.block.Block; import net.minecraft.block.Blocks; -import net.minecraft.block.FernBlock; +import net.minecraft.block.ShortPlantBlock; import net.minecraft.block.TallPlantBlock; -import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.BlockRenderLayer; +import net.minecraft.client.render.VertexConsumer; public class Xray extends Module { private double gamma; public Xray() { - super("Xray", KEY_UNBOUND, ModuleCategory.RENDER, "Baritone is for zoomers.", + super("Xray", KEY_UNBOUND, ModuleCategory.RENDER, "Makes chosen blocks (ores by default) visible through terrain.", new SettingToggle("Fluids", false).withDesc("Show fluids."), new SettingToggle("Opacity", true).withDesc("Toggles an adjustable alpha level for non-xray blocks.").withChildren( new SettingSlider("Value", 0, 255, 64, 0).withDesc("Block alpha value."), @@ -100,10 +101,19 @@ public void onRenderBlockOpaque(EventRenderBlock.Opaque event) { @BleachSubscribe public void onRenderBlockDrawSide(EventRenderBlock.ShouldDrawSide event) { - if (getSetting(2).asList(Block.class).contains(event.getState().getBlock())) { - event.setDrawSide(true); + boolean isTarget = getSetting(2).asList(Block.class).contains(event.getState().getBlock()); + boolean neighborIsTarget = getSetting(2).asList(Block.class).contains(event.getNeighborState().getBlock()); + + if (isTarget) { + // Always reveal target blocks (even fully enclosed in solid terrain), except the shared + // face between two touching target blocks of the same type - nothing to see there. + event.setDrawSide(!neighborIsTarget || event.getNeighborState().getBlock() != event.getState().getBlock()); } else if (!getSetting(1).asToggle().getState()) { event.setDrawSide(false); + } else if (neighborIsTarget) { + // Also draw a non-target block's face where it directly touches a target block, so the + // target isn't sitting in a fully culled (invisible) socket of translucent terrain. + event.setDrawSide(true); } } @@ -112,14 +122,14 @@ public void onRenderBlockTesselate(EventRenderBlock.Tesselate event) { if (!getSetting(2).asList(Block.class).contains(event.getState().getBlock())) { if (getSetting(1).asToggle().getState()) { if (getSetting(1).asToggle().getChild(1).asToggle().getState() - && (event.getState().getBlock() instanceof FernBlock + && (event.getState().getBlock() instanceof ShortPlantBlock || event.getState().getBlock() instanceof TallPlantBlock || WorldUtils.getTopBlockIgnoreLeaves(event.getPos().getX(), event.getPos().getZ()) == event.getPos().getY())) { event.setCancelled(true); return; } - event.getVertexConsumer().fixedColor(-1, -1, -1, getSetting(1).asToggle().getChild(0).asSlider().getValueInt()); + event.setVertexConsumer(new FixedAlphaVertexConsumer(event.getVertexConsumer(), getSetting(1).asToggle().getChild(0).asSlider().getValueInt())); } else { event.setCancelled(true); } @@ -129,7 +139,7 @@ public void onRenderBlockTesselate(EventRenderBlock.Tesselate event) { @BleachSubscribe public void onRenderBlockLayer(EventRenderBlock.Layer event) { if (getSetting(1).asToggle().getState() && !getSetting(2).asList(Block.class).contains(event.getState().getBlock())) { - event.setLayer(RenderLayer.getTranslucent()); + event.setLayer(BlockRenderLayer.TRANSLUCENT); } } @@ -139,4 +149,58 @@ public void onRenderFluid(EventRenderFluid event) { event.setCancelled(true); } } + + // 1.21.11 removed BufferBuilder's stateful fixedColor()/BufferVertexConsumer trick this module + // used to force block transparency - this wrapping decorator (swapped in via + // EventRenderBlock.Tesselate#setVertexConsumer) is the direct replacement: same effect, just an + // immutable wrapper instead of an in-place field flip. + private static class FixedAlphaVertexConsumer implements VertexConsumer { + private final VertexConsumer delegate; + private final int alpha; + + private FixedAlphaVertexConsumer(VertexConsumer delegate, int alpha) { + this.delegate = delegate; + this.alpha = alpha; + } + + @Override + public VertexConsumer vertex(float x, float y, float z) { + return delegate.vertex(x, y, z); + } + + @Override + public VertexConsumer color(int red, int green, int blue, int alpha) { + return delegate.color(red, green, blue, this.alpha); + } + + @Override + public VertexConsumer color(int argb) { + return delegate.color((argb & 0xFFFFFF) | (this.alpha << 24)); + } + + @Override + public VertexConsumer texture(float u, float v) { + return delegate.texture(u, v); + } + + @Override + public VertexConsumer overlay(int u, int v) { + return delegate.overlay(u, v); + } + + @Override + public VertexConsumer light(int u, int v) { + return delegate.light(u, v); + } + + @Override + public VertexConsumer normal(float x, float y, float z) { + return delegate.normal(x, y, z); + } + + @Override + public VertexConsumer lineWidth(float width) { + return delegate.lineWidth(width); + } + } } diff --git a/src/main/java/org/bleachhack/module/mods/Zoom.java b/src/main/java/org/bleachhack/module/mods/Zoom.java index e0e9ea9974..849d0a980f 100644 --- a/src/main/java/org/bleachhack/module/mods/Zoom.java +++ b/src/main/java/org/bleachhack/module/mods/Zoom.java @@ -15,28 +15,32 @@ public class Zoom extends Module { - public int prevFov; public double prevSens; public Zoom() { - super("Zoom", KEY_UNBOUND, ModuleCategory.RENDER, "ok zoomer.", + super("Zoom", KEY_UNBOUND, ModuleCategory.RENDER, "Zooms in your view.", new SettingSlider("Scale", 1, 10, 3, 2).withDesc("How much to zoom.")); } + public float getScale() { + return getSetting(0).asSlider().getValueFloat(); + } + @Override public void onEnable(boolean inWorld) { super.onEnable(inWorld); - prevFov = mc.options.getFov().getValue(); + // FOV itself is no longer touched here - writing straight into GameOptions.getFov() + // persisted the zoomed-in value into the options screen/options.txt (and any bug in + // restoring it on disable left the player stuck there), so this now matches Meteor's Zoom: + // MixinGameRenderer divides the *computed* per-frame FOV on the fly (see bleachhack_zoomFov) + // instead, leaving the real option untouched. prevSens = mc.options.getMouseSensitivity().getValue(); - - mc.options.getFov().setValue((int) (prevFov / getSetting(0).asSlider().getValue())); - mc.options.getMouseSensitivity().setValue(prevSens / getSetting(0).asSlider().getValue()); + mc.options.getMouseSensitivity().setValue(prevSens / Math.max(getScale() * 0.5, 1)); } @Override public void onDisable(boolean inWorld) { - mc.options.getFov().setValue(prevFov); mc.options.getMouseSensitivity().setValue(prevSens); super.onDisable(inWorld); diff --git a/src/main/java/org/bleachhack/setting/Setting.java b/src/main/java/org/bleachhack/setting/Setting.java index 099cc12f8c..e9a9c4a486 100644 --- a/src/main/java/org/bleachhack/setting/Setting.java +++ b/src/main/java/org/bleachhack/setting/Setting.java @@ -1,5 +1,6 @@ package org.bleachhack.setting; +import java.util.Objects; import java.util.function.UnaryOperator; import com.google.gson.JsonElement; @@ -55,7 +56,8 @@ public void resetValue() { } public boolean isDefault() { - return getValue().equals(defaultValue); + // SettingButton is a Setting with a null value, so this has to be null-safe. + return Objects.equals(getValue(), defaultValue); } public JsonElement write() { diff --git a/src/main/java/org/bleachhack/setting/SettingDataHandlers.java b/src/main/java/org/bleachhack/setting/SettingDataHandlers.java index 62cb2828fe..aaa0c01331 100644 --- a/src/main/java/org/bleachhack/setting/SettingDataHandlers.java +++ b/src/main/java/org/bleachhack/setting/SettingDataHandlers.java @@ -92,7 +92,7 @@ public JsonElement write(Block value) { } public Block read(JsonElement json) { - Block bl = Registries.BLOCK.get(new Identifier(json.getAsString())); + Block bl = Registries.BLOCK.get(Identifier.of(json.getAsString())); return bl != Blocks.AIR ? bl : null; } }; @@ -103,7 +103,7 @@ public JsonElement write(Item value) { } public Item read(JsonElement json) { - Item item = Registries.ITEM.get(new Identifier(json.getAsString())); + Item item = Registries.ITEM.get(Identifier.of(json.getAsString())); return item != Items.AIR ? item : null; } }; diff --git a/src/main/java/org/bleachhack/setting/module/ModuleSetting.java b/src/main/java/org/bleachhack/setting/module/ModuleSetting.java index a366939586..eec832a90a 100644 --- a/src/main/java/org/bleachhack/setting/module/ModuleSetting.java +++ b/src/main/java/org/bleachhack/setting/module/ModuleSetting.java @@ -8,6 +8,7 @@ */ package org.bleachhack.setting.module; +import java.util.function.Supplier; import java.util.function.UnaryOperator; import org.bleachhack.gui.clickgui.window.ClickGuiWindow.Tooltip; @@ -16,7 +17,7 @@ import org.bleachhack.gui.clickgui.window.ModuleWindow; import org.bleachhack.util.io.BleachFileHelper; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; public abstract class ModuleSetting extends Setting { @@ -96,14 +97,29 @@ public SettingKey asBind() { public Tooltip getTooltip(ModuleWindow window, int x, int y, int len) { return new Tooltip(x + len + 2, y, getTooltip()); } - + + // Lets a setting hide itself depending on another setting in the same module (e.g. a slider + // that's meaningless while a particular SettingMode option is selected), mirroring Meteor's + // per-setting .visible(...) predicate. Defaults to always-visible so existing settings don't + // need to opt in. ModuleWindow skips both layout height and rendering for hidden settings. + private Supplier visiblePredicate = () -> true; + + public boolean isVisible() { + return visiblePredicate.get(); + } + + public ModuleSetting visibleWhen(Supplier visiblePredicate) { + this.visiblePredicate = visiblePredicate; + return this; + } + @Override public void setValue(T value) { super.setValue(value); BleachFileHelper.SCHEDULE_SAVE_MODULES.set(true); } - public abstract void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len); + public abstract void render(ModuleWindow window, DrawContext matrices, int x, int y, int len); public abstract int getHeight(int len); } diff --git a/src/main/java/org/bleachhack/setting/module/SettingBlockList.java b/src/main/java/org/bleachhack/setting/module/SettingBlockList.java index 2af335072a..24e9c6c925 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingBlockList.java +++ b/src/main/java/org/bleachhack/setting/module/SettingBlockList.java @@ -15,11 +15,9 @@ import net.minecraft.registry.Registries; import org.bleachhack.setting.SettingDataHandlers; -import com.mojang.blaze3d.systems.RenderSystem; - import net.minecraft.block.Block; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; @@ -41,21 +39,20 @@ private static Collection getAllBlocks(Predicate filter) { } @Override - public void renderItem(MinecraftClient mc, MatrixStack matrices, Block item, int x, int y, int w, int h) { + public void renderItem(MinecraftClient mc, DrawContext matrices, Block item, int x, int y, int w, int h) { if (item == null || item.asItem() == Items.AIR) { super.renderItem(mc, matrices, item, x, y, w, h); } else { - RenderSystem.getModelViewStack().push(); + matrices.getMatrices().pushMatrix(); float scale = (h - 2) / 16f; float offset = 1f / scale; - RenderSystem.getModelViewStack().scale(scale, scale, 1f); + matrices.getMatrices().scale(scale, scale); - mc.getItemRenderer().renderInGuiWithOverrides(matrices, new ItemStack(item.asItem()), (int) ((x + 1) * offset), (int) ((y + 1) * offset)); + matrices.drawItem(new ItemStack(item.asItem()), (int) ((x + 1) * offset), (int) ((y + 1) * offset)); - RenderSystem.getModelViewStack().pop(); - RenderSystem.applyModelViewMatrix(); + matrices.getMatrices().popMatrix(); } } diff --git a/src/main/java/org/bleachhack/setting/module/SettingButton.java b/src/main/java/org/bleachhack/setting/module/SettingButton.java index f5eaa68933..6cfe9f9540 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingButton.java +++ b/src/main/java/org/bleachhack/setting/module/SettingButton.java @@ -12,9 +12,10 @@ import org.bleachhack.setting.SettingDataHandlers; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.input.MouseInput; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; public class SettingButton extends ModuleSetting { @@ -26,17 +27,17 @@ public SettingButton(String text, Runnable action) { this.action = action; } - public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len) { + public void render(ModuleWindow window, DrawContext matrices, int x, int y, int len) { if (window.mouseOver(x, y, x + len, y + 12)) { - DrawableHelper.fill(matrices, x + 1, y, x + len, y + 12, 0x70303070); + matrices.fill(x + 1, y, x + len, y + 12, 0x70303070); } - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, getName(), x + 3, y + 2, 0xcfe0cf); + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, getName(), x + 3, y + 2, 0xcfe0cf); if (window.mouseOver(x, y, x + len, y + 12) && window.lmDown) { window.mouseReleased(window.mouseX, window.mouseY, 1); - MinecraftClient.getInstance().currentScreen.mouseReleased(window.mouseX, window.mouseY, 0); - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + MinecraftClient.getInstance().currentScreen.mouseReleased(new Click(window.mouseX, window.mouseY, new MouseInput(0, 0))); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); action.run(); } } diff --git a/src/main/java/org/bleachhack/setting/module/SettingColor.java b/src/main/java/org/bleachhack/setting/module/SettingColor.java index f4592c8709..1cf2a48e2e 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingColor.java +++ b/src/main/java/org/bleachhack/setting/module/SettingColor.java @@ -11,16 +11,10 @@ import org.bleachhack.gui.clickgui.window.ModuleWindow; import org.bleachhack.gui.window.Window; import org.bleachhack.setting.SettingDataHandlers; -import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.util.math.ColorHelper; public class SettingColor extends ModuleSetting { @@ -28,7 +22,7 @@ public SettingColor(String text, int r, int g, int b) { super(text, rgbToHsv(r, g, b), float[]::clone, SettingDataHandlers.FLOAT_ARRAY); } - public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len) { + public void render(ModuleWindow window, DrawContext matrices, int x, int y, int len) { int sx = x + 3; int sy = y + 2; int ex = x + len - 18; @@ -36,31 +30,24 @@ public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int float[] hsv = getValue(); int[] rgb = hsvToRgb(hsv[0], 1f, 1f); + int hueColor = 0xff000000 | pack(rgb); Window.fill(matrices, sx - 1, sy - 1, ex + 1, ey + 1, 0xff8070b0, 0xff6060b0, 0x00000000); - DrawableHelper.fill(matrices, sx, sy, ex, ey, -1); - - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - - // Color square - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); - bufferBuilder.vertex(ex, sy, 0).color(rgb[0], rgb[1], rgb[2], 255).next(); - bufferBuilder.vertex(sx, sy, 0).color(255, 255, 255, 255).next(); - bufferBuilder.vertex(sx, ey, 0).color(255, 255, 255, 255).next(); - bufferBuilder.vertex(ex, ey, 0).color(rgb[0], rgb[1], rgb[2], 255).next(); - - bufferBuilder.vertex(ex, sy, 0).color(0, 0, 0, 0).next(); - bufferBuilder.vertex(sx, sy, 0).color(0, 0, 0, 0).next(); - bufferBuilder.vertex(sx, ey, 0).color(0, 0, 0, 255).next(); - bufferBuilder.vertex(ex, ey, 0).color(0, 0, 0, 255).next(); - tessellator.draw(); - - RenderSystem.disableBlend(); + matrices.fill(sx, sy, ex, ey, -1); + + // Color square: a per-pixel fill replaces the old two-overlapping-Tessellator-quads trick. + // DrawContext.fill() queues into the same deferred GUI render batch as everything else in this + // screen - drawing straight to the framebuffer via Tessellator here (like 1.19.4 did) would + // composite at the wrong time relative to that batch (it'd end up hidden behind it). + for (int px = sx; px < ex; px++) { + float tx = (float) (px - sx) / (ex - sx); + int rowColor = ColorHelper.lerp(tx, 0xffffffff, hueColor); + for (int py = sy; py < ey; py++) { + float ty = (float) (py - sy) / (ey - sy); + matrices.fill(px, py, px + 1, py + 1, ColorHelper.lerp(ty, rowColor, 0xff000000)); + } + } // Color square input handler if (window.mouseOver(sx, sy, ex, ey) && window.lmHeld) { @@ -73,15 +60,15 @@ public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int int cursorX = (int) (sx + (ex - sx) * hsv[1]); int cursorY = (int) (ey - (ey - sy) * hsv[2]); - DrawableHelper.fill(matrices, cursorX - 2, cursorY, cursorX, cursorY + 1, 0xffd0d0d0); - DrawableHelper.fill(matrices, cursorX + 1, cursorY, cursorX + 3, cursorY + 1, 0xffd0d0d0); - DrawableHelper.fill(matrices, cursorX, cursorY - 2, cursorX + 1, cursorY, 0xffd0d0d0); - DrawableHelper.fill(matrices, cursorX, cursorY + 1, cursorX + 1, cursorY + 3, 0xffd0d0d0); + matrices.fill(cursorX - 2, cursorY, cursorX, cursorY + 1, 0xffd0d0d0); + matrices.fill(cursorX + 1, cursorY, cursorX + 3, cursorY + 1, 0xffd0d0d0); + matrices.fill(cursorX, cursorY - 2, cursorX + 1, cursorY, 0xffd0d0d0); + matrices.fill(cursorX, cursorY + 1, cursorX + 1, cursorY + 3, 0xffd0d0d0); - matrices.push(); - matrices.scale(0.75f, 0.75f, 1f); - MinecraftClient.getInstance().textRenderer.draw(matrices, getName(), (int) ((sx + 1) / 0.75), (int) ((sy + 1) / 0.75), 0x000000); - matrices.pop(); + matrices.getMatrices().pushMatrix(); + matrices.getMatrices().scale(0.75f, 0.75f); + matrices.drawText(MinecraftClient.getInstance().textRenderer, getName(), (int) ((sx + 1) / 0.75), (int) ((sy + 1) / 0.75), 0x000000, false); + matrices.getMatrices().popMatrix(); // Hue bar sx = ex + 5; @@ -90,7 +77,7 @@ public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int for (int i = sy; i < ey; i++) { float curHue = (float) (i - sy) / (ey - sy); - DrawableHelper.fill(matrices, sx, i, ex, i + 1, 0xff000000 | pack(hsvToRgb(curHue, 1f, 1f))); + matrices.fill(sx, i, ex, i + 1, 0xff000000 | pack(hsvToRgb(curHue, 1f, 1f))); } // Hue bar input handler @@ -101,10 +88,10 @@ public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int // Hue bar cursor cursorY = (int) (sy + (ey - sy) * hsv[0]); - DrawableHelper.fill(matrices, sx, cursorY - 1, sx + 1, cursorY + 2, 0xffd0d0d0); - DrawableHelper.fill(matrices, ex - 1, cursorY - 1, ex, cursorY + 2, 0xffd0d0d0); - DrawableHelper.fill(matrices, sx, cursorY, sx + 2, cursorY + 1, 0xffd0d0d0); - DrawableHelper.fill(matrices, ex - 2, cursorY, ex, cursorY + 1, 0xffd0d0d0); + matrices.fill(sx, cursorY - 1, sx + 1, cursorY + 2, 0xffd0d0d0); + matrices.fill(ex - 1, cursorY - 1, ex, cursorY + 2, 0xffd0d0d0); + matrices.fill(sx, cursorY, sx + 2, cursorY + 1, 0xffd0d0d0); + matrices.fill(ex - 2, cursorY, ex, cursorY + 1, 0xffd0d0d0); } public SettingColor withDesc(String desc) { diff --git a/src/main/java/org/bleachhack/setting/module/SettingItemList.java b/src/main/java/org/bleachhack/setting/module/SettingItemList.java index c434a3b4be..c24bfb580f 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingItemList.java +++ b/src/main/java/org/bleachhack/setting/module/SettingItemList.java @@ -15,10 +15,8 @@ import net.minecraft.registry.Registries; import org.bleachhack.setting.SettingDataHandlers; -import com.mojang.blaze3d.systems.RenderSystem; - import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.gui.DrawContext; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -41,21 +39,20 @@ private static Collection getAllItems(Predicate filter) { } @Override - public void renderItem(MinecraftClient mc, MatrixStack matrices, Item item, int x, int y, int w, int h) { + public void renderItem(MinecraftClient mc, DrawContext matrices, Item item, int x, int y, int w, int h) { if (item == null || item == Items.AIR) { super.renderItem(mc, matrices, item, x, y, w, h); } else { - RenderSystem.getModelViewStack().push(); + matrices.getMatrices().pushMatrix(); float scale = (h - 2) / 16f; float offset = 1f / scale; - RenderSystem.getModelViewStack().scale(scale, scale, 1f); + matrices.getMatrices().scale(scale, scale); - mc.getItemRenderer().renderInGuiWithOverrides(matrices, new ItemStack(item), (int) ((x + 1) * offset), (int) ((y + 1) * offset)); + matrices.drawItem(new ItemStack(item), (int) ((x + 1) * offset), (int) ((y + 1) * offset)); - RenderSystem.getModelViewStack().pop(); - RenderSystem.applyModelViewMatrix(); + matrices.getMatrices().popMatrix(); } } diff --git a/src/main/java/org/bleachhack/setting/module/SettingKey.java b/src/main/java/org/bleachhack/setting/module/SettingKey.java index 1235dbd09b..af4f4c72cb 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingKey.java +++ b/src/main/java/org/bleachhack/setting/module/SettingKey.java @@ -14,10 +14,10 @@ import org.lwjgl.glfw.GLFW; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.input.KeyInput; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.util.InputUtil; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; public class SettingKey extends ModuleSetting { @@ -27,26 +27,26 @@ public SettingKey(int key) { } @Override - public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len) { + public void render(ModuleWindow window, DrawContext matrices, int x, int y, int len) { if (window.mouseOver(x, y, x + len, y + 12)) { - DrawableHelper.fill(matrices, x + 1, y, x + len, y + 12, 0x70303070); + matrices.fill(x + 1, y, x + len, y + 12, 0x70303070); } - + if (window.keyDown >= 0 && window.keyDown != GLFW.GLFW_KEY_ESCAPE && window.mouseOver(x, y, x + len, y + 12)) { setValue(window.keyDown == GLFW.GLFW_KEY_DELETE ? Module.KEY_UNBOUND : window.keyDown); MinecraftClient.getInstance().getSoundManager().play( - PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); } int key = getValue(); - String name = key < 0 ? "NONE" : InputUtil.fromKeyCode(key, -1).getLocalizedText().getString(); + String name = key < 0 ? "NONE" : InputUtil.fromKeyCode(new KeyInput(key, -1, 0)).getLocalizedText().getString(); if (name == null) name = "KEY" + key; else if (name.isEmpty()) name = "NONE"; - MinecraftClient.getInstance().textRenderer.drawWithShadow( - matrices, "Bind: " + name + (window.mouseOver(x, y, x + len, y + 12) ? "..." : ""), x + 3, y + 2, 0xcfe0cf); + matrices.drawTextWithShadow( + MinecraftClient.getInstance().textRenderer, "Bind: " + name + (window.mouseOver(x, y, x + len, y + 12) ? "..." : ""), x + 3, y + 2, 0xcfe0cf); } public SettingKey withDesc(String desc) { diff --git a/src/main/java/org/bleachhack/setting/module/SettingList.java b/src/main/java/org/bleachhack/setting/module/SettingList.java index 28ddc97b34..60bc170dc5 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingList.java +++ b/src/main/java/org/bleachhack/setting/module/SettingList.java @@ -8,12 +8,12 @@ */ package org.bleachhack.setting.module; -import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.input.MouseInput; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.sound.SoundEvents; @@ -44,19 +44,19 @@ public SettingList(String text, String windowText, SettingDataHandler itemHan this.itemPool = new LinkedHashSet<>(itemPool); } - public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len) { + public void render(ModuleWindow window, DrawContext matrices, int x, int y, int len) { if (window.mouseOver(x, y, x + len, y + 12)) { - DrawableHelper.fill(matrices, x + 1, y, x + len, y + 12, 0x70303070); + matrices.fill(x + 1, y, x + len, y + 12, 0x70303070); } - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, getName(), x + 3, y + 2, 0xcfe0cf); + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, getName(), x + 3, y + 2, 0xcfe0cf); - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, "...", x + len - 7, y + 2, 0xcfd0cf); + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "...", x + len - 7, y + 2, 0xcfd0cf); if (window.mouseOver(x, y, x + len, y + 12) && window.lmDown) { window.mouseReleased(window.mouseX, window.mouseY, 1); - MinecraftClient.getInstance().currentScreen.mouseReleased(window.mouseX, window.mouseY, 0); - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + MinecraftClient.getInstance().currentScreen.mouseReleased(new Click(window.mouseX, window.mouseY, new MouseInput(0, 0))); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); MinecraftClient.getInstance().setScreen(new ListWidowScreen(MinecraftClient.getInstance().currentScreen)); } } @@ -65,17 +65,17 @@ public boolean contains(T item) { return getValue().contains(item); } - public void renderItem(MinecraftClient mc, MatrixStack matrices, T item, int x, int y, int w, int h) { - matrices.push(); + public void renderItem(MinecraftClient mc, DrawContext matrices, T item, int x, int y, int w, int h) { + matrices.getMatrices().pushMatrix(); float scale = (h - 2) / 10f; float offset = 1f / scale; - matrices.scale(scale, scale, 1f); + matrices.getMatrices().scale(scale, scale); - mc.textRenderer.drawWithShadow(matrices, "?", (x + 5) * offset, (y + 4) * offset, -1); + matrices.drawTextWithShadow(mc.textRenderer, "?", (int) ((x + 5) * offset), (int) ((y + 4) * offset), -1); - matrices.pop(); + matrices.getMatrices().popMatrix(); } /** @@ -143,12 +143,13 @@ public void init() { scrollbar = getWindow(0).addWidget(new WindowScrollbarWidget(x2 - 11, 12, 0, y2 - 39, scrollbar == null ? 0 : scrollbar.getPageOffset())); } - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - renderBackground(matrices); + public void render(DrawContext matrices, int mouseX, int mouseY, float delta) { + // Screen.renderWithTooltip() now calls renderBackground() once itself before render() runs + // (1.21.11) - calling it again here throws "Can only blur once per frame". super.render(matrices, mouseX, mouseY, delta); } - public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mouseY) { + public void onRenderWindow(DrawContext matrices, int window, int mouseX, int mouseY) { super.onRenderWindow(matrices, window, mouseX, mouseY); toAddItem = null; @@ -194,25 +195,19 @@ public void onRenderWindow(MatrixStack matrices, int window, int mouseX, int mou int curY = y1 + inputField.y1 - 4 - toDraw.size() * 17; int longest = toDraw.stream().mapToInt(e -> textRenderer.getWidth(getName(e))).max().orElse(0); - RenderSystem.getModelViewStack().push(); - RenderSystem.getModelViewStack().translate(0, 0, 150); - - matrices.push(); - matrices.translate(0, 0, 150); - + // 1.19.4 pushed a Z offset here (RenderSystem model-view matrix + MatrixStack) so the + // search dropdown draws above the entry list. DrawContext has no Z axis (Matrix3x2f is + // 2D) - its GUI queue instead layers strictly by submission order, and this dropdown is + // already submitted after the entry list above, so it draws on top with no extra work. for (T e: toDraw) { drawSearchEntry(matrices, e, x1 + inputField.x1, curY, longest + 23, 16, mouseX, mouseY); curY += 17; } - - matrices.pop(); - RenderSystem.getModelViewStack().pop(); - RenderSystem.applyModelViewMatrix(); } } } - private void drawEntry(MatrixStack matrices, T item, int x, int y, int width, int height, int mouseX, int mouseY) { + private void drawEntry(DrawContext matrices, T item, int x, int y, int width, int height, int mouseX, int mouseY) { boolean mouseOverDelete = mouseX >= x + width - 14 && mouseX <= x + width - 1 && mouseY >= y + 2 && mouseY <= y + height - 2; Window.fill(matrices, x + width - 14, y + 2, x + width - 1, y + height - 2, mouseOverDelete ? 0x4fb070f0 : 0x60606090); @@ -222,13 +217,13 @@ private void drawEntry(MatrixStack matrices, T item, int x, int y, int width, in renderItem(client, matrices, item, x, y, height, height); - drawTextWithShadow(matrices, textRenderer, getName(item), x + height + 4, y + 4, -1); - drawTextWithShadow(matrices, textRenderer, "\u00a7cx", x + width - 10, y + 5, -1); + matrices.drawTextWithShadow(textRenderer, getName(item), x + height + 4, y + 4, -1); + matrices.drawTextWithShadow(textRenderer, "\u00a7cx", x + width - 10, y + 5, -1); } - private void drawSearchEntry(MatrixStack matrices, T item, int x, int y, int width, int height, int mouseX, int mouseY) { + private void drawSearchEntry(DrawContext matrices, T item, int x, int y, int width, int height, int mouseX, int mouseY) { boolean mouseOver = mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height; - DrawableHelper.fill(matrices, x, y - 1, x + width, y + height, mouseOver ? 0xdf8070d0 : 0xb0606090); + matrices.fill(x, y - 1, x + width, y + height, mouseOver ? 0xdf8070d0 : 0xb0606090); if (mouseOver) { toAddItem = item; @@ -236,7 +231,7 @@ private void drawSearchEntry(MatrixStack matrices, T item, int x, int y, int wid renderItem(client, matrices, item, x, y, height, height); - drawTextWithShadow(matrices, textRenderer, getName(item), x + height + 4, y + 4, -1); + matrices.drawTextWithShadow(textRenderer, getName(item), x + height + 4, y + 4, -1); } @Override @@ -249,28 +244,28 @@ public boolean shouldPause() { return false; } - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(Click click, boolean doubleClick) { if (toAddItem != null) { getValue().add(toAddItem); inputField.textField.setFocused(true); - client.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + client.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); BleachFileHelper.SCHEDULE_SAVE_MODULES.set(true); return false; } else if (toDeleteItem != null) { getValue().remove(toDeleteItem); - client.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + client.getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); BleachFileHelper.SCHEDULE_SAVE_MODULES.set(true); } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(click, doubleClick); } - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { if (!inputField.textField.isFocused() || inputField.textField.getText().isEmpty()) { - scrollbar.scroll(amount); + scrollbar.scroll(verticalAmount); } - return super.mouseScrolled(mouseX, mouseY, amount); + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } } } diff --git a/src/main/java/org/bleachhack/setting/module/SettingMode.java b/src/main/java/org/bleachhack/setting/module/SettingMode.java index 0e159fa35b..7c1e9d7747 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingMode.java +++ b/src/main/java/org/bleachhack/setting/module/SettingMode.java @@ -14,9 +14,8 @@ import com.google.gson.JsonElement; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.MathHelper; @@ -33,16 +32,16 @@ public int getMode() { return getValue().intValue(); } - public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len) { + public void render(ModuleWindow window, DrawContext matrices, int x, int y, int len) { if (window.mouseOver(x, y, x + len, y + 12)) { - DrawableHelper.fill(matrices, x + 1, y, x + len, y + 12, 0x70303070); + matrices.fill(x + 1, y, x + len, y + 12, 0x70303070); } - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, getName() + ": " + modes[getValue()], x + 3, y + 2, 0xcfe0cf); + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, getName() + ": " + modes[getValue()], x + 3, y + 2, 0xcfe0cf); if (window.mouseOver(x, y, x + len, y + 12) && window.lmDown) { setValue(getValue() >= modes.length - 1 ? 0 : getValue() + 1); - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); } } diff --git a/src/main/java/org/bleachhack/setting/module/SettingSlider.java b/src/main/java/org/bleachhack/setting/module/SettingSlider.java index 9ecb848a1f..83bca93d61 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingSlider.java +++ b/src/main/java/org/bleachhack/setting/module/SettingSlider.java @@ -16,9 +16,8 @@ import org.bleachhack.setting.SettingDataHandlers; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.MathHelper; @@ -47,17 +46,17 @@ public long getValueLong() { return getValue().longValue(); } - public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len) { + public void render(ModuleWindow window, DrawContext matrices, int x, int y, int len) { boolean mo = window.mouseOver(x, y, x + len, y + 12); if (mo) { - DrawableHelper.fill(matrices, x + 1, y, x + len, y + 12, 0x70303070); + matrices.fill(x + 1, y, x + len, y + 12, 0x70303070); } int pixels = (int) Math.round(MathHelper.clamp(len * ((getValue() - min) / (max - min)), 0, len)); Window.horizontalGradient(matrices, x + 1, y, x + pixels, y + 12, mo ? 0xf03078b0 : 0xf03080a0, mo ? 0xf02068c0 : 0xf02070b0); - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, getName() + ": " + (decimals == 0 ? Integer.toString(getValueInt()) : getValue()), x + 3, y + 2, 0xcfe0cf); @@ -72,7 +71,7 @@ public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int double units = 1 / (Math.pow(10, decimals)); setValue(MathHelper.clamp(getValue() + units * window.mwScroll, min, max)); - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); } } } diff --git a/src/main/java/org/bleachhack/setting/module/SettingToggle.java b/src/main/java/org/bleachhack/setting/module/SettingToggle.java index 8d0bb6e809..19bb445b3f 100644 --- a/src/main/java/org/bleachhack/setting/module/SettingToggle.java +++ b/src/main/java/org/bleachhack/setting/module/SettingToggle.java @@ -20,9 +20,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; public class SettingToggle extends ModuleSetting { @@ -38,21 +37,21 @@ public boolean getState() { return getValue().booleanValue(); } - public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int len) { + public void render(ModuleWindow window, DrawContext matrices, int x, int y, int len) { String color2 = getValue() ? "\u00a7a" : "\u00a7c"; if (window.mouseOver(x, y, x + len, y + 12)) { - DrawableHelper.fill(matrices, x + 1, y, x + len, y + 12, 0x70303070); + matrices.fill(x + 1, y, x + len, y + 12, 0x70303070); } if (!children.isEmpty()) { if (window.rmDown && window.mouseOver(x, y, x + len, y + 12)) { expanded = !expanded; - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); } if (expanded) { - DrawableHelper.fill(matrices, x + 2, y + 12, x + 3, y + getHeight(len) - 1, 0xff8070b0); + matrices.fill(x + 2, y + 12, x + 3, y + getHeight(len) - 1, 0xff8070b0); int h = y + 12; for (ModuleSetting s : children) { @@ -63,26 +62,26 @@ public void render(ModuleWindow window, MatrixStack matrices, int x, int y, int } if (expanded) { - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, color2 + "\u2228", x + len - 8, y + 3, -1); } else { - matrices.push(); + matrices.getMatrices().pushMatrix(); - matrices.scale(0.75f, 0.75f, 1f); - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, + matrices.getMatrices().scale(0.75f, 0.75f); + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, color2 + "\u00a7l>", (int) ((x + len - 7) * 1 / 0.75), (int) ((y + 4) * 1 / 0.75), -1); - matrices.pop(); + matrices.getMatrices().popMatrix(); } } - MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, color2 + getName(), x + 3, y + 2, 0xffffff); + matrices.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, color2 + getName(), x + 3, y + 2, 0xffffff); if (window.mouseOver(x, y, x + len, y + 12) && window.lmDown) { setValue(!getValue()); - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.ui(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F, 0.3F)); } } @@ -102,6 +101,10 @@ public ModuleSetting getChild(int c) { return children.get(c); } + public List> getChildren() { + return children; + } + public SettingToggle withChildren(ModuleSetting... children) { this.children.addAll(Arrays.asList(children)); return this; diff --git a/src/main/java/org/bleachhack/setting/option/OptionString.java b/src/main/java/org/bleachhack/setting/option/OptionString.java index 0a2bf25e15..26303437ed 100644 --- a/src/main/java/org/bleachhack/setting/option/OptionString.java +++ b/src/main/java/org/bleachhack/setting/option/OptionString.java @@ -6,7 +6,6 @@ import org.bleachhack.gui.window.widget.WindowWidget; import org.bleachhack.setting.SettingDataHandlers; -import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.widget.TextFieldWidget; public class OptionString extends Option { @@ -48,10 +47,10 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { textField.setText(getRealValue()); if (validator != null && !validator.apply(getRealValue())) { - DrawableHelper.fill(ms, wx + w.x1 - 1, wy + w.y1 - 1, wx + w.x2 + 1, wy + w.y1, 0xffd07070); - DrawableHelper.fill(ms, wx + w.x1 - 1, wy + w.y2, wx + w.x2 + 1, wy + w.y2 + 1, 0xffd07070); - DrawableHelper.fill(ms, wx + w.x1 - 1, wy + w.y1, wx + w.x1, wy + w.y2, 0xffd07070); - DrawableHelper.fill(ms, wx + w.x2, wy + w.y1, wx + w.x2 + 1, wy + w.y2, 0xffd07070); + ms.fill(wx + w.x1 - 1, wy + w.y1 - 1, wx + w.x2 + 1, wy + w.y1, 0xffd07070); + ms.fill(wx + w.x1 - 1, wy + w.y2, wx + w.x2 + 1, wy + w.y2 + 1, 0xffd07070); + ms.fill(wx + w.x1 - 1, wy + w.y1, wx + w.x1, wy + w.y2, 0xffd07070); + ms.fill(wx + w.x2, wy + w.y1, wx + w.x2 + 1, wy + w.y2, 0xffd07070); } }); } diff --git a/src/main/java/org/bleachhack/util/FriendManager.java b/src/main/java/org/bleachhack/util/FriendManager.java index 64d247a422..f7f5fdc462 100644 --- a/src/main/java/org/bleachhack/util/FriendManager.java +++ b/src/main/java/org/bleachhack/util/FriendManager.java @@ -9,7 +9,6 @@ package org.bleachhack.util; import java.util.Collection; -import java.util.Locale; import java.util.Set; import java.util.TreeSet; @@ -34,7 +33,7 @@ public void add(Entity entity) { } public void add(String name) { - name = Formatting.strip(name).toLowerCase(Locale.ENGLISH); + name = Formatting.strip(name); if (!name.isEmpty()) { friends.add(name); @@ -44,14 +43,14 @@ public void add(String name) { public void addAll(Collection names) { names.forEach(this::add); } - + public void remove(Entity entity) { if (entity instanceof PlayerEntity) remove(entity.getName().getString()); } public void remove(String name) { - name = Formatting.strip(name).toLowerCase(Locale.ENGLISH); + name = Formatting.strip(name); if (!name.isEmpty()) { friends.remove(name); @@ -61,16 +60,16 @@ public void remove(String name) { public void removeAll(Collection names) { names.forEach(this::remove); } - + public boolean has(Entity entity) { if (entity instanceof PlayerEntity) return has(entity.getName().getString()); - + return false; } public boolean has(String name) { - name = Formatting.strip(name).toLowerCase(Locale.ENGLISH); + name = Formatting.strip(name); if (!name.isEmpty()) { return friends.contains(name); diff --git a/src/main/java/org/bleachhack/util/InventoryUtils.java b/src/main/java/org/bleachhack/util/InventoryUtils.java index a3eec7cdc0..8e6d2f11d5 100644 --- a/src/main/java/org/bleachhack/util/InventoryUtils.java +++ b/src/main/java/org/bleachhack/util/InventoryUtils.java @@ -48,8 +48,8 @@ public static Hand selectSlot(boolean offhand, IntPredicate filter) { public static Hand selectSlot(int slot) { if (slot >= 0 && slot <= 36) { if (slot < 9) { - if (slot != mc.player.getInventory().selectedSlot) { - mc.player.getInventory().selectedSlot = slot; + if (slot != mc.player.getInventory().getSelectedSlot()) { + mc.player.getInventory().setSelectedSlot(slot); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(slot)); } @@ -59,8 +59,8 @@ public static Hand selectSlot(int slot) { if (mc.player.getInventory().getStack(i).isEmpty()) { mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, slot, 0, SlotActionType.QUICK_MOVE, mc.player); - if (i != mc.player.getInventory().selectedSlot) { - mc.player.getInventory().selectedSlot = i; + if (i != mc.player.getInventory().getSelectedSlot()) { + mc.player.getInventory().setSelectedSlot(i); mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(i)); } @@ -69,7 +69,7 @@ public static Hand selectSlot(int slot) { } mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, slot, 0, SlotActionType.PICKUP, mc.player); - mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, 36 + mc.player.getInventory().selectedSlot, 0, SlotActionType.PICKUP, mc.player); + mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, 36 + mc.player.getInventory().getSelectedSlot(), 0, SlotActionType.PICKUP, mc.player); mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, slot, 0, SlotActionType.PICKUP, mc.player); return Hand.MAIN_HAND; } @@ -84,11 +84,11 @@ public static int[] getInventorySlots(boolean offhand) { int[] i = new int[offhand ? 38 : 37]; // Add hand slots first - i[0] = mc.player.getInventory().selectedSlot; + i[0] = mc.player.getInventory().getSelectedSlot(); i[1] = 40; for (int j = 0; j < 36; j++) { - if (j != mc.player.getInventory().selectedSlot) { + if (j != mc.player.getInventory().getSelectedSlot()) { i[offhand ? j + 2 : j + 1] = j; } } diff --git a/src/main/java/org/bleachhack/util/ItemContentUtils.java b/src/main/java/org/bleachhack/util/ItemContentUtils.java index 0b41fd34fe..bc6851e6a2 100644 --- a/src/main/java/org/bleachhack/util/ItemContentUtils.java +++ b/src/main/java/org/bleachhack/util/ItemContentUtils.java @@ -9,28 +9,41 @@ package org.bleachhack.util; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import net.minecraft.client.MinecraftClient; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.BundleContentsComponent; +import net.minecraft.component.type.ContainerComponent; +import net.minecraft.component.type.WritableBookContentComponent; +import net.minecraft.component.type.WrittenBookContentComponent; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; +import net.minecraft.text.RawFilteredPair; import net.minecraft.text.Text; +import net.minecraft.util.collection.DefaultedList; public class ItemContentUtils { public static List getItemsInContainer(ItemStack item) { - List items = new ArrayList<>(Collections.nCopies(27, new ItemStack(Items.AIR))); - NbtCompound nbt = item.getOrCreateNbt().contains("BlockEntityTag", 10) - ? item.getNbt().getCompound("BlockEntityTag") : item.getNbt(); + DefaultedList items = DefaultedList.ofSize(27, new ItemStack(Items.AIR)); - if (nbt.contains("Items", 9)) { - NbtList nbt2 = nbt.getList("Items", 10); - for (int i = 0; i < nbt2.size(); i++) { - int slot = nbt2.getCompound(i).contains("Slot", 99) ? nbt2.getCompound(i).getByte("Slot") : i; - items.set(slot, ItemStack.fromNbt(nbt2.getCompound(i))); + // ported: 1.19.4 read shulker box contents from the item's "BlockEntityTag.Items" nbt list + // and bundle contents from a top-level "Items" nbt list; 1.21.11 componentizes both as + // DataComponentTypes.CONTAINER (shulker/chest-like blocks) and BUNDLE_CONTENTS (bundles). + ContainerComponent container = item.get(DataComponentTypes.CONTAINER); + if (container != null) { + container.copyTo(items); + } else { + BundleContentsComponent bundle = item.get(DataComponentTypes.BUNDLE_CONTENTS); + if (bundle != null) { + int i = 0; + for (ItemStack stack : bundle.iterateCopy()) { + if (i >= items.size()) { + break; + } + items.set(i++, stack); + } } } @@ -39,17 +52,22 @@ public static List getItemsInContainer(ItemStack item) { public static List> getTextInBook(ItemStack item) { List pages = new ArrayList<>(); - NbtCompound nbt = item.getNbt(); - - if (nbt != null && nbt.contains("pages")) { - NbtList nbt2 = nbt.getList("pages", 8); - for (int i = 0; i < nbt2.size(); i++) { - if (item.getItem() == Items.WRITABLE_BOOK) { - pages.add(nbt2.getString(i)); - } else { - Text text = Text.Serializer.fromLenientJson(nbt2.getString(i)); - pages.add(text != null ? text.getString() : nbt2.getString(i)); + // ported: 1.19.4 read book pages from the item's "pages" nbt list (raw strings for + // writable books, json-text strings for written books); 1.21.11 stores them as typed + // components with the written book pages already parsed into Text. + if (item.getItem() == Items.WRITABLE_BOOK) { + WritableBookContentComponent content = item.get(DataComponentTypes.WRITABLE_BOOK_CONTENT); + if (content != null) { + for (RawFilteredPair page : content.pages()) { + pages.add(page.raw()); + } + } + } else { + WrittenBookContentComponent content = item.get(DataComponentTypes.WRITTEN_BOOK_CONTENT); + if (content != null) { + for (Text text : content.getPages(false)) { + pages.add(text.getString()); } } } diff --git a/src/main/java/org/bleachhack/util/NotebotUtils.java b/src/main/java/org/bleachhack/util/NotebotUtils.java index bc104bc18a..327724fc01 100644 --- a/src/main/java/org/bleachhack/util/NotebotUtils.java +++ b/src/main/java/org/bleachhack/util/NotebotUtils.java @@ -36,7 +36,7 @@ import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; -import net.minecraft.block.enums.Instrument; +import net.minecraft.block.enums.NoteBlockInstrument; import net.minecraft.client.MinecraftClient; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.item.ItemStack; @@ -52,23 +52,23 @@ public class NotebotUtils { public static final String[] NOTE_NAMES = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; private static final int[] NOTE_POSES = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; - public static final EnumMap INSTRUMENT_TO_ITEM = Util.make(new EnumMap<>(Instrument.class), it -> { - it.put(Instrument.HARP, new ItemStack(Items.DIRT)); - it.put(Instrument.BASEDRUM, new ItemStack(Items.STONE)); - it.put(Instrument.SNARE, new ItemStack(Items.SAND)); - it.put(Instrument.HAT, new ItemStack(Items.GLASS)); - it.put(Instrument.BASS, new ItemStack(Items.OAK_WOOD)); - it.put(Instrument.FLUTE, new ItemStack(Items.CLAY)); - it.put(Instrument.BELL, new ItemStack(Items.GOLD_BLOCK)); - it.put(Instrument.GUITAR, new ItemStack(Items.WHITE_WOOL)); - it.put(Instrument.CHIME, new ItemStack(Items.PACKED_ICE)); - it.put(Instrument.XYLOPHONE, new ItemStack(Items.BONE_BLOCK)); - it.put(Instrument.IRON_XYLOPHONE, new ItemStack(Items.IRON_BLOCK)); - it.put(Instrument.COW_BELL, new ItemStack(Items.SOUL_SAND)); - it.put(Instrument.DIDGERIDOO, new ItemStack(Items.PUMPKIN)); - it.put(Instrument.BIT, new ItemStack(Items.EMERALD_BLOCK)); - it.put(Instrument.BANJO, new ItemStack(Items.HAY_BLOCK)); - it.put(Instrument.PLING, new ItemStack(Items.GLOWSTONE)); + public static final EnumMap INSTRUMENT_TO_ITEM = Util.make(new EnumMap<>(NoteBlockInstrument.class), it -> { + it.put(NoteBlockInstrument.HARP, new ItemStack(Items.DIRT)); + it.put(NoteBlockInstrument.BASEDRUM, new ItemStack(Items.STONE)); + it.put(NoteBlockInstrument.SNARE, new ItemStack(Items.SAND)); + it.put(NoteBlockInstrument.HAT, new ItemStack(Items.GLASS)); + it.put(NoteBlockInstrument.BASS, new ItemStack(Items.OAK_WOOD)); + it.put(NoteBlockInstrument.FLUTE, new ItemStack(Items.CLAY)); + it.put(NoteBlockInstrument.BELL, new ItemStack(Items.GOLD_BLOCK)); + it.put(NoteBlockInstrument.GUITAR, new ItemStack(Items.WHITE_WOOL)); + it.put(NoteBlockInstrument.CHIME, new ItemStack(Items.PACKED_ICE)); + it.put(NoteBlockInstrument.XYLOPHONE, new ItemStack(Items.BONE_BLOCK)); + it.put(NoteBlockInstrument.IRON_XYLOPHONE, new ItemStack(Items.IRON_BLOCK)); + it.put(NoteBlockInstrument.COW_BELL, new ItemStack(Items.SOUL_SAND)); + it.put(NoteBlockInstrument.DIDGERIDOO, new ItemStack(Items.PUMPKIN)); + it.put(NoteBlockInstrument.BIT, new ItemStack(Items.EMERALD_BLOCK)); + it.put(NoteBlockInstrument.BANJO, new ItemStack(Items.HAY_BLOCK)); + it.put(NoteBlockInstrument.PLING, new ItemStack(Items.GLOWSTONE)); }); public static void downloadSongs(boolean log) { @@ -108,13 +108,13 @@ public static void downloadSongs(boolean log) { public static void playNote(Multimap song, int tick) { for (Note note: song.get(tick)) { - play(Instrument.values()[note.instrument].getSound().value(), (float) Math.pow(2.0D, (note.pitch - 12) / 12.0D)); + play(NoteBlockInstrument.values()[note.instrument].getSound().value(), (float) Math.pow(2.0D, (note.pitch - 12) / 12.0D)); } } private static void play(SoundEvent sound, float pitch) { MinecraftClient mc = MinecraftClient.getInstance(); - Vec3d vec = mc.player == null ? Vec3d.ZERO : mc.player.getPos(); + Vec3d vec = mc.player == null ? Vec3d.ZERO : mc.player.getEntityPos(); mc.getSoundManager().play(new PositionedSoundInstance(sound, SoundCategory.RECORDS, 3.0F, pitch, Random.create(0L), vec.x, vec.y, vec.z)); } @@ -224,7 +224,7 @@ public static Song parseMidi(Path path) { byte[] data = msg.getData(); if (msg.getType() == 0x03) { - out += " Meta Instrument: " + new String(data); + out += " Meta NoteBlockInstrument: " + new String(data); } else if (msg.getType() == 0x51) { int tempo = (data[0] & 0xff) << 16 | (data[1] & 0xff) << 8 | (data[2] & 0xff); bpm = 60_000_000 / tempo; diff --git a/src/main/java/org/bleachhack/util/PlayerInteractEntityC2SUtils.java b/src/main/java/org/bleachhack/util/PlayerInteractEntityC2SUtils.java index 66b9c38265..cdffe03230 100644 --- a/src/main/java/org/bleachhack/util/PlayerInteractEntityC2SUtils.java +++ b/src/main/java/org/bleachhack/util/PlayerInteractEntityC2SUtils.java @@ -20,14 +20,14 @@ public class PlayerInteractEntityC2SUtils { public static Entity getEntity(PlayerInteractEntityC2SPacket packet) { PacketByteBuf packetBuf = new PacketByteBuf(Unpooled.buffer()); - packet.write(packetBuf); + PlayerInteractEntityC2SPacket.CODEC.encode(packetBuf, packet); return MinecraftClient.getInstance().world.getEntityById(packetBuf.readVarInt()); } public static InteractType getInteractType(PlayerInteractEntityC2SPacket packet) { PacketByteBuf packetBuf = new PacketByteBuf(Unpooled.buffer()); - packet.write(packetBuf); + PlayerInteractEntityC2SPacket.CODEC.encode(packetBuf, packet); packetBuf.readVarInt(); return packetBuf.readEnumConstant(InteractType.class); diff --git a/src/main/java/org/bleachhack/util/auth/LoginHelper.java b/src/main/java/org/bleachhack/util/auth/LoginHelper.java index 8db6eabd67..db66727e19 100644 --- a/src/main/java/org/bleachhack/util/auth/LoginHelper.java +++ b/src/main/java/org/bleachhack/util/auth/LoginHelper.java @@ -8,15 +8,14 @@ */ package org.bleachhack.util.auth; -import java.net.Proxy; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.nio.charset.StandardCharsets; import java.util.Base64; -import java.util.Locale; import java.util.Optional; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -27,12 +26,9 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.mojang.authlib.Agent; import com.mojang.authlib.exceptions.AuthenticationException; -import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; -import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; -import net.minecraft.client.util.Session; +import net.minecraft.client.session.Session; public final class LoginHelper { @@ -45,29 +41,13 @@ public final class LoginHelper { private static final Pattern MS_REDIRECT_PATTERN = Pattern.compile("urlPost:'(.*?)'"); private static final Pattern MS_ACCESS_TOKEN_PATTERN = Pattern.compile("accessToken=(.*?)(&|$)"); + // Legacy Mojang email+password login is gone, not just renamed: authlib 7.x no longer ships + // YggdrasilUserAuthentication/Agent at all (Mojang discontinued the underlying legacy login + // service years before 1.21.11 - every account had to migrate to Microsoft). There's no API to + // port this to because the service it talked to no longer exists; Microsoft login (below) is the + // only real login path left. public static Session createMojangSession(String email, String password) throws AuthenticationException { - YggdrasilUserAuthentication auth = (YggdrasilUserAuthentication) new YggdrasilAuthenticationService( - Proxy.NO_PROXY, "").createUserAuthentication(Agent.MINECRAFT); - - auth.setUsername(email); - auth.setPassword(password); - - try { - auth.logIn(); - } catch (AuthenticationException e) { - if (e.getMessage().toLowerCase(Locale.ENGLISH).contains("credentials")) - throw new AuthenticationException("Invalid Password!"); - - if (e.getMessage().toLowerCase(Locale.ENGLISH).contains("410")) - throw new AuthenticationException("Account Migrated, Use Microsoft Login."); - - throw e; - } - - return new Session(auth.getSelectedProfile().getName(), - auth.getSelectedProfile().getId().toString(), - auth.getAuthenticatedToken(), - Optional.empty(), Optional.empty(), Session.AccountType.MOJANG); + throw new AuthenticationException("Mojang accounts were discontinued - use Microsoft login."); } public static Session createMicrosoftSession(String email, String password) throws AuthenticationException { @@ -178,7 +158,7 @@ private static Session getSessionFromXsts(String xstsId, String xstsToken) throw if (id.length() == 32) id = id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20); - return new Session(profileJson.get("name").getAsString(), id, mcToken, Optional.empty(), Optional.empty(), Session.AccountType.MSA); + return new Session(profileJson.get("name").getAsString(), UUID.fromString(id), mcToken, Optional.empty(), Optional.empty()); } private static void throwIfInvalid(HttpResponse response, boolean checkStatus, String reason) throws AuthenticationException { diff --git a/src/main/java/org/bleachhack/util/io/BleachFileHelper.java b/src/main/java/org/bleachhack/util/io/BleachFileHelper.java index 78907f2def..ef2c4c1e7b 100644 --- a/src/main/java/org/bleachhack/util/io/BleachFileHelper.java +++ b/src/main/java/org/bleachhack/util/io/BleachFileHelper.java @@ -50,14 +50,28 @@ public static void startSavingExecutor() { savingExecutor = MoreExecutors.getExitingScheduledExecutorService(new ScheduledThreadPoolExecutor(1)); savingExecutor.scheduleAtFixedRate(() -> { - if (SCHEDULE_SAVE_MODULES.getAndSet(false)) saveModules(); - if (SCHEDULE_SAVE_OPTIONS.getAndSet(false)) saveOptions(); - if (SCHEDULE_SAVE_CLICKGUI.getAndSet(false)) saveClickGui(); - if (SCHEDULE_SAVE_FRIENDS.getAndSet(false)) saveFriends(); - if (SCHEDULE_SAVE_UI.getAndSet(false)) saveUI(); + // scheduleAtFixedRate silently cancels the task forever if the runnable throws, which + // would stop *all* saving for the rest of the session with nothing in the log. Guard + // each save so one broken one can't take the others down with it. + trySave(SCHEDULE_SAVE_MODULES, BleachFileHelper::saveModules, "modules"); + trySave(SCHEDULE_SAVE_OPTIONS, BleachFileHelper::saveOptions, "options"); + trySave(SCHEDULE_SAVE_CLICKGUI, BleachFileHelper::saveClickGui, "clickgui"); + trySave(SCHEDULE_SAVE_FRIENDS, BleachFileHelper::saveFriends, "friends"); + trySave(SCHEDULE_SAVE_UI, BleachFileHelper::saveUI, "ui"); }, 0, 5, TimeUnit.SECONDS); } + private static void trySave(AtomicBoolean flag, Runnable save, String name) { + if (!flag.getAndSet(false)) + return; + + try { + save.run(); + } catch (Throwable t) { + BleachLogger.logger.error("Error saving " + name + "!", t); + } + } + public static void stopSavingExecutor() { savingExecutor.shutdown(); savingExecutor = null; diff --git a/src/main/java/org/bleachhack/util/operation/PlaceDirOperation.java b/src/main/java/org/bleachhack/util/operation/PlaceDirOperation.java index cdef3061eb..348d9469eb 100644 --- a/src/main/java/org/bleachhack/util/operation/PlaceDirOperation.java +++ b/src/main/java/org/bleachhack/util/operation/PlaceDirOperation.java @@ -33,9 +33,9 @@ protected PlaceDirOperation(BlockPos pos, Direction dir, Item... items) { } public static OperationBlueprint blueprint(int localX, int localY, int localZ, Direction localDir, Item... items) { - int horizontal = (localDir.getHorizontal() + 1) % 4; + int horizontal = (localDir.getHorizontalQuarterTurns() + 1) % 4; return (origin, dir) -> new PlaceDirOperation(origin.add(rotate(localX, localY, localZ, dir)), - localDir.getAxis() == Axis.Y ? localDir : Direction.fromHorizontal(Math.floorMod(dir.getHorizontal() - horizontal, 4)), items); + localDir.getAxis() == Axis.Y ? localDir : Direction.fromHorizontalQuarterTurns(Math.floorMod(dir.getHorizontalQuarterTurns() - horizontal, 4)), items); } @Override diff --git a/src/main/java/org/bleachhack/util/operation/PlaceOperation.java b/src/main/java/org/bleachhack/util/operation/PlaceOperation.java index 1ae06506b8..72f2a530c2 100644 --- a/src/main/java/org/bleachhack/util/operation/PlaceOperation.java +++ b/src/main/java/org/bleachhack/util/operation/PlaceOperation.java @@ -15,8 +15,11 @@ import org.bleachhack.util.render.color.QuadColor; import org.bleachhack.util.world.WorldUtils; +import java.util.List; + import net.minecraft.block.BlockState; -import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.BlockRenderLayers; +import net.minecraft.client.render.model.BlockModelPart; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; @@ -69,12 +72,13 @@ public void render() { MatrixStack matrices = WorldRenderer.matrixFrom(pos.getX(), pos.getY(), pos.getZ()); BlockState state = ((BlockItem) item).getBlock().getDefaultState(); + List parts = mc.getBlockRenderManager().getModel(state).getParts(Random.create(0L)); mc.getBlockRenderManager().renderBlock(state, pos, mc.world, matrices, - mc.getBufferBuilders().getEntityVertexConsumers().getBuffer(RenderLayers.getMovingBlockLayer(state)), - false, Random.create(0L)); + mc.getBufferBuilders().getEntityVertexConsumers().getBuffer(BlockRenderLayers.getMovingBlockLayer(state)), + false, parts); - mc.getBufferBuilders().getEntityVertexConsumers().draw(RenderLayers.getMovingBlockLayer(state)); + mc.getBufferBuilders().getEntityVertexConsumers().draw(BlockRenderLayers.getMovingBlockLayer(state)); for (Box box: state.getOutlineShape(mc.world, pos).getBoundingBoxes()) { Renderer.drawBoxFill(box.offset(pos), QuadColor.single(0.45f, 0.7f, 1f, 0.4f)); diff --git a/src/main/java/org/bleachhack/util/render/FrustumUtils.java b/src/main/java/org/bleachhack/util/render/FrustumUtils.java index b29f48a62b..29e10b5f78 100644 --- a/src/main/java/org/bleachhack/util/render/FrustumUtils.java +++ b/src/main/java/org/bleachhack/util/render/FrustumUtils.java @@ -1,18 +1,25 @@ package org.bleachhack.util.render; import org.bleachhack.mixin.AccessorFrustum; -import org.bleachhack.mixin.AccessorWorldRenderer; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.Frustum; import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; -import org.joml.Vector4f; public class FrustumUtils { + // 1.21.11's WorldRenderer no longer keeps a persistent "current frustum" field (frustum culling + // was reworked to pass the Frustum through the per-frame render call chain as a parameter + // instead) - so there's nothing left for an Accessor mixin to expose. MixinWorldRenderer instead + // captures the live per-frame Frustum straight out of fillEntityRenderStates(...) into this field. + private static Frustum currentFrustum; + + public static void setCurrentFrustum(Frustum frustum) { + currentFrustum = frustum; + } + public static Frustum getFrustum() { - return ((AccessorWorldRenderer) MinecraftClient.getInstance().worldRenderer).getFrustum(); + return currentFrustum; } public static boolean isBoxVisible(Box box) { diff --git a/src/main/java/org/bleachhack/util/render/Renderer.java b/src/main/java/org/bleachhack/util/render/Renderer.java index a78d5cc738..d57eb31ed8 100644 --- a/src/main/java/org/bleachhack/util/render/Renderer.java +++ b/src/main/java/org/bleachhack/util/render/Renderer.java @@ -13,17 +13,24 @@ import org.bleachhack.util.render.color.LineColor; import org.bleachhack.util.render.color.QuadColor; -import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gl.UniformType; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Camera; -import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.RenderSetup; import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; +import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Direction; @@ -32,6 +39,40 @@ public class Renderer { + // 1.19.4 achieved "see through walls" by manually calling RenderSystem.disableDepthTest() around a + // draw call - that method no longer exists (depth-test is baked into the RenderPipeline). These are + // NO_DEPTH_TEST variants of vanilla's own debug-fill/lines pipelines, reusing their exact GLSL/ + // uniform declarations (position_color / rendertype_lines) so only the depth test differs. + // + // NO_DEPTH_FILL must declare the DynamicTransforms/Projection uniforms itself (matching vanilla's + // private TRANSFORMS_AND_PROJECTION_SNIPPET, which DEBUG_FILLED_BOX/DEBUG_QUADS are built from) - + // without them the vertex shader never gets a transform/projection matrix bound and silently draws + // nothing, which is why this was invisible while the NO_DEPTH_LINES sibling (built from the + // already-widened RENDERTYPE_LINES_SNIPPET, which already includes them) worked fine. + // Package-visible (not private) so ShaderEspRenderer can reuse it for its offscreen silhouette pass. + static final RenderLayer NO_DEPTH_FILL = RenderLayer.of("bleachhack_no_depth_fill", + RenderSetup.builder(RenderPipeline.builder() + .withLocation(Identifier.of("bleachhack", "pipeline/no_depth_fill")) + .withUniform("DynamicTransforms", UniformType.UNIFORM_BUFFER) + .withUniform("Projection", UniformType.UNIFORM_BUFFER) + .withVertexShader(Identifier.of("minecraft", "core/position_color")) + .withFragmentShader(Identifier.of("minecraft", "core/position_color")) + .withVertexFormat(VertexFormats.POSITION_COLOR, VertexFormat.DrawMode.QUADS) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withDepthWrite(false) + .withCull(false) + .build()) + .translucent() + .build()); + + private static final RenderLayer NO_DEPTH_LINES = RenderLayer.of("bleachhack_no_depth_lines", + RenderSetup.builder(RenderPipeline.builder(RenderPipelines.RENDERTYPE_LINES_SNIPPET) + .withLocation(Identifier.of("bleachhack", "pipeline/no_depth_lines")) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .build()) + .build()); + // -------------------- Fill + Outline Boxes -------------------- public static void drawBoxBoth(BlockPos blockPos, QuadColor color, float lineWidth, Direction... excludeDirs) { @@ -65,21 +106,21 @@ public static void drawBoxFill(Box box, QuadColor color, Direction... excludeDir return; } - setup(); - MatrixStack matrices = matrixFrom(box.minX, box.minY, box.minZ); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); + RenderLayer layer = RenderLayers.DEBUG_FILLED_BOX; + BufferBuilder buffer = Tessellator.getInstance().begin(layer.getDrawMode(), layer.getVertexFormat()); + Vertexer.vertexBoxQuads(matrices, buffer, Boxes.moveToZero(box), color, excludeDirs); + layer.draw(buffer.end()); + } - // Fill - RenderSystem.setShader(GameRenderer::getPositionColorProgram); + /** Same as {@link #drawBoxFill}, but ignores depth test - visible through walls (ESP "Shader" mode). */ + public static void drawBoxFillThroughWalls(Box box, QuadColor color, Direction... excludeDirs) { + MatrixStack matrices = matrixFrom(box.minX, box.minY, box.minZ); - buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + BufferBuilder buffer = Tessellator.getInstance().begin(NO_DEPTH_FILL.getDrawMode(), NO_DEPTH_FILL.getVertexFormat()); Vertexer.vertexBoxQuads(matrices, buffer, Boxes.moveToZero(box), color, excludeDirs); - tessellator.draw(); - - cleanup(); + NO_DEPTH_FILL.draw(buffer.end()); } // -------------------- Outline Boxes -------------------- @@ -93,25 +134,21 @@ public static void drawBoxOutline(Box box, QuadColor color, float lineWidth, Dir return; } - setup(); - MatrixStack matrices = matrixFrom(box.minX, box.minY, box.minZ); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - // Outline - RenderSystem.disableCull(); - RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram); - RenderSystem.lineWidth(lineWidth); - - buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES); - Vertexer.vertexBoxLines(matrices, buffer, Boxes.moveToZero(box), color, excludeDirs); - tessellator.draw(); + RenderLayer layer = RenderLayers.LINES; + BufferBuilder buffer = Tessellator.getInstance().begin(layer.getDrawMode(), layer.getVertexFormat()); + Vertexer.vertexBoxLines(matrices, buffer, Boxes.moveToZero(box), color, lineWidth, excludeDirs); + layer.draw(buffer.end()); + } - RenderSystem.enableCull(); + /** Same as {@link #drawBoxOutline}, but ignores depth test - visible through walls (ESP "Shader" mode). */ + public static void drawBoxOutlineThroughWalls(Box box, QuadColor color, float lineWidth, Direction... excludeDirs) { + MatrixStack matrices = matrixFrom(box.minX, box.minY, box.minZ); - cleanup(); + BufferBuilder buffer = Tessellator.getInstance().begin(NO_DEPTH_LINES.getDrawMode(), NO_DEPTH_LINES.getVertexFormat()); + Vertexer.vertexBoxLines(matrices, buffer, Boxes.moveToZero(box), color, lineWidth, excludeDirs); + NO_DEPTH_LINES.draw(buffer.end()); } // -------------------- Quads -------------------- @@ -122,26 +159,17 @@ public static void drawQuadFill(double x1, double y1, double z1, double x2, doub return; } - setup(); - MatrixStack matrices = matrixFrom(x1, y1, z1); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - // Fill - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - - buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + RenderLayer layer = RenderLayers.DEBUG_QUADS; + BufferBuilder buffer = Tessellator.getInstance().begin(layer.getDrawMode(), layer.getVertexFormat()); Vertexer.vertexQuad(matrices, buffer, 0f, 0f, 0f, (float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1), (float) (x3 - x1), (float) (y3 - y1), (float) (z3 - z1), (float) (x4 - x1), (float) (y4 - y1), (float) (z4 - z1), cullMode, color); - tessellator.draw(); - - cleanup(); + layer.draw(buffer.end()); } public static void drawQuadOutline(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3, double x4, double y4, double z4, float lineWidth, QuadColor color) { @@ -150,29 +178,16 @@ public static void drawQuadOutline(double x1, double y1, double z1, double x2, d return; } - setup(); - MatrixStack matrices = matrixFrom(x1, y1, z1); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - int[] colors = color.getAllColors(); - // Outline - RenderSystem.disableCull(); - RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram); - RenderSystem.lineWidth(lineWidth); - - buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES); - Vertexer.vertexLine(matrices, buffer, 0f, 0f, 0f, (float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1), LineColor.gradient(colors[0], colors[1])); - Vertexer.vertexLine(matrices, buffer, (float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1), (float) (x3 - x1), (float) (y3 - y1), (float) (z3 - z1), LineColor.gradient(colors[1], colors[2])); - Vertexer.vertexLine(matrices, buffer, (float) (x3 - x1), (float) (y3 - y1), (float) (z3 - z1), (float) (x4 - x1), (float) (y4 - y1), (float) (z4 - z1), LineColor.gradient(colors[2], colors[3])); - Vertexer.vertexLine(matrices, buffer, (float) (x4 - x1), (float) (y4 - y1), (float) (z4 - z1), 0f, 0f, 0f, LineColor.gradient(colors[3], colors[0])); - tessellator.draw(); - - RenderSystem.enableCull(); - cleanup(); + RenderLayer layer = RenderLayers.LINES; + BufferBuilder buffer = Tessellator.getInstance().begin(layer.getDrawMode(), layer.getVertexFormat()); + Vertexer.vertexLine(matrices, buffer, 0f, 0f, 0f, (float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1), LineColor.gradient(colors[0], colors[1]), lineWidth); + Vertexer.vertexLine(matrices, buffer, (float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1), (float) (x3 - x1), (float) (y3 - y1), (float) (z3 - z1), LineColor.gradient(colors[1], colors[2]), lineWidth); + Vertexer.vertexLine(matrices, buffer, (float) (x3 - x1), (float) (y3 - y1), (float) (z3 - z1), (float) (x4 - x1), (float) (y4 - y1), (float) (z4 - z1), LineColor.gradient(colors[2], colors[3]), lineWidth); + Vertexer.vertexLine(matrices, buffer, (float) (x4 - x1), (float) (y4 - y1), (float) (z4 - z1), 0f, 0f, 0f, LineColor.gradient(colors[3], colors[0]), lineWidth); + layer.draw(buffer.end()); } // -------------------- Lines -------------------- @@ -182,26 +197,11 @@ public static void drawLine(double x1, double y1, double z1, double x2, double y return; } - setup(); - MatrixStack matrices = matrixFrom(x1, y1, z1); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - // Line - RenderSystem.disableDepthTest(); - RenderSystem.disableCull(); - RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram); - RenderSystem.lineWidth(width); - - buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES); - Vertexer.vertexLine(matrices, buffer, 0f, 0f, 0f, (float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1), color); - tessellator.draw(); - - RenderSystem.enableCull(); - RenderSystem.enableDepthTest(); - cleanup(); + BufferBuilder buffer = Tessellator.getInstance().begin(NO_DEPTH_LINES.getDrawMode(), NO_DEPTH_LINES.getVertexFormat()); + Vertexer.vertexLine(matrices, buffer, 0f, 0f, 0f, (float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1), color, width); + NO_DEPTH_LINES.draw(buffer.end()); } // -------------------- Utils -------------------- @@ -213,7 +213,7 @@ public static MatrixStack matrixFrom(double x, double y, double z) { matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); - matrices.translate(x - camera.getPos().x, y - camera.getPos().y, z - camera.getPos().z); + matrices.translate(x - camera.getCameraPos().x, y - camera.getCameraPos().y, z - camera.getCameraPos().z); return matrices; } @@ -223,19 +223,10 @@ public static Vec3d getInterpolationOffset(Entity e) { return Vec3d.ZERO; } - double tickDelta = MinecraftClient.getInstance().getTickDelta(); + double tickDelta = MinecraftClient.getInstance().getRenderTickCounter().getTickProgress(true); return new Vec3d( e.getX() - MathHelper.lerp(tickDelta, e.lastRenderX, e.getX()), e.getY() - MathHelper.lerp(tickDelta, e.lastRenderY, e.getY()), e.getZ() - MathHelper.lerp(tickDelta, e.lastRenderZ, e.getZ())); } - - public static void setup() { - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - } - - public static void cleanup() { - RenderSystem.disableBlend(); - } } diff --git a/src/main/java/org/bleachhack/util/render/ShaderEspRenderer.java b/src/main/java/org/bleachhack/util/render/ShaderEspRenderer.java new file mode 100644 index 0000000000..dc06ee8f53 --- /dev/null +++ b/src/main/java/org/bleachhack/util/render/ShaderEspRenderer.java @@ -0,0 +1,287 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.util.render; + +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gl.PostEffectProcessor; +import net.minecraft.client.gl.SimpleFramebuffer; +import net.minecraft.client.model.Model; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.FrameGraphBuilder; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.block.MovingBlockRenderState; +import net.minecraft.client.render.command.ModelCommandRenderer; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; +import net.minecraft.client.render.command.RenderCommandQueue; +import net.minecraft.client.render.entity.EntityRenderManager; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.item.ItemRenderState; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.render.state.CameraRenderState; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.memory.ObjectAllocator; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemDisplayContext; +import net.minecraft.text.OrderedText; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.ColorHelper; +import net.minecraft.util.math.RotationAxis; +import net.minecraft.util.math.Vec3d; +import org.jspecify.annotations.Nullable; + +import java.util.Map; +import java.util.Set; + +/** + * A real, from-scratch port of Meteor Client's ESP "Shader" mode - a private silhouette + * framebuffer, populated every frame with a flat-recolored render of each matched entity's actual + * posed model (not vanilla's Glowing-effect outline system, which this used to piggyback on: that + * meant sharing GPU resources/behavior with real Glowing potion effects/team glow, and capped how + * different the result could ever look from vanilla's own built-in glow), then composited onto the + * main framebuffer through Meteor's real distance-field glow shader. + * + *

Architecture, mapped from Meteor's utils.render.postprocess (EntityShader/EntityOutlineShader/ + * CustomOutlineVertexConsumerProvider + LevelRendererMixin's push/popEntityOutlineFramebuffer) onto + * this engine's actual APIs: + *

    + *
  • Meteor's own MC snapshot hands entities a raw {@code VertexConsumerProvider}, so it captures + * geometry by wrapping that. This engine's {@code EntityRenderer.render(...)} instead takes an + * {@code OrderedRenderCommandQueue} (a command-pattern queue, not a raw vertex sink) - so instead + * this intercepts {@code submitModel}/{@code submitModelPart} and calls {@code ModelPart.render(...)} + * directly with a flat forced color, which is simpler than Meteor's own per-vertex-consumer capture + * and gives real per-limb silhouette geometry (not just a bounding box).
  • + *
  • Meteor pushes/pops its own {@code RenderTarget} onto the level renderer's outline framebuffer + * field mid-frame. This engine's entity_outline framebuffer is a {@code Handle} baked + * into a {@code FrameGraphBuilder} DAG, not a simple swappable field - so instead of hooking that + * pipeline at all, this uses {@code RenderSystem.outputColorTextureOverride} (confirmed against + * {@code RenderLayer.draw}'s own source: it already checks this override before every immediate + * draw) to redirect this pass's draws into our own framebuffer, entirely independent of + * WorldRenderer's frame graph.
  • + *
  • Compositing (our shader, then blit) reuses the exact same 2-pass pattern vanilla's own + * entity_outline post effect uses (a custom shader pass into a "swap" target, then blit back onto + * the real target) - see assets/bleachhack/post_effect/esp_outline.json - finished off with + * {@code Framebuffer.drawBlit(...)}, the same call {@code WorldRenderer.drawEntityOutlinesFramebuffer()} + * uses for vanilla's own outline, which already carries the correct alpha blending + * ({@code RenderPipelines.ENTITY_OUTLINE_BLIT}).
  • + *
+ */ +public class ShaderEspRenderer { + + private static final MinecraftClient mc = MinecraftClient.getInstance(); + + private static final Identifier ESP_OUTLINE = Identifier.of("bleachhack", "esp_outline"); + + private static @Nullable SimpleFramebuffer framebuffer; + + private static final SilhouetteQueue QUEUE = new SilhouetteQueue(); + + public static void render(Map entities, float tickDelta) { + if (entities.isEmpty()) { + return; + } + + ensureFramebuffer(); + + RenderSystem.getDevice().createCommandEncoder().clearColorTexture(framebuffer.getColorAttachment(), 0); + + Camera camera = mc.gameRenderer.getCamera(); + Vec3d camPos = camera.getCameraPos(); + + CameraRenderState cameraState = new CameraRenderState(); + cameraState.pos = camPos; + + EntityRenderManager dispatcher = mc.getEntityRenderDispatcher(); + + RenderSystem.outputColorTextureOverride = framebuffer.getColorAttachmentView(); + try { + BufferBuilder buffer = new BufferBuilder(new net.minecraft.client.util.BufferAllocator(4096), + Renderer.NO_DEPTH_FILL.getDrawMode(), Renderer.NO_DEPTH_FILL.getVertexFormat()); + QUEUE.target = new FlatVertexConsumer(buffer); + + for (Map.Entry entry : entities.entrySet()) { + Entity entity = entry.getKey(); + int[] color = entry.getValue(); + + EntityRenderState state = dispatcher.getAndUpdateRenderState(entity, tickDelta); + + MatrixStack matrices = new MatrixStack(); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); + + QUEUE.color = ColorHelper.getArgb(255, color[0], color[1], color[2]); + dispatcher.render(state, cameraState, state.x - camPos.x, state.y - camPos.y, state.z - camPos.z, matrices, QUEUE); + } + + var built = buffer.endNullable(); + if (built != null) { + Renderer.NO_DEPTH_FILL.draw(built); + } + } finally { + RenderSystem.outputColorTextureOverride = null; + } + + PostEffectProcessor processor = mc.getShaderLoader().loadPostEffect(ESP_OUTLINE, Set.of(ESP_OUTLINE)); + if (processor == null) { + return; + } + + FrameGraphBuilder builder = new FrameGraphBuilder(); + PostEffectProcessor.FramebufferSet framebufferSet = PostEffectProcessor.FramebufferSet.singleton( + ESP_OUTLINE, builder.createObjectNode("esp_outline", framebuffer)); + processor.render(builder, framebuffer.textureWidth, framebuffer.textureHeight, framebufferSet); + builder.run(ObjectAllocator.TRIVIAL); + + framebuffer.drawBlit(mc.getFramebuffer().getColorAttachmentView()); + } + + private static void ensureFramebuffer() { + int w = mc.getWindow().getFramebufferWidth(); + int h = mc.getWindow().getFramebufferHeight(); + + if (framebuffer == null) { + framebuffer = new SimpleFramebuffer("BleachHack ESP Outline", w, h, true); + } else if (framebuffer.textureWidth != w || framebuffer.textureHeight != h) { + framebuffer.resize(w, h); + } + } + + /** Strips texture/overlay/light/normal channels ModelPart.render() sends that our plain position-color buffer doesn't support - only position+color actually matter for a flat silhouette. */ + private static final class FlatVertexConsumer implements VertexConsumer { + private final VertexConsumer delegate; + + private FlatVertexConsumer(VertexConsumer delegate) { + this.delegate = delegate; + } + + @Override + public VertexConsumer vertex(float x, float y, float z) { + delegate.vertex(x, y, z); + return this; + } + + @Override + public VertexConsumer color(int red, int green, int blue, int alpha) { + delegate.color(red, green, blue, alpha); + return this; + } + + @Override + public VertexConsumer color(int argb) { + delegate.color(argb); + return this; + } + + @Override + public VertexConsumer texture(float u, float v) { + return this; + } + + @Override + public VertexConsumer overlay(int u, int v) { + return this; + } + + @Override + public VertexConsumer light(int u, int v) { + return this; + } + + @Override + public VertexConsumer normal(float x, float y, float z) { + return this; + } + + @Override + public VertexConsumer lineWidth(float width) { + return this; + } + } + + /** Intercepts model submission and draws a flat-colored copy of the real posed model instead of the textured/lit mesh. Everything else (labels/fire/leash/blocks/items) is irrelevant to a silhouette pass and is ignored. */ + private static final class SilhouetteQueue implements OrderedRenderCommandQueue { + + private @Nullable VertexConsumer target; + private int color; + + @Override + public void submitModel(Model model, S modelState, MatrixStack matrices, RenderLayer renderLayer, int light, int overlay, + int tintedColor, @Nullable Sprite sprite, int outlineColor, ModelCommandRenderer.@Nullable CrumblingOverlayCommand crumblingOverlay) { + model.getRootPart().render(matrices, target, light, overlay, color); + } + + @Override + public void submitModelPart(ModelPart part, MatrixStack matrices, RenderLayer renderLayer, int light, int overlay, @Nullable Sprite sprite, + boolean sheeted, boolean hasGlint, int tintedColor, ModelCommandRenderer.@Nullable CrumblingOverlayCommand crumblingOverlay, int i) { + part.render(matrices, target, light, overlay, color); + } + + @Override + public RenderCommandQueue getBatchingQueue(int order) { + return this; + } + + @Override + public void submitShadowPieces(MatrixStack matrices, float shadowRadius, java.util.List shadowPieces) { + } + + @Override + public void submitLabel(MatrixStack matrices, @Nullable Vec3d nameLabelPos, int y, Text label, boolean notSneaking, int light, + double squaredDistanceToCamera, CameraRenderState cameraState) { + } + + @Override + public void submitText(MatrixStack matrices, float x, float y, OrderedText text, boolean dropShadow, TextRenderer.TextLayerType layerType, + int light, int color, int backgroundColor, int outlineColor) { + } + + @Override + public void submitFire(MatrixStack matrices, EntityRenderState renderState, org.joml.Quaternionf rotation) { + } + + @Override + public void submitLeash(MatrixStack matrices, EntityRenderState.LeashData leashData) { + } + + @Override + public void submitBlock(MatrixStack matrices, BlockState state, int light, int overlay, int outlineColor) { + } + + @Override + public void submitMovingBlock(MatrixStack matrices, MovingBlockRenderState state) { + } + + @Override + public void submitBlockStateModel(MatrixStack matrices, RenderLayer renderLayer, BlockStateModel model, float r, float g, float b, int light, + int overlay, int outlineColor) { + } + + @Override + public void submitItem(MatrixStack matrices, ItemDisplayContext displayContext, int light, int overlay, int outlineColors, int[] tintLayers, + java.util.List quads, RenderLayer renderLayer, ItemRenderState.Glint glintType) { + } + + @Override + public void submitCustom(MatrixStack matrices, RenderLayer renderLayer, OrderedRenderCommandQueue.Custom customRenderer) { + } + + @Override + public void submitCustom(OrderedRenderCommandQueue.LayeredCustom customRenderer) { + } + } +} diff --git a/src/main/java/org/bleachhack/util/render/Vertexer.java b/src/main/java/org/bleachhack/util/render/Vertexer.java index 389dcc2225..b10e524751 100644 --- a/src/main/java/org/bleachhack/util/render/Vertexer.java +++ b/src/main/java/org/bleachhack/util/render/Vertexer.java @@ -9,8 +9,6 @@ import net.minecraft.util.math.Box; import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; -import org.joml.Matrix3f; -import org.joml.Matrix4f; import org.joml.Vector3f; public class Vertexer { @@ -56,23 +54,24 @@ public static void vertexBoxQuads(MatrixStack matrices, VertexConsumer vertexCon public static void vertexQuad(MatrixStack matrices, VertexConsumer vertexConsumer, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, int cullMode, QuadColor quadColor) { int[] color = quadColor.getAllColors(); + MatrixStack.Entry entry = matrices.peek(); if (cullMode != CULL_FRONT) { - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x1, y1, z1).color(color[0], color[1], color[2], color[3]).next(); - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x2, y2, z2).color(color[4], color[5], color[6], color[7]).next(); - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x3, y3, z3).color(color[8], color[9], color[10], color[11]).next(); - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x4, y4, z4).color(color[12], color[13], color[14], color[15]).next(); + vertexConsumer.vertex(entry, x1, y1, z1).color(color[0], color[1], color[2], color[3]); + vertexConsumer.vertex(entry, x2, y2, z2).color(color[4], color[5], color[6], color[7]); + vertexConsumer.vertex(entry, x3, y3, z3).color(color[8], color[9], color[10], color[11]); + vertexConsumer.vertex(entry, x4, y4, z4).color(color[12], color[13], color[14], color[15]); } if (cullMode != CULL_BACK) { - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x4, y4, z4).color(color[0], color[1], color[2], color[3]).next(); - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x3, y3, z3).color(color[4], color[5], color[6], color[7]).next(); - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x2, y2, z2).color(color[8], color[9], color[10], color[11]).next(); - vertexConsumer.vertex(matrices.peek().getPositionMatrix(), x1, y1, z1).color(color[12], color[13], color[14], color[15]).next(); + vertexConsumer.vertex(entry, x4, y4, z4).color(color[0], color[1], color[2], color[3]); + vertexConsumer.vertex(entry, x3, y3, z3).color(color[4], color[5], color[6], color[7]); + vertexConsumer.vertex(entry, x2, y2, z2).color(color[8], color[9], color[10], color[11]); + vertexConsumer.vertex(entry, x1, y1, z1).color(color[12], color[13], color[14], color[15]); } } - public static void vertexBoxLines(MatrixStack matrices, VertexConsumer vertexConsumer, Box box, QuadColor quadColor, Direction... excludeDirs) { + public static void vertexBoxLines(MatrixStack matrices, VertexConsumer vertexConsumer, Box box, QuadColor quadColor, float lineWidth, Direction... excludeDirs) { float x1 = (float) box.minX; float y1 = (float) box.minY; float z1 = (float) box.minZ; @@ -90,59 +89,58 @@ public static void vertexBoxLines(MatrixStack matrices, VertexConsumer vertexCon int[] color = quadColor.getAllColors(); if (!exDown) { - vertexLine(matrices, vertexConsumer, x1, y1, z1, x2, y1, z1, LineColor.single(color[0], color[1], color[2], color[3])); - vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y1, z2, LineColor.single(color[4], color[5], color[6], color[7])); - vertexLine(matrices, vertexConsumer, x2, y1, z2, x1, y1, z2, LineColor.single(color[8], color[9], color[10], color[11])); - vertexLine(matrices, vertexConsumer, x1, y1, z2, x1, y1, z1, LineColor.single(color[12], color[13], color[14], color[15])); + vertexLine(matrices, vertexConsumer, x1, y1, z1, x2, y1, z1, LineColor.single(color[0], color[1], color[2], color[3]), lineWidth); + vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y1, z2, LineColor.single(color[4], color[5], color[6], color[7]), lineWidth); + vertexLine(matrices, vertexConsumer, x2, y1, z2, x1, y1, z2, LineColor.single(color[8], color[9], color[10], color[11]), lineWidth); + vertexLine(matrices, vertexConsumer, x1, y1, z2, x1, y1, z1, LineColor.single(color[12], color[13], color[14], color[15]), lineWidth); } if (!exWest) { - if (exDown) vertexLine(matrices, vertexConsumer, x1, y1, z1, x1, y1, z2, LineColor.single(color[0], color[1], color[2], color[3])); - vertexLine(matrices, vertexConsumer, x1, y1, z2, x1, y2, z2, LineColor.single(color[4], color[5], color[6], color[7])); - vertexLine(matrices, vertexConsumer, x1, y1, z1, x1, y2, z1, LineColor.single(color[8], color[9], color[10], color[11])); - if (exUp) vertexLine(matrices, vertexConsumer, x1, y2, z1, x1, y2, z2, LineColor.single(color[12], color[13], color[14], color[15])); + if (exDown) vertexLine(matrices, vertexConsumer, x1, y1, z1, x1, y1, z2, LineColor.single(color[0], color[1], color[2], color[3]), lineWidth); + vertexLine(matrices, vertexConsumer, x1, y1, z2, x1, y2, z2, LineColor.single(color[4], color[5], color[6], color[7]), lineWidth); + vertexLine(matrices, vertexConsumer, x1, y1, z1, x1, y2, z1, LineColor.single(color[8], color[9], color[10], color[11]), lineWidth); + if (exUp) vertexLine(matrices, vertexConsumer, x1, y2, z1, x1, y2, z2, LineColor.single(color[12], color[13], color[14], color[15]), lineWidth); } if (!exEast) { - if (exDown) vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y1, z2, LineColor.single(color[0], color[1], color[2], color[3])); - vertexLine(matrices, vertexConsumer, x2, y1, z2, x2, y2, z2, LineColor.single(color[4], color[5], color[6], color[7])); - vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y2, z1, LineColor.single(color[8], color[9], color[10], color[11])); - if (exUp) vertexLine(matrices, vertexConsumer, x2, y2, z1, x2, y2, z2, LineColor.single(color[12], color[13], color[14], color[15])); + if (exDown) vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y1, z2, LineColor.single(color[0], color[1], color[2], color[3]), lineWidth); + vertexLine(matrices, vertexConsumer, x2, y1, z2, x2, y2, z2, LineColor.single(color[4], color[5], color[6], color[7]), lineWidth); + vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y2, z1, LineColor.single(color[8], color[9], color[10], color[11]), lineWidth); + if (exUp) vertexLine(matrices, vertexConsumer, x2, y2, z1, x2, y2, z2, LineColor.single(color[12], color[13], color[14], color[15]), lineWidth); } if (!exNorth) { - if (exDown) vertexLine(matrices, vertexConsumer, x1, y1, z1, x2, y1, z1, LineColor.single(color[0], color[1], color[2], color[3])); - if (exEast) vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y2, z1, LineColor.single(color[4], color[5], color[6], color[7])); - if (exWest) vertexLine(matrices, vertexConsumer, x1, y1, z1, x1, y2, z1, LineColor.single(color[8], color[9], color[10], color[11])); - if (exUp) vertexLine(matrices, vertexConsumer, x1, y2, z1, x2, y2, z1, LineColor.single(color[12], color[13], color[14], color[15])); + if (exDown) vertexLine(matrices, vertexConsumer, x1, y1, z1, x2, y1, z1, LineColor.single(color[0], color[1], color[2], color[3]), lineWidth); + if (exEast) vertexLine(matrices, vertexConsumer, x2, y1, z1, x2, y2, z1, LineColor.single(color[4], color[5], color[6], color[7]), lineWidth); + if (exWest) vertexLine(matrices, vertexConsumer, x1, y1, z1, x1, y2, z1, LineColor.single(color[8], color[9], color[10], color[11]), lineWidth); + if (exUp) vertexLine(matrices, vertexConsumer, x1, y2, z1, x2, y2, z1, LineColor.single(color[12], color[13], color[14], color[15]), lineWidth); } if (!exSouth) { - if (exDown) vertexLine(matrices, vertexConsumer, x1, y1, z2, x2, y1, z2, LineColor.single(color[0], color[1], color[2], color[3])); - if (exEast) vertexLine(matrices, vertexConsumer, x2, y1, z2, x2, y2, z2, LineColor.single(color[4], color[5], color[6], color[7])); - if (exWest) vertexLine(matrices, vertexConsumer, x1, y1, z2, x1, y2, z2, LineColor.single(color[8], color[9], color[10], color[11])); - if (exUp) vertexLine(matrices, vertexConsumer, x1, y2, z2, x2, y2, z2, LineColor.single(color[12], color[13], color[14], color[15])); + if (exDown) vertexLine(matrices, vertexConsumer, x1, y1, z2, x2, y1, z2, LineColor.single(color[0], color[1], color[2], color[3]), lineWidth); + if (exEast) vertexLine(matrices, vertexConsumer, x2, y1, z2, x2, y2, z2, LineColor.single(color[4], color[5], color[6], color[7]), lineWidth); + if (exWest) vertexLine(matrices, vertexConsumer, x1, y1, z2, x1, y2, z2, LineColor.single(color[8], color[9], color[10], color[11]), lineWidth); + if (exUp) vertexLine(matrices, vertexConsumer, x1, y2, z2, x2, y2, z2, LineColor.single(color[12], color[13], color[14], color[15]), lineWidth); } if (!exUp) { - vertexLine(matrices, vertexConsumer, x1, y2, z1, x2, y2, z1, LineColor.single(color[0], color[1], color[2], color[3])); - vertexLine(matrices, vertexConsumer, x2, y2, z1, x2, y2, z2, LineColor.single(color[4], color[5], color[6], color[7])); - vertexLine(matrices, vertexConsumer, x2, y2, z2, x1, y2, z2, LineColor.single(color[8], color[9], color[10], color[11])); - vertexLine(matrices, vertexConsumer, x1, y2, z2, x1, y2, z1, LineColor.single(color[12], color[13], color[14], color[15])); + vertexLine(matrices, vertexConsumer, x1, y2, z1, x2, y2, z1, LineColor.single(color[0], color[1], color[2], color[3]), lineWidth); + vertexLine(matrices, vertexConsumer, x2, y2, z1, x2, y2, z2, LineColor.single(color[4], color[5], color[6], color[7]), lineWidth); + vertexLine(matrices, vertexConsumer, x2, y2, z2, x1, y2, z2, LineColor.single(color[8], color[9], color[10], color[11]), lineWidth); + vertexLine(matrices, vertexConsumer, x1, y2, z2, x1, y2, z1, LineColor.single(color[12], color[13], color[14], color[15]), lineWidth); } } - public static void vertexLine(MatrixStack matrices, VertexConsumer vertexConsumer, float x1, float y1, float z1, float x2, float y2, float z2, LineColor lineColor) { - Matrix4f model = matrices.peek().getPositionMatrix(); - Matrix3f normal = matrices.peek().getNormalMatrix(); + public static void vertexLine(MatrixStack matrices, VertexConsumer vertexConsumer, float x1, float y1, float z1, float x2, float y2, float z2, LineColor lineColor, float lineWidth) { + MatrixStack.Entry entry = matrices.peek(); Vector3f normalVec = getNormal(x1, y1, z1, x2, y2, z2); int[] color1 = lineColor.getColor(x1, y1, z1, 0); int[] color2 = lineColor.getColor(x2, y2, z2, 1); - vertexConsumer.vertex(model, x1, y1, z1).color(color1[0], color1[1], color1[2], color1[3]).normal(normal, normalVec.x(), normalVec.y(), normalVec.z()).next(); - vertexConsumer.vertex(model, x2, y2, z2).color(color2[0], color2[1], color2[2], color2[3]).normal(normal, normalVec.x(), normalVec.y(), normalVec.z()).next(); + vertexConsumer.vertex(entry, x1, y1, z1).color(color1[0], color1[1], color1[2], color1[3]).normal(entry, normalVec).lineWidth(lineWidth); + vertexConsumer.vertex(entry, x2, y2, z2).color(color2[0], color2[1], color2[2], color2[3]).normal(entry, normalVec).lineWidth(lineWidth); } public static Vector3f getNormal(float x1, float y1, float z1, float x2, float y2, float z2) { diff --git a/src/main/java/org/bleachhack/util/render/WireframeEntityRenderer.java b/src/main/java/org/bleachhack/util/render/WireframeEntityRenderer.java new file mode 100644 index 0000000000..9216fe0875 --- /dev/null +++ b/src/main/java/org/bleachhack/util/render/WireframeEntityRenderer.java @@ -0,0 +1,219 @@ +/* + * This file is part of the BleachHack distribution (https://github.com/BleachDev/BleachHack/). + * Copyright (c) 2021 Bleach and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package org.bleachhack.util.render; + +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.model.Model; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.block.MovingBlockRenderState; +import net.minecraft.client.render.command.ModelCommandRenderer; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; +import net.minecraft.client.render.command.RenderCommandQueue; +import net.minecraft.client.render.entity.EntityRenderManager; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.item.ItemRenderState; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.render.state.CameraRenderState; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.BufferAllocator; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemDisplayContext; +import net.minecraft.text.OrderedText; +import net.minecraft.text.Text; +import net.minecraft.util.math.RotationAxis; +import net.minecraft.util.math.Vec3d; +import org.jspecify.annotations.Nullable; + +import java.util.List; + +/** + * Meteor Client's ESP "Wireframe" mode re-renders the entity's actual posed 3D model as a + * wireframe instead of drawing a bounding box - each face of every body-part cuboid outlined + * (and optionally filled), not just one big AABB. Meteor's own port does this by re-submitting + * the model through a custom vertex consumer that captures every quad; our 1.21.11 renderer + * doesn't hand entities a raw VertexConsumerProvider any more (EntityRenderer.render takes an + * OrderedRenderCommandQueue instead), so this intercepts that queue's submitModel/submitModelPart + * calls - the model is already correctly posed for this frame by the entity's own renderer by the + * time those are called - and walks each ModelPart's cuboids directly via ModelPart#forEachCuboid, + * which hands out per-part-transformed MatrixStack.Entry objects ready to feed straight into a + * VertexConsumer, exactly like ModelPart.Cuboid's own (private) renderCuboid does. + */ +public class WireframeEntityRenderer { + + private static final MinecraftClient mc = MinecraftClient.getInstance(); + + private static final BufferAllocator FILL_BUFFER = new BufferAllocator(1536); + private static final BufferAllocator LINE_BUFFER = new BufferAllocator(1536); + + public static void render(Entity entity, float tickDelta, int r, int g, int b, int fillAlpha, float lineWidth) { + EntityRenderManager dispatcher = mc.getEntityRenderDispatcher(); + EntityRenderState state = dispatcher.getAndUpdateRenderState(entity, tickDelta); + + Camera camera = mc.gameRenderer.getCamera(); + Vec3d camPos = camera.getCameraPos(); + + CameraRenderState cameraState = new CameraRenderState(); + cameraState.pos = camPos; + + MatrixStack matrices = new MatrixStack(); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); + + Capture capture = new Capture(r, g, b, fillAlpha, lineWidth); + dispatcher.render(state, cameraState, state.x - camPos.x, state.y - camPos.y, state.z - camPos.z, matrices, capture); + capture.finish(); + } + + private static class Capture implements OrderedRenderCommandQueue { + + private final int r, g, b, fillAlpha; + private final float lineWidth; + + private @Nullable BufferBuilder fillBuf; + private @Nullable BufferBuilder lineBuf; + + private Capture(int r, int g, int b, int fillAlpha, float lineWidth) { + this.r = r; + this.g = g; + this.b = b; + this.fillAlpha = fillAlpha; + this.lineWidth = lineWidth; + + if (fillAlpha != 0) { + fillBuf = new BufferBuilder(FILL_BUFFER, RenderLayers.DEBUG_FILLED_BOX.getDrawMode(), RenderLayers.DEBUG_FILLED_BOX.getVertexFormat()); + } + if (lineWidth != 0) { + lineBuf = new BufferBuilder(LINE_BUFFER, RenderLayers.LINES.getDrawMode(), RenderLayers.LINES.getVertexFormat()); + } + } + + private void finish() { + // Not every entity submits a ModelPart/Model - dropped items, end crystals, fishing + // bobbers etc. render through submitItem/submitCustom instead, which this doesn't + // intercept, so nothing ever gets written to the buffers for them. end() throws on an + // empty buffer; endNullable() just returns null instead, so use that here. + if (fillBuf != null) { + var built = fillBuf.endNullable(); + if (built != null) { + RenderLayers.DEBUG_FILLED_BOX.draw(built); + } + } + if (lineBuf != null) { + var built = lineBuf.endNullable(); + if (built != null) { + RenderLayers.LINES.draw(built); + } + } + } + + private void drawPart(ModelPart part, MatrixStack matrices) { + part.forEachCuboid(matrices, (entry, path, index, cuboid) -> { + for (ModelPart.Quad quad : cuboid.sides) { + ModelPart.Vertex[] v = quad.vertices(); + + if (fillBuf != null) { + for (ModelPart.Vertex vertex : v) { + fillBuf.vertex(entry, vertex.worldX(), vertex.worldY(), vertex.worldZ()).color(r, g, b, fillAlpha); + } + } + + if (lineBuf != null) { + var direction = entry.transformNormal(quad.direction(), new org.joml.Vector3f()); + for (int i = 0; i < v.length; i++) { + ModelPart.Vertex from = v[i]; + ModelPart.Vertex to = v[(i + 1) % v.length]; + + lineBuf.vertex(entry, from.worldX(), from.worldY(), from.worldZ()) + .color(r, g, b, 255).normal(direction.x(), direction.y(), direction.z()).lineWidth(lineWidth); + lineBuf.vertex(entry, to.worldX(), to.worldY(), to.worldZ()) + .color(r, g, b, 255).normal(direction.x(), direction.y(), direction.z()).lineWidth(lineWidth); + } + } + } + }); + } + + // -------------------- The only commands ESP's wireframe cares about -------------------- + + @Override + public void submitModel(Model model, S modelState, MatrixStack matrices, RenderLayer renderLayer, int light, int overlay, + int tintedColor, @Nullable Sprite sprite, int outlineColor, ModelCommandRenderer.@Nullable CrumblingOverlayCommand crumblingOverlay) { + drawPart(model.getRootPart(), matrices); + } + + @Override + public void submitModelPart(ModelPart part, MatrixStack matrices, RenderLayer renderLayer, int light, int overlay, @Nullable Sprite sprite, + boolean sheeted, boolean hasGlint, int tintedColor, ModelCommandRenderer.@Nullable CrumblingOverlayCommand crumblingOverlay, int i) { + drawPart(part, matrices); + } + + // -------------------- Everything else: not real geometry, ignore -------------------- + + @Override + public RenderCommandQueue getBatchingQueue(int order) { + return this; + } + + @Override + public void submitShadowPieces(MatrixStack matrices, float shadowRadius, List shadowPieces) { + } + + @Override + public void submitLabel(MatrixStack matrices, @Nullable Vec3d nameLabelPos, int y, Text label, boolean notSneaking, int light, + double squaredDistanceToCamera, CameraRenderState cameraState) { + } + + @Override + public void submitText(MatrixStack matrices, float x, float y, OrderedText text, boolean dropShadow, TextRenderer.TextLayerType layerType, + int light, int color, int backgroundColor, int outlineColor) { + } + + @Override + public void submitFire(MatrixStack matrices, EntityRenderState renderState, org.joml.Quaternionf rotation) { + } + + @Override + public void submitLeash(MatrixStack matrices, EntityRenderState.LeashData leashData) { + } + + @Override + public void submitBlock(MatrixStack matrices, BlockState state, int light, int overlay, int outlineColor) { + } + + @Override + public void submitMovingBlock(MatrixStack matrices, MovingBlockRenderState state) { + } + + @Override + public void submitBlockStateModel(MatrixStack matrices, RenderLayer renderLayer, BlockStateModel model, float r, float g, float b, int light, + int overlay, int outlineColor) { + } + + @Override + public void submitItem(MatrixStack matrices, ItemDisplayContext displayContext, int light, int overlay, int outlineColors, int[] tintLayers, + List quads, RenderLayer renderLayer, ItemRenderState.Glint glintType) { + } + + @Override + public void submitCustom(MatrixStack matrices, RenderLayer renderLayer, OrderedRenderCommandQueue.Custom customRenderer) { + } + + @Override + public void submitCustom(OrderedRenderCommandQueue.LayeredCustom customRenderer) { + } + } +} diff --git a/src/main/java/org/bleachhack/util/render/WorldRenderer.java b/src/main/java/org/bleachhack/util/render/WorldRenderer.java index 1500b13526..7f673e9913 100644 --- a/src/main/java/org/bleachhack/util/render/WorldRenderer.java +++ b/src/main/java/org/bleachhack/util/render/WorldRenderer.java @@ -10,37 +10,26 @@ import net.minecraft.client.font.TextRenderer; import net.minecraft.util.math.RotationAxis; -import org.apache.commons.lang3.reflect.FieldUtils; - -import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.Camera; -import net.minecraft.client.render.DiffuseLighting; -import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.render.model.json.ModelTransformationMode; +import net.minecraft.client.util.BufferAllocator; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; -import org.joml.Vector3f; public class WorldRenderer { private static final MinecraftClient mc = MinecraftClient.getInstance(); - // A Pointer to RenderSystem.shaderLightDirections - private static final Vector3f[] shaderLight; - - static { - try { - shaderLight = (Vector3f[]) FieldUtils.getField(RenderSystem.class, "shaderLightDirections", true).get(null); - } catch (IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } + // Shared/reused like vanilla's Tessellator buffer (1.19.4 used Tessellator.getInstance().getBuffer() + // directly, which no longer exists in 1.21.11 - Tessellator's allocator is private now). Allocating a + // fresh BufferAllocator per drawText call instead would leak native memory every call since + // BufferAllocator is AutoCloseable and was never closed, which under sustained nametag rendering could + // eventually make allocations fail and drop text mid-session. + private static final BufferAllocator TEXT_BUFFER = new BufferAllocator(256); /** Draws text in the world. **/ public static void drawText(Text text, double x, double y, double z, double scale, boolean shadow) { @@ -55,15 +44,12 @@ public static void drawText(Text text, double x, double y, double z, double offX matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-camera.getYaw())); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - matrices.translate(offX, offY, 0); matrices.scale(-0.025f * (float) scale, -0.025f * (float) scale, 1); int halfWidth = mc.textRenderer.getWidth(text) / 2; - VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); + VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(TEXT_BUFFER); if (fill) { int opacity = (int) (MinecraftClient.getInstance().options.getTextBackgroundOpacity(0.25F) * 255.0F) << 24; @@ -77,44 +63,28 @@ public static void drawText(Text text, double x, double y, double z, double offX matrices.pop(); } - mc.textRenderer.draw(text, -halfWidth, 0f, -1, false, matrices.peek().getPositionMatrix(), immediate, TextRenderer.TextLayerType.NORMAL, 0, 0xf000f0); + // Vanilla's own entity nametags (LabelCommandRenderer) always draw a translucent SEE_THROUGH + // copy of the text - a RenderLayer variant that ignores the depth test - before the opaque + // NORMAL copy, so the label stays dimly visible behind terrain/foliage/other entities instead + // of disappearing outright. This only ever drew NORMAL, so any nametag whose world position + // happened to be behind so much as a leaf block or a fence post vanished completely instead of + // dimming, which is what looked like "some nametags just don't render". + mc.textRenderer.draw(text, -halfWidth, 0f, -2130706433, false, matrices.peek().getPositionMatrix(), immediate, TextRenderer.TextLayerType.SEE_THROUGH, 0, 0xf000f0); immediate.draw(); - RenderSystem.disableBlend(); + mc.textRenderer.draw(text, -halfWidth, 0f, -1, false, matrices.peek().getPositionMatrix(), immediate, TextRenderer.TextLayerType.NORMAL, 0, 0xf000f0); + immediate.draw(); } + // 1.21.11: item rendering moved to the same RenderState/OrderedRenderCommandQueue architecture as + // entities and block entities (see task #3/#4 notes) - ItemRenderState.render(...) and every + // HeldItemRenderer/ItemRenderer entry point require an OrderedRenderCommandQueue, which is only + // ever handed out by vanilla's own per-frame render dispatch, not obtainable standalone. There is + // no accessible way left to render an arbitrary ItemStack immediately outside that callback, so + // this floating 3D item icon can't be preserved - callers (Nametags/AutoSteal) keep their + // surrounding text (name/count) via drawText, just without the item icon itself. /** Draws a 2D gui items somewhere in the world. **/ public static void drawGuiItem(double x, double y, double z, double offX, double offY, double scale, ItemStack item) { - if (item.isEmpty()) { - return; - } - - MatrixStack matrices = matrixFrom(x, y, z); - - Camera camera = mc.gameRenderer.getCamera(); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-camera.getYaw())); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); - - matrices.translate(offX, offY, 0); - matrices.scale((float) scale, (float) scale, 0.001f); - - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180f)); - - mc.getBufferBuilders().getEntityVertexConsumers().draw(); - - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - - Vector3f[] currentLight = shaderLight.clone(); - DiffuseLighting.disableGuiDepthLighting(); - - mc.getItemRenderer().renderItem(item, ModelTransformationMode.GUI, 0xF000F0, - OverlayTexture.DEFAULT_UV, matrices, mc.getBufferBuilders().getEntityVertexConsumers(), mc.world, 0); - - mc.getBufferBuilders().getEntityVertexConsumers().draw(); - - RenderSystem.setShaderLights(currentLight[0], currentLight[1]); - RenderSystem.disableBlend(); } public static MatrixStack matrixFrom(double x, double y, double z) { @@ -124,7 +94,7 @@ public static MatrixStack matrixFrom(double x, double y, double z) { matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); - matrices.translate(x - camera.getPos().x, y - camera.getPos().y, z - camera.getPos().z); + matrices.translate(x - camera.getCameraPos().x, y - camera.getCameraPos().y, z - camera.getCameraPos().z); return matrices; } diff --git a/src/main/java/org/bleachhack/util/shader/BleachCoreShaders.java b/src/main/java/org/bleachhack/util/shader/BleachCoreShaders.java deleted file mode 100644 index 0ac9aa6b85..0000000000 --- a/src/main/java/org/bleachhack/util/shader/BleachCoreShaders.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bleachhack.util.shader; - -import java.io.IOException; - -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.util.Identifier; - -public class BleachCoreShaders { - - private static final ShaderProgram COLOR_OVERLAY_SHADER; - - public static ShaderProgram getColorOverlayShader() { - return COLOR_OVERLAY_SHADER; - } - - static { - try { - COLOR_OVERLAY_SHADER = ShaderLoader.load(VertexFormats.POSITION_COLOR_TEXTURE, new Identifier("bleachhack", "color_overlay")); - } catch (IOException e) { - throw new RuntimeException("Failed to initilize BleachHack core shaders", e); - } - } - -} diff --git a/src/main/java/org/bleachhack/util/shader/ColorVertexConsumerProvider.java b/src/main/java/org/bleachhack/util/shader/ColorVertexConsumerProvider.java deleted file mode 100644 index 00572ed2a8..0000000000 --- a/src/main/java/org/bleachhack/util/shader/ColorVertexConsumerProvider.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.bleachhack.util.shader; - -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.render.*; -import net.minecraft.client.render.RenderPhase.TextureBase; -import net.minecraft.util.Identifier; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Supplier; - -public class ColorVertexConsumerProvider { - - private final VertexConsumerProvider.Immediate plainDrawer = VertexConsumerProvider.immediate(new BufferBuilder(256)); - - private Supplier shader; - private Function layerCreator; - - public ColorVertexConsumerProvider(Framebuffer framebuffer, Supplier shader) { - this.shader = shader; - setFramebuffer(framebuffer); - } - - public VertexConsumerProvider createDualProvider(VertexConsumerProvider parent, int red, int green, int blue, int alpha) { - return layer -> { - VertexConsumer parentBuffer = parent.getBuffer(layer); - - if (!(layer instanceof RenderLayer.MultiPhase) - || ((RenderLayer.MultiPhase) layer).getPhases().outlineMode == RenderLayer.OutlineMode.NONE) { - return parentBuffer; - } - - VertexConsumer plainBuffer = this.plainDrawer.getBuffer( - layerCreator.apply(((RenderLayer.MultiPhase) layer).getPhases().texture)); - ColorVertexConsumer outlineVertexConsumer = new ColorVertexConsumer(plainBuffer, red, green, blue, alpha); - return VertexConsumers.union(outlineVertexConsumer, parentBuffer); - }; - } - - public VertexConsumerProvider createSingleProvider(VertexConsumerProvider parent, int red, int green, int blue, int alpha) { - return layer -> { - VertexConsumer parentBuffer = parent.getBuffer(layer); - - if (!(layer instanceof RenderLayer.MultiPhase) - || ((RenderLayer.MultiPhase) layer).getPhases().outlineMode == RenderLayer.OutlineMode.NONE) { - return parentBuffer; - } - - VertexConsumer plainBuffer = this.plainDrawer.getBuffer( - layerCreator.apply(((RenderLayer.MultiPhase) layer).getPhases().texture)); - return new ColorVertexConsumer(plainBuffer, red, green, blue, alpha); - }; - } - - public void setFramebuffer(Framebuffer framebuffer) { - layerCreator = memoizeTexture(texture -> new RenderLayer( - "bleachhack_outline", VertexFormats.POSITION_COLOR_TEXTURE, VertexFormat.DrawMode.QUADS, 256, false, false, - () -> { - texture.startDrawing(); - RenderSystem.setShader(shader); - framebuffer.beginWrite(false); - }, - () -> MinecraftClient.getInstance().getFramebuffer().beginWrite(false)) {}); - } - - private Function memoizeTexture(Function function) { - return new Function<>() { - private final Map cache = new HashMap<>(); - - public RenderLayer apply(TextureBase texture) { - return this.cache.computeIfAbsent(texture.getId().get(), id -> function.apply(texture)); - } - }; - } - - public void draw() { - this.plainDrawer.draw(); - } - - static class ColorVertexConsumer extends FixedColorVertexConsumer { - private final VertexConsumer delegate; // plainBuffer - private double x; - private double y; - private double z; - private float u; - private float v; - - ColorVertexConsumer(VertexConsumer vertexConsumer, int i, int j, int k, int l) { - this.delegate = vertexConsumer; - super.fixedColor(i, j, k, l); - } - - public void fixedColor(int red, int green, int blue, int alpha) { - } - - public void unfixColor() { - } - - public VertexConsumer vertex(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - return this; - } - - public VertexConsumer color(int red, int green, int blue, int alpha) { - return this; - } - - public VertexConsumer texture(float u, float v) { - this.u = u; - this.v = v; - return this; - } - - public VertexConsumer overlay(int u, int v) { - return this; - } - - public VertexConsumer light(int u, int v) { - return this; - } - - public VertexConsumer normal(float x, float y, float z) { - return this; - } - - public void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) { - this.delegate.vertex(x, y, z).color(this.fixedRed, this.fixedGreen, this.fixedBlue, this.fixedAlpha).texture(u, v).next(); - } - - public void next() { - this.delegate.vertex(this.x, this.y, this.z).color(this.fixedRed, this.fixedGreen, this.fixedBlue, this.fixedAlpha).texture(this.u, this.v).next(); - } - } -} diff --git a/src/main/java/org/bleachhack/util/shader/OpenResourceManager.java b/src/main/java/org/bleachhack/util/shader/OpenResourceManager.java deleted file mode 100644 index fe2f2e44b5..0000000000 --- a/src/main/java/org/bleachhack/util/shader/OpenResourceManager.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.bleachhack.util.shader; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.regex.Pattern; -import java.util.stream.Stream; - -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.resource.Resource; -import net.minecraft.resource.ResourceManager; -import net.minecraft.resource.ResourcePack; -import net.minecraft.util.Identifier; - -/** - * A open resource manager that can get resources from Fabric mods using their namespace - * or from a URL with the __url__ namespace and an encoded path. - * - * USE WITH CAUTION! - */ -public class OpenResourceManager implements ResourceManager { - - private static Pattern DECODE_PATTERN = Pattern.compile("_([0-9]+)_"); - - private ResourceManager parent; - - public OpenResourceManager(ResourceManager parent) { - this.parent = parent; - } - - public OpenResourceManager(ResourceManager parent, Function customResources) { - this.parent = parent; - } - - @Override - public Optional getResource(Identifier id) { - if ("minecraft".equals(id.getNamespace())) - return parent.getResource(id); - - if ("__url__".equals(id.getNamespace())) - return Optional.of(new Resource(MinecraftClient.getInstance().getDefaultResourcePack(), () -> parseURL(id.getPath()))); - - // Scuffed resource loader - Path path = FabricLoader.getInstance().getModContainer(id.getNamespace()).get().findPath("assets/" + id.getNamespace() + "/" + id.getPath()).get(); - return Optional.of(new Resource(MinecraftClient.getInstance().getDefaultResourcePack(), () -> Files.newInputStream(path))); - } - - @Override - public Set getAllNamespaces() { - return parent.getAllNamespaces(); - } - - @Override - public List getAllResources(Identifier id) { - return parent.getAllResources(id); - } - - @Override - public Map findResources(String startingPath, Predicate allowedPathPredicate) { - return parent.findResources(startingPath, allowedPathPredicate); - } - - @Override - public Stream streamResourcePacks() { - return parent.streamResourcePacks(); - } - - private InputStream parseURL(String path) throws IOException { - String decoded = DECODE_PATTERN.matcher(path).replaceAll(m -> Character.toString(Integer.parseInt(m.group(1)))); - return new URL(decoded).openStream(); - } - - @Override - public Map> findAllResources(String startingPath, - Predicate allowedPathPredicate) { - return null; - } - -} diff --git a/src/main/java/org/bleachhack/util/shader/ShaderEffectWrapper.java b/src/main/java/org/bleachhack/util/shader/ShaderEffectWrapper.java deleted file mode 100644 index ec9d543f2a..0000000000 --- a/src/main/java/org/bleachhack/util/shader/ShaderEffectWrapper.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.bleachhack.util.shader; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.gl.PostEffectProcessor; -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.BufferRenderer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; - -public class ShaderEffectWrapper { - - private static MinecraftClient mc = MinecraftClient.getInstance(); - - private PostEffectProcessor shader; - private int lastWidth = -1; - private int lastHeight = -1; - - public ShaderEffectWrapper(PostEffectProcessor effect) { - this.shader = effect; - } - - public void prepare() { - if (lastWidth != mc.getWindow().getFramebufferWidth() || lastHeight != mc.getWindow().getFramebufferHeight()) - resizeShader(); - } - - public void render() { - shader.render(mc.getTickDelta()); - mc.getFramebuffer().beginWrite(false); - } - - public Framebuffer getFramebuffer(String framebuffer) { - return shader.getSecondaryTarget(framebuffer); - } - - public void clearFramebuffer(String framebuffer) { - getFramebuffer(framebuffer).clear(MinecraftClient.IS_SYSTEM_MAC); - mc.getFramebuffer().beginWrite(false); - } - - public void drawFramebufferToMain(String framebuffer) { - Framebuffer buffer = getFramebuffer(framebuffer); - ShaderProgram blitshader = mc.gameRenderer.blitScreenProgram; - blitshader.addSampler("DiffuseSampler", buffer.getColorAttachment()); - - double w = mc.getWindow().getFramebufferWidth(); - double h = mc.getWindow().getFramebufferHeight(); - float ws = (float) buffer.viewportWidth / (float) buffer.textureWidth; - float hs = (float) buffer.viewportHeight / (float) buffer.textureHeight; - - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SrcFactor.ZERO, GlStateManager.DstFactor.ONE); - - GlStateManager._colorMask(true, true, true, false); - GlStateManager._disableDepthTest(); - GlStateManager._depthMask(false); - GlStateManager._viewport(0, 0, (int) w, (int) h); - - blitshader.bind(); - Tessellator tessellator = RenderSystem.renderThreadTesselator(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); - bufferBuilder.vertex(0, h, 0).texture(0f, 0f).color(255, 255, 255, 255).next(); - bufferBuilder.vertex(w, h, 0).texture(ws, 0f).color(255, 255, 255, 255).next(); - bufferBuilder.vertex(w, 0, 0).texture(ws, hs).color(255, 255, 255, 255).next(); - bufferBuilder.vertex(0, 0, 0).texture(0f, hs).color(255, 255, 255, 255).next(); - BufferRenderer.draw(bufferBuilder.end()); - blitshader.unbind(); - - GlStateManager._depthMask(true); - GlStateManager._colorMask(true, true, true, true); - - RenderSystem.disableBlend(); - } - - private void resizeShader() { - shader.setupDimensions(mc.getWindow().getFramebufferWidth(), mc.getWindow().getFramebufferHeight()); - lastWidth = mc.getWindow().getFramebufferWidth(); - lastHeight = mc.getWindow().getFramebufferHeight(); - } - - public PostEffectProcessor getShader() { - return shader; - } - - public void setShader(PostEffectProcessor shader) { - this.shader = shader; - } -} diff --git a/src/main/java/org/bleachhack/util/shader/ShaderLoader.java b/src/main/java/org/bleachhack/util/shader/ShaderLoader.java index a94d6e4a12..e61dc6fb30 100644 --- a/src/main/java/org/bleachhack/util/shader/ShaderLoader.java +++ b/src/main/java/org/bleachhack/util/shader/ShaderLoader.java @@ -1,30 +1,19 @@ package org.bleachhack.util.shader; -import java.io.IOException; -import com.google.gson.JsonSyntaxException; - import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; import net.minecraft.client.gl.PostEffectProcessor; -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.texture.TextureManager; -import net.minecraft.resource.ResourceManager; import net.minecraft.util.Identifier; -public class ShaderLoader { +import java.util.Set; - public static ShaderProgram load(VertexFormat format, Identifier id) throws IOException { - ResourceManager resMang = MinecraftClient.getInstance().getResourceManager(); - - return new ShaderProgram(new OpenResourceManager(resMang), id.toString(), format); - } +public class ShaderLoader { - public static PostEffectProcessor loadEffect(Framebuffer framebuffer, Identifier id) throws JsonSyntaxException, IOException { - ResourceManager resMang = MinecraftClient.getInstance().getResourceManager(); - TextureManager texMang = MinecraftClient.getInstance().getTextureManager(); - - return new PostEffectProcessor(texMang, new OpenResourceManager(resMang), framebuffer, id); + // 1.21.11: post effects are loaded (and compile-cached) through vanilla's own centralized + // MinecraftClient.getShaderLoader() instead of a raw `new PostEffectProcessor(...)` construction - + // mod-bundled assets//post_effect/*.json is found automatically since our mod jar is + // already a resource pack, so the old OpenResourceManager hack is no longer needed at all. + public static PostEffectProcessor loadEffect(Identifier id) { + return MinecraftClient.getInstance().getShaderLoader().loadPostEffect(id, Set.of()); } } diff --git a/src/main/java/org/bleachhack/util/world/ChunkProcessor.java b/src/main/java/org/bleachhack/util/world/ChunkProcessor.java index 93963171b5..ded0c73811 100644 --- a/src/main/java/org/bleachhack/util/world/ChunkProcessor.java +++ b/src/main/java/org/bleachhack/util/world/ChunkProcessor.java @@ -9,13 +9,10 @@ import org.bleachhack.eventbus.BleachSubscribe; import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; -import net.minecraft.nbt.NbtCompound; import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket; import net.minecraft.network.packet.s2c.play.ChunkDeltaUpdateS2CPacket; -import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket; import net.minecraft.network.packet.s2c.play.UnloadChunkS2CPacket; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; @@ -73,12 +70,10 @@ public void onReadPacket(EventPacket.Read event) { BlockUpdateS2CPacket packet = (BlockUpdateS2CPacket) event.getPacket(); executor.execute(() -> updateBlockConsumer.accept(packet.getPos(), packet.getState())); - } else if (updateBlockConsumer != null && event.getPacket() instanceof ExplosionS2CPacket) { - ExplosionS2CPacket packet = (ExplosionS2CPacket) event.getPacket(); - - for (BlockPos pos: packet.getAffectedBlocks()) { - executor.execute(() -> updateBlockConsumer.accept(pos, Blocks.AIR.getDefaultState())); - } + // 1.19.4 read ExplosionS2CPacket#getAffectedBlocks() to clear destroyed blocks immediately. That + // field was removed in 1.21.11 - ExplosionS2CPacket now only carries sound/particle data + // (see ClientPlayNetworkHandler#onExplosion), and the actual block removals arrive right after + // via BlockUpdateS2CPacket/ChunkDeltaUpdateS2CPacket, which are already handled below. } else if (updateBlockConsumer != null && event.getPacket() instanceof ChunkDeltaUpdateS2CPacket) { ChunkDeltaUpdateS2CPacket packet = (ChunkDeltaUpdateS2CPacket) event.getPacket(); @@ -89,15 +84,15 @@ public void onReadPacket(EventPacket.Read event) { } else if (loadChunkConsumer != null && event.getPacket() instanceof ChunkDataS2CPacket) { ChunkDataS2CPacket packet = (ChunkDataS2CPacket) event.getPacket(); - ChunkPos cp = new ChunkPos(packet.getX(), packet.getZ()); + ChunkPos cp = new ChunkPos(packet.getChunkX(), packet.getChunkZ()); WorldChunk chunk = new WorldChunk(MinecraftClient.getInstance().world, cp); - chunk.loadFromPacket(packet.getChunkData().getSectionsDataBuf(), new NbtCompound(), packet.getChunkData().getBlockEntities(packet.getX(), packet.getZ())); + chunk.loadFromPacket(packet.getChunkData().getSectionsDataBuf(), packet.getChunkData().getHeightmap(), packet.getChunkData().getBlockEntities(packet.getChunkX(), packet.getChunkZ())); executor.execute(() -> loadChunkConsumer.accept(cp, chunk)); } else if (unloadChunkConsumer != null && event.getPacket() instanceof UnloadChunkS2CPacket) { UnloadChunkS2CPacket packet = (UnloadChunkS2CPacket) event.getPacket(); - ChunkPos cp = new ChunkPos(packet.getX(), packet.getZ()); + ChunkPos cp = packet.pos(); WorldChunk chunk = MinecraftClient.getInstance().world.getChunk(cp.x, cp.z); executor.execute(() -> unloadChunkConsumer.accept(cp, chunk)); diff --git a/src/main/java/org/bleachhack/util/world/DamageUtils.java b/src/main/java/org/bleachhack/util/world/DamageUtils.java index 75e2d7b157..05fd7e5e75 100644 --- a/src/main/java/org/bleachhack/util/world/DamageUtils.java +++ b/src/main/java/org/bleachhack/util/world/DamageUtils.java @@ -9,50 +9,156 @@ package org.bleachhack.util.world; import net.minecraft.client.MinecraftClient; +import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.DamageUtil; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityGroup; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.EntityAttribute; import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.tag.DamageTypeTags; +import net.minecraft.registry.tag.EntityTypeTags; import net.minecraft.util.math.Box; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.Difficulty; -import net.minecraft.world.explosion.Explosion; +import net.minecraft.world.explosion.ExplosionImpl; public class DamageUtils { private static final MinecraftClient mc = MinecraftClient.getInstance(); + /** + * Resolves an {@link Enchantments} {@link RegistryKey} (data-driven registry entries as of 1.20.5+) to + * the {@link RegistryEntry} that {@link EnchantmentHelper#getLevel} now expects, using the client's + * dynamic registry manager (enchantments are synced to the client just like any other registry). + */ + private static RegistryEntry ench(RegistryKey key) { + return mc.world.getRegistryManager().getEntryOrThrow(key); + } + + /** + * Finds the first attribute modifier on {@code stack} (in {@code slot}) for the given attribute. + * Replaces the old {@code ItemStack.getAttributeModifiers(EquipmentSlot).get(attribute)} map lookup, + * which was removed in favor of a callback-based {@code applyAttributeModifiers}. + */ + private static double getBaseAttributeModifier(ItemStack stack, RegistryEntry attribute, EquipmentSlot slot) { + double[] holder = {Double.NaN}; + stack.applyAttributeModifiers(slot, (attr, modifier) -> { + if (Double.isNaN(holder[0]) && attr.matches(attribute)) { + holder[0] = modifier.value(); + } + }); + return Double.isNaN(holder[0]) ? 0 : holder[0]; + } + + /** + * ported: Sharpness/Smite/Bane of Arthropods attack-damage bonuses are data-driven "damage" effect + * components as of 1.20.5+ (see EnchantmentHelper#getDamage), evaluated against a LootContext that + * vanilla builds from a live ServerWorld (Enchantment#createEnchantedDamageLootContext requires + * ServerWorld). DamageUtils only has the client's ClientWorld available, so instead of driving that + * generic (and server-only) effect pipeline, this replicates the exact numbers vanilla ships in + * data/minecraft/enchantment/{sharpness,smite,bane_of_arthropods}.json: Sharpness applies + * unconditionally (base 1.0 + 0.5/level above first), Smite/Bane of Arthropods add 2.5/level but only + * if the target's EntityType is in the matching "sensitive_to_*" tag (the modern replacement for the + * old EntityGroup.UNDEAD/ARTHROPOD checks). + */ + private static float getEnchantAttackDamage(ItemStack stack, Entity target) { + float bonus = 0f; + + int sharpness = EnchantmentHelper.getLevel(ench(Enchantments.SHARPNESS), stack); + if (sharpness > 0) { + bonus += 1.0f + 0.5f * (sharpness - 1); + } + + int smite = EnchantmentHelper.getLevel(ench(Enchantments.SMITE), stack); + if (smite > 0 && target != null && target.getType().isIn(EntityTypeTags.SENSITIVE_TO_SMITE)) { + bonus += 2.5f + 2.5f * (smite - 1); + } + + int bane = EnchantmentHelper.getLevel(ench(Enchantments.BANE_OF_ARTHROPODS), stack); + if (bane > 0 && target != null && target.getType().isIn(EntityTypeTags.SENSITIVE_TO_BANE_OF_ARTHROPODS)) { + bonus += 2.5f + 2.5f * (bane - 1); + } + + return bonus; + } + + private static float sumArmorProtection(LivingEntity target, RegistryKey enchantment, float base, float perLevel) { + float total = 0f; + for (EquipmentSlot slot : EquipmentSlot.VALUES) { + if (!slot.isArmorSlot()) { + continue; + } + + int level = EnchantmentHelper.getLevel(ench(enchantment), target.getEquippedStack(slot)); + if (level > 0) { + total += base + perLevel * (level - 1); + } + } + + return total; + } + + /** + * ported: same reasoning as {@link #getEnchantAttackDamage}. EnchantmentHelper.getProtectionAmount is + * now (ServerWorld, LivingEntity, DamageSource) and needs a real ServerWorld internally, which isn't + * available client-side. Replicated directly from data/minecraft/enchantment/{protection, + * fire_protection,blast_protection,projectile_protection,feather_falling}.json: Protection applies + * to any damage (1.0 + 1.0/level above first) unless the source bypasses invulnerability; the other + * four are the same shape (2.0 or 3.0 base/per-level) gated on the matching DamageTypeTags entry + * (is_fire/is_explosion/is_projectile/is_fall) - the modern replacement for the old + * ProtectionEnchantment.Type checks. + */ + private static float getEnchantProtectionAmount(LivingEntity target, DamageSource source) { + if (source.isIn(DamageTypeTags.BYPASSES_INVULNERABILITY)) { + return 0f; + } + + float total = sumArmorProtection(target, Enchantments.PROTECTION, 1.0f, 1.0f); + + if (source.isIn(DamageTypeTags.IS_FIRE)) { + total += sumArmorProtection(target, Enchantments.FIRE_PROTECTION, 2.0f, 2.0f); + } + + if (source.isIn(DamageTypeTags.IS_EXPLOSION)) { + total += sumArmorProtection(target, Enchantments.BLAST_PROTECTION, 2.0f, 2.0f); + } + + if (source.isIn(DamageTypeTags.IS_PROJECTILE)) { + total += sumArmorProtection(target, Enchantments.PROJECTILE_PROTECTION, 2.0f, 2.0f); + } + + if (source.isIn(DamageTypeTags.IS_FALL)) { + total += sumArmorProtection(target, Enchantments.FEATHER_FALLING, 3.0f, 3.0f); + } + + return total; + } + public static float getItemAttackDamage(ItemStack stack) { - float damage = 1f - + (float) stack.getAttributeModifiers(EquipmentSlot.MAINHAND).get(EntityAttributes.GENERIC_ATTACK_DAMAGE) - .stream() - .mapToDouble(e -> e.getValue()) - .findFirst().orElse(0); + float damage = 1f + (float) getBaseAttributeModifier(stack, EntityAttributes.ATTACK_DAMAGE, EquipmentSlot.MAINHAND); - return damage + EnchantmentHelper.getAttackDamage(stack, EntityGroup.DEFAULT); + return damage + getEnchantAttackDamage(stack, null); } public static float getAttackDamage(PlayerEntity attacker, Entity target) { float cooldown = attacker.getAttackCooldownProgress(0.5F); - float damage = (float) attacker.getAttributeValue(EntityAttributes.GENERIC_ATTACK_DAMAGE) - + (float) attacker.getMainHandStack().getAttributeModifiers(EquipmentSlot.MAINHAND).get(EntityAttributes.GENERIC_ATTACK_DAMAGE) - .stream() - .mapToDouble(e -> e.getValue()) - .findFirst().orElse(0); + float damage = (float) attacker.getAttributeValue(EntityAttributes.ATTACK_DAMAGE) + + (float) getBaseAttributeModifier(attacker.getMainHandStack(), EntityAttributes.ATTACK_DAMAGE, EquipmentSlot.MAINHAND); damage *= 0.2f + cooldown * cooldown * 0.8f; - float enchDamage = EnchantmentHelper.getAttackDamage( - attacker.getMainHandStack(), target instanceof LivingEntity ? ((LivingEntity) target).getGroup() : EntityGroup.DEFAULT) * cooldown; + float enchDamage = getEnchantAttackDamage(attacker.getMainHandStack(), target) * cooldown; if (damage <= 0f && enchDamage <= 0f) { return 0f; @@ -75,9 +181,11 @@ public static float getAttackDamage(PlayerEntity attacker, Entity target) { if (target instanceof LivingEntity) { LivingEntity livingTarget = (LivingEntity) target; + DamageSource damageSource = mc.world.getDamageSources().playerAttack(attacker); + // Armor - damage = DamageUtil.getDamageLeft(damage, livingTarget.getArmor(), - (float) livingTarget.getAttributeValue(EntityAttributes.GENERIC_ARMOR_TOUGHNESS)); + damage = DamageUtil.getDamageLeft(livingTarget, damage, damageSource, livingTarget.getArmor(), + (float) livingTarget.getAttributeValue(EntityAttributes.ARMOR_TOUGHNESS)); // Enchantments if (livingTarget.hasStatusEffect(StatusEffects.RESISTANCE)) { @@ -85,15 +193,17 @@ public static float getAttackDamage(PlayerEntity attacker, Entity target) { float resistance_1 = damage * resistance; damage = Math.max(resistance_1 / 25f, 0f); } - } - if (damage <= 0f) { - damage = 0f; - } else { - int protAmount = EnchantmentHelper.getProtectionAmount(target.getArmorItems(), mc.world.getDamageSources().playerAttack(attacker)); - if (protAmount > 0) { - damage = DamageUtil.getInflictedDamage(damage, protAmount); + if (damage <= 0f) { + damage = 0f; + } else { + float protAmount = getEnchantProtectionAmount(livingTarget, damageSource); + if (protAmount > 0) { + damage = DamageUtil.getInflictedDamage(damage, protAmount); + } } + } else if (damage <= 0f) { + damage = 0f; } return damage; @@ -114,7 +224,16 @@ public static float getExplosionDamage(Vec3d explosionPos, float power, LivingEn return 0f; } - if (!target.isImmuneToExplosion() && !target.isInvulnerable()) { + // ported: Entity.isImmuneToExplosion() now takes an Explosion instance (Explosion#getWorld() + // requires a live ServerWorld, unavailable client-side, so a real Explosion can't be constructed + // here). Only WardenEntity (digging/emerging) and ArmorStandEntity (invisible, and only if the + // explosion "preserves decorative entities") override the base "false" - and WardenEntity's own + // isDiggingOrEmerging() is itself package-private, so it can't be read from here either. DamageUtils + // is only ever called against players/mobs in combat modules (CrystalAura/AutoLog), never wardens + // or armor stands, so this falls back to the base Entity behavior (never immune) unconditionally. + boolean immuneToExplosion = false; + + if (!immuneToExplosion && !target.isInvulnerable()) { double distExposure = Math.sqrt(target.squaredDistanceTo(explosionPos)) / maxDist; if (distExposure <= 1.0) { double xDiff = target.getX() - explosionPos.x; @@ -122,7 +241,7 @@ public static float getExplosionDamage(Vec3d explosionPos, float power, LivingEn double zDiff = target.getZ() - explosionPos.z; double diff = Math.sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff); if (diff != 0.0) { - double exposure = Explosion.getExposure(explosionPos, target); + double exposure = ExplosionImpl.calculateReceivedDamage(explosionPos, target); double finalExposure = (1.0 - distExposure) * exposure; float toDamage = (float) Math.floor((finalExposure * finalExposure + finalExposure) / 2.0 * 7.0 * maxDist + 1.0); @@ -135,9 +254,11 @@ public static float getExplosionDamage(Vec3d explosionPos, float power, LivingEn } } + DamageSource explosionSource = mc.world.getDamageSources().explosion(null, null); + // Armor - toDamage = DamageUtil.getDamageLeft(toDamage, target.getArmor(), - (float) target.getAttributeInstance(EntityAttributes.GENERIC_ARMOR_TOUGHNESS).getValue()); + toDamage = DamageUtil.getDamageLeft(target, toDamage, explosionSource, target.getArmor(), + (float) target.getAttributeInstance(EntityAttributes.ARMOR_TOUGHNESS).getValue()); // Enchantments if (target.hasStatusEffect(StatusEffects.RESISTANCE)) { @@ -149,7 +270,7 @@ public static float getExplosionDamage(Vec3d explosionPos, float power, LivingEn if (toDamage <= 0f) { toDamage = 0f; } else { - int protAmount = EnchantmentHelper.getProtectionAmount(target.getArmorItems(), mc.world.getDamageSources().explosion(null, null)); + float protAmount = getEnchantProtectionAmount(target, explosionSource); if (protAmount > 0) { toDamage = DamageUtil.getInflictedDamage(toDamage, protAmount); } @@ -182,7 +303,7 @@ public static boolean willPop(LivingEntity target, float damage) { public static boolean willPopOrKill(LivingEntity target, float damage) { return damage >= target.getHealth() + target.getAbsorptionAmount(); } - + public static boolean willGoBelowHealth(LivingEntity target, float damage, float minHealth) { return target.getHealth() + target.getAbsorptionAmount() - damage < minHealth; } diff --git a/src/main/java/org/bleachhack/util/world/PlayerCopyEntity.java b/src/main/java/org/bleachhack/util/world/PlayerCopyEntity.java index eea6f81321..7a0f0f8fa9 100644 --- a/src/main/java/org/bleachhack/util/world/PlayerCopyEntity.java +++ b/src/main/java/org/bleachhack/util/world/PlayerCopyEntity.java @@ -34,13 +34,13 @@ public PlayerCopyEntity(PlayerEntity player, double x, double y, double z) { // Cache the player textures, then switch to a random uuid // because the world doesn't allow duplicate uuids in 1.17+ getPlayerListEntry(); - dataTracker.set(PLAYER_MODEL_PARTS, player.getDataTracker().get(PLAYER_MODEL_PARTS)); + dataTracker.set(PLAYER_MODE_CUSTOMIZATION_ID, player.getDataTracker().get(PLAYER_MODE_CUSTOMIZATION_ID)); setUuid(UUID.randomUUID()); } public void spawn() { unsetRemoved(); - MinecraftClient.getInstance().world.addEntity(this.getId(), this); + MinecraftClient.getInstance().world.addEntity(this); } public void despawn() { diff --git a/src/main/java/org/bleachhack/util/world/ProjectileSimulator.java b/src/main/java/org/bleachhack/util/world/ProjectileSimulator.java index 1be1e54f2f..a2b0f0b65e 100644 --- a/src/main/java/org/bleachhack/util/world/ProjectileSimulator.java +++ b/src/main/java/org/bleachhack/util/world/ProjectileSimulator.java @@ -15,8 +15,10 @@ import net.minecraft.entity.projectile.ArrowEntity; import net.minecraft.entity.projectile.TridentEntity; import net.minecraft.entity.projectile.thrown.ExperienceBottleEntity; +import net.minecraft.entity.projectile.thrown.LingeringPotionEntity; import net.minecraft.entity.projectile.thrown.PotionEntity; import net.minecraft.entity.projectile.thrown.SnowballEntity; +import net.minecraft.entity.projectile.thrown.SplashPotionEntity; import net.minecraft.entity.projectile.thrown.ThrownEntity; import net.minecraft.item.*; import net.minecraft.predicate.entity.EntityPredicates; @@ -37,10 +39,10 @@ public class ProjectileSimulator { private static MinecraftClient mc = MinecraftClient.getInstance(); public static Entity summonProjectile(PlayerEntity thrower, boolean allowThrowables, boolean allowXp, boolean allowPotions) { - ItemStack hand = (isThrowable(thrower.getInventory().getMainHandStack().getItem(), allowThrowables, allowXp, allowPotions) - ? thrower.getInventory().getMainHandStack() - : isThrowable(thrower.getInventory().offHand.get(0).getItem(), allowThrowables, allowXp, allowPotions) - ? thrower.getInventory().offHand.get(0) + ItemStack hand = (isThrowable(thrower.getMainHandStack().getItem(), allowThrowables, allowXp, allowPotions) + ? thrower.getMainHandStack() + : isThrowable(thrower.getOffHandStack().getItem(), allowThrowables, allowXp, allowPotions) + ? thrower.getOffHandStack() : null); if (hand == null) { @@ -52,20 +54,26 @@ public static Entity summonProjectile(PlayerEntity thrower, boolean allowThrowab : hand.getItem() == Items.CROSSBOW ? 0f : BowItem.getPullProgress(thrower.getItemUseTime()); if (charged > 0f) { - Entity e = new ArrowEntity(mc.world, mc.player); + ItemStack arrowStack = thrower.getProjectileType(hand); + if (arrowStack.isEmpty()) { + arrowStack = new ItemStack(Items.ARROW); + } + Entity e = new ArrowEntity(mc.world, thrower, arrowStack, hand); initProjectile(e, thrower, 0f, charged * 3); return e; } } else if (hand.getItem() instanceof SnowballItem || hand.getItem() instanceof EggItem || hand.getItem() instanceof EnderPearlItem) { - Entity e = new SnowballEntity(mc.world, mc.player); + Entity e = new SnowballEntity(mc.world, thrower, hand); initProjectile(e, thrower, 0f, 1.5f); return e; } else if (hand.getItem() instanceof ExperienceBottleItem) { - Entity e = new ExperienceBottleEntity(mc.world, mc.player); + Entity e = new ExperienceBottleEntity(mc.world, thrower, hand); initProjectile(e, thrower, -20f, 0.7f); return e; } else if (hand.getItem() instanceof ThrowablePotionItem) { - Entity e = new PotionEntity(mc.world, mc.player); + Entity e = hand.getItem() instanceof LingeringPotionItem + ? new LingeringPotionEntity(mc.world, thrower, hand) + : new SplashPotionEntity(mc.world, thrower, hand); initProjectile(e, thrower, -20f, 0.5f); return e; } else if (hand.getItem() instanceof TridentItem) { @@ -98,8 +106,8 @@ private static void initProjectile(Entity e, Entity thrower, float addPitch, flo float float_3 = MathHelper.sqrt((float) velVec.horizontalLengthSquared()); e.setYaw((float) (MathHelper.atan2(velVec.x, velVec.z) * 57.2957763671875)); e.setPitch((float) (MathHelper.atan2(velVec.y, float_3) * 57.2957763671875)); - e.prevYaw = e.getYaw(); - e.prevPitch = e.getPitch(); + e.lastYaw = e.getYaw(); + e.lastPitch = e.getPitch(); e.setVelocity(velVec.add(thrower.getVelocity().x, thrower.isOnGround() ? 0.0D : thrower.getVelocity().y, thrower.getVelocity().z)); } diff --git a/src/main/java/org/bleachhack/util/world/WorldUtils.java b/src/main/java/org/bleachhack/util/world/WorldUtils.java index 32500b217c..629501c41b 100644 --- a/src/main/java/org/bleachhack/util/world/WorldUtils.java +++ b/src/main/java/org/bleachhack/util/world/WorldUtils.java @@ -26,11 +26,11 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; -import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; -import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket.Mode; +import net.minecraft.network.packet.c2s.play.PlayerInputC2SPacket; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; import net.minecraft.util.Hand; +import net.minecraft.util.PlayerInput; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; @@ -41,6 +41,7 @@ import net.minecraft.util.math.Direction.Axis; import net.minecraft.world.Heightmap; import net.minecraft.world.RaycastContext; +import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.WorldChunk; public class WorldUtils { @@ -136,6 +137,68 @@ public static boolean doesBoxCollide(Box box) { return false; } + // Shared by the packet-teleport combat modules (Mace Kill, Spear Kill, Infinite Reach, + // Projectile Launcher) - a candidate landing spot is unsafe if it's in an unloaded chunk, would + // put the entity's hitbox in lava/collision, or would put it inside another entity. + public static boolean isTeleportUnsafe(Entity entity, Vec3d pos) { + BlockPos blockPos = BlockPos.ofFloored(pos); + if (mc.world == null || mc.world.getChunk(blockPos.getX() >> 4, blockPos.getZ() >> 4, ChunkStatus.FULL, false) == null) { + return true; + } + + Box box = entity.getBoundingBox().offset(pos.subtract(entity.getEntityPos())); + + for (int x = (int) Math.floor(box.minX); x < Math.ceil(box.maxX); x++) { + for (int y = (int) Math.floor(box.minY); y < Math.ceil(box.maxY); y++) { + for (int z = (int) Math.floor(box.minZ); z < Math.ceil(box.maxZ); z++) { + if (mc.world.getBlockState(new BlockPos(x, y, z)).isOf(Blocks.LAVA)) { + return true; + } + } + } + } + + if (doesBoxCollide(box)) { + return true; + } + + for (Entity e : mc.world.getOtherEntities(entity, box)) { + if (e.isCollidable(entity)) { + return true; + } + } + + return false; + } + + // Randomized small nudge away from a landing spot (breaks up an otherwise identical repeated + // teleport pattern), falling back to a vertical-only nudge or the exact position if every + // horizontal direction happens to be blocked. + public static Vec3d findSafeOffset(Entity entity, Vec3d base, double horizontal, double vertical) { + List offsets = new ArrayList<>(List.of( + base.add(horizontal, vertical, 0), base.add(-horizontal, vertical, 0), + base.add(0, vertical, horizontal), base.add(0, vertical, -horizontal), + base.add(horizontal, vertical, horizontal), base.add(-horizontal, vertical, -horizontal), + base.add(-horizontal, vertical, horizontal), base.add(horizontal, vertical, -horizontal))); + java.util.Collections.shuffle(offsets); + + for (Vec3d offset : offsets) { + if (!isTeleportUnsafe(entity, offset)) { + return offset; + } + } + + Vec3d verticalOnly = base.add(0, vertical, 0); + return !isTeleportUnsafe(entity, verticalOnly) ? verticalOnly : base; + } + + // Sends a bare position update - used by the packet-teleport modules to claim a new position + // server-side for a single tick without going through normal movement/collision. + public static void sendTeleport(Vec3d pos) { + mc.player.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + pos.x, pos.y, pos.z, false, mc.player.horizontalCollision)); + } + public static boolean placeBlock(BlockPos pos, int slot, SettingRotate sr, boolean forceLegit, boolean airPlace, boolean swingHand) { return placeBlock(pos, slot, !sr.getState() ? 0 : sr.getRotateMode() + 1, forceLegit, airPlace, swingHand); } @@ -150,7 +213,7 @@ public static boolean placeBlock(BlockPos pos, int slot, int rotateMode, boolean Block neighborBlock = mc.world.getBlockState(pos.offset(d)).getBlock(); - if (!airPlace && neighborBlock.getDefaultState().getMaterial().isReplaceable()) + if (!airPlace && neighborBlock.getDefaultState().isReplaceable()) continue; Vec3d vec = getLegitLookPos(pos.offset(d), d.getOpposite(), true, 5); @@ -167,7 +230,7 @@ public static boolean placeBlock(BlockPos pos, int slot, int rotateMode, boolean } } - int prevSlot = mc.player.getInventory().selectedSlot; + int prevSlot = mc.player.getInventory().getSelectedSlot(); Hand hand = InventoryUtils.selectSlot(slot); if (hand == null) { @@ -181,7 +244,7 @@ public static boolean placeBlock(BlockPos pos, int slot, int rotateMode, boolean } if (RIGHTCLICKABLE_BLOCKS.contains(neighborBlock)) { - mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, Mode.PRESS_SHIFT_KEY)); + mc.player.networkHandler.sendPacket(new PlayerInputC2SPacket(new PlayerInput(false, false, false, false, false, true, false))); } if (swingHand) { @@ -194,9 +257,9 @@ public static boolean placeBlock(BlockPos pos, int slot, int rotateMode, boolean new BlockHitResult(Vec3d.ofCenter(pos), airPlace ? d : d.getOpposite(), airPlace ? pos : pos.offset(d), false)); if (RIGHTCLICKABLE_BLOCKS.contains(neighborBlock)) - mc.player.networkHandler.sendPacket(new ClientCommandC2SPacket(mc.player, Mode.RELEASE_SHIFT_KEY)); + mc.player.networkHandler.sendPacket(new PlayerInputC2SPacket(PlayerInput.DEFAULT)); - mc.player.getInventory().selectedSlot = prevSlot; + mc.player.getInventory().setSelectedSlot(prevSlot); return true; } @@ -211,16 +274,16 @@ public static Vec3d getLegitLookPos(BlockPos pos, Direction dir, boolean raycast public static Vec3d getLegitLookPos(Box box, Direction dir, boolean raycast, int res, double extrude) { Vec3d eyePos = mc.player.getEyePos(); Vec3d blockPos = new Vec3d(box.minX, box.minY, box.minZ).add( - (dir == Direction.WEST ? -extrude : dir.getOffsetX() * box.getXLength() + extrude), - (dir == Direction.DOWN ? -extrude : dir.getOffsetY() * box.getYLength() + extrude), - (dir == Direction.NORTH ? -extrude : dir.getOffsetZ() * box.getZLength() + extrude)); + (dir == Direction.WEST ? -extrude : dir.getOffsetX() * box.getLengthX() + extrude), + (dir == Direction.DOWN ? -extrude : dir.getOffsetY() * box.getLengthY() + extrude), + (dir == Direction.NORTH ? -extrude : dir.getOffsetZ() * box.getLengthZ() + extrude)); for (double i = 0; i <= 1; i += 1d / (double) res) { for (double j = 0; j <= 1; j += 1d / (double) res) { Vec3d lookPos = blockPos.add( - (dir.getAxis() == Axis.X ? 0 : i * box.getXLength()), - (dir.getAxis() == Axis.Y ? 0 : dir.getAxis() == Axis.Z ? j * box.getYLength() : i * box.getYLength()), - (dir.getAxis() == Axis.Z ? 0 : j * box.getZLength())); + (dir.getAxis() == Axis.X ? 0 : i * box.getLengthX()), + (dir.getAxis() == Axis.Y ? 0 : dir.getAxis() == Axis.Z ? j * box.getLengthY() : i * box.getLengthY()), + (dir.getAxis() == Axis.Z ? 0 : j * box.getLengthZ())); if (eyePos.distanceTo(lookPos) > 4.55) continue; @@ -240,7 +303,7 @@ public static Vec3d getLegitLookPos(Box box, Direction dir, boolean raycast, int } public static boolean isBlockEmpty(BlockPos pos) { - if (!mc.world.getBlockState(pos).getMaterial().isReplaceable()) { + if (!mc.world.getBlockState(pos).isReplaceable()) { return false; } @@ -281,7 +344,7 @@ public static void facePosPacket(double x, double y, double z) { mc.player.networkHandler.sendPacket( new PlayerMoveC2SPacket.LookAndOnGround( mc.player.getYaw() + MathHelper.wrapDegrees(rot[0] - mc.player.getYaw()), - mc.player.getPitch() + MathHelper.wrapDegrees(rot[1] - mc.player.getPitch()), mc.player.isOnGround())); + mc.player.getPitch() + MathHelper.wrapDegrees(rot[1] - mc.player.getPitch()), mc.player.isOnGround(), mc.player.horizontalCollision)); } public static float[] getViewingRotation(Entity entity, double x, double y, double z) { diff --git a/src/main/resources/assets/bleachhack/post_effect/antialias.json b/src/main/resources/assets/bleachhack/post_effect/antialias.json new file mode 100644 index 0000000000..c595b2e36c --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/antialias.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/antialias", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/bits.json b/src/main/resources/assets/bleachhack/post_effect/bits.json new file mode 100644 index 0000000000..16f980b896 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/bits.json @@ -0,0 +1,52 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/bits", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap", + "uniforms": { + "BitsConfig": [ + { + "name": "Resolution", + "type": "float", + "value": 4.0 + }, + { + "name": "MosaicSize", + "type": "float", + "value": 8.0 + } + ] + } + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/blobs.json b/src/main/resources/assets/bleachhack/post_effect/blobs.json new file mode 100644 index 0000000000..b73aa0d4a4 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/blobs.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/blobs", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/blobs2.json b/src/main/resources/assets/bleachhack/post_effect/blobs2.json new file mode 100644 index 0000000000..a5032b4a2f --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/blobs2.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/blobs2", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/blur.json b/src/main/resources/assets/bleachhack/post_effect/blur.json new file mode 100644 index 0000000000..176fcee98d --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/blur.json @@ -0,0 +1,162 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/box_blur", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main", + "bilinear": true + } + ], + "output": "swap", + "uniforms": { + "BlurConfig": [ + { + "name": "BlurDir", + "type": "vec2", + "value": [ 1.0, 0.0 ] + }, + { + "name": "Radius", + "type": "float", + "value": 0.0 + } + ] + } + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/box_blur", + "inputs": [ + { + "sampler_name": "In", + "target": "swap", + "bilinear": true + } + ], + "output": "minecraft:main", + "uniforms": { + "BlurConfig": [ + { + "name": "BlurDir", + "type": "vec2", + "value": [ 0.0, 1.0 ] + }, + { + "name": "Radius", + "type": "float", + "value": 0.0 + } + ] + } + }, { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/box_blur", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main", + "bilinear": true + } + ], + "output": "swap", + "uniforms": { + "BlurConfig": [ + { + "name": "BlurDir", + "type": "vec2", + "value": [ 1.0, 0.0 ] + }, + { + "name": "Radius", + "type": "float", + "value": 0.0 + } + ] + } + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/box_blur", + "inputs": [ + { + "sampler_name": "In", + "target": "swap", + "bilinear": true + } + ], + "output": "minecraft:main", + "uniforms": { + "BlurConfig": [ + { + "name": "BlurDir", + "type": "vec2", + "value": [ 0.0, 1.0 ] + }, + { + "name": "Radius", + "type": "float", + "value": 0.0 + } + ] + } + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/box_blur", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main", + "bilinear": true + } + ], + "output": "swap", + "uniforms": { + "BlurConfig": [ + { + "name": "BlurDir", + "type": "vec2", + "value": [ 1.0, 0.0 ] + }, + { + "name": "Radius", + "type": "float", + "value": 0.0 + } + ] + } + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/box_blur", + "inputs": [ + { + "sampler_name": "In", + "target": "swap", + "bilinear": true + } + ], + "output": "minecraft:main", + "uniforms": { + "BlurConfig": [ + { + "name": "BlurDir", + "type": "vec2", + "value": [ 0.0, 1.0 ] + }, + { + "name": "Radius", + "type": "float", + "value": 0.0 + } + ] + } + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/bumpy.json b/src/main/resources/assets/bleachhack/post_effect/bumpy.json new file mode 100644 index 0000000000..4b68d530bc --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/bumpy.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/bumpy", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/deconverge.json b/src/main/resources/assets/bleachhack/post_effect/deconverge.json new file mode 100644 index 0000000000..29b62b1166 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/deconverge.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/deconverge", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/desaturate.json b/src/main/resources/assets/bleachhack/post_effect/desaturate.json new file mode 100644 index 0000000000..35a9e5a1b3 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/desaturate.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/desaturate", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/esp_outline.json b/src/main/resources/assets/bleachhack/post_effect/esp_outline.json new file mode 100644 index 0000000000..7a492ad9fc --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/esp_outline.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/entity_outline_meteor", + "inputs": [ + { + "sampler_name": "In", + "target": "bleachhack:esp_outline" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "bleachhack:esp_outline" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/fxaa.json b/src/main/resources/assets/bleachhack/post_effect/fxaa.json new file mode 100644 index 0000000000..020dcc47a8 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/fxaa.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/fxaa", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/green.json b/src/main/resources/assets/bleachhack/post_effect/green.json new file mode 100644 index 0000000000..d6cb91a0ec --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/green.json @@ -0,0 +1,74 @@ +{ + "targets": { + "swap": {}, + "swap2": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/color_convolve", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap", + "uniforms": { + "ColorConfig": [ + { + "name": "RedMatrix", + "type": "vec3", + "value": [ 0.0, 0.0, 0.0 ] + }, + { + "name": "GreenMatrix", + "type": "vec3", + "value": [ 0.3, 0.59, 0.11 ] + }, + { + "name": "BlueMatrix", + "type": "vec3", + "value": [ 0.0, 0.0, 0.0 ] + } + ] + } + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/bits", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "output": "swap2", + "uniforms": { + "BitsConfig": [ + { + "name": "Resolution", + "type": "float", + "value": 4.0 + }, + { + "name": "MosaicSize", + "type": "float", + "value": 8.0 + } + ] + } + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/scan_pincushion", + "inputs": [ + { + "sampler_name": "In", + "target": "swap2" + } + ], + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/notch.json b/src/main/resources/assets/bleachhack/post_effect/notch.json new file mode 100644 index 0000000000..b4d016fa7a --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/notch.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/notch", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/pencil.json b/src/main/resources/assets/bleachhack/post_effect/pencil.json new file mode 100644 index 0000000000..ee8170e178 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/pencil.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/outline_soft", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/scanline.json b/src/main/resources/assets/bleachhack/post_effect/scanline.json new file mode 100644 index 0000000000..6e44050263 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/scanline.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/scan_pincushion", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/sobel.json b/src/main/resources/assets/bleachhack/post_effect/sobel.json new file mode 100644 index 0000000000..73b0f3383e --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/sobel.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/sobel", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/post_effect/vibrant.json b/src/main/resources/assets/bleachhack/post_effect/vibrant.json new file mode 100644 index 0000000000..2e3a828437 --- /dev/null +++ b/src/main/resources/assets/bleachhack/post_effect/vibrant.json @@ -0,0 +1,38 @@ +{ + "targets": { + "swap": {} + }, + "passes": [ + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "bleachhack:post/vibrant", + "inputs": [ + { + "sampler_name": "In", + "target": "minecraft:main" + } + ], + "output": "swap" + }, + { + "vertex_shader": "minecraft:core/screenquad", + "fragment_shader": "minecraft:post/blit", + "inputs": [ + { + "sampler_name": "In", + "target": "swap" + } + ], + "uniforms": { + "BlitConfig": [ + { + "name": "ColorModulate", + "type": "vec4", + "value": [ 1.0, 1.0, 1.0, 1.0 ] + } + ] + }, + "output": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/bleachhack/shaders/core/color_overlay.fsh b/src/main/resources/assets/bleachhack/shaders/core/color_overlay.fsh deleted file mode 100644 index f0a0f990de..0000000000 --- a/src/main/resources/assets/bleachhack/shaders/core/color_overlay.fsh +++ /dev/null @@ -1,19 +0,0 @@ -#version 150 - -uniform sampler2D Sampler0; - -uniform vec4 ColorModulator; - -in vec4 vertexColor; -in vec2 texCoord0; - -out vec4 fragColor; - -void main() { - vec4 color = texture(Sampler0, texCoord0); - if (color.a == 0.0) { - discard; - } - - fragColor = vertexColor; -} diff --git a/src/main/resources/assets/bleachhack/shaders/core/color_overlay.json b/src/main/resources/assets/bleachhack/shaders/core/color_overlay.json deleted file mode 100644 index 7e1812ff16..0000000000 --- a/src/main/resources/assets/bleachhack/shaders/core/color_overlay.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "blend": { - "func": "add", - "srcrgb": "srcalpha", - "dstrgb": "1-srcalpha" - }, - "vertex": "bleachhack:color_overlay", - "fragment": "bleachhack:color_overlay", - "attributes": [ - "Position", - "Color", - "UV0" - ], - "samplers": [ - { "name": "Sampler0" } - ], - "uniforms": [ - { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] } - ] -} diff --git a/src/main/resources/assets/bleachhack/shaders/core/color_overlay.vsh b/src/main/resources/assets/bleachhack/shaders/core/color_overlay.vsh deleted file mode 100644 index 44e105d4c2..0000000000 --- a/src/main/resources/assets/bleachhack/shaders/core/color_overlay.vsh +++ /dev/null @@ -1,18 +0,0 @@ -#version 150 - -in vec3 Position; -in vec4 Color; -in vec2 UV0; - -uniform mat4 ModelViewMat; -uniform mat4 ProjMat; - -out vec4 vertexColor; -out vec2 texCoord0; - -void main() { - gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); - - vertexColor = Color; - texCoord0 = UV0; -} diff --git a/src/main/resources/assets/bleachhack/shaders/post/antialias.fsh b/src/main/resources/assets/bleachhack/shaders/post/antialias.fsh new file mode 100644 index 0000000000..02865aa63f --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/antialias.fsh @@ -0,0 +1,39 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/antialias.fsh (Mojang). + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +void main() { + vec2 oneTexel = 1.0 / InSize; + + vec4 c = texture(InSampler, texCoord); + vec4 u1 = texture(InSampler, texCoord + vec2( 0.0, -oneTexel.y )); + vec4 u2 = texture(InSampler, texCoord + vec2( 0.0, -oneTexel.y * 2.0)); + vec4 d1 = texture(InSampler, texCoord + vec2( 0.0, oneTexel.y )); + vec4 d2 = texture(InSampler, texCoord + vec2( 0.0, oneTexel.y * 2.0)); + vec4 l1 = texture(InSampler, texCoord + vec2(-oneTexel.x, 0.0)); + vec4 l2 = texture(InSampler, texCoord + vec2(-oneTexel.x * 2.0, 0.0)); + vec4 r1 = texture(InSampler, texCoord + vec2( oneTexel.x, 0.0)); + vec4 r2 = texture(InSampler, texCoord + vec2( oneTexel.x * 2.0, 0.0)); + + vec4 v1 = mix(c, mix(l1, l2, 0.667), 0.75); + vec4 v2 = mix(c, mix(r1, r2, 0.667), 0.75); + vec4 v3 = mix(c, mix(u1, u2, 0.667), 0.75); + vec4 v4 = mix(c, mix(d1, d2, 0.667), 0.75); + + vec4 v5 = mix(v1, v2, 0.5); + vec4 v6 = mix(v3, v4, 0.5); + + vec4 color = mix(v5, v6, 0.5); + fragColor = vec4(color.rgb, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/blobs.fsh b/src/main/resources/assets/bleachhack/shaders/post/blobs.fsh new file mode 100644 index 0000000000..f9ed624526 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/blobs.fsh @@ -0,0 +1,53 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/blobs.fsh (Mojang). + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +void main() { + vec2 oneTexel = 1.0 / InSize; + + vec4 u = texture(InSampler, texCoord + vec2( 0.0, -oneTexel.y)); + vec4 d = texture(InSampler, texCoord + vec2( 0.0, oneTexel.y)); + vec4 l = texture(InSampler, texCoord + vec2(-oneTexel.x, 0.0)); + vec4 r = texture(InSampler, texCoord + vec2( oneTexel.x, 0.0)); + + vec4 v1 = min(l, r); + vec4 v2 = min(u, d); + vec4 v3 = min(v1, v2); + + vec4 ul = texture(InSampler, texCoord + vec2(-oneTexel.x, -oneTexel.y)); + vec4 dr = texture(InSampler, texCoord + vec2( oneTexel.x, oneTexel.y)); + vec4 dl = texture(InSampler, texCoord + vec2(-oneTexel.x, oneTexel.y)); + vec4 ur = texture(InSampler, texCoord + vec2( oneTexel.x, -oneTexel.y)); + + vec4 v4 = min(ul, dr); + vec4 v5 = min(ur, dl); + vec4 v6 = min(v4, v5); + + vec4 v7 = min(v3, v6); + + vec4 uu = texture(InSampler, texCoord + vec2( 0.0, -oneTexel.y * 2.0)); + vec4 dd = texture(InSampler, texCoord + vec2( 0.0, oneTexel.y * 2.0)); + vec4 ll = texture(InSampler, texCoord + vec2(-oneTexel.x * 2.0, 0.0)); + vec4 rr = texture(InSampler, texCoord + vec2( oneTexel.x * 2.0, 0.0)); + + vec4 v8 = min(uu, dd); + vec4 v9 = min(ll, rr); + vec4 v10 = min(v8, v9); + + vec4 v11 = min(v7, v10); + + vec4 c = texture(InSampler, texCoord); + vec4 color = min(c, v11); + fragColor = vec4(color.rgb, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/blobs2.fsh b/src/main/resources/assets/bleachhack/shaders/post/blobs2.fsh new file mode 100644 index 0000000000..e111c501c9 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/blobs2.fsh @@ -0,0 +1,42 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/blobs2.fsh (Mojang). Radius was a live uniform +// there; baked as a const here since 1.21.11 post-effect uniforms are read once at load, not +// per-frame (see entity_outline_meteor.fsh for the same tradeoff). + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +const float Radius = 7.0; + +void main() { + vec2 oneTexel = 1.0 / InSize; + + vec4 c = texture(InSampler, texCoord); + vec4 maxVal = c; + for (float u = 0.0; u <= Radius; u += 1.0) { + for (float v = 0.0; v <= Radius; v += 1.0) { + float weight = (((sqrt(u * u + v * v) / Radius) > 1.0) ? 0.0 : 1.0); + + vec4 s0 = texture(InSampler, texCoord + vec2(-u * oneTexel.x, -v * oneTexel.y)); + vec4 s1 = texture(InSampler, texCoord + vec2( u * oneTexel.x, v * oneTexel.y)); + vec4 s2 = texture(InSampler, texCoord + vec2(-u * oneTexel.x, v * oneTexel.y)); + vec4 s3 = texture(InSampler, texCoord + vec2( u * oneTexel.x, -v * oneTexel.y)); + + vec4 o0 = max(s0, s1); + vec4 o1 = max(s2, s3); + vec4 tempMax = max(o0, o1); + maxVal = mix(maxVal, max(maxVal, tempMax), weight); + } + } + + fragColor = vec4(maxVal.rgb, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/bumpy.fsh b/src/main/resources/assets/bleachhack/shaders/post/bumpy.fsh new file mode 100644 index 0000000000..adb5efd448 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/bumpy.fsh @@ -0,0 +1,45 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/bumpy.fsh (Mojang) - same effect, updated to +// 1.21.11's uniform-block/InSampler conventions since the old sampler/uniform names no longer exist. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +void main() { + vec2 oneTexel = 1.0 / InSize; + + vec4 c = texture(InSampler, texCoord); + vec4 u = texture(InSampler, texCoord + vec2( 0.0, -oneTexel.y)); + vec4 d = texture(InSampler, texCoord + vec2( 0.0, oneTexel.y)); + vec4 l = texture(InSampler, texCoord + vec2(-oneTexel.x, 0.0)); + vec4 r = texture(InSampler, texCoord + vec2( oneTexel.x, 0.0)); + + vec4 nc = normalize(c); + vec4 nu = normalize(u); + vec4 nd = normalize(d); + vec4 nl = normalize(l); + vec4 nr = normalize(r); + + float du = dot(nc, nu); + float dd = dot(nc, nd); + float dl = dot(nc, nl); + float dr = dot(nc, nr); + + float i = 64.0; + + float f = 1.0; + f += (du * i) - (dd * i); + f += (dr * i) - (dl * i); + + vec4 color = c * clamp(f, 0.5, 2.0); + fragColor = vec4(color.rgb, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/deconverge.fsh b/src/main/resources/assets/bleachhack/shaders/post/deconverge.fsh new file mode 100644 index 0000000000..e30809f540 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/deconverge.fsh @@ -0,0 +1,37 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/deconverge.fsh (Mojang). The Converge*/ +// RadialConverge* uniforms were live there; baked as consts here since 1.21.11 post-effect +// uniforms are read once at load, not per-frame. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +const vec3 ConvergeX = vec3(-4.0, 0.0, 2.0); +const vec3 ConvergeY = vec3( 0.0, -4.0, 2.0); +const vec3 RadialConvergeX = vec3(1.0, 1.0, 1.0); +const vec3 RadialConvergeY = vec3(1.0, 1.0, 1.0); + +void main() { + vec2 oneTexel = 1.0 / InSize; + + vec3 CoordX = texCoord.x * RadialConvergeX; + vec3 CoordY = texCoord.y * RadialConvergeY; + + CoordX += ConvergeX * oneTexel.x - (RadialConvergeX - 1.0) * 0.5; + CoordY += ConvergeY * oneTexel.y - (RadialConvergeY - 1.0) * 0.5; + + float RedValue = texture(InSampler, vec2(CoordX.x, CoordY.x)).r; + float GreenValue = texture(InSampler, vec2(CoordX.y, CoordY.y)).g; + float BlueValue = texture(InSampler, vec2(CoordX.z, CoordY.z)).b; + + fragColor = vec4(RedValue, GreenValue, BlueValue, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/desaturate.fsh b/src/main/resources/assets/bleachhack/shaders/post/desaturate.fsh new file mode 100644 index 0000000000..d569b970b5 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/desaturate.fsh @@ -0,0 +1,30 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/color_convolve.fsh (Mojang), used there as the +// "Desaturate" mode via a Saturation=0.2 uniform override. 1.21.11's own color_convolve.fsh (kept +// for Creeper mode) hardcodes Saturation as a const 1.8, so it can't be reused for this - this is +// the same convolve+saturation math with Saturation baked to the old Desaturate value instead. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +const vec3 Gray = vec3(0.3, 0.59, 0.11); +const float Saturation = 0.2; + +out vec4 fragColor; + +void main() { + vec4 InTexel = texture(InSampler, texCoord); + + float Luma = dot(InTexel.rgb, Gray); + vec3 Chroma = InTexel.rgb - Luma; + vec3 OutColor = (Chroma * Saturation) + Luma; + + fragColor = vec4(OutColor, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/entity_outline.json b/src/main/resources/assets/bleachhack/shaders/post/entity_outline.json deleted file mode 100644 index a45886393d..0000000000 --- a/src/main/resources/assets/bleachhack/shaders/post/entity_outline.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "targets": [ - "main", - "swap" - ], - "passes": [ - { - "name": "bleachhack:entity_outline", - "intarget": "main", - "outtarget": "swap" - }, - { - "name": "blit", - "intarget": "swap", - "outtarget": "main" - } - ] -} \ No newline at end of file diff --git a/src/main/resources/assets/bleachhack/shaders/post/entity_outline_meteor.fsh b/src/main/resources/assets/bleachhack/shaders/post/entity_outline_meteor.fsh new file mode 100644 index 0000000000..94762c7191 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/entity_outline_meteor.fsh @@ -0,0 +1,66 @@ +#version 330 + +// Ported from Meteor Client's outline.frag (MeteorDevelopment/meteor-client, +// utils/render/postprocess/PostProcessShaders) - same distance-field glow algorithm. +// +// Width/fill/glow are baked as consts instead of live post-effect uniforms. An earlier +// version tried to hot-swap a fresh PostEffectProcessor (with per-frame uniform values) +// into ShaderLoader's cache whenever ESP's sliders changed, since post-effect uniforms +// are otherwise only read once at resource-load time - but that swap never actually took +// effect at runtime, so the *static* JSON-declared pass below kept rendering instead, +// which is why "Shader" mode always looked like a flat single-color outline no matter +// what the sliders were set to. AnarchyClient's working esp_outline.fsh (same hijack of +// vanilla's entity_outline post effect) uses this exact baked-const approach - proven to +// actually render Meteor's fill+glow, at the cost of the sliders no longer being live. + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +uniform sampler2D InSampler; + +in vec2 texCoord; + +out vec4 fragColor; + +// Meteor's own literal defaults (width 2, fill 0.3, glow 3.5) read as barely more than a thin +// outline at typical resolutions - AnarchyClient's proven esp_outline.fsh tunes these up for an +// actually-visible glow+fill, so match those numbers instead of Meteor's raw slider defaults. +const int WIDTH = 4; +const float FILL_OPACITY = 0.25; +const float GLOW_MULTIPLIER = 3.0; + +void main() { + vec4 center = texture(InSampler, texCoord); + + // Inside the entity silhouette - translucent fill (Meteor's shapeMode "Both"/"Sides"). + if (center.a > 0.0) { + fragColor = vec4(center.rgb, center.a * FILL_OPACITY); + return; + } + + // Outside the silhouette - soft glow falloff towards the nearest silhouette pixel. + float minDist = float(WIDTH * WIDTH) + 1.0; + vec3 glowColor = vec3(0.0); + + for (int x = -WIDTH; x <= WIDTH; x++) { + for (int y = -WIDTH; y <= WIDTH; y++) { + vec4 sampled = texture(InSampler, texCoord + vec2(x, y) / InSize); + if (sampled.a > 0.0) { + float d = float(x * x + y * y) - 1.0; + if (d < minDist) { + minDist = d; + glowColor = sampled.rgb; + } + } + } + } + + float threshold = float(WIDTH * WIDTH); + if (minDist > threshold) { + discard; + } + + fragColor = vec4(glowColor, min((1.0 - minDist / threshold) * GLOW_MULTIPLIER, 1.0)); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/fxaa.fsh b/src/main/resources/assets/bleachhack/shaders/post/fxaa.fsh new file mode 100644 index 0000000000..b67a152228 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/fxaa.fsh @@ -0,0 +1,69 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/fxaa.fsh (Mojang). The original vertex shader +// precomputed a "posPos" varying (center + a quarter-pixel NW offset) for the fragment shader to +// reuse - 1.21.11's shared minecraft:core/screenquad vertex shader only provides texCoord, so the +// NW offset is just computed inline here instead. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +const float FXAA_REDUCE_MIN = 1.0 / 128.0; +const float SpanMax = 8.0; +const float ReduceMul = 0.125; + +vec3 FxaaPixelShader(vec2 posM, vec2 posNW, sampler2D tex, vec2 rcpFrame) { + vec3 rgbNW = texture(tex, posNW).xyz; + vec3 rgbNE = textureOffset(tex, posNW, ivec2(1, 0)).xyz; + vec3 rgbSW = textureOffset(tex, posNW, ivec2(0, 1)).xyz; + vec3 rgbSE = textureOffset(tex, posNW, ivec2(1, 1)).xyz; + + vec3 rgbM = texture(tex, posM).xyz; + + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * ReduceMul), FXAA_REDUCE_MIN); + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(SpanMax, SpanMax), max(vec2(-SpanMax, -SpanMax), dir * rcpDirMin)) * rcpFrame.xy; + + vec3 rgbA = 0.5 * ( + texture(tex, posM + dir * (1.0 / 3.0 - 0.5)).xyz + + texture(tex, posM + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture(tex, posM + dir * (0.0 / 3.0 - 0.5)).xyz + + texture(tex, posM + dir * (3.0 / 3.0 - 0.5)).xyz); + + float lumaB = dot(rgbB, luma); + + if ((lumaB < lumaMin) || (lumaB > lumaMax)) { + return rgbA; + } else { + return rgbB; + } +} + +void main() { + vec2 rcpFrame = 1.0 / OutSize; + vec2 posNW = texCoord - rcpFrame * 0.5; + fragColor = vec4(FxaaPixelShader(texCoord, posNW, InSampler, rcpFrame), 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/notch.fsh b/src/main/resources/assets/bleachhack/shaders/post/notch.fsh new file mode 100644 index 0000000000..6ddf5e653c --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/notch.fsh @@ -0,0 +1,42 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/notch.fsh (Mojang). The original sampled a 4x4 +// procedurally-generated DitherSampler texture (registered as an "auxtarget" in the old post +// chain format, which 1.21.11's post_effect JSON has no equivalent for) - replaced with an +// equivalent 4x4 Bayer ordered-dither matrix computed inline instead of sampled from a texture. +// Same dithering effect, no aux texture needed. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +const mat4 BayerMatrix = mat4( + 0.0, 8.0, 2.0, 10.0, + 12.0, 4.0, 14.0, 6.0, + 3.0, 11.0, 1.0, 9.0, + 15.0, 7.0, 13.0, 5.0 +) / 16.0; + +void main() { + vec2 halfSize = InSize * 0.5; + + vec2 steppedCoord = texCoord; + steppedCoord.x = float(int(steppedCoord.x * halfSize.x)) / halfSize.x; + steppedCoord.y = float(int(steppedCoord.y * halfSize.y)) / halfSize.y; + + ivec2 ditherCoord = ivec2(mod(steppedCoord * halfSize, 4.0)); + float noise = BayerMatrix[ditherCoord.x][ditherCoord.y] - 0.5; + + vec4 col = texture(InSampler, steppedCoord) + noise * vec4(1.0 / 12.0, 1.0 / 12.0, 1.0 / 6.0, 1.0); + float r = float(int(col.r * 8.0)) / 8.0; + float g = float(int(col.g * 8.0)) / 8.0; + float b = float(int(col.b * 4.0)) / 4.0; + fragColor = vec4(r, g, b, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/outline_soft.fsh b/src/main/resources/assets/bleachhack/shaders/post/outline_soft.fsh new file mode 100644 index 0000000000..f0f223535b --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/outline_soft.fsh @@ -0,0 +1,52 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/outline_soft.fsh (Mojang) - Pencil mode. +// LumaRamp/LumaLevel were live uniforms there; baked as consts here since 1.21.11 post-effect +// uniforms are read once at load, not per-frame. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +const float LumaRamp = 16.0; +const float LumaLevel = 4.0; + +void main() { + vec2 oneTexel = 1.0 / InSize; + + vec4 center = texture(InSampler, texCoord); + vec4 up = texture(InSampler, texCoord + vec2( 0.0, -oneTexel.y)); + vec4 up2 = texture(InSampler, texCoord + vec2( 0.0, -oneTexel.y) * 2.0); + vec4 down = texture(InSampler, texCoord + vec2( oneTexel.x, 0.0)); + vec4 down2 = texture(InSampler, texCoord + vec2( oneTexel.x, 0.0) * 2.0); + vec4 left = texture(InSampler, texCoord + vec2(-oneTexel.x, 0.0)); + vec4 left2 = texture(InSampler, texCoord + vec2(-oneTexel.x, 0.0) * 2.0); + vec4 right = texture(InSampler, texCoord + vec2( 0.0, oneTexel.y)); + vec4 right2 = texture(InSampler, texCoord + vec2( 0.0, oneTexel.y) * 2.0); + vec4 uDiff = abs(center - up); + vec4 dDiff = abs(center - down); + vec4 lDiff = abs(center - left); + vec4 rDiff = abs(center - right); + vec4 u2Diff = abs(center - up2); + vec4 d2Diff = abs(center - down2); + vec4 l2Diff = abs(center - left2); + vec4 r2Diff = abs(center - right2); + vec4 sum = uDiff + dDiff + lDiff + rDiff + u2Diff + d2Diff + l2Diff + r2Diff; + vec4 gray = vec4(0.3, 0.59, 0.11, 0.0); + float sumLuma = 1.0 - dot(clamp(sum, 0.0, 1.0), gray); + + float centerLuma = dot(center + (center - pow(center, vec4(LumaRamp))), gray); + + centerLuma = centerLuma - fract(centerLuma * LumaLevel) / LumaLevel; + centerLuma = centerLuma * (LumaLevel / (LumaLevel - 1.0)); + centerLuma = centerLuma * sumLuma; + + fragColor = vec4(centerLuma, centerLuma, centerLuma, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/scan_pincushion.fsh b/src/main/resources/assets/bleachhack/shaders/post/scan_pincushion.fsh new file mode 100644 index 0000000000..1e7c2928be --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/scan_pincushion.fsh @@ -0,0 +1,63 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/scan_pincushion.fsh (Mojang) - Scanline mode. +// All parameters were already consts there. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +const vec4 Zero = vec4(0.0); +const vec4 Half = vec4(0.5); +const vec4 One = vec4(1.0); +const vec4 Two = vec4(2.0); + +const float Pi = 3.1415926535; +const float PincushionAmount = 0.02; +const float CurvatureAmount = 0.02; +const float ScanlineAmount = 0.8; +const float ScanlineScale = 1.0; +const float ScanlineHeight = 1.0; +const float ScanlineBrightScale = 1.0; +const float ScanlineOffset = 0.0; +const vec3 Floor = vec3(0.05, 0.05, 0.05); +const vec3 Power = vec3(0.8, 0.8, 0.8); + +out vec4 fragColor; + +void main() { + vec4 InTexel = texture(InSampler, texCoord); + + vec2 PinUnitCoord = texCoord * Two.xy - One.xy; + float PincushionR2 = pow(length(PinUnitCoord), 2.0); + vec2 PincushionCurve = PinUnitCoord * PincushionAmount * PincushionR2; + vec2 ScanCoord = texCoord; + + ScanCoord *= One.xy - PincushionAmount * 0.2; + ScanCoord += PincushionAmount * 0.1; + ScanCoord += PincushionCurve; + + // -- Alpha Clipping -- + if (ScanCoord.x < 0.0) discard; + if (ScanCoord.y < 0.0) discard; + if (ScanCoord.x > 1.0) discard; + if (ScanCoord.y > 1.0) discard; + + // -- Scanline Simulation -- + float InnerSine = ScanCoord.y * InSize.y * ScanlineScale * 0.25; + float ScanBrightMod = sin(InnerSine * Pi + ScanlineOffset * InSize.y * 0.25); + float ScanBrightness = mix(1.0, (pow(ScanBrightMod * ScanBrightMod, ScanlineHeight) * ScanlineBrightScale + 1.0) * 0.5, ScanlineAmount); + vec3 ScanlineTexel = InTexel.rgb * ScanBrightness; + + // -- Color Compression (increasing the floor of the signal without affecting the ceiling) -- + ScanlineTexel = Floor + (One.xyz - Floor) * ScanlineTexel; + + ScanlineTexel.rgb = pow(ScanlineTexel.rgb, Power); + + fragColor = vec4(ScanlineTexel.rgb, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/sobel.fsh b/src/main/resources/assets/bleachhack/shaders/post/sobel.fsh new file mode 100644 index 0000000000..b79fcbfda0 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/sobel.fsh @@ -0,0 +1,30 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/sobel.fsh (Mojang). + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +out vec4 fragColor; + +void main() { + vec2 oneTexel = 1.0 / InSize; + + vec4 center = texture(InSampler, texCoord); + vec4 left = texture(InSampler, texCoord - vec2(oneTexel.x, 0.0)); + vec4 right = texture(InSampler, texCoord + vec2(oneTexel.x, 0.0)); + vec4 up = texture(InSampler, texCoord - vec2(0.0, oneTexel.y)); + vec4 down = texture(InSampler, texCoord + vec2(0.0, oneTexel.y)); + vec4 leftDiff = center - left; + vec4 rightDiff = center - right; + vec4 upDiff = center - up; + vec4 downDiff = center - down; + vec4 total = clamp(leftDiff + rightDiff + upDiff + downDiff, 0.0, 1.0); + fragColor = vec4(total.rgb, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/post/vibrant.fsh b/src/main/resources/assets/bleachhack/shaders/post/vibrant.fsh new file mode 100644 index 0000000000..df22593f93 --- /dev/null +++ b/src/main/resources/assets/bleachhack/shaders/post/vibrant.fsh @@ -0,0 +1,30 @@ +#version 330 + +// Ported from Minecraft 1.19.4's shaders/program/color_convolve.fsh (Mojang), used there as the +// "Vibrant" mode via a Saturation=1.4 uniform override. Same reasoning as desaturate.fsh - 1.21.11's +// own color_convolve.fsh hardcodes a different Saturation const, so this bakes the original value +// instead of reusing it. + +uniform sampler2D InSampler; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + +in vec2 texCoord; + +const vec3 Gray = vec3(0.3, 0.59, 0.11); +const float Saturation = 1.4; + +out vec4 fragColor; + +void main() { + vec4 InTexel = texture(InSampler, texCoord); + + float Luma = dot(InTexel.rgb, Gray); + vec3 Chroma = InTexel.rgb - Luma; + vec3 OutColor = (Chroma * Saturation) + Luma; + + fragColor = vec4(OutColor, 1.0); +} diff --git a/src/main/resources/assets/bleachhack/shaders/program/entity_outline.fsh b/src/main/resources/assets/bleachhack/shaders/program/entity_outline.fsh deleted file mode 100644 index ea52092685..0000000000 --- a/src/main/resources/assets/bleachhack/shaders/program/entity_outline.fsh +++ /dev/null @@ -1,26 +0,0 @@ -#version 150 - -uniform sampler2D DiffuseSampler; - -in vec2 texCoord; -in vec2 oneTexel; - -out vec4 fragColor; - -void main() { - vec4 center = texture(DiffuseSampler, texCoord); - vec4 left = texture(DiffuseSampler, texCoord - vec2(oneTexel.x, 0.0)); - vec4 right = texture(DiffuseSampler, texCoord + vec2(oneTexel.x, 0.0)); - vec4 up = texture(DiffuseSampler, texCoord - vec2(0.0, oneTexel.y)); - vec4 down = texture(DiffuseSampler, texCoord + vec2(0.0, oneTexel.y)); - - float leftDiff = abs(center.a - left.a); - float rightDiff = abs(center.a - right.a); - float upDiff = abs(center.a - up.a); - float downDiff = abs(center.a - down.a); - - float alpha = leftDiff + rightDiff + upDiff + downDiff > 0.0 ? 1.0 : center.a; - vec3 rgb = max(max(max(max(center.rgb, left.rgb), right.rgb), up.rgb), down.rgb); - - fragColor = vec4(rgb, alpha); -} \ No newline at end of file diff --git a/src/main/resources/assets/bleachhack/shaders/program/entity_outline.json b/src/main/resources/assets/bleachhack/shaders/program/entity_outline.json deleted file mode 100644 index a279e4e9fa..0000000000 --- a/src/main/resources/assets/bleachhack/shaders/program/entity_outline.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "blend": { - "func": "add", - "srcrgb": "srcalpha", - "dstrgb": "1-srcalpha" - }, - "vertex": "sobel", - "fragment": "bleachhack:entity_outline", - "attributes": [ "Position" ], - "samplers": [ - { "name": "DiffuseSampler" } - ], - "uniforms": [ - { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, - { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] } - ] -} diff --git a/src/main/resources/bleachhack.accesswidener b/src/main/resources/bleachhack.accesswidener index 46a7193e34..e8af7b44f9 100644 --- a/src/main/resources/bleachhack.accesswidener +++ b/src/main/resources/bleachhack.accesswidener @@ -10,21 +10,17 @@ accessible field net/minecraft/client/network/ClientPlayerInteractionManag # MinecraftVersion -# - For ProtocolScreen to make the version constants accessible -accessible field net/minecraft/MinecraftVersion name Ljava/lang/String; -mutable field net/minecraft/MinecraftVersion name Ljava/lang/String; -# accessible field net/minecraft/MinecraftVersion releaseTarget Ljava/lang/String; -# mutable field net/minecraft/MinecraftVersion releaseTarget Ljava/lang/String; -accessible field net/minecraft/MinecraftVersion protocolVersion I -mutable field net/minecraft/MinecraftVersion protocolVersion I -accessible field net/minecraft/MinecraftVersion dataPackVersion I -mutable field net/minecraft/MinecraftVersion dataPackVersion I +# - ProtocolScreen used to mutate MinecraftVersion's name/protocolVersion/dataPackVersion fields directly. +# As of 1.21.11 SharedConstants.getGameVersion() returns an immutable GameVersion interface (record-backed); +# MinecraftVersion only exposes static factories now. No field-widener equivalent exists. +# ProtocolScreen now spoofs the outgoing handshake packet's protocolVersion instead (see +# MixinClientConnection/ProtocolScreen.java) - done. # MinecraftClient # - For AccountManager to change the session -accessible field net/minecraft/client/MinecraftClient session Lnet/minecraft/client/util/Session; -mutable field net/minecraft/client/MinecraftClient session Lnet/minecraft/client/util/Session; +accessible field net/minecraft/client/MinecraftClient session Lnet/minecraft/client/session/Session; +mutable field net/minecraft/client/MinecraftClient session Lnet/minecraft/client/session/Session; # - For FastUse to change the item use cooldown and rightclick the mouse accessible method net/minecraft/client/MinecraftClient doItemUse ()V accessible field net/minecraft/client/MinecraftClient itemUseCooldown I @@ -35,6 +31,7 @@ accessible field net/minecraft/client/MinecraftClient currentFps I # SoundManager # - For NotebotStealer to access soundsystem accessible field net/minecraft/client/sound/SoundManager soundSystem Lnet/minecraft/client/sound/SoundSystem; +# SoundSystem.sounds is still a Multimap in 1.21.11 - unchanged descriptor. accessible field net/minecraft/client/sound/SoundSystem sounds Lcom/google/common/collect/Multimap; @@ -43,33 +40,41 @@ accessible field net/minecraft/client/sound/SoundSystem sounds Lcom/ # ChunkBuilder # - For MixinChunkRebuildTask to overwrite the chunk building method +# 1.21.11 moved the tesselation loop out of RebuildTask into a standalone SectionBuilder.build(...) - +# MixinChunkRebuildTask now redirects that instead (done, matched line-for-line against SectionBuilder's +# decompiled source). accessible class net/minecraft/client/render/chunk/ChunkBuilder$BuiltChunk$RebuildTask -accessible class net/minecraft/client/render/chunk/ChunkBuilder$BuiltChunk$RebuildTask$RenderData -accessible field net/minecraft/client/render/chunk/ChunkBuilder$ChunkData nonEmptyLayers Ljava/util/Set; -accessible field net/minecraft/client/render/chunk/ChunkBuilder$ChunkData occlusionGraph Lnet/minecraft/client/render/chunk/ChunkOcclusionData; -# accessible field net/minecraft/client/render/chunk/ChunkBuilder$ChunkData bufferState Lnet/minecraft/client/render/BufferBuilder$State; -accessible method net/minecraft/client/render/chunk/ChunkBuilder$BuiltChunk$RebuildTask$RenderData ()V +accessible class net/minecraft/client/render/chunk/ChunkRenderData # RenderLayer -# - Making various classes accessible for ColorVertexConsumerProvider -accessible class net/minecraft/client/render/RenderLayer$MultiPhase -accessible method net/minecraft/client/render/RenderLayer$MultiPhase getPhases ()Lnet/minecraft/client/render/RenderLayer$MultiPhaseParameters; +# 1.21.11 removed RenderPhase and RenderLayer$MultiPhase/$MultiPhaseParameters/$OutlineMode entirely +# (renderer overhaul to a RenderPipeline-based system). -accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters -accessible field net/minecraft/client/render/RenderLayer$MultiPhaseParameters texture Lnet/minecraft/client/render/RenderPhase$TextureBase; -accessible field net/minecraft/client/render/RenderLayer$MultiPhaseParameters outlineMode Lnet/minecraft/client/render/RenderLayer$OutlineMode; +# RenderLayers +# - DEBUG_FILLED_BOX/DEBUG_QUADS are vanilla's own translucent position-color quad RenderLayers +# (used by Minecraft's own debug renderers) - reused by Renderer.java for ESP/box/quad fills +# instead of constructing a brand new RenderPipeline, since RenderLayer.of(...) itself is +# package-private in 1.21.11 (no public factory for arbitrary custom RenderLayers any more). +accessible field net/minecraft/client/render/RenderLayers DEBUG_FILLED_BOX Lnet/minecraft/client/render/RenderLayer; +accessible field net/minecraft/client/render/RenderLayers DEBUG_QUADS Lnet/minecraft/client/render/RenderLayer; -accessible class net/minecraft/client/render/RenderPhase$TextureBase -accessible method net/minecraft/client/render/RenderPhase$TextureBase getId ()Ljava/util/Optional; +# RenderLayer.of +# - For Renderer.java's NO_DEPTH_FILL/NO_DEPTH_LINES custom "see through walls" RenderLayers +# (RenderLayer.of(...) is package-private in 1.21.11 - no public factory for custom RenderLayers). +accessible method net/minecraft/client/render/RenderLayer of (Ljava/lang/String;Lnet/minecraft/client/render/RenderSetup;)Lnet/minecraft/client/render/RenderLayer; -accessible class net/minecraft/client/render/RenderLayer$OutlineMode -accessible field net/minecraft/client/render/RenderLayer$MultiPhaseParameters outlineMode Lnet/minecraft/client/render/RenderLayer$OutlineMode; +# RenderPipelines.RENDERTYPE_LINES_SNIPPET +# - For Renderer's "see through walls" NO_DEPTH_TEST line variant to reuse vanilla's exact lines +# shader/uniform declarations (Fog/Globals/Projection/DynamicTransforms) instead of trying to +# redeclare them by hand and risk a subtly wrong (and unverifiable without a running game) pipeline. +accessible field net/minecraft/client/gl/RenderPipelines RENDERTYPE_LINES_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet; # TextRenderer -# - Making the font storage accessible so WindowPassTextFieldWidget can override the text renderer -accessible field net/minecraft/client/font/TextRenderer fontStorageAccessor Ljava/util/function/Function; +# - Making the font provider accessible so WindowPassTextFieldWidget can override the text renderer. +# fontStorageAccessor (a Function) was replaced by the "fonts" field (TextRenderer$GlyphsProvider). +accessible field net/minecraft/client/font/TextRenderer fonts Lnet/minecraft/client/font/TextRenderer$GlyphsProvider; ## =========== Screens =========== @@ -77,9 +82,10 @@ accessible field net/minecraft/client/font/TextRenderer fontStorageAcce # DisconnectedScreen # - For AutoReconnect to read the various fields of DisconnectedScreen +# reason/reasonHeight were replaced by a single DisconnectionInfo record field ("info"); AutoReconnect.java +# reads the disconnect text via info.reason() instead - done. accessible field net/minecraft/client/gui/screen/DisconnectedScreen parent Lnet/minecraft/client/gui/screen/Screen; -accessible field net/minecraft/client/gui/screen/DisconnectedScreen reason Lnet/minecraft/text/Text; -accessible field net/minecraft/client/gui/screen/DisconnectedScreen reasonHeight I +accessible field net/minecraft/client/gui/screen/DisconnectedScreen info Lnet/minecraft/network/DisconnectionInfo; # HandledScreen @@ -90,6 +96,9 @@ accessible field net/minecraft/client/gui/screen/ingame/HandledScreen f # SignEditScreen # - For AutoSign to read the sign entity from the sign screen accessible field net/minecraft/client/gui/screen/ingame/AbstractSignEditScreen blockEntity Lnet/minecraft/block/entity/SignBlockEntity; +# - For AutoSign to know which side of the sign (front/back) is being edited, since +# UpdateSignC2SPacket now needs that flag explicitly. +accessible field net/minecraft/client/gui/screen/ingame/AbstractSignEditScreen front Z ## =========== Entities =========== @@ -105,22 +114,17 @@ accessible field net/minecraft/entity/projectile/FishingBobberEntity CA # EntityVelocityUpdateS2CPacket # - For NoVelocity to cancel entity velocity -accessible field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityX I -mutable field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityX I -accessible field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityY I -mutable field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityY I -accessible field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityZ I -mutable field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityZ I +# 1.19.4 had separate int velocityX/Y/Z fields; 1.21.11 merged them into one final Vec3d "velocity" field. +accessible field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocity Lnet/minecraft/util/math/Vec3d; +mutable field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocity Lnet/minecraft/util/math/Vec3d; # ExplosionS2CPacket # - For NoVelocity to cancel explosion velocity -accessible field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerVelocityX F -mutable field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerVelocityX F -accessible field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerVelocityY F -mutable field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerVelocityY F -accessible field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerVelocityZ F -mutable field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerVelocityZ F +# ExplosionS2CPacket is now a record; playerVelocityX/Y/Z merged into one Optional "playerKnockback" +# field. Widening removes the record's synthetic finality so the field can still be reassigned in place. +accessible field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerKnockback Ljava/util/Optional; +mutable field net/minecraft/network/packet/s2c/play/ExplosionS2CPacket playerKnockback Ljava/util/Optional; # GameMessageS2CPacket @@ -143,10 +147,20 @@ mutable field net/minecraft/network/packet/c2s/play/PlayerMoveC2SPacket # PlayerPositionLookS2CPacket # - For ElytraFly & PacketFly to change the yaw and pitch -accessible field net/minecraft/network/packet/s2c/play/PlayerPositionLookS2CPacket pitch F -mutable field net/minecraft/network/packet/s2c/play/PlayerPositionLookS2CPacket pitch F -accessible field net/minecraft/network/packet/s2c/play/PlayerPositionLookS2CPacket yaw F -mutable field net/minecraft/network/packet/s2c/play/PlayerPositionLookS2CPacket yaw F +# 1.21.11: PlayerPositionLookS2CPacket is now a record; pitch/yaw were merged into a nested +# EntityPosition record ("change" field). EntityPosition has a withRotation(float yaw, float pitch) +# method - ElytraFly.java/PacketFly.java do packet.change = packet.change().withRotation(newYaw, newPitch) - done. +accessible field net/minecraft/network/packet/s2c/play/PlayerPositionLookS2CPacket change Lnet/minecraft/entity/EntityPosition; +mutable field net/minecraft/network/packet/s2c/play/PlayerPositionLookS2CPacket change Lnet/minecraft/entity/EntityPosition; + + +# PalettedContainer +# - For NewChunks' New mode to scan a chunk section's block-state palette by insertion order +# (the "PaletteExploit" new/being-updated-chunk detection from Trouser-Streak) - no public API +# exposes the palette itself, only aggregate queries like hasAny()/count(). +accessible field net/minecraft/world/chunk/PalettedContainer data Lnet/minecraft/world/chunk/PalettedContainer$Data; +accessible class net/minecraft/world/chunk/PalettedContainer$Data +accessible method net/minecraft/world/chunk/PalettedContainer$Data palette ()Lnet/minecraft/world/chunk/Palette; # VehicleMoveC2SPacket diff --git a/src/main/resources/bleachhack.commands.json b/src/main/resources/bleachhack.commands.json index dbabd3e2fa..e5cb49d0b4 100644 --- a/src/main/resources/bleachhack.commands.json +++ b/src/main/resources/bleachhack.commands.json @@ -28,6 +28,7 @@ "CmdSpammer", "CmdTerrain", "CmdToggle", - "CmdWatermark" + "CmdWatermark", + "CmdModuleSettings" ] } \ No newline at end of file diff --git a/src/main/resources/bleachhack.mixins.json b/src/main/resources/bleachhack.mixins.json index c80b3723d8..de6912d198 100644 --- a/src/main/resources/bleachhack.mixins.json +++ b/src/main/resources/bleachhack.mixins.json @@ -8,17 +8,14 @@ "AccessorHeldItemRenderer", "AccessorMinecraftClient", "AccessorScreen", - "AccessorWorldRenderer", "MixinAbstractBlock", "MixinAbstractBlockState", - "MixinBackgroundRenderer", "MixinBeaconScreen", "MixinBiomeColors", "MixinBlock", "MixinBlockCollisionSpliterator", "MixinBlockEntityRenderDispatcher", "MixinBossBarHud", - "MixinBufferBuilder", "MixinCamera", "MixinChatScreen", "MixinChunkRebuildTask", @@ -28,21 +25,20 @@ "MixinClientPlayerEntity", "MixinClientPlayerInteractionManager", "MixinClientWorld", - "MixinDimensionEffects", + "MixinDrawContext", + "MixinDrawContextTextAlpha", "MixinEntity", - "MixinEntityRenderDispatcher", "MixinEntityRenderer", "MixinFlowableFluid", "MixinGameRenderer", "MixinInGameHud", "MixinInGameOverlayRenderer", - "MixinJsonEffectShaderProgram", "MixinKeyboard", "MixinLightmapTextureManager", "MixinLivingEntity", - "MixinLlamaPigStriderEntity", "MixinMapRenderer", "MixinMinecraftClient", + "MixinMobEntity", "MixinOptionsScreen", "MixinPacketByteBuf", "MixinPacketInflater", @@ -53,14 +49,18 @@ "MixinRenderTickCounter", "MixinScreen", "MixinServerScreen", - "MixinShader", - "MixinSharedConstants", + "MixinSkyRendering", "MixinSoundSystem", + "MixinStatusEffectFogModifier", + "MixinStringHelper", "MixinTitleScreen", "MixinWorldRenderer" ], "mixinPriority": 899, "injectors": { "defaultRequire": 1 - } + }, + "mixins": [ + "BlockedServersMixin" + ] } diff --git a/src/main/resources/bleachhack.modules.json b/src/main/resources/bleachhack.modules.json index a8eca1b0c7..d945ea4045 100644 --- a/src/main/resources/bleachhack.modules.json +++ b/src/main/resources/bleachhack.modules.json @@ -51,10 +51,12 @@ "Ghosthand", "HandProgress", "HoleESP", + "InfiniteReach", "Jesus", "Killaura", "LiquidFiller", "LogoutSpot", + "MaceKill", "MouseFriend", "Nametags", "NewChunks", @@ -72,6 +74,7 @@ "PacketFly", "Panic", "Peek", + "ProjectileLauncher", "PlayerCrash", "Reach", "RotationSnap", @@ -81,6 +84,7 @@ "SecretClose", "ShaderRender", "Sneak", + "SpearKill", "Solidify", "Spammer", "Speed",