Added and fixed tons of clientside fixes

This commit is contained in:
RaphiMC 2023-11-26 21:11:41 +01:00
parent 3cd08a8ae0
commit a4794e3e48
No known key found for this signature in database
GPG Key ID: 0F6BB0657A03AC94
129 changed files with 7157 additions and 1510 deletions

View File

@ -80,6 +80,9 @@ dependencies {
// Lenni0451 Libraries // Lenni0451 Libraries
jij "net.lenni0451:Reflect:${project.reflect_version}" jij "net.lenni0451:Reflect:${project.reflect_version}"
jij("net.lenni0451:MCPing:${project.mcping_version}") {
exclude group: "com.google.code.gson", module: "gson"
}
// Misc Libraries // Misc Libraries
jij("org.cloudburstmc.netty:netty-transport-raknet:${project.raknet_transport_version}") { jij("org.cloudburstmc.netty:netty-transport-raknet:${project.raknet_transport_version}") {

View File

@ -27,6 +27,7 @@ raknet_transport_version=1.0.0.CR1-SNAPSHOT
# Lenni0451 Libraries # Lenni0451 Libraries
reflect_version=1.3.0 reflect_version=1.3.0
mcping_version=1.3.0
# Misc Libraries # Misc Libraries
mod_menu_version=8.0.0 mod_menu_version=8.0.0

View File

@ -20,12 +20,11 @@
package de.florianmichael.viafabricplus; package de.florianmichael.viafabricplus;
import de.florianmichael.viafabricplus.event.PostGameLoadCallback; import de.florianmichael.viafabricplus.event.PostGameLoadCallback;
import de.florianmichael.viafabricplus.event.LoadCallback;
import de.florianmichael.viafabricplus.fixes.ClientsideFixes; import de.florianmichael.viafabricplus.fixes.ClientsideFixes;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.util.ClassLoaderPriorityUtil;
import de.florianmichael.viafabricplus.save.SaveManager; import de.florianmichael.viafabricplus.save.SaveManager;
import de.florianmichael.viafabricplus.settings.SettingsManager; import de.florianmichael.viafabricplus.settings.SettingsManager;
import de.florianmichael.viafabricplus.util.ClassLoaderPriorityUtil;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -38,7 +37,7 @@ import java.io.File;
* - Window interactions in <= 1.16.5 has changed and can be detected by the server * - Window interactions in <= 1.16.5 has changed and can be detected by the server
* - Most CTS protocol features aren't supported (see https://github.com/ViaVersion/ViaFabricPlus/issues/181) * - Most CTS protocol features aren't supported (see https://github.com/ViaVersion/ViaFabricPlus/issues/181)
* - Most CPE features aren't implemented correctly (see https://github.com/ViaVersion/ViaFabricPlus/issues/152) * - Most CPE features aren't implemented correctly (see https://github.com/ViaVersion/ViaFabricPlus/issues/152)
* - Bedrock scaffolding should be added as soon as ViaBedrock supports block placement (see https://github.com/ViaVersion/ViaFabricPlus/issues/204) * - Check if MixinPlayerScreenHandler.injectTransferSlot is needed? Check git log
* *
* TODO | Movement * TODO | Movement
* - X/Z Face based jump movement in <= 1.13.2 is broken (https://github.com/ViaVersion/ViaFabricPlus/issues/189) * - X/Z Face based jump movement in <= 1.13.2 is broken (https://github.com/ViaVersion/ViaFabricPlus/issues/189)
@ -46,13 +45,16 @@ import java.io.File;
* - Blit-jump is not supported in <= 1.8.9 (https://github.com/ViaVersion/ViaFabricPlus/issues/225) * - Blit-jump is not supported in <= 1.8.9 (https://github.com/ViaVersion/ViaFabricPlus/issues/225)
* *
* TODO | Migration v3 * TODO | Migration v3
* - Rename all methods
* - Use ViaProxy config patch for some clientside fixes options (Remove ViaFabricPlusVLViaConfig and MixinViaLegacyConfig) * - Use ViaProxy config patch for some clientside fixes options (Remove ViaFabricPlusVLViaConfig and MixinViaLegacyConfig)
* - Fix auto detect to not be a huge mess * - Add setting for VFP AlphaInventoryProvider
* - Fix MixinAbstractDonkeyEntity * - Fix MixinAbstractDonkeyEntity
* - Boats are probably broken. Check entity height offset fix
* - Check TO DO in MixinEntity * - Check TO DO in MixinEntity
* - Diff ItemRegistryDiff from projects and add missing items * - Fix MixinMultiplayerServerListWidget_ServerEntry
* - Test villagers
* - Test offhand
* - Check if attack cooldown is there or not
* - Test very large 1.8 chests
* - Test block ack
*/ */
public class ViaFabricPlus { public class ViaFabricPlus {
private static final ViaFabricPlus instance = new ViaFabricPlus(); private static final ViaFabricPlus instance = new ViaFabricPlus();

View File

@ -0,0 +1,41 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes;
import net.minecraft.util.ActionResult;
public class ActionResultException extends RuntimeException {
private final ActionResult actionResult;
public ActionResultException(final ActionResult actionResult) {
this.actionResult = actionResult;
}
public ActionResult getActionResult() {
return this.actionResult;
}
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}

View File

@ -0,0 +1,67 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ArmorType;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registries;
public class ArmorUpdateListener {
public static void init() {
ClientTickEvents.START_WORLD_TICK.register(world -> {
if (MinecraftClient.getInstance().player != null) {
try {
sendArmorUpdate();
} catch (Throwable t) {
ViaFabricPlus.global().getLogger().error("Error sending armor update", t);
}
}
});
}
public static void sendArmorUpdate() throws Exception {
int armor = 0;
for (final ItemStack stack : MinecraftClient.getInstance().player.getInventory().armor) {
armor += ArmorType.findByType(Registries.ITEM.getId(stack.getItem()).toString()).getArmorPoints();
}
if (armor == this.oldArmor) return;
this.oldArmor = armor;
final PacketWrapper properties = PacketWrapper.create(ClientboundPackets1_9.ENTITY_PROPERTIES, MinecraftClient.getInstance().getNetworkHandler().getConnection().getUserConnection());
properties.write(Type.VAR_INT, MinecraftClient.getInstance().player.getId());
properties.write(Type.INT, 1);
properties.write(Type.STRING, "generic.armor");
properties.write(Type.DOUBLE, 0D);
properties.write(Type.VAR_INT, 1);
properties.write(Type.UUID, ARMOR_POINTS_UUID);
properties.write(Type.DOUBLE, (double) armor);
properties.write(Type.BYTE, (byte) 0);
properties.scheduleSend(Protocol1_9To1_8.class);
}
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper;
import java.util.function.Consumer;
public class ChestHandler1_13_2 {
public static final Consumer<PacketByteBuf> OLD_PACKET_HANDLER = data -> {
final MinecraftClient mc = MinecraftClient.getInstance();
try {
final int windowId = data.readUnsignedByte();
final int slots = data.readUnsignedByte();
final Text title = data.readText();
final GenericContainerScreenHandler screenHandler = new GenericContainerScreenHandler(null, windowId, mc.player.getInventory(), new SimpleInventory(slots), MathHelper.ceil(slots / 9F));
mc.player.currentScreenHandler = screenHandler;
mc.setScreen(new GenericContainerScreen(screenHandler, mc.player.getInventory(), title));
} catch (Throwable t) {
throw new RuntimeException("Failed to handle OpenWindow packet data", t);
}
};
}

View File

@ -21,7 +21,7 @@ package de.florianmichael.viafabricplus.fixes;
import de.florianmichael.viafabricplus.ViaFabricPlus; import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.protocolhack.util.BlockStateTranslator; import de.florianmichael.viafabricplus.protocolhack.translator.BlockStateTranslator;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -33,62 +33,62 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec2f;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
public class ClientPlayerInteractionManager1_18_2 { public class ClientPlayerInteractionManager1_18_2 {
public static final Consumer<PacketByteBuf> OLD_PACKET_HANDLER = data -> { public static final Consumer<PacketByteBuf> OLD_PACKET_HANDLER = data -> {
try { try {
final var pos = data.readBlockPos(); final var pos = data.readBlockPos();
final var blockState = Block.STATE_IDS.get(BlockStateTranslator.translateBlockState1_18(data.readVarInt())); final var blockState = BlockStateTranslator.via1_18_2toMc(data.readVarInt());
final var action = data.readEnumConstant(PlayerActionC2SPacket.Action.class); final var action = data.readEnumConstant(PlayerActionC2SPacket.Action.class);
final var allGood = data.readBoolean(); final var allGood = data.readBoolean();
ClientPlayerInteractionManager1_18_2.handleBlockBreakAck(pos, blockState, action, allGood); ClientPlayerInteractionManager1_18_2.handleBlockBreakAck(pos, blockState, action, allGood);
} catch (Exception e) { } catch (Throwable t) {
ViaFabricPlus.global().getLogger().error("Failed to read BlockBreakAck packet data", e); throw new RuntimeException("Failed to handle BlockBreakAck packet data", t);
} }
}; };
private static final Object2ObjectLinkedOpenHashMap<Pair<BlockPos, PlayerActionC2SPacket.Action>, PositionAndRotation> UN_ACKED_ACTIONS = new Object2ObjectLinkedOpenHashMap<>(); private static final Object2ObjectLinkedOpenHashMap<Pair<BlockPos, PlayerActionC2SPacket.Action>, PositionAndRotation> UNACKED_ACTIONS = new Object2ObjectLinkedOpenHashMap<>();
public static void trackBlockAction(final PlayerActionC2SPacket.Action action, final BlockPos blockPos) { public static void trackPlayerAction(final PlayerActionC2SPacket.Action action, final BlockPos blockPos) {
final var player = MinecraftClient.getInstance().player; final var player = MinecraftClient.getInstance().player;
if (player == null) return; if (player == null) return;
var rotation = new Vec2f(player.getYaw(), player.getPitch()); var rotation = new Vec2f(player.getYaw(), player.getPitch());
if (ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_16_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_1)) {
rotation = null; rotation = null;
} }
UN_ACKED_ACTIONS.put(new Pair<>(blockPos, action), new PositionAndRotation(player.getPos().x, player.getPos().y, player.getPos().z, rotation)); UNACKED_ACTIONS.put(new Pair<>(blockPos, action), new PositionAndRotation(player.getPos().x, player.getPos().y, player.getPos().z, rotation));
} }
public static void handleBlockBreakAck(final BlockPos blockPos, final BlockState blockState, final PlayerActionC2SPacket.Action action, final boolean allGood) { public static void handleBlockBreakAck(final BlockPos blockPos, final BlockState expectedState, final PlayerActionC2SPacket.Action action, final boolean allGood) {
final var player = MinecraftClient.getInstance().player; final var player = MinecraftClient.getInstance().player;
if (player == null) return; if (player == null) return;
final var world = MinecraftClient.getInstance().getNetworkHandler().getWorld();
final var world = Objects.requireNonNull(MinecraftClient.getInstance().getNetworkHandler()).getWorld(); final var oldPlayerState = UNACKED_ACTIONS.remove(new Pair<>(blockPos, action));
final var actualState = world.getBlockState(blockPos);
final var next = UN_ACKED_ACTIONS.remove(new Pair<>(blockPos, action)); if ((oldPlayerState == null || !allGood || action != PlayerActionC2SPacket.Action.START_DESTROY_BLOCK && actualState != expectedState) && (actualState != expectedState || ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_15_2))) {
final var blockStateFromPos = world.getBlockState(blockPos); world.setBlockState(blockPos, expectedState, Block.NOTIFY_ALL | Block.FORCE_STATE);
if (oldPlayerState != null && ((ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_1) || (world == player.getWorld() && player.collidesWithStateAtPos(blockPos, expectedState))))) {
if ((next == null || !allGood || action != PlayerActionC2SPacket.Action.START_DESTROY_BLOCK && blockStateFromPos != blockState) && blockStateFromPos != blockState) { if (oldPlayerState.rotation != null) {
world.setBlockState(blockPos, blockState); player.updatePositionAndAngles(oldPlayerState.x, oldPlayerState.y, oldPlayerState.z, oldPlayerState.rotation.x, oldPlayerState.rotation.y);
if (next != null && world == player.getWorld() && player.collidesWithStateAtPos(blockPos, blockState)) {
if (next.rotation != null) {
player.updatePositionAndAngles(next.x, next.y, next.z, next.rotation.x, next.rotation.y);
} else { } else {
player.updatePosition(next.x, next.y, next.z); player.updatePosition(oldPlayerState.x, oldPlayerState.y, oldPlayerState.z);
} }
} }
} }
while (UN_ACKED_ACTIONS.size() >= 50) { while (UNACKED_ACTIONS.size() >= 50) {
ViaFabricPlus.global().getLogger().error("Too many unacked block actions, dropping {}", UN_ACKED_ACTIONS.firstKey()); ViaFabricPlus.global().getLogger().warn("Too many unacked block actions, dropping {}", UNACKED_ACTIONS.firstKey());
UN_ACKED_ACTIONS.removeFirst(); UNACKED_ACTIONS.removeFirst();
} }
} }
public record PositionAndRotation(double x, double y, double z, Vec2f rotation) { public record PositionAndRotation(double x, double y, double z, Vec2f rotation) {
} }
} }

View File

@ -19,28 +19,22 @@
package de.florianmichael.viafabricplus.fixes; package de.florianmichael.viafabricplus.fixes;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ArmorType;
import de.florianmichael.viafabricplus.event.ChangeProtocolVersionCallback; import de.florianmichael.viafabricplus.event.ChangeProtocolVersionCallback;
import de.florianmichael.viafabricplus.event.PostGameLoadCallback;
import de.florianmichael.viafabricplus.event.LoadClassicProtocolExtensionCallback; import de.florianmichael.viafabricplus.event.LoadClassicProtocolExtensionCallback;
import de.florianmichael.viafabricplus.fixes.classic.CustomClassicProtocolExtensions; import de.florianmichael.viafabricplus.fixes.classic.CustomClassicProtocolExtensions;
import de.florianmichael.viafabricplus.fixes.classic.screen.ClassicItemSelectionScreen; import de.florianmichael.viafabricplus.fixes.classic.screen.ClassicItemSelectionScreen;
import de.florianmichael.viafabricplus.injection.ViaFabricPlusMixinPlugin; import de.florianmichael.viafabricplus.injection.ViaFabricPlusMixinPlugin;
import net.minecraft.block.Block; import net.minecraft.block.*;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.FontStorage; import net.minecraft.client.font.FontStorage;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.data.ClassicProtocolExtension; import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.data.ClassicProtocolExtension;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import net.raphimc.vialoader.util.VersionRange;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -54,16 +48,6 @@ public class ClientsideFixes {
*/ */
private static List<Block> RELOADABLE_BLOCKS; private static List<Block> RELOADABLE_BLOCKS;
/**
* Legacy versions do not support SRV records, so we need to resolve them manually
*/
public static final VersionRange LEGACY_SRV_RESOLVE = VersionRange.andOlder(VersionEnum.r1_2_4tor1_2_5).add(VersionRange.single(VersionEnum.bedrockLatest));
/**
* Contains the armor points of all armor items in legacy versions (<= 1.8.x)
*/
private static final Map<Item, Integer> LEGACY_ARMOR_POINTS = new HashMap<>();
/** /**
* Contains all tasks that are waiting for a packet to be received, this system can be used to sync ViaVersion tasks with the correct thread * Contains all tasks that are waiting for a packet to be received, this system can be used to sync ViaVersion tasks with the correct thread
*/ */
@ -74,63 +58,59 @@ public class ClientsideFixes {
*/ */
public static final String PACKET_SYNC_IDENTIFIER = UUID.randomUUID() + ":" + UUID.randomUUID(); public static final String PACKET_SYNC_IDENTIFIER = UUID.randomUUID() + ":" + UUID.randomUUID();
private static final float DEFAULT_SOUL_SAND_VELOCITY_MULTIPLIER = Blocks.SOUL_SAND.getVelocityMultiplier();
private static final float _1_14_4_SOUL_SAND_VELOCITY_MULTIPLIER = 1F;
/** /**
* The current chat limit * The current chat limit
*/ */
private static int currentChatLimit = 256; private static int currentChatLength = 256;
public static void init() { public static void init() {
CustomClassicProtocolExtensions.create(); CustomClassicProtocolExtensions.create();
EntityHitboxUpdateListener.init();
PostGameLoadCallback.EVENT.register(() -> { ArmorUpdateListener.init();
// Loads the armor points of all armor items in legacy versions (<= 1.8.x)
for (Item armorItem : Arrays.asList(Items.LEATHER_HELMET, Items.LEATHER_CHESTPLATE, Items.LEATHER_BOOTS,
Items.CHAINMAIL_HELMET, Items.CHAINMAIL_CHESTPLATE, Items.CHAINMAIL_LEGGINGS, Items.CHAINMAIL_BOOTS,
Items.IRON_HELMET, Items.IRON_CHESTPLATE, Items.IRON_LEGGINGS, Items.IRON_BOOTS, Items.DIAMOND_HELMET,
Items.DIAMOND_CHESTPLATE, Items.DIAMOND_LEGGINGS, Items.DIAMOND_BOOTS, Items.GOLDEN_HELMET,
Items.GOLDEN_CHESTPLATE, Items.GOLDEN_LEGGINGS, Items.GOLDEN_BOOTS)) {
LEGACY_ARMOR_POINTS.put(armorItem, ArmorType.findByType(Registries.ITEM.getId(armorItem).toString()).getArmorPoints());
}
RELOADABLE_BLOCKS = Arrays.asList(Blocks.ANVIL, Blocks.WHITE_BED, Blocks.ORANGE_BED,
Blocks.MAGENTA_BED, Blocks.LIGHT_BLUE_BED, Blocks.YELLOW_BED, Blocks.LIME_BED, Blocks.PINK_BED, Blocks.GRAY_BED,
Blocks.LIGHT_GRAY_BED, Blocks.CYAN_BED, Blocks.PURPLE_BED, Blocks.BLUE_BED, Blocks.BROWN_BED, Blocks.GREEN_BED,
Blocks.RED_BED, Blocks.BLACK_BED, Blocks.BREWING_STAND, Blocks.CAULDRON, Blocks.CHEST, Blocks.PITCHER_CROP,
Blocks.END_PORTAL, Blocks.END_PORTAL_FRAME, Blocks.FARMLAND, Blocks.OAK_FENCE, Blocks.HOPPER, Blocks.LADDER,
Blocks.LILY_PAD, Blocks.GLASS_PANE, Blocks.WHITE_STAINED_GLASS_PANE, Blocks.ORANGE_STAINED_GLASS_PANE,
Blocks.MAGENTA_STAINED_GLASS_PANE, Blocks.LIGHT_BLUE_STAINED_GLASS_PANE, Blocks.YELLOW_STAINED_GLASS_PANE,
Blocks.LIME_STAINED_GLASS_PANE, Blocks.PINK_STAINED_GLASS_PANE, Blocks.GRAY_STAINED_GLASS_PANE,
Blocks.LIGHT_GRAY_STAINED_GLASS_PANE, Blocks.CYAN_STAINED_GLASS_PANE, Blocks.PURPLE_STAINED_GLASS_PANE,
Blocks.BLUE_STAINED_GLASS_PANE, Blocks.BROWN_STAINED_GLASS_PANE, Blocks.GREEN_STAINED_GLASS_PANE,
Blocks.RED_STAINED_GLASS_PANE, Blocks.BLACK_STAINED_GLASS_PANE, Blocks.PISTON, Blocks.PISTON_HEAD,
Blocks.SNOW, Blocks.COBBLESTONE_WALL, Blocks.MOSSY_COBBLESTONE_WALL
);
});
// Reloads some clientside stuff when the protocol version changes // Reloads some clientside stuff when the protocol version changes
ChangeProtocolVersionCallback.EVENT.register((oldVersion, newVersion) -> MinecraftClient.getInstance().execute(() -> { ChangeProtocolVersionCallback.EVENT.register((oldVersion, newVersion) -> MinecraftClient.getInstance().execute(() -> {
if (MinecraftClient.getInstance() == null) return; // Soul sand velocity multiplier
if (isNewerThan(oldVersion, newVersion, VersionEnum.r1_14_4)) {
Blocks.SOUL_SAND.velocityMultiplier = DEFAULT_SOUL_SAND_VELOCITY_MULTIPLIER;
}
if (isOlderThanOrEqualTo(oldVersion, newVersion, VersionEnum.r1_14_4)) {
Blocks.SOUL_SAND.velocityMultiplier = _1_14_4_SOUL_SAND_VELOCITY_MULTIPLIER;
}
// Reloads all bounding boxes // Reloads all bounding boxes
for (Block block : RELOADABLE_BLOCKS) { for (Block block : Registries.BLOCK) {
for (BlockState state : block.getStateManager().getStates()) { if (block instanceof AnvilBlock || block instanceof BedBlock || block instanceof BrewingStandBlock
state.initShapeCache(); || block instanceof CarpetBlock || block instanceof CauldronBlock || block instanceof ChestBlock
|| block instanceof EnderChestBlock || block instanceof EndPortalBlock || block instanceof EndPortalFrameBlock
|| block instanceof FarmlandBlock || block instanceof FenceBlock || block instanceof FenceGateBlock
|| block instanceof HopperBlock || block instanceof LadderBlock || block instanceof LeavesBlock
|| block instanceof LilyPadBlock || block instanceof PaneBlock || block instanceof PistonBlock
|| block instanceof PistonHeadBlock || block instanceof SnowBlock || block instanceof WallBlock
|| block instanceof CropBlock || block instanceof FlowerbedBlock
) {
for (BlockState state : block.getStateManager().getStates()) {
state.initShapeCache();
}
} }
} }
// Calculates the current chat limit, since it changes depending on the protocol version // Calculates the current chat length limit
if (newVersion.isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) { if (newVersion.isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) {
currentChatLimit = 64 - (MinecraftClient.getInstance().getSession().getUsername().length() + 2); currentChatLength = 64 - (MinecraftClient.getInstance().getSession().getUsername().length() + 2);
} else if (newVersion.equals(VersionEnum.bedrockLatest)) { } else if (newVersion.equals(VersionEnum.bedrockLatest)) {
currentChatLimit = 512; currentChatLength = 512;
} else if (newVersion.isOlderThanOrEqualTo(VersionEnum.r1_9_3tor1_9_4)) { } else if (newVersion.isOlderThanOrEqualTo(VersionEnum.r1_9_3tor1_9_4)) {
currentChatLimit = 100; currentChatLength = 100;
} else { } else {
currentChatLimit = 256; currentChatLength = 256;
} }
// Text Renderer invisible character fix
if (!ViaFabricPlusMixinPlugin.DASH_LOADER_PRESENT) { if (!ViaFabricPlusMixinPlugin.DASH_LOADER_PRESENT) {
// Reloads all font storages to fix the font renderer
for (FontStorage storage : MinecraftClient.getInstance().fontManager.fontStorages.values()) { for (FontStorage storage : MinecraftClient.getInstance().fontManager.fontStorages.values()) {
storage.glyphRendererCache.clear(); storage.glyphRendererCache.clear();
storage.glyphCache.clear(); storage.glyphCache.clear();
@ -145,7 +125,7 @@ public class ClientsideFixes {
// Calculates the current chat limit, since it changes depending on the protocol version // Calculates the current chat limit, since it changes depending on the protocol version
LoadClassicProtocolExtensionCallback.EVENT.register(classicProtocolExtension -> { LoadClassicProtocolExtensionCallback.EVENT.register(classicProtocolExtension -> {
if (classicProtocolExtension == ClassicProtocolExtension.LONGER_MESSAGES) { if (classicProtocolExtension == ClassicProtocolExtension.LONGER_MESSAGES) {
currentChatLimit = Short.MAX_VALUE * 2; currentChatLength = Short.MAX_VALUE * 2;
} }
}); });
} }
@ -163,33 +143,30 @@ public class ClientsideFixes {
} }
public static void handleSyncTask(final PacketByteBuf buf) { public static void handleSyncTask(final PacketByteBuf buf) {
buf.resetReaderIndex();
final var uuid = buf.readString(); final var uuid = buf.readString();
if (PENDING_EXECUTION_TASKS.containsKey(uuid)) { if (PENDING_EXECUTION_TASKS.containsKey(uuid)) {
MinecraftClient.getInstance().execute(() -> { // Execute the task on the main thread MinecraftClient.getInstance().execute(() -> { // Execute the task on the main thread
final var task = PENDING_EXECUTION_TASKS.get(uuid); final var task = PENDING_EXECUTION_TASKS.remove(uuid);
PENDING_EXECUTION_TASKS.remove(uuid);
task.accept(buf); task.accept(buf);
}); });
} }
} }
/** public static int getCurrentChatLength() {
* Returns the armor points of an armor item in legacy versions (<= 1.8.x) return currentChatLength;
*
* @param itemStack The item stack to get the armor points from
* @return The armor points of the item stack
*/
public static int getLegacyArmorPoints(final ItemStack itemStack) {
if (!LEGACY_ARMOR_POINTS.containsKey(itemStack.getItem())) return 0; // Just in case
return LEGACY_ARMOR_POINTS.get(itemStack.getItem());
} }
public static int getCurrentChatLimit() { private static boolean isOlderThanOrEqualTo(final VersionEnum oldVersion, final VersionEnum newVersion, final VersionEnum toCheck) {
return currentChatLimit; return oldVersion.isNewerThan(toCheck) && newVersion.isOlderThanOrEqualTo(toCheck);
} }
private static boolean isNewerThan(final VersionEnum oldVersion, final VersionEnum newVersion, final VersionEnum toCheck) {
return newVersion.isNewerThan(toCheck) && oldVersion.isOlderThanOrEqualTo(toCheck);
}
private static boolean didCrossBoundary(final VersionEnum oldVersion, final VersionEnum newVersion, final VersionEnum toCheck) {
return isNewerThan(oldVersion, newVersion, toCheck) || isOlderThanOrEqualTo(oldVersion, newVersion, toCheck);
}
} }

View File

@ -39,144 +39,141 @@ import org.joml.Vector3f;
public class EntityHeightOffsetsPre1_20_2 { public class EntityHeightOffsetsPre1_20_2 {
public static Vector3f getMountedHeightOffset(final Entity entity, final Entity passenger) { public static Vector3f getMountedHeightOffset(final Entity entity, final Entity passenger) {
double yOffset = entity.getHeight() * 0.75; float yOffset = entity.getHeight() * 0.75F;
if (entity instanceof LlamaEntity llamaEntity) { if (entity instanceof BoatEntity boatEntity) {
yOffset = entity.getHeight() * 0.6; if (!boatEntity.hasPassenger(passenger)) return new Vector3f();
final float xOffset = MathHelper.sin(llamaEntity.bodyYaw * 0.017453292F); if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
final float zOffset = MathHelper.cos(llamaEntity.bodyYaw * 0.017453292F); yOffset = -0.3F;
final float xOffset = MathHelper.cos(boatEntity.getYaw() * MathHelper.PI / 180F);
final float zOffset = MathHelper.sin(boatEntity.getYaw() * MathHelper.PI / 180F);
return new Vector3f(0.3F * xOffset, (float) yOffset, -(0.3F * zOffset)); return new Vector3f(0.4F * xOffset, yOffset, 0.4F * zOffset);
} else if (entity instanceof CamelEntity camelEntity) {
yOffset = entity.getDimensions(camelEntity.isSitting() ? EntityPose.SITTING : EntityPose.STANDING).height - (camelEntity.isBaby() ? 0.35F : 0.6F);
final int passengerIndex = camelEntity.getPassengerList().indexOf(passenger);
final boolean firstIndex = passengerIndex == 0;
if (passengerIndex >= 0) {
float zOffset = 0.5f;
if (camelEntity.isRemoved()) {
yOffset = 0.01f;
} else {
final var fakeDimension = EntityDimensions.fixed(0F, (0.375F * camelEntity.getScaleFactor()) + (float) yOffset); // Reverts original calculation to set yOffset to our field
yOffset = camelEntity.getPassengerAttachmentY(firstIndex, 0.0f, fakeDimension, camelEntity.getScaleFactor());
}
if (camelEntity.getPassengerList().size() > 1) {
if (!firstIndex) zOffset = -0.7f;
if (passenger instanceof AnimalEntity) zOffset += 0.2f;
}
return new Vector3f(0, (float) yOffset, zOffset);
} else { } else {
return new Vector3f(); if (boatEntity.isRemoved()) {
yOffset = 0.01F;
} else {
yOffset = boatEntity.getVariant() == BoatEntity.Type.BAMBOO ? 0.25F : -0.1F;
}
float xOffset = boatEntity instanceof ChestBoatEntity ? 0.15F : 0F;
if (boatEntity.getPassengerList().size() > 1) {
final int idx = boatEntity.getPassengerList().indexOf(passenger);
if (idx == 0) {
xOffset = 0.2F;
} else {
xOffset = -0.6F;
}
if (passenger instanceof AnimalEntity) xOffset += 0.2F;
}
return new Vector3f(xOffset, yOffset, 0F);
} }
} else if (entity instanceof SnifferEntity) { } else if (entity instanceof CamelEntity camelEntity) {
yOffset = 1.8; if (!camelEntity.hasPassenger(passenger)) return new Vector3f();
final boolean firstPassenger = camelEntity.getPassengerList().indexOf(passenger) == 0;
yOffset = camelEntity.getDimensions(camelEntity.isSitting() ? EntityPose.SITTING : EntityPose.STANDING).height - (camelEntity.isBaby() ? 0.35F : 0.6F);
if (camelEntity.isRemoved()) {
yOffset = 0.01F;
} else {
yOffset = (float) camelEntity.getPassengerAttachmentY(firstPassenger, 0F, EntityDimensions.fixed(0F, (0.375F * camelEntity.getScaleFactor()) + yOffset), camelEntity.getScaleFactor());
}
float zOffset = 0.5F;
if (camelEntity.getPassengerList().size() > 1) {
if (!firstPassenger) zOffset = -0.7F;
if (passenger instanceof AnimalEntity) zOffset += 0.2F;
}
return new Vector3f(0, yOffset, zOffset);
} else if (entity instanceof ChickenEntity chickenEntity) {
final float xOffset = MathHelper.sin(chickenEntity.bodyYaw * MathHelper.PI / 180F);
final float zOffset = MathHelper.cos(chickenEntity.bodyYaw * MathHelper.PI / 180F);
return new Vector3f(0.1F * xOffset, (float) (chickenEntity.getBodyY(0.5D) - chickenEntity.getY()), -0.1F * zOffset);
} else if (entity instanceof EnderDragonEntity enderDragonEntity) { } else if (entity instanceof EnderDragonEntity enderDragonEntity) {
yOffset = enderDragonEntity.body.getHeight(); yOffset = enderDragonEntity.body.getHeight();
} else if (entity instanceof PiglinEntity) {
yOffset = entity.getHeight() * 0.92;
} else if (entity instanceof HoglinEntity hoglinEntity) { } else if (entity instanceof HoglinEntity hoglinEntity) {
yOffset = entity.getHeight() - (hoglinEntity.isBaby() ? 0.2 : 0.15); yOffset = hoglinEntity.getHeight() - (hoglinEntity.isBaby() ? 0.2F : 0.15F);
} else if (entity instanceof SkeletonHorseEntity) { } else if (entity instanceof LlamaEntity llamaEntity) {
yOffset -= 0.1875; yOffset = entity.getHeight() * 0.6F;
final float xOffset = MathHelper.sin(llamaEntity.bodyYaw * MathHelper.PI / 180F);
final float zOffset = MathHelper.cos(llamaEntity.bodyYaw * MathHelper.PI / 180F);
return new Vector3f(0.3F * xOffset, yOffset, 0.3F * zOffset);
} else if (entity instanceof PhantomEntity) { } else if (entity instanceof PhantomEntity) {
yOffset = entity.getEyeHeight(entity.getPose()); yOffset = entity.getStandingEyeHeight();
} else if (entity instanceof PiglinEntity) {
yOffset = entity.getHeight() * 0.92F;
} else if (entity instanceof RavagerEntity) { } else if (entity instanceof RavagerEntity) {
yOffset = 2.1; yOffset = 2.1F;
} else if (entity instanceof ZoglinEntity zoglinEntity) { } else if (entity instanceof SkeletonHorseEntity) {
yOffset = (double) entity.getHeight() - (zoglinEntity.isBaby() ? 0.2 : 0.15); yOffset -= 0.1875F;
} else if (entity instanceof BoatEntity boatEntity) { } else if (entity instanceof SnifferEntity) {
final var version = ProtocolHack.getTargetVersion(); yOffset = 1.8F;
if (version.isOlderThanOrEqualTo(VersionEnum.r1_8)) {
yOffset = -0.3;
} else {
yOffset = boatEntity.getVariant() == BoatEntity.Type.BAMBOO ? 0.25 : -0.1;
}
if (boatEntity.hasPassenger(passenger)) {
float xOffset = (boatEntity instanceof ChestBoatEntity) ? 0.15F : 0.0F;
yOffset = (boatEntity.isRemoved() ? (double) 0.01f : yOffset);
if (boatEntity.getPassengerList().size() > 1) {
int i = boatEntity.getPassengerList().indexOf(passenger);
xOffset = i == 0 ? 0.2f : -0.6f;
if (passenger instanceof AnimalEntity) {
xOffset += 0.2f;
}
}
return new Vector3f(xOffset, (float) yOffset, 0.0F);
} else {
return new Vector3f();
}
} else if (entity instanceof StriderEntity striderEntity) {
final var var1 = Math.min(0.25F, striderEntity.limbAnimator.getSpeed());
final var var2 = striderEntity.limbAnimator.getPos();
yOffset = (double) striderEntity.getHeight() - 0.19 + (double) (0.12F * MathHelper.cos(var2 * 1.5F) * 2.0F * var1);
} else if (entity instanceof SpiderEntity) { } else if (entity instanceof SpiderEntity) {
yOffset = entity.getHeight() * 0.5F; yOffset = entity.getHeight() * 0.5F;
} else if (entity instanceof ChickenEntity chickenEntity) { } else if (entity instanceof StriderEntity striderEntity) {
final var xOffset = MathHelper.sin(chickenEntity.bodyYaw * (MathHelper.PI / 180)); final float f = Math.min(0.25F, striderEntity.limbAnimator.getSpeed());
final var zOffset = MathHelper.cos(chickenEntity.bodyYaw * (MathHelper.PI / 180)); final float g = striderEntity.limbAnimator.getPos();
yOffset = striderEntity.getHeight() - 0.19F + (0.12F * MathHelper.cos(g * 1.5F) * 2F * f);
return new Vector3f(0.1f * xOffset, (float) (chickenEntity.getBodyY(0.5) - chickenEntity.getY()), -(0.1f * zOffset)); } else if (entity instanceof ZoglinEntity zoglinEntity) {
yOffset = zoglinEntity.getHeight() - (zoglinEntity.isBaby() ? 0.2F : 0.15F);
} else if (entity instanceof AbstractDonkeyEntity) {
yOffset -= 0.25F;
} else if (entity instanceof AbstractMinecartEntity) {
yOffset = 0F;
} }
if (entity instanceof AbstractDonkeyEntity) { if (entity instanceof AbstractHorseEntity abstractHorseEntity) {
yOffset -= 0.25;
} else if (entity instanceof AbstractMinecartEntity) {
yOffset = 0.0;
} else if (entity instanceof AbstractHorseEntity abstractHorseEntity) {
if (abstractHorseEntity.lastAngryAnimationProgress > 0.0f) { if (abstractHorseEntity.lastAngryAnimationProgress > 0.0f) {
final float xOffset = MathHelper.sin(abstractHorseEntity.bodyYaw * ((float) Math.PI / 180)); final float xOffset = MathHelper.sin(abstractHorseEntity.bodyYaw * MathHelper.PI / 180F);
final float zOffset = MathHelper.cos(abstractHorseEntity.bodyYaw * ((float) Math.PI / 180)); final float zOffset = MathHelper.cos(abstractHorseEntity.bodyYaw * MathHelper.PI / 180F);
final float xzFactor = 0.7F * abstractHorseEntity.lastAngryAnimationProgress; final float xzFactor = 0.7F * abstractHorseEntity.lastAngryAnimationProgress;
return new Vector3f(xzFactor * xOffset, (float) (yOffset + 0.15F * abstractHorseEntity.lastAngryAnimationProgress), xzFactor * zOffset); return new Vector3f(xzFactor * xOffset, yOffset + 0.15F * abstractHorseEntity.lastAngryAnimationProgress, xzFactor * zOffset);
} }
} }
return new Vector3f(0.0F, (float) yOffset, 0.0F); return new Vector3f(0, yOffset, 0);
} }
public static double getHeightOffset(final Entity entity) { public static double getHeightOffset(final Entity entity) {
if (entity instanceof ArmorStandEntity armorStandEntity && !armorStandEntity.isMarker()) { if (entity instanceof AllayEntity || entity instanceof VexEntity) {
return 0.1;
} else if (entity instanceof EndermiteEntity) {
return 0.1;
} else if (entity instanceof ShulkerEntity shulkerEntity) {
final var vehicleType = shulkerEntity.getVehicle().getType();
return !(shulkerEntity.getVehicle() instanceof BoatEntity) && vehicleType != EntityType.MINECART ? 0 : 0.1875 - getMountedHeightOffset(shulkerEntity.getVehicle(), null).y;
} else if (entity instanceof SilverfishEntity) {
return 0.1;
} else if (entity instanceof AllayEntity || entity instanceof VexEntity) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) {
return 0D; return 0D;
} }
return 0.4; return 0.4D;
} else if (entity instanceof ArmorStandEntity armorStandEntity) {
return armorStandEntity.isMarker() ? 0D : 0.1D;
} else if (entity instanceof EndermiteEntity) {
return 0.1D;
} else if (entity instanceof ShulkerEntity shulkerEntity) {
final EntityType<?> vehicleType = shulkerEntity.getVehicle().getType();
return !(shulkerEntity.getVehicle() instanceof BoatEntity) && vehicleType != EntityType.MINECART ? 0D : 0.1875D - getMountedHeightOffset(shulkerEntity.getVehicle(), null).y;
} else if (entity instanceof SilverfishEntity) {
return 0.1D;
} else if (entity instanceof ZombifiedPiglinEntity zombifiedPiglinEntity) { } else if (entity instanceof ZombifiedPiglinEntity zombifiedPiglinEntity) {
return zombifiedPiglinEntity.isBaby() ? -0.05 : -0.45; return zombifiedPiglinEntity.isBaby() ? -0.05D : -0.45D;
} else if (entity instanceof ZombieEntity zombieEntity) { } else if (entity instanceof ZombieEntity zombieEntity) {
return zombieEntity.isBaby() ? 0.0 : -0.45; return zombieEntity.isBaby() ? 0D : -0.45D;
} else if (entity instanceof AnimalEntity) {
return 0.14D;
} else if (entity instanceof PatrolEntity) {
return -0.45D;
} else if (entity instanceof PlayerEntity) {
return -0.35D;
} else if (entity instanceof AbstractPiglinEntity abstractPiglinEntity) {
return abstractPiglinEntity.isBaby() ? -0.05D : -0.45D;
} else if (entity instanceof AbstractSkeletonEntity) {
return -0.6D;
} }
if (entity instanceof PlayerEntity) { return 0D;
return -0.35;
} else if (entity instanceof PatrolEntity) {
return -0.45;
} else if (entity instanceof AbstractPiglinEntity abstractPiglinEntity) {
return abstractPiglinEntity.isBaby() ? -0.05 : -0.45;
} else if (entity instanceof AbstractSkeletonEntity) {
return -0.6;
} else if (entity instanceof AnimalEntity) {
return 0.14;
}
return 0;
} }
} }

View File

@ -0,0 +1,162 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes;
import de.florianmichael.viafabricplus.event.ChangeProtocolVersionCallback;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.raphimc.vialoader.util.VersionEnum;
import java.util.LinkedHashMap;
import java.util.Map;
public class EntityHitboxUpdateListener {
private static final Map<EntityType<?>, Map<VersionEnum, EntityDimensions>> ENTITY_DIMENSIONS = linkedHashMap(
EntityType.WITHER, linkedHashMap(
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.9F, 4.0F),
VersionEnum.r1_8, EntityType.WITHER.getDimensions()
),
EntityType.SILVERFISH, linkedHashMap(
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.3F, 0.7F),
VersionEnum.r1_8, EntityType.SILVERFISH.getDimensions()
),
EntityType.SNOW_GOLEM, linkedHashMap(
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.4F, 1.8F),
VersionEnum.r1_8, EntityType.SNOW_GOLEM.getDimensions()
),
EntityType.ZOMBIE, linkedHashMap(
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.6F, 1.8F),
VersionEnum.r1_8, EntityDimensions.fixed(EntityType.ZOMBIE.getDimensions().width, EntityType.ZOMBIE.getDimensions().height),
VersionEnum.r1_9, EntityType.ZOMBIE.getDimensions()
),
EntityType.CHICKEN, linkedHashMap(
VersionEnum.b1_7tob1_7_3, EntityDimensions.changing(0.3F, 0.4F),
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.3F, 0.7F),
VersionEnum.r1_8, EntityType.CHICKEN.getDimensions()
),
EntityType.SHEEP, linkedHashMap(
VersionEnum.c0_28toc0_30, EntityDimensions.changing(1.4F, 1.72F),
VersionEnum.a1_0_15, EntityType.SHEEP.getDimensions()
),
EntityType.OCELOT, linkedHashMap(
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.6F, 0.8F),
VersionEnum.r1_8, EntityType.OCELOT.getDimensions()
),
EntityType.BOAT, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(1.5F, 0.6F),
VersionEnum.r1_9, EntityType.BOAT.getDimensions()
),
EntityType.CREEPER, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(0.6F, 1.8F),
VersionEnum.r1_9, EntityType.CREEPER.getDimensions()
),
EntityType.IRON_GOLEM, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(1.4F, 2.9F),
VersionEnum.r1_9, EntityType.IRON_GOLEM.getDimensions()
),
EntityType.SKELETON, linkedHashMap(
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.6F, 1.8F),
VersionEnum.r1_8, EntityDimensions.changing(0.6F, 1.95F),
VersionEnum.r1_9, EntityType.SKELETON.getDimensions()
),
EntityType.WITHER_SKELETON, linkedHashMap(
VersionEnum.r1_4_6tor1_4_7, EntityDimensions.changing(0.72F, 2.16F),
VersionEnum.r1_7_6tor1_7_10, EntityDimensions.changing(0.72F, 2.34F),
VersionEnum.r1_8, EntityDimensions.changing(0.72F, 2.535F),
VersionEnum.r1_9, EntityType.WITHER_SKELETON.getDimensions()
),
EntityType.COW, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(0.9F, 1.3F),
VersionEnum.r1_9, EntityType.COW.getDimensions()
),
EntityType.HORSE, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(1.4F, 1.6F),
VersionEnum.r1_9, EntityType.HORSE.getDimensions()
),
EntityType.MOOSHROOM, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(0.9F, 1.3F),
VersionEnum.r1_9, EntityType.MOOSHROOM.getDimensions()
),
EntityType.RABBIT, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(0.6F, 0.7F),
VersionEnum.r1_9, EntityType.RABBIT.getDimensions()
),
EntityType.SQUID, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(0.95F, 0.95F),
VersionEnum.r1_9, EntityType.SQUID.getDimensions()
),
EntityType.VILLAGER, linkedHashMap(
VersionEnum.r1_8, EntityDimensions.changing(0.6F, 1.8F),
VersionEnum.r1_9, EntityType.VILLAGER.getDimensions()
),
EntityType.WOLF, linkedHashMap(
VersionEnum.r1_1, EntityDimensions.changing(0.8F, 0.8F),
VersionEnum.r1_8, EntityDimensions.changing(0.6F, 0.8F),
VersionEnum.r1_9, EntityType.WOLF.getDimensions()
),
EntityType.DRAGON_FIREBALL, linkedHashMap(
VersionEnum.r1_10, EntityDimensions.changing(0.3125F, 0.3125F),
VersionEnum.r1_11, EntityType.DRAGON_FIREBALL.getDimensions()
),
EntityType.LEASH_KNOT, linkedHashMap(
VersionEnum.r1_16_4tor1_16_5, EntityDimensions.changing(0.5F, 0.5F),
VersionEnum.r1_17, EntityType.LEASH_KNOT.getDimensions()
),
EntityType.SLIME, linkedHashMap(
VersionEnum.r1_13_2, EntityDimensions.changing(2F, 2F),
VersionEnum.r1_14, EntityType.SLIME.getDimensions()
),
EntityType.MAGMA_CUBE, linkedHashMap(
VersionEnum.r1_13_2, EntityDimensions.changing(2F, 2F),
VersionEnum.r1_14, EntityType.MAGMA_CUBE.getDimensions()
),
EntityType.ARROW, linkedHashMap(
VersionEnum.c0_28toc0_30, EntityDimensions.changing(0.3F, 0.5F),
VersionEnum.a1_0_15, EntityType.ARROW.getDimensions()
)
);
public static void init() {
ChangeProtocolVersionCallback.EVENT.register((oldVersion, newVersion) -> MinecraftClient.getInstance().execute(() -> ENTITY_DIMENSIONS.forEach((entityType, dimensionMap) -> {
for (Map.Entry<VersionEnum, EntityDimensions> entry : dimensionMap.entrySet()) {
final VersionEnum version = entry.getKey();
final EntityDimensions dimensions = entry.getValue();
if (oldVersion.isNewerThan(version) && newVersion.isOlderThanOrEqualTo(version)) {
entityType.dimensions = dimensions;
break;
}
if (newVersion.isNewerThanOrEqualTo(version) && oldVersion.isOlderThanOrEqualTo(version)) {
entityType.dimensions = dimensions;
}
}
})));
}
private static <K, V> Map<K, V> linkedHashMap(final Object... objects) {
if (objects.length % 2 != 0) throw new IllegalArgumentException("Uneven object count");
final Map<K, V> map = new LinkedHashMap<>();
for (int i = 0; i < objects.length; i += 2) map.put((K) objects[i], (V) objects[i + 1]);
return map;
}
}

