[Feature] AirSelectionItem
allows Items to highlight/use air blocks
This commit is contained in:
parent
296696d23b
commit
75ccdf38d5
3 changed files with 89 additions and 41 deletions
|
@ -0,0 +1,60 @@
|
||||||
|
package org.betterx.bclib.interfaces;
|
||||||
|
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.context.UseOnContext;
|
||||||
|
import net.minecraft.world.level.ClipBlockStateContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public interface AirSelectionItem {
|
||||||
|
default boolean renderAirSelection() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default int airSelectionColor() {
|
||||||
|
return 0xBFF6FA70;
|
||||||
|
}
|
||||||
|
|
||||||
|
default BlockHitResult getAirSelectionHit(Level level, Player player) {
|
||||||
|
if (renderAirSelection()) {
|
||||||
|
final var vec = new Vec3(0, 0, 1)
|
||||||
|
.xRot(-player.getXRot() * Mth.DEG_TO_RAD)
|
||||||
|
.yRot(-player.getYHeadRot() * Mth.DEG_TO_RAD);
|
||||||
|
|
||||||
|
return level.isBlockInLine(new ClipBlockStateContext(
|
||||||
|
player.getEyePosition(),
|
||||||
|
player.getEyePosition().add(vec.scale(4.9)),
|
||||||
|
BlockBehaviour.BlockStateBase::isAir
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default InteractionResultHolder<ItemStack> useOnAir(Level level, Player player, InteractionHand interactionHand) {
|
||||||
|
final BlockHitResult hit = getAirSelectionHit(level, player);
|
||||||
|
|
||||||
|
if (hit != null) {
|
||||||
|
var result = this.useOn(new UseOnContext(player, interactionHand, hit));
|
||||||
|
|
||||||
|
if (result == InteractionResult.SUCCESS)
|
||||||
|
return InteractionResultHolder.success(player.getItemInHand(interactionHand));
|
||||||
|
else if (result == InteractionResult.FAIL)
|
||||||
|
return InteractionResultHolder.fail(player.getItemInHand(interactionHand));
|
||||||
|
else if (result == InteractionResult.PASS)
|
||||||
|
return InteractionResultHolder.pass(player.getItemInHand(interactionHand));
|
||||||
|
else if (result == InteractionResult.CONSUME)
|
||||||
|
return InteractionResultHolder.consume(player.getItemInHand(interactionHand));
|
||||||
|
}
|
||||||
|
|
||||||
|
return InteractionResultHolder.pass(player.getItemInHand(interactionHand));
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractionResult useOn(UseOnContext useOnContext);
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package org.betterx.bclib.items;
|
||||||
import de.ambertation.wunderlib.math.Bounds;
|
import de.ambertation.wunderlib.math.Bounds;
|
||||||
import org.betterx.bclib.client.models.ModelsHelper;
|
import org.betterx.bclib.client.models.ModelsHelper;
|
||||||
import org.betterx.bclib.commands.PlaceCommand;
|
import org.betterx.bclib.commands.PlaceCommand;
|
||||||
|
import org.betterx.bclib.interfaces.AirSelectionItem;
|
||||||
import org.betterx.bclib.interfaces.ItemModelProvider;
|
import org.betterx.bclib.interfaces.ItemModelProvider;
|
||||||
import org.betterx.bclib.util.BlocksHelper;
|
import org.betterx.bclib.util.BlocksHelper;
|
||||||
import org.betterx.ui.ColorUtil;
|
import org.betterx.ui.ColorUtil;
|
||||||
|
@ -20,7 +21,6 @@ import net.minecraft.network.chat.Style;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.util.Mth;
|
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.InteractionResultHolder;
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
|
@ -28,7 +28,6 @@ import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.context.UseOnContext;
|
import net.minecraft.world.item.context.UseOnContext;
|
||||||
import net.minecraft.world.level.ClipBlockStateContext;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.JigsawBlock;
|
import net.minecraft.world.level.block.JigsawBlock;
|
||||||
|
@ -36,11 +35,8 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.JigsawBlockEntity;
|
import net.minecraft.world.level.block.entity.JigsawBlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
|
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool;
|
import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
|
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
|
@ -48,7 +44,7 @@ import net.fabricmc.api.Environment;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class DebugDataItem extends Item implements ItemModelProvider {
|
public class DebugDataItem extends Item implements ItemModelProvider, AirSelectionItem {
|
||||||
|
|
||||||
public static final ResourceLocation DEFAULT_ICON = new ResourceLocation("stick");
|
public static final ResourceLocation DEFAULT_ICON = new ResourceLocation("stick");
|
||||||
|
|
||||||
|
@ -134,7 +130,7 @@ public class DebugDataItem extends Item implements ItemModelProvider {
|
||||||
|
|
||||||
if (predicate.test(level.getBlockState(pos))) {
|
if (predicate.test(level.getBlockState(pos))) {
|
||||||
level.setBlock(pos, newState, BlocksHelper.SET_SILENT);
|
level.setBlock(pos, newState, BlocksHelper.SET_SILENT);
|
||||||
|
|
||||||
floodFillStructureEntityBounds(level, bounds, pos.above(), entity, predicate, newState, visited);
|
floodFillStructureEntityBounds(level, bounds, pos.above(), entity, predicate, newState, visited);
|
||||||
floodFillStructureEntityBounds(level, bounds, pos.below(), entity, predicate, newState, visited);
|
floodFillStructureEntityBounds(level, bounds, pos.below(), entity, predicate, newState, visited);
|
||||||
floodFillStructureEntityBounds(level, bounds, pos.north(), entity, predicate, newState, visited);
|
floodFillStructureEntityBounds(level, bounds, pos.north(), entity, predicate, newState, visited);
|
||||||
|
@ -177,6 +173,11 @@ public class DebugDataItem extends Item implements ItemModelProvider {
|
||||||
this.placeInAir = placeInAir;
|
this.placeInAir = placeInAir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean renderAirSelection() {
|
||||||
|
return placeInAir;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFoil(ItemStack itemStack) {
|
public boolean isFoil(ItemStack itemStack) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -218,32 +219,7 @@ public class DebugDataItem extends Item implements ItemModelProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionHand) {
|
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionHand) {
|
||||||
if (placeInAir) {
|
return AirSelectionItem.super.useOnAir(level, player, interactionHand);
|
||||||
final var vec = new Vec3(0, 0, 1)
|
|
||||||
.xRot(-player.getXRot() * Mth.DEG_TO_RAD)
|
|
||||||
.yRot(-player.getYHeadRot() * Mth.DEG_TO_RAD);
|
|
||||||
|
|
||||||
BlockHitResult hit = level.isBlockInLine(new ClipBlockStateContext(
|
|
||||||
player.getEyePosition(),
|
|
||||||
player.getEyePosition().add(vec.scale(4.9)),
|
|
||||||
BlockBehaviour.BlockStateBase::isAir
|
|
||||||
));
|
|
||||||
|
|
||||||
if (hit != null) {
|
|
||||||
var result = this.useOn(new UseOnContext(player, interactionHand, hit));
|
|
||||||
|
|
||||||
if (result == InteractionResult.SUCCESS)
|
|
||||||
return InteractionResultHolder.success(player.getItemInHand(interactionHand));
|
|
||||||
else if (result == InteractionResult.FAIL)
|
|
||||||
return InteractionResultHolder.fail(player.getItemInHand(interactionHand));
|
|
||||||
else if (result == InteractionResult.PASS)
|
|
||||||
return InteractionResultHolder.pass(player.getItemInHand(interactionHand));
|
|
||||||
else if (result == InteractionResult.CONSUME)
|
|
||||||
return InteractionResultHolder.consume(player.getItemInHand(interactionHand));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return InteractionResultHolder.pass(player.getItemInHand(interactionHand));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DebugDataItem forLootTable(ResourceLocation table, Item icon) {
|
public static DebugDataItem forLootTable(ResourceLocation table, Item icon) {
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
package org.betterx.bclib.mixin.client;
|
package org.betterx.bclib.mixin.client;
|
||||||
|
|
||||||
import org.betterx.bclib.BCLib;
|
import org.betterx.bclib.BCLib;
|
||||||
import org.betterx.bclib.items.DebugDataItem;
|
import org.betterx.bclib.interfaces.AirSelectionItem;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.*;
|
import net.minecraft.client.renderer.*;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.util.FastColor;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
@ -66,18 +70,26 @@ public abstract class LevelRendererMixin {
|
||||||
if (BCLib.isDevEnvironment() && minecraft.hitResult instanceof BlockHitResult blockHitResult) {
|
if (BCLib.isDevEnvironment() && minecraft.hitResult instanceof BlockHitResult blockHitResult) {
|
||||||
//will render a block outline when empty blocks are targeted
|
//will render a block outline when empty blocks are targeted
|
||||||
ItemStack item = minecraft.player.getMainHandItem();
|
ItemStack item = minecraft.player.getMainHandItem();
|
||||||
if (item != null && (item.getItem() instanceof DebugDataItem ddi) && ddi.placeInAir) {
|
if (item != null
|
||||||
final var pos = blockHitResult.getBlockPos();
|
&& (item.getItem() instanceof AirSelectionItem airSelect)
|
||||||
final var state = Blocks.DIRT.defaultBlockState();
|
&& airSelect.renderAirSelection()
|
||||||
MultiBufferSource.BufferSource bufferSource = this.renderBuffers.bufferSource();
|
&& blockHitResult.getType() == HitResult.Type.MISS
|
||||||
VertexConsumer consumer = bufferSource.getBuffer(RenderType.lines());
|
) {
|
||||||
Vec3 camPos = camera.getPosition();
|
final BlockPos pos = blockHitResult.getBlockPos();
|
||||||
|
final BlockState state = Blocks.DIRT.defaultBlockState();
|
||||||
|
final int color = airSelect.airSelectionColor();
|
||||||
|
final MultiBufferSource.BufferSource bufferSource = this.renderBuffers.bufferSource();
|
||||||
|
final VertexConsumer consumer = bufferSource.getBuffer(RenderType.lines());
|
||||||
|
final Vec3 camPos = camera.getPosition();
|
||||||
|
|
||||||
this.renderShape(
|
this.renderShape(
|
||||||
poseStack, consumer,
|
poseStack, consumer,
|
||||||
state.getShape(minecraft.level, pos, CollisionContext.of(camera.getEntity())),
|
state.getShape(minecraft.level, pos, CollisionContext.of(camera.getEntity())),
|
||||||
pos.getX() - camPos.x(), pos.getY() - camPos.y(), pos.getZ() - camPos.z(),
|
pos.getX() - camPos.x(), pos.getY() - camPos.y(), pos.getZ() - camPos.z(),
|
||||||
246.0f / 0xff, 250.0f / 0xff, 112.0f / 0xff, 0.75F
|
FastColor.ARGB32.red(color) / (float) 0xff,
|
||||||
|
FastColor.ARGB32.green(color) / (float) 0xff,
|
||||||
|
FastColor.ARGB32.blue(color) / (float) 0xff,
|
||||||
|
FastColor.ARGB32.alpha(color) / (float) 0xff
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue