ViaFabricPlus/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinMinecraftClient.java

170 lines
8.3 KiB
Java

/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2024 FlorianMichael/EnZaXD <florian.michael07@gmail.com> and RK_01/RaphiMC
* Copyright (C) 2023-2024 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 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_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3;
import de.florianmichael.viafabricplus.fixes.data.ItemRegistryDiff;
import de.florianmichael.viafabricplus.injection.access.IMouseKeyboard;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.settings.impl.DebugSettings;
import net.minecraft.client.Keyboard;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
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.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.CallbackInfoReturnable;
import java.util.Queue;
@Mixin(MinecraftClient.class)
public abstract class MixinMinecraftClient {
@Shadow
@Nullable
public ClientPlayerEntity player;
@Shadow
public int attackCooldown;
@Shadow
@Final
public Mouse mouse;
@Shadow
@Final
public Keyboard keyboard;
@Redirect(method = "doItemPick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerInventory;addPickBlock(Lnet/minecraft/item/ItemStack;)V"))
private void filterItem(PlayerInventory instance, ItemStack stack) {
if (ItemRegistryDiff.keepItem(stack.getItem())) {
instance.addPickBlock(stack);
}
}
/**
* Never happens in Vanilla, this is only for {@link ItemRegistryDiff} to work
*/
@Redirect(method = "doItemPick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;clickCreativeStack(Lnet/minecraft/item/ItemStack;I)V"))
private void dontSendEmptyItem(ClientPlayerInteractionManager instance, ItemStack stack, int slotId) {
if (!stack.isEmpty()) {
instance.clickCreativeStack(stack, slotId);
}
}
@Redirect(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/ActionResult;shouldSwingHand()Z", ordinal = 0))
private boolean disableSwing(ActionResult instance) {
return instance.shouldSwingHand() && ProtocolHack.getTargetVersion().isNewerThanOrEqualTo(VersionEnum.r1_15);
}
@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);
}
}
@WrapWithCondition(method = "doAttack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;swingHand(Lnet/minecraft/util/Hand;)V"))
private boolean fixSwingPacketOrder(ClientPlayerEntity instance, Hand hand) {
return ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_8);
}
@Redirect(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;attackCooldown:I", ordinal = 1))
private int dontIncrementCooldown(MinecraftClient instance) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
return 0;
}
return attackCooldown;
}
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;handleInputEvents()V", shift = At.Shift.BEFORE))
private void postIncrementCooldown(CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8)) {
if (this.attackCooldown > 0) {
--this.attackCooldown;
}
}
}
@ModifyExpressionValue(method = "handleBlockBreaking", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isUsingItem()Z"))
private boolean allowBlockBreakAndItemUsageAtTheSameTime(boolean original) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_7_6tor1_7_10)) {
return false;
}
return original;
}
}