View File

@ -0,0 +1,62 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes;
import net.minecraft.block.BlockState;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.PendingUpdateManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.BlockPos;
public class PendingUpdateManager1_18_2 extends PendingUpdateManager {
@Override
public void addPendingUpdate(BlockPos pos, BlockState state, ClientPlayerEntity player) {
}
@Override
public boolean hasPendingUpdate(BlockPos pos, BlockState state) {
return false;
}
@Override
public void processPendingUpdates(int maxProcessableSequence, ClientWorld world) {
}
@Override
public PendingUpdateManager incrementSequence() {
return this;
}
@Override
public void close() {
}
@Override
public int getSequence() {
return 0;
}
@Override
public boolean hasPendingSequence() {
return false;
}
}

View File

@ -1,66 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.resource.featuretoggle.FeatureFlags;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.text.Text;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
public class TripleChestHandler1_13_2 {
public static final Consumer<PacketByteBuf> TRIPLE_CHEST_HANDLER = data -> {
final var byteBuf = data.asByteBuf();
try {
TripleChestHandler1_13_2.handleTripleChestHandler(Type.SHORT.readPrimitive(byteBuf), Type.COMPONENT.read(byteBuf), Type.SHORT.readPrimitive(byteBuf));
} catch (Exception e) {
ViaFabricPlus.global().getLogger().error("Failed to open custom ScreenHandler with dimension 9xN", e);
}
};
public static void handleTripleChestHandler(final short windowID, final JsonElement title, final short slots) {
int n = slots / 9;
final int modulo = slots % 9;
if (modulo > 0) n++;
final var screenHandler = new AtomicReference<ScreenHandlerType<?>>();
int finalN = n;
screenHandler.set(new TripleChestScreenHandlerType((syncId, playerInventory) -> new GenericContainerScreenHandler(screenHandler.get(), syncId, playerInventory, finalN), FeatureFlags.VANILLA_FEATURES));
HandledScreens.open(screenHandler.get(), MinecraftClient.getInstance(), windowID, Text.Serializer.fromJson(title.toString()));
}
public static class TripleChestScreenHandlerType extends ScreenHandlerType<GenericContainerScreenHandler> {
public TripleChestScreenHandlerType(Factory<GenericContainerScreenHandler> factory, FeatureSet requiredFeatures) {
super(factory, requiredFeatures);
}
}
}

View File

@ -33,7 +33,7 @@ import java.util.List;
@SuppressWarnings("DataFlowIssue") @SuppressWarnings("DataFlowIssue")
public class ClassicItemSelectionScreen extends VFPScreen { public class ClassicItemSelectionScreen extends VFPScreen {
public static ClassicItemSelectionScreen INSTANCE = new ClassicItemSelectionScreen(); public static final ClassicItemSelectionScreen INSTANCE = new ClassicItemSelectionScreen();
private static final int MAX_ROW_DIVIDER = 9; private static final int MAX_ROW_DIVIDER = 9;
private static final int ITEM_XY_BOX_DIMENSION_CLASSIC = 25; private static final int ITEM_XY_BOX_DIMENSION_CLASSIC = 25;

File diff suppressed because it is too large Load Diff

View File

@ -1,106 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes.diff;
import net.minecraft.block.ConcretePowderBlock;
import net.minecraft.block.GlazedTerracottaBlock;
import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.client.MinecraftClient;
import net.minecraft.inventory.RecipeInputInventory;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket;
import net.minecraft.recipe.*;
import net.minecraft.screen.ScreenHandler;
import net.raphimc.vialoader.util.VersionEnum;
import java.util.List;
/**
* Handles all recipe related stuff for versions older than 1.12.
*/
public class RecipesPre1_12 {
/**
* Removes recipes that are not supported in 1.11 and older versions.
*
* @param recipes List of recipes
* @param version Version of the client
*/
public static void editRecipes(final List<Recipe<?>> recipes, final VersionEnum version) {
final var registryManager = MinecraftClient.getInstance().world.getRegistryManager();
recipes.removeIf(recipe -> {
if (recipe.getResult(registryManager).getItem() instanceof BlockItem block) {
return block.getBlock() instanceof ConcretePowderBlock || block.getBlock() instanceof GlazedTerracottaBlock;
}
return false;
});
if (version.isOlderThanOrEqualTo(VersionEnum.r1_11)) {
recipes.removeIf(recipe -> recipe.getResult(registryManager).getItem() == Items.IRON_NUGGET);
if (version.isOlderThanOrEqualTo(VersionEnum.r1_10)) {
recipes.removeIf(recipe -> {
Item item = recipe.getResult(registryManager).getItem();
if (item instanceof BlockItem blockItem) {
return blockItem.getBlock() instanceof ShulkerBoxBlock;
} else if (item == Items.OBSERVER || item == Items.IRON_NUGGET) {
return true;
} else if (item == Items.GOLD_NUGGET) {
return recipe.getSerializer() == RecipeSerializer.SMELTING;
} else {
return false;
}
});
}
if (version.isOlderThanOrEqualTo(VersionEnum.r1_9_3tor1_9_4)) {
recipes.removeIf(recipe -> recipe.getResult(registryManager).getItem() == Items.BONE_BLOCK);
}
}
}
/**
* Sets the result slot of a crafting screen handler to the correct item stack. In MC <= 1.11.2 the result slot
* is not updated when the input slots change, so we need to update it manually, Spigot and Paper re-syncs the slot,
* so we don't notice this bug on servers that use Spigot or Paper
*
* @param syncId The sync id of the screen handler
* @param screenHandler The screen handler
* @param inventory The inventory of the screen handler
*/
public static void setCraftingResultSlot(final int syncId, final ScreenHandler screenHandler, final RecipeInputInventory inventory) {
final var network = MinecraftClient.getInstance().getNetworkHandler();
if (network == null) return;
final var world = MinecraftClient.getInstance().world;
final var result = network.getRecipeManager().
getFirstMatch(RecipeType.CRAFTING, inventory, world). // Get the first matching recipe
map(recipe -> recipe.value().craft(inventory, world.getRegistryManager())). // Craft the recipe to get the result
orElse(ItemStack.EMPTY); // If there is no recipe, set the result to air
// Update the result slot
network.onScreenHandlerSlotUpdate(new ScreenHandlerSlotUpdateS2CPacket(syncId, screenHandler.getRevision(), 0, result));
}
}

View File

@ -0,0 +1,982 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes.diff;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntConsumer;
import net.raphimc.vialoader.util.VersionEnum;
import static java.util.stream.IntStream.rangeClosed;
import static net.raphimc.vialoader.util.VersionEnum.*;
public class RenderableGlyphDiff {
private static final Int2ObjectMap<VersionEnum> RENDERABLE_GLYPH_DIFF_LEGACY = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<VersionEnum> RENDERABLE_GLYPH_DIFF = new Int2ObjectOpenHashMap<>();
static {
rangeClosed(0, 887).forEach(putLegacy(c0_0_15a_1));
rangeClosed(890, 894).forEach(putLegacy(c0_0_15a_1));
rangeClosed(900, 906).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(908, c0_0_15a_1);
rangeClosed(910, 929).forEach(putLegacy(c0_0_15a_1));
rangeClosed(931, 1315).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1329, 1366).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1369, 1418).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(1423, c0_0_15a_1);
rangeClosed(1425, 1479).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1488, 1514).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1520, 1524).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1536, 1539).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1542, 1563).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1566, 1567).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1569, 1630).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1632, 1805).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1807, 1866).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1869, 1969).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1984, 2042).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2305, 2361).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2364, 2381).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2384, 2388).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2392, 2418).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2427, 2431).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2433, 2435).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2437, 2444).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2447, 2448).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2451, 2472).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2474, 2480).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2482, c0_0_15a_1);
rangeClosed(2486, 2489).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2492, 2500).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2503, 2504).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2507, 2510).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2519, c0_0_15a_1);
rangeClosed(2524, 2525).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2527, 2531).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2534, 2554).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2561, 2563).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2565, 2570).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2575, 2576).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2579, 2600).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2602, 2608).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2610, 2611).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2613, 2614).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2616, 2617).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2620, c0_0_15a_1);
rangeClosed(2622, 2626).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2631, 2632).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2635, 2637).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2641, c0_0_15a_1);
rangeClosed(2649, 2652).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2654, c0_0_15a_1);
rangeClosed(2662, 2677).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2689, 2691).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2693, 2701).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2703, 2705).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2707, 2728).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2730, 2736).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2738, 2739).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2741, 2745).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2748, 2757).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2759, 2761).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2763, 2765).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2768, c0_0_15a_1);
rangeClosed(2784, 2787).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2790, 2799).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2801, c0_0_15a_1);
rangeClosed(2817, 2819).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2821, 2828).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2831, 2832).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2835, 2856).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2858, 2864).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2866, 2867).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2869, 2873).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2876, 2884).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2887, 2888).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2891, 2893).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2902, 2903).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2908, 2909).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2911, 2915).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2918, 2929).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2946, 2947).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2949, 2954).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2958, 2960).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2962, 2965).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2969, 2970).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(2972, c0_0_15a_1);
rangeClosed(2974, 2975).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2979, 2980).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2984, 2986).forEach(putLegacy(c0_0_15a_1));
rangeClosed(2990, 3001).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3006, 3010).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3014, 3016).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3018, 3021).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3024, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(3031, c0_0_15a_1);
rangeClosed(3046, 3066).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3073, 3075).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3077, 3084).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3086, 3088).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3090, 3112).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3114, 3123).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3125, 3129).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3133, 3140).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3142, 3144).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3146, 3149).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3157, 3158).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3160, 3161).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3168, 3171).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3174, 3183).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3192, 3199).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3202, 3203).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3205, 3212).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3214, 3216).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3218, 3240).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3242, 3251).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3253, 3257).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3260, 3268).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3270, 3272).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3274, 3277).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3285, 3286).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3294, c0_0_15a_1);
rangeClosed(3296, 3299).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3302, 3311).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3313, 3314).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3330, 3331).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3333, 3340).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3342, 3344).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3346, 3368).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3370, 3385).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3389, 3396).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3398, 3400).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3402, 3405).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3415, c0_0_15a_1);
rangeClosed(3424, 3427).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3430, 3445).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3449, 3455).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3458, 3459).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3461, 3478).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3482, 3505).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3507, 3515).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3517, c0_0_15a_1);
rangeClosed(3520, 3526).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3530, c0_0_15a_1);
rangeClosed(3535, 3540).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3542, c0_0_15a_1);
rangeClosed(3544, 3551).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3570, 3572).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3585, 3642).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3647, 3675).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3713, 3714).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3716, c0_0_15a_1);
rangeClosed(3719, 3720).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3722, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(3725, c0_0_15a_1);
rangeClosed(3732, 3735).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3737, 3743).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3745, 3747).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3749, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(3751, c0_0_15a_1);
rangeClosed(3754, 3755).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3757, 3769).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3771, 3773).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3776, 3780).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(3782, c0_0_15a_1);
rangeClosed(3784, 3789).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3792, 3801).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3804, 3805).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3840, 3911).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3913, 3948).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3953, 3979).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3984, 3991).forEach(putLegacy(c0_0_15a_1));
rangeClosed(3993, 4028).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4030, 4044).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4046, 4052).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4096, 4249).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4254, 4293).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4304, 4348).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4352, 4441).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4447, 4514).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4520, 4601).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4608, 4680).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4682, 4685).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4688, 4694).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(4696, c0_0_15a_1);
rangeClosed(4698, 4701).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4704, 4744).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4746, 4749).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4752, 4784).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4786, 4789).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4792, 4798).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(4800, c0_0_15a_1);
rangeClosed(4802, 4805).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4808, 4822).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4824, 4880).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4882, 4885).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4888, 4954).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4959, 4988).forEach(putLegacy(c0_0_15a_1));
rangeClosed(4992, 5017).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5024, 5108).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5121, 5750).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5760, 5788).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5792, 5880).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5888, 5900).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5902, 5908).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5920, 5942).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5952, 5971).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5984, 5996).forEach(putLegacy(c0_0_15a_1));
rangeClosed(5998, 6000).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6002, 6003).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6016, 6109).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6112, 6121).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6128, 6137).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6144, 6158).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6160, 6169).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6176, 6263).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6272, 6314).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6400, 6428).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6432, 6443).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6448, 6459).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(6464, c0_0_15a_1);
rangeClosed(6468, 6509).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6512, 6516).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6528, 6569).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6576, 6601).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6608, 6617).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6622, 6683).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6686, 6687).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6912, 6987).forEach(putLegacy(c0_0_15a_1));
rangeClosed(6992, 7036).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7040, 7082).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7086, 7097).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7168, 7223).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7227, 7241).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7245, 7295).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7424, 7654).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7678, 7957).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7960, 7965).forEach(putLegacy(c0_0_15a_1));
rangeClosed(7968, 8005).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8008, 8013).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8016, 8023).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(8025, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(8027, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(8029, c0_0_15a_1);
rangeClosed(8031, 8061).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8064, 8116).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8118, 8132).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8134, 8147).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8150, 8155).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8157, 8175).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8178, 8180).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8182, 8190).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8192, 8292).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8298, 8305).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8308, 8334).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8336, 8340).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8352, 8373).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(8381, c0_0_15a_1);
rangeClosed(8400, 8432).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8448, 8527).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8531, 8584).forEach(putLegacy(c0_0_15a_1));
rangeClosed(8592, 9143).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9145, 9191).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9193, 9194).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9197, 9199).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9204, 9213).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9216, 9254).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9280, 9290).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9312, 9885).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9888, 9916).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9920, 9923).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(9935, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(9960, c0_0_15a_1);
rangeClosed(9985, 9988).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9990, 9993).forEach(putLegacy(c0_0_15a_1));
rangeClosed(9996, 10023).forEach(putLegacy(c0_0_15a_1));
rangeClosed(10025, 10061).forEach(putLegacy(c0_0_15a_1));
rangeClosed(10063, 10066).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(10070, c0_0_15a_1);
rangeClosed(10072, 10078).forEach(putLegacy(c0_0_15a_1));
rangeClosed(10081, 10132).forEach(putLegacy(c0_0_15a_1));
rangeClosed(10136, 10159).forEach(putLegacy(c0_0_15a_1));
rangeClosed(10161, 10174).forEach(putLegacy(c0_0_15a_1));
rangeClosed(10176, 10186).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(10188, c0_0_15a_1);
rangeClosed(10192, 11084).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11088, 11092).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(11096, c0_0_15a_1);
rangeClosed(11264, 11310).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11312, 11358).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11360, 11375).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11377, 11389).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11392, 11498).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11513, 11557).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11568, 11621).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(11631, c0_0_15a_1);
rangeClosed(11648, 11670).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11680, 11686).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11688, 11694).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11696, 11702).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11704, 11710).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11712, 11718).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11720, 11726).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11728, 11734).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11736, 11742).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11744, 11824).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(11829, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(11832, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(11841, c0_0_15a_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(11851, c0_0_15a_1);
rangeClosed(11904, 11929).forEach(putLegacy(c0_0_15a_1));
rangeClosed(11931, 12019).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12032, 12245).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12272, 12283).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12288, 12351).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12353, 12438).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12441, 12543).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12549, 12589).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12593, 12686).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12688, 12727).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12736, 12771).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12784, 12830).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12832, 12867).forEach(putLegacy(c0_0_15a_1));
rangeClosed(12880, 13054).forEach(putLegacy(c0_0_15a_1));
rangeClosed(13056, 19893).forEach(putLegacy(c0_0_15a_1));
rangeClosed(19904, 40899).forEach(putLegacy(c0_0_15a_1));
rangeClosed(40960, 42124).forEach(putLegacy(c0_0_15a_1));
rangeClosed(42128, 42182).forEach(putLegacy(c0_0_15a_1));
rangeClosed(42240, 42539).forEach(putLegacy(c0_0_15a_1));
rangeClosed(42560, 42591).forEach(putLegacy(c0_0_15a_1));
rangeClosed(42594, 42611).forEach(putLegacy(c0_0_15a_1));
rangeClosed(42620, 42647).forEach(putLegacy(c0_0_15a_1));
rangeClosed(42752, 42892).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(42928, c0_0_15a_1);
rangeClosed(43003, 43051).forEach(putLegacy(c0_0_15a_1));
rangeClosed(43072, 43127).forEach(putLegacy(c0_0_15a_1));
rangeClosed(43136, 43204).forEach(putLegacy(c0_0_15a_1));
rangeClosed(43214, 43225).forEach(putLegacy(c0_0_15a_1));
rangeClosed(43264, 43347).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(43359, c0_0_15a_1);
rangeClosed(43520, 43574).forEach(putLegacy(c0_0_15a_1));
rangeClosed(43584, 43597).forEach(putLegacy(c0_0_15a_1));
rangeClosed(43600, 43609).forEach(putLegacy(c0_0_15a_1));
rangeClosed(43612, 43615).forEach(putLegacy(c0_0_15a_1));
rangeClosed(44032, 55203).forEach(putLegacy(c0_0_15a_1));
rangeClosed(63744, 64045).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64048, 64106).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64112, 64217).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64256, 64262).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64275, 64279).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64285, 64310).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64312, 64316).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(64318, c0_0_15a_1);
rangeClosed(64320, 64321).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64323, 64324).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64326, 64433).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64467, 64831).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64848, 64911).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64914, 64967).forEach(putLegacy(c0_0_15a_1));
rangeClosed(64976, 65021).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65024, 65049).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65056, 65062).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65072, 65106).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65108, 65126).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65128, 65131).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65136, 65140).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65142, 65276).forEach(putLegacy(c0_0_15a_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(65279, c0_0_15a_1);
rangeClosed(65281, 65470).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65474, 65479).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65482, 65487).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65490, 65495).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65498, 65500).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65504, 65510).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65512, 65518).forEach(putLegacy(c0_0_15a_1));
rangeClosed(65529, 65535).forEach(putLegacy(c0_0_15a_1));
rangeClosed(1316, 1327).forEach(putLegacy(r1_16));
RENDERABLE_GLYPH_DIFF_LEGACY.put(4295, r1_16);
RENDERABLE_GLYPH_DIFF_LEGACY.put(4301, r1_16);
rangeClosed(4349, 4351).forEach(putLegacy(r1_16));
RENDERABLE_GLYPH_DIFF_LEGACY.put(8382, r1_16);
RENDERABLE_GLYPH_DIFF_LEGACY.put(9924, r1_16);
RENDERABLE_GLYPH_DIFF_LEGACY.put(9928, r1_16);
rangeClosed(11390, 11391).forEach(putLegacy(r1_16));
rangeClosed(42900, 42901).forEach(putLegacy(r1_16));
rangeClosed(42920, 42921).forEach(putLegacy(r1_16));
rangeClosed(42927, 42927).forEach(putLegacy(r1_16));
RENDERABLE_GLYPH_DIFF_LEGACY.put(42948, r1_16);
RENDERABLE_GLYPH_DIFF_LEGACY.put(42950, r1_16);
rangeClosed(43856, 43857).forEach(putLegacy(r1_16));
RENDERABLE_GLYPH_DIFF_LEGACY.put(43875, r1_16);
rangeClosed(66352, 66378).forEach(putLegacy(r1_16));
RENDERABLE_GLYPH_DIFF_LEGACY.put(127754, r1_16);
RENDERABLE_GLYPH_DIFF_LEGACY.put(127783, r1_16);
RENDERABLE_GLYPH_DIFF_LEGACY.put(128293, r1_16);
rangeClosed(8528, 8530).forEach(putLegacy(r1_16_2));
RENDERABLE_GLYPH_DIFF_LEGACY.put(8585, r1_16_2);
rangeClosed(11242, 11243).forEach(putLegacy(r1_16_2));
RENDERABLE_GLYPH_DIFF_LEGACY.put(127907, r1_16_2);
RENDERABLE_GLYPH_DIFF_LEGACY.put(127993, r1_16_2);
RENDERABLE_GLYPH_DIFF_LEGACY.put(128305, r1_16_2);
RENDERABLE_GLYPH_DIFF_LEGACY.put(128481, r1_16_2);
RENDERABLE_GLYPH_DIFF_LEGACY.put(128737, r1_16_2);
RENDERABLE_GLYPH_DIFF_LEGACY.put(129514, r1_16_2);
RENDERABLE_GLYPH_DIFF_LEGACY.put(129683, r1_16_2);
rangeClosed(8374, 8380).forEach(putLegacy(r1_17_1));
RENDERABLE_GLYPH_DIFF_LEGACY.put(8383, r1_17_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(9203, r1_17_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(127830, r1_17_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(128276, r1_17_1);
RENDERABLE_GLYPH_DIFF_LEGACY.put(129699, r1_17_1);
// 1.20 switch to using Unihex as a main font
rangeClosed(0, 2559).forEach(put(r1_20tor1_20_1));
rangeClosed(2561, 55295).forEach(put(r1_20tor1_20_1));
rangeClosed(61425, 61426).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(61429, r1_20tor1_20_1);
rangeClosed(63744, 65533).forEach(put(r1_20tor1_20_1));
rangeClosed(65536, 72543).forEach(put(r1_20tor1_20_1));
rangeClosed(72704, 73727).forEach(put(r1_20tor1_20_1));
rangeClosed(74650, 74751).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(74863, r1_20tor1_20_1);
rangeClosed(74869, 74879).forEach(put(r1_20tor1_20_1));
rangeClosed(75076, 77823).forEach(put(r1_20tor1_20_1));
rangeClosed(78895, 82943).forEach(put(r1_20tor1_20_1));
rangeClosed(83527, 92159).forEach(put(r1_20tor1_20_1));
rangeClosed(92729, 94207).forEach(put(r1_20tor1_20_1));
rangeClosed(100344, 100351).forEach(put(r1_20tor1_20_1));
rangeClosed(101120, 101631).forEach(put(r1_20tor1_20_1));
rangeClosed(101641, 128124).forEach(put(r1_20tor1_20_1));
rangeClosed(128126, 131069).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(131083, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131207, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131209, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131234, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131236, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131276, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131428, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131490, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131603, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131883, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131953, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(131969, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(132089, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(132170, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(132361, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(132566, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(132648, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(132726, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(132943, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(133127, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(133178, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(133305, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(133500, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(133533, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(133843, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(133917, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(134047, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(134352, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(134469, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(134625, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(134756, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(134765, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(134805, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135007, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135359, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135681, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135741, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135765, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135796, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135803, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135895, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135908, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135933, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135963, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(135990, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(136004, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(136090, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(136132, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(136211, r1_20tor1_20_1);
rangeClosed(136301, 136302).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(136663, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(136775, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(136884, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(136966, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(137026, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(137405, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(137667, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138326, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138541, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138565, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138594, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138616, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138642, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138652, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138657, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138679, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(138720, r1_20tor1_20_1);
rangeClosed(138803, 138804).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(139038, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(139126, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(139258, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(139643, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(139800, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(140062, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(140205, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(141043, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(141403, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(141483, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(141711, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(142008, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(142150, r1_20tor1_20_1);
rangeClosed(142159, 142160).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(142246, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(142365, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(142372, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(142817, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(143798, r1_20tor1_20_1);
rangeClosed(143811, 143812).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(143861, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144242, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144336, r1_20tor1_20_1);
rangeClosed(144338, 144339).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(144341, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144346, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144351, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144356, r1_20tor1_20_1);
rangeClosed(144458, 144459).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(144465, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144485, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144612, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144730, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144788, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144836, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(144843, r1_20tor1_20_1);
rangeClosed(144952, 144954).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(144967, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(145164, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(145180, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(145215, r1_20tor1_20_1);
rangeClosed(145251, 145252).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(145383, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(145407, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(145444, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(145469, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(146072, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(146559, r1_20tor1_20_1);
rangeClosed(146583, 146584).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(146686, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(146688, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(146702, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(146752, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(146899, r1_20tor1_20_1);
rangeClosed(146937, 146938).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(146979, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(147326, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(147606, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(147715, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(147910, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(147966, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(147982, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(148412, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(149033, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(149157, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(149489, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(149654, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(149737, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(149979, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150017, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150093, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150141, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150217, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150358, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150383, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150550, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(150804, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151054, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151095, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151146, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151179, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151626, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151637, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151842, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(151977, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152013, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152037, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152094, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152140, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152622, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152718, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152793, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152846, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152882, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(152930, r1_20tor1_20_1);
rangeClosed(152999, 153000).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(153457, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(153513, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(153524, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(154052, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(154068, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(154327, r1_20tor1_20_1);
rangeClosed(154339, 154340).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(154353, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(154546, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(154699, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(154724, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155041, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155182, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155209, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155222, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155234, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155237, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155330, r1_20tor1_20_1);
rangeClosed(155351, 155352).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(155368, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155427, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155484, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155604, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155616, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155643, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155660, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155671, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155744, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(155885, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(156193, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(156272, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(156294, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(156492, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(156674, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(156813, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(157302, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(157310, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(157360, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(157469, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(157564, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(157917, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(157930, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158033, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158063, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158173, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158238, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158296, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158348, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158391, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158463, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158556, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158753, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158761, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158835, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(158941, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(159296, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(159333, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(159636, r1_20tor1_20_1);
rangeClosed(159734, 159736).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(159988, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(160013, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(160057, r1_20tor1_20_1);
rangeClosed(160730, 160731).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(160766, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(160784, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(160841, r1_20tor1_20_1);
rangeClosed(161300, 161301).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(161329, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(161412, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(161427, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(161550, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(161571, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(161618, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(161970, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(162181, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(162436, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(162739, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(162750, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(162759, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(163000, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(163232, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(163344, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(163503, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(163767, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(163833, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(163978, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164027, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164471, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164482, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164595, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164813, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164872, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164876, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(164949, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(165227, r1_20tor1_20_1);
rangeClosed(165320, 165321).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(165496, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(165525, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(165591, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(165626, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(165856, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166214, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166217, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166251, r1_20tor1_20_1);
rangeClosed(166279, 166280).forEach(put(r1_20tor1_20_1));
rangeClosed(166330, 166331).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(166336, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166415, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166430, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166441, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166467, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166513, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166553, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166605, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166621, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166628, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166726, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166729, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166734, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166849, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166895, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166983, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166991, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166993, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(166996, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167184, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167281, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167419, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167439, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167455, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167478, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167561, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167577, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167659, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167730, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(167928, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(168608, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(168625, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(169104, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(169423, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(169599, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(169712, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(169753, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(169808, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(170000, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(170182, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(170610, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171477, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171483, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171541, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171581, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171593, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171658, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171716, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171739, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171753, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171902, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171907, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171916, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(171982, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(172058, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(172079, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(172162, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(172281, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(172432, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(172940, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(173111, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(173553, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(173570, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(173594, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(173746, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(174045, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(174141, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(174331, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(174359, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(174640, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(174646, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(174680, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(176034, r1_20tor1_20_1);
rangeClosed(176423, 176424).forEach(put(r1_20tor1_20_1));
rangeClosed(176439, 176440).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(176621, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(176896, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(176995, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177007, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177010, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177021, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177156, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177168, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177171, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177249, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177383, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177391, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177398, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177401, r1_20tor1_20_1);
rangeClosed(177421, 177422).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(177462, r1_20tor1_20_1);
rangeClosed(177582, 177583).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(177587, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177639, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177652, r1_20tor1_20_1);
rangeClosed(177692, 177693).forEach(put(r1_20tor1_20_1));
rangeClosed(177702, 177704).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(177706, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177708, r1_20tor1_20_1);
rangeClosed(177813, 177814).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(177837, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(177901, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178089, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178117, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178150, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178167, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178169, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178172, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178182, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178186, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178204, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178360, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178840, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(178887, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179039, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179042, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179068, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179075, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179227, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179575, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179591, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179703, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(179753, r1_20tor1_20_1);
rangeClosed(180265, 180266).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(180393, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(180426, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(180693, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(180697, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(180729, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(180860, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(180872, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(180900, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181015, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181083, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181089, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181092, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181384, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181396, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181399, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181570, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181643, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181779, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181784, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181793, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181801, r1_20tor1_20_1);
rangeClosed(181803, 181805).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(181807, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(181826, r1_20tor1_20_1);
rangeClosed(181834, 181835).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(182060, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182063, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182175, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182209, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182252, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182269, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182489, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182494, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182497, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182515, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182535, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182538, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182557, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182786, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182798, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182909, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182953, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(182994, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183081, r1_20tor1_20_1);
rangeClosed(183085, 183086).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183089, r1_20tor1_20_1);
rangeClosed(183096, 183097).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183099, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183103, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183105, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183114, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183118, r1_20tor1_20_1);
rangeClosed(183130, 183131).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183140, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183145, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183148, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183151, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183155, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183158, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183160, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183164, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183217, r1_20tor1_20_1);
rangeClosed(183231, 183232).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183246, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183382, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183391, r1_20tor1_20_1);
rangeClosed(183541, 183542).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183549, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183551, r1_20tor1_20_1);
rangeClosed(183554, 183555).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183562, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183688, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183691, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183693, r1_20tor1_20_1);
rangeClosed(183695, 183696).forEach(put(r1_20tor1_20_1));
rangeClosed(183711, 183712).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183720, r1_20tor1_20_1);
rangeClosed(183725, 183726).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(183765, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183832, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183834, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183843, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183846, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183850, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183932, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183944, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(183955, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(185218, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(185668, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(194692, r1_20tor1_20_1);
RENDERABLE_GLYPH_DIFF.put(194742, r1_20tor1_20_1);
rangeClosed(200413, 200414).forEach(put(r1_20tor1_20_1));
RENDERABLE_GLYPH_DIFF.put(200812, r1_20tor1_20_1);
rangeClosed(917504, 917631).forEach(put(r1_20tor1_20_1));
rangeClosed(917760, 917999).forEach(put(r1_20tor1_20_1));
rangeClosed(1048574, 1048575).forEach(put(r1_20tor1_20_1));
}
public static boolean isGlyphRenderable(final int codePoint) {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(r1_20tor1_20_1)) {
return RENDERABLE_GLYPH_DIFF.containsKey(codePoint) && ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(RENDERABLE_GLYPH_DIFF.get(codePoint));
}
return RENDERABLE_GLYPH_DIFF_LEGACY.containsKey(codePoint) && ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(RENDERABLE_GLYPH_DIFF_LEGACY.get(codePoint));
}
private static IntConsumer putLegacy(final VersionEnum version) {
return i -> RENDERABLE_GLYPH_DIFF_LEGACY.put(i, version);
}
private static IntConsumer put(final VersionEnum version) {
return i -> RENDERABLE_GLYPH_DIFF.put(i, version);
}
}

View File

@ -0,0 +1,183 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes.recipe;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.block.entity.BannerBlockEntity;
import net.minecraft.inventory.RecipeInputInventory;
import net.minecraft.item.BannerItem;
import net.minecraft.item.DyeItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtList;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.SpecialCraftingRecipe;
import net.minecraft.recipe.SpecialRecipeSerializer;
import net.minecraft.recipe.book.CraftingRecipeCategory;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.util.DyeColor;
import net.minecraft.world.World;
import net.raphimc.vialoader.util.VersionEnum;
public class AddBannerPatternRecipe extends SpecialCraftingRecipe {
public static final RecipeSerializer<AddBannerPatternRecipe> SERIALIZER = new SpecialRecipeSerializer<>(AddBannerPatternRecipe::new);
public AddBannerPatternRecipe(CraftingRecipeCategory craftingRecipeCategory) {
super(craftingRecipeCategory);
}
@Override
public boolean matches(RecipeInputInventory inv, World world) {
boolean foundBanner = false;
for (int i = 0; i < inv.size(); i++) {
ItemStack stack = inv.getStack(i);
if (stack.getItem() instanceof BannerItem) {
if (foundBanner)
return false;
if (BannerBlockEntity.getPatternCount(stack) >= 6)
return false;
foundBanner = true;
}
}
return foundBanner && getBannerPattern(inv) != null;
}
@Override
public ItemStack craft(RecipeInputInventory inv, DynamicRegistryManager registryManager) {
ItemStack result = ItemStack.EMPTY;
for (int i = 0; i < inv.size(); i++) {
ItemStack stack = inv.getStack(i);
if (!stack.isEmpty() && stack.getItem() instanceof BannerItem) {
result = stack.copy();
result.setCount(1);
break;
}
}
BannerPattern_1_13_2 pattern = getBannerPattern(inv);
if (pattern != null) {
DyeColor color = ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2) ? DyeColor.BLACK : DyeColor.WHITE;
for (int i = 0; i < inv.size(); i++) {
Item item = inv.getStack(i).getItem();
if (item instanceof DyeItem dyeItem) {
color = dyeItem.getColor();
}
}
NbtCompound tileEntityNbt = result.getOrCreateSubNbt("BlockEntityTag");
NbtList patterns;
if (tileEntityNbt.contains("Patterns", 9)) {
patterns = tileEntityNbt.getList("Patterns", 10);
} else {
patterns = new NbtList();
tileEntityNbt.put("Patterns", patterns);
}
NbtCompound patternNbt = new NbtCompound();
patternNbt.putString("Pattern", pattern.getId());
patternNbt.putInt("Color", color.getId());
patterns.add(patternNbt);
}
return result;
}
@Override
public boolean fits(int width, int height) {
return width >= 3 && height >= 3;
}
@Override
public RecipeSerializer<AddBannerPatternRecipe> getSerializer() {
return SERIALIZER;
}
private static BannerPattern_1_13_2 getBannerPattern(RecipeInputInventory inv) {
for (BannerPattern_1_13_2 pattern : BannerPattern_1_13_2.values()) {
if (!pattern.isCraftable())
continue;
boolean matches = true;
if (pattern.hasBaseStack()) {
boolean foundBaseItem = false;
boolean foundDye = false;
for (int i = 0; i < inv.size(); i++) {
ItemStack stack = inv.getStack(i);
if (!stack.isEmpty() && !(stack.getItem() instanceof BannerItem)) {
if (stack.getItem() instanceof DyeItem) {
if (foundDye) {
matches = false;
break;
}
foundDye = true;
} else {
if (foundBaseItem || !(!stack.isEmpty() && ItemStack.areItemsEqual(stack, pattern.getBaseStack()))) {
matches = false;
break;
}
foundBaseItem = true;
}
}
}
if (!foundBaseItem || (!foundDye && ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_10))) matches = false;
} else if (inv.size() == pattern.getRecipePattern().length * pattern.getRecipePattern()[0].length()) {
DyeColor patternColor = null;
for (int i = 0; i < inv.size(); i++) {
int row = i / 3;
int col = i % 3;
ItemStack stack = inv.getStack(i);
Item item = stack.getItem();
if (!stack.isEmpty() && !(item instanceof BannerItem)) {
if (!(item instanceof DyeItem)) {
matches = false;
break;
}
DyeColor color = ((DyeItem) item).getColor();
if (patternColor != null && color != patternColor) {
matches = false;
break;
}
if (pattern.getRecipePattern()[row].charAt(col) == ' ') {
matches = false;
break;
}
patternColor = color;
} else if (pattern.getRecipePattern()[row].charAt(col) != ' ') {
matches = false;
break;
}
}
} else {
matches = false;
}
if (matches)
return pattern;
}
return null;
}
}

View File

@ -0,0 +1,112 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes.recipe;
import net.minecraft.block.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
// safe from vanilla modification + removal of recipes
public enum BannerPattern_1_13_2 {
BASE("b"),
SQUARE_BOTTOM_LEFT("bl", " ", " ", "# "),
SQUARE_BOTTOM_RIGHT("br", " ", " ", " #"),
SQUARE_TOP_LEFT("tl", "# ", " ", " "),
SQUARE_TOP_RIGHT("tr", " #", " ", " "),
STRIPE_BOTTOM("bs", " ", " ", "###"),
STRIPE_TOP("ts", "###", " ", " "),
STRIPE_LEFT("ls", "# ", "# ", "# "),
STRIPE_RIGHT("rs", " #", " #", " #"),
STRIPE_CENTER("cs", " # ", " # ", " # "),
STRIPE_MIDDLE("ms", " ", "###", " "),
STRIPE_DOWNRIGHT("drs", "# ", " # ", " #"),
STRIPE_DOWNLEFT("dls", " #", " # ", "# "),
STRIPE_SMALL("ss", "# #", "# #", " "),
CROSS("cr", "# #", " # ", "# #"),
STRAIGHT_CROSS("sc", " # ", "###", " # "),
TRIANGLE_BOTTOM("bt", " ", " # ", "# #"),
TRIANGLE_TOP("tt", "# #", " # ", " "),
TRIANGLES_BOTTOM("bts", " ", "# #", " # "),
TRIANGLES_TOP("tts", " # ", "# #", " "),
DIAGONAL_LEFT("ld", "## ", "# ", " "),
DIAGONAL_RIGHT("rd", " ", " #", " ##"),
DIAGONAL_LEFT_MIRROR("lud", " ", "# ", "## "),
DIAGONAL_RIGHT_MIRROR("rud", " ##", " #", " "),
CIRCLE_MIDDLE("mc", " ", " # ", " "),
RHOMBUS_MIDDLE("mr", " # ", "# #", " # "),
HALF_VERTICAL("vh", "## ", "## ", "## "),
HALF_HORIZONTAL("hh", "###", "###", " "),
HALF_VERTICAL_MIRROR("vhr", " ##", " ##", " ##"),
HALF_HORIZONTAL_MIRROR("hhb", " ", "###", "###"),
BORDER("bo", "###", "# #", "###"),
CURLY_BORDER("cbo", new ItemStack(Blocks.VINE)),
GRADIENT("gra", "# #", " # ", " # "),
GRADIENT_UP("gru", " # ", " # ", "# #"),
BRICKS("bri", new ItemStack(Blocks.BRICKS)),
GLOBE("glb"),
CREEPER("cre", new ItemStack(Items.CREEPER_HEAD)),
SKULL("sku", new ItemStack(Items.WITHER_SKELETON_SKULL)),
FLOWER("flo", new ItemStack(Blocks.OXEYE_DAISY)),
MOJANG("moj", new ItemStack(Items.ENCHANTED_GOLDEN_APPLE));
private final String id;
private final String[] recipePattern;
private ItemStack baseStack;
BannerPattern_1_13_2(String id) {
this.recipePattern = new String[3];
this.baseStack = ItemStack.EMPTY;
this.id = id;
}
BannerPattern_1_13_2(String id, ItemStack baseStack) {
this(id);
this.baseStack = baseStack;
}
BannerPattern_1_13_2(String id, String recipe1, String recipe2, String recipe3) {
this(id);
this.recipePattern[0] = recipe1;
this.recipePattern[1] = recipe2;
this.recipePattern[2] = recipe3;
}
public String getId() {
return this.id;
}
public boolean isCraftable() {
return !this.baseStack.isEmpty() || this.recipePattern[0] != null;
}
public boolean hasBaseStack() {
return !this.baseStack.isEmpty();
}
public ItemStack getBaseStack() {
return this.baseStack;
}
public String[] getRecipePattern() {
return this.recipePattern;
}
}

View File

@ -0,0 +1,217 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes.recipe;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.*;
import net.minecraft.recipe.book.CookingRecipeCategory;
import net.minecraft.recipe.book.CraftingRecipeCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.collection.DefaultedList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Supplier;
public final class RecipeInfo<T extends Recipe<?>> {
private final Supplier<Recipe<?>> creator;
private final RecipeSerializer<T> recipeType;
private final ItemStack output;
private String distinguisher = "";
private RecipeInfo(Supplier<Recipe<?>> creator, RecipeSerializer<T> recipeType, ItemStack output) {
this.creator = creator;
this.recipeType = recipeType;
this.output = output;
}
public static <T extends Recipe<?>> RecipeInfo<T> of(Supplier<Recipe<?>> creator, RecipeSerializer<T> recipeType, ItemStack output) {
return new RecipeInfo<>(creator, recipeType, output);
}
public static <T extends Recipe<?>> RecipeInfo<T> of(Supplier<Recipe<?>> creator, RecipeSerializer<T> recipeType, ItemConvertible output) {
return of(creator, recipeType, new ItemStack(output));
}
public static <T extends Recipe<?>> RecipeInfo<T> of(Supplier<Recipe<?>> creator, RecipeSerializer<T> recipeType, ItemConvertible output, int count) {
return of(creator, recipeType, new ItemStack(output, count));
}
public static RecipeInfo<ShapedRecipe> shaped(ItemStack output, Object... args) {
return shaped("", output, args);
}
public static RecipeInfo<ShapedRecipe> shaped(ItemConvertible output, Object... args) {
return shaped("", output, args);
}
public static RecipeInfo<ShapedRecipe> shaped(int count, ItemConvertible output, Object... args) {
return shaped("", count, output, args);
}
public static RecipeInfo<ShapedRecipe> shaped(String group, ItemStack output, Object... args) {
int i;
int width = 0;
List<String> shape = new ArrayList<>();
for (i = 0; i < args.length && args[i] instanceof String str; i++) {
if (i == 0)
width = str.length();
else if (str.length() != width)
throw new IllegalArgumentException("Rows do not have consistent width");
shape.add(str);
}
var legend = new HashMap<Character, Ingredient>();
while (i < args.length && args[i] instanceof Character key) {
i++;
List<ItemConvertible> items = new ArrayList<>();
for (; i < args.length && args[i] instanceof ItemConvertible; i++) {
items.add((ItemConvertible) args[i]);
}
legend.put(key, Ingredient.ofItems(items.toArray(new ItemConvertible[0])));
}
if (i != args.length)
throw new IllegalArgumentException("Unexpected argument at index " + i + ": " + args[i]);
int height = shape.size();
DefaultedList<Ingredient> ingredients = DefaultedList.of();
for (String row : shape) {
for (int x = 0; x < width; x++) {
char key = row.charAt(x);
Ingredient ingredient = legend.get(key);
if (ingredient == null) {
if (key == ' ')
ingredient = Ingredient.EMPTY;
else
throw new IllegalArgumentException("Unknown character in shape: " + key);
}
ingredients.add(ingredient);
}
}
final int width_f = width;
return new RecipeInfo<>(() -> new ShapedRecipe(group, CraftingRecipeCategory.MISC, width_f, height, ingredients, output), RecipeSerializer.SHAPED, output);
}
public static RecipeInfo<ShapedRecipe> shaped(String group, ItemConvertible output, Object... args) {
return shaped(group, new ItemStack(output), args);
}
public static RecipeInfo<ShapedRecipe> shaped(String group, int count, ItemConvertible output, Object... args) {
return shaped(group, new ItemStack(output, count), args);
}
public static RecipeInfo<ShapelessRecipe> shapeless(String group, ItemStack output, ItemConvertible... inputs) {
ItemConvertible[][] newInputs = new ItemConvertible[inputs.length][1];
for (int i = 0; i < inputs.length; i++)
newInputs[i] = new ItemConvertible[]{inputs[i]};
return shapeless(group, output, newInputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(String group, ItemConvertible output, ItemConvertible... inputs) {
return shapeless(group, new ItemStack(output), inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(String group, int count, ItemConvertible output, ItemConvertible... inputs) {
return shapeless(group, new ItemStack(output, count), inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(String group, ItemStack output, ItemConvertible[]... inputs) {
DefaultedList<Ingredient> ingredients = DefaultedList.of();
for (ItemConvertible[] input : inputs) {
ingredients.add(Ingredient.ofItems(input));
}
return new RecipeInfo<>(() -> new ShapelessRecipe(group, CraftingRecipeCategory.MISC, output, ingredients), RecipeSerializer.SHAPELESS, output);
}
public static RecipeInfo<ShapelessRecipe> shapeless(String group, ItemConvertible output, ItemConvertible[]... inputs) {
return shapeless(group, new ItemStack(output), inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(String group, int count, ItemConvertible output, ItemConvertible[]... inputs) {
return shapeless(group, new ItemStack(output, count), inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(ItemStack output, ItemConvertible... inputs) {
return shapeless("", output, inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(ItemConvertible output, ItemConvertible... inputs) {
return shapeless("", output, inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(int count, ItemConvertible output, ItemConvertible... inputs) {
return shapeless("", count, output, inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(ItemStack output, ItemConvertible[]... inputs) {
return shapeless("", output, inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(ItemConvertible output, ItemConvertible[]... inputs) {
return shapeless("", output, inputs);
}
public static RecipeInfo<ShapelessRecipe> shapeless(int count, ItemConvertible output, ItemConvertible[]... inputs) {
return shapeless("", count, output, inputs);
}
public static RecipeInfo<SmeltingRecipe> smelting(ItemConvertible output, ItemConvertible input, float experience) {
return smelting(output, input, experience, 200);
}
public static RecipeInfo<SmeltingRecipe> smelting(ItemConvertible output, Ingredient input, float experience) {
return smelting(output, input, experience, 200);
}
public static RecipeInfo<SmeltingRecipe> smelting(ItemConvertible output, ItemConvertible input, float experience, int cookTime) {
return smelting(output, Ingredient.ofItems(input), experience, cookTime);
}
public static RecipeInfo<SmeltingRecipe> smelting(ItemConvertible output, Ingredient input, float experience, int cookTime) {
ItemStack outputStack = new ItemStack(output);
return new RecipeInfo<>(() -> new SmeltingRecipe("", CookingRecipeCategory.MISC, input, outputStack, experience, cookTime), RecipeSerializer.SMELTING, outputStack);
}
public RecipeInfo<T> distinguisher(String distinguisher) {
this.distinguisher = distinguisher;
return this;
}
public RecipeEntry<?> create(Identifier id) {
return new RecipeEntry<Recipe<?>>(id, this.creator.get());
}
public RecipeSerializer<T> getRecipeType() {
return this.recipeType;
}
public ItemStack getOutput() {
return this.output;
}
public String getDistinguisher() {
return this.distinguisher;
}
}

View File

@ -0,0 +1,713 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.fixes.recipe;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.inventory.RecipeInputInventory;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket;
import net.minecraft.recipe.*;
import net.minecraft.recipe.book.CraftingRecipeCategory;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.screen.ScreenHandler;
import net.raphimc.vialoader.util.VersionEnum;
import java.util.ArrayList;
import java.util.List;
public class Recipes1_11_2 {
public static List<RecipeInfo<?>> getRecipes() {
final List<RecipeInfo<?>> recipes = new ArrayList<>();
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_4_2)) {
recipes.add(RecipeInfo.of(() -> new ArmorDyeRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.ARMOR_DYE, Items.LEATHER_HELMET));
recipes.add(RecipeInfo.of(() -> new MapCloningRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.MAP_CLONING, Items.FILLED_MAP, 2));
recipes.add(RecipeInfo.of(() -> new MapExtendingRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.MAP_EXTENDING, Items.FILLED_MAP));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_4_6tor1_4_7)) {
recipes.add(RecipeInfo.of(() -> new FireworkRocketRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.FIREWORK_ROCKET, Items.FIREWORK_ROCKET));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_11)) {
recipes.add(RecipeInfo.of(() -> new ShulkerBoxColoringRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.SHULKER_BOX, Items.WHITE_SHULKER_BOX));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_9)) {
recipes.add(RecipeInfo.of(() -> new TippedArrowRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.TIPPED_ARROW, Items.TIPPED_ARROW));
recipes.add(RecipeInfo.of(() -> new ShieldDecorationRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.SHIELD_DECORATION, Items.SHIELD));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) {
recipes.add(RecipeInfo.of(() -> new RepairItemRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.REPAIR_ITEM, Items.WOODEN_SWORD));
recipes.add(RecipeInfo.of(() -> new BannerDuplicateRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.BANNER_DUPLICATE, Items.WHITE_BANNER, 2));
recipes.add(RecipeInfo.of(() -> new AddBannerPatternRecipe(CraftingRecipeCategory.MISC), AddBannerPatternRecipe.SERIALIZER, Items.WHITE_BANNER));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
recipes.add(RecipeInfo.of(() -> new BookCloningRecipe(CraftingRecipeCategory.MISC), RecipeSerializer.BOOK_CLONING, Items.WRITABLE_BOOK, 2));
}
recipes.add(RecipeInfo.shaped(Items.WOODEN_SWORD, "X", "X", "#", '#', Items.STICK, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.WOODEN_SHOVEL, "X", "#", "#", '#', Items.STICK, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.WOODEN_PICKAXE, "XXX", " # ", " # ", '#', Items.STICK, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.WOODEN_HOE, "XX", " #", " #", '#', Items.STICK, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.WOODEN_AXE, "XX", "X#", " #", '#', Items.STICK, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.STONE_SWORD, "X", "X", "#", '#', Items.STICK, 'X', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(4, Blocks.COBBLESTONE_STAIRS, "# ", "## ", "###", '#', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Items.STONE_SHOVEL, "X", "#", "#", '#', Items.STICK, 'X', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Items.STONE_PICKAXE, "XXX", " # ", " # ", '#', Items.STICK, 'X', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Items.STONE_HOE, "XX", " #", " #", '#', Items.STICK, 'X', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Blocks.STONE_BUTTON, "#", '#', Blocks.STONE));
recipes.add(RecipeInfo.shaped(Items.STONE_AXE, "XX", "X#", " #", '#', Items.STICK, 'X', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(4, Items.STICK, "#", "#", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Blocks.SNOW_BLOCK, "##", "##", '#', Items.SNOWBALL));
recipes.add(RecipeInfo.shaped(Blocks.REDSTONE_TORCH, "X", "#", '#', Items.STICK, 'X', Blocks.REDSTONE_WIRE));
recipes.add(RecipeInfo.shaped(16, Blocks.RAIL, "X X", "X#X", "X X", '#', Items.STICK, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(3, Items.PAPER, "###", '#', Blocks.SUGAR_CANE));
recipes.add(RecipeInfo.shaped(Items.PAINTING, "###", "#X#", "###", '#', Items.STICK, 'X', Blocks.WHITE_WOOL, Blocks.ORANGE_WOOL, Blocks.MAGENTA_WOOL, Blocks.LIGHT_BLUE_WOOL, Blocks.YELLOW_WOOL, Blocks.LIME_WOOL, Blocks.PINK_WOOL, Blocks.GRAY_WOOL, Blocks.LIGHT_GRAY_WOOL, Blocks.CYAN_WOOL, Blocks.PURPLE_WOOL, Blocks.BLUE_WOOL, Blocks.BROWN_WOOL, Blocks.GREEN_WOOL, Blocks.RED_WOOL, Blocks.BLACK_WOOL));
recipes.add(RecipeInfo.shaped("wooden_stairs", 4, Blocks.OAK_STAIRS, "# ", "## ", "###", '#', Blocks.OAK_PLANKS));
recipes.add(RecipeInfo.shaped("planks", 4, Blocks.OAK_PLANKS, "#", '#', Blocks.OAK_LOG));
recipes.add(RecipeInfo.shaped(Items.MINECART, "# #", "###", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.LEVER, "X", "#", '#', Blocks.COBBLESTONE, 'X', Items.STICK));
recipes.add(RecipeInfo.shaped(Items.LEATHER_LEGGINGS, "XXX", "X X", "X X", 'X', Items.LEATHER));
recipes.add(RecipeInfo.shaped(Items.LEATHER_HELMET, "XXX", "X X", 'X', Items.LEATHER));
recipes.add(RecipeInfo.shaped(Items.LEATHER_CHESTPLATE, "X X", "XXX", "XXX", 'X', Items.LEATHER));
recipes.add(RecipeInfo.shaped(Items.LEATHER_BOOTS, "X X", "X X", 'X', Items.LEATHER));
recipes.add(RecipeInfo.shaped(Blocks.JUKEBOX, "###", "#X#", "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.IRON_SWORD, "X", "X", "#", '#', Items.STICK, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.IRON_SHOVEL, "X", "#", "#", '#', Items.STICK, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.IRON_PICKAXE, "XXX", " # ", " # ", '#', Items.STICK, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.IRON_LEGGINGS, "XXX", "X X", "X X", 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped("iron_ingot", 9, Items.IRON_INGOT, "#", '#', Blocks.IRON_BLOCK));
recipes.add(RecipeInfo.shaped(Items.IRON_HOE, "XX", " #", " #", '#', Items.STICK, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.IRON_HELMET, "XXX", "X X", 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.IRON_CHESTPLATE, "X X", "XXX", "XXX", 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.IRON_BOOTS, "X X", "X X", 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.IRON_BLOCK, "###", "###", "###", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.IRON_AXE, "XX", "X#", " #", '#', Items.STICK, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_SWORD, "X", "X", "#", '#', Items.STICK, 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_SHOVEL, "X", "#", "#", '#', Items.STICK, 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_PICKAXE, "XXX", " # ", " # ", '#', Items.STICK, 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_LEGGINGS, "XXX", "X X", "X X", 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_HOE, "XX", " #", " #", '#', Items.STICK, 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_HELMET, "XXX", "X X", 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_CHESTPLATE, "X X", "XXX", "XXX", 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_BOOTS, "X X", "X X", 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_AXE, "XX", "X#", " #", '#', Items.STICK, 'X', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped("gold_ingot", 9, Items.GOLD_INGOT, "#", '#', Blocks.GOLD_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.GOLD_BLOCK, "###", "###", "###", '#', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Items.FURNACE_MINECART, "A", "B", 'A', Blocks.FURNACE, 'B', Items.MINECART));
recipes.add(RecipeInfo.shaped(Blocks.FURNACE, "###", "# #", "###", '#', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_SWORD, "X", "X", "#", '#', Items.STICK, 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_SHOVEL, "X", "#", "#", '#', Items.STICK, 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_PICKAXE, "XXX", " # ", " # ", '#', Items.STICK, 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_LEGGINGS, "XXX", "X X", "X X", 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_HOE, "XX", " #", " #", '#', Items.STICK, 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_HELMET, "XXX", "X X", 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_CHESTPLATE, "X X", "XXX", "XXX", 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_BOOTS, "X X", "X X", 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Blocks.DIAMOND_BLOCK, "###", "###", "###", '#', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(Items.DIAMOND_AXE, "XX", "X#", " #", '#', Items.STICK, 'X', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(9, Items.DIAMOND, "#", '#', Blocks.DIAMOND_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.CRAFTING_TABLE, "##", "##", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Blocks.CLAY, "##", "##", '#', Items.CLAY_BALL));
recipes.add(RecipeInfo.shaped(Items.CHEST_MINECART, "A", "B", 'A', Blocks.CHEST, 'B', Items.MINECART));
recipes.add(RecipeInfo.shaped(Blocks.CHEST, "###", "# #", "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.BUCKET, "# #", " # ", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.BRICKS, "##", "##", '#', Items.BRICK));
recipes.add(RecipeInfo.shaped(Items.BREAD, "###", '#', Items.WHEAT));
recipes.add(RecipeInfo.shaped(4, Items.BOWL, "# #", " # ", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.BOW, " #X", "# X", " #X", '#', Items.STICK, 'X', Blocks.TRIPWIRE));
recipes.add(RecipeInfo.shaped(Blocks.BOOKSHELF, "###", "XXX", "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'X', Items.BOOK));
recipes.add(RecipeInfo.shaped(4, Items.ARROW, "X", "#", "Y", '#', Items.STICK, 'X', Items.FLINT, 'Y', Items.FEATHER));
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_12)) {
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.YELLOW_CONCRETE_POWDER, Items.YELLOW_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.WHITE_CONCRETE_POWDER, Items.BONE_MEAL, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.RED_CONCRETE_POWDER, Items.RED_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.PURPLE_CONCRETE_POWDER, Items.PURPLE_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.PINK_CONCRETE_POWDER, Items.PINK_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.ORANGE_CONCRETE_POWDER, Items.ORANGE_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.MAGENTA_CONCRETE_POWDER, Items.MAGENTA_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.LIME_CONCRETE_POWDER, Items.LIME_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.LIGHT_GRAY_CONCRETE_POWDER, Items.LIGHT_GRAY_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.LIGHT_BLUE_CONCRETE_POWDER, Items.LIGHT_BLUE_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.GREEN_CONCRETE_POWDER, Items.GREEN_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.GRAY_CONCRETE_POWDER, Items.GRAY_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.CYAN_CONCRETE_POWDER, Items.CYAN_DYE, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.BROWN_CONCRETE_POWDER, Blocks.COCOA, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.BLUE_CONCRETE_POWDER, Items.LAPIS_LAZULI, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("concrete_powder", 8, Blocks.BLACK_CONCRETE_POWDER, Items.INK_SAC, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.SAND, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL, Blocks.GRAVEL));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.YELLOW_BED, Blocks.WHITE_BED, Items.YELLOW_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.RED_BED, Blocks.WHITE_BED, Items.RED_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.PURPLE_BED, Blocks.WHITE_BED, Items.PURPLE_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.PINK_BED, Blocks.WHITE_BED, Items.PINK_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.ORANGE_BED, Blocks.WHITE_BED, Items.ORANGE_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.MAGENTA_BED, Blocks.WHITE_BED, Items.MAGENTA_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.LIME_BED, Blocks.WHITE_BED, Items.LIME_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.LIGHT_GRAY_BED, Blocks.WHITE_BED, Items.LIGHT_GRAY_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.LIGHT_BLUE_BED, Blocks.WHITE_BED, Items.LIGHT_BLUE_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.GREEN_BED, Blocks.WHITE_BED, Items.GREEN_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.GRAY_BED, Blocks.WHITE_BED, Items.GRAY_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.CYAN_BED, Blocks.WHITE_BED, Items.CYAN_DYE));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.BROWN_BED, Blocks.WHITE_BED, Blocks.COCOA));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.BLUE_BED, Blocks.WHITE_BED, Items.LAPIS_LAZULI));
recipes.add(RecipeInfo.shapeless("dyed_bed", Blocks.BLACK_BED, Blocks.WHITE_BED, Items.INK_SAC));
recipes.add(RecipeInfo.shaped("bed", Blocks.YELLOW_BED, "###", "XXX", '#', Blocks.YELLOW_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.WHITE_BED, "###", "XXX", '#', Blocks.WHITE_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.RED_BED, "###", "XXX", '#', Blocks.RED_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.PURPLE_BED, "###", "XXX", '#', Blocks.PURPLE_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.PINK_BED, "###", "XXX", '#', Blocks.PINK_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.ORANGE_BED, "###", "XXX", '#', Blocks.ORANGE_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.MAGENTA_BED, "###", "XXX", '#', Blocks.MAGENTA_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.LIME_BED, "###", "XXX", '#', Blocks.LIME_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.LIGHT_GRAY_BED, "###", "XXX", '#', Blocks.LIGHT_GRAY_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.LIGHT_BLUE_BED, "###", "XXX", '#', Blocks.LIGHT_BLUE_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.GREEN_BED, "###", "XXX", '#', Blocks.GREEN_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.GRAY_BED, "###", "XXX", '#', Blocks.GRAY_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.CYAN_BED, "###", "XXX", '#', Blocks.CYAN_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.BROWN_BED, "###", "XXX", '#', Blocks.BROWN_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.BLUE_BED, "###", "XXX", '#', Blocks.BLUE_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("bed", Blocks.BLACK_BED, "###", "XXX", '#', Blocks.BLACK_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
} else {
recipes.add(RecipeInfo.shapeless(Blocks.WHITE_WOOL, Blocks.WHITE_WOOL, Items.BONE_MEAL));
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_3tob1_3_1)) {
recipes.add(RecipeInfo.shaped("bed", Blocks.RED_BED, "###", "XXX", '#', Blocks.YELLOW_WOOL, Blocks.BLACK_WOOL, Blocks.BLUE_WOOL, Blocks.BROWN_WOOL, Blocks.CYAN_WOOL, Blocks.GRAY_WOOL, Blocks.GREEN_WOOL, Blocks.LIGHT_BLUE_WOOL, Blocks.LIGHT_GRAY_WOOL, Blocks.WHITE_WOOL, Blocks.RED_WOOL, Blocks.PURPLE_WOOL, Blocks.PINK_WOOL, Blocks.ORANGE_WOOL, Blocks.LIME_WOOL, Blocks.MAGENTA_WOOL, 'X', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
}
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) {
recipes.add(RecipeInfo.shaped(9, Items.IRON_NUGGET, "#", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped("iron_ingot", Items.IRON_INGOT, "###", "###", "###", '#', Items.IRON_NUGGET).distinguisher("iron_nugget_to_ingot"));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_11)) {
recipes.add(RecipeInfo.shaped(Blocks.OBSERVER, "###", "RRQ", "###", 'Q', Items.QUARTZ, 'R', Blocks.REDSTONE_WIRE, '#', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Blocks.PURPLE_SHULKER_BOX, "-", "#", "-", '#', Blocks.CHEST, '-', Items.SHULKER_SHELL));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_10)) {
recipes.add(RecipeInfo.shapeless("bonemeal", 9, Items.BONE_MEAL, Blocks.BONE_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.BONE_BLOCK, "XXX", "XXX", "XXX", 'X', Items.BONE_MEAL));
recipes.add(RecipeInfo.shaped(Blocks.MAGMA_BLOCK, "##", "##", '#', Items.MAGMA_CREAM));
recipes.add(RecipeInfo.shaped(Blocks.NETHER_WART_BLOCK, "###", "###", "###", '#', Blocks.NETHER_WART));
recipes.add(RecipeInfo.shaped(Blocks.RED_NETHER_BRICKS, "NW", "WN", 'W', Blocks.NETHER_WART, 'N', Items.NETHER_BRICK));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_9)) {
recipes.add(RecipeInfo.shapeless(Blocks.TRAPPED_CHEST, Blocks.CHEST, Blocks.TRIPWIRE_HOOK));
recipes.add(RecipeInfo.shaped(Items.SHIELD, "WoW", "WWW", " W ", 'W', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'o', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(4, Blocks.PURPUR_BLOCK, "FF", "FF", 'F', Items.POPPED_CHORUS_FRUIT));
recipes.add(RecipeInfo.shaped(6, Blocks.PURPUR_SLAB, "###", '#', Blocks.PURPUR_BLOCK));
recipes.add(RecipeInfo.shaped(4, Blocks.PURPUR_STAIRS, "# ", "## ", "###", '#', Blocks.PURPUR_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.PURPUR_PILLAR, "#", "#", '#', Blocks.PURPUR_SLAB));
recipes.add(RecipeInfo.shaped(4, Blocks.END_STONE_BRICKS, "##", "##", '#', Blocks.END_STONE));
recipes.add(RecipeInfo.shaped("boat", Items.SPRUCE_BOAT, "# #", "###", '#', Blocks.SPRUCE_PLANKS));
recipes.add(RecipeInfo.shaped("boat", Items.JUNGLE_BOAT, "# #", "###", '#', Blocks.JUNGLE_PLANKS));
recipes.add(RecipeInfo.shaped("boat", Items.OAK_BOAT, "# #", "###", '#', Blocks.OAK_PLANKS));
recipes.add(RecipeInfo.shaped("boat", Items.DARK_OAK_BOAT, "# #", "###", '#', Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("boat", Items.BIRCH_BOAT, "# #", "###", '#', Blocks.BIRCH_PLANKS));
recipes.add(RecipeInfo.shaped("boat", Items.ACACIA_BOAT, "# #", "###", '#', Blocks.ACACIA_PLANKS));
recipes.add(RecipeInfo.shaped(4, Blocks.END_ROD, "/", "#", '#', Items.POPPED_CHORUS_FRUIT, '/', Items.BLAZE_ROD));
recipes.add(RecipeInfo.shaped(Items.END_CRYSTAL, "GGG", "GEG", "GTG", 'T', Items.GHAST_TEAR, 'E', Items.ENDER_EYE, 'G', Blocks.GLASS));
recipes.add(RecipeInfo.shaped(2, Items.SPECTRAL_ARROW, " # ", "#X#", " # ", '#', Items.GLOWSTONE_DUST, 'X', Items.ARROW));
recipes.add(RecipeInfo.shapeless("red_dye", Items.RED_DYE, Items.BEETROOT));
recipes.add(RecipeInfo.shaped(Items.BEETROOT_SOUP, "OOO", "OOO", " B ", 'B', Items.BOWL, 'O', Items.BEETROOT));
} else {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_5tor1_5_1)) {
recipes.add(RecipeInfo.shaped(Blocks.TRAPPED_CHEST, "#-", '#', Blocks.CHEST, '-', Blocks.TRIPWIRE_HOOK));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_3_1tor1_3_2)) {
recipes.add(RecipeInfo.shaped(Items.ENCHANTED_GOLDEN_APPLE, "###", "#X#", "###", '#', Items.GOLD_BLOCK, 'X', Items.APPLE));
}
recipes.add(RecipeInfo.shaped("boat", Items.OAK_BOAT, "# #", "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.DARK_OAK_PLANKS, Blocks.BIRCH_PLANKS, Blocks.ACACIA_PLANKS));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) {
recipes.add(RecipeInfo.shapeless(Blocks.MOSSY_COBBLESTONE, Blocks.COBBLESTONE, Blocks.VINE));
recipes.add(RecipeInfo.shapeless(Blocks.MOSSY_STONE_BRICKS, Blocks.STONE_BRICKS, Blocks.VINE));
recipes.add(RecipeInfo.shaped(Blocks.CHISELED_STONE_BRICKS, "#", "#", '#', Blocks.STONE_BRICK_SLAB));
recipes.add(RecipeInfo.shaped(4, Blocks.COARSE_DIRT, "DG", "GD", 'D', Blocks.DIRT, 'G', Blocks.GRAVEL));
recipes.add(RecipeInfo.shaped("wooden_fence", 3, Blocks.SPRUCE_FENCE, "W#W", "W#W", '#', Items.STICK, 'W', Blocks.SPRUCE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence", 3, Blocks.JUNGLE_FENCE, "W#W", "W#W", '#', Items.STICK, 'W', Blocks.JUNGLE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence", 3, Blocks.OAK_FENCE, "W#W", "W#W", '#', Items.STICK, 'W', Blocks.OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence", 3, Blocks.DARK_OAK_FENCE, "W#W", "W#W", '#', Items.STICK, 'W', Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence", 3, Blocks.BIRCH_FENCE, "W#W", "W#W", '#', Items.STICK, 'W', Blocks.BIRCH_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence", 3, Blocks.ACACIA_FENCE, "W#W", "W#W", '#', Items.STICK, 'W', Blocks.ACACIA_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence_gate", Blocks.SPRUCE_FENCE_GATE, "#W#", "#W#", '#', Items.STICK, 'W', Blocks.SPRUCE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence_gate", Blocks.JUNGLE_FENCE_GATE, "#W#", "#W#", '#', Items.STICK, 'W', Blocks.JUNGLE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence_gate", Blocks.OAK_FENCE_GATE, "#W#", "#W#", '#', Items.STICK, 'W', Blocks.OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence_gate", Blocks.DARK_OAK_FENCE_GATE, "#W#", "#W#", '#', Items.STICK, 'W', Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence_gate", Blocks.BIRCH_FENCE_GATE, "#W#", "#W#", '#', Items.STICK, 'W', Blocks.BIRCH_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_fence_gate", Blocks.ACACIA_FENCE_GATE, "#W#", "#W#", '#', Items.STICK, 'W', Blocks.ACACIA_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_door", 3, Blocks.OAK_DOOR, "##", "##", "##", '#', Blocks.OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_door", 3, Blocks.SPRUCE_DOOR, "##", "##", "##", '#', Blocks.SPRUCE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_door", 3, Blocks.JUNGLE_DOOR, "##", "##", "##", '#', Blocks.JUNGLE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_door", 3, Blocks.DARK_OAK_DOOR, "##", "##", "##", '#', Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_door", 3, Blocks.BIRCH_DOOR, "##", "##", "##", '#', Blocks.BIRCH_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_door", 3, Blocks.ACACIA_DOOR, "##", "##", "##", '#', Blocks.ACACIA_PLANKS));
recipes.add(RecipeInfo.shaped("banner", Blocks.YELLOW_BANNER, "###", "###", " | ", '#', Blocks.YELLOW_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.RED_BANNER, "###", "###", " | ", '#', Blocks.RED_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.PURPLE_BANNER, "###", "###", " | ", '#', Blocks.PURPLE_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.PINK_BANNER, "###", "###", " | ", '#', Blocks.PINK_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.ORANGE_BANNER, "###", "###", " | ", '#', Blocks.ORANGE_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.MAGENTA_BANNER, "###", "###", " | ", '#', Blocks.MAGENTA_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.LIME_BANNER, "###", "###", " | ", '#', Blocks.LIME_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.LIGHT_GRAY_BANNER, "###", "###", " | ", '#', Blocks.LIGHT_GRAY_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.LIGHT_BLUE_BANNER, "###", "###", " | ", '#', Blocks.LIGHT_BLUE_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.GREEN_BANNER, "###", "###", " | ", '#', Blocks.GREEN_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.GRAY_BANNER, "###", "###", " | ", '#', Blocks.GRAY_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.CYAN_BANNER, "###", "###", " | ", '#', Blocks.CYAN_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.BROWN_BANNER, "###", "###", " | ", '#', Blocks.BROWN_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.BLUE_BANNER, "###", "###", " | ", '#', Blocks.BLUE_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.BLACK_BANNER, "###", "###", " | ", '#', Blocks.BLACK_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("banner", Blocks.WHITE_BANNER, "###", "###", " | ", '#', Blocks.WHITE_WOOL, '|', Items.STICK));
recipes.add(RecipeInfo.shaped("rabbit_stew", Items.RABBIT_STEW, " R ", "CPD", " B ", 'P', Items.BAKED_POTATO, 'R', Items.COOKED_RABBIT, 'B', Items.BOWL, 'C', Blocks.CARROTS, 'D', Blocks.RED_MUSHROOM));
recipes.add(RecipeInfo.shaped("rabbit_stew", Items.RABBIT_STEW, " R ", "CPM", " B ", 'P', Items.BAKED_POTATO, 'R', Items.COOKED_RABBIT, 'B', Items.BOWL, 'C', Blocks.CARROTS, 'M', Blocks.BROWN_MUSHROOM));
recipes.add(RecipeInfo.shaped(3, Blocks.IRON_DOOR, "##", "##", "##", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.IRON_TRAPDOOR, "##", "##", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.RED_SANDSTONE, "##", "##", '#', Blocks.RED_SAND));
recipes.add(RecipeInfo.shaped(4, Blocks.CUT_RED_SANDSTONE, "##", "##", '#', Blocks.RED_SANDSTONE));
recipes.add(RecipeInfo.shaped(6, Blocks.RED_SANDSTONE_SLAB, "###", '#', Blocks.RED_SANDSTONE, Blocks.CHISELED_RED_SANDSTONE, Blocks.CUT_RED_SANDSTONE));
recipes.add(RecipeInfo.shaped(4, Blocks.RED_SANDSTONE_STAIRS, "# ", "## ", "###", '#', Blocks.RED_SANDSTONE, Blocks.CHISELED_RED_SANDSTONE, Blocks.CUT_RED_SANDSTONE));
recipes.add(RecipeInfo.shaped(Blocks.CHISELED_RED_SANDSTONE, "#", "#", '#', Blocks.RED_SANDSTONE_SLAB));
recipes.add(RecipeInfo.shaped(Items.LEATHER, "##", "##", '#', Items.RABBIT_HIDE));
recipes.add(RecipeInfo.shaped(Items.ARMOR_STAND, "///", " / ", "/_/", '/', Items.STICK, '_', Blocks.SMOOTH_STONE_SLAB));
recipes.add(RecipeInfo.shaped(Blocks.SEA_LANTERN, "SCS", "CCC", "SCS", 'S', Items.PRISMARINE_SHARD, 'C', Items.PRISMARINE_CRYSTALS));
recipes.add(RecipeInfo.shaped(Blocks.PRISMARINE_BRICKS, "SSS", "SSS", "SSS", 'S', Items.PRISMARINE_SHARD));
recipes.add(RecipeInfo.shaped(Blocks.PRISMARINE, "SS", "SS", 'S', Items.PRISMARINE_SHARD));
recipes.add(RecipeInfo.shaped(Blocks.DARK_PRISMARINE, "SSS", "SIS", "SSS", 'S', Items.PRISMARINE_SHARD, 'I', Items.INK_SAC));
recipes.add(RecipeInfo.shaped(9, Items.SLIME_BALL, "#", '#', Blocks.SLIME_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.SLIME_BLOCK, "###", "###", "###", '#', Items.SLIME_BALL));
recipes.add(RecipeInfo.shaped(2, Blocks.DIORITE, "CQ", "QC", 'Q', Items.QUARTZ, 'C', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shapeless(2, Blocks.ANDESITE, Blocks.DIORITE, Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shapeless(Blocks.GRANITE, Blocks.DIORITE, Items.QUARTZ));
recipes.add(RecipeInfo.shaped(4, Blocks.POLISHED_GRANITE, "SS", "SS", 'S', Blocks.GRANITE));
recipes.add(RecipeInfo.shaped(4, Blocks.POLISHED_DIORITE, "SS", "SS", 'S', Blocks.DIORITE));
recipes.add(RecipeInfo.shaped(4, Blocks.POLISHED_ANDESITE, "SS", "SS", 'S', Blocks.ANDESITE));
} else {
recipes.add(RecipeInfo.shaped("wooden_fence", 2, Blocks.OAK_FENCE, "###", "###", '#', Items.STICK));
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_8tob1_8_1)) {
recipes.add(RecipeInfo.shaped("wooden_fence_gate", Blocks.OAK_FENCE_GATE, "#W#", "#W#", '#', Items.STICK, 'W', Blocks.OAK_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.DARK_OAK_PLANKS, Blocks.BIRCH_PLANKS, Blocks.ACACIA_PLANKS));
}
recipes.add(RecipeInfo.shaped(Blocks.IRON_DOOR, "##", "##", "##", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped("wooden_door", Blocks.OAK_DOOR, "##", "##", "##", '#', Blocks.OAK_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.DARK_OAK_PLANKS, Blocks.BIRCH_PLANKS, Blocks.ACACIA_PLANKS));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.YELLOW_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.YELLOW_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.WHITE_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.BONE_MEAL));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.RED_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.RED_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.PURPLE_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.PURPLE_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.PINK_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.PINK_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.ORANGE_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.ORANGE_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.MAGENTA_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.MAGENTA_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.LIME_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.LIME_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.LIGHT_GRAY_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.LIGHT_GRAY_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.LIGHT_BLUE_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.LIGHT_BLUE_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.GREEN_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.GREEN_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.GRAY_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.GRAY_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.CYAN_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.CYAN_DYE));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.BROWN_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Blocks.COCOA));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.BLUE_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.LAPIS_LAZULI));
recipes.add(RecipeInfo.shaped("stained_glass", 8, Blocks.BLACK_STAINED_GLASS, "###", "#X#", "###", '#', Blocks.GLASS, 'X', Items.INK_SAC));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.YELLOW_STAINED_GLASS_PANE, "###", "###", '#', Blocks.YELLOW_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.WHITE_STAINED_GLASS_PANE, "###", "###", '#', Blocks.WHITE_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.RED_STAINED_GLASS_PANE, "###", "###", '#', Blocks.RED_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.PURPLE_STAINED_GLASS_PANE, "###", "###", '#', Blocks.PURPLE_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.PINK_STAINED_GLASS_PANE, "###", "###", '#', Blocks.PINK_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.ORANGE_STAINED_GLASS_PANE, "###", "###", '#', Blocks.ORANGE_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.MAGENTA_STAINED_GLASS_PANE, "###", "###", '#', Blocks.MAGENTA_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.LIME_STAINED_GLASS_PANE, "###", "###", '#', Blocks.LIME_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.LIGHT_GRAY_STAINED_GLASS_PANE, "###", "###", '#', Blocks.LIGHT_GRAY_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.LIGHT_BLUE_STAINED_GLASS_PANE, "###", "###", '#', Blocks.LIGHT_BLUE_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.GREEN_STAINED_GLASS_PANE, "###", "###", '#', Blocks.GREEN_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.GRAY_STAINED_GLASS_PANE, "###", "###", '#', Blocks.GRAY_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.CYAN_STAINED_GLASS_PANE, "###", "###", '#', Blocks.CYAN_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.BROWN_STAINED_GLASS_PANE, "###", "###", '#', Blocks.BROWN_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.BLUE_STAINED_GLASS_PANE, "###", "###", '#', Blocks.BLUE_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("stained_glass_pane", 16, Blocks.BLACK_STAINED_GLASS_PANE, "###", "###", '#', Blocks.BLACK_STAINED_GLASS));
recipes.add(RecipeInfo.shaped("planks", 4, Blocks.ACACIA_PLANKS, "#", '#', Blocks.ACACIA_LOG));
recipes.add(RecipeInfo.shaped("planks", 4, Blocks.DARK_OAK_PLANKS, "#", '#', Blocks.DARK_OAK_LOG));
recipes.add(RecipeInfo.shaped("wooden_slab", 6, Blocks.ACACIA_SLAB, "###", '#', Blocks.ACACIA_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_stairs", 4, Blocks.ACACIA_STAIRS, "# ", "## ", "###", '#', Blocks.ACACIA_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_slab", 6, Blocks.DARK_OAK_SLAB, "###", '#', Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_stairs", 4, Blocks.DARK_OAK_STAIRS, "# ", "## ", "###", '#', Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Blocks.TNT, "X#X", "#X#", "X#X", '#', Blocks.SAND, Blocks.RED_SAND, 'X', Items.GUNPOWDER));
recipes.add(RecipeInfo.shapeless("red_dye", Items.RED_DYE, Blocks.RED_TULIP));
recipes.add(RecipeInfo.shapeless("orange_dye", Items.ORANGE_DYE, Blocks.ORANGE_TULIP));
recipes.add(RecipeInfo.shapeless("light_gray_dye", Items.LIGHT_GRAY_DYE, Blocks.WHITE_TULIP));
recipes.add(RecipeInfo.shapeless("pink_dye", Items.PINK_DYE, Blocks.PINK_TULIP));
recipes.add(RecipeInfo.shapeless("light_blue_dye", Items.LIGHT_BLUE_DYE, Blocks.BLUE_ORCHID));
recipes.add(RecipeInfo.shapeless("magenta_dye", Items.MAGENTA_DYE, Blocks.ALLIUM));
recipes.add(RecipeInfo.shapeless("light_gray_dye", Items.LIGHT_GRAY_DYE, Blocks.AZURE_BLUET));
recipes.add(RecipeInfo.shapeless("light_gray_dye", Items.LIGHT_GRAY_DYE, Blocks.OXEYE_DAISY));
recipes.add(RecipeInfo.shapeless("yellow_dye", 2, Items.YELLOW_DYE, Blocks.SUNFLOWER));
recipes.add(RecipeInfo.shapeless("pink_dye", 2, Items.PINK_DYE, Blocks.PEONY));
recipes.add(RecipeInfo.shapeless("red_dye", 2, Items.RED_DYE, Blocks.ROSE_BUSH));
recipes.add(RecipeInfo.shapeless("magenta_dye", 2, Items.MAGENTA_DYE, Blocks.LILAC));
recipes.add(RecipeInfo.shapeless(Items.FLINT_AND_STEEL, Items.IRON_INGOT, Items.FLINT));
} else {
recipes.add(RecipeInfo.shaped(Items.FLINT_AND_STEEL, "A ", " B", 'A', Items.IRON_INGOT, 'B', Items.FLINT));
recipes.add(RecipeInfo.shaped(Blocks.TNT, "X#X", "#X#", "X#X", '#', Blocks.SAND, 'X', Items.GUNPOWDER));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_6_1)) {
recipes.add(RecipeInfo.shaped(Items.GOLDEN_APPLE, "###", "#X#", "###", '#', Items.GOLD_INGOT, 'X', Items.APPLE));
recipes.add(RecipeInfo.shaped(Items.GLISTERING_MELON_SLICE, "###", "#X#", "###", '#', Items.GOLD_NUGGET, 'X', Items.MELON_SLICE));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.YELLOW_CARPET, "##", '#', Blocks.YELLOW_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.WHITE_CARPET, "##", '#', Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.RED_CARPET, "##", '#', Blocks.RED_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.PURPLE_CARPET, "##", '#', Blocks.PURPLE_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.PINK_CARPET, "##", '#', Blocks.PINK_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.ORANGE_CARPET, "##", '#', Blocks.ORANGE_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.MAGENTA_CARPET, "##", '#', Blocks.MAGENTA_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.LIME_CARPET, "##", '#', Blocks.LIME_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.LIGHT_GRAY_CARPET, "##", '#', Blocks.LIGHT_GRAY_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.LIGHT_BLUE_CARPET, "##", '#', Blocks.LIGHT_BLUE_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.GREEN_CARPET, "##", '#', Blocks.GREEN_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.GRAY_CARPET, "##", '#', Blocks.GRAY_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.CYAN_CARPET, "##", '#', Blocks.CYAN_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.BROWN_CARPET, "##", '#', Blocks.BROWN_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.BLUE_CARPET, "##", '#', Blocks.BLUE_WOOL));
recipes.add(RecipeInfo.shaped("carpet", 3, Blocks.BLACK_CARPET, "##", '#', Blocks.BLACK_WOOL));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.YELLOW_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.YELLOW_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.WHITE_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.BONE_MEAL));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.RED_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.RED_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.PURPLE_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.PURPLE_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.PINK_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.PINK_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.ORANGE_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.ORANGE_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.MAGENTA_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.MAGENTA_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.LIME_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.LIME_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.LIGHT_GRAY_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.LIGHT_GRAY_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.LIGHT_BLUE_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.LIGHT_BLUE_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.GREEN_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.GREEN_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.GRAY_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.GRAY_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.CYAN_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.CYAN_DYE));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.BROWN_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Blocks.COCOA));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.BLUE_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.LAPIS_LAZULI));
recipes.add(RecipeInfo.shaped("stained_hardened_clay", 8, Blocks.BLACK_TERRACOTTA, "###", "#X#", "###", '#', Blocks.TERRACOTTA, 'X', Items.INK_SAC));
recipes.add(RecipeInfo.shaped(2, Items.LEAD, "~~ ", "~O ", " ~", '~', Blocks.TRIPWIRE, 'O', Items.SLIME_BALL));
recipes.add(RecipeInfo.shaped(Blocks.HAY_BLOCK, "###", "###", "###", '#', Items.WHEAT));
recipes.add(RecipeInfo.shaped(9, Items.WHEAT, "#", '#', Blocks.HAY_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.COAL_BLOCK, "###", "###", "###", '#', Items.COAL));
recipes.add(RecipeInfo.shaped(9, Items.COAL, "#", '#', Blocks.COAL_BLOCK));
} else {
recipes.add(RecipeInfo.shaped(Items.GOLDEN_APPLE, "###", "#X#", "###", '#', Items.GOLD_NUGGET, 'X', Items.APPLE));
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_0_0tor1_0_1)) {
recipes.add(RecipeInfo.shapeless(Items.GLISTERING_MELON_SLICE, Items.GOLD_NUGGET, Items.MELON_SLICE));
}
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_5tor1_5_1)) {
recipes.add(RecipeInfo.shaped(6, Blocks.SNOW, "###", '#', Blocks.SNOW_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.QUARTZ_BLOCK, "##", "##", '#', Items.QUARTZ));
recipes.add(RecipeInfo.shaped(2, Blocks.QUARTZ_PILLAR, "#", "#", '#', Blocks.QUARTZ_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.CHISELED_QUARTZ_BLOCK, "#", "#", '#', Blocks.QUARTZ_SLAB));
recipes.add(RecipeInfo.shaped(6, Blocks.QUARTZ_SLAB, "###", '#', Blocks.QUARTZ_BLOCK, Blocks.CHISELED_QUARTZ_BLOCK, Blocks.QUARTZ_PILLAR));
recipes.add(RecipeInfo.shaped(6, Blocks.ACTIVATOR_RAIL, "XSX", "X#X", "XSX", '#', Blocks.REDSTONE_TORCH, 'S', Items.STICK, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.TNT_MINECART, "A", "B", 'A', Blocks.TNT, 'B', Items.MINECART));
recipes.add(RecipeInfo.shaped(Items.HOPPER_MINECART, "A", "B", 'A', Blocks.HOPPER, 'B', Items.MINECART));
recipes.add(RecipeInfo.shaped(4, Blocks.QUARTZ_STAIRS, "# ", "## ", "###", '#', Blocks.QUARTZ_BLOCK, Blocks.CHISELED_QUARTZ_BLOCK, Blocks.QUARTZ_PILLAR));
recipes.add(RecipeInfo.shaped(Blocks.COMPARATOR, " # ", "#X#", "III", '#', Blocks.REDSTONE_TORCH, 'X', Items.QUARTZ, 'I', Blocks.STONE));
recipes.add(RecipeInfo.shaped(Blocks.LIGHT_WEIGHTED_PRESSURE_PLATE, "##", '#', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.HEAVY_WEIGHTED_PRESSURE_PLATE, "##", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.DROPPER, "###", "# #", "#R#", 'R', Blocks.REDSTONE_WIRE, '#', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Blocks.HOPPER, "I I", "ICI", " I ", 'C', Blocks.CHEST, 'I', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.NETHER_BRICKS, "NN", "NN", 'N', Items.NETHER_BRICK));
recipes.add(RecipeInfo.shaped(Blocks.DAYLIGHT_DETECTOR, "GGG", "QQQ", "WWW", 'Q', Items.QUARTZ, 'G', Blocks.GLASS, 'W', Blocks.OAK_SLAB, Blocks.SPRUCE_SLAB, Blocks.BIRCH_SLAB, Blocks.JUNGLE_SLAB, Blocks.ACACIA_SLAB, Blocks.DARK_OAK_SLAB));
recipes.add(RecipeInfo.shaped(Blocks.REDSTONE_BLOCK, "###", "###", "###", '#', Blocks.REDSTONE_WIRE));
recipes.add(RecipeInfo.shaped(9, Blocks.REDSTONE_WIRE, "#", '#', Blocks.REDSTONE_BLOCK));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_4_6tor1_4_7)) {
recipes.add(RecipeInfo.shaped(6, Blocks.NETHER_BRICK_SLAB, "###", '#', Blocks.NETHER_BRICKS));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_4_2)) {
recipes.add(RecipeInfo.shaped(6, Blocks.COBBLESTONE_WALL, "###", "###", '#', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(6, Blocks.MOSSY_COBBLESTONE_WALL, "###", "###", '#', Blocks.MOSSY_COBBLESTONE));
recipes.add(RecipeInfo.shaped(Blocks.FLOWER_POT, "# #", " # ", '#', Items.BRICK));
recipes.add(RecipeInfo.shaped(Items.CARROT_ON_A_STICK, "# ", " X", '#', Items.FISHING_ROD, 'X', Blocks.CARROTS));
recipes.add(RecipeInfo.shaped(Items.ITEM_FRAME, "###", "#X#", "###", '#', Items.STICK, 'X', Items.LEATHER));
recipes.add(RecipeInfo.shaped(Items.GOLDEN_CARROT, "###", "#X#", "###", '#', Items.GOLD_NUGGET, 'X', Blocks.CARROTS));
recipes.add(RecipeInfo.shaped(Blocks.OAK_BUTTON, "#", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Blocks.ANVIL, "III", " i ", "iii", 'I', Blocks.IRON_BLOCK, 'i', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.BEACON, "GGG", "GSG", "OOO", 'S', Items.NETHER_STAR, 'G', Blocks.GLASS, 'O', Blocks.OBSIDIAN));
recipes.add(RecipeInfo.shapeless(Items.PUMPKIN_PIE, Blocks.CARVED_PUMPKIN, Items.SUGAR, Items.EGG));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_3_1tor1_3_2)) {
recipes.add(RecipeInfo.shapeless(Items.WRITABLE_BOOK, Items.BOOK, Items.INK_SAC, Items.FEATHER));
recipes.add(RecipeInfo.shapeless(Items.BOOK, Items.PAPER, Items.PAPER, Items.PAPER, Items.LEATHER));
recipes.add(RecipeInfo.shaped(3, Blocks.OAK_SIGN, "###", "###", " X ", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'X', Items.STICK));
recipes.add(RecipeInfo.shaped("wooden_slab", 6, Blocks.SPRUCE_SLAB, "###", '#', Blocks.SPRUCE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_slab", 6, Blocks.BIRCH_SLAB, "###", '#', Blocks.BIRCH_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_slab", 6, Blocks.JUNGLE_SLAB, "###", '#', Blocks.JUNGLE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_slab", 6, Blocks.OAK_SLAB, "###", '#', Blocks.OAK_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_stairs", 4, Blocks.SPRUCE_STAIRS, "# ", "## ", "###", '#', Blocks.SPRUCE_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_stairs", 4, Blocks.BIRCH_STAIRS, "# ", "## ", "###", '#', Blocks.BIRCH_PLANKS));
recipes.add(RecipeInfo.shaped("wooden_stairs", 4, Blocks.JUNGLE_STAIRS, "# ", "## ", "###", '#', Blocks.JUNGLE_PLANKS));
recipes.add(RecipeInfo.shaped(4, Blocks.SANDSTONE_STAIRS, "# ", "## ", "###", '#', Blocks.SANDSTONE, Blocks.CHISELED_SANDSTONE, Blocks.CUT_SANDSTONE));
recipes.add(RecipeInfo.shaped(2, Blocks.TRIPWIRE_HOOK, "I", "S", "#", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'S', Items.STICK, 'I', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Blocks.ENDER_CHEST, "###", "#E#", "###", '#', Blocks.OBSIDIAN, 'E', Items.ENDER_EYE));
recipes.add(RecipeInfo.shaped(Blocks.EMERALD_BLOCK, "###", "###", "###", '#', Items.EMERALD));
recipes.add(RecipeInfo.shaped(9, Items.EMERALD, "#", '#', Blocks.EMERALD_BLOCK));
} else {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_2_1tor1_2_3)) {
recipes.add(RecipeInfo.shaped("wooden_slab", 6, Blocks.OAK_SLAB, "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
} else {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_3tob1_3_1)) {
recipes.add(RecipeInfo.shaped("wooden_slab", 3, Blocks.OAK_SLAB, "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
}
}
recipes.add(RecipeInfo.shaped(Items.BOOK, "#", "#", "#", '#', Items.PAPER));
recipes.add(RecipeInfo.shaped(Blocks.OAK_SIGN, "###", "###", " X ", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'X', Items.STICK));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_2_4tor1_2_5)) {
recipes.add(RecipeInfo.shaped("planks", 4, Blocks.BIRCH_PLANKS, "#", '#', Blocks.BIRCH_LOG));
recipes.add(RecipeInfo.shaped("planks", 4, Blocks.SPRUCE_PLANKS, "#", '#', Blocks.SPRUCE_LOG));
recipes.add(RecipeInfo.shaped("planks", 4, Blocks.JUNGLE_PLANKS, "#", '#', Blocks.JUNGLE_LOG));
recipes.add(RecipeInfo.shaped(Blocks.CHISELED_SANDSTONE, "#", "#", '#', Blocks.SANDSTONE_SLAB));
recipes.add(RecipeInfo.shaped(4, Blocks.CUT_SANDSTONE, "##", "##", '#', Blocks.SANDSTONE));
} else {
recipes.add(RecipeInfo.shaped("planks", 4, Blocks.OAK_PLANKS, "#", '#', Blocks.BIRCH_LOG, Blocks.SPRUCE_LOG, Blocks.JUNGLE_LOG));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_2_1tor1_2_3)) {
recipes.add(RecipeInfo.shaped(3, Blocks.LADDER, "# #", "###", "# #", '#', Items.STICK));
recipes.add(RecipeInfo.shaped(6, Blocks.SMOOTH_STONE_SLAB, "###", '#', Blocks.STONE));
recipes.add(RecipeInfo.shaped(6, Blocks.SANDSTONE_SLAB, "###", '#', Blocks.SANDSTONE, Blocks.CHISELED_SANDSTONE, Blocks.CUT_SANDSTONE));
recipes.add(RecipeInfo.shaped(6, Blocks.COBBLESTONE_SLAB, "###", '#', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(6, Blocks.BRICK_SLAB, "###", '#', Blocks.BRICKS));
recipes.add(RecipeInfo.shaped(6, Blocks.STONE_BRICK_SLAB, "###", '#', Blocks.STONE_BRICKS, Blocks.MOSSY_STONE_BRICKS, Blocks.CRACKED_STONE_BRICKS, Blocks.CHISELED_STONE_BRICKS));
recipes.add(RecipeInfo.shaped(Blocks.REDSTONE_LAMP, " R ", "RGR", " R ", 'R', Blocks.REDSTONE_WIRE, 'G', Blocks.GLOWSTONE));
recipes.add(RecipeInfo.shapeless(3, Items.FIRE_CHARGE, new ItemConvertible[]{Items.GUNPOWDER}, new ItemConvertible[]{Items.BLAZE_POWDER}, new ItemConvertible[]{Items.COAL, Items.CHARCOAL}));
} else {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_5tob1_5_2)) {
recipes.add(RecipeInfo.shaped(2, Blocks.LADDER, "# #", "###", "# #", '#', Items.STICK));
} else {
recipes.add(RecipeInfo.shaped(1, Blocks.LADDER, "# #", "###", "# #", '#', Items.STICK));
}
recipes.add(RecipeInfo.shaped(3, Blocks.SMOOTH_STONE_SLAB, "###", '#', Blocks.STONE));
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_3tob1_3_1)) {
recipes.add(RecipeInfo.shaped(3, Blocks.SANDSTONE_SLAB, "###", '#', Blocks.SANDSTONE, Blocks.CHISELED_SANDSTONE, Blocks.CUT_SANDSTONE));
recipes.add(RecipeInfo.shaped(3, Blocks.COBBLESTONE_SLAB, "###", '#', Blocks.COBBLESTONE));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_8tob1_8_1)) {
recipes.add(RecipeInfo.shaped(3, Blocks.BRICK_SLAB, "###", '#', Blocks.BRICKS));
recipes.add(RecipeInfo.shaped(3, Blocks.STONE_BRICK_SLAB, "###", '#', Blocks.STONE_BRICKS, Blocks.MOSSY_STONE_BRICKS, Blocks.CRACKED_STONE_BRICKS, Blocks.CHISELED_STONE_BRICKS));
}
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_0_0tor1_0_1)) {
recipes.add(RecipeInfo.shapeless(Items.MUSHROOM_STEW, Blocks.BROWN_MUSHROOM, Blocks.RED_MUSHROOM, Items.BOWL));
recipes.add(RecipeInfo.shaped(4, Blocks.NETHER_BRICK_STAIRS, "# ", "## ", "###", '#', Blocks.NETHER_BRICKS));
recipes.add(RecipeInfo.shaped(6, Blocks.NETHER_BRICK_FENCE, "###", "###", '#', Blocks.NETHER_BRICKS));
recipes.add(RecipeInfo.shaped(3, Items.GLASS_BOTTLE, "# #", " # ", '#', Blocks.GLASS));
recipes.add(RecipeInfo.shaped(Blocks.BREWING_STAND, " B ", "###", 'B', Items.BLAZE_ROD, '#', Blocks.COBBLESTONE));
recipes.add(RecipeInfo.shaped(Blocks.CAULDRON, "# #", "# #", "###", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shapeless(Items.ENDER_EYE, Items.ENDER_PEARL, Items.BLAZE_POWDER));
recipes.add(RecipeInfo.shaped(Blocks.ENCHANTING_TABLE, " B ", "D#D", "###", 'B', Items.BOOK, '#', Blocks.OBSIDIAN, 'D', Items.DIAMOND));
recipes.add(RecipeInfo.shaped(4, Blocks.PUMPKIN_STEM, "M", 'M', Blocks.CARVED_PUMPKIN));
recipes.add(RecipeInfo.shapeless(Items.FERMENTED_SPIDER_EYE, Items.SPIDER_EYE, Blocks.BROWN_MUSHROOM, Items.SUGAR));
recipes.add(RecipeInfo.shapeless(2, Items.BLAZE_POWDER, Items.BLAZE_ROD));
recipes.add(RecipeInfo.shapeless(Items.MAGMA_CREAM, Items.BLAZE_POWDER, Items.SLIME_BALL));
recipes.add(RecipeInfo.shaped(9, Items.GOLD_NUGGET, "#", '#', Items.GOLD_INGOT));
recipes.add(RecipeInfo.shaped("gold_ingot", Items.GOLD_INGOT, "###", "###", "###", '#', Items.GOLD_NUGGET));
} else {
recipes.add(RecipeInfo.shaped(Items.MUSHROOM_STEW, "Y", "X", "#", 'X', Blocks.BROWN_MUSHROOM, 'Y', Blocks.RED_MUSHROOM, '#', Items.BOWL));
recipes.add(RecipeInfo.shaped(Items.MUSHROOM_STEW, "Y", "X", "#", 'X', Blocks.RED_MUSHROOM, 'Y', Blocks.BROWN_MUSHROOM, '#', Items.BOWL));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_8tob1_8_1)) {
recipes.add(RecipeInfo.shaped(4, Blocks.BRICK_STAIRS, "# ", "## ", "###", '#', Blocks.BRICKS));
recipes.add(RecipeInfo.shaped(4, Blocks.STONE_BRICK_STAIRS, "# ", "## ", "###", '#', Blocks.STONE_BRICKS, Blocks.MOSSY_STONE_BRICKS, Blocks.CRACKED_STONE_BRICKS, Blocks.CHISELED_STONE_BRICKS));
recipes.add(RecipeInfo.shaped(4, Blocks.STONE_BRICKS, "##", "##", '#', Blocks.STONE));
recipes.add(RecipeInfo.shaped(16, Blocks.IRON_BARS, "###", "###", '#', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(16, Blocks.GLASS_PANE, "###", "###", '#', Blocks.GLASS));
recipes.add(RecipeInfo.shaped(Blocks.MELON, "MMM", "MMM", "MMM", 'M', Items.MELON_SLICE));
recipes.add(RecipeInfo.shaped(Blocks.MELON_STEM, "M", 'M', Items.MELON_SLICE));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_7tob1_7_3)) {
recipes.add(RecipeInfo.shaped(Blocks.STICKY_PISTON, "S", "P", 'P', Blocks.PISTON, 'S', Items.SLIME_BALL));
recipes.add(RecipeInfo.shaped(Blocks.PISTON, "TTT", "#X#", "#R#", 'R', Blocks.REDSTONE_WIRE, '#', Blocks.COBBLESTONE, 'T', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(Items.SHEARS, " #", "# ", '#', Items.IRON_INGOT));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_6tob1_6_6)) {
recipes.add(RecipeInfo.shaped(Blocks.GLOWSTONE, "##", "##", '#', Items.GLOWSTONE_DUST));
recipes.add(RecipeInfo.shaped(Blocks.WHITE_WOOL, "##", "##", '#', Blocks.TRIPWIRE));
recipes.add(RecipeInfo.shaped(2, Blocks.OAK_TRAPDOOR, "###", "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Items.MAP, "###", "#X#", "###", '#', Items.PAPER, 'X', Items.COMPASS));
} else {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.a1_2_0toa1_2_1_1)) {
recipes.add(RecipeInfo.shaped(Blocks.GLOWSTONE, "###", "###", "###", '#', Items.GLOWSTONE_DUST));
}
recipes.add(RecipeInfo.shaped(Blocks.WHITE_WOOL, "###", "###", "###", '#', Blocks.TRIPWIRE));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_5tob1_5_2)) {
recipes.add(RecipeInfo.shaped(6, Blocks.DETECTOR_RAIL, "X X", "X#X", "XRX", 'R', Blocks.REDSTONE_WIRE, '#', Blocks.STONE_PRESSURE_PLATE, 'X', Items.IRON_INGOT));
recipes.add(RecipeInfo.shaped(6, Blocks.POWERED_RAIL, "X X", "X#X", "XRX", 'R', Blocks.REDSTONE_WIRE, '#', Items.STICK, 'X', Items.GOLD_INGOT));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_4tob1_4_1)) {
recipes.add(RecipeInfo.shaped(8, Items.COOKIE, "#X#", '#', Items.WHEAT, 'X', Blocks.COCOA));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_3tob1_3_1)) {
recipes.add(RecipeInfo.shaped(Blocks.REPEATER, "#X#", "III", '#', Blocks.REDSTONE_TORCH, 'X', Blocks.REDSTONE_WIRE, 'I', Blocks.STONE));
recipes.add(RecipeInfo.shaped(Blocks.OAK_PRESSURE_PLATE, "##", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Blocks.STONE_PRESSURE_PLATE, "##", '#', Blocks.STONE));
} else {
recipes.add(RecipeInfo.shaped(Blocks.OAK_PRESSURE_PLATE, "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS));
recipes.add(RecipeInfo.shaped(Blocks.STONE_PRESSURE_PLATE, "###", '#', Blocks.STONE));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_2_0tob1_2_2)) {
recipes.add(RecipeInfo.shaped(Blocks.NOTE_BLOCK, "###", "#X#", "###", '#', Blocks.OAK_PLANKS, Blocks.SPRUCE_PLANKS, Blocks.BIRCH_PLANKS, Blocks.JUNGLE_PLANKS, Blocks.ACACIA_PLANKS, Blocks.DARK_OAK_PLANKS, 'X', Blocks.REDSTONE_WIRE));
recipes.add(RecipeInfo.shaped(Blocks.CAKE, "AAA", "BEB", "CCC", 'A', Items.MILK_BUCKET, 'B', Items.SUGAR, 'C', Items.WHEAT, 'E', Items.EGG));
recipes.add(RecipeInfo.shaped(Items.SUGAR, "#", '#', Blocks.SUGAR_CANE));
recipes.add(RecipeInfo.shaped(4, Blocks.TORCH, "X", "#", '#', Items.STICK, 'X', Items.COAL, Items.CHARCOAL));
recipes.add(RecipeInfo.shaped(Blocks.DISPENSER, "###", "#X#", "#R#", 'R', Blocks.REDSTONE_WIRE, '#', Blocks.COBBLESTONE, 'X', Items.BOW));
recipes.add(RecipeInfo.shaped(Blocks.SANDSTONE, "##", "##", '#', Blocks.SAND));
recipes.add(RecipeInfo.shapeless("wool", Blocks.YELLOW_WOOL, Items.YELLOW_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("yellow_dye", Items.YELLOW_DYE, Blocks.DANDELION));
recipes.add(RecipeInfo.shapeless("wool", Blocks.RED_WOOL, Items.RED_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("red_dye", Items.RED_DYE, Blocks.POPPY));
recipes.add(RecipeInfo.shapeless("wool", Blocks.PURPLE_WOOL, Items.PURPLE_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless(2, Items.PURPLE_DYE, Items.LAPIS_LAZULI, Items.RED_DYE));
recipes.add(RecipeInfo.shapeless("wool", Blocks.PINK_WOOL, Items.PINK_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("pink_dye", 2, Items.PINK_DYE, Items.RED_DYE, Items.BONE_MEAL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.ORANGE_WOOL, Items.ORANGE_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("orange_dye", 2, Items.ORANGE_DYE, Items.RED_DYE, Items.YELLOW_DYE));
recipes.add(RecipeInfo.shapeless("wool", Blocks.MAGENTA_WOOL, Items.MAGENTA_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("magenta_dye", 2, Items.MAGENTA_DYE, Items.PURPLE_DYE, Items.PINK_DYE));
recipes.add(RecipeInfo.shapeless("magenta_dye", 3, Items.MAGENTA_DYE, Items.LAPIS_LAZULI, Items.RED_DYE, Items.PINK_DYE));
recipes.add(RecipeInfo.shapeless("magenta_dye", 4, Items.MAGENTA_DYE, Items.LAPIS_LAZULI, Items.RED_DYE, Items.RED_DYE, Items.BONE_MEAL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.LIME_WOOL, Items.LIME_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless(2, Items.LIME_DYE, Items.GREEN_DYE, Items.BONE_MEAL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.LIGHT_GRAY_WOOL, Items.LIGHT_GRAY_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("light_gray_dye", 3, Items.LIGHT_GRAY_DYE, Items.INK_SAC, Items.BONE_MEAL, Items.BONE_MEAL));
recipes.add(RecipeInfo.shapeless("light_gray_dye", 2, Items.LIGHT_GRAY_DYE, Items.GRAY_DYE, Items.BONE_MEAL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.LIGHT_BLUE_WOOL, Items.LIGHT_BLUE_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("light_blue_dye", 2, Items.LIGHT_BLUE_DYE, Items.LAPIS_LAZULI, Items.BONE_MEAL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.GREEN_WOOL, Items.GREEN_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.GRAY_WOOL, Items.GRAY_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless(2, Items.GRAY_DYE, Items.INK_SAC, Items.BONE_MEAL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.CYAN_WOOL, Items.CYAN_DYE, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless(2, Items.CYAN_DYE, Items.LAPIS_LAZULI, Items.GREEN_DYE));
recipes.add(RecipeInfo.shapeless("wool", Blocks.BLUE_WOOL, Items.LAPIS_LAZULI, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.BLACK_WOOL, Items.INK_SAC, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("wool", Blocks.BROWN_WOOL, Blocks.COCOA, Blocks.WHITE_WOOL));
recipes.add(RecipeInfo.shapeless("bonemeal", 3, Items.BONE_MEAL, Items.BONE));
recipes.add(RecipeInfo.shaped(9, Items.LAPIS_LAZULI, "#", '#', Blocks.LAPIS_BLOCK));
recipes.add(RecipeInfo.shaped(Blocks.LAPIS_BLOCK, "###", "###", "###", '#', Items.LAPIS_LAZULI));
} else {
recipes.add(RecipeInfo.shaped(4, Blocks.TORCH, "X", "#", '#', Items.STICK, 'X', Items.COAL));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.a1_2_0toa1_2_1_1)) {
recipes.add(RecipeInfo.shaped(Blocks.JACK_O_LANTERN, "A", "B", 'A', Blocks.CARVED_PUMPKIN, 'B', Blocks.TORCH));
recipes.add(RecipeInfo.shaped(Items.CLOCK, " # ", "#X#", " # ", '#', Items.GOLD_INGOT, 'X', Blocks.REDSTONE_WIRE));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.a1_1_0toa1_1_2_1)) {
recipes.add(RecipeInfo.shaped(Items.FISHING_ROD, " #", " #X", "# X", '#', Items.STICK, 'X', Blocks.TRIPWIRE));
recipes.add(RecipeInfo.shaped(Items.COMPASS, " # ", "#X#", " # ", '#', Items.IRON_INGOT, 'X', Blocks.REDSTONE_WIRE));
}
recipes.add(RecipeInfo.smelting(Items.IRON_INGOT, Items.IRON_ORE, 0.7F));
recipes.add(RecipeInfo.smelting(Items.GOLD_INGOT, Items.GOLD_ORE, 1.0F));
recipes.add(RecipeInfo.smelting(Items.DIAMOND, Items.DIAMOND_ORE, 1.0F));
recipes.add(RecipeInfo.smelting(Items.GLASS, Ingredient.fromTag(ItemTags.SAND), 0.1F));
recipes.add(RecipeInfo.smelting(Items.COOKED_PORKCHOP, Items.PORKCHOP, 0.35F));
recipes.add(RecipeInfo.smelting(Items.STONE, Items.COBBLESTONE, 0.1F));
recipes.add(RecipeInfo.smelting(Items.BRICK, Items.CLAY_BALL, 0.3F));
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_12)) {
recipes.add(RecipeInfo.smelting(Items.WHITE_GLAZED_TERRACOTTA, Items.WHITE_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.ORANGE_GLAZED_TERRACOTTA, Items.ORANGE_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.MAGENTA_GLAZED_TERRACOTTA, Items.MAGENTA_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.LIGHT_BLUE_GLAZED_TERRACOTTA, Items.LIGHT_BLUE_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.YELLOW_GLAZED_TERRACOTTA, Items.YELLOW_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.LIME_GLAZED_TERRACOTTA, Items.LIME_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.PINK_GLAZED_TERRACOTTA, Items.PINK_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.GRAY_GLAZED_TERRACOTTA, Items.GRAY_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.LIGHT_GRAY_GLAZED_TERRACOTTA, Items.LIGHT_GRAY_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.CYAN_GLAZED_TERRACOTTA, Items.CYAN_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.PURPLE_GLAZED_TERRACOTTA, Items.PURPLE_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.BLUE_GLAZED_TERRACOTTA, Items.BLUE_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.BROWN_GLAZED_TERRACOTTA, Items.BROWN_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.GREEN_GLAZED_TERRACOTTA, Items.GREEN_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.RED_GLAZED_TERRACOTTA, Items.RED_TERRACOTTA, 0.1F));
recipes.add(RecipeInfo.smelting(Items.BLACK_GLAZED_TERRACOTTA, Items.BLACK_TERRACOTTA, 0.1F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) {
recipes.add(RecipeInfo.smelting(Items.IRON_NUGGET, Ingredient.ofItems(Items.CHAINMAIL_HELMET, Items.CHAINMAIL_CHESTPLATE, Items.CHAINMAIL_LEGGINGS, Items.CHAINMAIL_BOOTS, Items.IRON_PICKAXE, Items.IRON_SHOVEL, Items.IRON_AXE, Items.IRON_HOE, Items.IRON_SWORD, Items.IRON_HELMET, Items.IRON_CHESTPLATE, Items.IRON_LEGGINGS, Items.IRON_BOOTS, Items.IRON_HORSE_ARMOR), 0.1F));
recipes.add(RecipeInfo.smelting(Items.GOLD_NUGGET, Ingredient.ofItems(Items.GOLDEN_PICKAXE, Items.GOLDEN_SHOVEL, Items.GOLDEN_AXE, Items.GOLDEN_HOE, Items.GOLDEN_SWORD, Items.GOLDEN_HELMET, Items.GOLDEN_CHESTPLATE, Items.GOLDEN_LEGGINGS, Items.GOLDEN_BOOTS, Items.GOLDEN_HORSE_ARMOR), 0.1F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_9)) {
recipes.add(RecipeInfo.smelting(Items.POPPED_CHORUS_FRUIT, Items.CHORUS_FRUIT, 0.1F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
recipes.add(RecipeInfo.smelting(Items.COOKED_RABBIT, Items.RABBIT, 0.35F));
recipes.add(RecipeInfo.smelting(Items.COOKED_MUTTON, Items.MUTTON, 0.35F));
recipes.add(RecipeInfo.smelting(Items.CRACKED_STONE_BRICKS, Items.STONE_BRICKS, 0.1F));
recipes.add(RecipeInfo.smelting(Items.SPONGE, Items.WET_SPONGE, 0.15F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_6_1)) {
recipes.add(RecipeInfo.smelting(Items.TERRACOTTA, Items.CLAY, 0.35F));
recipes.add(RecipeInfo.smelting(Items.COOKED_SALMON, Items.SALMON, 0.35F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_5tor1_5_1)) {
recipes.add(RecipeInfo.smelting(Items.NETHER_BRICK, Items.NETHERRACK, 0.1F));
recipes.add(RecipeInfo.smelting(Items.QUARTZ, Items.NETHER_QUARTZ_ORE, 0.2F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_4_2)) {
recipes.add(RecipeInfo.smelting(Items.BAKED_POTATO, Items.POTATO, 0.35F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_3_1tor1_3_2)) {
recipes.add(RecipeInfo.smelting(Items.EMERALD, Items.EMERALD_ORE, 1.0F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_0_0tor1_0_1)) {
recipes.add(RecipeInfo.smelting(Items.COAL, Items.COAL_ORE, 0.1F));
recipes.add(RecipeInfo.smelting(Items.REDSTONE, Items.REDSTONE_ORE, 0.7F));
recipes.add(RecipeInfo.smelting(Items.LAPIS_LAZULI, Items.LAPIS_ORE, 0.2F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_8tob1_8_1)) {
recipes.add(RecipeInfo.smelting(Items.COOKED_CHICKEN, Items.CHICKEN, 0.35F));
recipes.add(RecipeInfo.smelting(Items.COOKED_BEEF, Items.BEEF, 0.35F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.b1_2_0tob1_2_2)) {
recipes.add(RecipeInfo.smelting(Items.CHARCOAL, Ingredient.fromTag(ItemTags.LOGS), 0.15F));
recipes.add(RecipeInfo.smelting(Items.GREEN_DYE, Items.CACTUS, 0.2F));
}
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.a1_2_0toa1_2_1_1)) {
recipes.add(RecipeInfo.smelting(Items.COOKED_COD, Items.COD, 0.35F));
}
return recipes;
}
/**
* Sets the result slot of a crafting screen handler to the correct item stack. In MC <= 1.11.2 the result slot
* is not updated when the input slots change, so we need to update it manually, Spigot and Paper re-syncs the slot,
* so we don't notice this bug on servers that use Spigot or Paper
*
* @param syncId The sync id of the screen handler
* @param screenHandler The screen handler
* @param inventory The inventory of the screen handler
*/
public static void setCraftingResultSlot(final int syncId, final ScreenHandler screenHandler, final RecipeInputInventory inventory) {
final var network = MinecraftClient.getInstance().getNetworkHandler();
final var world = MinecraftClient.getInstance().world;
final var result = network.getRecipeManager()
.getFirstMatch(RecipeType.CRAFTING, inventory, world) // Get the first matching recipe
.map(recipe -> recipe.value().craft(inventory, network.getRegistryManager())) // Craft the recipe to get the result
.orElse(ItemStack.EMPTY); // If there is no recipe, set the result to air
// Update the result slot
network.onScreenHandlerSlotUpdate(new ScreenHandlerSlotUpdateS2CPacket(syncId, screenHandler.getRevision(), 0, result));
}
}

View File

@ -0,0 +1,30 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.access;
public interface IChunkTracker {
int viaFabricPlus$getSubChunkRequests();
int viaFabricPlus$getPendingSubChunks();
int viaFabricPlus$getChunks();
}

View File

@ -21,7 +21,7 @@ package de.florianmichael.viafabricplus.injection.access;
public interface IItemStack { public interface IItemStack {
boolean viaFabricPlus$has1_10ProtocolHackTag(); boolean viaFabricPlus$has1_10ViaFabricPlusTag();
int viaFabricPlus$get1_10Count(); int viaFabricPlus$get1_10Count();

View File

@ -0,0 +1,28 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.access;
import java.util.Queue;
public interface IMouseKeyboard {
Queue<Runnable> viaFabricPlus$getPendingScreenEvents();
}

View File

@ -0,0 +1,28 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.access;
public interface IRakSessionCodec {
int viaFabricPlus$getOutgoingPackets();
int viaFabricPlus$SentDatagrams();
}

View File

@ -21,5 +21,8 @@ package de.florianmichael.viafabricplus.injection.access;
public interface IScreenHandler { public interface IScreenHandler {
short viaFabricPlus$getAndIncrementLastActionId(); short viaFabricPlus$getActionId();
short viaFabricPlus$incrementAndGetActionId();
} }

View File

@ -0,0 +1,62 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.base.integration;
import de.florianmichael.viafabricplus.injection.access.IChunkTracker;
import net.raphimc.viabedrock.api.chunk.BedrockChunk;
import net.raphimc.viabedrock.protocol.storage.ChunkTracker;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Map;
import java.util.Set;
@Mixin(value = ChunkTracker.class, remap = false)
public abstract class MixinChunkTracker implements IChunkTracker {
@Shadow
@Final
private Set<?> subChunkRequests;
@Shadow
@Final
private Set<?> pendingSubChunks;
@Shadow
@Final
private Map<Long, BedrockChunk> chunks;
@Override
public int viaFabricPlus$getSubChunkRequests() {
return this.subChunkRequests.size();
}
@Override
public int viaFabricPlus$getPendingSubChunks() {
return this.pendingSubChunks.size();
}
@Override
public int viaFabricPlus$getChunks() {
return this.chunks.size();
}
}

View File

@ -19,30 +19,71 @@
package de.florianmichael.viafabricplus.injection.mixin.base.integration; package de.florianmichael.viafabricplus.injection.mixin.base.integration;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.ViaFabricPlus; import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.protocolhack.provider.vialegacy.ViaFabricPlusClassicMPPassProvider; import de.florianmichael.viafabricplus.injection.access.IServerInfo;
import de.florianmichael.viafabricplus.settings.impl.AuthenticationSettings; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.MinecraftClient; import de.florianmichael.viafabricplus.settings.impl.GeneralSettings;
import net.minecraft.network.ClientConnection; import net.lenni0451.mcping.MCPing;
import net.minecraft.network.packet.Packet; import net.minecraft.client.gui.screen.ConnectScreen;
import net.minecraft.network.packet.c2s.login.LoginHelloC2SPacket; import net.minecraft.client.network.ServerInfo;
import net.minecraft.client.session.Session;
import net.minecraft.text.Text;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.net.InetSocketAddress;
@Mixin(targets = "net.minecraft.client.gui.screen.ConnectScreen$1") @Mixin(targets = "net.minecraft.client.gui.screen.ConnectScreen$1")
public abstract class MixinConnectScreen_1 { public abstract class MixinConnectScreen_1 {
@Redirect(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;send(Lnet/minecraft/network/packet/Packet;)V")) @Shadow
private void spoofUserName(ClientConnection instance, Packet<?> packet) { @Final
if (AuthenticationSettings.global().setSessionNameToClassiCubeNameInServerList.getValue() && ViaFabricPlusClassicMPPassProvider.classiCubeMPPass != null) { ServerInfo field_40415;
final var account = ViaFabricPlus.global().getSaveManager().getAccountsSave().getClassicubeAccount();
if (account != null) { @Shadow
instance.send(new LoginHelloC2SPacket(account.username(), MinecraftClient.getInstance().getSession().getUuidOrNull())); @Final
return; ConnectScreen field_2416;
}
@Redirect(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/session/Session;getUsername()Ljava/lang/String;"))
private String useClassiCubeUsername(Session instance) {
final var account = ViaFabricPlus.global().getSaveManager().getAccountsSave().getClassicubeAccount();
if (account != null) {
return account.username();
} }
instance.send(packet); return instance.getUsername();
} }
}
@SuppressWarnings("InvalidInjectorMethodSignature")
@Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;connect(Ljava/net/InetSocketAddress;ZLnet/minecraft/network/ClientConnection;)Lio/netty/channel/ChannelFuture;", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD)
private void setServerInfo(CallbackInfo ci, InetSocketAddress inetSocketAddress) {
final VersionEnum serverVersion = ((IServerInfo) this.field_40415).viaFabricPlus$forcedVersion();
if (serverVersion != null) {
ProtocolHack.setTargetVersion(serverVersion);
} else if (GeneralSettings.global().autoDetectVersion.getValue()) {
this.field_2416.setStatus(Text.translatable("base.viafabricplus.detecting_server_version"));
MCPing
.pingModern(-1)
.address(inetSocketAddress.getHostString(), inetSocketAddress.getPort())
.noResolve()
.timeout(1000, 1000)
.exceptionHandler(t -> {
})
.responseHandler(r -> {
if (ProtocolVersion.isRegistered(r.version.protocol)) {
ProtocolHack.setTargetVersion(VersionEnum.fromProtocolId(r.version.protocol));
}
})
.getSync();
}
}
}

View File

@ -26,21 +26,26 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.fixes.tracker.JoinGameTracker; import de.florianmichael.viafabricplus.fixes.tracker.JoinGameTracker;
import de.florianmichael.viafabricplus.injection.ViaFabricPlusMixinPlugin; import de.florianmichael.viafabricplus.injection.ViaFabricPlusMixinPlugin;
import de.florianmichael.viafabricplus.injection.access.IBlobCache; import de.florianmichael.viafabricplus.injection.access.IBlobCache;
import de.florianmichael.viafabricplus.injection.access.IChunkTracker;
import de.florianmichael.viafabricplus.injection.access.IRakSessionCodec;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.protocolhack.provider.viabedrock.ViaFabricPlusBlobCacheProvider; import de.florianmichael.viafabricplus.protocolhack.provider.viabedrock.ViaFabricPlusBlobCacheProvider;
import de.florianmichael.viafabricplus.settings.impl.GeneralSettings; import de.florianmichael.viafabricplus.settings.impl.GeneralSettings;
import de.florianmichael.viafabricplus.util.ChatUtil; import de.florianmichael.viafabricplus.util.ChatUtil;
import de.florianmichael.viafabricplus.util.StringUtil; import de.florianmichael.viafabricplus.util.StringUtil;
import net.lenni0451.reflect.stream.RStream;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.DebugHud; import net.minecraft.client.gui.hud.DebugHud;
import net.minecraft.util.Formatting;
import net.raphimc.viabedrock.protocol.data.enums.bedrock.ServerMovementModes; import net.raphimc.viabedrock.protocol.data.enums.bedrock.ServerMovementModes;
import net.raphimc.viabedrock.protocol.providers.BlobCacheProvider; import net.raphimc.viabedrock.protocol.providers.BlobCacheProvider;
import net.raphimc.viabedrock.protocol.storage.BlobCache; import net.raphimc.viabedrock.protocol.storage.BlobCache;
import net.raphimc.viabedrock.protocol.storage.ChunkTracker;
import net.raphimc.viabedrock.protocol.storage.GameSessionStorage; import net.raphimc.viabedrock.protocol.storage.GameSessionStorage;
import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.storage.ExtensionProtocolMetadataStorage; import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.storage.ExtensionProtocolMetadataStorage;
import net.raphimc.vialegacy.protocols.release.protocol1_2_1_3to1_1.storage.SeedStorage; import net.raphimc.vialegacy.protocols.release.protocol1_2_1_3to1_1.storage.SeedStorage;
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.storage.EntityTracker; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.storage.EntityTracker;
import org.cloudburstmc.netty.channel.raknet.RakClientChannel;
import org.cloudburstmc.netty.handler.codec.raknet.common.RakSessionCodec;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@ -48,8 +53,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("DataFlowIssue") @SuppressWarnings("DataFlowIssue")
@Mixin(DebugHud.class) @Mixin(DebugHud.class)
@ -69,19 +72,39 @@ public abstract class MixinDebugHud {
information.add(""); information.add("");
// Title // Title
information.add(ChatUtil.PREFIX + " " + ViaFabricPlusMixinPlugin.VFP_VERSION); information.add(ChatUtil.PREFIX + Formatting.GRAY + " " + ViaFabricPlusMixinPlugin.VFP_VERSION);
// common // common
final ProtocolInfo info = userConnection.getProtocolInfo(); final ProtocolInfo info = userConnection.getProtocolInfo();
information.add( information.add(
"P: " + info.getPipeline().pipes().size() + "P: " + info.getPipeline().pipes().size() +
" / C: " + ProtocolVersion.getProtocol(info.getProtocolVersion()) + " C: " + ProtocolVersion.getProtocol(info.getProtocolVersion()) +
" / S: " + ProtocolVersion.getProtocol(info.getServerProtocolVersion()) " S: " + ProtocolVersion.getProtocol(info.getServerProtocolVersion())
); );
// r1_7_10
final EntityTracker entityTracker1_7_10 = userConnection.get(EntityTracker.class);
if (entityTracker1_7_10 != null) {
information.add(
"1.7 Entities: " + entityTracker1_7_10.getTrackedEntities().size() +
", Virtual holograms: " + entityTracker1_7_10.getVirtualHolograms().size()
);
}
// r1_1
final SeedStorage seedStorage = userConnection.get(SeedStorage.class);
if (seedStorage != null) {
information.add("World Seed: " + seedStorage.seed);
}
// c0.30cpe
final ExtensionProtocolMetadataStorage extensionProtocolMetadataStorage = userConnection.get(ExtensionProtocolMetadataStorage.class);
if (extensionProtocolMetadataStorage != null) {
information.add("CPE extensions: " + extensionProtocolMetadataStorage.getExtensionCount());
}
// bedrock // bedrock
final JoinGameTracker joinGameTracker = userConnection.get(JoinGameTracker.class); final JoinGameTracker joinGameTracker = userConnection.get(JoinGameTracker.class);
if (joinGameTracker != null) { if (joinGameTracker != null) {
final int movementMode = userConnection.get(GameSessionStorage.class).getMovementMode(); final int movementMode = userConnection.get(GameSessionStorage.class).getMovementMode();
String movement = "Server with rewind"; String movement = "Server with rewind";
@ -91,7 +114,10 @@ public abstract class MixinDebugHud {
movement = "Server"; movement = "Server";
} }
information.add("Bedrock Level: " + joinGameTracker.getLevelId() + " / Enchantment Seed: " + joinGameTracker.getEnchantmentSeed() + " / Movement: " + movement); information.add("Bedrock Level: " + joinGameTracker.getLevelId() + ", Enchantment Seed: " + joinGameTracker.getEnchantmentSeed() + ", Movement: " + movement);
}
if (joinGameTracker != null) {
information.add("World Seed: " + joinGameTracker.getSeed());
} }
final BlobCache blobCache = userConnection.get(BlobCache.class); final BlobCache blobCache = userConnection.get(BlobCache.class);
if (blobCache != null) { if (blobCache != null) {
@ -101,34 +127,24 @@ public abstract class MixinDebugHud {
final int blobCount = blobCacheProvider.getBlobs().size(); final int blobCount = blobCacheProvider.getBlobs().size();
final int pendingCount = ((IBlobCache) blobCache).viaFabricPlus$getPending().size(); final int pendingCount = ((IBlobCache) blobCache).viaFabricPlus$getPending().size();
if (totalSize != 0 || blobCount != 0 || pendingCount != 0) { information.add("Blob Cache: S: " + StringUtil.formatBytes(totalSize) + ", C: " + blobCount + ", P: " + pendingCount);
information.add("Blob Cache: S: " + StringUtil.formatBytes(totalSize) + " / C: " + blobCount + " / Pending: " + pendingCount); }
final ChunkTracker chunkTracker = userConnection.get(ChunkTracker.class);
if (chunkTracker != null) {
final int subChunkRequests = ((IChunkTracker) chunkTracker).viaFabricPlus$getSubChunkRequests();
final int pendingSubChunks = ((IChunkTracker) chunkTracker).viaFabricPlus$getPendingSubChunks();
final int chunks = ((IChunkTracker) chunkTracker).viaFabricPlus$getChunks();
cir.getReturnValue().add("Chunk Tracker: R: " + subChunkRequests + ", P: " + pendingSubChunks + ", C: " + chunks);
}
if (userConnection.getChannel() instanceof RakClientChannel rakClientChannel) {
final RakSessionCodec rakSessionCodec = rakClientChannel.parent().pipeline().get(RakSessionCodec.class);
if (rakSessionCodec != null) {
final int transmitQueue = ((IRakSessionCodec) rakSessionCodec).viaFabricPlus$getOutgoingPackets();
final int retransmitQueue = ((IRakSessionCodec) rakSessionCodec).viaFabricPlus$SentDatagrams();
cir.getReturnValue().add("RTT: " + Math.round(rakSessionCodec.getRTT()) + " ms, P: " + rakSessionCodec.getPing() + " ms" + ", TQ: " + transmitQueue + ", RTQ: " + retransmitQueue);
} }
} }
// r1_7_10
final EntityTracker entityTracker1_7_10 = userConnection.get(EntityTracker.class);
if (entityTracker1_7_10 != null) {
information.add(
"1.7 Entities: " + entityTracker1_7_10.getTrackedEntities().size() +
" / Virtual holograms: " + entityTracker1_7_10.getVirtualHolograms().size()
);
}
// r1_1 and bedrock
final SeedStorage seedStorage = userConnection.get(SeedStorage.class);
if (seedStorage != null) {
information.add("World Seed: " + seedStorage.seed);
} else if (joinGameTracker != null) {
information.add("World Seed: " + joinGameTracker.getSeed());
}
// c0.30cpe
final ExtensionProtocolMetadataStorage extensionProtocolMetadataStorage = userConnection.get(ExtensionProtocolMetadataStorage.class);
if (extensionProtocolMetadataStorage != null) {
information.add("CPE extensions: " + extensionProtocolMetadataStorage.getExtensionCount());
}
information.add(""); information.add("");
cir.getReturnValue().addAll(information); cir.getReturnValue().addAll(information);

View File

@ -45,6 +45,9 @@ public abstract class MixinDownloadingTerrainScreen extends Screen {
if (GeneralSettings.global().showClassicLoadingProgressInConnectScreen.getValue()) { if (GeneralSettings.global().showClassicLoadingProgressInConnectScreen.getValue()) {
// Check if ViaVersion is translating // Check if ViaVersion is translating
final UserConnection connection = ProtocolHack.getPlayNetworkUserConnection(); final UserConnection connection = ProtocolHack.getPlayNetworkUserConnection();
if (connection == null) {
return;
}
// Check if the client is connecting to a classic server // Check if the client is connecting to a classic server
final ClassicProgressStorage classicProgressStorage = connection.get(ClassicProgressStorage.class); final ClassicProgressStorage classicProgressStorage = connection.get(ClassicProgressStorage.class);

View File

@ -21,20 +21,15 @@ package de.florianmichael.viafabricplus.injection.mixin.base.integration;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import de.florianmichael.viafabricplus.injection.access.IServerInfo;
import de.florianmichael.viafabricplus.settings.impl.GeneralSettings;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget; import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
import net.minecraft.client.network.ServerInfo; import net.minecraft.client.network.ServerInfo;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Mixin(MultiplayerServerListWidget.ServerEntry.class) @Mixin(MultiplayerServerListWidget.ServerEntry.class)
@ -46,7 +41,7 @@ public abstract class MixinMultiplayerServerListWidget_ServerEntry {
@WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerScreen;setMultiplayerScreenTooltip(Ljava/util/List;)V", ordinal = 0)) @WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerScreen;setMultiplayerScreenTooltip(Ljava/util/List;)V", ordinal = 0))
private void drawTranslatingState(MultiplayerScreen instance, List<Text> tooltip, Operation<Void> original) { private void drawTranslatingState(MultiplayerScreen instance, List<Text> tooltip, Operation<Void> original) {
if (GeneralSettings.global().showAdvertisedServerVersion.getValue()) { /*if (GeneralSettings.global().showAdvertisedServerVersion.getValue()) {
final IServerInfo mixinServerInfo = ((IServerInfo) server); final IServerInfo mixinServerInfo = ((IServerInfo) server);
if (mixinServerInfo.viaFabricPlus$enabled()) { if (mixinServerInfo.viaFabricPlus$enabled()) {
@ -55,7 +50,7 @@ public abstract class MixinMultiplayerServerListWidget_ServerEntry {
tooltip.add(Text.translatable("base.viafabricplus.via_translates_to", versionEnum != VersionEnum.UNKNOWN ? versionEnum.getName() + " (" + versionEnum.getVersion() + ")" : mixinServerInfo.viaFabricPlus$translatingVersion())); tooltip.add(Text.translatable("base.viafabricplus.via_translates_to", versionEnum != VersionEnum.UNKNOWN ? versionEnum.getName() + " (" + versionEnum.getVersion() + ")" : mixinServerInfo.viaFabricPlus$translatingVersion()));
tooltip.add(Text.translatable("base.viafabricplus.server_version", server.version.getString() + " (" + server.protocolVersion + ")")); tooltip.add(Text.translatable("base.viafabricplus.server_version", server.version.getString() + " (" + server.protocolVersion + ")"));
} }
} }*/
original.call(instance, tooltip); original.call(instance, tooltip);
} }

View File

@ -0,0 +1,50 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.base.integration;
import de.florianmichael.viafabricplus.injection.access.IRakSessionCodec;
import io.netty.util.collection.IntObjectMap;
import org.cloudburstmc.netty.channel.raknet.packet.EncapsulatedPacket;
import org.cloudburstmc.netty.channel.raknet.packet.RakDatagramPacket;
import org.cloudburstmc.netty.handler.codec.raknet.common.RakSessionCodec;
import org.cloudburstmc.netty.util.FastBinaryMinHeap;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(value = RakSessionCodec.class, remap = false)
public abstract class MixinRakSessionCodec implements IRakSessionCodec {
@Shadow
private FastBinaryMinHeap<EncapsulatedPacket> outgoingPackets;
@Shadow
private IntObjectMap<RakDatagramPacket> sentDatagrams;
@Override
public int viaFabricPlus$getOutgoingPackets() {
return this.outgoingPackets.size();
}
@Override
public int viaFabricPlus$SentDatagrams() {
return this.sentDatagrams.size();
}
}

View File

@ -39,4 +39,5 @@ public abstract class MixinKeyPairResponse implements ILegacyKeySignatureStorage
public void viafabricplus$setLegacyPublicKeySignature(byte[] signature) { public void viafabricplus$setLegacyPublicKeySignature(byte[] signature) {
this.viaFabricPlus$legacyKeySignature = signature; this.viaFabricPlus$legacyKeySignature = signature;
} }
} }

View File

@ -22,8 +22,9 @@ package de.florianmichael.viafabricplus.injection.mixin.fixes.authlib;
import com.mojang.authlib.minecraft.client.MinecraftClient; import com.mojang.authlib.minecraft.client.MinecraftClient;
import com.mojang.authlib.yggdrasil.YggdrasilUserApiService; import com.mojang.authlib.yggdrasil.YggdrasilUserApiService;
import com.mojang.authlib.yggdrasil.response.KeyPairResponse; import com.mojang.authlib.yggdrasil.response.KeyPairResponse;
import de.florianmichael.viafabricplus.injection.reference.KeyPairResponse1_19_0; import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.injection.access.ILegacyKeySignatureStorage; import de.florianmichael.viafabricplus.injection.access.ILegacyKeySignatureStorage;
import de.florianmichael.viafabricplus.injection.reference.KeyPairResponse1_19_0;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -36,9 +37,13 @@ import java.net.URL;
@Mixin(value = YggdrasilUserApiService.class, remap = false) @Mixin(value = YggdrasilUserApiService.class, remap = false)
public abstract class MixinYggdrasilUserApiService { public abstract class MixinYggdrasilUserApiService {
@Shadow @Final private MinecraftClient minecraftClient; @Shadow
@Final
private MinecraftClient minecraftClient;
@Shadow @Final private URL routeKeyPair; @Shadow
@Final
private URL routeKeyPair;
@Inject(method = "getKeyPair", at = @At("HEAD"), cancellable = true) @Inject(method = "getKeyPair", at = @At("HEAD"), cancellable = true)
private void storeLegacyPublicKeySignature(CallbackInfoReturnable<KeyPairResponse> cir) { private void storeLegacyPublicKeySignature(CallbackInfoReturnable<KeyPairResponse> cir) {
@ -58,8 +63,11 @@ public abstract class MixinYggdrasilUserApiService {
response.refreshedAfter() response.refreshedAfter()
); );
// set the legacy public key signature in the object if (response.publicKeySignature() != null && response.publicKeySignature().array().length != 0) {
((ILegacyKeySignatureStorage) (Object) keyPairResponse).viafabricplus$setLegacyPublicKeySignature(response.publicKeySignature().array()); ((ILegacyKeySignatureStorage) (Object) keyPairResponse).viafabricplus$setLegacyPublicKeySignature(response.publicKeySignature().array());
} else {
ViaFabricPlus.global().getLogger().error("Could not get legacy public key signature. 1.19.0 with secure-profiles enabled will not work!");
}
cir.setReturnValue(keyPairResponse); cir.setReturnValue(keyPairResponse);
} }

View File

@ -17,29 +17,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.fixes.TripleChestHandler1_13_2;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.client.network.Address;
import net.minecraft.client.gui.screen.ingame.HandledScreens; import net.minecraft.client.network.AddressResolver;
import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.client.network.AllowedAddressResolver;
import net.minecraft.screen.ScreenHandler; import net.minecraft.client.network.ServerAddress;
import net.minecraft.screen.ScreenHandlerType;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(HandledScreens.class) import java.util.Optional;
public abstract class MixinHandledScreens {
@Inject(method = "getProvider", at = @At("HEAD"), cancellable = true) @Mixin(AllowedAddressResolver.class)
private static <T extends ScreenHandler> void returnFakeProvider(ScreenHandlerType<T> type, CallbackInfoReturnable<HandledScreens.@Nullable Provider> cir) { public abstract class MixinAllowedAddressResolver {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2) && type instanceof TripleChestHandler1_13_2.TripleChestScreenHandlerType) {
cir.setReturnValue((handler, playerInventory, title) -> new GenericContainerScreen((GenericContainerScreenHandler) handler, playerInventory, title)); @Shadow
@Final
private AddressResolver addressResolver;
@Inject(method = "resolve", at = @At("HEAD"), cancellable = true)
private void oldResolveBehaviour(ServerAddress address, CallbackInfoReturnable<Optional<Address>> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_4tor1_16_5) || ProtocolHack.getTargetVersion().equals(VersionEnum.bedrockLatest)) {
cir.setReturnValue(this.addressResolver.resolve(address));
} }
} }

View File

@ -17,24 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.merchant; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import net.raphimc.vialoader.util.VersionEnum;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.screen.MerchantScreenHandler; import net.minecraft.client.render.chunk.ChunkBuilder;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(MerchantScreenHandler.class) @Mixin(ChunkBuilder.BuiltChunk.class)
public abstract class MixinMerchantScreenHandler { public abstract class MixinBuiltChunk {
@Inject(method = "switchTo", at = @At("HEAD"), cancellable = true) @Inject(method = "shouldBuild", at = @At("HEAD"), cancellable = true)
private void dontSwitchTo(int recipeId, CallbackInfo ci) { private void modifyRenderCondition(CallbackInfoReturnable<Boolean> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
ci.cancel(); cir.setReturnValue(true);
} }
} }

View File

@ -0,0 +1,95 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ChatInputSuggestor;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.OrderedText;
import net.minecraft.text.Style;
import net.raphimc.vialoader.util.VersionEnum;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@Mixin(ChatInputSuggestor.class)
public abstract class MixinChatInputSuggestor {
@Shadow
public abstract void refresh();
@Shadow
@Nullable
private ChatInputSuggestor.@Nullable SuggestionWindow window;
@Shadow
@Final
TextFieldWidget textField;
@Shadow
@Final
private List<OrderedText> messages;
@Inject(method = "provideRenderText", at = @At(value = "HEAD"), cancellable = true)
private void disableTextFieldColors(String original, int firstCharacterIndex, CallbackInfoReturnable<OrderedText> cir) {
if (!this.cancelTabComplete()) return;
cir.setReturnValue(OrderedText.styledForwardsVisitedString(original, Style.EMPTY));
}
@Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true)
private void handle1_12_2KeyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
if (!this.cancelTabComplete()) return;
if (keyCode == GLFW.GLFW_KEY_TAB && this.window == null) {
this.refresh();
} else if (this.window != null) {
if (this.window.keyPressed(keyCode, scanCode, modifiers)) {
cir.setReturnValue(true);
return;
}
this.textField.setSuggestion(null);
this.window = null;
}
}
@Inject(method = "render", at = @At("HEAD"))
private void clearMessages(DrawContext drawContext, int mouseX, int mouseY, CallbackInfo ci) {
if (!this.cancelTabComplete()) return;
this.messages.clear();
}
@Unique
private boolean cancelTabComplete() {
return ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2) && this.textField.getText().startsWith("/");
}
}

View File

@ -0,0 +1,49 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.network.ClientCommandSource;
import net.raphimc.vialoader.util.VersionEnum;
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.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Collection;
import java.util.Set;
@Mixin(ClientCommandSource.class)
public abstract class MixinClientCommandSource {
@Shadow
@Final
private Set<String> chatSuggestions;
@Inject(method = {"getPlayerNames", "getChatSuggestions"}, at = @At("HEAD"), cancellable = true)
private void returnChatSuggestions(CallbackInfoReturnable<Collection<String>> cir) {
if (ProtocolHack.getTargetVersion().equals(VersionEnum.bedrockLatest)) {
cir.setReturnValue(this.chatSuggestions);
}
}
}

View File

@ -1,200 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ServerboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.Protocol1_17To1_16_4;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.fixes.ClientPlayerInteractionManager1_18_2;
import de.florianmichael.viafabricplus.injection.access.IClientConnection;
import de.florianmichael.viafabricplus.injection.access.IScreenHandler;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.protocolhack.provider.viaversion.ViaFabricPlusHandItemProvider;
import de.florianmichael.viafabricplus.protocolhack.util.ItemTranslator;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.client.network.SequencedPacketCreator;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@SuppressWarnings("DataFlowIssue")
@Mixin(ClientPlayerInteractionManager.class)
public abstract class MixinClientPlayerInteractionManager {
@Shadow
@Final
private MinecraftClient client;
@Shadow
protected abstract ActionResult interactBlockInternal(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult);
@Shadow
@Final
private ClientPlayNetworkHandler networkHandler;
@Shadow
private BlockPos currentBreakingPos;
@Shadow private float currentBreakingProgress;
@Unique
private ItemStack viaFabricPlus$oldCursorStack;
@Unique
private List<ItemStack> viaFabricPlus$oldItems;
@Inject(method = "getBlockBreakingProgress", at = @At("HEAD"), cancellable = true)
private void changeCalculation(CallbackInfoReturnable<Integer> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_4)) {
cir.setReturnValue((int)(this.currentBreakingProgress * 10.0F) - 1);
}
}
@Inject(method = "sendSequencedPacket", at = @At("HEAD"))
private void handleBlockAcknowledgements(ClientWorld world, SequencedPacketCreator packetCreator, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isBetweenInclusive(VersionEnum.r1_14_4, VersionEnum.r1_18_2) && packetCreator instanceof PlayerActionC2SPacket playerActionC2SPacket) {
ClientPlayerInteractionManager1_18_2.trackBlockAction(playerActionC2SPacket.getAction(), playerActionC2SPacket.getPos());
}
}
@ModifyVariable(method = "clickSlot", at = @At(value = "STORE"), ordinal = 0)
private List<ItemStack> captureOldItems(List<ItemStack> oldItems) {
assert client.player != null;
viaFabricPlus$oldCursorStack = client.player.currentScreenHandler.getCursorStack().copy();
return this.viaFabricPlus$oldItems = oldItems;
}
// Special Cases
@Unique
private boolean viaFabricPlus$shouldEmpty(final SlotActionType type, final int slot) {
// quick craft always uses empty stack for verification
if (type == SlotActionType.QUICK_CRAFT) return true;
// quick move always uses empty stack for verification since 1.12
if (type == SlotActionType.QUICK_MOVE && ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_11_1to1_11_2)) return true;
// pickup with slot -999 (outside window) to throw items always uses empty stack for verification
return type == SlotActionType.PICKUP && slot == -999;
}
@WrapWithCondition(method = "clickSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V"))
private boolean modifySlotClickPacket(ClientPlayNetworkHandler instance, Packet<?> packet) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_4tor1_16_5) && packet instanceof ClickSlotC2SPacket clickSlot) {
ItemStack slotItemBeforeModification;
if (this.viaFabricPlus$shouldEmpty(clickSlot.getActionType(), clickSlot.getSlot()))
slotItemBeforeModification = ItemStack.EMPTY;
else if (clickSlot.getSlot() < 0 || clickSlot.getSlot() >= viaFabricPlus$oldItems.size())
slotItemBeforeModification = viaFabricPlus$oldCursorStack;
else
slotItemBeforeModification = viaFabricPlus$oldItems.get(clickSlot.getSlot());
final var clickSlotPacket = PacketWrapper.create(ServerboundPackets1_16_2.CLICK_WINDOW, ((IClientConnection)networkHandler.getConnection()).viaFabricPlus$getUserConnection());
clickSlotPacket.write(Type.UNSIGNED_BYTE, (short) clickSlot.getSyncId());
clickSlotPacket.write(Type.SHORT, (short) clickSlot.getSlot());
clickSlotPacket.write(Type.BYTE, (byte) clickSlot.getButton());
clickSlotPacket.write(Type.SHORT, ((IScreenHandler) client.player.currentScreenHandler).viaFabricPlus$getAndIncrementLastActionId());
clickSlotPacket.write(Type.VAR_INT, clickSlot.getActionType().ordinal());
clickSlotPacket.write(Type.ITEM1_13_2, ItemTranslator.MC_TO_VIA_LATEST_TO_TARGET(slotItemBeforeModification, VersionEnum.r1_16));
try {
clickSlotPacket.sendToServer(Protocol1_17To1_16_4.class);
} catch (Exception e) {
ViaFabricPlus.global().getLogger().error("Failed to send Click Slot Packet", e);
}
viaFabricPlus$oldCursorStack = null;
viaFabricPlus$oldItems = null;
return false;
}
return true;
}
@WrapWithCondition(method = "interactItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V", ordinal = 0),
slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;syncSelectedSlot()V"),
to = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;sendSequencedPacket(Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/client/network/SequencedPacketCreator;)V", ordinal = 0)))
private boolean redirectInteractItem(ClientPlayNetworkHandler instance, Packet<?> packet) {
return ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_17);
}
@Inject(method = "breakBlock", at = @At("TAIL"))
private void resetBlockBreaking(BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_14_3)) {
this.currentBreakingPos = new BlockPos(this.currentBreakingPos.getX(), -1, this.currentBreakingPos.getZ());
}
}
@Unique
private ActionResult viaFabricPlus$actionResult;
@Inject(method = "interactBlock", at = @At("HEAD"), cancellable = true)
private void cacheActionResult(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable<ActionResult> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) {
this.viaFabricPlus$actionResult = this.interactBlockInternal(player, hand, hitResult);
if (this.viaFabricPlus$actionResult == ActionResult.FAIL) {
cir.setReturnValue(this.viaFabricPlus$actionResult);
}
}
}
@Redirect(method = "method_41933", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;interactBlockInternal(Lnet/minecraft/client/network/ClientPlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;"))
private ActionResult provideCachedResult(ClientPlayerInteractionManager instance, ClientPlayerEntity player, Hand hand, BlockHitResult hitResult) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) {
return this.viaFabricPlus$actionResult;
}
return interactBlockInternal(player, hand, hitResult);
}
@Inject(method = "interactItem", at = @At("HEAD"))
private void trackLastUsedItem(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
ViaFabricPlusHandItemProvider.lastUsedItem = player.getStackInHand(hand).copy();
}
@Inject(method = "interactBlock", at = @At("HEAD"))
private void trackLastUsedBlock(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable<ActionResult> cir) {
ViaFabricPlusHandItemProvider.lastUsedItem = player.getStackInHand(hand).copy();
}
}

View File

@ -0,0 +1,135 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.fixes.PendingUpdateManager1_18_2;
import de.florianmichael.viafabricplus.injection.access.IEntity;
import de.florianmichael.viafabricplus.settings.impl.DebugSettings;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.PendingUpdateManager;
import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.world.EntityList;
import net.minecraft.world.MutableWorldProperties;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.function.Supplier;
@Mixin(value = ClientWorld.class, priority = 900)
public abstract class MixinClientWorld extends World {
@Shadow
@Final
EntityList entityList;
@Mutable
@Shadow
@Final
private PendingUpdateManager pendingUpdateManager;
protected MixinClientWorld(MutableWorldProperties properties, RegistryKey<World> registryRef, DynamicRegistryManager registryManager, RegistryEntry<DimensionType> dimensionEntry, Supplier<Profiler> profiler, boolean isClient, boolean debugWorld, long biomeAccess, int maxChainedNeighborUpdates) {
super(properties, registryRef, registryManager, dimensionEntry, profiler, isClient, debugWorld, biomeAccess, maxChainedNeighborUpdates);
}
@Inject(method = "<init>", at = @At("RETURN"))
private void removePendingUpdateManager(ClientPlayNetworkHandler networkHandler, ClientWorld.Properties properties, RegistryKey<World> registryRef, RegistryEntry<DimensionType> dimensionTypeEntry, int loadDistance, int simulationDistance, Supplier<Profiler> profiler, WorldRenderer worldRenderer, boolean debugWorld, long seed, CallbackInfo ci) {
if (DebugSettings.global().disableSequencing.isEnabled()) {
this.pendingUpdateManager = new PendingUpdateManager1_18_2();
}
}
/**
* @author RK_01
* @reason ProtocolHack
*/
@Overwrite
public void tickEntity(Entity entity) {
entity.resetPosition();
final IEntity mixinEntity = (IEntity) entity;
if (mixinEntity.viaFabricPlus$isInLoadedChunkAndShouldTick() || entity.isSpectator()) {
entity.age++;
this.getProfiler().push(() -> Registries.ENTITY_TYPE.getId(entity.getType()).toString());
entity.tick();
this.getProfiler().pop();
}
this.checkChunk(entity);
if (mixinEntity.viaFabricPlus$isInLoadedChunkAndShouldTick()) {
for (Entity entity2 : entity.getPassengerList()) {
this.tickPassenger(entity, entity2);
}
}
}
/**
* @author RK_01
* @reason ProtocolHack
*/
@Overwrite
private void tickPassenger(Entity entity, Entity passenger) {
if (!passenger.isRemoved() && passenger.getVehicle() == entity) {
if (passenger instanceof PlayerEntity || this.entityList.has(passenger)) {
final IEntity mixinPassenger = (IEntity) passenger;
passenger.resetPosition();
if (mixinPassenger.viaFabricPlus$isInLoadedChunkAndShouldTick()) {
passenger.age++;
passenger.tickRiding();
}
this.checkChunk(passenger);
if (mixinPassenger.viaFabricPlus$isInLoadedChunkAndShouldTick()) {
for (Entity entity2 : passenger.getPassengerList()) {
this.tickPassenger(passenger, entity2);
}
}
}
} else {
passenger.stopRiding();
}
}
@Unique
private void checkChunk(Entity entity) {
this.getProfiler().push("chunkCheck");
final IEntity mixinEntity = (IEntity) entity;
final int chunkX = MathHelper.floor(entity.getX() / 16.0D);
final int chunkZ = MathHelper.floor(entity.getZ() / 16.0D);
if (!mixinEntity.viaFabricPlus$isInLoadedChunkAndShouldTick() || entity.getChunkPos().x != chunkX || entity.getChunkPos().z != chunkZ) {
if (!(this.getChunk(chunkX, chunkZ).isEmpty())) {
mixinEntity.viaFabricPlus$setInLoadedChunkAndShouldTick(true);
}
}
this.getProfiler().pop();
}
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.enchantment.EnchantmentHelper;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(EnchantmentHelper.class)
public abstract class MixinEnchantmentHelper {
@ModifyConstant(method = "getLevelFromNbt", constant = @Constant(intValue = 0))
private static int usePossibleMinLevel(int constant) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_14_4)) {
return Short.MIN_VALUE;
}
return constant;
}
@ModifyConstant(method = "getLevelFromNbt", constant = @Constant(intValue = 255))
private static int usePossibleMaxLevel(int constant) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_14_4)) {
return Short.MAX_VALUE;
}
return constant;
}
}

View File

@ -0,0 +1,55 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.fixes.diff.Material1_19_4;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.block.*;
import net.minecraft.fluid.FlowableFluid;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(FlowableFluid.class)
public abstract class MixinFlowableFluid {
@Redirect(method = "isFlowBlocked", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;isSideSolidFullSquare(Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)Z"))
private boolean modifyIsSolidBlock(BlockState instance, BlockView blockView, BlockPos blockPos, Direction direction) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) {
return Material1_19_4.getMaterial(instance).solid();
} else if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2)) {
final Block block = instance.getBlock();
if (block instanceof ShulkerBoxBlock || block instanceof LeavesBlock || block instanceof TrapdoorBlock ||
block == Blocks.BEACON || block == Blocks.CAULDRON || block == Blocks.GLASS ||
block == Blocks.GLOWSTONE || block == Blocks.ICE || block == Blocks.SEA_LANTERN ||
block instanceof StainedGlassBlock || block == Blocks.PISTON || block == Blocks.STICKY_PISTON ||
block == Blocks.PISTON_HEAD || block instanceof StairsBlock) {
return false;
}
}
return instance.isSideSolidFullSquare(blockView, blockPos, direction);
}
}

View File

@ -19,9 +19,13 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import com.llamalad7.mixinextras.sugar.Local;
import de.florianmichael.viafabricplus.fixes.diff.RenderableGlyphDiff;
import de.florianmichael.viafabricplus.injection.reference.BuiltinEmptyGlyph1_12_2; import de.florianmichael.viafabricplus.injection.reference.BuiltinEmptyGlyph1_12_2;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.settings.impl.VisualSettings; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.*; import net.minecraft.client.font.*;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
@ -31,97 +35,89 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; 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.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
@Mixin(FontStorage.class) @Mixin(FontStorage.class)
public abstract class MixinFontStorage { public abstract class MixinFontStorage {
@Shadow @Shadow
protected abstract GlyphRenderer getGlyphRenderer(RenderableGlyph c); private GlyphRenderer blankGlyphRenderer;
@Shadow @Shadow
private GlyphRenderer blankGlyphRenderer; protected abstract GlyphRenderer getGlyphRenderer(RenderableGlyph c);
@Shadow @Shadow
@Final @Final
private Identifier id; private Identifier id;
@Unique @Unique
private Map<String, List<Integer>> viaFabricPlus$forbiddenCharacters; private GlyphRenderer blankGlyphRenderer1_12_2;
@Unique @Unique
private boolean viaFabricPlus$obfuscation; private Object2IntMap<Font> providedGlyphsCache;
@Inject(method = "setFonts", at = @At("HEAD")) @Inject(method = "setFonts", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/font/BuiltinEmptyGlyph;bake(Ljava/util/function/Function;)Lnet/minecraft/client/font/GlyphRenderer;", ordinal = 0))
private void trackForbiddenCharacters(List<Font> fonts, CallbackInfo ci) { private void bakeBlankGlyph1_12_2(List<Font> fonts, CallbackInfo ci) {
// viaFabricPlus$forbiddenCharacters = CharacterMappings.getForbiddenCharactersForID(this.id); this.blankGlyphRenderer1_12_2 = BuiltinEmptyGlyph1_12_2.INSTANCE.bake(this::getGlyphRenderer);
viaFabricPlus$forbiddenCharacters = new HashMap<>(); // TODO | Fix this.providedGlyphsCache = new Object2IntOpenHashMap<>();
}
@Inject(method = "findGlyph", at = @At("RETURN"), cancellable = true)
private void filterGlyphs1(int codePoint, CallbackInfoReturnable<FontStorage.GlyphPair> cir, @Local Font font) {
if (this.shouldBeInvisible(cir.getReturnValue().equals(FontStorage.GlyphPair.MISSING) ? null : font, codePoint)) {
cir.setReturnValue(this.getBlankGlyphPair());
}
}
@Inject(method = "findGlyphRenderer", at = @At("RETURN"), cancellable = true)
private void filterGlyphs2(int codePoint, CallbackInfoReturnable<GlyphRenderer> cir, @Local Font font) {
if (this.shouldBeInvisible(cir.getReturnValue().equals(this.blankGlyphRenderer) ? null : font, codePoint)) {
cir.setReturnValue(this.getBlankGlyphRenderer());
}
}
@Inject(method = "findGlyph", at = @At("RETURN"), cancellable = true)
private void fixBlankGlyph1_12_2(int codePoint, CallbackInfoReturnable<FontStorage.GlyphPair> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) {
final FontStorage.GlyphPair glyphPair = cir.getReturnValue();
final Glyph glyph1 = glyphPair.glyph();
final Glyph glyph2 = glyphPair.advanceValidatedGlyph();
cir.setReturnValue(new FontStorage.GlyphPair(glyph1 == BuiltinEmptyGlyph.MISSING ? BuiltinEmptyGlyph1_12_2.INSTANCE : glyph1, glyph2 == BuiltinEmptyGlyph.MISSING ? BuiltinEmptyGlyph1_12_2.INSTANCE : glyph2));
}
}
@Redirect(method = "findGlyphRenderer", at = @At(value = "FIELD", target = "Lnet/minecraft/client/font/FontStorage;blankGlyphRenderer:Lnet/minecraft/client/font/GlyphRenderer;"))
private GlyphRenderer fixBlankGlyphRenderer1_12_2(FontStorage instance) {
return this.getBlankGlyphRenderer();
} }
@Unique @Unique
private boolean viaFabricPlus$isForbiddenCharacter(final Font font, final int codePoint) { private boolean shouldBeInvisible(final Font font, final int codePoint) {
String fontName = null; if (font != null && this.providedGlyphsCache.computeIfAbsent(font, f -> ((Font) f).getProvidedGlyphs().size()) == 1) {
if (font instanceof BitmapFont) { return false; // Probably a custom icon character from a resource pack
fontName = "BitmapFont";
} else if (font instanceof BlankFont) {
fontName = "BlankFont";
} else if (font instanceof SpaceFont) {
fontName = "SpaceFont";
} else if (font instanceof UnihexFont) {
fontName = "UnihexFont";
} }
if (fontName == null) return false;
final var forbiddenCodepoints = viaFabricPlus$forbiddenCharacters.get(fontName); return (this.id.equals(MinecraftClient.DEFAULT_FONT_ID) || this.id.equals(MinecraftClient.UNICODE_FONT_ID)) && !RenderableGlyphDiff.isGlyphRenderable(codePoint);
if (forbiddenCodepoints == null) return false;
return forbiddenCodepoints.contains(codePoint);
} }
@Inject(method = "findGlyph", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/font/Font;getGlyph(I)Lnet/minecraft/client/font/Glyph;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) @Unique
private void injectFindGlyph(int codePoint, CallbackInfoReturnable<FontStorage.GlyphPair> cir, Glyph glyph, Iterator var3, Font font) { private FontStorage.GlyphPair getBlankGlyphPair() {
if (!this.id.getNamespace().equals("minecraft")) return; if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) {
return new FontStorage.GlyphPair(BuiltinEmptyGlyph1_12_2.INSTANCE, BuiltinEmptyGlyph1_12_2.INSTANCE);
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_4)) {
if (viaFabricPlus$isForbiddenCharacter(font, codePoint)) cir.setReturnValue(FontStorage.GlyphPair.MISSING);
if (VisualSettings.global().changeFontRendererBehaviour.isEnabled() && cir.getReturnValue() == FontStorage.GlyphPair.MISSING) {
cir.setReturnValue(new FontStorage.GlyphPair(BuiltinEmptyGlyph1_12_2.VERY_MISSING, BuiltinEmptyGlyph1_12_2.VERY_MISSING));
}
} }
return FontStorage.GlyphPair.MISSING;
} }
@Inject(method = "findGlyphRenderer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/font/Font;getGlyph(I)Lnet/minecraft/client/font/Glyph;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) @Unique
private void injectFindGlyphRenderer(int codePoint, CallbackInfoReturnable<GlyphRenderer> cir, Iterator var2, Font font) { private GlyphRenderer getBlankGlyphRenderer() {
if (!this.id.getNamespace().equals("minecraft")) return; if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) {
return this.blankGlyphRenderer1_12_2;
if (!viaFabricPlus$obfuscation && ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_4)) {
if (viaFabricPlus$isForbiddenCharacter(font, codePoint)) cir.setReturnValue(this.blankGlyphRenderer);
if (VisualSettings.global().changeFontRendererBehaviour.isEnabled() && cir.getReturnValue() == this.blankGlyphRenderer) {
cir.setReturnValue(BuiltinEmptyGlyph1_12_2.VERY_MISSING.bake(this::getGlyphRenderer));
}
} }
} return this.blankGlyphRenderer;
/*
Minecraft uses all characters that exist for obfuscation mode, even those that no longer exist in the selected target version,
so we must not make the fix in case it is executed from an obfuscated text, because otherwise the obfuscation would have missing characters
*/
@Inject(method = "getObfuscatedGlyphRenderer", at = @At("HEAD"))
private void trackObfuscationState(Glyph glyph, CallbackInfoReturnable<GlyphRenderer> cir) {
viaFabricPlus$obfuscation = true;
}
@Inject(method = "getGlyphRenderer(I)Lnet/minecraft/client/font/GlyphRenderer;", at = @At("RETURN"))
private void revertObfuscationState(int codePoint, CallbackInfoReturnable<GlyphRenderer> cir) {
viaFabricPlus$obfuscation = false;
} }
} }

View File

@ -0,0 +1,57 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.option.GameOptions;
import net.raphimc.vialoader.util.VersionEnum;
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.ModifyVariable;
@Mixin(GameOptions.class)
public abstract class MixinGameOptions {
@Shadow
public boolean useNativeTransport;
@ModifyVariable(method = "setServerViewDistance", at = @At("HEAD"), ordinal = 0, argsOnly = true)
private int changeServerViewDistance(int viewDistance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_17_1)) return 0;
return viewDistance;
}
/**
* @author RK_01
* @reason Needed as an indicator if the client wants to ping a server or connect to a server
*/
@Overwrite
public boolean shouldUseNativeTransport() {
if (!this.useNativeTransport) {
ViaFabricPlus.global().getLogger().error("Native transport is disabled, but enabling it anyway");
}
return true;
}
}

View File

@ -0,0 +1,68 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(GameRenderer.class)
public abstract class MixinGameRenderer {
@Shadow
@Final
MinecraftClient client;
@ModifyExpressionValue(method = "updateTargetedEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;raycast(DFZ)Lnet/minecraft/util/hit/HitResult;"))
private HitResult bedrockReachAroundRaycast(HitResult hitResult) {
if (ProtocolHack.getTargetVersion().equals(VersionEnum.bedrockLatest)) {
final Entity entity = this.client.getCameraEntity();
if (hitResult.getType() != HitResult.Type.MISS) return hitResult;
if (!this.canReachAround(entity)) return hitResult;
final int x = MathHelper.floor(entity.getX());
final int y = MathHelper.floor(entity.getY() - 0.2F);
final int z = MathHelper.floor(entity.getZ());
final BlockPos floorPos = new BlockPos(x, y, z);
return new BlockHitResult(floorPos.toCenterPos(), entity.getHorizontalFacing(), floorPos, false);
}
return hitResult;
}
@Unique
private boolean canReachAround(final Entity entity) {
return entity.isOnGround() && entity.getVehicle() == null && entity.getPitch() >= 45;
}
}

View File

@ -0,0 +1,60 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.injection.access.IMouseKeyboard;
import de.florianmichael.viafabricplus.settings.impl.DebugSettings;
import net.minecraft.client.Keyboard;
import net.minecraft.client.MinecraftClient;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
@Mixin(Keyboard.class)
public abstract class MixinKeyboard implements IMouseKeyboard {
@Shadow
@Final
private MinecraftClient client;
@Unique
private final Queue<Runnable> viaFabricPlus$pendingScreenEvents = new ConcurrentLinkedQueue<>();
@Redirect(method = {"method_22676", "method_22675"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;execute(Ljava/lang/Runnable;)V"))
private void storeEvent(MinecraftClient instance, Runnable runnable) {
if (this.client.getNetworkHandler() != null && this.client.currentScreen != null && DebugSettings.global().executeInputsInSync.isEnabled()) {
this.viaFabricPlus$pendingScreenEvents.offer(runnable);
} else {
instance.execute(runnable);
}
}
@Override
public Queue<Runnable> viaFabricPlus$getPendingScreenEvents() {
return this.viaFabricPlus$pendingScreenEvents;
}
}

View File

@ -20,34 +20,36 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.Protocol1_12To1_11_1; import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3; import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3;
import de.florianmichael.viafabricplus.ViaFabricPlus; import de.florianmichael.viafabricplus.fixes.diff.ItemRegistryDiff;
import de.florianmichael.viafabricplus.injection.access.IMouseKeyboard;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.settings.impl.DebugSettings; import de.florianmichael.viafabricplus.settings.impl.DebugSettings;
import net.minecraft.client.Keyboard;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.Mouse;
import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.render.item.HeldItemRenderer; import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.item.SwordItem; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.Queue;
@Mixin(MinecraftClient.class) @Mixin(MinecraftClient.class)
public abstract class MixinMinecraftClient { public abstract class MixinMinecraftClient {
@ -56,58 +58,85 @@ public abstract class MixinMinecraftClient {
@Nullable @Nullable
public ClientPlayerEntity player; public ClientPlayerEntity player;
@Shadow protected int attackCooldown; @Shadow
public int attackCooldown;
@Shadow @Nullable public abstract ClientPlayNetworkHandler getNetworkHandler(); @Shadow
@Final
public Mouse mouse;
@Shadow
@Final
public Keyboard keyboard;
@Unique @Redirect(method = "doItemPick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerInventory;addPickBlock(Lnet/minecraft/item/ItemStack;)V"))
private final ConcurrentLinkedDeque<Runnable> viaFabricPlus$mouseInteractions = new ConcurrentLinkedDeque<>(); private void filterItem(PlayerInventory instance, ItemStack stack) {
if (ItemRegistryDiff.keepItem(stack.getItem())) {
@Unique instance.addPickBlock(stack);
private final ConcurrentLinkedDeque<Runnable> viaFabricPlus$keyboardInteractions = new ConcurrentLinkedDeque<>();
@SuppressWarnings("ConstantConditions")
@Inject(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;",
ordinal = 4, shift = At.Shift.BEFORE))
private void injectTick(CallbackInfo ci) {
if (!DebugSettings.global().executeInputsInSync.isEnabled()) {
return;
}
while (!viaFabricPlus$mouseInteractions.isEmpty()) {
viaFabricPlus$mouseInteractions.poll().run();
}
while (!viaFabricPlus$keyboardInteractions.isEmpty()) {
viaFabricPlus$keyboardInteractions.poll().run();
} }
} }
@Inject(method = "handleInputEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;hasRidingInventory()Z")) @Redirect(method = "doItemPick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;clickCreativeStack(Lnet/minecraft/item/ItemStack;I)V"))
private void onInventoryKeyPressed(CallbackInfo ci) { private void dontSendEmptyItem(ClientPlayerInteractionManager instance, ItemStack stack, int slotId) {
if (getNetworkHandler() != null && DebugSettings.global().sendOpenInventoryPacket.isEnabled()) { if (!stack.isEmpty()) {
final UserConnection userConnection = ProtocolHack.getPlayNetworkUserConnection(); instance.clickCreativeStack(stack, slotId);
if (userConnection != null && userConnection.getProtocolInfo().getPipeline().contains(Protocol1_12To1_11_1.class)) {
final PacketWrapper clientStatus = PacketWrapper.create(ServerboundPackets1_9_3.CLIENT_STATUS, userConnection);
clientStatus.write(Type.VAR_INT, 2); // Open Inventory Achievement
try {
clientStatus.sendToServer(Protocol1_12To1_11_1.class);
} catch (Exception e) {
ViaFabricPlus.global().getLogger().error("Failed to send Open Inventory Packet", e);
}
}
} }
} }
@WrapWithCondition(method = "doItemUse", @Redirect(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/ActionResult;shouldSwingHand()Z", ordinal = 0))
slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;interactItem(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;")), private boolean disableSwing(ActionResult instance) {
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;resetEquipProgress(Lnet/minecraft/util/Hand;)V", ordinal = 0)) return instance.shouldSwingHand() && ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_15);
private boolean removeEquipProgressReset(HeldItemRenderer instance, Hand hand) {
return ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_8) || !(player.getStackInHand(hand).getItem() instanceof SwordItem);
} }
@Redirect(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/ActionResult;shouldSwingHand()Z", ordinal = 2))
private boolean disableSwing2(ActionResult instance) {
return instance.shouldSwingHand() && ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_15);
}
@Redirect(method = "handleInputEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;swingHand(Lnet/minecraft/util/Hand;)V"))
private void disableSwing(ClientPlayerEntity instance, Hand hand) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_14_4)) return;
instance.swingHand(hand);
}
@Inject(method = "tick",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", ordinal = 0, shift = At.Shift.BEFORE),
slice = @Slice(
from = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;attackCooldown:I", ordinal = 0),
to = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V")
)
)
private void processInputQueues(CallbackInfo ci) {
if (DebugSettings.global().executeInputsInSync.isEnabled()) {
Queue<Runnable> inputEvents = ((IMouseKeyboard) this.mouse).viaFabricPlus$getPendingScreenEvents();
while (!inputEvents.isEmpty()) inputEvents.poll().run();
inputEvents = ((IMouseKeyboard) this.keyboard).viaFabricPlus$getPendingScreenEvents();
while (!inputEvents.isEmpty()) inputEvents.poll().run();
}
}
@Inject(method = "handleInputEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/tutorial/TutorialManager;onInventoryOpened()V", shift = At.Shift.AFTER))
private void sendOpenInventoryPacket(CallbackInfo ci) throws Exception {
if (DebugSettings.global().sendOpenInventoryPacket.isEnabled()) {
final PacketWrapper clientStatus = PacketWrapper.create(ServerboundPackets1_9_3.CLIENT_STATUS, ProtocolHack.getPlayNetworkUserConnection());
clientStatus.write(Type.VAR_INT, 2); // Open Inventory Achievement
clientStatus.scheduleSendToServer(Protocol1_12To1_11_1.class);
}
}
@Inject(method = "doAttack", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;crosshairTarget:Lnet/minecraft/util/hit/HitResult;", shift = At.Shift.BEFORE, ordinal = 0))
private void fixSwingPacketOrder(CallbackInfoReturnable<Boolean> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
this.player.swingHand(Hand.MAIN_HAND);
}
}
@Redirect(method = "doAttack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;swingHand(Lnet/minecraft/util/Hand;)V"))
private void fixSwingPacketOrder(ClientPlayerEntity instance, Hand hand) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) return;
instance.swingHand(Hand.MAIN_HAND);
}
@Redirect(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;attackCooldown:I", ordinal = 1)) @Redirect(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;attackCooldown:I", ordinal = 1))
private int dontIncrementCooldown(MinecraftClient instance) { private int dontIncrementCooldown(MinecraftClient instance) {
@ -126,17 +155,6 @@ public abstract class MixinMinecraftClient {
} }
} }
@Redirect(method = "doItemUse",
slice = @Slice(to = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;interactEntity(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;")),
at = @At(value = "INVOKE", target = "Lnet/minecraft/util/ActionResult;isAccepted()Z", ordinal = 0))
private boolean preventGenericInteract(ActionResult instance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_7_6tor1_7_10)) {
return false;
}
return instance.isAccepted();
}
@ModifyExpressionValue(method = "handleBlockBreaking", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isUsingItem()Z")) @ModifyExpressionValue(method = "handleBlockBreaking", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isUsingItem()Z"))
private boolean allowBlockBreakAndItemUsageAtTheSameTime(boolean original) { private boolean allowBlockBreakAndItemUsageAtTheSameTime(boolean original) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_7_6tor1_7_10)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_7_6tor1_7_10)) {

View File

@ -0,0 +1,73 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.injection.access.IMouseKeyboard;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.settings.impl.DebugSettings;
import de.florianmichael.viafabricplus.util.MouseSensitivityUtil;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
import net.minecraft.client.option.SimpleOption;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
@Mixin(Mouse.class)
public abstract class MixinMouse implements IMouseKeyboard {
@Shadow
@Final
private MinecraftClient client;
@Unique
private final Queue<Runnable> viaFabricPlus$pendingScreenEvents = new ConcurrentLinkedQueue<>();
@Redirect(method = {"method_22684", "method_22685"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;execute(Ljava/lang/Runnable;)V"))
private void storeEvent(MinecraftClient instance, Runnable runnable) {
if (this.client.getNetworkHandler() != null && this.client.currentScreen != null && DebugSettings.global().executeInputsInSync.isEnabled()) {
this.viaFabricPlus$pendingScreenEvents.offer(runnable);
} else {
instance.execute(runnable);
}
}
@Redirect(method = "updateMouse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/SimpleOption;getValue()Ljava/lang/Object;", ordinal = 0))
private Object adjustMouseSensitivity1_13_2(SimpleOption<Double> instance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2)) {
return (double) MouseSensitivityUtil.get1_13SliderValue(instance.getValue().floatValue()).keyFloat();
}
return instance.getValue();
}
@Override
public Queue<Runnable> viaFabricPlus$getPendingScreenEvents() {
return this.viaFabricPlus$pendingScreenEvents;
}
}

View File

@ -0,0 +1,62 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.collection.DefaultedList;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.Slice;
import java.util.AbstractList;
@Mixin(PlayerInventory.class)
public abstract class MixinPlayerInventory {
@Redirect(method = "<init>", slice = @Slice(from = @At(value = "CONSTANT", args = "intValue=1")), at = @At(value = "INVOKE", target = "Lnet/minecraft/util/collection/DefaultedList;ofSize(ILjava/lang/Object;)Lnet/minecraft/util/collection/DefaultedList;", ordinal = 0))
private <T> DefaultedList<T> redirectOffhandInventory(int size, T def) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
//noinspection MixinInnerClass
return new DefaultedList<>(new AbstractList<T>() {
@Override
public T get(int index) {
return def;
}
@Override
public T set(int index, T element) {
return def;
}
@Override
public int size() {
return 0;
}
}, def) {
};
}
return DefaultedList.ofSize(size, def);
}
}

View File

@ -19,20 +19,25 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.settings.impl.DebugSettings; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.network.PendingUpdateManager; import net.minecraft.client.network.RedirectResolver;
import net.minecraft.client.network.ServerAddress;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PendingUpdateManager.class) import javax.naming.directory.DirContext;
public abstract class MixinPendingUpdateManager { import java.util.Optional;
@Inject(method = "incrementSequence", at = @At(value = "FIELD", target = "Lnet/minecraft/client/network/PendingUpdateManager;pendingSequence:Z", shift = At.Shift.BEFORE), cancellable = true) @Mixin(RedirectResolver.class)
private void injectIncrementSequence(CallbackInfoReturnable<PendingUpdateManager> cir) { public interface MixinRedirectResolver {
if (DebugSettings.global().disableSequencing.isEnabled()) {
cir.setReturnValue((PendingUpdateManager) (Object) this); @Inject(method = "method_36911", at = @At("HEAD"), cancellable = true)
private static void disableSrvForPre1_3(DirContext context, ServerAddress address, CallbackInfoReturnable<Optional<ServerAddress>> cir) {
if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_3_1tor1_3_2)) {
cir.setReturnValue(Optional.empty());
} }
} }

View File

@ -0,0 +1,47 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.network.AllowedAddressResolver;
import net.minecraft.client.network.ServerAddress;
import net.raphimc.vialoader.util.VersionEnum;
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.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerAddress.class)
public abstract class MixinServerAddress {
@Shadow
@Final
private static ServerAddress INVALID;
@Inject(method = "parse", at = @At("RETURN"), cancellable = true)
private static void resolveSrv(String address, CallbackInfoReturnable<ServerAddress> cir) {
if (!cir.getReturnValue().equals(INVALID) && ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_4tor1_16_5)) {
cir.setReturnValue(AllowedAddressResolver.DEFAULT.redirectResolver.lookupRedirect(cir.getReturnValue()).orElse(cir.getReturnValue()));
}
}
}

View File

@ -22,6 +22,7 @@ package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import com.google.common.hash.HashCode; import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.llamalad7.mixinextras.sugar.Local;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.GameVersion; import net.minecraft.GameVersion;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
@ -29,7 +30,6 @@ import net.minecraft.client.resource.ServerResourcePackProvider;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
@ -45,9 +45,6 @@ import java.util.Map;
@Mixin(ServerResourcePackProvider.class) @Mixin(ServerResourcePackProvider.class)
public abstract class MixinServerResourcePackProvider { public abstract class MixinServerResourcePackProvider {
@Unique
private File viaFabricPlus$trackedFile;
@Redirect(method = "getDownloadHeaders", at = @At(value = "INVOKE", target = "Lnet/minecraft/SharedConstants;getGameVersion()Lnet/minecraft/GameVersion;")) @Redirect(method = "getDownloadHeaders", at = @At(value = "INVOKE", target = "Lnet/minecraft/SharedConstants;getGameVersion()Lnet/minecraft/GameVersion;"))
private static GameVersion editHeaders() { private static GameVersion editHeaders() {
// return PackFormatsMappings.current(); // return PackFormatsMappings.current();
@ -68,23 +65,16 @@ public abstract class MixinServerResourcePackProvider {
cir.setReturnValue(modifiableMap); cir.setReturnValue(modifiableMap);
} }
@Inject(method = "verifyFile", at = @At("HEAD"))
private void keepFile(String expectedSha1, File file, CallbackInfoReturnable<Boolean> cir) {
viaFabricPlus$trackedFile = file;
}
@Redirect(method = "verifyFile", at = @At(value = "INVOKE", target = "Lcom/google/common/hash/HashCode;toString()Ljava/lang/String;", remap = false)) @Redirect(method = "verifyFile", at = @At(value = "INVOKE", target = "Lcom/google/common/hash/HashCode;toString()Ljava/lang/String;", remap = false))
private String revertHashAlgorithm(HashCode instance) { private String revertHashAlgorithm(HashCode instance, @Local File file) throws IOException {
try { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) { //noinspection deprecation
//noinspection deprecation return Hashing.sha1().hashBytes(Files.toByteArray(file)).toString();
return Hashing.sha1().hashBytes(Files.toByteArray(viaFabricPlus$trackedFile)).toString(); } else if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_18tor1_18_1)) {
} else if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_18tor1_18_1)) { return DigestUtils.sha1Hex(new FileInputStream(file));
return DigestUtils.sha1Hex(new FileInputStream(viaFabricPlus$trackedFile)); } else {
} return instance.toString();
} catch (IOException ignored) {
} }
return instance.toString();
} }
@Redirect(method = "verifyFile", at = @At(value = "INVOKE", target = "Ljava/lang/String;toLowerCase(Ljava/util/Locale;)Ljava/lang/String;")) @Redirect(method = "verifyFile", at = @At(value = "INVOKE", target = "Ljava/lang/String;toLowerCase(Ljava/util/Locale;)Ljava/lang/String;"))

View File

@ -20,7 +20,6 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.fixes.ClientsideFixes; import de.florianmichael.viafabricplus.fixes.ClientsideFixes;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.StringHelper; import net.minecraft.util.StringHelper;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant; import org.spongepowered.asm.mixin.injection.Constant;
@ -30,12 +29,8 @@ import org.spongepowered.asm.mixin.injection.ModifyConstant;
public abstract class MixinStringHelper { public abstract class MixinStringHelper {
@ModifyConstant(method = "truncateChat", constant = @Constant(intValue = 256)) @ModifyConstant(method = "truncateChat", constant = @Constant(intValue = 256))
private static int expandChatLength(int constant) { private static int modifyMaxChatLength(int constant) {
if (MinecraftClient.getInstance().isInSingleplayer()) { return ClientsideFixes.getCurrentChatLength();
return 256;
}
return ClientsideFixes.getCurrentChatLimit();
} }
} }

View File

@ -41,17 +41,24 @@ import java.util.List;
@Mixin(TextRenderer.class) @Mixin(TextRenderer.class)
public abstract class MixinTextRenderer { public abstract class MixinTextRenderer {
@Shadow public abstract List<OrderedText> wrapLines(StringVisitable text, int width); @Shadow
public abstract List<OrderedText> wrapLines(StringVisitable text, int width);
@Shadow public abstract int draw(OrderedText text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextRenderer.TextLayerType layerType, int backgroundColor, int light); @Shadow
public abstract int draw(OrderedText text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextRenderer.TextLayerType layerType, int backgroundColor, int light);
@Shadow public abstract String mirror(String text); @Shadow
public abstract String mirror(String text);
@Shadow @Final public int fontHeight; @Shadow
@Final
public int fontHeight;
@Shadow protected abstract int drawInternal(OrderedText text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextRenderer.TextLayerType layerType, int backgroundColor, int light); @Shadow
protected abstract int drawInternal(OrderedText text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextRenderer.TextLayerType layerType, int backgroundColor, int light);
@Shadow public abstract int getWidth(OrderedText text); @Shadow
public abstract int getWidth(OrderedText text);
@Inject(method = "draw(Ljava/lang/String;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/font/TextRenderer$TextLayerType;IIZ)I", at = @At("HEAD"), cancellable = true) @Inject(method = "draw(Ljava/lang/String;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/font/TextRenderer$TextLayerType;IIZ)I", at = @At("HEAD"), cancellable = true)
private void allowNewLines_String(String text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextRenderer.TextLayerType layerType, int backgroundColor, int light, boolean rightToLeft, CallbackInfoReturnable<Integer> cir) { private void allowNewLines_String(String text, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextRenderer.TextLayerType layerType, int backgroundColor, int light, boolean rightToLeft, CallbackInfoReturnable<Integer> cir) {

View File

@ -1,3 +1,22 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.entity; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.entity;
import de.florianmichael.viafabricplus.fixes.EntityHeightOffsetsPre1_20_2; import de.florianmichael.viafabricplus.fixes.EntityHeightOffsetsPre1_20_2;

View File

@ -98,12 +98,11 @@ public abstract class MixinLivingEntity extends Entity {
return instance.isLogicalSideForUpdatingMovement(); return instance.isLogicalSideForUpdatingMovement();
} }
@Redirect(method = "tickCramming", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;isClient()Z")) @Inject(method = "tickCramming", at = @At("HEAD"), cancellable = true)
private boolean revertOnlyPlayerCramming(World instance) { private void preventEntityPush(CallbackInfo ci) {
if (DebugSettings.global().alwaysTickOnlyPlayer.isEnabled()) { if (DebugSettings.global().preventEntityCramming.isEnabled()) {
return false; ci.cancel();
} }
return instance.isClient();
} }
@Redirect(method = "travel", at = @At(value = "INVOKE", target = "Ljava/lang/Math;cos(D)D", remap = false)) @Redirect(method = "travel", at = @At(value = "INVOKE", target = "Ljava/lang/Math;cos(D)D", remap = false))

View File

@ -1,3 +1,22 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.entity; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.entity;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;

View File

@ -31,7 +31,7 @@ public abstract class MixinDrawContext {
@Redirect(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getCount()I")) @Redirect(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getCount()I"))
private int handleNegativeItemCount(ItemStack instance) { private int handleNegativeItemCount(ItemStack instance) {
if (((IItemStack) (Object) instance).viaFabricPlus$has1_10ProtocolHackTag()) { if (((IItemStack) (Object) instance).viaFabricPlus$has1_10ViaFabricPlusTag()) {
return ((IItemStack) (Object) instance).viaFabricPlus$get1_10Count(); return ((IItemStack) (Object) instance).viaFabricPlus$get1_10Count();
} }
return instance.getCount(); return instance.getCount();

View File

@ -19,6 +19,7 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.item; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.item;
import de.florianmichael.viafabricplus.fixes.diff.ItemRegistryDiff;
import de.florianmichael.viafabricplus.settings.impl.GeneralSettings; import de.florianmichael.viafabricplus.settings.impl.GeneralSettings;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@ -34,7 +35,9 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(targets = "net.minecraft.item.ItemGroup$EntriesImpl") @Mixin(targets = "net.minecraft.item.ItemGroup$EntriesImpl")
public abstract class MixinItemGroup_EntriesImpl { public abstract class MixinItemGroup_EntriesImpl {
@Shadow @Final private ItemGroup group; @Shadow
@Final
private ItemGroup group;
@Redirect(method = "add", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isEnabled(Lnet/minecraft/resource/featuretoggle/FeatureSet;)Z")) @Redirect(method = "add", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isEnabled(Lnet/minecraft/resource/featuretoggle/FeatureSet;)Z"))
private boolean removeUnknownItems(Item instance, FeatureSet featureSet) { private boolean removeUnknownItems(Item instance, FeatureSet featureSet) {
@ -43,11 +46,9 @@ public abstract class MixinItemGroup_EntriesImpl {
if (index == 2 || MinecraftClient.getInstance().isInSingleplayer()) return instance.isEnabled(featureSet); if (index == 2 || MinecraftClient.getInstance().isInSingleplayer()) return instance.isEnabled(featureSet);
if (index == 1 && !Registries.ITEM_GROUP.getId(this.group).getNamespace().equals("minecraft")) return instance.isEnabled(featureSet); if (index == 1 && !Registries.ITEM_GROUP.getId(this.group).getNamespace().equals("minecraft")) return instance.isEnabled(featureSet);
// TODO | Fix if (ItemRegistryDiff.keepItem(instance)) {
return instance.isEnabled(featureSet);
// if (ItemRegistryDiffPre1_20_2.INSTANCE.getCurrentMap().contains(instance)) { }
// return instance.isEnabled(featureSet);
// }
return false; return false;
} }

View File

@ -105,7 +105,7 @@ public abstract class MixinItemStack implements IItemStack {
} }
@Override @Override
public boolean viaFabricPlus$has1_10ProtocolHackTag() { public boolean viaFabricPlus$has1_10ViaFabricPlusTag() {
return this.viaFabricPlus$has1_10ProtocolHackTag; return this.viaFabricPlus$has1_10ProtocolHackTag;
} }

View File

@ -20,22 +20,17 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import de.florianmichael.viafabricplus.fixes.ClientsideFixes; import de.florianmichael.viafabricplus.fixes.ClientsideFixes;
import net.minecraft.client.MinecraftClient;
import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(ChatMessageC2SPacket.class) @Mixin(ChatMessageC2SPacket.class)
public abstract class MixinChatMessageC2SPacket { public abstract class MixinChatMessageC2SPacket {
@ModifyArg(method = "write", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketByteBuf;writeString(Ljava/lang/String;I)Lnet/minecraft/network/PacketByteBuf;")) @ModifyConstant(method = "write", constant = @Constant(intValue = 256))
private int modifyChatLength(int maxLength) { private int modifyChatLength(int maxLength) {
if (MinecraftClient.getInstance().isInSingleplayer()) { return ClientsideFixes.getCurrentChatLength();
return 256;
}
return ClientsideFixes.getCurrentChatLimit();
} }
} }

View File

@ -19,11 +19,14 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.storage.InventoryAcknowledgements;
import de.florianmichael.viafabricplus.fixes.ClientsideFixes; import de.florianmichael.viafabricplus.fixes.ClientsideFixes;
import de.florianmichael.viafabricplus.injection.access.IClientConnection;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload; import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientCommonNetworkHandler; import net.minecraft.client.network.ClientCommonNetworkHandler;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.listener.ServerPacketListener; import net.minecraft.network.listener.ServerPacketListener;
import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.common.CommonPingS2CPacket; import net.minecraft.network.packet.s2c.common.CommonPingS2CPacket;
@ -42,14 +45,22 @@ import java.time.Duration;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
@SuppressWarnings("UnstableApiUsage") @SuppressWarnings("UnstableApiUsage")
@Mixin(value = ClientCommonNetworkHandler.class, priority = 1 /* Has to be applied before Fabric's Networking API, so it doesn't cancel our custom-payload packets */) @Mixin(value = ClientCommonNetworkHandler.class, priority = 1001 /* Has to be applied before Fabric's Networking API, so it doesn't cancel our custom-payload packets */)
public abstract class MixinClientCommonNetworkHandler { public abstract class MixinClientCommonNetworkHandler {
@Shadow @Final protected MinecraftClient client; @Shadow
@Final
protected MinecraftClient client;
@Shadow protected abstract void send(Packet<? extends ServerPacketListener> packet, BooleanSupplier sendCondition, Duration expiry); @Shadow
protected abstract void send(Packet<? extends ServerPacketListener> packet, BooleanSupplier sendCondition, Duration expiry);
@Shadow public abstract void sendPacket(Packet<?> packet); @Shadow
public abstract void sendPacket(Packet<?> packet);
@Shadow
@Final
protected ClientConnection connection;
@Redirect(method = "onKeepAlive", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientCommonNetworkHandler;send(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V")) @Redirect(method = "onKeepAlive", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientCommonNetworkHandler;send(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V"))
private void forceSendKeepAlive(ClientCommonNetworkHandler instance, Packet<? extends ServerPacketListener> packet, BooleanSupplier sendCondition, Duration expiry) { private void forceSendKeepAlive(ClientCommonNetworkHandler instance, Packet<? extends ServerPacketListener> packet, BooleanSupplier sendCondition, Duration expiry) {
@ -63,19 +74,22 @@ public abstract class MixinClientCommonNetworkHandler {
@Inject(method = "onPing", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", shift = At.Shift.AFTER), cancellable = true) @Inject(method = "onPing", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", shift = At.Shift.AFTER), cancellable = true)
private void onPing(CommonPingS2CPacket packet, CallbackInfo ci) { private void onPing(CommonPingS2CPacket packet, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_17)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_4tor1_16_5)) {
return; final InventoryAcknowledgements acks = ((IClientConnection) this.connection).viaFabricPlus$getUserConnection().get(InventoryAcknowledgements.class);
if (acks.removeId(packet.getParameter())) {
final short inventoryId = (short) ((packet.getParameter() >> 16) & 0xFF);
ScreenHandler handler = null;
if (inventoryId == 0) handler = client.player.playerScreenHandler;
else if (inventoryId == client.player.currentScreenHandler.syncId) handler = client.player.currentScreenHandler;
if (handler != null) {
acks.addId(packet.getParameter());
} else {
ci.cancel();
}
}
} }
final int inventoryId = (packet.getParameter() >> 16) & 0xFF; // Fix Via Bug from 1.16.5 (Window Confirmation -> PlayPing) Usage for MiningFast Detection
ScreenHandler handler = null;
if (client.player == null) return;
if (inventoryId == 0) handler = client.player.playerScreenHandler;
if (inventoryId == client.player.currentScreenHandler.syncId) handler = client.player.currentScreenHandler;
if (handler == null) ci.cancel();
} }
@Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true) @Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true)

View File

@ -0,0 +1,45 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.util.ChatUtil;
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
import net.minecraft.network.packet.s2c.config.FeaturesS2CPacket;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.raphimc.vialoader.util.VersionEnum;
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;
@Mixin(ClientConfigurationNetworkHandler.class)
public abstract class MixinClientConfigurationNetworkHandler {
@Inject(method = "onFeatures", at = @At(value = "HEAD"))
private void notifyAboutFeatures(FeaturesS2CPacket packet, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_20tor1_20_1) && packet.features().contains(new Identifier("update_1_20"))) {
ChatUtil.sendPrefixedMessage(Text.literal("This server has the update_1_20 features enabled. This is not fully supported and may cause issues.").formatted(Formatting.RED));
}
}
}

View File

@ -0,0 +1,38 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.network.ClientLoginNetworkHandler;
import net.minecraft.network.ClientConnection;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ClientLoginNetworkHandler.class)
public abstract class MixinClientLoginNetworkHandler {
@Redirect(method = "onCompression", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;setCompressionThreshold(IZ)V"))
private void pre1_17_1CompressionBehaviour(ClientConnection instance, int compressionThreshold, boolean rejectsBadPackets) {
instance.setCompressionThreshold(compressionThreshold, ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_17));
}
}

View File

@ -20,22 +20,21 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import com.llamalad7.mixinextras.injector.WrapWithCondition; import com.llamalad7.mixinextras.injector.WrapWithCondition;
import de.florianmichael.viafabricplus.fixes.diff.RecipesPre1_12; import de.florianmichael.viafabricplus.fixes.recipe.RecipeInfo;
import de.florianmichael.viafabricplus.fixes.recipe.Recipes1_11_2;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.settings.impl.VisualSettings; import de.florianmichael.viafabricplus.settings.impl.VisualSettings;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.DownloadingTerrainScreen; import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
import net.minecraft.client.network.ClientConnectionState; import net.minecraft.client.network.*;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.entity.Entity;
import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.s2c.play.*; import net.minecraft.network.packet.s2c.play.*;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeEntry; import net.minecraft.recipe.RecipeEntry;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.world.GameMode;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@ -49,11 +48,9 @@ import java.util.ArrayList;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings("DataFlowIssue")
@Mixin(ClientPlayNetworkHandler.class) @Mixin(ClientPlayNetworkHandler.class)
public abstract class MixinClientPlayNetworkHandler { public abstract class MixinClientPlayNetworkHandler extends ClientCommonNetworkHandler {
@Shadow @Shadow
public abstract void onEntityStatus(EntityStatusS2CPacket packet); public abstract void onEntityStatus(EntityStatusS2CPacket packet);
@ -66,23 +63,47 @@ public abstract class MixinClientPlayNetworkHandler {
@Shadow @Shadow
public abstract void onSimulationDistance(SimulationDistanceS2CPacket packet); public abstract void onSimulationDistance(SimulationDistanceS2CPacket packet);
@Shadow public abstract ClientConnection getConnection(); @Shadow
public abstract ClientConnection getConnection();
@Shadow
public abstract void onSynchronizeRecipes(SynchronizeRecipesS2CPacket packet);
protected MixinClientPlayNetworkHandler(MinecraftClient client, ClientConnection connection, ClientConnectionState connectionState) {
super(client, connection, connectionState);
}
@WrapWithCondition(method = "onChatMessage", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) @WrapWithCondition(method = "onChatMessage", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean removeError(Logger instance, String s, Object o) { private boolean removeChatPacketError(Logger instance, String s, Object o) {
return ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_20_2); return ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_20_2);
} }
@Redirect(method = "handlePlayerListAction", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;onGameModeChanged(Lnet/minecraft/world/GameMode;)V"))
private void dontResetVelocity(ClientPlayerEntity instance, GameMode gameMode) {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_20tor1_20_1)) {
instance.onGameModeChanged(gameMode);
}
}
@WrapWithCondition(method = "setPublicSession", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) @WrapWithCondition(method = "setPublicSession", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean removeInvalidSignatureWarning(Logger instance, String s, Object o) { private boolean removeInvalidSignatureWarning(Logger instance, String s, Object o) {
return ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_19_4); return ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_19_4);
} }
@WrapWithCondition(method = "onPlayerList", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) @WrapWithCondition(method = "onPlayerList", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean removeWarning(Logger instance, String s, Object o) { private boolean removeUnknownPlayerListEntryWarning(Logger instance, String s, Object o) {
return ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_19_3); return ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_19_3);
} }
@Redirect(method = {"onEntityPosition", "onEntity"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;isLogicalSideForUpdatingMovement()Z"))
private boolean allowPlayerToBeMovedByEntityPackets(Entity instance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_3) || ProtocolHack.getTargetVersion().equals(VersionEnum.bedrockLatest)) {
return instance.getControllingPassenger() instanceof PlayerEntity player ? player.isMainPlayer() : !instance.getWorld().isClient;
}
return instance.isLogicalSideForUpdatingMovement();
}
@Inject(method = "<init>", at = @At("RETURN")) @Inject(method = "<init>", at = @At("RETURN"))
private void fixPlayerListOrdering(MinecraftClient client, ClientConnection clientConnection, ClientConnectionState clientConnectionState, CallbackInfo ci) { private void fixPlayerListOrdering(MinecraftClient client, ClientConnection clientConnection, ClientConnectionState clientConnectionState, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) {
@ -90,7 +111,7 @@ public abstract class MixinClientPlayNetworkHandler {
} }
} }
@Redirect(method = "onServerMetadata", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/ServerMetadataS2CPacket;isSecureChatEnforced()Z")) @Redirect(method = "onServerMetadata", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/ServerMetadataS2CPacket;isSecureChatEnforced()Z", ordinal = 1))
private boolean removeSecureChatWarning(ServerMetadataS2CPacket instance) { private boolean removeSecureChatWarning(ServerMetadataS2CPacket instance) {
return instance.isSecureChatEnforced() || VisualSettings.global().disableSecureChatWarning.isEnabled(); return instance.isSecureChatEnforced() || VisualSettings.global().disableSecureChatWarning.isEnabled();
} }
@ -102,17 +123,18 @@ public abstract class MixinClientPlayNetworkHandler {
@Inject(method = "onPlayerPositionLook", at = @At("RETURN")) @Inject(method = "onPlayerPositionLook", at = @At("RETURN"))
private void closeDownloadingTerrain(PlayerPositionLookS2CPacket packet, CallbackInfo ci) { private void closeDownloadingTerrain(PlayerPositionLookS2CPacket packet, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_18_2) && MinecraftClient.getInstance().currentScreen instanceof DownloadingTerrainScreen) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_18tor1_18_1) && this.client.currentScreen instanceof DownloadingTerrainScreen downloadingTerrainScreen) {
MinecraftClient.getInstance().setScreen(null); downloadingTerrainScreen.setReady();
} }
} }
@SuppressWarnings({"InvalidInjectorMethodSignature"})
@ModifyConstant(method = "onEntityPassengersSet", constant = @Constant(classValue = BoatEntity.class)) @ModifyConstant(method = "onEntityPassengersSet", constant = @Constant(classValue = BoatEntity.class))
private Class<?> dontChangePlayerYaw(Object entity, Class<?> constant) { private Class<?> dontChangeYawWhenMountingBoats(Object entity, Class<?> boatClass) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_18_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_18tor1_18_1)) {
return Integer.class; return Integer.class;
} }
return constant; return boatClass;
} }
@Inject(method = "onChunkLoadDistance", at = @At("RETURN")) @Inject(method = "onChunkLoadDistance", at = @At("RETURN"))
@ -122,29 +144,27 @@ public abstract class MixinClientPlayNetworkHandler {
} }
} }
@Redirect(method = "onSynchronizeRecipes", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/SynchronizeRecipesS2CPacket;getRecipes()Ljava/util/List;")) @Redirect(method = "onEntityPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;updateTrackedPositionAndAngles(DDDFFI)V"))
private List<RecipeEntry<?>> rewriteRecipes(SynchronizeRecipesS2CPacket instance) { private void cancelSmallChanges(Entity instance, double x, double y, double z, float yaw, float pitch, int interpolationSteps) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_1) && Math.abs(instance.getX() - x) < 0.03125 && Math.abs(instance.getY() - y) < 0.015625 && Math.abs(instance.getZ() - z) < 0.03125) {
final List<Recipe<?>> recipes = instance.getRecipes().stream().map(RecipeEntry::value).collect(Collectors.toList()); instance.updateTrackedPositionAndAngles(instance.getX(), instance.getY(), instance.getZ(), yaw, pitch, ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_15_2) ? 0 : interpolationSteps);
RecipesPre1_12.editRecipes(recipes, ProtocolHack.getTargetVersion()); } else {
instance.updateTrackedPositionAndAngles(x, y, z, yaw, pitch, interpolationSteps);
final List<RecipeEntry<?>> entries = new ArrayList<>();
int recipeId = 0;
for (final Recipe<?> recipe : recipes) {
entries.add(new RecipeEntry<>(new Identifier(String.valueOf(recipeId++)), recipe));
}
return entries;
} }
return instance.getRecipes();
} }
@Inject(method = {"onGameJoin", "onPlayerRespawn"}, at = @At("TAIL")) @Inject(method = "onGameJoin", at = @At("RETURN"))
private void injectOnOnGameJoinOrRespawn(CallbackInfo ci) { private void sendAdditionalData(CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
ClientPlayerEntity player = MinecraftClient.getInstance().player; this.onEntityStatus(new EntityStatusS2CPacket(this.client.player, (byte) 28)); // Op-level 4
assert player != null; }
onEntityStatus(new EntityStatusS2CPacket(player, (byte) 28)); if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_12)) {
final List<RecipeEntry<?>> recipes = new ArrayList<>();
final List<RecipeInfo<?>> recipeInfos = Recipes1_11_2.getRecipes();
for (int i = 0; i < recipeInfos.size(); i++) {
recipes.add(recipeInfos.get(i).create(new Identifier("viafabricplus", "recipe/" + i)));
}
this.onSynchronizeRecipes(new SynchronizeRecipesS2CPacket(recipes));
} }
} }

View File

@ -0,0 +1,324 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ServerboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.Protocol1_17To1_16_4;
import de.florianmichael.viafabricplus.fixes.ActionResultException;
import de.florianmichael.viafabricplus.fixes.ClientPlayerInteractionManager1_18_2;
import de.florianmichael.viafabricplus.injection.access.IClientConnection;
import de.florianmichael.viafabricplus.injection.access.IScreenHandler;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.protocolhack.provider.viaversion.ViaFabricPlusHandItemProvider;
import de.florianmichael.viafabricplus.protocolhack.translator.ItemTranslator;
import de.florianmichael.viafabricplus.settings.impl.VisualSettings;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.SnowBlock;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.client.network.SequencedPacketCreator;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.GameMode;
import net.raphimc.vialoader.util.VersionEnum;
import org.apache.commons.lang3.mutable.MutableObject;
import org.spongepowered.asm.mixin.*;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@SuppressWarnings("DataFlowIssue")
@Mixin(ClientPlayerInteractionManager.class)
public abstract class MixinClientPlayerInteractionManager {
@Shadow
@Final
private MinecraftClient client;
@Shadow
protected abstract ActionResult interactBlockInternal(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult);
@Shadow
@Final
private ClientPlayNetworkHandler networkHandler;
@Shadow
private BlockPos currentBreakingPos;
@Shadow
private float currentBreakingProgress;
@Shadow
protected abstract void sendSequencedPacket(ClientWorld world, SequencedPacketCreator packetCreator);
@Shadow
private GameMode gameMode;
@Unique
private ItemStack viaFabricPlus$oldCursorStack;
@Unique
private List<ItemStack> viaFabricPlus$oldItems;
@Inject(method = "getBlockBreakingProgress", at = @At("HEAD"), cancellable = true)
private void changeCalculation(CallbackInfoReturnable<Integer> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_4)) {
cir.setReturnValue((int) (this.currentBreakingProgress * 10.0F) - 1);
}
}
@Inject(method = "sendSequencedPacket", at = @At("HEAD"))
private void trackPlayerAction(ClientWorld world, SequencedPacketCreator packetCreator, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isBetweenInclusive(VersionEnum.r1_14_4, VersionEnum.r1_18_2) && packetCreator instanceof PlayerActionC2SPacket playerActionC2SPacket) {
ClientPlayerInteractionManager1_18_2.trackPlayerAction(playerActionC2SPacket.getAction(), playerActionC2SPacket.getPos());
}
}
@Redirect(method = {"attackBlock", "cancelBlockBreaking"}, at = @At(value = "NEW", target = "(Lnet/minecraft/network/packet/c2s/play/PlayerActionC2SPacket$Action;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)Lnet/minecraft/network/packet/c2s/play/PlayerActionC2SPacket;"))
private PlayerActionC2SPacket trackPlayerAction(PlayerActionC2SPacket.Action action, BlockPos pos, Direction direction) {
if (ProtocolHack.getTargetVersion().isBetweenInclusive(VersionEnum.r1_14_4, VersionEnum.r1_18_2)) {
ClientPlayerInteractionManager1_18_2.trackPlayerAction(action, pos);
}
return new PlayerActionC2SPacket(action, pos, direction);
}
@Redirect(method = "interactItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V", ordinal = 0))
private void redirectPlayerPosPacket(ClientPlayNetworkHandler instance, Packet<?> packet) {
if (ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_16_4tor1_16_5)) {
instance.sendPacket(packet);
}
}
@ModifyVariable(method = "clickSlot", at = @At(value = "STORE"), ordinal = 0)
private List<ItemStack> captureOldItems(List<ItemStack> oldItems) {
viaFabricPlus$oldCursorStack = client.player.currentScreenHandler.getCursorStack().copy();
return this.viaFabricPlus$oldItems = oldItems;
}
@WrapWithCondition(method = "clickSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V"))
private boolean handleWindowClick1_16_5(ClientPlayNetworkHandler instance, Packet<?> packet) throws Exception {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_16_4tor1_16_5) && packet instanceof ClickSlotC2SPacket clickSlot) {
ItemStack slotItemBeforeModification;
if (this.viaFabricPlus$shouldBeEmpty(clickSlot.getActionType(), clickSlot.getSlot()))
slotItemBeforeModification = ItemStack.EMPTY;
else if (clickSlot.getSlot() < 0 || clickSlot.getSlot() >= viaFabricPlus$oldItems.size())
slotItemBeforeModification = viaFabricPlus$oldCursorStack;
else
slotItemBeforeModification = viaFabricPlus$oldItems.get(clickSlot.getSlot());
final var clickWindowPacket = PacketWrapper.create(ServerboundPackets1_16_2.CLICK_WINDOW, ((IClientConnection) networkHandler.getConnection()).viaFabricPlus$getUserConnection());
clickWindowPacket.write(Type.UNSIGNED_BYTE, (short) clickSlot.getSyncId());
clickWindowPacket.write(Type.SHORT, (short) clickSlot.getSlot());
clickWindowPacket.write(Type.BYTE, (byte) clickSlot.getButton());
clickWindowPacket.write(Type.SHORT, ((IScreenHandler) client.player.currentScreenHandler).viaFabricPlus$incrementAndGetActionId());
clickWindowPacket.write(Type.VAR_INT, clickSlot.getActionType().ordinal());
clickWindowPacket.write(Type.ITEM1_13_2, ItemTranslator.mcToVia(slotItemBeforeModification, VersionEnum.r1_16_4tor1_16_5));
clickWindowPacket.scheduleSendToServer(Protocol1_17To1_16_4.class);
viaFabricPlus$oldCursorStack = null;
viaFabricPlus$oldItems = null;
return false;
}
return true;
}
@Redirect(method = {"method_41936", "method_41935"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;breakBlock(Lnet/minecraft/util/math/BlockPos;)Z"))
private boolean checkFireBlock(ClientPlayerInteractionManager instance, BlockPos pos, @Local Direction direction) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_15_2)) {
if (!this.extinguishFire(pos, direction)) {
return instance.breakBlock(pos);
} else {
return false;
}
}
return instance.breakBlock(pos);
}
@Inject(method = "breakBlock", at = @At("TAIL"))
private void resetBlockBreaking(BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_14_3)) {
this.currentBreakingPos = new BlockPos(this.currentBreakingPos.getX(), -1, this.currentBreakingPos.getZ());
}
}
@Inject(method = "interactBlockInternal", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isEmpty()Z", ordinal = 2, shift = At.Shift.BEFORE))
private void interactBlock1_12_2(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable<ActionResult> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) {
final ItemStack itemStack = player.getStackInHand(hand);
BlockHitResult checkHitResult = hitResult;
if (itemStack.getItem() instanceof BlockItem) {
final BlockState clickedBlock = this.client.world.getBlockState(hitResult.getBlockPos());
if (clickedBlock.getBlock().equals(Blocks.SNOW)) {
if (clickedBlock.get(SnowBlock.LAYERS) == 1) {
checkHitResult = hitResult.withSide(Direction.UP);
}
}
final ItemUsageContext itemUsageContext = new ItemUsageContext(player, hand, checkHitResult);
final ItemPlacementContext itemPlacementContext = new ItemPlacementContext(itemUsageContext);
if (!itemPlacementContext.canPlace() || ((BlockItem) itemPlacementContext.getStack().getItem()).getPlacementState(itemPlacementContext) == null) {
throw new ActionResultException(ActionResult.PASS);
}
}
this.networkHandler.sendPacket(new PlayerInteractBlockC2SPacket(hand, hitResult, 0));
if (itemStack.isEmpty()) {
throw new ActionResultException(ActionResult.PASS);
}
final ItemUsageContext itemUsageContext = new ItemUsageContext(player, hand, checkHitResult);
ActionResult actionResult;
if (this.gameMode.isCreative()) {
final int count = itemStack.getCount();
actionResult = itemStack.useOnBlock(itemUsageContext);
itemStack.setCount(count);
} else {
actionResult = itemStack.useOnBlock(itemUsageContext);
}
if (!actionResult.isAccepted()) {
actionResult = ActionResult.PASS; // In <= 1.12.2 FAIL is the same as PASS
}
throw new ActionResultException(actionResult);
}
}
@Inject(method = "method_41929", at = @At("HEAD"))
private void trackLastUsedItem(Hand hand, PlayerEntity playerEntity, MutableObject<ActionResult> mutableObject, int sequence, CallbackInfoReturnable<Packet<?>> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
ViaFabricPlusHandItemProvider.lastUsedItem = playerEntity.getStackInHand(hand).copy();
}
}
@Inject(method = "interactItem", at = @At("HEAD"), cancellable = true)
private void cancelOffHandItemInteract(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8) && !Hand.MAIN_HAND.equals(hand)) cir.setReturnValue(ActionResult.PASS);
}
@Inject(method = "interactBlock", at = @At("HEAD"), cancellable = true)
private void cancelOffHandBlockPlace(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable<ActionResult> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8) && !Hand.MAIN_HAND.equals(hand)) cir.setReturnValue(ActionResult.PASS);
}
/**
* @author RK_01
* @reason Block place fix
*/
@Overwrite
private Packet<?> method_41933(MutableObject<ActionResult> mutableObject, ClientPlayerEntity clientPlayerEntity, Hand hand, BlockHitResult blockHitResult, int sequence) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
ViaFabricPlusHandItemProvider.lastUsedItem = clientPlayerEntity.getStackInHand(hand).copy();
}
try {
mutableObject.setValue(this.interactBlockInternal(clientPlayerEntity, hand, blockHitResult));
return new PlayerInteractBlockC2SPacket(hand, blockHitResult, sequence);
} catch (ActionResultException e) {
mutableObject.setValue(e.getActionResult());
throw e;
}
}
@Redirect(method = "interactBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;sendSequencedPacket(Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/client/network/SequencedPacketCreator;)V"))
private void catchPacketCancelException(ClientPlayerInteractionManager instance, ClientWorld world, SequencedPacketCreator packetCreator) {
try {
this.sendSequencedPacket(world, packetCreator);
} catch (ActionResultException ignored) {
}
}
@Inject(method = "clickSlot", at = @At("HEAD"), cancellable = true)
private void removeClickActions(int syncId, int slotId, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.b1_5tob1_5_2) && !actionType.equals(SlotActionType.PICKUP)) {
ci.cancel();
} else if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_4_6tor1_4_7) && !actionType.equals(SlotActionType.PICKUP) && !actionType.equals(SlotActionType.QUICK_MOVE) && !actionType.equals(SlotActionType.SWAP) && !actionType.equals(SlotActionType.CLONE)) {
ci.cancel();
}
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8) && actionType == SlotActionType.SWAP && button == 40) { // Pressing 'F' in inventory
ci.cancel();
}
}
@Inject(method = "hasExperienceBar", at = @At("HEAD"), cancellable = true)
private void removeExperienceBar(CallbackInfoReturnable<Boolean> cir) {
if (VisualSettings.global().removeNewerHudElements.isEnabled()) {
cir.setReturnValue(false);
}
}
@Inject(method = "getReachDistance", at = @At("RETURN"), cancellable = true)
private void modifyReachDistance(CallbackInfoReturnable<Float> cir) {
if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_0_0tor1_0_1) && !this.gameMode.isCreative()) {
cir.setReturnValue(4F);
}
}
@Unique
private boolean extinguishFire(BlockPos blockPos, final Direction direction) {
blockPos = blockPos.offset(direction);
if (this.client.world.getBlockState(blockPos).getBlock() == Blocks.FIRE) {
this.client.world.syncWorldEvent(this.client.player, 1009, blockPos, 0);
this.client.world.removeBlock(blockPos, false);
return true;
}
return false;
}
@Unique
private boolean viaFabricPlus$shouldBeEmpty(final SlotActionType type, final int slot) {
// quick craft always uses empty stack for verification
if (type == SlotActionType.QUICK_CRAFT) return true;
// Special case: throw always uses empty stack for verification
if (type == SlotActionType.THROW) return true;
// quick move always uses empty stack for verification since 1.12
if (type == SlotActionType.QUICK_MOVE && ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_11_1to1_11_2)) return true;
// pickup with slot -999 (outside window) to throw items always uses empty stack for verification
return type == SlotActionType.PICKUP && slot == -999;
}
}

View File

@ -0,0 +1,71 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import com.google.common.collect.ImmutableMap;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.packet.BrandCustomPayload;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
import net.minecraft.network.packet.s2c.custom.DebugGameTestAddMarkerCustomPayload;
import net.minecraft.network.packet.s2c.custom.DebugGameTestClearCustomPayload;
import net.minecraft.util.Identifier;
import net.raphimc.vialoader.util.VersionEnum;
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;
import java.util.Map;
@Mixin(CustomPayloadS2CPacket.class)
public abstract class MixinCustomPayloadS2CPacket {
@Unique
private static final Map<Identifier, VersionEnum> PAYLOAD_DIFF = ImmutableMap.<Identifier, VersionEnum>builder()
.put(BrandCustomPayload.ID, VersionEnum.c0_0_15a_1)
.put(DebugGameTestAddMarkerCustomPayload.ID, VersionEnum.r1_14)
.put(DebugGameTestClearCustomPayload.ID, VersionEnum.r1_14)
.build();
@Redirect(method = "readPayload", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", remap = false))
private static Object filterAllowedCustomPayloads(Map<?, ?> instance, Object identifier) {
if (instance.containsKey(identifier)) {
if (!PAYLOAD_DIFF.containsKey(identifier) || ProtocolHack.getTargetVersion().isOlderThan(PAYLOAD_DIFF.get(identifier))) {
return null;
}
final PacketByteBuf.PacketReader<? extends CustomPayload> reader = (PacketByteBuf.PacketReader<? extends CustomPayload>) instance.get(identifier);
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_20tor1_20_1)) {
return (PacketByteBuf.PacketReader<? extends CustomPayload>) packetByteBuf -> {
final CustomPayload result = reader.apply(packetByteBuf);
packetByteBuf.skipBytes(packetByteBuf.readableBytes());
return result;
};
} else {
return reader;
}
}
return null;
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import net.minecraft.client.network.MultiplayerServerListPinger;
import net.minecraft.client.network.ServerAddress;
import net.minecraft.client.network.ServerInfo;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import java.net.InetSocketAddress;
@Mixin(MultiplayerServerListPinger.class)
public abstract class MixinMultiplayerServerListPinger {
/**
* @author RK_01
* @reason Remove legacy ping which didn't even work
*/
@Overwrite
public void ping(InetSocketAddress socketAddress, ServerAddress address, ServerInfo serverInfo) {
}
}

View File

@ -19,24 +19,43 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import net.raphimc.vialoader.util.VersionEnum; import de.florianmichael.viafabricplus.injection.access.IItemStack;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text; import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; 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.CallbackInfoReturnable;
@Mixin(value = PacketByteBuf.class) @Mixin(value = PacketByteBuf.class)
public abstract class MixinPacketByteBuf { public abstract class MixinPacketByteBuf {
@Inject(method = "readText", at = @At(value = "INVOKE", target = "Lio/netty/handler/codec/DecoderException;<init>(Ljava/lang/String;)V", shift = At.Shift.BEFORE, remap = false), cancellable = true) @Redirect(method = "readItemStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;setNbt(Lnet/minecraft/nbt/NbtCompound;)V"))
private void injectReadText(CallbackInfoReturnable<Text> cir) { private void removeViaFabricPlusTag(ItemStack instance, NbtCompound tag) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_18tor1_18_1)) { if (tag != null && tag.contains("1_10_ViaFabricPlus_ItemCount", NbtElement.BYTE_TYPE) && ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_10)) {
cir.setReturnValue(null); final IItemStack mixinItemStack = ((IItemStack) (Object) instance);
mixinItemStack.viaFabricPlus$set1_10Count(tag.getByte("1_10_ViaFabricPlus_ItemCount"));
tag.remove("1_10_ViaFabricPlus_ItemCount");
if (tag.isEmpty()) tag = null;
} }
instance.setNbt(tag);
}
@Redirect(method = "writeItemStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getNbt()Lnet/minecraft/nbt/NbtCompound;"))
private NbtCompound addViaFabricPlusTag(ItemStack instance) {
NbtCompound tag = instance.getNbt();
final IItemStack mixinItemStack = ((IItemStack) (Object) instance);
if (mixinItemStack.viaFabricPlus$has1_10ViaFabricPlusTag()) {
if (tag == null) tag = new NbtCompound();
tag.putByte("1_10_ViaFabricPlus_ItemCount", (byte) mixinItemStack.viaFabricPlus$get1_10Count());
}
return tag;
} }
} }

View File

@ -19,27 +19,35 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network;
import net.raphimc.vialoader.util.VersionEnum;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerAbilities; import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.packet.c2s.play.UpdatePlayerAbilitiesC2SPacket; import net.minecraft.network.packet.c2s.play.UpdatePlayerAbilitiesC2SPacket;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(UpdatePlayerAbilitiesC2SPacket.class) @Mixin(UpdatePlayerAbilitiesC2SPacket.class)
public abstract class MixinUpdatePlayerAbilitiesC2SPacket { public abstract class MixinUpdatePlayerAbilitiesC2SPacket {
@Unique
private PlayerAbilities viaFabricPlus$abilities;
@Inject(method = "<init>(Lnet/minecraft/entity/player/PlayerAbilities;)V", at = @At("RETURN"))
private void capturePlayerAbilities(PlayerAbilities abilities, CallbackInfo ci) {
this.viaFabricPlus$abilities = abilities;
}
@Redirect(method = "write", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketByteBuf;writeByte(I)Lnet/minecraft/network/PacketByteBuf;")) @Redirect(method = "write", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketByteBuf;writeByte(I)Lnet/minecraft/network/PacketByteBuf;"))
private PacketByteBuf implementFlags(PacketByteBuf instance, int value) { private PacketByteBuf implementFlags(PacketByteBuf instance, int value) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_15_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_15_2)) {
final PlayerAbilities playerAbilities = MinecraftClient.getInstance().player.getAbilities(); if (viaFabricPlus$abilities.invulnerable) value |= 1;
if (viaFabricPlus$abilities.allowFlying) value |= 4;
if (playerAbilities.invulnerable) value |= 1; if (viaFabricPlus$abilities.creativeMode) value |= 8;
if (playerAbilities.allowFlying) value |= 4;
if (playerAbilities.creativeMode) value |= 8;
} }
return instance.writeByte(value); return instance.writeByte(value);

View File

@ -0,0 +1,40 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.gui.screen.ChatInputSuggestor;
import net.minecraft.client.gui.screen.ingame.AbstractCommandBlockScreen;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(AbstractCommandBlockScreen.class)
public abstract class MixinAbstractCommandBlockScreen {
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ChatInputSuggestor;refresh()V"))
private void cancelAutoComplete(ChatInputSuggestor instance) {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_13)) {
instance.refresh();
}
}
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.gui.screen.ingame.BookEditScreen;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(BookEditScreen.class)
public abstract class MixinBookEditScreen {
@ModifyConstant(method = "method_27596", constant = @Constant(intValue = 1024))
private int modifyPageLength(int oldVal) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2)) {
return 256;
} else {
return oldVal;
}
}
@ModifyConstant(method = "appendNewPage", constant = @Constant(intValue = 100))
private int modifyPageCount(int oldVal) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2)) {
return 50;
} else {
return oldVal;
}
}
}

View File

@ -19,15 +19,18 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen;
import de.florianmichael.viafabricplus.settings.impl.VisualSettings;
import de.florianmichael.viafabricplus.fixes.ClientsideFixes; import de.florianmichael.viafabricplus.fixes.ClientsideFixes;
import net.minecraft.client.MinecraftClient; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.settings.impl.VisualSettings;
import net.minecraft.client.gui.hud.ChatHud; import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.MessageIndicator; import net.minecraft.client.gui.hud.MessageIndicator;
import net.minecraft.client.gui.screen.ChatInputSuggestor;
import net.minecraft.client.gui.screen.ChatScreen; import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.gui.widget.TextFieldWidget;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
@ -36,13 +39,18 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ChatScreen.class) @Mixin(ChatScreen.class)
public abstract class MixinChatScreen { public abstract class MixinChatScreen {
@Shadow protected TextFieldWidget chatField; @Shadow
protected TextFieldWidget chatField;
@Shadow
private String originalChatText;
@Shadow
ChatInputSuggestor chatInputSuggestor;
@Inject(method = "init", at = @At("RETURN")) @Inject(method = "init", at = @At("RETURN"))
private void changeChatLength(CallbackInfo ci) { private void changeChatLength(CallbackInfo ci) {
if (!MinecraftClient.getInstance().isInSingleplayer()) { this.chatField.setMaxLength(ClientsideFixes.getCurrentChatLength());
this.chatField.setMaxLength(ClientsideFixes.getCurrentChatLimit());
}
} }
@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/ChatHud;getIndicatorAt(DD)Lnet/minecraft/client/gui/hud/MessageIndicator;")) @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/ChatHud;getIndicatorAt(DD)Lnet/minecraft/client/gui/hud/MessageIndicator;"))
@ -54,4 +62,37 @@ public abstract class MixinChatScreen {
return instance.getIndicatorAt(mouseX, mouseY); return instance.getIndicatorAt(mouseX, mouseY);
} }
@Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/TextFieldWidget;setText(Ljava/lang/String;)V"))
private void moveSetTextDown(TextFieldWidget instance, String text) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) return;
instance.setText(text);
}
@Inject(method = "init", at = @At("RETURN"))
private void moveSetTextDown(CallbackInfo ci) {
if (!ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) return;
this.chatField.setText(this.originalChatText);
this.chatInputSuggestor.refresh();
}
@Redirect(method = "onChatFieldUpdate", at = @At(value = "INVOKE", target = "Ljava/lang/String;equals(Ljava/lang/Object;)Z"))
private boolean fixCommandKey(String instance, Object other) {
if (!this.cancelTabComplete()) return instance.equals(other);
return instance.isEmpty();
}
@Redirect(method = "onChatFieldUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ChatInputSuggestor;refresh()V"))
private void disableAutoTabComplete(ChatInputSuggestor instance) {
if (this.cancelTabComplete()) return;
instance.refresh();
}
@Unique
private boolean cancelTabComplete() {
return ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2) && this.chatField.getText().startsWith("/");
}
} }

View File

@ -37,6 +37,7 @@ public abstract class MixinCommandBlockScreen {
@Shadow @Shadow
private CyclingButtonWidget<Boolean> conditionalModeButton; private CyclingButtonWidget<Boolean> conditionalModeButton;
@Shadow @Shadow
private CyclingButtonWidget<Boolean> redstoneTriggerButton; private CyclingButtonWidget<Boolean> redstoneTriggerButton;

View File

@ -19,6 +19,7 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen;
import com.llamalad7.mixinextras.sugar.Local;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ProfileKey; import com.viaversion.viaversion.api.minecraft.ProfileKey;
import com.viaversion.viaversion.api.minecraft.signature.storage.ChatSession1_19_0; import com.viaversion.viaversion.api.minecraft.signature.storage.ChatSession1_19_0;
@ -27,20 +28,12 @@ import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.injection.access.IClientConnection; import de.florianmichael.viafabricplus.injection.access.IClientConnection;
import de.florianmichael.viafabricplus.injection.access.ILegacyKeySignatureStorage; import de.florianmichael.viafabricplus.injection.access.ILegacyKeySignatureStorage;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.protocolhack.provider.vialegacy.ViaFabricPlusClassicMPPassProvider;
import de.florianmichael.viafabricplus.settings.impl.AuthenticationSettings;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ConnectScreen;
import net.minecraft.client.network.ServerAddress; import net.minecraft.client.network.ServerAddress;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import net.minecraft.network.encryption.PlayerPublicKey; import net.minecraft.network.encryption.PlayerPublicKey;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.login.LoginHelloC2SPacket;
import net.raphimc.minecraftauth.MinecraftAuth;
import net.raphimc.minecraftauth.util.MicrosoftConstants;
import net.raphimc.viabedrock.protocol.storage.AuthChainData; import net.raphimc.viabedrock.protocol.storage.AuthChainData;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.apache.http.impl.client.CloseableHttpClient;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -59,72 +52,43 @@ public abstract class MixinConnectScreen_1 {
@Shadow @Shadow
ServerAddress field_33737; ServerAddress field_33737;
@Final @Redirect(method = "run", at = @At(value = "INVOKE", target = "Ljava/net/InetSocketAddress;getHostName()Ljava/lang/String;", remap = false))
@Shadow private String getRealAddress(InetSocketAddress instance) {
ConnectScreen field_2416; if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_17)) {
@Redirect(method = "run", at = @At(value = "INVOKE", target = "Ljava/net/InetSocketAddress;getHostName()Ljava/lang/String;", ordinal = 0))
private String replaceAddress(InetSocketAddress instance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_17) || ProtocolHack.getTargetVersion() == VersionEnum.bedrockLatest) {
return field_33737.getAddress(); return field_33737.getAddress();
} }
return instance.getHostName(); return instance.getHostName();
} }
@Redirect(method = "run", at = @At(value = "INVOKE", target = "Ljava/net/InetSocketAddress;getPort()I")) @Redirect(method = "run", at = @At(value = "INVOKE", target = "Ljava/net/InetSocketAddress;getPort()I", remap = false))
private int replacePort(InetSocketAddress instance) { private int getRealPort(InetSocketAddress instance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_17) || ProtocolHack.getTargetVersion() == VersionEnum.bedrockLatest) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_17)) {
return field_33737.getPort(); return field_33737.getPort();
} }
return instance.getPort(); return instance.getPort();
} }
@Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;send(Lnet/minecraft/network/packet/Packet;)V", shift = At.Shift.BEFORE)) @Inject(method = "run", at = @At(value = "INVOKE", target = "Lio/netty/channel/ChannelFuture;syncUninterruptibly()Lio/netty/channel/ChannelFuture;", shift = At.Shift.AFTER))
private void setupConnectionSessions(CallbackInfo ci) { private void setupConnectionSessions(CallbackInfo ci, @Local ClientConnection clientConnection) {
final ClientConnection connection = field_2416.connection; final UserConnection userConnection = ((IClientConnection) clientConnection).viaFabricPlus$getUserConnection();
if (connection == null || connection.channel == null) return;
final UserConnection userConnection = ((IClientConnection) connection).viaFabricPlus$getUserConnection();
if (userConnection == null) return; if (userConnection == null) return;
final VersionEnum targetVersion = VersionEnum.fromUserConnection(userConnection); final VersionEnum targetVersion = VersionEnum.fromUserConnection(userConnection);
if (targetVersion == VersionEnum.bedrockLatest) { if (targetVersion.isBetweenInclusive(VersionEnum.r1_19, VersionEnum.r1_19_1tor1_19_2)) {
var bedrockSession = ViaFabricPlus.global().getSaveManager().getAccountsSave().getBedrockAccount(); final var keyPair = MinecraftClient.getInstance().getProfileKeys().fetchKeyPair().join().orElse(null);
if (bedrockSession == null) return; if (keyPair != null) {
final PlayerPublicKey.PublicKeyData publicKeyData = keyPair.publicKey().data();
try (final CloseableHttpClient httpClient = MicrosoftConstants.createHttpClient()) {
bedrockSession = MinecraftAuth.BEDROCK_DEVICE_CODE_LOGIN.refresh(httpClient, bedrockSession);
} catch (Exception e) {
ViaFabricPlus.global().getLogger().error("Failed to refresh Bedrock chain data. Please re-login to Bedrock!", e);
return;
}
final var deviceId = bedrockSession.getMcChain().getXblXsts().getInitialXblSession().getXblDeviceToken().getId();
final var playFabId = bedrockSession.getPlayFabToken().getPlayFabId();
final var mcChain = bedrockSession.getMcChain();
userConnection.put(new AuthChainData(mcChain.getMojangJwt(), mcChain.getIdentityJwt(), mcChain.getPublicKey(), mcChain.getPrivateKey(), deviceId, playFabId));
return;
}
if (targetVersion.isOlderThan(VersionEnum.r1_19)) {
return; // This disables the chat session emulation for all versions <= 1.18.2
}
if (targetVersion.isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) {
final var profile = MinecraftClient.getInstance().getProfileKeys().fetchKeyPair().join().orElse(null);
if (profile != null) {
final PlayerPublicKey.PublicKeyData publicKeyData = profile.publicKey().data();
final UUID playerUuid = MinecraftClient.getInstance().getSession().getUuidOrNull(); final UUID playerUuid = MinecraftClient.getInstance().getSession().getUuidOrNull();
userConnection.put(new ChatSession1_19_1(playerUuid, profile.privateKey(), new ProfileKey(publicKeyData.expiresAt().toEpochMilli(), publicKeyData.key().getEncoded(), publicKeyData.keySignature()))); userConnection.put(new ChatSession1_19_1(playerUuid, keyPair.privateKey(), new ProfileKey(publicKeyData.expiresAt().toEpochMilli(), publicKeyData.key().getEncoded(), publicKeyData.keySignature())));
if (targetVersion == VersionEnum.r1_19) { if (targetVersion == VersionEnum.r1_19) {
final var legacyKey = ((ILegacyKeySignatureStorage) (Object) publicKeyData).viafabricplus$getLegacyPublicKeySignature(); final var legacyKey = ((ILegacyKeySignatureStorage) (Object) publicKeyData).viafabricplus$getLegacyPublicKeySignature();
if (legacyKey != null) { if (legacyKey != null) {
userConnection.put(new ChatSession1_19_0(playerUuid, profile.privateKey(), new ProfileKey(publicKeyData.expiresAt().toEpochMilli(), publicKeyData.key().getEncoded(), legacyKey))); userConnection.put(new ChatSession1_19_0(playerUuid, keyPair.privateKey(), new ProfileKey(publicKeyData.expiresAt().toEpochMilli(), publicKeyData.key().getEncoded(), legacyKey)));
} else { } else {
ViaFabricPlus.global().getLogger().error("Failed to fetch legacy key, can't setup ChatSession"); ViaFabricPlus.global().getLogger().error("Failed to fetch legacy key, can't setup ChatSession");
} }
@ -132,6 +96,15 @@ public abstract class MixinConnectScreen_1 {
} else { } else {
ViaFabricPlus.global().getLogger().error("Failed to fetch keyPair, can't setup ChatSession"); ViaFabricPlus.global().getLogger().error("Failed to fetch keyPair, can't setup ChatSession");
} }
} else if (targetVersion == VersionEnum.bedrockLatest) {
var bedrockSession = ViaFabricPlus.global().getSaveManager().getAccountsSave().refreshAndGetBedrockAccount();
if (bedrockSession != null) {
final var deviceId = bedrockSession.getMcChain().getXblXsts().getInitialXblSession().getXblDeviceToken().getId();
final var playFabId = bedrockSession.getPlayFabToken().getPlayFabId();
final var mcChain = bedrockSession.getMcChain();
userConnection.put(new AuthChainData(mcChain.getMojangJwt(), mcChain.getIdentityJwt(), mcChain.getPublicKey(), mcChain.getPrivateKey(), deviceId, playFabId));
}
} }
} }

View File

@ -34,8 +34,6 @@ public abstract class MixinCreativeInventoryScreen {
@Inject(method = "init", at = @At("RETURN")) @Inject(method = "init", at = @At("RETURN"))
private void replaceCreativeMenu(CallbackInfo ci) { private void replaceCreativeMenu(CallbackInfo ci) {
if (VisualSettings.global().replaceCreativeInventory.isEnabled()) { if (VisualSettings.global().replaceCreativeInventory.isEnabled()) {
if (ClassicItemSelectionScreen.INSTANCE == null) return;
MinecraftClient.getInstance().setScreen(ClassicItemSelectionScreen.INSTANCE); MinecraftClient.getInstance().setScreen(ClassicItemSelectionScreen.INSTANCE);
} }
} }

View File

@ -25,7 +25,6 @@ import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.network.packet.c2s.common.KeepAliveC2SPacket; import net.minecraft.network.packet.c2s.common.KeepAliveC2SPacket;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -33,14 +32,19 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; 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.CallbackInfo;
@Mixin(DownloadingTerrainScreen.class) @Mixin(DownloadingTerrainScreen.class)
public abstract class MixinDownloadingTerrainScreen extends Screen { public abstract class MixinDownloadingTerrainScreen extends Screen {
@Shadow @Final private long loadStartTime; @Shadow
@Shadow private boolean closeOnNextTick; @Final
@Shadow private boolean ready; private long loadStartTime;
@Shadow
private boolean ready;
@Unique @Unique
private int viaFabricPlus$tickCounter; private int viaFabricPlus$tickCounter;
@ -49,32 +53,30 @@ public abstract class MixinDownloadingTerrainScreen extends Screen {
} }
@Inject(method = "tick", at = @At("HEAD"), cancellable = true) @Inject(method = "tick", at = @At("HEAD"), cancellable = true)
private void injectTick(CallbackInfo ci) { private void modifyCloseCondition(CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_1)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_18tor1_18_1)) {
viaFabricPlus$tickCounter++;
if (viaFabricPlus$tickCounter % 20 == 0) {
MinecraftClient.getInstance().getNetworkHandler().sendPacket(new KeepAliveC2SPacket(0));
}
}
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) {
final boolean isTimeOver = this.closeOnNextTick || System.currentTimeMillis() > this.loadStartTime + 2000L;
if (isTimeOver && this.client != null && this.client.player != null) {
final BlockPos blockPos = this.client.player.getBlockPos();
final boolean isWorldLoaded = this.client.world != null && this.client.world.isOutOfHeightLimit(blockPos.getY());
if (isWorldLoaded || this.client.worldRenderer.isRenderingReady(blockPos)) {
this.close();
}
if (this.ready) {
this.closeOnNextTick = true;
}
}
ci.cancel(); ci.cancel();
if (this.ready) {
this.close();
}
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_1)) {
this.viaFabricPlus$tickCounter++;
if (this.viaFabricPlus$tickCounter % 20 == 0) {
MinecraftClient.getInstance().getNetworkHandler().sendPacket(new KeepAliveC2SPacket(0));
}
}
} }
} }
@Redirect(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/screen/DownloadingTerrainScreen;ready:Z"))
private boolean modifyCloseBehaviour(DownloadingTerrainScreen instance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) {
return this.ready/*TODO: Not in 1.19.2, but make the screen close faster*/ || System.currentTimeMillis() > this.loadStartTime + 2000;
}
return this.ready;
}
} }

View File

@ -38,7 +38,9 @@ import java.util.List;
public abstract class MixinGameModeSelectionScreen extends Screen { public abstract class MixinGameModeSelectionScreen extends Screen {
@Mutable @Mutable
@Shadow @Final private static int UI_WIDTH; @Shadow
@Final
private static int UI_WIDTH;
@Unique @Unique
private GameModeSelectionScreen.GameModeSelection[] viaFabricPlus$unwrappedGameModes; private GameModeSelectionScreen.GameModeSelection[] viaFabricPlus$unwrappedGameModes;

View File

@ -19,10 +19,10 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen;
import net.raphimc.vialoader.util.VersionEnum;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.GameModeSelectionScreen; import net.minecraft.client.gui.screen.GameModeSelectionScreen;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -36,14 +36,18 @@ import java.util.Optional;
@Mixin(GameModeSelectionScreen.GameModeSelection.class) @Mixin(GameModeSelectionScreen.GameModeSelection.class)
public abstract class MixinGameModeSelectionScreen_GameModeSelection { public abstract class MixinGameModeSelectionScreen_GameModeSelection {
@Shadow @Final public static GameModeSelectionScreen.GameModeSelection SURVIVAL; @Shadow
@Final
public static GameModeSelectionScreen.GameModeSelection SURVIVAL;
@Shadow @Final public static GameModeSelectionScreen.GameModeSelection CREATIVE; @Shadow
@Final
public static GameModeSelectionScreen.GameModeSelection CREATIVE;
@Inject(method = "next", at = @At("HEAD"), cancellable = true) @Inject(method = "next", at = @At("HEAD"), cancellable = true)
private void unwrapGameModes(CallbackInfoReturnable<Optional<GameModeSelectionScreen.GameModeSelection>> cir) { private void unwrapGameModes(CallbackInfoReturnable<Optional<GameModeSelectionScreen.GameModeSelection>> cir) {
if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_8)) { if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_8)) {
switch ((GameModeSelectionScreen.GameModeSelection)(Object)this) { switch ((GameModeSelectionScreen.GameModeSelection) (Object) this) {
case CREATIVE -> cir.setReturnValue(Optional.of(SURVIVAL)); case CREATIVE -> cir.setReturnValue(Optional.of(SURVIVAL));
case SURVIVAL -> { case SURVIVAL -> {
if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_2_4tor1_2_5)) { if (ProtocolHack.getTargetVersion().isOlderThan(VersionEnum.r1_2_4tor1_2_5)) {
@ -61,7 +65,7 @@ public abstract class MixinGameModeSelectionScreen_GameModeSelection {
private void oldCommand(CallbackInfoReturnable<String> cir) { private void oldCommand(CallbackInfoReturnable<String> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_2_4tor1_2_5)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_2_4tor1_2_5)) {
cir.setReturnValue( cir.setReturnValue(
"gamemode " + MinecraftClient.getInstance().getSession().getUsername() + ' ' + switch (((Enum<?>)(Object)this).ordinal()) { "gamemode " + MinecraftClient.getInstance().getSession().getUsername() + ' ' + switch (((Enum<?>) (Object) this).ordinal()) {
case 0, 3 -> 1; case 0, 3 -> 1;
case 1, 2 -> 0; case 1, 2 -> 0;
default -> throw new AssertionError(); default -> throw new AssertionError();

View File

@ -51,7 +51,7 @@ public abstract class MixinJigsawBlockScreen extends Screen {
} }
@Inject(method = "init", at = @At("RETURN")) @Inject(method = "init", at = @At("RETURN"))
private void injectInit(CallbackInfo ci) { private void removeWidgets(CallbackInfo ci) {
if (VisualSettings.global().removeNewerFeaturesFromJigsawScreen.isEnabled()) { if (VisualSettings.global().removeNewerFeaturesFromJigsawScreen.isEnabled()) {
nameField.active = false; nameField.active = false;
jointRotationButton.active = false; jointRotationButton.active = false;
@ -63,7 +63,7 @@ public abstract class MixinJigsawBlockScreen extends Screen {
} }
@Inject(method = "render", at = @At("HEAD")) @Inject(method = "render", at = @At("HEAD"))
private void injectRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { private void copyText(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
if (VisualSettings.global().removeNewerFeaturesFromJigsawScreen.isEnabled()) { if (VisualSettings.global().removeNewerFeaturesFromJigsawScreen.isEnabled()) {
nameField.setText(targetField.getText()); nameField.setText(targetField.getText());
} }

View File

@ -20,39 +20,35 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.gui.screen.ingame.AnvilScreen; import de.florianmichael.viafabricplus.util.MouseSensitivityUtil;
import net.minecraft.client.gui.screen.ingame.ForgingScreen; import net.minecraft.client.gui.DrawContext;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.network.packet.c2s.play.RenameItemC2SPacket; import net.minecraft.client.gui.screen.option.GameOptionsScreen;
import net.minecraft.screen.AnvilScreenHandler; import net.minecraft.client.gui.screen.option.MouseOptionsScreen;
import net.minecraft.screen.slot.Slot; import net.minecraft.client.gui.widget.OptionListWidget;
import net.minecraft.client.option.GameOptions;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(AnvilScreen.class) @Mixin(MouseOptionsScreen.class)
public abstract class MixinAnvilScreen extends ForgingScreen<AnvilScreenHandler> { public abstract class MixinMouseOptionsScreen extends GameOptionsScreen {
public MixinAnvilScreen(AnvilScreenHandler handler, PlayerInventory playerInventory, Text title, Identifier texture) { @Shadow
super(handler, playerInventory, title, texture); private OptionListWidget buttonList;
public MixinMouseOptionsScreen(Screen parent, GameOptions gameOptions, Text title) {
super(parent, gameOptions, title);
} }
@Inject(method = "onRenamed", at = @At("HEAD"), cancellable = true) @Inject(method = "render", at = @At("RETURN"))
private void changePacketLogic(String name, CallbackInfo ci) { private void render1_13SliderValue(DrawContext drawContext, int mouseX, int mouseY, float delta, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_4) && !name.isEmpty()) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2) && this.buttonList.getWidgetFor(this.gameOptions.getMouseSensitivity()).isHovered()) {
String string = name; drawContext.drawTooltip(textRenderer, Text.of("<=1.13.2 Sensitivity: " + MouseSensitivityUtil.get1_13SliderValue(this.gameOptions.getMouseSensitivity().getValue().floatValue()).valueInt() + "%"), mouseX, mouseY);
Slot slot = this.handler.getSlot(0);
if (slot != null && slot.hasStack() && !slot.getStack().hasCustomName() && name.equals(slot.getStack().getName().getString())) {
string = "";
}
this.handler.setNewItemName(string);
this.client.player.networkHandler.sendPacket(new RenameItemC2SPacket(string));
ci.cancel();
} }
} }

View File

@ -35,7 +35,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Screen.class) @Mixin(Screen.class)
public abstract class MixinScreen { public abstract class MixinScreen {
@Shadow @Nullable protected MinecraftClient client; @Shadow
@Nullable
protected MinecraftClient client;
@Inject(method = "handleTextClick", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;)V", shift = At.Shift.BEFORE, ordinal = 1, remap = false), cancellable = true) @Inject(method = "handleTextClick", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;)V", shift = At.Shift.BEFORE, ordinal = 1, remap = false), cancellable = true)
private void allowRunCommandAction(Style style, CallbackInfoReturnable<Boolean> cir) { private void allowRunCommandAction(Style style, CallbackInfoReturnable<Boolean> cir) {

View File

@ -19,12 +19,11 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen;
import net.raphimc.vialoader.util.VersionEnum;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@ -38,7 +37,7 @@ public abstract class MixinStructureBlockScreen_1 extends TextFieldWidget {
} }
@Inject(method = "charTyped(CI)Z", at = @At("HEAD"), cancellable = true) @Inject(method = "charTyped(CI)Z", at = @At("HEAD"), cancellable = true)
private void onCharTyped(char chr, int keyCode, CallbackInfoReturnable<Boolean> ci) { private void removeValidation(char chr, int keyCode, CallbackInfoReturnable<Boolean> ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2)) {
ci.setReturnValue(super.charTyped(chr, keyCode)); ci.setReturnValue(super.charTyped(chr, keyCode));
} }

View File

@ -19,25 +19,23 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.hud; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.hud;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import de.florianmichael.viafabricplus.settings.impl.VisualSettings; import de.florianmichael.viafabricplus.settings.impl.VisualSettings;
import net.minecraft.client.gui.hud.ChatHud; import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.ChatHudLine;
import net.minecraft.client.gui.hud.MessageIndicator; import net.minecraft.client.gui.hud.MessageIndicator;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(ChatHud.class) @Mixin(ChatHud.class)
public abstract class MixinChatHud { public abstract class MixinChatHud {
@WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/ChatHudLine$Visible;indicator()Lnet/minecraft/client/gui/hud/MessageIndicator;"), require = 0) @ModifyVariable(method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;ILnet/minecraft/client/gui/hud/MessageIndicator;Z)V", at = @At("HEAD"), ordinal = 0, argsOnly = true)
private MessageIndicator removeIndicators(ChatHudLine.Visible instance, Operation<MessageIndicator> original) { private MessageIndicator removeIndicator(MessageIndicator instance) {
if (VisualSettings.global().hideSignatureIndicator.isEnabled()) { if (VisualSettings.global().hideSignatureIndicator.isEnabled()) {
return null; return null;
} }
return original.call(instance); return instance;
} }
} }

View File

@ -28,7 +28,10 @@ import net.minecraft.entity.LivingEntity;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@ -40,11 +43,6 @@ public abstract class MixinInGameHud {
// Removing newer elements // Removing newer elements
@Inject(method = "renderExperienceBar", at = @At("HEAD"), cancellable = true)
private void removeExperienceBar(DrawContext context, int x, CallbackInfo ci) {
if (VisualSettings.global().removeNewerHudElements.isEnabled()) ci.cancel();
}
@Inject(method = "renderMountJumpBar", at = @At("HEAD"), cancellable = true) @Inject(method = "renderMountJumpBar", at = @At("HEAD"), cancellable = true)
private void removeMountJumpBar(JumpingMount mount, DrawContext context, int x, CallbackInfo ci) { private void removeMountJumpBar(JumpingMount mount, DrawContext context, int x, CallbackInfo ci) {
if (VisualSettings.global().removeNewerHudElements.isEnabled()) ci.cancel(); if (VisualSettings.global().removeNewerHudElements.isEnabled()) ci.cancel();

View File

@ -1,67 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.merchant;
import de.florianmichael.viafabricplus.settings.impl.DebugSettings;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.ingame.MerchantScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.packet.c2s.play.SelectMerchantTradeC2SPacket;
import net.minecraft.screen.MerchantScreenHandler;
import net.minecraft.text.Text;
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;
@Mixin(MerchantScreen.class)
public abstract class MixinMerchantScreen extends HandledScreen<MerchantScreenHandler> {
@Shadow
private int selectedIndex;
@Unique
private int viaFabricPlus$previousRecipeIndex;
public MixinMerchantScreen(MerchantScreenHandler handler, PlayerInventory inventory, Text title) {
super(handler, inventory, title);
}
@Inject(method = "init", at = @At("HEAD"))
private void reset(CallbackInfo ci) {
viaFabricPlus$previousRecipeIndex = 0;
}
@Inject(method = "syncRecipeIndex", at = @At("HEAD"))
private void smoothOutRecipeIndex(CallbackInfo ci) {
if (DebugSettings.global().smoothOutMerchantScreens.isEnabled()) {
if (viaFabricPlus$previousRecipeIndex != selectedIndex) {
int direction = viaFabricPlus$previousRecipeIndex < selectedIndex ? 1 : -1;
for (int smooth = viaFabricPlus$previousRecipeIndex + direction /* don't send the page we already are on */; smooth != selectedIndex; smooth += direction) {
client.getNetworkHandler().sendPacket(new SelectMerchantTradeC2SPacket(smooth));
}
viaFabricPlus$previousRecipeIndex = selectedIndex;
}
}
}
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.AbstractFurnaceScreenHandler;
import net.raphimc.vialoader.util.VersionEnum;
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.Redirect;
@Mixin(AbstractFurnaceScreenHandler.class)
public abstract class MixinAbstractFurnaceScreenHandler {
@Shadow
protected abstract boolean isSmeltable(ItemStack itemStack);
@Shadow
protected abstract boolean isFuel(ItemStack itemStack);
@Redirect(method = "quickMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/AbstractFurnaceScreenHandler;isSmeltable(Lnet/minecraft/item/ItemStack;)Z"))
private boolean disableShiftClickSmeltingSlot(AbstractFurnaceScreenHandler instance, ItemStack itemStack) {
return this.isSmeltable(itemStack) && !ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_2_1tor1_2_3);
}
@Redirect(method = "quickMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/AbstractFurnaceScreenHandler;isFuel(Lnet/minecraft/item/ItemStack;)Z"))
private boolean disableShiftClickFuelSlot(AbstractFurnaceScreenHandler instance, ItemStack itemStack) {
return this.isFuel(itemStack) && !ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_2_1tor1_2_3);
}
}

View File

@ -19,11 +19,10 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler;
import net.raphimc.vialoader.util.VersionEnum;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@ -37,9 +36,9 @@ public abstract class MixinBrewingStandScreenHandler_FuelSlot extends Slot {
} }
@Inject(method = "matches(Lnet/minecraft/item/ItemStack;)Z", at = @At("HEAD"), cancellable = true) @Inject(method = "matches(Lnet/minecraft/item/ItemStack;)Z", at = @At("HEAD"), cancellable = true)
private static void removeFuelSlot(CallbackInfoReturnable<Boolean> ci) { private static void removeFuelSlot(CallbackInfoReturnable<Boolean> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
ci.setReturnValue(false); cir.setReturnValue(false);
} }
} }

View File

@ -19,10 +19,11 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler;
import de.florianmichael.viafabricplus.fixes.diff.RecipesPre1_12; import de.florianmichael.viafabricplus.fixes.recipe.Recipes1_11_2;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.RecipeInputInventory; import net.minecraft.inventory.RecipeInputInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.AbstractRecipeScreenHandler; import net.minecraft.screen.AbstractRecipeScreenHandler;
import net.minecraft.screen.CraftingScreenHandler; import net.minecraft.screen.CraftingScreenHandler;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
@ -32,21 +33,30 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; 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.CallbackInfo;
@Mixin(CraftingScreenHandler.class) @Mixin(CraftingScreenHandler.class)
public abstract class MixinCraftingScreenHandler extends AbstractRecipeScreenHandler<RecipeInputInventory> { public abstract class MixinCraftingScreenHandler extends AbstractRecipeScreenHandler<RecipeInputInventory> {
@Shadow @Final private RecipeInputInventory input; @Shadow
@Final
private RecipeInputInventory input;
public MixinCraftingScreenHandler(ScreenHandlerType<?> screenHandlerType, int i) { public MixinCraftingScreenHandler(ScreenHandlerType<?> screenHandlerType, int i) {
super(screenHandlerType, i); super(screenHandlerType, i);
} }
@Redirect(method = "quickMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/CraftingScreenHandler;insertItem(Lnet/minecraft/item/ItemStack;IIZ)Z", ordinal = 1))
private boolean noShiftClickMoveIntoCraftingTable(CraftingScreenHandler instance, ItemStack itemStack, int startIndex, int endIndex, boolean fromLast) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_14_4)) return false;
return this.insertItem(itemStack, startIndex, endIndex, fromLast);
}
@Inject(method = "onContentChanged", at = @At("HEAD")) @Inject(method = "onContentChanged", at = @At("HEAD"))
private void updateResultSlot(Inventory inventory, CallbackInfo ci) { private void clientSideCrafting(Inventory inventory, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) {
RecipesPre1_12.setCraftingResultSlot(syncId, this, input); Recipes1_11_2.setCraftingResultSlot(syncId, this, input);
} }
} }

View File

@ -0,0 +1,118 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.MerchantScreenHandler;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.village.MerchantInventory;
import net.minecraft.village.TradeOfferList;
import net.raphimc.vialoader.util.VersionEnum;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(MerchantScreenHandler.class)
public abstract class MixinMerchantScreenHandler extends ScreenHandler {
@Shadow
@Final
private MerchantInventory merchantInventory;
@Shadow
public abstract TradeOfferList getRecipes();
protected MixinMerchantScreenHandler(@Nullable ScreenHandlerType<?> type, int syncId) {
super(type, syncId);
}
@Inject(method = "switchTo", at = @At("HEAD"), cancellable = true)
private void onSwitchTo(int recipeId, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2)) {
ci.cancel();
if (recipeId >= this.getRecipes().size()) return;
final ClientPlayerInteractionManager interactionManager = MinecraftClient.getInstance().interactionManager;
final ClientPlayerEntity player = MinecraftClient.getInstance().player;
// move 1st input slot to inventory
if (!this.merchantInventory.getStack(0).isEmpty()) {
final int count = this.merchantInventory.getStack(0).getCount();
interactionManager.clickSlot(syncId, 0, 0, SlotActionType.QUICK_MOVE, player);
if (count == this.merchantInventory.getStack(0).getCount()) return;
}
// move 2nd input slot to inventory
if (!this.merchantInventory.getStack(1).isEmpty()) {
final int count = this.merchantInventory.getStack(1).getCount();
interactionManager.clickSlot(syncId, 1, 0, SlotActionType.QUICK_MOVE, player);
if (count == this.merchantInventory.getStack(1).getCount()) return;
}
// refill the slots
if (this.merchantInventory.getStack(0).isEmpty() && this.merchantInventory.getStack(1).isEmpty()) {
this.autofill(interactionManager, player, 0, this.getRecipes().get(recipeId).getAdjustedFirstBuyItem());
this.autofill(interactionManager, player, 1, this.getRecipes().get(recipeId).getSecondBuyItem());
}
}
}
@Inject(method = "canInsertIntoSlot", at = @At("HEAD"), cancellable = true)
private void modifyCanInsertIntoSlot(ItemStack stack, Slot slot, CallbackInfoReturnable<Boolean> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2)) {
cir.setReturnValue(true);
}
}
@Unique
private void autofill(ClientPlayerInteractionManager interactionManager, ClientPlayerEntity player, int inputSlot, ItemStack stackNeeded) {
if (stackNeeded.isEmpty()) return;
int slot;
for (slot = 3; slot < 39; slot++) {
final ItemStack stack = slots.get(slot).getStack();
if (ItemStack.canCombine(stack, stackNeeded)) {
break;
}
}
if (slot == 39) return;
final boolean wasHoldingItem = !player.currentScreenHandler.getCursorStack().isEmpty();
interactionManager.clickSlot(syncId, slot, 0, SlotActionType.PICKUP, player);
interactionManager.clickSlot(syncId, slot, 0, SlotActionType.PICKUP_ALL, player);
interactionManager.clickSlot(syncId, inputSlot, 0, SlotActionType.PICKUP, player);
if (wasHoldingItem) interactionManager.clickSlot(syncId, slot, 0, SlotActionType.PICKUP, player);
}
}

View File

@ -19,56 +19,50 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler; package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler;
import de.florianmichael.viafabricplus.fixes.diff.RecipesPre1_12; import de.florianmichael.viafabricplus.fixes.recipe.Recipes1_11_2;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.RecipeInputInventory; import net.minecraft.inventory.RecipeInputInventory;
import net.raphimc.vialoader.util.VersionEnum;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.screen.AbstractRecipeScreenHandler; import net.minecraft.screen.AbstractRecipeScreenHandler;
import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.*; 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.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerScreenHandler.class) @Mixin(PlayerScreenHandler.class)
public abstract class MixinPlayerScreenHandler extends AbstractRecipeScreenHandler<CraftingInventory> { public abstract class MixinPlayerScreenHandler extends AbstractRecipeScreenHandler<CraftingInventory> {
@Shadow @Final private RecipeInputInventory craftingInput; @Shadow
@Final
private RecipeInputInventory craftingInput;
public MixinPlayerScreenHandler(ScreenHandlerType<?> screenHandlerType, int i) { public MixinPlayerScreenHandler(ScreenHandlerType<?> screenHandlerType, int i) {
super(screenHandlerType, i); super(screenHandlerType, i);
} }
@Inject(method = "onContentChanged", at = @At("HEAD")) @Inject(method = "onContentChanged", at = @At("HEAD"))
public void updateResultSlot(Inventory inventory, CallbackInfo ci) { public void clientSideCrafting(Inventory inventory, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) {
RecipesPre1_12.setCraftingResultSlot(syncId, this, craftingInput); Recipes1_11_2.setCraftingResultSlot(syncId, this, craftingInput);
} }
} }
@Redirect(method = "<init>", @Redirect(method = "<init>",
slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/screen/PlayerScreenHandler$2;<init>(Lnet/minecraft/screen/PlayerScreenHandler;Lnet/minecraft/inventory/Inventory;IIILnet/minecraft/entity/player/PlayerEntity;)V")), slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/screen/PlayerScreenHandler$2;<init>(Lnet/minecraft/screen/PlayerScreenHandler;Lnet/minecraft/inventory/Inventory;IIILnet/minecraft/entity/player/PlayerEntity;)V")),
at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/PlayerScreenHandler;addSlot(Lnet/minecraft/screen/slot/Slot;)Lnet/minecraft/screen/slot/Slot;", ordinal = 0)) at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/PlayerScreenHandler;addSlot(Lnet/minecraft/screen/slot/Slot;)Lnet/minecraft/screen/slot/Slot;", ordinal = 0))
private Slot redirectAddOffhandSlot(PlayerScreenHandler screenHandler, Slot slot) { private Slot removeOffhandSlot(PlayerScreenHandler screenHandler, Slot slot) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8))
return null; return null;
return addSlot(slot); return addSlot(slot);
} }
@SuppressWarnings("InvalidInjectorMethodSignature")
@ModifyVariable(method = "quickMove", ordinal = 0, at = @At(value = "STORE", ordinal = 0))
private EquipmentSlot injectTransferSlot(EquipmentSlot slot) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8) && slot == EquipmentSlot.OFFHAND) {
return EquipmentSlot.MAINHAND;
} else {
return slot;
}
}
} }

View File

@ -21,32 +21,39 @@ package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.s
import de.florianmichael.viafabricplus.injection.access.IScreenHandler; import de.florianmichael.viafabricplus.injection.access.IScreenHandler;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack;
import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.SlotActionType;
import net.raphimc.vialoader.util.VersionEnum; import net.raphimc.vialoader.util.VersionEnum;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; 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;
@Mixin(ScreenHandler.class) @Mixin(ScreenHandler.class)
public abstract class MixinScreenHandler implements IScreenHandler { public abstract class MixinScreenHandler implements IScreenHandler {
@Unique @Shadow
private short viaFabricPlus$lastActionId = 0; private ItemStack cursorStack;
@Inject(method = "internalOnSlotClick", at = @At("HEAD"), cancellable = true) @Unique
private void injectInternalOnSlotClick(int slot, int clickData, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) { private short viaFabricPlus$actionId = 0;
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8) && actionType == SlotActionType.SWAP && clickData == 40) {
ci.cancel(); @Redirect(method = "updateSlotStacks", at = @At(value = "FIELD", target = "Lnet/minecraft/screen/ScreenHandler;cursorStack:Lnet/minecraft/item/ItemStack;"))
private void preventUpdate(ScreenHandler instance, ItemStack value) {
if (ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_17_1)) {
this.cursorStack = value;
} }
} }
@Override @Override
public short viaFabricPlus$getAndIncrementLastActionId() { public short viaFabricPlus$getActionId() {
return ++viaFabricPlus$lastActionId; return viaFabricPlus$actionId;
}
@Override
public short viaFabricPlus$incrementAndGetActionId() {
return ++viaFabricPlus$actionId;
} }
} }

View File

@ -24,12 +24,12 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant; import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(CommandBlockProvider.class) @Mixin(value = CommandBlockProvider.class, remap = false)
public abstract class MixinCommandBlockProvider { public abstract class MixinCommandBlockProvider {
@ModifyConstant(method = "sendPermission", constant = @Constant(intValue = 26), remap = false) @ModifyConstant(method = "sendPermission", constant = @Constant(intValue = 26))
private int modifyPermissionLevel(int constant) { private int modifyPermissionLevel(int constant) {
return 28; return 28; // OP level 4
} }
} }

View File

@ -20,16 +20,39 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion; package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion;
import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ByteTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.protocols.protocol1_11to1_10.EntityIdRewriter; import com.viaversion.viaversion.protocols.protocol1_11to1_10.EntityIdRewriter;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = EntityIdRewriter.class, remap = false) @Mixin(value = EntityIdRewriter.class, remap = false)
public abstract class MixinEntityIdRewriter { public abstract class MixinEntityIdRewriter {
@Redirect(method = "toClientItem(Lcom/viaversion/viaversion/api/minecraft/item/Item;Z)V", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/minecraft/item/Item;setAmount(I)V")) @Inject(method = "toClientItem(Lcom/viaversion/viaversion/api/minecraft/item/Item;Z)V", at = @At("HEAD"))
private static void allowNegativeItems(Item instance, int i) { private static void handleNegativeItemCountS2C(Item item, boolean backwards, CallbackInfo ci) {
if (item != null && item.amount() <= 0) {
CompoundTag tag = item.tag();
if (tag == null) {
tag = new CompoundTag();
item.setTag(tag);
}
tag.put("1_10_ViaFabricPlus_ItemCount", new ByteTag((byte) item.amount()));
item.setTag(tag);
}
}
@Inject(method = "toServerItem(Lcom/viaversion/viaversion/api/minecraft/item/Item;Z)V", at = @At("HEAD"))
private static void handleNegativeItemCountC2S(Item item, boolean backwards, CallbackInfo ci) {
if (item != null && item.tag() != null) {
if (item.tag().contains("1_10_ViaFabricPlus_ItemCount")) {
item.setAmount(item.tag().<ByteTag>remove("1_10_ViaFabricPlus_ItemCount").asByte());
if (item.tag().isEmpty()) item.setTag(null);
}
}
} }
} }

View File

@ -0,0 +1,26 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.Protocol1_19_4To1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.packets.EntityPackets;
import com.viaversion.viaversion.rewriter.EntityRewriter;
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;
@Mixin(value = EntityPackets.class, remap = false)
public abstract class MixinEntityPackets1_19_4 extends EntityRewriter<ClientboundPackets1_19_3, Protocol1_19_4To1_19_3> {
protected MixinEntityPackets1_19_4(Protocol1_19_4To1_19_3 protocol) {
super(protocol);
}
@Inject(method = "registerPackets", at = @At("RETURN"))
private void fixTeleportBehaviour(CallbackInfo ci) {
this.protocol.registerClientbound(ClientboundPackets1_19_3.ENTITY_TELEPORT, ClientboundPackets1_19_4.ENTITY_TELEPORT, wrapper -> {
}, true);
}
}

View File

@ -33,12 +33,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public abstract class MixinInventoryAcknowledgements { public abstract class MixinInventoryAcknowledgements {
@Mutable @Mutable
@Shadow @Final private IntList ids; @Shadow
@Final
private IntList ids;
@Unique @Unique
private it.unimi.dsi.fastutil.ints.IntList viaFabricPlus$ids; private it.unimi.dsi.fastutil.ints.IntList viaFabricPlus$ids;
@Inject(method = "<init>", at = @At("RETURN")) @Inject(method = "<init>", at = @At("RETURN"))
private void fixJavaIssue(CallbackInfo ci) { private void makeConcurrent(CallbackInfo ci) {
this.ids = null; this.ids = null;
this.viaFabricPlus$ids = IntLists.synchronize(new IntArrayList()); this.viaFabricPlus$ids = IntLists.synchronize(new IntArrayList());
} }

View File

@ -19,65 +19,36 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion; package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement; import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14; import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.packets.InventoryPackets; import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.packets.InventoryPackets;
import de.florianmichael.viafabricplus.fixes.ChestHandler1_13_2;
import de.florianmichael.viafabricplus.fixes.ClientsideFixes; import de.florianmichael.viafabricplus.fixes.ClientsideFixes;
import de.florianmichael.viafabricplus.fixes.TripleChestHandler1_13_2; import de.florianmichael.viafabricplus.protocolhack.translator.TextComponentTranslator;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import io.netty.buffer.Unpooled;
import net.minecraft.SharedConstants;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
@Mixin(value = InventoryPackets.class, remap = false) @Mixin(value = InventoryPackets.class, remap = false)
public abstract class MixinInventoryPackets { public abstract class MixinInventoryPackets {
@Inject(method = "lambda$registerPackets$0", at = @At(value = "INVOKE", target = "Ljava/util/logging/Logger;warning(Ljava/lang/String;)V"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) @Inject(method = "lambda$registerPackets$0", at = @At(value = "INVOKE", target = "Ljava/util/logging/Logger;warning(Ljava/lang/String;)V", remap = false), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
private static void supportCustomSlots(PacketWrapper wrapper, CallbackInfo ci, Short windowId, String type, JsonElement title, Short slots, int typeId) { private static void supportLargeContainers(PacketWrapper wrapper, CallbackInfo ci, Short windowId, String type, JsonElement title, Short slots) {
if (typeId == -1) { if ((type.equals("minecraft:container") || type.equals("minecraft:chest")) && (slots > 54 || slots <= 0)) {
ci.cancel();
final String uuid = ClientsideFixes.executeSyncTask(ChestHandler1_13_2.OLD_PACKET_HANDLER);
wrapper.clearPacket(); wrapper.clearPacket();
wrapper.setPacketType(ClientboundPackets1_14.PLUGIN_MESSAGE); wrapper.setPacketType(ClientboundPackets1_14.PLUGIN_MESSAGE);
wrapper.write(Type.STRING, ClientsideFixes.PACKET_SYNC_IDENTIFIER); wrapper.write(Type.STRING, ClientsideFixes.PACKET_SYNC_IDENTIFIER);
wrapper.write(Type.STRING, uuid);
final List<ProtocolPathEntry> protocolPath = Via.getManager().getProtocolManager().getProtocolPath(SharedConstants.getProtocolVersion(), ProtocolVersion.v1_13_2.getVersion()); wrapper.write(Type.UNSIGNED_BYTE, windowId);
final var userConnection = ProtocolHack.createFakerUserConnection(); wrapper.write(Type.UNSIGNED_BYTE, slots);
wrapper.write(Type.COMPONENT, TextComponentTranslator.via1_13_2toViaLatest(title));
try {
var fakeOpenWindow = PacketWrapper.create(ClientboundPackets1_14.OPEN_WINDOW, Unpooled.buffer(), userConnection);
fakeOpenWindow.write(Type.VAR_INT, windowId.intValue());
fakeOpenWindow.write(Type.VAR_INT, typeId);
fakeOpenWindow.write(Type.COMPONENT, title);
fakeOpenWindow.apply(Direction.CLIENTBOUND, State.PLAY, 0, protocolPath.stream().map(ProtocolPathEntry::protocol).collect(Collectors.toList()), true);
fakeOpenWindow.read(Type.VAR_INT);
fakeOpenWindow.read(Type.VAR_INT);
final String uuid = ClientsideFixes.executeSyncTask(TripleChestHandler1_13_2.TRIPLE_CHEST_HANDLER);
wrapper.write(Type.STRING, uuid);
wrapper.write(Type.SHORT, windowId);
wrapper.write(Type.COMPONENT, fakeOpenWindow.read(Type.COMPONENT));
wrapper.write(Type.SHORT, slots);
} catch (Exception e) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Failed to emulate Triple Chest", e);
}
ci.cancel();
} }
} }

View File

@ -0,0 +1,29 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ServerboundPackets1_14;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.packets.InventoryPackets;
import com.viaversion.viaversion.rewriter.ItemRewriter;
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;
@Mixin(value = InventoryPackets.class, remap = false)
public abstract class MixinInventoryPackets1_13 extends ItemRewriter<ClientboundPackets1_13, ServerboundPackets1_14, Protocol1_14To1_13_2> {
public MixinInventoryPackets1_13(Protocol1_14To1_13_2 protocol, Type<Item> itemType, Type<Item[]> itemArrayType) {
super(protocol, itemType, itemArrayType);
}
@Inject(method = "registerPackets", at = @At("RETURN"))
private void dontResyncInventory(CallbackInfo ci) {
this.protocol.registerServerbound(ServerboundPackets1_14.SELECT_TRADE, ServerboundPackets1_13.SELECT_TRADE, (PacketHandler) null, true);
}
}

View File

@ -0,0 +1,51 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ServerboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.packets.InventoryPackets;
import com.viaversion.viaversion.rewriter.ItemRewriter;
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;
@Mixin(value = InventoryPackets.class, remap = false)
public abstract class MixinInventoryPackets1_17 extends ItemRewriter<ClientboundPackets1_16_2, ServerboundPackets1_17, Protocol1_17To1_16_4> {
public MixinInventoryPackets1_17(Protocol1_17To1_16_4 protocol, Type<Item> itemType, Type<Item[]> itemArrayType) {
super(protocol, itemType, itemArrayType);
}
@Inject(method = "registerPackets", at = @At("RETURN"))
private void removeWindowClickHandler(CallbackInfo ci) {
this.protocol.registerServerbound(ServerboundPackets1_17.CLICK_WINDOW, ServerboundPackets1_16_2.CLICK_WINDOW, wrapper -> {
Via.getPlatform().getLogger().severe("Tried to remap >=1.17 CLICK_WINDOW packet which is impossible without breaking the content! Find the cause and fix it!");
wrapper.cancel();
}, true);
}
}

View File

@ -19,19 +19,20 @@
package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion; package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag; import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.storage.InventoryTracker1_16;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.providers.blockentities.SkullHandler;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = SkullHandler.class, remap = false) @Mixin(value = InventoryTracker1_16.class, remap = false)
public abstract class MixinSkullHandler { public abstract class MixinInventoryTracker1_16 {
@Inject(method = "getLong", at = @At("HEAD"), cancellable = true) /**
public void checkIfTagExists(NumberTag tag, CallbackInfoReturnable<Long> cir) { * @author RK_01
if (tag == null) cir.setReturnValue(0L); * @reason Fix ViaVersion cancelling swing packets even when no inventory is open
*/
@Overwrite
public boolean isInventoryOpen() {
return false;
} }
} }

View File

@ -22,48 +22,15 @@ package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion;
import com.viaversion.viaversion.api.type.types.misc.NamedCompoundTagType; import com.viaversion.viaversion.api.type.types.misc.NamedCompoundTagType;
import com.viaversion.viaversion.libs.opennbt.tag.limiter.TagLimiter; import com.viaversion.viaversion.libs.opennbt.tag.limiter.TagLimiter;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = NamedCompoundTagType.class, remap = false) @Mixin(value = NamedCompoundTagType.class, remap = false)
public abstract class MixinNamedCompoundTagType { public abstract class MixinNamedCompoundTagType {
@Unique
private static final TagLimiter viaFabricPlus$tag_limiter = new TagLimiter() {
private final int maxBytes = 2097152;
private int bytes;
@Override
public void countBytes(int i) {
this.bytes += bytes;
if (this.bytes >= this.maxBytes) {
throw new IllegalArgumentException("NBT data larger than expected (capped at " + this.maxBytes + ")");
}
}
@Override
public void checkLevel(int i) {}
@Override
public int maxBytes() {
return this.maxBytes;
}
@Override
public int maxLevels() {
return 512; // Not used anymore
}
@Override
public int bytes() {
return this.bytes;
}
};
@Redirect(method = "read(Lio/netty/buffer/ByteBuf;Z)Lcom/viaversion/viaversion/libs/opennbt/tag/builtin/CompoundTag;", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/libs/opennbt/tag/limiter/TagLimiter;create(II)Lcom/viaversion/viaversion/libs/opennbt/tag/limiter/TagLimiter;")) @Redirect(method = "read(Lio/netty/buffer/ByteBuf;Z)Lcom/viaversion/viaversion/libs/opennbt/tag/builtin/CompoundTag;", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/libs/opennbt/tag/limiter/TagLimiter;create(II)Lcom/viaversion/viaversion/libs/opennbt/tag/limiter/TagLimiter;"))
private static TagLimiter replaceTagLimiter(int maxBytes, int maxLevels) { private static TagLimiter removeNBTSizeLimit(int maxBytes, int maxLevels) {
return viaFabricPlus$tag_limiter; return TagLimiter.noop();
} }
} }

Some files were not shown because too many files have changed in this diff Show More