Added breaking animation to all breakable blocks.

Smart preview: only blocks that can be (re)placed show a preview.
Smart outline when breaking: only blocks that can be broken by the current tool get an outline.
Improved occlusion by render further block previews first.
Reversed order of mirror and array to mirror arrays (for roofs etc).
This commit is contained in:
Christian Knaapen
2018-12-15 16:59:13 +01:00
parent 408d96622b
commit 3e81378c7c
7 changed files with 186 additions and 55 deletions

View File

@@ -89,6 +89,7 @@ public class Array {
blockState = BuildModifiers.getBlockStateFromItem(itemStack, player, startPos, EnumFacing.UP, new Vec3d(0, 0, 0), EnumHand.MAIN_HAND);
}
//blockState = blockState.getBlock().getStateForPlacement(player.world, pos, )
blockStates.add(blockState);
itemStacks.add(itemStack);
}

View File

@@ -86,13 +86,17 @@ public class BuildModifiers {
public static void onBlockBroken(BlockEvent.BreakEvent event) {
if (event.getWorld().isRemote) return;
//get coordinates
List<BlockPos> coordinates = findCoordinates(event.getPlayer(), event.getPos());
BuildSettingsManager.BuildSettings buildSettings = BuildSettingsManager.getBuildSettings(event.getPlayer());
//Only use own break event if anything is enabled
if (isEnabled(buildSettings, event.getPos())) {
//get coordinates
List<BlockPos> coordinates = findCoordinates(event.getPlayer(), event.getPos());
//break all those blocks
for (BlockPos coordinate : coordinates) {
if (event.getWorld().isBlockLoaded(coordinate, false)) {
SurvivalHelper.breakBlock(event.getWorld(), event.getPlayer(), coordinate);
//break all those blocks
for (BlockPos coordinate : coordinates) {
if (event.getWorld().isBlockLoaded(coordinate, false)) {
SurvivalHelper.breakBlock(event.getWorld(), event.getPlayer(), coordinate);
}
}
}
}
@@ -102,12 +106,12 @@ public class BuildModifiers {
//Add current block being placed too
coordinates.add(startPos);
List<BlockPos> mirrorCoordinates = Mirror.findCoordinates(player, startPos);
coordinates.addAll(mirrorCoordinates);
coordinates.addAll(Array.findCoordinates(player, startPos));
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, startPos);
coordinates.addAll(arrayCoordinates);
coordinates.addAll(Mirror.findCoordinates(player, startPos));
//get array for each coordinate
for (BlockPos coordinate : mirrorCoordinates) {
coordinates.addAll(Array.findCoordinates(player, coordinate));
for (BlockPos coordinate : arrayCoordinates) {
coordinates.addAll(Mirror.findCoordinates(player, coordinate));
}
return coordinates;
@@ -137,17 +141,26 @@ public class BuildModifiers {
blockStates.add(blockState);
itemStacks.add(itemStack);
List<IBlockState> mirrorBlockStates = Mirror.findBlockStates(player, startPos, blockState, itemStack, itemStacks);
blockStates.addAll(mirrorBlockStates);
blockStates.addAll(Array.findBlockStates(player, startPos, blockState, itemStack, itemStacks));
List<IBlockState> arrayBlockStates = Array.findBlockStates(player, startPos, blockState, itemStack, itemStacks);
blockStates.addAll(arrayBlockStates);
blockStates.addAll(Mirror.findBlockStates(player, startPos, blockState, itemStack, itemStacks));
//add array for each mirror coordinate
List<BlockPos> findCoordinates = Mirror.findCoordinates(player, startPos);
for (int i = 0; i < findCoordinates.size(); i++) {
BlockPos coordinate = findCoordinates.get(i);
IBlockState blockState1 = mirrorBlockStates.get(i);
blockStates.addAll(Array.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, startPos);
for (int i = 0; i < arrayCoordinates.size(); i++) {
BlockPos coordinate = arrayCoordinates.get(i);
IBlockState blockState1 = arrayBlockStates.get(i);
blockStates.addAll(Mirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
}
//Adjust blockstates for torches and ladders etc to place on a valid side
//TODO optimize findCoordinates (done twice now)
//TODO fix mirror
// List<BlockPos> coordinates = findCoordinates(player, startPos);
// for (int i = 0; i < blockStates.size(); i++) {
// blockStates.set(i, blockStates.get(i).getBlock().getStateForPlacement(player.world, coordinates.get(i), facing,
// (float) hitVec.x, (float) hitVec.y, (float) hitVec.z, itemStacks.get(i).getMetadata(), player, EnumHand.MAIN_HAND));
// }
return blockStates;
}

View File

@@ -101,7 +101,7 @@ public class EventHandler
IBlockState blockState = world.getBlockState(coordinate);
//add hardness for each blockstate, if can break
if (SurvivalHelper.canBreak(world, player, coordinate))
totalBlockHardness += world.getBlockState(coordinate).getBlockHardness(world, coordinate);
totalBlockHardness += blockState.getBlockHardness(world, coordinate);
}
//Grabbing percentage from config

View File

@@ -26,7 +26,7 @@ public class Mirror {
public Vec3d position = new Vec3d(0.5, 64.5, 0.5);
public boolean mirrorX = true, mirrorY = false, mirrorZ = false;
public int radius = 20;
public boolean drawLines = true, drawPlanes = false;
public boolean drawLines = true, drawPlanes = true;
public MirrorSettings() {
}

View File

@@ -1,20 +1,25 @@
package nl.requios.effortlessbuilding.helper;
import com.google.common.collect.Maps;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemTool;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.*;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -25,11 +30,13 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.util.Color;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Mod.EventBusSubscriber(Side.CLIENT)
public class RenderHelper {
public class RenderHelper implements IWorldEventListener {
private static final Color colorX = new Color(255, 72, 52);
private static final Color colorY = new Color(67, 204, 51);
@@ -76,20 +83,7 @@ public class RenderHelper {
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_CONSTANT_ALPHA, GL11.GL_ONE_MINUS_CONSTANT_ALPHA);
GL14.glBlendColor(1F, 1F, 1F, 0.6f);
}
public static void renderBlockOutline(BlockPos pos) {
renderBlockOutline(pos, pos);
}
//Renders outline. Pos1 has to be minimal x,y,z and pos2 maximal x,y,z
public static void renderBlockOutline(BlockPos pos1, BlockPos pos2) {
GL11.glLineWidth(2);
AxisAlignedBB aabb = new AxisAlignedBB(pos1, pos2.add(1, 1, 1)).grow(0.0020000000949949026);
RenderGlobal.drawSelectionBoundingBox(aabb, 0f, 0f, 0f, 0.4f);
GL14.glBlendColor(1F, 1F, 1F, 0.8f);
}
private static void endBlockPreviews() {
@@ -109,10 +103,23 @@ public class RenderHelper {
GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.translate(-0.005f, -0.005f, 0.005f);
GlStateManager.scale(1.01f, 1.01f, 1.01f);
dispatcher.renderBlockBrightness(blockState, 1f);
dispatcher.renderBlockBrightness(blockState, 0.85f);
GlStateManager.popMatrix();
}
public static void renderBlockOutline(BlockPos pos) {
renderBlockOutline(pos, pos);
}
//Renders outline. Pos1 has to be minimal x,y,z and pos2 maximal x,y,z
public static void renderBlockOutline(BlockPos pos1, BlockPos pos2) {
GL11.glLineWidth(2);
AxisAlignedBB aabb = new AxisAlignedBB(pos1, pos2.add(1, 1, 1)).grow(0.0020000000949949026);
RenderGlobal.drawSelectionBoundingBox(aabb, 0f, 0f, 0f, 0.4f);
}
@SubscribeEvent
public static void onRender(RenderWorldLastEvent event) {
EntityPlayer player = Minecraft.getMinecraft().player;
@@ -170,7 +177,7 @@ public class RenderHelper {
//Check if tool (or none) in hand
ItemStack mainhand = player.getHeldItemMainhand();
boolean toolInHand = !mainhand.isEmpty() && mainhand.getItem() instanceof ItemTool;
boolean toolInHand = mainhand.isEmpty() || (!mainhand.isEmpty() && mainhand.getItem() instanceof ItemTool);
boolean replaceable =
player.world.getBlockState(startPos).getBlock().isReplaceable(player.world, startPos);
if (!buildSettings.doQuickReplace() && !toolInHand && !replaceable) {
@@ -201,10 +208,16 @@ public class RenderHelper {
//check if valid blockstates
if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) {
for (int i = 0; i < newCoordinates.size(); i++) {
for (int i = newCoordinates.size() - 1; i >= 0; i--) {
BlockPos blockPos = newCoordinates.get(i);
IBlockState blockState = blockStates.get(i);
renderBlockPreview(dispatcher, blockPos, blockState);
ItemStack itemstack = itemStacks.get(i);
//Check if can place
if (!itemstack.isEmpty() && SurvivalHelper.canPlayerEdit(player, player.world, blockPos, itemstack) &&
SurvivalHelper.mayPlace(player.world, Block.getBlockFromItem(itemstack.getItem()), blockState, blockPos, true, EnumFacing.UP, player) &&
SurvivalHelper.canReplace(player.world, player, blockPos)) {
renderBlockPreview(dispatcher, blockPos, blockState);
}
}
}
}
@@ -217,7 +230,8 @@ public class RenderHelper {
BlockPos coordinate = newCoordinates.get(i);
IBlockState blockState = player.world.getBlockState(coordinate);
if (!blockState.getBlock().isAir(blockState, player.world, coordinate)) {
if (!blockState.getBlock().isAir(blockState, player.world, coordinate) &&
SurvivalHelper.canBreak(player.world, player, coordinate)) {
renderBlockOutline(coordinate);
}
}
@@ -312,4 +326,82 @@ public class RenderHelper {
tessellator.draw();
}
//IWORLDEVENTLISTENER IMPLEMENTATION
@Override
public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {
}
@Override
public void notifyLightSet(BlockPos pos) {
}
@Override
public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {
}
@Override
public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category,
double x, double y, double z, float volume, float pitch) {
}
@Override
public void playRecord(SoundEvent soundIn, BlockPos pos) {
}
@Override
public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord,
double xSpeed, double ySpeed, double zSpeed, int... parameters) {
}
@Override
public void spawnParticle(int id, boolean ignoreRange, boolean p_190570_3_, double x, double y, double z,
double xSpeed, double ySpeed, double zSpeed, int... parameters) {
}
@Override
public void onEntityAdded(Entity entityIn) {
}
@Override
public void onEntityRemoved(Entity entityIn) {
}
@Override
public void broadcastSound(int soundID, BlockPos pos, int data) {
}
@Override
public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {
}
//Sends breaking progress for all coordinates to renderglobal, so all blocks get visually broken
@Override
public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {
Minecraft mc = Minecraft.getMinecraft();
BuildSettingsManager.BuildSettings buildSettings = BuildSettingsManager.getBuildSettings(mc.player);
if (!BuildModifiers.isEnabled(buildSettings, pos)) return;
List<BlockPos> coordinates = BuildModifiers.findCoordinates(mc.player, pos);
for (int i = 1; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
if (SurvivalHelper.canBreak(mc.world, mc.player, coordinate)) {
//Send i as entity id because only one block can be broken per id
//Unless i happens to be the player id, then take something else
int fakeId = mc.player.getEntityId() != i ? i : coordinates.size();
mc.renderGlobal.sendBlockBreakProgress(fakeId, coordinate, progress);
}
}
}
}

View File

@@ -1,6 +1,7 @@
package nl.requios.effortlessbuilding.helper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
@@ -20,6 +21,7 @@ import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import nl.requios.effortlessbuilding.BuildSettingsManager;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
@@ -108,11 +110,12 @@ public class SurvivalHelper {
//Can break using held tool? (or in creative)
public static boolean canBreak(World world, EntityPlayer player, BlockPos pos) {
IBlockState blockState = world.getBlockState(pos);
if (blockState.getBlock() instanceof BlockLiquid) return false;
if (player.isCreative()) return true;
IBlockState blockState = world.getBlockState(pos);
return canHarvestBlock(blockState.getBlock(), player, world, pos);
}
//From ForgeHooks#canHarvestBlock
@@ -169,21 +172,23 @@ public class SurvivalHelper {
}
//From EntityPlayer#canPlayerEdit
private static boolean canPlayerEdit(EntityPlayer player, World world, BlockPos pos, ItemStack stack)
public static boolean canPlayerEdit(EntityPlayer player, World world, BlockPos pos, ItemStack stack)
{
if (player.capabilities.allowEdit)
{
//True in creative and survival mode
return true;
}
else
{
//Adventure mode
Block block = world.getBlockState(pos).getBlock();
return stack.canPlaceOn(block) || stack.canEditBlocks();
}
}
//From World#mayPlace
private static boolean mayPlace(World world, Block blockIn, IBlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, EnumFacing sidePlacedOn, @Nullable Entity placer)
public static boolean mayPlace(World world, Block blockIn, IBlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, EnumFacing sidePlacedOn, @Nullable Entity placer)
{
IBlockState iblockstate1 = world.getBlockState(pos);
AxisAlignedBB axisalignedbb = skipCollisionCheck ? null : blockIn.getDefaultState().getCollisionBoundingBox(world, pos);
@@ -204,9 +209,11 @@ public class SurvivalHelper {
return true;
}
//TODO check config for allow to replace
return true;
//TODO fix check canPlaceBlockOnSide
//return /*iblockstate1.getBlock().isReplaceable(world, pos) &&*/ blockIn.canPlaceBlockOnSide(world, pos, sidePlacedOn);
//Check quickreplace
if (placer instanceof EntityPlayer && BuildSettingsManager.getBuildSettings(((EntityPlayer) placer)).doQuickReplace()) {
return true;
}
return iblockstate1.getBlock().isReplaceable(world, pos) && blockIn.canPlaceBlockOnSide(world, pos, sidePlacedOn);
}
}

View File

@@ -2,20 +2,27 @@ package nl.requios.effortlessbuilding.proxy;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.*;
@@ -28,8 +35,12 @@ import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.BuildSettingsManager;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.gui.SettingsGui;
import nl.requios.effortlessbuilding.helper.RenderHelper;
import nl.requios.effortlessbuilding.network.BuildSettingsMessage;
import org.lwjgl.input.Keyboard;
import scala.collection.parallel.ParIterableLike;
import javax.annotation.Nullable;
@Mod.EventBusSubscriber(Side.CLIENT)
public class ClientProxy implements IProxy {
@@ -88,6 +99,13 @@ public class ClientProxy implements IProxy {
}
}
@SubscribeEvent
public static void onEntityJoinWorld(EntityJoinWorldEvent event) {
if (event.getEntity() == Minecraft.getMinecraft().player) {
event.getWorld().addEventListener(new RenderHelper());
}
}
@SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true)
public static void onKeyPress(InputEvent.KeyInputEvent event) {
EntityPlayerSP player = Minecraft.getMinecraft().player;