[Feature] Support for Debug Items
This commit is contained in:
parent
a34a15620a
commit
fb5f0a933c
6 changed files with 398 additions and 1 deletions
|
@ -36,6 +36,7 @@ import net.minecraft.network.chat.Style;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.*;
|
||||
import net.minecraft.world.level.block.entity.*;
|
||||
|
@ -603,6 +604,31 @@ public class PlaceCommand {
|
|||
return bb;
|
||||
}
|
||||
|
||||
public static BlockState setJigsawOrientation(
|
||||
boolean rollable,
|
||||
Player player,
|
||||
BlockPos pos,
|
||||
BlockState state
|
||||
) {
|
||||
final int deltaY = player.getBlockY() - pos.getY();
|
||||
if (deltaY < 2 && deltaY > -2 && rollable) {
|
||||
state = state.setValue(
|
||||
JigsawBlock.ORIENTATION,
|
||||
FrontAndTop.fromFrontAndTop(player.getDirection().getOpposite(), Direction.UP)
|
||||
);
|
||||
} else if (deltaY < 0) {
|
||||
state = state.setValue(
|
||||
JigsawBlock.ORIENTATION,
|
||||
FrontAndTop.fromFrontAndTop(Direction.DOWN, player.getDirection().getOpposite())
|
||||
);
|
||||
} else {
|
||||
state = state.setValue(
|
||||
JigsawBlock.ORIENTATION,
|
||||
FrontAndTop.fromFrontAndTop(Direction.UP, player.getDirection().getOpposite())
|
||||
);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -17,7 +17,7 @@ import java.util.concurrent.CompletableFuture;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConnectorArgument extends ResourceLocationArgument {
|
||||
private static final Collection<String> EXAMPLES = Arrays.asList("-:entrance", "-:decoration", "-:street");
|
||||
private static final Collection<String> EXAMPLES = Arrays.asList("-:building_entrance", "-:bottom", "-:street");
|
||||
|
||||
@Override
|
||||
public Collection<String> getExamples() {
|
||||
|
|
284
src/main/java/org/betterx/bclib/items/DebugDataItem.java
Normal file
284
src/main/java/org/betterx/bclib/items/DebugDataItem.java
Normal file
|
@ -0,0 +1,284 @@
|
|||
package org.betterx.bclib.items;
|
||||
|
||||
import org.betterx.bclib.client.models.ModelsHelper;
|
||||
import org.betterx.bclib.commands.PlaceCommand;
|
||||
import org.betterx.bclib.interfaces.ItemModelProvider;
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
import org.betterx.ui.ColorUtil;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.FrontAndTop;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.data.worldgen.Pools;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
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.Item;
|
||||
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.Blocks;
|
||||
import net.minecraft.world.level.block.JigsawBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.JigsawBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
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.Environment;
|
||||
|
||||
public class DebugDataItem extends Item implements ItemModelProvider {
|
||||
|
||||
public static final ResourceLocation DEFAULT_ICON = new ResourceLocation("stick");
|
||||
|
||||
interface DebugInteraction {
|
||||
InteractionResult use(UseOnContext useOnContext);
|
||||
}
|
||||
|
||||
interface DebugEntityInteraction extends DebugInteraction {
|
||||
@Override
|
||||
default InteractionResult use(UseOnContext useOnContext) {
|
||||
var entity = useOnContext.getLevel().getBlockEntity(useOnContext.getClickedPos());
|
||||
if (entity != null) {
|
||||
return use(useOnContext.getPlayer(), entity, useOnContext);
|
||||
}
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
InteractionResult use(Player player, BlockEntity entity, UseOnContext useOnContext);
|
||||
}
|
||||
|
||||
protected final DebugInteraction interaction;
|
||||
protected final ResourceLocation icon;
|
||||
public final boolean placeInAir;
|
||||
|
||||
public DebugDataItem(DebugEntityInteraction interaction, boolean placeInAir, ResourceLocation icon) {
|
||||
this((DebugInteraction) interaction, placeInAir, icon);
|
||||
}
|
||||
|
||||
public DebugDataItem(DebugInteraction interaction, boolean placeInAir, ResourceLocation icon) {
|
||||
super(new Item.Properties().fireResistant().stacksTo(1));
|
||||
|
||||
this.interaction = interaction;
|
||||
this.icon = (icon == null ? DEFAULT_ICON : icon);
|
||||
this.placeInAir = placeInAir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFoil(ItemStack itemStack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||
return ModelsHelper.createItemModel(icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext useOnContext) {
|
||||
if (!useOnContext.getPlayer().canUseGameMasterBlocks()) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
return interaction.use(useOnContext);
|
||||
}
|
||||
|
||||
public static void message(Player player, String text) {
|
||||
message(player, text, ColorUtil.GRAY);
|
||||
}
|
||||
|
||||
public static void message(Player player, String text, int color) {
|
||||
message(player, Component.literal(text).withStyle(Style.EMPTY.withColor(color)));
|
||||
}
|
||||
|
||||
public static void message(Player player, Component component) {
|
||||
if (player instanceof ServerPlayer sp) {
|
||||
sp.sendSystemMessage(component, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttackBlock(BlockState blockState, Level level, BlockPos blockPos, Player player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionHand) {
|
||||
if (placeInAir) {
|
||||
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(6.0)),
|
||||
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) {
|
||||
ResourceLocation iconId = BuiltInRegistries.ITEM.getKey(icon);
|
||||
return new DebugDataItem(
|
||||
(player, entity, ctx) -> {
|
||||
CompoundTag tag = entity.saveWithoutMetadata();
|
||||
tag.remove(RandomizableContainerBlockEntity.LOOT_TABLE_SEED_TAG);
|
||||
tag.remove("Items");
|
||||
|
||||
tag.putString(RandomizableContainerBlockEntity.LOOT_TABLE_TAG, table.toString());
|
||||
|
||||
entity.load(tag);
|
||||
message(player, "Did set Loot Table to " + table.toString());
|
||||
return InteractionResult.SUCCESS;
|
||||
},
|
||||
false,
|
||||
iconId
|
||||
);
|
||||
}
|
||||
|
||||
public static DebugDataItem forSteetJigSaw(
|
||||
String modID,
|
||||
ResourceKey<StructureTemplatePool> pool,
|
||||
Item icon
|
||||
) {
|
||||
return forJigsaw(
|
||||
pool == null ? Pools.EMPTY : pool,
|
||||
new ResourceLocation(modID, "street"),
|
||||
JigsawBlockEntity.JointType.ALIGNED,
|
||||
null,
|
||||
null,
|
||||
icon
|
||||
);
|
||||
}
|
||||
|
||||
public static DebugDataItem forHouseEntranceJigSaw(
|
||||
String modID,
|
||||
ResourceKey<StructureTemplatePool> pool,
|
||||
Item icon
|
||||
) {
|
||||
return forJigsaw(
|
||||
pool == null ? Pools.EMPTY : pool,
|
||||
new ResourceLocation(modID, "building_entrance"),
|
||||
JigsawBlockEntity.JointType.ALIGNED,
|
||||
null,
|
||||
null,
|
||||
icon
|
||||
);
|
||||
}
|
||||
|
||||
public static DebugDataItem forDecorationJigSaw(
|
||||
String modID,
|
||||
ResourceKey<StructureTemplatePool> pool,
|
||||
Item icon
|
||||
) {
|
||||
return forJigsaw(
|
||||
pool == null ? Pools.EMPTY : pool,
|
||||
new ResourceLocation(modID, "bottom"),
|
||||
pool == null ? new ResourceLocation("empty") : new ResourceLocation(modID, "bottom"),
|
||||
JigsawBlockEntity.JointType.ROLLABLE,
|
||||
null,
|
||||
pool == null ? FrontAndTop.NORTH_UP : null,
|
||||
icon
|
||||
);
|
||||
}
|
||||
|
||||
public static DebugDataItem forJigsaw(
|
||||
ResourceKey<StructureTemplatePool> pool,
|
||||
ResourceLocation connector,
|
||||
JigsawBlockEntity.JointType type,
|
||||
BlockState finalState,
|
||||
FrontAndTop forceOrientation,
|
||||
Item icon
|
||||
) {
|
||||
return forJigsaw(pool, connector, connector, type, finalState, forceOrientation, icon);
|
||||
}
|
||||
|
||||
public static DebugDataItem forJigsaw(
|
||||
ResourceKey<StructureTemplatePool> pool,
|
||||
ResourceLocation name,
|
||||
ResourceLocation target,
|
||||
JigsawBlockEntity.JointType type,
|
||||
BlockState finalState,
|
||||
FrontAndTop forceOrientation,
|
||||
Item icon
|
||||
) {
|
||||
ResourceLocation iconId = BuiltInRegistries.ITEM.getKey(icon);
|
||||
return new DebugDataItem(
|
||||
(ctx) -> {
|
||||
final var player = ctx.getPlayer();
|
||||
final var level = ctx.getLevel();
|
||||
final var pos = ctx.getClickedPos();
|
||||
var state = level.getBlockState(pos);
|
||||
var entity = level.getBlockEntity(pos);
|
||||
var targetState = finalState;
|
||||
if (!(entity instanceof JigsawBlockEntity)) {
|
||||
if (targetState == null)
|
||||
targetState = state;
|
||||
state = Blocks.JIGSAW.defaultBlockState();
|
||||
level.setBlock(pos, state, BlocksHelper.SET_SILENT);
|
||||
entity = level.getBlockEntity(pos);
|
||||
|
||||
message(player, "Created JigSaw at " + pos.toString());
|
||||
}
|
||||
|
||||
if (entity instanceof JigsawBlockEntity e) {
|
||||
if (forceOrientation == null) {
|
||||
state = PlaceCommand.setJigsawOrientation(
|
||||
JigsawBlockEntity.JointType.ROLLABLE != type,
|
||||
player, pos, state
|
||||
);
|
||||
} else {
|
||||
state = state.setValue(JigsawBlock.ORIENTATION, forceOrientation);
|
||||
}
|
||||
level.setBlock(pos, state, BlocksHelper.SET_SILENT);
|
||||
|
||||
if (pool != null) e.setName(name);
|
||||
if (pool != null) e.setTarget(target);
|
||||
if (pool != null) e.setPool(pool);
|
||||
if (targetState != null) e.setFinalState(BlockStateParser.serialize(targetState));
|
||||
e.setJoint(type);
|
||||
|
||||
|
||||
message(player, "Did update Jigsaw at " + pos.toString());
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
return InteractionResult.FAIL;
|
||||
},
|
||||
true,
|
||||
iconId
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package org.betterx.bclib.mixin.client;
|
||||
|
||||
import org.betterx.bclib.BCLib;
|
||||
import org.betterx.bclib.items.DebugDataItem;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
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;
|
||||
|
||||
@Mixin(LevelRenderer.class)
|
||||
public abstract class LevelRendererMixin {
|
||||
@Final
|
||||
@Shadow
|
||||
private Minecraft minecraft;
|
||||
@Shadow
|
||||
@Final
|
||||
private RenderBuffers renderBuffers;
|
||||
|
||||
@Shadow
|
||||
protected static void renderShape(
|
||||
PoseStack poseStack,
|
||||
VertexConsumer vertexConsumer,
|
||||
VoxelShape voxelShape,
|
||||
double d,
|
||||
double e,
|
||||
double f,
|
||||
float g,
|
||||
float h,
|
||||
float i,
|
||||
float j
|
||||
) {
|
||||
}
|
||||
|
||||
@Inject(method = "renderLevel", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lcom/mojang/blaze3d/systems/RenderSystem;getModelViewStack()Lcom/mojang/blaze3d/vertex/PoseStack;",
|
||||
shift = At.Shift.BEFORE
|
||||
))
|
||||
public void bcl_renderLevel(
|
||||
PoseStack poseStack,
|
||||
float f,
|
||||
long l,
|
||||
boolean bl,
|
||||
Camera camera,
|
||||
GameRenderer gameRenderer,
|
||||
LightTexture lightTexture,
|
||||
Matrix4f matrix4f,
|
||||
CallbackInfo info
|
||||
) {
|
||||
if (BCLib.isDevEnvironment() && minecraft.hitResult instanceof BlockHitResult blockHitResult) {
|
||||
//will render a block outline when empty blocks are targeted
|
||||
ItemStack item = minecraft.player.getMainHandItem();
|
||||
if (item != null && (item.getItem() instanceof DebugDataItem ddi) && ddi.placeInAir) {
|
||||
final var pos = blockHitResult.getBlockPos();
|
||||
final var state = Blocks.DIRT.defaultBlockState();
|
||||
MultiBufferSource.BufferSource bufferSource = this.renderBuffers.bufferSource();
|
||||
VertexConsumer consumer = bufferSource.getBuffer(RenderType.lines());
|
||||
Vec3 camPos = camera.getPosition();
|
||||
|
||||
this.renderShape(
|
||||
poseStack, consumer,
|
||||
state.getShape(minecraft.level, pos, CollisionContext.of(camera.getEntity())),
|
||||
pos.getX() - camPos.x(), pos.getY() - camPos.y(), pos.getZ() - camPos.z(),
|
||||
246.0f / 0xff, 250.0f / 0xff, 112.0f / 0xff, 0.75F
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ accessible method net/minecraft/world/level/block/Blocks ocelotOrParrot (Lnet/mi
|
|||
accessible method net/minecraft/world/level/block/Blocks never (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
|
||||
accessible method net/minecraft/world/level/block/Blocks never (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z
|
||||
accessible method net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement <init> (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;)V
|
||||
accessible method net/minecraft/world/level/levelgen/structure/pools/LegacySinglePoolElement <init> (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;)V
|
||||
|
||||
#Fields
|
||||
accessible field net/minecraft/world/entity/ai/village/poi/PoiTypes TYPE_BY_STATE Ljava/util/Map;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"ClientPacketListenerMixin",
|
||||
"ClientRecipeBookMixin",
|
||||
"FogRendererMixin",
|
||||
"LevelRendererMixin",
|
||||
"MinecraftMixin",
|
||||
"ModelManagerMixin",
|
||||
"PresetEditorMixin",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue