Add new recipe book controls and front block outline.

This commit is contained in:
LambdAurora
2020-02-16 00:46:03 +01:00
parent 40dc8d424c
commit 581757aaee
6 changed files with 204 additions and 8 deletions

View File

@@ -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;
}
}

View File

@@ -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());

View File

@@ -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()) {

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -16,7 +16,9 @@
"KeyBindingMixin",
"MinecraftClientMixin",
"MouseMixin",
"SettingsScreenMixin"
"RecipeBookWidgetAccessor",
"SettingsScreenMixin",
"WorldRendererMixin"
],
"injectors": {
"defaultRequire": 1