mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-15 21:03:41 +01:00
Assisted Placement, Part IV
- added 👻-blocks as a placement preview
This commit is contained in:
parent
34de9a0319
commit
b9d1a586c1
18 changed files with 668 additions and 76 deletions
|
@ -1,10 +1,5 @@
|
||||||
package com.simibubi.create;
|
package com.simibubi.create;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
|
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer;
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer;
|
||||||
import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity;
|
import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity;
|
||||||
|
@ -17,8 +12,8 @@ import com.simibubi.create.foundation.block.render.SpriteShifter;
|
||||||
import com.simibubi.create.foundation.item.CustomItemModels;
|
import com.simibubi.create.foundation.item.CustomItemModels;
|
||||||
import com.simibubi.create.foundation.item.CustomRenderedItems;
|
import com.simibubi.create.foundation.item.CustomRenderedItems;
|
||||||
import com.simibubi.create.foundation.utility.SuperByteBufferCache;
|
import com.simibubi.create.foundation.utility.SuperByteBufferCache;
|
||||||
|
import com.simibubi.create.foundation.utility.ghost.GhostBlocks;
|
||||||
import com.simibubi.create.foundation.utility.outliner.Outliner;
|
import com.simibubi.create.foundation.utility.outliner.Outliner;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.BlockModelShapes;
|
import net.minecraft.client.renderer.BlockModelShapes;
|
||||||
|
@ -36,6 +31,11 @@ import net.minecraftforge.client.model.ModelLoader;
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class CreateClient {
|
public class CreateClient {
|
||||||
|
|
||||||
public static ClientSchematicLoader schematicSender;
|
public static ClientSchematicLoader schematicSender;
|
||||||
|
@ -43,6 +43,7 @@ public class CreateClient {
|
||||||
public static SchematicAndQuillHandler schematicAndQuillHandler;
|
public static SchematicAndQuillHandler schematicAndQuillHandler;
|
||||||
public static SuperByteBufferCache bufferCache;
|
public static SuperByteBufferCache bufferCache;
|
||||||
public static final Outliner outliner = new Outliner();
|
public static final Outliner outliner = new Outliner();
|
||||||
|
public static GhostBlocks ghostBlocks;
|
||||||
|
|
||||||
private static CustomBlockModels customBlockModels;
|
private static CustomBlockModels customBlockModels;
|
||||||
private static CustomItemModels customItemModels;
|
private static CustomItemModels customItemModels;
|
||||||
|
@ -67,6 +68,8 @@ public class CreateClient {
|
||||||
bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
|
bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
|
||||||
bufferCache.registerCompartment(ContraptionRenderer.CONTRAPTION, 20);
|
bufferCache.registerCompartment(ContraptionRenderer.CONTRAPTION, 20);
|
||||||
|
|
||||||
|
ghostBlocks = new GhostBlocks();
|
||||||
|
|
||||||
AllKeys.register();
|
AllKeys.register();
|
||||||
AllContainerTypes.registerScreenFactories();
|
AllContainerTypes.registerScreenFactories();
|
||||||
//AllTileEntities.registerRenderers();
|
//AllTileEntities.registerRenderers();
|
||||||
|
|
|
@ -5,7 +5,6 @@ import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
||||||
import com.simibubi.create.foundation.utility.DyeHelper;
|
import com.simibubi.create.foundation.utility.DyeHelper;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||||
|
@ -216,7 +215,8 @@ public class SailBlock extends ProperDirectionalBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), state.get(FACING));
|
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), state.get(FACING));
|
||||||
|
displayGhost(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,7 +279,6 @@ public class GantryShaftBlock extends DirectionalKineticBlock {
|
||||||
return PlacementOffset.success(offset.getPos(), offset.getTransform()
|
return PlacementOffset.success(offset.getPos(), offset.getTransform()
|
||||||
.andThen(s -> s.with(POWERED, state.get(POWERED))));
|
.andThen(s -> s.with(POWERED, state.get(POWERED))));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock;
|
||||||
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
|
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
|
||||||
import com.simibubi.create.content.contraptions.relays.elementary.CogwheelBlockItem;
|
import com.simibubi.create.content.contraptions.relays.elementary.CogwheelBlockItem;
|
||||||
import com.simibubi.create.foundation.block.ITE;
|
import com.simibubi.create.foundation.block.ITE;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||||
|
@ -20,7 +19,6 @@ import net.minecraft.item.BlockItemUseContext;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.ActionResultType;
|
import net.minecraft.util.ActionResultType;
|
||||||
import net.minecraft.util.Direction;
|
|
||||||
import net.minecraft.util.Direction.Axis;
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -111,9 +109,11 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE,
|
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE,
|
||||||
state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X));
|
// state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X));
|
||||||
|
|
||||||
|
displayGhost(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock;
|
||||||
import com.simibubi.create.content.contraptions.base.IRotate;
|
import com.simibubi.create.content.contraptions.base.IRotate;
|
||||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||||
|
@ -150,9 +149,11 @@ public class CogwheelBlockItem extends BlockItem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)),
|
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)),
|
||||||
((CogWheelBlock) state.getBlock()).isLarge ? 1.5D : 0.75D);
|
// ((CogWheelBlock) state.getBlock()).isLarge ? 1.5D : 0.75D);
|
||||||
|
|
||||||
|
displayGhost(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,8 +228,10 @@ public class CogwheelBlockItem extends BlockItem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)), 1D);
|
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)), 1D);
|
||||||
|
|
||||||
|
displayGhost(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hitOnShaft(BlockState state, BlockRayTraceResult ray) {
|
protected boolean hitOnShaft(BlockState state, BlockRayTraceResult ray) {
|
||||||
|
@ -320,10 +323,12 @@ public class CogwheelBlockItem extends BlockItem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, offset.getTransform()
|
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, offset.getTransform()
|
||||||
.apply(AllBlocks.LARGE_COGWHEEL.getDefaultState())
|
// .apply(AllBlocks.LARGE_COGWHEEL.getDefaultState())
|
||||||
.get(AXIS)));
|
// .get(AXIS)));
|
||||||
|
|
||||||
|
displayGhost(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ public class ClientEvents {
|
||||||
ArmInteractionPointHandler.tick();
|
ArmInteractionPointHandler.tick();
|
||||||
PlacementHelpers.tick();
|
PlacementHelpers.tick();
|
||||||
CreateClient.outliner.tickOutlines();
|
CreateClient.outliner.tickOutlines();
|
||||||
|
CreateClient.ghostBlocks.tickGhosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
@ -122,6 +123,8 @@ public class ClientEvents {
|
||||||
|
|
||||||
CouplingRenderer.renderAll(ms, buffer);
|
CouplingRenderer.renderAll(ms, buffer);
|
||||||
CreateClient.schematicHandler.render(ms, buffer);
|
CreateClient.schematicHandler.render(ms, buffer);
|
||||||
|
CreateClient.ghostBlocks.renderAll(ms, buffer);
|
||||||
|
|
||||||
CreateClient.outliner.renderOutlines(ms, buffer);
|
CreateClient.outliner.renderOutlines(ms, buffer);
|
||||||
// CollisionDebugger.render(ms, buffer);
|
// CollisionDebugger.render(ms, buffer);
|
||||||
buffer.draw();
|
buffer.draw();
|
||||||
|
|
|
@ -24,19 +24,7 @@ public class HighlightCommand {
|
||||||
public static ArgumentBuilder<CommandSource, ?> register() {
|
public static ArgumentBuilder<CommandSource, ?> register() {
|
||||||
return Commands.literal("highlight")
|
return Commands.literal("highlight")
|
||||||
.requires(cs -> cs.hasPermissionLevel(0))
|
.requires(cs -> cs.hasPermissionLevel(0))
|
||||||
.requires(AllCommands.sourceIsPlayer)
|
|
||||||
.then(Commands.argument("pos", BlockPosArgument.blockPos())
|
.then(Commands.argument("pos", BlockPosArgument.blockPos())
|
||||||
.requires(AllCommands.sourceIsPlayer)
|
|
||||||
.executes(ctx -> {
|
|
||||||
BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, "pos");
|
|
||||||
|
|
||||||
AllPackets.channel.send(
|
|
||||||
PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()),
|
|
||||||
new HighlightPacket(pos)
|
|
||||||
);
|
|
||||||
|
|
||||||
return Command.SINGLE_SUCCESS;
|
|
||||||
})
|
|
||||||
.then(Commands.argument("players", EntityArgument.players())
|
.then(Commands.argument("players", EntityArgument.players())
|
||||||
.executes(ctx -> {
|
.executes(ctx -> {
|
||||||
Collection<ServerPlayerEntity> players = EntityArgument.getPlayers(ctx, "players");
|
Collection<ServerPlayerEntity> players = EntityArgument.getPlayers(ctx, "players");
|
||||||
|
@ -52,7 +40,19 @@ public class HighlightCommand {
|
||||||
return players.size();
|
return players.size();
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
//.requires(AllCommands.sourceIsPlayer)
|
||||||
|
.executes(ctx -> {
|
||||||
|
BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, "pos");
|
||||||
|
|
||||||
|
AllPackets.channel.send(
|
||||||
|
PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()),
|
||||||
|
new HighlightPacket(pos)
|
||||||
|
);
|
||||||
|
|
||||||
|
return Command.SINGLE_SUCCESS;
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
//.requires(AllCommands.sourceIsPlayer)
|
||||||
.executes(ctx -> {
|
.executes(ctx -> {
|
||||||
ServerPlayerEntity player = ctx.getSource().asPlayer();
|
ServerPlayerEntity player = ctx.getSource().asPlayer();
|
||||||
return highlightAssemblyExceptionFor(player, ctx.getSource());
|
return highlightAssemblyExceptionFor(player, ctx.getSource());
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package com.simibubi.create.foundation.command;
|
package com.simibubi.create.foundation.command;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command;
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
|
|
||||||
import net.minecraft.command.CommandSource;
|
import net.minecraft.command.CommandSource;
|
||||||
import net.minecraft.command.Commands;
|
import net.minecraft.command.Commands;
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
|
@ -30,7 +30,8 @@ public class ToggleDebugCommand {
|
||||||
|
|
||||||
ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " rainbow debug"), true);
|
ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " rainbow debug"), true);
|
||||||
|
|
||||||
return 1;
|
return Command.SINGLE_SUCCESS;
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ public class CClient extends ConfigBase {
|
||||||
|
|
||||||
public ConfigInt overlayOffsetX = i(20, Integer.MIN_VALUE, Integer.MAX_VALUE, "overlayOffsetX", "Offset the overlay from goggle- and hover- information by this many pixels on the X axis; Use /create overlay");
|
public ConfigInt overlayOffsetX = i(20, Integer.MIN_VALUE, Integer.MAX_VALUE, "overlayOffsetX", "Offset the overlay from goggle- and hover- information by this many pixels on the X axis; Use /create overlay");
|
||||||
public ConfigInt overlayOffsetY = i(0, Integer.MIN_VALUE, Integer.MAX_VALUE, "overlayOffsetY", "Offset the overlay from goggle- and hover- information by this many pixels on the Y axis; Use /create overlay");
|
public ConfigInt overlayOffsetY = i(0, Integer.MIN_VALUE, Integer.MAX_VALUE, "overlayOffsetY", "Offset the overlay from goggle- and hover- information by this many pixels on the Y axis; Use /create overlay");
|
||||||
|
public ConfigBool smoothPlacementIndicator = b(false, "smoothPlacementIndicator", "Use an alternative indicator when showing where the assisted placement ends up relative to your crosshair");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package com.simibubi.create.foundation.utility;
|
package com.simibubi.create.foundation.utility;
|
||||||
|
|
||||||
import java.util.Random;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||||
import javax.annotation.Nullable;
|
import net.minecraft.client.renderer.Quaternion;
|
||||||
|
import net.minecraft.client.renderer.Vector3f;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.nbt.DoubleNBT;
|
import net.minecraft.nbt.DoubleNBT;
|
||||||
import net.minecraft.nbt.ListNBT;
|
import net.minecraft.nbt.ListNBT;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
|
@ -13,6 +15,9 @@ import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.math.Vec3i;
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class VecHelper {
|
public class VecHelper {
|
||||||
|
|
||||||
public static final Vec3d CENTER_OF_ORIGIN = new Vec3d(.5, .5, .5);
|
public static final Vec3d CENTER_OF_ORIGIN = new Vec3d(.5, .5, .5);
|
||||||
|
@ -145,4 +150,52 @@ public class VecHelper {
|
||||||
return origin.add(lineDirection.scale(t));
|
return origin.add(lineDirection.scale(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//https://forums.minecraftforge.net/topic/88562-116solved-3d-to-2d-conversion/?do=findComment&comment=413573 slightly modified
|
||||||
|
public static Vec3d projectToPlayerView(Vec3d target, float partialTicks) {
|
||||||
|
/* The (centered) location on the screen of the given 3d point in the world.
|
||||||
|
* Result is (dist right of center screen, dist up from center screen, if < 0, then in front of view plane) */
|
||||||
|
ActiveRenderInfo ari = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
|
||||||
|
Vec3d camera_pos = ari.getProjectedView();
|
||||||
|
Quaternion camera_rotation_conj = ari.getRotation().copy();
|
||||||
|
camera_rotation_conj.conjugate();
|
||||||
|
|
||||||
|
Vector3f result3f = new Vector3f((float) (camera_pos.x - target.x),
|
||||||
|
(float) (camera_pos.y - target.y),
|
||||||
|
(float) (camera_pos.z - target.z));
|
||||||
|
result3f.func_214905_a(camera_rotation_conj);
|
||||||
|
|
||||||
|
// ----- compensate for view bobbing (if active) -----
|
||||||
|
// the following code adapted from GameRenderer::applyBobbing (to invert it)
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
if (mc.gameSettings.viewBobbing) {
|
||||||
|
Entity renderViewEntity = mc.getRenderViewEntity();
|
||||||
|
if (renderViewEntity instanceof PlayerEntity) {
|
||||||
|
PlayerEntity playerentity = (PlayerEntity) renderViewEntity;
|
||||||
|
float distwalked_modified = playerentity.distanceWalkedModified;
|
||||||
|
|
||||||
|
float f = distwalked_modified - playerentity.prevDistanceWalkedModified;
|
||||||
|
float f1 = -(distwalked_modified + f * partialTicks);
|
||||||
|
float f2 = MathHelper.lerp(partialTicks, playerentity.prevCameraYaw, playerentity.cameraYaw);
|
||||||
|
Quaternion q2 = new Quaternion(Vector3f.POSITIVE_X, Math.abs(MathHelper.cos(f1 * (float) Math.PI - 0.2F) * f2) * 5.0F, true);
|
||||||
|
q2.conjugate();
|
||||||
|
result3f.func_214905_a(q2);
|
||||||
|
|
||||||
|
Quaternion q1 = new Quaternion(Vector3f.POSITIVE_Z, MathHelper.sin(f1 * (float) Math.PI) * f2 * 3.0F, true);
|
||||||
|
q1.conjugate();
|
||||||
|
result3f.func_214905_a(q1);
|
||||||
|
|
||||||
|
Vector3f bob_translation = new Vector3f((MathHelper.sin(f1 * (float) Math.PI) * f2 * 0.5F), (-Math.abs(MathHelper.cos(f1 * (float) Math.PI) * f2)), 0.0f);
|
||||||
|
bob_translation.setY(-bob_translation.getY()); // this is weird but hey, if it works
|
||||||
|
result3f.add(bob_translation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- adjust for fov -----
|
||||||
|
float fov = (float) mc.gameRenderer.getFOVModifier(ari, partialTicks, true);
|
||||||
|
|
||||||
|
float half_height = (float) mc.getWindow().getScaledHeight() / 2;
|
||||||
|
float scale_factor = half_height / (result3f.getZ() * (float) Math.tan(Math.toRadians(fov / 2)));
|
||||||
|
return new Vec3d(-result3f.getX() * scale_factor, result3f.getY() * scale_factor, result3f.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.simibubi.create.foundation.utility.ghost;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class GhostBlockParams {
|
||||||
|
|
||||||
|
protected final BlockState state;
|
||||||
|
protected BlockPos pos;
|
||||||
|
protected Supplier<Float> alphaSupplier;
|
||||||
|
|
||||||
|
private GhostBlockParams(BlockState state) {
|
||||||
|
this.state = state;
|
||||||
|
this.pos = BlockPos.ZERO;
|
||||||
|
this.alphaSupplier = () -> 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GhostBlockParams of(BlockState state) {
|
||||||
|
return new GhostBlockParams(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GhostBlockParams of(Block block) {
|
||||||
|
return of(block.getDefaultState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlockParams at(BlockPos pos) {
|
||||||
|
this.pos = pos;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlockParams at(int x, int y, int z) {
|
||||||
|
return this.at(new BlockPos(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlockParams alpha(Supplier<Float> alphaSupplier) {
|
||||||
|
this.alphaSupplier = alphaSupplier;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlockParams alpha(float alpha) {
|
||||||
|
return this.alpha(() -> alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlockParams breathingAlpha() {
|
||||||
|
return this.alpha(() -> (float) GhostBlocks.getBreathingAlpha());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
package com.simibubi.create.foundation.utility.ghost;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||||
|
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
||||||
|
import com.simibubi.create.foundation.utility.VirtualEmptyModelData;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.*;
|
||||||
|
import net.minecraft.client.renderer.model.BakedQuad;
|
||||||
|
import net.minecraft.client.renderer.model.IBakedModel;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.nio.Buffer;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public abstract class GhostBlockRenderer {
|
||||||
|
|
||||||
|
private static final GhostBlockRenderer transparent = new TransparentGhostBlockRenderer();
|
||||||
|
public static GhostBlockRenderer transparent() {
|
||||||
|
return transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final GhostBlockRenderer standard = new DefaultGhostBlockRenderer();
|
||||||
|
public static GhostBlockRenderer standard() {
|
||||||
|
return standard;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract void render(MatrixStack ms, SuperRenderTypeBuffer buffer, GhostBlockParams params);
|
||||||
|
|
||||||
|
private static class DefaultGhostBlockRenderer extends GhostBlockRenderer {
|
||||||
|
|
||||||
|
public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, GhostBlockParams params) {
|
||||||
|
ms.push();
|
||||||
|
|
||||||
|
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
|
||||||
|
|
||||||
|
IBakedModel model = dispatcher.getModelForState(params.state);
|
||||||
|
|
||||||
|
RenderType layer = RenderTypeLookup.getEntityBlockLayer(params.state);
|
||||||
|
IVertexBuilder vb = buffer.getEarlyBuffer(layer);
|
||||||
|
|
||||||
|
BlockPos pos = params.pos;
|
||||||
|
ms.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
|
||||||
|
dispatcher.getBlockModelRenderer().renderModel(ms.peek(), vb, params.state, model, 1f, 1f, 1f, 0xF000F0, OverlayTexture.DEFAULT_UV, VirtualEmptyModelData.INSTANCE);
|
||||||
|
|
||||||
|
ms.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TransparentGhostBlockRenderer extends GhostBlockRenderer {
|
||||||
|
|
||||||
|
public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, GhostBlockParams params) {
|
||||||
|
|
||||||
|
//prepare
|
||||||
|
ms.push();
|
||||||
|
|
||||||
|
//RenderSystem.pushMatrix();
|
||||||
|
|
||||||
|
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
|
||||||
|
|
||||||
|
IBakedModel model = dispatcher.getModelForState(params.state);
|
||||||
|
|
||||||
|
//RenderType layer = RenderTypeLookup.getEntityBlockLayer(params.state);
|
||||||
|
RenderType layer = RenderType.getTranslucent();
|
||||||
|
IVertexBuilder vb = buffer.getEarlyBuffer(layer);
|
||||||
|
|
||||||
|
BlockPos pos = params.pos;
|
||||||
|
ms.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
|
||||||
|
//dispatcher.getBlockModelRenderer().renderModel(ms.peek(), vb, params.state, model, 1f, 1f, 1f, 0xF000F0, OverlayTexture.DEFAULT_UV, VirtualEmptyModelData.INSTANCE);
|
||||||
|
renderModel(params, ms.peek(), vb, params.state, model, 1f, 1f, 1f, 0xF000F0, OverlayTexture.DEFAULT_UV, VirtualEmptyModelData.INSTANCE);
|
||||||
|
|
||||||
|
//buffer.draw();
|
||||||
|
//clean
|
||||||
|
//RenderSystem.popMatrix();
|
||||||
|
ms.pop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//BlockModelRenderer
|
||||||
|
public void renderModel(GhostBlockParams params, MatrixStack.Entry entry, IVertexBuilder vb, @Nullable BlockState state, IBakedModel model, float p_228804_5_, float p_228804_6_, float p_228804_7_, int p_228804_8_, int p_228804_9_, net.minecraftforge.client.model.data.IModelData modelData) {
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
for (Direction direction : Direction.values()) {
|
||||||
|
random.setSeed(42L);
|
||||||
|
renderQuad(params, entry, vb, p_228804_5_, p_228804_6_, p_228804_7_, model.getQuads(state, direction, random, modelData), p_228804_8_, p_228804_9_);
|
||||||
|
}
|
||||||
|
|
||||||
|
random.setSeed(42L);
|
||||||
|
renderQuad(params, entry, vb, p_228804_5_, p_228804_6_, p_228804_7_, model.getQuads(state, (Direction) null, random, modelData), p_228804_8_, p_228804_9_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//BlockModelRenderer
|
||||||
|
private static void renderQuad(GhostBlockParams params, MatrixStack.Entry p_228803_0_, IVertexBuilder p_228803_1_, float p_228803_2_, float p_228803_3_, float p_228803_4_, List<BakedQuad> p_228803_5_, int p_228803_6_, int p_228803_7_) {
|
||||||
|
Float alpha = params.alphaSupplier.get();
|
||||||
|
|
||||||
|
for (BakedQuad bakedquad : p_228803_5_) {
|
||||||
|
float f;
|
||||||
|
float f1;
|
||||||
|
float f2;
|
||||||
|
if (bakedquad.hasTintIndex()) {
|
||||||
|
f = MathHelper.clamp(p_228803_2_, 0.0F, 1.0F);
|
||||||
|
f1 = MathHelper.clamp(p_228803_3_, 0.0F, 1.0F);
|
||||||
|
f2 = MathHelper.clamp(p_228803_4_, 0.0F, 1.0F);
|
||||||
|
} else {
|
||||||
|
f = 1.0F;
|
||||||
|
f1 = 1.0F;
|
||||||
|
f2 = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
quad(alpha, p_228803_1_, p_228803_0_, bakedquad, new float[]{1f, 1f, 1f, 1f}, f, f1, f2, new int[]{p_228803_6_, p_228803_6_, p_228803_6_, p_228803_6_}, p_228803_7_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//IVertexBuilder
|
||||||
|
static void quad(float alpha, IVertexBuilder vb, MatrixStack.Entry p_227890_1_, BakedQuad p_227890_2_, float[] p_227890_3_, float p_227890_4_, float p_227890_5_, float p_227890_6_, int[] p_227890_7_, int p_227890_8_) {
|
||||||
|
int[] aint = p_227890_2_.getVertexData();
|
||||||
|
Vec3i vec3i = p_227890_2_.getFace().getDirectionVec();
|
||||||
|
Vector3f vector3f = new Vector3f((float) vec3i.getX(), (float) vec3i.getY(), (float) vec3i.getZ());
|
||||||
|
Matrix4f matrix4f = p_227890_1_.getModel();
|
||||||
|
vector3f.transform(p_227890_1_.getNormal());
|
||||||
|
int i = 8;
|
||||||
|
int j = aint.length / 8;
|
||||||
|
|
||||||
|
try (MemoryStack memorystack = MemoryStack.stackPush()) {
|
||||||
|
ByteBuffer bytebuffer = memorystack.malloc(DefaultVertexFormats.BLOCK.getSize());
|
||||||
|
IntBuffer intbuffer = bytebuffer.asIntBuffer();
|
||||||
|
|
||||||
|
for (int k = 0; k < j; ++k) {
|
||||||
|
((Buffer) intbuffer).clear();
|
||||||
|
intbuffer.put(aint, k * 8, 8);
|
||||||
|
float f = bytebuffer.getFloat(0);
|
||||||
|
float f1 = bytebuffer.getFloat(4);
|
||||||
|
float f2 = bytebuffer.getFloat(8);
|
||||||
|
float r;
|
||||||
|
float g;
|
||||||
|
float b;
|
||||||
|
|
||||||
|
r = p_227890_3_[k] * p_227890_4_;
|
||||||
|
g = p_227890_3_[k] * p_227890_5_;
|
||||||
|
b = p_227890_3_[k] * p_227890_6_;
|
||||||
|
|
||||||
|
|
||||||
|
int l = vb.applyBakedLighting(p_227890_7_[k], bytebuffer);
|
||||||
|
float f9 = bytebuffer.getFloat(16);
|
||||||
|
float f10 = bytebuffer.getFloat(20);
|
||||||
|
Vector4f vector4f = new Vector4f(f, f1, f2, 1.0F);
|
||||||
|
vector4f.transform(matrix4f);
|
||||||
|
vb.applyBakedNormals(vector3f, bytebuffer, p_227890_1_.getNormal());
|
||||||
|
vb.vertex(vector4f.getX(), vector4f.getY(), vector4f.getZ(), r, g, b, alpha, f9, f10, p_227890_8_, l, vector3f.getX(), vector3f.getY(), vector3f.getZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package com.simibubi.create.foundation.utility.ghost;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class GhostBlocks {
|
||||||
|
|
||||||
|
public static double getBreathingAlpha() {
|
||||||
|
double period = 2500;
|
||||||
|
double timer = System.currentTimeMillis() % period;
|
||||||
|
double offset = Math.cos((2d/period) * Math.PI * timer);
|
||||||
|
return 0.75d - 0.2d * offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<Object, Entry> ghosts;
|
||||||
|
|
||||||
|
public GhostBlockParams showGhostState(Object slot, BlockState state) {
|
||||||
|
return showGhostState(slot, state, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlockParams showGhostState(Object slot, BlockState state, int ttl) {
|
||||||
|
Entry e = refresh(slot, GhostBlockRenderer.transparent(), GhostBlockParams.of(state), ttl);
|
||||||
|
return e.params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlockParams showGhost(Object slot, GhostBlockRenderer ghost, GhostBlockParams params, int ttl) {
|
||||||
|
Entry e = refresh(slot, ghost, params, ttl);
|
||||||
|
return e.params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Entry refresh(Object slot, GhostBlockRenderer ghost, GhostBlockParams params, int ttl) {
|
||||||
|
if (!ghosts.containsKey(slot))
|
||||||
|
ghosts.put(slot, new Entry(ghost, params, ttl));
|
||||||
|
|
||||||
|
Entry e = ghosts.get(slot);
|
||||||
|
e.ticksToLive = ttl;
|
||||||
|
e.params = params;
|
||||||
|
e.ghost = ghost;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GhostBlocks() {
|
||||||
|
ghosts = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tickGhosts() {
|
||||||
|
ghosts.forEach((slot, entry) -> entry.ticksToLive--);
|
||||||
|
ghosts.entrySet().removeIf(e -> !e.getValue().isAlive());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderAll(MatrixStack ms, SuperRenderTypeBuffer buffer) {
|
||||||
|
ghosts.forEach((slot, entry) -> {
|
||||||
|
GhostBlockRenderer ghost = entry.ghost;
|
||||||
|
ghost.render(ms, buffer, entry.params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Entry {
|
||||||
|
|
||||||
|
private GhostBlockRenderer ghost;
|
||||||
|
private GhostBlockParams params;
|
||||||
|
private int ticksToLive;
|
||||||
|
|
||||||
|
public Entry(GhostBlockRenderer ghost, GhostBlockParams params) {
|
||||||
|
this(ghost, params, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry(GhostBlockRenderer ghost, GhostBlockParams params, int ttl) {
|
||||||
|
this.ghost = ghost;
|
||||||
|
this.params = params;
|
||||||
|
this.ticksToLive = ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAlive() {
|
||||||
|
return ticksToLive >= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
import mcp.MethodsReturnNonnullByDefault;
|
import mcp.MethodsReturnNonnullByDefault;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -46,9 +47,21 @@ public interface IPlacementHelper {
|
||||||
*/
|
*/
|
||||||
PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray);
|
PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray);
|
||||||
|
|
||||||
|
//overrides the default ghost state of the helper with the actual state of the held block item, this is used in PlacementHelpers and can be ignored in most cases
|
||||||
|
default PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray, ItemStack heldItem) {
|
||||||
|
PlacementOffset offset = getOffset(world, state, pos, ray);
|
||||||
|
if (heldItem.getItem() instanceof BlockItem) {
|
||||||
|
BlockItem blockItem = (BlockItem) heldItem.getItem();
|
||||||
|
offset = offset.withGhostState(blockItem.getBlock().getDefaultState());
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
//only gets called when placementOffset is successful
|
//only gets called when placementOffset is successful
|
||||||
default void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
default void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), ray.getFace());
|
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), ray.getFace());
|
||||||
|
|
||||||
|
displayGhost(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renderArrow(Vec3d center, Vec3d target, Direction arrowPlane) {
|
static void renderArrow(Vec3d center, Vec3d target, Direction arrowPlane) {
|
||||||
|
@ -67,6 +80,15 @@ public interface IPlacementHelper {
|
||||||
CreateClient.outliner.showLine("placementArrowB" + center + target, start.add(offset), endB.add(offset)).lineWidth(1/16f);
|
CreateClient.outliner.showLine("placementArrowB" + center + target, start.add(offset), endB.add(offset)).lineWidth(1/16f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void displayGhost(PlacementOffset offset) {
|
||||||
|
if (!offset.hasGhostState())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CreateClient.ghostBlocks.showGhostState(this, offset.getTransform().apply(offset.getGhostState()))
|
||||||
|
.at(offset.getBlockPos())
|
||||||
|
.breathingAlpha();
|
||||||
|
}
|
||||||
|
|
||||||
static List<Direction> orderedByDistanceOnlyAxis(BlockPos pos, Vec3d hit, Direction.Axis axis) {
|
static List<Direction> orderedByDistanceOnlyAxis(BlockPos pos, Vec3d hit, Direction.Axis axis) {
|
||||||
return orderedByDistance(pos, hit, dir -> dir.getAxis() == axis);
|
return orderedByDistance(pos, hit, dir -> dir.getAxis() == axis);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,43 @@
|
||||||
package com.simibubi.create.foundation.utility.placement;
|
package com.simibubi.create.foundation.utility.placement;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
|
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingAngle;
|
||||||
|
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
|
||||||
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.MainWindow;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.BlockRayTraceResult;
|
import net.minecraft.util.math.BlockRayTraceResult;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Mod.EventBusSubscriber
|
||||||
public class PlacementHelpers {
|
public class PlacementHelpers {
|
||||||
|
|
||||||
private static final List<IPlacementHelper> helpers = new ArrayList<>();
|
private static final List<IPlacementHelper> helpers = new ArrayList<>();
|
||||||
|
private static int animationTick = 0;
|
||||||
|
private static final InterpolatedChasingValue angle = new InterpolatedChasingAngle().withSpeed(0.15f);
|
||||||
|
private static BlockPos target = null;
|
||||||
|
private static BlockPos lastTarget = null;
|
||||||
|
|
||||||
public static int register(IPlacementHelper helper) {
|
public static int register(IPlacementHelper helper) {
|
||||||
helpers.add(helper);
|
helpers.add(helper);
|
||||||
|
@ -32,6 +53,23 @@ public class PlacementHelpers {
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public static void tick() {
|
public static void tick() {
|
||||||
|
setTarget(null);
|
||||||
|
checkHelpers();
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
if (animationTick > 0)
|
||||||
|
animationTick = Math.max(animationTick - 2, 0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animationTick < 10)
|
||||||
|
animationTick++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private static void checkHelpers() {
|
||||||
Minecraft mc = Minecraft.getInstance();
|
Minecraft mc = Minecraft.getInstance();
|
||||||
ClientWorld world = mc.world;
|
ClientWorld world = mc.world;
|
||||||
|
|
||||||
|
@ -46,29 +84,154 @@ public class PlacementHelpers {
|
||||||
if (mc.player == null)
|
if (mc.player == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<IPlacementHelper> filteredForHeldItem = helpers.stream().filter(helper -> Arrays.stream(Hand.values()).anyMatch(hand -> helper.getItemPredicate().test(mc.player.getHeldItem(hand)))).collect(Collectors.toList());
|
|
||||||
if (filteredForHeldItem.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mc.player.isSneaking())//for now, disable all helpers when sneaking TODO add helpers that respect sneaking but still show position
|
if (mc.player.isSneaking())//for now, disable all helpers when sneaking TODO add helpers that respect sneaking but still show position
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BlockPos pos = ray.getPos();
|
for (Hand hand : Hand.values()) {
|
||||||
BlockState state = world.getBlockState(pos);
|
|
||||||
|
|
||||||
List<IPlacementHelper> filteredForState = filteredForHeldItem.stream().filter(helper -> helper.getStatePredicate().test(state)).collect(Collectors.toList());
|
ItemStack heldItem = mc.player.getHeldItem(hand);
|
||||||
|
List<IPlacementHelper> filteredForHeldItem = helpers.stream().filter(helper -> helper.matchesItem(heldItem)).collect(Collectors.toList());
|
||||||
|
if (filteredForHeldItem.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (filteredForState.isEmpty())
|
BlockPos pos = ray.getPos();
|
||||||
return;
|
BlockState state = world.getBlockState(pos);
|
||||||
|
|
||||||
for (IPlacementHelper h : filteredForState) {
|
List<IPlacementHelper> filteredForState = filteredForHeldItem.stream().filter(helper -> helper.matchesState(state)).collect(Collectors.toList());
|
||||||
PlacementOffset offset = h.getOffset(world, state, pos, ray);
|
if (filteredForState.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
boolean atLeastOneMatch = false;
|
||||||
|
for (IPlacementHelper h : filteredForState) {
|
||||||
|
PlacementOffset offset = h.getOffset(world, state, pos, ray, heldItem);
|
||||||
|
|
||||||
|
if (offset.isSuccessful()) {
|
||||||
|
h.renderAt(pos, state, ray, offset);
|
||||||
|
setTarget(offset.getBlockPos());
|
||||||
|
atLeastOneMatch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (offset.isSuccessful()) {
|
|
||||||
h.renderAt(pos, state, ray, offset);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//at least one helper activated, no need to check the offhand if we are still in the mainhand
|
||||||
|
if (atLeastOneMatch)
|
||||||
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setTarget(BlockPos target) {
|
||||||
|
PlacementHelpers.target = target;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lastTarget == null) {
|
||||||
|
lastTarget = target;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lastTarget.equals(target))
|
||||||
|
lastTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static void onRender(RenderGameOverlayEvent.Pre event) {
|
||||||
|
if (event.getType() != RenderGameOverlayEvent.ElementType.CROSSHAIRS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
PlayerEntity player = mc.player;
|
||||||
|
|
||||||
|
if (player != null && animationTick > 0) {
|
||||||
|
MainWindow res = event.getWindow();
|
||||||
|
//MatrixStack matrix = event.getMatrix();
|
||||||
|
//String text = "( )";
|
||||||
|
|
||||||
|
//matrix.push();
|
||||||
|
//matrix.translate(res.getScaledWidth() / 2F, res.getScaledHeight() / 2f - 4, 0);
|
||||||
|
float screenY = res.getScaledHeight() / 2f;
|
||||||
|
float screenX = res.getScaledWidth() / 2f;
|
||||||
|
//float y = screenY - 3.5f;
|
||||||
|
//float x = screenX;
|
||||||
|
//x -= mc.fontRenderer.getStringWidth(text)/2f - 0.25f;
|
||||||
|
|
||||||
|
float progress = Math.min(animationTick / 10f/* + event.getPartialTicks()*/, 1f);
|
||||||
|
//int opacity = ((int) (255 * (progress * progress))) << 24;
|
||||||
|
|
||||||
|
//mc.fontRenderer.drawString(text, x, y, 0xFFFFFF | opacity);
|
||||||
|
|
||||||
|
boolean flag = AllConfigs.CLIENT.smoothPlacementIndicator.get();
|
||||||
|
if (flag)
|
||||||
|
drawDirectionIndicator(event.getPartialTicks(), screenX, screenY, progress);
|
||||||
|
|
||||||
|
else {
|
||||||
|
//TODO find something more in style
|
||||||
|
}
|
||||||
|
//matrix.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private static void drawDirectionIndicator(float partialTicks, float centerX, float centerY, float progress) {
|
||||||
|
float r = .8f;
|
||||||
|
float g = .8f;
|
||||||
|
float b = .8f;
|
||||||
|
float a = progress * progress;
|
||||||
|
|
||||||
|
Vec3d projTarget = VecHelper.projectToPlayerView(VecHelper.getCenterOf(lastTarget), partialTicks);
|
||||||
|
|
||||||
|
Vec3d target = new Vec3d(projTarget.x, projTarget.y, 0);
|
||||||
|
Vec3d norm = target.normalize();
|
||||||
|
Vec3d ref = new Vec3d(0, 1, 0);
|
||||||
|
float targetAngle = AngleHelper.deg(Math.acos(norm.dotProduct(ref)));
|
||||||
|
|
||||||
|
if (norm.x > 0) {
|
||||||
|
targetAngle = 360 - targetAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animationTick < 10)
|
||||||
|
angle.set(targetAngle);
|
||||||
|
|
||||||
|
angle.target(targetAngle);
|
||||||
|
angle.tick();
|
||||||
|
|
||||||
|
|
||||||
|
float length = 10;
|
||||||
|
//TOD O if the target is off screen, use length to show a meaningful distance
|
||||||
|
|
||||||
|
RenderSystem.pushMatrix();
|
||||||
|
RenderSystem.disableTexture();
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.disableAlphaTest();
|
||||||
|
RenderSystem.defaultBlendFunc();
|
||||||
|
RenderSystem.shadeModel(GL11.GL_SMOOTH);
|
||||||
|
|
||||||
|
RenderSystem.translated(centerX, centerY, 0);
|
||||||
|
RenderSystem.rotatef(angle.get(0.1f), 0, 0, -1);
|
||||||
|
//RenderSystem.scaled(3, 3, 3);
|
||||||
|
|
||||||
|
Tessellator tessellator = Tessellator.getInstance();
|
||||||
|
BufferBuilder bufferbuilder = tessellator.getBuffer();
|
||||||
|
bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION_COLOR);
|
||||||
|
|
||||||
|
bufferbuilder.vertex(0, - (10 + length), 0).color(r, g, b, a).endVertex();
|
||||||
|
|
||||||
|
bufferbuilder.vertex(-9, -3, 0).color(r, g, b, 0f).endVertex();
|
||||||
|
bufferbuilder.vertex(-6, -6, 0).color(r, g, b, 0f).endVertex();
|
||||||
|
bufferbuilder.vertex(-3, -8, 0).color(r, g, b, 0f).endVertex();
|
||||||
|
bufferbuilder.vertex(0, -8.5, 0).color(r, g, b, 0f).endVertex();
|
||||||
|
bufferbuilder.vertex(3, -8, 0).color(r, g, b, 0f).endVertex();
|
||||||
|
bufferbuilder.vertex(6, -6, 0).color(r, g, b, 0f).endVertex();
|
||||||
|
bufferbuilder.vertex(9, -3, 0).color(r, g, b, 0f).endVertex();
|
||||||
|
|
||||||
|
tessellator.draw();
|
||||||
|
RenderSystem.shadeModel(GL11.GL_FLAT);
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
RenderSystem.enableAlphaTest();
|
||||||
|
RenderSystem.enableTexture();
|
||||||
|
RenderSystem.popMatrix();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,25 +27,46 @@ import java.util.function.Function;
|
||||||
public class PlacementOffset {
|
public class PlacementOffset {
|
||||||
|
|
||||||
private final boolean success;
|
private final boolean success;
|
||||||
private final Vec3i pos;
|
private Vec3i pos;
|
||||||
private final Function<BlockState, BlockState> stateTransform;
|
private Function<BlockState, BlockState> stateTransform;
|
||||||
|
private BlockState ghostState;
|
||||||
|
|
||||||
private PlacementOffset(boolean success, Vec3i pos, Function<BlockState, BlockState> transform) {
|
private PlacementOffset(boolean success) {
|
||||||
this.success = success;
|
this.success = success;
|
||||||
this.pos = pos;
|
this.pos = BlockPos.ZERO;
|
||||||
this.stateTransform = transform == null ? Function.identity() : transform;
|
this.stateTransform = Function.identity();
|
||||||
|
this.ghostState = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlacementOffset fail() {
|
public static PlacementOffset fail() {
|
||||||
return new PlacementOffset(false, Vec3i.NULL_VECTOR, null);
|
return new PlacementOffset(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlacementOffset success() {
|
||||||
|
return new PlacementOffset(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlacementOffset success(Vec3i pos) {
|
public static PlacementOffset success(Vec3i pos) {
|
||||||
return new PlacementOffset(true, pos, null);
|
return success().at(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlacementOffset success(Vec3i pos, Function<BlockState, BlockState> transform) {
|
public static PlacementOffset success(Vec3i pos, Function<BlockState, BlockState> transform) {
|
||||||
return new PlacementOffset(true, pos, transform);
|
return success().at(pos).withTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlacementOffset at(Vec3i pos) {
|
||||||
|
this.pos = pos;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlacementOffset withTransform(Function<BlockState, BlockState> stateTransform) {
|
||||||
|
this.stateTransform = stateTransform;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlacementOffset withGhostState(BlockState ghostState) {
|
||||||
|
this.ghostState = ghostState;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSuccessful() {
|
public boolean isSuccessful() {
|
||||||
|
@ -56,10 +77,25 @@ public class PlacementOffset {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BlockPos getBlockPos() {
|
||||||
|
if (pos instanceof BlockPos)
|
||||||
|
return (BlockPos) pos;
|
||||||
|
|
||||||
|
return new BlockPos(pos);
|
||||||
|
}
|
||||||
|
|
||||||
public Function<BlockState, BlockState> getTransform() {
|
public Function<BlockState, BlockState> getTransform() {
|
||||||
return stateTransform;
|
return stateTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasGhostState() {
|
||||||
|
return ghostState != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockState getGhostState() {
|
||||||
|
return ghostState;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isReplaceable(World world) {
|
public boolean isReplaceable(World world) {
|
||||||
if (!success)
|
if (!success)
|
||||||
return false;
|
return false;
|
||||||
|
@ -69,16 +105,15 @@ public class PlacementOffset {
|
||||||
|
|
||||||
public ActionResultType placeInWorld(World world, BlockItem blockItem, PlayerEntity player, Hand hand, BlockRayTraceResult ray) {
|
public ActionResultType placeInWorld(World world, BlockItem blockItem, PlayerEntity player, Hand hand, BlockRayTraceResult ray) {
|
||||||
|
|
||||||
ItemUseContext context = new ItemUseContext(player, hand, ray);
|
if (!isReplaceable(world))
|
||||||
|
return ActionResultType.PASS;
|
||||||
|
|
||||||
|
ItemUseContext context = new ItemUseContext(player, hand, ray);
|
||||||
BlockPos newPos = new BlockPos(pos);
|
BlockPos newPos = new BlockPos(pos);
|
||||||
|
|
||||||
if (!world.isBlockModifiable(player, newPos))
|
if (!world.isBlockModifiable(player, newPos))
|
||||||
return ActionResultType.PASS;
|
return ActionResultType.PASS;
|
||||||
|
|
||||||
if (!isReplaceable(world))
|
|
||||||
return ActionResultType.PASS;
|
|
||||||
|
|
||||||
BlockState state = stateTransform.apply(blockItem.getBlock().getDefaultState());
|
BlockState state = stateTransform.apply(blockItem.getBlock().getDefaultState());
|
||||||
if (state.has(BlockStateProperties.WATERLOGGED)) {
|
if (state.has(BlockStateProperties.WATERLOGGED)) {
|
||||||
IFluidState fluidState = world.getFluidState(newPos);
|
IFluidState fluidState = world.getFluidState(newPos);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.simibubi.create.foundation.utility.placement.util;
|
package com.simibubi.create.foundation.utility.placement.util;
|
||||||
|
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||||
import mcp.MethodsReturnNonnullByDefault;
|
import mcp.MethodsReturnNonnullByDefault;
|
||||||
|
@ -9,7 +8,6 @@ import net.minecraft.state.IProperty;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.BlockRayTraceResult;
|
import net.minecraft.util.math.BlockRayTraceResult;
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -71,7 +69,9 @@ public abstract class PoleHelper<T extends Comparable<T>> implements IPlacementH
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||||
Vec3d centerOffset = new Vec3d(ray.getFace().getDirectionVec()).scale(.3);
|
//Vec3d centerOffset = new Vec3d(ray.getFace().getDirectionVec()).scale(.3);
|
||||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos).add(centerOffset), VecHelper.getCenterOf(offset.getPos()).add(centerOffset), ray.getFace(), 0.75D);
|
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos).add(centerOffset), VecHelper.getCenterOf(offset.getPos()).add(centerOffset), ray.getFace(), 0.75D);
|
||||||
|
|
||||||
|
displayGhost(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,4 +23,7 @@ public net.minecraft.tileentity.BeaconTileEntity field_174909_f # beamSegments
|
||||||
|
|
||||||
# Server Tick List (For stopping placed fluids from spilling)
|
# Server Tick List (For stopping placed fluids from spilling)
|
||||||
public net.minecraft.world.server.ServerTickList field_205374_d # pendingTickListEntriesHashSet
|
public net.minecraft.world.server.ServerTickList field_205374_d # pendingTickListEntriesHashSet
|
||||||
public net.minecraft.world.server.ServerTickList field_205375_e # pendingTickListEntriesTreeSet
|
public net.minecraft.world.server.ServerTickList field_205375_e # pendingTickListEntriesTreeSet
|
||||||
|
|
||||||
|
# GameRenderer
|
||||||
|
public net.minecraft.client.renderer.GameRenderer func_215311_a(Lnet/minecraft/client/renderer/ActiveRenderInfo;FZ)D #getFOVModifier
|
Loading…
Reference in a new issue