mirror of
https://github.com/TeamMidnightDust/MidnightControls.git
synced 2025-12-13 07:15:10 +01:00
✨ Add new recipe book controls and front block outline.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
package me.lambdaurora.lambdacontrols.client;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.Controller;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
|
||||
@@ -19,8 +20,10 @@ import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccesso
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor;
|
||||
import me.lambdaurora.spruceui.SpruceLabelWidget;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.FluidBlock;
|
||||
import net.minecraft.block.SlabBlock;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.ParentElement;
|
||||
@@ -37,6 +40,8 @@ import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
|
||||
import net.minecraft.client.gui.widget.SliderWidget;
|
||||
import net.minecraft.container.Slot;
|
||||
import net.minecraft.container.SlotActionType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -671,6 +676,8 @@ public class LambdaInput
|
||||
|
||||
public static @Nullable BlockHitResult tryFrontPlace(@NotNull MinecraftClient client)
|
||||
{
|
||||
if (!LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable())
|
||||
return null;
|
||||
if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS && client.player.onGround && client.player.pitch > 35.0F) {
|
||||
if (client.player.isRiding())
|
||||
return null;
|
||||
@@ -686,8 +693,22 @@ public class LambdaInput
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BlockHitResult(client.crosshairTarget.getPos(), direction.getOpposite(), blockPos, false);
|
||||
return new BlockHitResult(client.crosshairTarget.getPos(), direction, blockPos, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @NotNull BlockHitResult withSideForFrontPlace(@NotNull BlockHitResult result, @Nullable ItemStack stack)
|
||||
{
|
||||
if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem))
|
||||
return result;
|
||||
return withSideForFrontPlace(result, Block.getBlockFromItem(stack.getItem()));
|
||||
}
|
||||
|
||||
public static @NotNull BlockHitResult withSideForFrontPlace(@NotNull BlockHitResult result, @NotNull Block block)
|
||||
{
|
||||
if (block instanceof SlabBlock)
|
||||
result = result.withSide(Direction.DOWN);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ package me.lambdaurora.lambdacontrols.client.controller;
|
||||
import me.lambdaurora.lambdacontrols.client.ButtonState;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.RecipeBookWidgetAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
@@ -19,6 +20,8 @@ import net.minecraft.client.gui.screen.advancement.AdvancementTab;
|
||||
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.ContainerScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
|
||||
import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget;
|
||||
import net.minecraft.client.util.ScreenshotUtils;
|
||||
import net.minecraft.container.Slot;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
@@ -59,14 +62,27 @@ public class InputHandlers
|
||||
return true;
|
||||
} else if (client.currentScreen instanceof CreativeInventoryScreen) {
|
||||
CreativeInventoryScreenAccessor inventory = (CreativeInventoryScreenAccessor) client.currentScreen;
|
||||
int currentSelectedTab = inventory.getSelectedTab();
|
||||
int nextTab = currentSelectedTab + (right ? 1 : -1);
|
||||
int currentTab = inventory.getSelectedTab();
|
||||
int nextTab = currentTab + (right ? 1 : -1);
|
||||
if (nextTab < 0)
|
||||
nextTab = ItemGroup.GROUPS.length - 1;
|
||||
else if (nextTab >= ItemGroup.GROUPS.length)
|
||||
nextTab = 0;
|
||||
inventory.lambdacontrols_setSelectedTab(ItemGroup.GROUPS[nextTab]);
|
||||
return true;
|
||||
} else if (client.currentScreen instanceof InventoryScreen) {
|
||||
RecipeBookWidgetAccessor recipeBook = (RecipeBookWidgetAccessor) ((InventoryScreen) client.currentScreen).getRecipeBookWidget();
|
||||
List<RecipeGroupButtonWidget> tabs = recipeBook.getTabButtons();
|
||||
RecipeGroupButtonWidget currentTab = recipeBook.getCurrentTab();
|
||||
int nextTab = tabs.indexOf(currentTab) + (right ? 1 : -1);
|
||||
if (nextTab < 0)
|
||||
nextTab = tabs.size() - 1;
|
||||
else if (nextTab >= tabs.size())
|
||||
nextTab = 0;
|
||||
currentTab.setToggled(false);
|
||||
recipeBook.setCurrentTab(currentTab = tabs.get(nextTab));
|
||||
currentTab.setToggled(true);
|
||||
recipeBook.lambdacontrols_refreshResults(true);
|
||||
} else if (client.currentScreen instanceof AdvancementsScreen) {
|
||||
AdvancementsScreenAccessor screen = (AdvancementsScreenAccessor) client.currentScreen;
|
||||
List<AdvancementTab> tabs = screen.getTabs().values().stream().distinct().collect(Collectors.toList());
|
||||
|
||||
@@ -24,6 +24,8 @@ import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -59,6 +61,10 @@ public abstract class MinecraftClientMixin
|
||||
@Shadow
|
||||
private int itemUseCooldown;
|
||||
|
||||
private BlockPos lambdacontrols_lastTargetPos;
|
||||
private Direction lambdacontrols_lockedSide;
|
||||
private int lambdacontrols_lockedSideCooldown;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void onInit(CallbackInfo ci)
|
||||
{
|
||||
@@ -68,14 +74,31 @@ public abstract class MinecraftClientMixin
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void onStartTick(CallbackInfo ci)
|
||||
{
|
||||
if (this.player != null && this.player.isCreative()) {
|
||||
if (!LambdaControlsFeature.FAST_BLOCK_INTERACTION.isAvailable())
|
||||
return;
|
||||
if (this.player != null) {
|
||||
int cooldown = this.itemUseCooldown;
|
||||
BlockHitResult hitResult;
|
||||
if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.BLOCK && this.player.abilities.flying) {
|
||||
if (cooldown > 1)
|
||||
hitResult = (BlockHitResult) this.crosshairTarget;
|
||||
BlockPos targetPos = hitResult.getBlockPos();
|
||||
Direction side = hitResult.getSide();
|
||||
|
||||
if (cooldown > 1 && !targetPos.equals(this.lambdacontrols_lastTargetPos) && (side.equals(this.lambdacontrols_lockedSide) || this.lambdacontrols_lockedSide == null)) {
|
||||
this.itemUseCooldown = 1;
|
||||
this.lambdacontrols_lockedSide = side;
|
||||
this.lambdacontrols_lockedSideCooldown = 10;
|
||||
} else {
|
||||
if (this.lambdacontrols_lockedSideCooldown == 0)
|
||||
this.lambdacontrols_lockedSide = null;
|
||||
else if (this.lambdacontrols_lockedSideCooldown > 0)
|
||||
this.lambdacontrols_lockedSideCooldown--;
|
||||
}
|
||||
|
||||
this.lambdacontrols_lastTargetPos = targetPos.toImmutable();
|
||||
} else if (this.player.isSprinting()) {
|
||||
BlockHitResult result = LambdaInput.tryFrontPlace(((MinecraftClient) (Object) this));
|
||||
if (result != null) {
|
||||
hitResult = LambdaInput.tryFrontPlace(((MinecraftClient) (Object) this));
|
||||
if (hitResult != null) {
|
||||
if (cooldown > 0)
|
||||
this.itemUseCooldown = 0;
|
||||
}
|
||||
@@ -106,6 +129,8 @@ public abstract class MinecraftClientMixin
|
||||
if (hitResult == null)
|
||||
return;
|
||||
|
||||
hitResult = LambdaInput.withSideForFrontPlace(hitResult, stackInHand);
|
||||
|
||||
int previousStackCount = stackInHand.getCount();
|
||||
ActionResult result = this.interactionManager.interactBlock(this.player, this.world, hand, hitResult);
|
||||
if (result.isAccepted()) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
* Licensed under the MIT license. For more information,
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget;
|
||||
import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(RecipeBookWidget.class)
|
||||
public interface RecipeBookWidgetAccessor
|
||||
{
|
||||
@Accessor("tabButtons")
|
||||
List<RecipeGroupButtonWidget> getTabButtons();
|
||||
|
||||
@Accessor("currentTab")
|
||||
RecipeGroupButtonWidget getCurrentTab();
|
||||
|
||||
@Accessor("currentTab")
|
||||
void setCurrentTab(RecipeGroupButtonWidget currentTab);
|
||||
|
||||
@Invoker("refreshResults")
|
||||
void lambdacontrols_refreshResults(boolean resetCurrentPage);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
* Licensed under the MIT license. For more information,
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaInput;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.SlabBlock;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.*;
|
||||
import net.minecraft.client.util.math.Matrix4f;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.EntityContext;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
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.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
/**
|
||||
* Represents a mixin to WorldRenderer.
|
||||
* <p>
|
||||
* Handles the rendering of the block outline of the front block placing.
|
||||
*/
|
||||
@Mixin(WorldRenderer.class)
|
||||
public abstract class WorldRendererMixin
|
||||
{
|
||||
@Shadow
|
||||
@Final
|
||||
private MinecraftClient client;
|
||||
|
||||
@Shadow
|
||||
private ClientWorld world;
|
||||
|
||||
@Shadow
|
||||
private static void drawShapeOutline(MatrixStack matrixStack, VertexConsumer vertexConsumer, VoxelShape voxelShape, double d, double e, double f, float g, float h, float i, float j)
|
||||
{
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "render",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
target = "Lnet/minecraft/client/MinecraftClient;crosshairTarget:Lnet/minecraft/util/hit/HitResult;",
|
||||
ordinal = 1,
|
||||
shift = At.Shift.AFTER
|
||||
),
|
||||
locals = LocalCapture.CAPTURE_FAILEXCEPTION
|
||||
)
|
||||
private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer,
|
||||
LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci,
|
||||
Profiler profiler, Vec3d cameraPos, double x, double y, double z, Matrix4f modelMatrix, boolean bl, Frustum frustum2, boolean bl3,
|
||||
VertexConsumerProvider.Immediate immediate)
|
||||
{
|
||||
if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS)
|
||||
return;
|
||||
BlockHitResult result = LambdaInput.tryFrontPlace(client);
|
||||
if (result == null)
|
||||
return;
|
||||
BlockPos blockPos = result.getBlockPos();
|
||||
if (this.world.getWorldBorder().contains(blockPos)) {
|
||||
ItemStack stack = this.client.player.getStackInHand(Hand.MAIN_HAND);
|
||||
if (stack == null || !(stack.getItem() instanceof BlockItem))
|
||||
return;
|
||||
Block block = ((BlockItem) stack.getItem()).getBlock();
|
||||
result = LambdaInput.withSideForFrontPlace(result, block);
|
||||
ItemPlacementContext context = new ItemPlacementContext(new ItemUsageContext(this.client.player, Hand.MAIN_HAND, result));
|
||||
VertexConsumer vertexConsumer = immediate.getBuffer(RenderLayer.getLines());
|
||||
BlockState placementState = block.getPlacementState(context);
|
||||
if (placementState == null)
|
||||
return;
|
||||
VoxelShape outlineShape = placementState.getOutlineShape(this.client.world, blockPos, EntityContext.of(camera.getFocusedEntity()));
|
||||
drawShapeOutline(matrices, vertexConsumer, outlineShape, (double) blockPos.getX() - x, (double) blockPos.getY() - y, (double) blockPos.getZ() - z, 0.0F, 0.0F, 0.0F, 0.4F);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
"KeyBindingMixin",
|
||||
"MinecraftClientMixin",
|
||||
"MouseMixin",
|
||||
"SettingsScreenMixin"
|
||||
"RecipeBookWidgetAccessor",
|
||||
"SettingsScreenMixin",
|
||||
"WorldRendererMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
||||
Reference in New Issue
Block a user