mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-29 08:27:03 +01:00
Merge remote-tracking branch 'upstream/mc1.15/dev' into mc1.15/experimental-rendering
# Conflicts: # src/main/java/com/simibubi/create/CreateClient.java # src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java # src/main/java/com/simibubi/create/events/ClientEvents.java # src/main/resources/META-INF/accesstransformer.cfg
This commit is contained in:
commit
24ab4e181f
21 changed files with 847 additions and 137 deletions
|
@ -1,5 +1,10 @@
|
|||
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.relays.encased.CasingConnectivity;
|
||||
import com.simibubi.create.content.schematics.ClientSchematicLoader;
|
||||
|
@ -15,7 +20,9 @@ import com.simibubi.create.foundation.render.backend.OptifineHandler;
|
|||
import com.simibubi.create.foundation.render.SuperByteBufferCache;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
|
||||
import com.simibubi.create.foundation.render.backend.Backend;
|
||||
import com.simibubi.create.foundation.utility.ghost.GhostBlocks;
|
||||
import com.simibubi.create.foundation.utility.outliner.Outliner;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BlockModelShapes;
|
||||
|
@ -33,11 +40,6 @@ import net.minecraftforge.client.model.ModelLoader;
|
|||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
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 static ClientSchematicLoader schematicSender;
|
||||
|
@ -46,6 +48,7 @@ public class CreateClient {
|
|||
public static SuperByteBufferCache bufferCache;
|
||||
public static KineticRenderer kineticRenderer;
|
||||
public static final Outliner outliner = new Outliner();
|
||||
public static GhostBlocks ghostBlocks;
|
||||
|
||||
private static CustomBlockModels customBlockModels;
|
||||
private static CustomItemModels customItemModels;
|
||||
|
@ -75,6 +78,8 @@ public class CreateClient {
|
|||
bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
|
||||
bufferCache.registerCompartment(ContraptionRenderDispatcher.CONTRAPTION, 20);
|
||||
|
||||
ghostBlocks = new GhostBlocks();
|
||||
|
||||
AllKeys.register();
|
||||
AllContainerTypes.registerScreenFactories();
|
||||
//AllTileEntities.registerRenderers();
|
||||
|
|
|
@ -29,11 +29,7 @@ import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock
|
|||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.fluid.CombinedTankWrapper;
|
||||
import com.simibubi.create.foundation.render.backend.light.EmptyLighter;
|
||||
import com.simibubi.create.foundation.utility.BlockFace;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.NBTProcessors;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.*;
|
||||
import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.material.PushReaction;
|
||||
|
@ -42,6 +38,7 @@ import net.minecraft.fluid.Fluids;
|
|||
import net.minecraft.fluid.IFluidState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.INBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
|
@ -56,6 +53,7 @@ import net.minecraft.util.Rotation;
|
|||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.palette.PaletteHashMap;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
|
@ -70,6 +68,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
|||
import net.minecraftforge.fluids.capability.templates.FluidTank;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
|
@ -600,58 +599,16 @@ public abstract class Contraption {
|
|||
presentTileEntities.clear();
|
||||
specialRenderedTileEntities.clear();
|
||||
|
||||
nbt.getList("Blocks", 10)
|
||||
.forEach(c -> {
|
||||
CompoundNBT comp = (CompoundNBT) c;
|
||||
BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")),
|
||||
NBTUtil.readBlockState(comp.getCompound("Block")),
|
||||
comp.contains("Data") ? comp.getCompound("Data") : null);
|
||||
blocks.put(info.pos, info);
|
||||
|
||||
if (world.isRemote) {
|
||||
Block block = info.state.getBlock();
|
||||
CompoundNBT tag = info.nbt;
|
||||
MovementBehaviour movementBehaviour = AllMovementBehaviours.of(block);
|
||||
if (tag == null)
|
||||
return;
|
||||
|
||||
tag.putInt("x", info.pos.getX());
|
||||
tag.putInt("y", info.pos.getY());
|
||||
tag.putInt("z", info.pos.getZ());
|
||||
|
||||
TileEntity te = TileEntity.create(tag);
|
||||
if (te == null)
|
||||
return;
|
||||
te.setLocation(new WrappedWorld(world) {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
if (!pos.equals(te.getPos()))
|
||||
return Blocks.AIR.getDefaultState();
|
||||
return info.state;
|
||||
}
|
||||
|
||||
}, te.getPos());
|
||||
if (te instanceof KineticTileEntity)
|
||||
((KineticTileEntity) te).setSpeed(0);
|
||||
te.getBlockState();
|
||||
|
||||
if (movementBehaviour == null || !movementBehaviour.hasSpecialInstancedRendering())
|
||||
maybeInstancedTileEntities.add(te);
|
||||
|
||||
if (movementBehaviour != null && !movementBehaviour.renderAsNormalTileEntity())
|
||||
return;
|
||||
|
||||
presentTileEntities.put(info.pos, te);
|
||||
specialRenderedTileEntities.add(te);
|
||||
}
|
||||
});
|
||||
INBT blocks = nbt.get("Blocks");
|
||||
//used to differentiate between the 'old' and the paletted serialization
|
||||
boolean usePalettedDeserialization = blocks != null && blocks.getId() == 10 && ((CompoundNBT) blocks).contains("Palette");
|
||||
readBlocksCompound(blocks, world, usePalettedDeserialization);
|
||||
|
||||
actors.clear();
|
||||
nbt.getList("Actors", 10)
|
||||
.forEach(c -> {
|
||||
CompoundNBT comp = (CompoundNBT) c;
|
||||
BlockInfo info = blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos")));
|
||||
BlockInfo info = this.blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos")));
|
||||
MovementContext context = MovementContext.readNBT(world, info, comp, this);
|
||||
getActors().add(MutablePair.of(info, context));
|
||||
});
|
||||
|
@ -716,15 +673,8 @@ public abstract class Contraption {
|
|||
public CompoundNBT writeNBT(boolean spawnPacket) {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
nbt.putString("Type", getType().id);
|
||||
ListNBT blocksNBT = new ListNBT();
|
||||
for (BlockInfo block : this.blocks.values()) {
|
||||
CompoundNBT c = new CompoundNBT();
|
||||
c.put("Block", NBTUtil.writeBlockState(block.state));
|
||||
c.put("Pos", NBTUtil.writeBlockPos(block.pos));
|
||||
if (block.nbt != null)
|
||||
c.put("Data", block.nbt);
|
||||
blocksNBT.add(c);
|
||||
}
|
||||
|
||||
CompoundNBT blocksNBT = writeBlocksCompound();
|
||||
|
||||
ListNBT actorsNBT = new ListNBT();
|
||||
for (MutablePair<BlockInfo, MovementContext> actor : getActors()) {
|
||||
|
@ -801,6 +751,107 @@ public abstract class Contraption {
|
|||
return nbt;
|
||||
}
|
||||
|
||||
private CompoundNBT writeBlocksCompound() {
|
||||
CompoundNBT compound = new CompoundNBT();
|
||||
PaletteHashMap<BlockState> palette = new PaletteHashMap<>(GameData.getBlockStateIDMap(), 16, (i, s) -> {throw new IllegalStateException("Palette Map index exceeded maximum");}, NBTUtil::readBlockState, NBTUtil::writeBlockState);
|
||||
ListNBT blockList = new ListNBT();
|
||||
|
||||
for (BlockInfo block : this.blocks.values()) {
|
||||
int id = palette.idFor(block.state);
|
||||
CompoundNBT c = new CompoundNBT();
|
||||
c.putLong("Pos", block.pos.toLong());
|
||||
c.putInt("State", id);
|
||||
if (block.nbt != null)
|
||||
c.put("Data", block.nbt);
|
||||
blockList.add(c);
|
||||
}
|
||||
|
||||
ListNBT paletteNBT = new ListNBT();
|
||||
palette.writePaletteToList(paletteNBT);
|
||||
compound.put("Palette", paletteNBT);
|
||||
compound.put("BlockList", blockList);
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
private void readBlocksCompound(INBT compound, World world, boolean usePalettedDeserialization) {
|
||||
PaletteHashMap<BlockState> palette = null;
|
||||
ListNBT blockList;
|
||||
if (usePalettedDeserialization) {
|
||||
CompoundNBT c = ((CompoundNBT) compound);
|
||||
palette = new PaletteHashMap<>(GameData.getBlockStateIDMap(), 16, (i, s) -> {throw new IllegalStateException("Palette Map index exceeded maximum");}, NBTUtil::readBlockState, NBTUtil::writeBlockState);
|
||||
palette.read(c.getList("Palette", 10));
|
||||
|
||||
blockList = c.getList("BlockList", 10);
|
||||
} else {
|
||||
blockList = (ListNBT) compound;
|
||||
}
|
||||
|
||||
PaletteHashMap<BlockState> finalPalette = palette;
|
||||
blockList.forEach(e -> {
|
||||
CompoundNBT c = (CompoundNBT) e;
|
||||
|
||||
BlockInfo info = usePalettedDeserialization ? readBlockInfo(c, finalPalette) : legacyReadBlockInfo(c);
|
||||
|
||||
this.blocks.put(info.pos, info);
|
||||
|
||||
if (world.isRemote) {
|
||||
Block block = info.state.getBlock();
|
||||
CompoundNBT tag = info.nbt;
|
||||
MovementBehaviour movementBehaviour = AllMovementBehaviours.of(block);
|
||||
if (tag == null || (movementBehaviour != null && movementBehaviour.hasSpecialMovementRenderer()))
|
||||
return;
|
||||
|
||||
tag.putInt("x", info.pos.getX());
|
||||
tag.putInt("y", info.pos.getY());
|
||||
tag.putInt("z", info.pos.getZ());
|
||||
|
||||
TileEntity te = TileEntity.create(tag);
|
||||
if (te == null)
|
||||
return;
|
||||
te.setLocation(new WrappedWorld(world) {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
if (!pos.equals(te.getPos()))
|
||||
return Blocks.AIR.getDefaultState();
|
||||
return info.state;
|
||||
}
|
||||
|
||||
}, te.getPos());
|
||||
if (te instanceof KineticTileEntity)
|
||||
((KineticTileEntity) te).setSpeed(0);
|
||||
te.getBlockState();
|
||||
|
||||
if (movementBehaviour == null || !movementBehaviour.hasSpecialInstancedRendering())
|
||||
maybeInstancedTileEntities.add(te);
|
||||
|
||||
if (movementBehaviour != null && !movementBehaviour.renderAsNormalTileEntity())
|
||||
return;
|
||||
|
||||
presentTileEntities.put(info.pos, te);
|
||||
specialRenderedTileEntities.add(te);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private static BlockInfo readBlockInfo(CompoundNBT blockListEntry, PaletteHashMap<BlockState> palette) {
|
||||
return new BlockInfo(
|
||||
BlockPos.fromLong(blockListEntry.getLong("Pos")),
|
||||
Objects.requireNonNull(palette.get(blockListEntry.getInt("State"))),
|
||||
blockListEntry.contains("Data") ? blockListEntry.getCompound("Data") : null
|
||||
);
|
||||
}
|
||||
|
||||
private static BlockInfo legacyReadBlockInfo(CompoundNBT blockListEntry) {
|
||||
return new BlockInfo(
|
||||
NBTUtil.readBlockPos(blockListEntry.getCompound("Pos")),
|
||||
NBTUtil.readBlockState(blockListEntry.getCompound("Block")),
|
||||
blockListEntry.contains("Data") ? blockListEntry.getCompound("Data") : null
|
||||
);
|
||||
}
|
||||
|
||||
public void removeBlocksFromWorld(World world, BlockPos offset) {
|
||||
storage.values()
|
||||
.forEach(MountedStorage::removeStorageFromWorld);
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.simibubi.create.AllShapes;
|
|||
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
||||
import com.simibubi.create.foundation.utility.DyeHelper;
|
||||
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.PlacementHelpers;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||
|
@ -216,7 +215,8 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
|
||||
@Override
|
||||
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()
|
||||
.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.CogwheelBlockItem;
|
||||
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.PlacementHelpers;
|
||||
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.tileentity.TileEntity;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -111,9 +109,11 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements
|
|||
|
||||
@Override
|
||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE,
|
||||
state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X));
|
||||
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE,
|
||||
// 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.foundation.advancement.AllTriggers;
|
||||
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.PlacementHelpers;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||
|
@ -150,9 +149,11 @@ public class CogwheelBlockItem extends BlockItem {
|
|||
|
||||
@Override
|
||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)),
|
||||
((CogWheelBlock) state.getBlock()).isLarge ? 1.5D : 0.75D);
|
||||
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)),
|
||||
// ((CogWheelBlock) state.getBlock()).isLarge ? 1.5D : 0.75D);
|
||||
|
||||
displayGhost(offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,8 +228,10 @@ public class CogwheelBlockItem extends BlockItem {
|
|||
|
||||
@Override
|
||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)), 1D);
|
||||
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)), 1D);
|
||||
|
||||
displayGhost(offset);
|
||||
}
|
||||
|
||||
protected boolean hitOnShaft(BlockState state, BlockRayTraceResult ray) {
|
||||
|
@ -320,10 +323,12 @@ public class CogwheelBlockItem extends BlockItem {
|
|||
|
||||
@Override
|
||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, offset.getTransform()
|
||||
.apply(AllBlocks.LARGE_COGWHEEL.getDefaultState())
|
||||
.get(AXIS)));
|
||||
//IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()),
|
||||
// Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, offset.getTransform()
|
||||
// .apply(AllBlocks.LARGE_COGWHEEL.getDefaultState())
|
||||
// .get(AXIS)));
|
||||
|
||||
displayGhost(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ public class ClientEvents {
|
|||
ArmInteractionPointHandler.tick();
|
||||
PlacementHelpers.tick();
|
||||
CreateClient.outliner.tickOutlines();
|
||||
CreateClient.ghostBlocks.tickGhosts();
|
||||
ContraptionRenderDispatcher.tick();
|
||||
}
|
||||
|
||||
|
@ -142,6 +143,8 @@ public class ClientEvents {
|
|||
|
||||
CouplingRenderer.renderAll(ms, buffer);
|
||||
CreateClient.schematicHandler.render(ms, buffer);
|
||||
CreateClient.ghostBlocks.renderAll(ms, buffer);
|
||||
|
||||
CreateClient.outliner.renderOutlines(ms, buffer);
|
||||
// LightVolumeDebugger.render(ms, buffer);
|
||||
// CollisionDebugger.render(ms, buffer);
|
||||
|
|
|
@ -24,19 +24,7 @@ public class HighlightCommand {
|
|||
public static ArgumentBuilder<CommandSource, ?> register() {
|
||||
return Commands.literal("highlight")
|
||||
.requires(cs -> cs.hasPermissionLevel(0))
|
||||
.requires(AllCommands.sourceIsPlayer)
|
||||
.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())
|
||||
.executes(ctx -> {
|
||||
Collection<ServerPlayerEntity> players = EntityArgument.getPlayers(ctx, "players");
|
||||
|
@ -52,7 +40,19 @@ public class HighlightCommand {
|
|||
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 -> {
|
||||
ServerPlayerEntity player = ctx.getSource().asPlayer();
|
||||
return highlightAssemblyExceptionFor(player, ctx.getSource());
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.simibubi.create.foundation.command;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
|
@ -30,7 +30,8 @@ public class ToggleDebugCommand {
|
|||
|
||||
ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " rainbow debug"), true);
|
||||
|
||||
return 1;
|
||||
}));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,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 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
|
||||
public String getName() {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.simibubi.create.foundation.gui;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.AbstractGui;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
@ -79,6 +78,9 @@ public enum AllGuiTextures {
|
|||
INDICATOR_YELLOW("widgets.png", 54, 18, 18, 6),
|
||||
INDICATOR_RED("widgets.png", 72, 18, 18, 6),
|
||||
|
||||
// PlacementIndicator
|
||||
PLACEMENT_INDICATOR_SHEET("placement_indicator.png", 0, 0, 16, 256);
|
||||
|
||||
;
|
||||
|
||||
public static final int FONT_COLOR = 0x575F7A;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
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.ListNBT;
|
||||
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.Vec3i;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
|
||||
public class VecHelper {
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
//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,83 @@
|
|||
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 net.minecraft.util.math.MathHelper;
|
||||
|
||||
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 = MathHelper.cos((float) ((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 net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -46,9 +47,21 @@ public interface IPlacementHelper {
|
|||
*/
|
||||
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
|
||||
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) {
|
||||
|
@ -67,6 +80,15 @@ public interface IPlacementHelper {
|
|||
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) {
|
||||
return orderedByDistance(pos, hit, dir -> dir.getAxis() == axis);
|
||||
}
|
||||
|
|
|
@ -1,22 +1,44 @@
|
|||
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.AllGuiTextures;
|
||||
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.client.MainWindow;
|
||||
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.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
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.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class PlacementHelpers {
|
||||
|
||||
private static final List<IPlacementHelper> helpers = new ArrayList<>();
|
||||
private static int animationTick = 0;
|
||||
private static final InterpolatedChasingValue angle = new InterpolatedChasingAngle().withSpeed(0.25f);
|
||||
private static BlockPos target = null;
|
||||
private static BlockPos lastTarget = null;
|
||||
|
||||
public static int register(IPlacementHelper helper) {
|
||||
helpers.add(helper);
|
||||
|
@ -32,6 +54,23 @@ public class PlacementHelpers {
|
|||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
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();
|
||||
ClientWorld world = mc.world;
|
||||
|
||||
|
@ -46,29 +85,212 @@ public class PlacementHelpers {
|
|||
if (mc.player == null)
|
||||
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
|
||||
return;
|
||||
|
||||
BlockPos pos = ray.getPos();
|
||||
BlockState state = world.getBlockState(pos);
|
||||
for (Hand hand : Hand.values()) {
|
||||
|
||||
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())
|
||||
return;
|
||||
BlockPos pos = ray.getPos();
|
||||
BlockState state = world.getBlockState(pos);
|
||||
|
||||
for (IPlacementHelper h : filteredForState) {
|
||||
PlacementOffset offset = h.getOffset(world, state, pos, ray);
|
||||
List<IPlacementHelper> filteredForState = filteredForHeldItem.stream().filter(helper -> helper.matchesState(state)).collect(Collectors.toList());
|
||||
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);
|
||||
|
||||
drawDirectionIndicator(event.getPartialTicks(), screenX, screenY, progress);
|
||||
//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);
|
||||
if (projTarget.z > 0) {
|
||||
target = target.inverse();
|
||||
}
|
||||
|
||||
Vec3d norm = target.normalize();
|
||||
Vec3d ref = new Vec3d(0, 1, 0);
|
||||
float targetAngle = AngleHelper.deg(Math.acos(norm.dotProduct(ref)));
|
||||
|
||||
angle.withSpeed(0.25f);
|
||||
|
||||
if (norm.x < 0) {
|
||||
targetAngle = 360 - targetAngle;
|
||||
}
|
||||
|
||||
if (animationTick < 10)
|
||||
angle.set(targetAngle);
|
||||
|
||||
angle.target(targetAngle);
|
||||
angle.tick();
|
||||
|
||||
float snapSize = 22.5f;
|
||||
float snappedAngle = (snapSize * Math.round(angle.get(0f) / snapSize)) % 360f;
|
||||
|
||||
float length = 10;
|
||||
//TOD O if the target is off screen, use length to show a meaningful distance
|
||||
|
||||
boolean flag = AllConfigs.CLIENT.smoothPlacementIndicator.get();
|
||||
if (flag)
|
||||
fadedArrow(centerX, centerY, r, g, b, a, length, snappedAngle);
|
||||
|
||||
else
|
||||
textured(centerX, centerY, a, snappedAngle);
|
||||
}
|
||||
|
||||
private static void fadedArrow(float centerX, float centerY, float r, float g, float b, float a, float length, float snappedAngle) {
|
||||
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), 0, 0, 1);
|
||||
//RenderSystem.rotatef(snappedAngle, 0, 0, 1);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
private static void textured(float centerX, float centerY, float alpha, float snappedAngle) {
|
||||
RenderSystem.pushMatrix();
|
||||
RenderSystem.enableTexture();
|
||||
//RenderSystem.disableTexture();
|
||||
AllGuiTextures.PLACEMENT_INDICATOR_SHEET.bind();
|
||||
RenderSystem.enableBlend();
|
||||
//RenderSystem.disableAlphaTest();
|
||||
RenderSystem.enableAlphaTest();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.color4f(1f, 1f, 1f, 1f);
|
||||
RenderSystem.shadeModel(GL11.GL_SMOOTH);
|
||||
|
||||
RenderSystem.translated(centerX, centerY, 0);
|
||||
//RenderSystem.rotatef(angle.get(0.1f), 0, 0, -1);
|
||||
//RenderSystem.translated(0, 10, 0);
|
||||
//RenderSystem.rotatef(angle.get(0.1f), 0, 0, 1);
|
||||
RenderSystem.scaled(12, 12, 0);
|
||||
|
||||
float index = snappedAngle / 22.5f;
|
||||
float tex_size = 16f/256f;
|
||||
|
||||
float tx = 0;
|
||||
float ty = index * tex_size;
|
||||
float tw = 1f;
|
||||
float th = tex_size;
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEXTURE);
|
||||
|
||||
|
||||
buffer.vertex(-1, -1, 0).color(1f, 1f, 1f, alpha).texture(tx, ty).endVertex();
|
||||
buffer.vertex(-1, 1, 0).color(1f, 1f, 1f, alpha).texture(tx, ty + th).endVertex();
|
||||
buffer.vertex(1, 1, 0).color(1f, 1f, 1f, alpha).texture(tx + tw, ty + th).endVertex();
|
||||
buffer.vertex(1, -1, 0).color(1f, 1f, 1f, alpha).texture(tx + tw, ty).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
RenderSystem.shadeModel(GL11.GL_FLAT);
|
||||
|
||||
//RenderSystem.enableTexture();
|
||||
|
||||
RenderSystem.disableBlend();
|
||||
//RenderSystem.enableAlphaTest();
|
||||
RenderSystem.popMatrix();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,25 +27,46 @@ import java.util.function.Function;
|
|||
public class PlacementOffset {
|
||||
|
||||
private final boolean success;
|
||||
private final Vec3i pos;
|
||||
private final Function<BlockState, BlockState> stateTransform;
|
||||
private Vec3i pos;
|
||||
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.pos = pos;
|
||||
this.stateTransform = transform == null ? Function.identity() : transform;
|
||||
this.pos = BlockPos.ZERO;
|
||||
this.stateTransform = Function.identity();
|
||||
this.ghostState = null;
|
||||
}
|
||||
|
||||
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) {
|
||||
return new PlacementOffset(true, pos, null);
|
||||
return success().at(pos);
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -56,10 +77,25 @@ public class PlacementOffset {
|
|||
return pos;
|
||||
}
|
||||
|
||||
public BlockPos getBlockPos() {
|
||||
if (pos instanceof BlockPos)
|
||||
return (BlockPos) pos;
|
||||
|
||||
return new BlockPos(pos);
|
||||
}
|
||||
|
||||
public Function<BlockState, BlockState> getTransform() {
|
||||
return stateTransform;
|
||||
}
|
||||
|
||||
public boolean hasGhostState() {
|
||||
return ghostState != null;
|
||||
}
|
||||
|
||||
public BlockState getGhostState() {
|
||||
return ghostState;
|
||||
}
|
||||
|
||||
public boolean isReplaceable(World world) {
|
||||
if (!success)
|
||||
return false;
|
||||
|
@ -69,16 +105,15 @@ public class PlacementOffset {
|
|||
|
||||
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);
|
||||
|
||||
if (!world.isBlockModifiable(player, newPos))
|
||||
return ActionResultType.PASS;
|
||||
|
||||
if (!isReplaceable(world))
|
||||
return ActionResultType.PASS;
|
||||
|
||||
BlockState state = stateTransform.apply(blockItem.getBlock().getDefaultState());
|
||||
if (state.has(BlockStateProperties.WATERLOGGED)) {
|
||||
IFluidState fluidState = world.getFluidState(newPos);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
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.PlacementOffset;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
@ -9,7 +8,6 @@ import net.minecraft.state.IProperty;
|
|||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -71,7 +69,9 @@ public abstract class PoleHelper<T extends Comparable<T>> implements IPlacementH
|
|||
|
||||
@Override
|
||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
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);
|
||||
//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);
|
||||
|
||||
displayGhost(offset);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,4 +38,10 @@ public net.minecraft.client.renderer.GameRenderer func_228383_b_(Lcom/mojang/bla
|
|||
public com.mojang.blaze3d.platform.GlStateManager$FogState
|
||||
public com.mojang.blaze3d.platform.GlStateManager field_225663_h_ #FOG
|
||||
public com.mojang.blaze3d.platform.GlStateManager$BooleanState
|
||||
public com.mojang.blaze3d.platform.GlStateManager$BooleanState field_179201_b #field_179201_b
|
||||
public com.mojang.blaze3d.platform.GlStateManager$BooleanState field_179201_b #field_179201_b
|
||||
|
||||
# GameRenderer
|
||||
public net.minecraft.client.renderer.GameRenderer func_215311_a(Lnet/minecraft/client/renderer/ActiveRenderInfo;FZ)D #getFOVModifier
|
||||
|
||||
# IResizeCallback
|
||||
public net.minecraft.util.palette.IResizeCallback
|
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
Loading…
Reference in a new issue