diff --git a/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java b/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java index a02c859..5ea8858 100644 --- a/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java +++ b/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java @@ -60,5 +60,8 @@ public class BuildConfig { @Comment({"Use fancy shaders while placing blocks"}) public boolean useShaders = true; + + @Comment({"How long the dissolve effect takes when placing blocks, in ticks."}) + public int dissolveTime = 60; } } diff --git a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java index c6abd20..2231202 100644 --- a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java +++ b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java @@ -3,6 +3,8 @@ package nl.requios.effortlessbuilding; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; import net.minecraft.util.text.TextComponentString; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.config.Config; @@ -55,6 +57,8 @@ public class EffortlessBuilding public static final ItemReachUpgrade2 ITEM_REACH_UPGRADE_2 = new ItemReachUpgrade2(); public static final ItemReachUpgrade3 ITEM_REACH_UPGRADE_3 = new ItemReachUpgrade3(); + public static final SoundEvent SOUND_BUILD_CLICK = createSoundEvent("build_click"); + public static final Block[] BLOCKS = { }; @@ -65,6 +69,10 @@ public class EffortlessBuilding ITEM_REACH_UPGRADE_3 }; + public static final SoundEvent[] SOUND_EVENTS = { + SOUND_BUILD_CLICK + }; + public static final int RANDOMIZER_BAG_GUI = 0; @EventHandler @@ -89,6 +97,8 @@ public class EffortlessBuilding EffortlessBuilding.packetHandler.registerMessage(CancelModeMessage.MessageHandler.class, CancelModeMessage.class, 4, Side.SERVER); + EffortlessBuilding.packetHandler.registerMessage(RequestLookAtMessage.MessageHandler.class, RequestLookAtMessage.class, 5, Side.CLIENT); + proxy.preInit(event); } @@ -128,4 +138,9 @@ public class EffortlessBuilding public static void log(EntityPlayer player, String msg, boolean actionBar){ player.sendStatusMessage(new TextComponentString(msg), actionBar); } + + private static SoundEvent createSoundEvent(String soundName) { + final ResourceLocation soundID = new ResourceLocation(EffortlessBuilding.MODID, soundName); + return new SoundEvent(soundID).setRegistryName(soundID); + } } diff --git a/src/main/java/nl/requios/effortlessbuilding/EventHandler.java b/src/main/java/nl/requios/effortlessbuilding/EventHandler.java index dcdce43..055bdc5 100644 --- a/src/main/java/nl/requios/effortlessbuilding/EventHandler.java +++ b/src/main/java/nl/requios/effortlessbuilding/EventHandler.java @@ -8,6 +8,7 @@ import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.config.Config; @@ -26,6 +27,7 @@ import nl.requios.effortlessbuilding.capability.ModeCapabilityManager; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.network.BlockPlacedMessage; +import nl.requios.effortlessbuilding.network.RequestLookAtMessage; import java.util.List; @@ -50,6 +52,12 @@ public class EventHandler } } + @SubscribeEvent + public static void registerSounds(RegistryEvent.Register event) { + EffortlessBuilding.log("testing"); + event.getRegistry().registerAll(EffortlessBuilding.SOUND_EVENTS); + } + @SubscribeEvent public static void attachCapabilities(AttachCapabilitiesEvent event) { if (event.getObject() instanceof EntityPlayer) { @@ -81,7 +89,7 @@ public class EventHandler event.setCanceled(true); } else { //Send message to client, which sends message back with raytrace info - EffortlessBuilding.packetHandler.sendTo(new BlockPlacedMessage(), (EntityPlayerMP) event.getPlayer()); + EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(), (EntityPlayerMP) event.getPlayer()); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java index dbb063b..bcd306c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java @@ -24,16 +24,10 @@ public class BuildModes { Line ("Line", new Line()), Wall ("Wall", new Wall()), Floor ("Floor", new Floor()), - Normal2 ("Normal", new Normal()), - NormalPlus2 ("Normal+", new NormalPlus()), - Line2 ("Line", new Line()), - Wall2 ("Wall", new Wall()), - Floor2 ("Floor", new Floor()) - ; -// DiagonalLine, -// DiagonalWall, -// SlopedFloor, -// Cube; + DiagonalLine ("Diagonal Line", new DiagonalLine()), + DiagonalWall ("Diagonal Wall", new DiagonalWall()), + SlopeFloor ("Slope Floor", new SlopeFloor()), + Cube ("Cube", new Cube()); public String name; public final IBuildMode instance; diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Cube.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Cube.java new file mode 100644 index 0000000..0719dcc --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Cube.java @@ -0,0 +1,36 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +import java.util.ArrayList; +import java.util.List; + +public class Cube implements IBuildMode { + @Override + public void initialize(EntityPlayer player) { + + } + + @Override + public List onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) { + return new ArrayList<>(); + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos blockPos) { + return new ArrayList<>(); + } + + @Override + public EnumFacing getSideHit(EntityPlayer player) { + return null; + } + + @Override + public Vec3d getHitVec(EntityPlayer player) { + return null; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/DiagonalLine.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/DiagonalLine.java new file mode 100644 index 0000000..c830c83 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/DiagonalLine.java @@ -0,0 +1,36 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +import java.util.ArrayList; +import java.util.List; + +public class DiagonalLine implements IBuildMode { + @Override + public void initialize(EntityPlayer player) { + + } + + @Override + public List onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) { + return new ArrayList<>(); + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos blockPos) { + return new ArrayList<>(); + } + + @Override + public EnumFacing getSideHit(EntityPlayer player) { + return null; + } + + @Override + public Vec3d getHitVec(EntityPlayer player) { + return null; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/DiagonalWall.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/DiagonalWall.java new file mode 100644 index 0000000..aa9f6eb --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/DiagonalWall.java @@ -0,0 +1,36 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +import java.util.ArrayList; +import java.util.List; + +public class DiagonalWall implements IBuildMode { + @Override + public void initialize(EntityPlayer player) { + + } + + @Override + public List onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) { + return new ArrayList<>(); + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos blockPos) { + return new ArrayList<>(); + } + + @Override + public EnumFacing getSideHit(EntityPlayer player) { + return null; + } + + @Override + public Vec3d getHitVec(EntityPlayer player) { + return null; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java index 584e1b1..0442966 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java @@ -79,7 +79,7 @@ public class Floor implements IBuildMode { double yDistSquared = yBound.subtract(start).lengthSquared(); - int reach = ReachHelper.getMaxReach(player); //4 times as much as normal placement reach + int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach //check if its not behind the player and its not too close and not too far boolean yValid = yBound.subtract(start).dotProduct(look) > 0 && diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Line.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Line.java index 759eb8a..65a62aa 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/Line.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Line.java @@ -3,34 +3,208 @@ package nl.requios.effortlessbuilding.buildmode; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; +import nl.requios.effortlessbuilding.helper.ReachHelper; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class Line implements IBuildMode { + Dictionary rightClickNrTable = new Hashtable<>(); + Dictionary firstPosTable = new Hashtable<>(); + Dictionary sideHitTable = new Hashtable<>(); + Dictionary hitVecTable = new Hashtable<>(); + @Override public void initialize(EntityPlayer player) { - + rightClickNrTable.put(player.getUniqueID(), 0); + firstPosTable.put(player.getUniqueID(), BlockPos.ORIGIN); + sideHitTable.put(player.getUniqueID(), EnumFacing.UP); + hitVecTable.put(player.getUniqueID(), Vec3d.ZERO); } @Override public List onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) { - return new ArrayList<>(); + List list = new ArrayList<>(); + + int rightClickNr = rightClickNrTable.get(player.getUniqueID()); + rightClickNr++; + rightClickNrTable.put(player.getUniqueID(), rightClickNr); + + if (rightClickNr == 1) { + //If clicking in air, reset and try again + if (blockPos == null) { + rightClickNrTable.put(player.getUniqueID(), 0); + return list; + } + + //First click, remember starting position + firstPosTable.put(player.getUniqueID(), blockPos); + sideHitTable.put(player.getUniqueID(), sideHit); + hitVecTable.put(player.getUniqueID(), hitVec); + //Keep list empty, dont place any blocks yet + } else { + //Second click, place wall + + list = findCoordinates(player, blockPos); + rightClickNrTable.put(player.getUniqueID(), 0); + } + + return list; } @Override public List findCoordinates(EntityPlayer player, BlockPos blockPos) { - return new ArrayList<>(); + List list = new ArrayList<>(); + int rightClickNr = rightClickNrTable.get(player.getUniqueID()); + BlockPos firstPos = firstPosTable.get(player.getUniqueID()); + + if (rightClickNr == 0) { + if (blockPos != null) + list.add(blockPos); + } else { + Vec3d look = player.getLookVec(); + Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ); + + + + //try on x axis + double x = firstPos.getX(); + + //then y and z are + double y = (x - start.x) / look.x * look.y + start.y; + double z = (x - start.x) / look.x * look.z + start.z; + + Vec3d xBound = new Vec3d(x, y, z); + Vec3d xBoundLine = toLongestLine(xBound, firstPos); + double xDistToLine = xBoundLine.subtract(xBound).lengthSquared(); + + //distance to player + double xDistSquared = xBound.subtract(start).lengthSquared(); + + + + //try on y axis + y = firstPos.getY(); + + //then x and z are + x = (y - start.y) / look.y * look.x + start.x; + z = (y - start.y) / look.y * look.z + start.z; + + Vec3d yBound = new Vec3d(x, y, z); + Vec3d yBoundLine = toLongestLine(yBound, firstPos); + double yDistToLine = yBoundLine.subtract(yBound).lengthSquared(); + + //distance to player + double yDistSquared = yBound.subtract(start).lengthSquared(); + + + + //try on z axis + z = firstPos.getZ(); + + //then x and y are + x = (z - start.z) / look.z * look.x + start.x; + y = (z - start.z) / look.z * look.y + start.y; + + Vec3d zBound = new Vec3d(x, y, z); + Vec3d zBoundLine = toLongestLine(zBound, firstPos); + double zDistToLine = zBoundLine.subtract(zBound).lengthSquared(); + + //distance to player + double zDistSquared = zBound.subtract(start).lengthSquared(); + + + + int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach + + //check if its not behind the player and its not too close and not too far + boolean xValid = xBound.subtract(start).dotProduct(look) > 0 && + xDistSquared > 4 && xDistSquared < reach * reach; + + boolean yValid = yBound.subtract(start).dotProduct(look) > 0 && + yDistSquared > 4 && yDistSquared < reach * reach; + + boolean zValid = zBound.subtract(start).dotProduct(look) > 0 && + zDistSquared > 4 && zDistSquared < reach * reach; + + //select the one that is closest (from wall position to its line counterpart) and is valid + Vec3d selected = null; + double selectedDistToLine = 0; + + if (xValid) { + selected = xBoundLine; + selectedDistToLine = xDistToLine; + } else if (yValid) { + selected = yBoundLine; + selectedDistToLine = yDistToLine; + } else if (zValid) { + selected = zBoundLine; + selectedDistToLine = yDistToLine; + } + + if (yValid && yDistToLine < selectedDistToLine) selected = yBoundLine; + if (zValid && zDistToLine < selectedDistToLine) selected = zBoundLine; + + if (selected == null) return list; + + //TODO check if it doesnt go through blocks + RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, selected, false, false, false); + if (rayTraceResult != null && rayTraceResult.typeOfHit != RayTraceResult.Type.BLOCK) { + //return empty list + return list; + } + + BlockPos secondPos = new BlockPos(selected); + + //Add whole line + + int x1 = firstPos.getX(), x2 = secondPos.getX(); + int y1 = firstPos.getY(), y2 = secondPos.getY(); + int z1 = firstPos.getZ(), z2 = secondPos.getZ(); + + for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { + + for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { + + for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { + list.add(new BlockPos(l, m, n)); + } + } + } + } + + return list; + } + + //Make it into a line + //Select the axis that is longest + private Vec3d toLongestLine(Vec3d boundVec, BlockPos firstPos) { + BlockPos bound = new BlockPos(boundVec); + + BlockPos firstToSecond = bound.subtract(firstPos); + firstToSecond = new BlockPos(Math.abs(firstToSecond.getX()), Math.abs(firstToSecond.getY()), Math.abs(firstToSecond.getZ())); + int longest = Math.max(firstToSecond.getX(), Math.max(firstToSecond.getY(), firstToSecond.getZ())); + if (longest == firstToSecond.getX()) { + return new Vec3d(bound.getX(), firstPos.getY(), firstPos.getZ()); + } + if (longest == firstToSecond.getY()) { + return new Vec3d(firstPos.getX(), bound.getY(), firstPos.getZ()); + } + if (longest == firstToSecond.getZ()) { + return new Vec3d(firstPos.getX(), firstPos.getY(), bound.getZ()); + } + return null; } @Override public EnumFacing getSideHit(EntityPlayer player) { - return null; + return sideHitTable.get(player.getUniqueID()); } @Override public Vec3d getHitVec(EntityPlayer player) { - return null; + return hitVecTable.get(player.getUniqueID()); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/SlopeFloor.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/SlopeFloor.java new file mode 100644 index 0000000..77f93e3 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/SlopeFloor.java @@ -0,0 +1,36 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +import java.util.ArrayList; +import java.util.List; + +public class SlopeFloor implements IBuildMode { + @Override + public void initialize(EntityPlayer player) { + + } + + @Override + public List onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) { + return new ArrayList<>(); + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos blockPos) { + return new ArrayList<>(); + } + + @Override + public EnumFacing getSideHit(EntityPlayer player) { + return null; + } + + @Override + public Vec3d getHitVec(EntityPlayer player) { + return null; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java index 88bc93f..62000ac 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java @@ -78,6 +78,9 @@ public class Wall implements IBuildMode { //distance to player double xDistSquared = xBound.subtract(start).lengthSquared(); + //angle to look + //double xAngle = xBound.subtract(new Vec3d(firstPos)).normalize().dotProduct(look); + //try on z axis z = firstPos.getZ(); @@ -90,7 +93,10 @@ public class Wall implements IBuildMode { //distance to player double zDistSquared = zBound.subtract(start).lengthSquared(); - int reach = ReachHelper.getMaxReach(player); //4 times as much as normal placement reach + //angle to look + //double zAngle = zBound.subtract(new Vec3d(firstPos)).normalize().dotProduct(look); + + int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach //check if its not behind the player and its not too close and not too far boolean xValid = xBound.subtract(start).dotProduct(look) > 0 && @@ -99,10 +105,13 @@ public class Wall implements IBuildMode { boolean zValid = zBound.subtract(start).dotProduct(look) > 0 && zDistSquared > 4 && zDistSquared < reach * reach; - //select the one that is closest to the player and is valid + //select the one that is closest and is valid Vec3d selected = null; - if (xValid) selected = xBound; - if (zValid && zDistSquared < xDistSquared) selected = zBound; + if (xValid) + selected = xBound; + else if (zValid) + selected = zBound; + if (zValid && zDistSquared < xDistSquared/*Math.abs(zAngle) < Math.abs(xAngle)*/) selected = zBound; if (selected == null) return list; diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java index 4fbf099..7b3811b 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java @@ -2,6 +2,7 @@ package nl.requios.effortlessbuilding.buildmodifier; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemBlock; @@ -18,6 +19,7 @@ import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.network.BlockBrokenMessage; +import nl.requios.effortlessbuilding.network.BlockPlacedMessage; import java.util.ArrayList; import java.util.Arrays; @@ -53,6 +55,9 @@ public class BuildModifiers { SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, true, false); } } + + EffortlessBuilding.packetHandler.sendTo(new BlockPlacedMessage(), ((EntityPlayerMP) player)); + } public static void onBlockBroken(EntityPlayer player, List posList) { @@ -117,13 +122,13 @@ public class BuildModifiers { ItemStack itemBlock = ItemStack.EMPTY; if (itemStack.getItem() instanceof ItemBlock) itemBlock = itemStack; ItemRandomizerBag.resetRandomness(); - if (itemStack.getItem() instanceof ItemRandomizerBag) itemBlock = ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(itemStack)); //Add blocks in posList first for (BlockPos blockPos : posList) { + if (itemStack.getItem() instanceof ItemRandomizerBag) itemBlock = ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(itemStack)); IBlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, EnumHand.MAIN_HAND); blockStates.add(blockState); - itemStacks.add(itemStack); + itemStacks.add(itemBlock); } for (BlockPos blockPos : posList) { diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java index 7fbc1c5..66e1d69 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java @@ -1,9 +1,9 @@ package nl.requios.effortlessbuilding.gui.buildmode; -import java.io.IOException; import java.util.ArrayList; import java.util.concurrent.TimeUnit; +import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.proxy.ClientProxy; import org.lwjgl.opengl.GL11; @@ -25,8 +25,7 @@ import static nl.requios.effortlessbuilding.buildmode.BuildModes.*; * From Chisels and Bits by AlgorithmX2 * https://github.com/AlgorithmX2/Chisels-and-Bits/blob/1.12/src/main/java/mod/chiselsandbits/client/gui/ChiselsAndBitsMenu.java */ -public class RadialMenu extends GuiScreen -{ +public class RadialMenu extends GuiScreen { private final float TIME_SCALE = 0.01f; public static final RadialMenu instance = new RadialMenu(); @@ -37,41 +36,32 @@ public class RadialMenu extends GuiScreen //public ButtonAction doAction = null; public boolean actionUsed = false; - private float clampVis( - final float f ) - { + private float clampVis(final float f) { return Math.max( 0.0f, Math.min( 1.0f, f ) ); } - public void raiseVisibility() - { + public void raiseVisibility() { visibility = clampVis( visibility + lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE ); lastChange = Stopwatch.createStarted(); } - public void decreaseVisibility() - { + public void decreaseVisibility() { visibility = clampVis( visibility - lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE ); lastChange = Stopwatch.createStarted(); } - public boolean isVisible() - { + public boolean isVisible() { return visibility > 0.001; } - public void configure( - final int scaledWidth, - final int scaledHeight ) - { + public void configure(final int scaledWidth, final int scaledHeight ) { mc = Minecraft.getMinecraft(); fontRenderer = mc.fontRenderer; width = scaledWidth; height = scaledHeight; } - private static class MenuButton - { + private static class MenuButton { public double x1, x2; public double y1, y2; @@ -83,14 +73,8 @@ public class RadialMenu extends GuiScreen public String name; public EnumFacing textSide; - public MenuButton( - final String name, - //final ButtonAction action, - final double x, - final double y, - final TextureAtlasSprite ico, - final EnumFacing textSide ) - { + public MenuButton(final String name, /*final ButtonAction action,*/ final double x, final double y, + final TextureAtlasSprite ico, final EnumFacing textSide) { this.name = name; //this.action = action; x1 = x; @@ -102,14 +86,8 @@ public class RadialMenu extends GuiScreen this.textSide = textSide; } - public MenuButton( - final String name, - //final ButtonAction action, - final double x, - final double y, - final int col, - final EnumFacing textSide ) - { + public MenuButton(final String name, /*final ButtonAction action,*/ final double x, final double y, + final int col, final EnumFacing textSide) { this.name = name; //this.action = action; x1 = x; @@ -122,38 +100,21 @@ public class RadialMenu extends GuiScreen } - static class MenuRegion - { + static class MenuRegion { public final BuildModeEnum mode; public double x1, x2; public double y1, y2; public boolean highlighted; - public MenuRegion( - final BuildModeEnum mode ) - { + public MenuRegion(final BuildModeEnum mode) { this.mode = mode; } } - public static class SpriteIconPositioning - { - public TextureAtlasSprite sprite; - - public double left; - public double top; - public double width; - public double height; - } - @Override - public void drawScreen( - final int mouseX, - final int mouseY, - final float partialTicks ) - { + public void drawScreen(final int mouseX, final int mouseY, final float partialTicks) { //TODO chisels compat // final ChiselToolType tool = ClientSide.instance.getHeldToolType( EnumHand.MAIN_HAND ); // @@ -165,172 +126,173 @@ public class RadialMenu extends GuiScreen GlStateManager.pushMatrix(); GlStateManager.translate( 0.0F, 0.0F, 200.0F ); - final int start = (int) ( visibility * 98 ) << 24; - final int end = (int) ( visibility * 128 ) << 24; + final int startColor = (int) ( visibility * 98 ) << 24; + final int endColor = (int) ( visibility * 128 ) << 24; - drawGradientRect( 0, 0, width, height, start, end ); + drawGradientRect(0, 0, width, height, startColor, endColor); GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); GlStateManager.disableAlpha(); - GlStateManager.tryBlendFuncSeparate( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0 ); - GlStateManager.shadeModel( GL11.GL_SMOOTH ); + GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + GlStateManager.shadeModel(GL11.GL_SMOOTH); final Tessellator tessellator = Tessellator.getInstance(); final BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); - final double vecX = mouseX - width / 2; - final double vecY = mouseY - height / 2; - double radians = Math.atan2( vecY, vecX ); + final double middleX = width / 2.0; + final double middleY = height / 2.0; - final double ring_inner_edge = 20; - final double ring_outer_edge = 50; - final double text_distnace = 65; + final double mouseXCenter = mouseX - middleX; + final double mouseYCenter = mouseY - middleY; + double mouseRadians = Math.atan2(mouseYCenter, mouseXCenter); + + final double ringInnerEdge = 20; + final double ringOuterEdge = 50; + final double textDistance = 65; final double quarterCircle = Math.PI / 2.0; - if ( radians < -quarterCircle ) - { - radians = radians + Math.PI * 2; + if ( mouseRadians < -quarterCircle ) { + mouseRadians = mouseRadians + Math.PI * 2; } - final double middle_x = width / 2; - final double middle_y = height / 2; - final ArrayList modes = new ArrayList(); - final ArrayList btns = new ArrayList(); + final ArrayList buttons = new ArrayList(); -// btns.add( new MenuButton( "mod.chiselsandbits.other.undo", ButtonAction.UNDO, text_distnace, -20, ClientSide.undoIcon, EnumFacing.EAST ) ); -// btns.add( new MenuButton( "mod.chiselsandbits.other.redo", ButtonAction.REDO, text_distnace, 4, ClientSide.redoIcon, EnumFacing.EAST ) ); +// buttons.add( new MenuButton( "mod.chiselsandbits.other.undo", ButtonAction.UNDO, textDistance, -20, ClientSide.undoIcon, EnumFacing.EAST ) ); +// buttons.add( new MenuButton( "mod.chiselsandbits.other.redo", ButtonAction.REDO, textDistance, 4, ClientSide.redoIcon, EnumFacing.EAST ) ); - for ( final BuildModeEnum mode : BuildModeEnum.values() ) - { - modes.add( new MenuRegion( mode ) ); + for (final BuildModeEnum mode : BuildModeEnum.values()) { + modes.add(new MenuRegion(mode)); } switchTo = null; //doAction = null; - if ( !modes.isEmpty() ) - { + if (!modes.isEmpty()) { final int totalModes = Math.max( 3, modes.size() ); int currentMode = 0; final double fragment = Math.PI * 0.005; final double fragment2 = Math.PI * 0.0025; final double perObject = 2.0 * Math.PI / totalModes; - for ( final MenuRegion mnuRgn : modes ) - { - final double begin_rad = currentMode * perObject - quarterCircle; - final double end_rad = ( currentMode + 1 ) * perObject - quarterCircle; + for (int i = 0; i < modes.size(); i++) { + MenuRegion menuRegion = modes.get(i); + final double beginRadians = currentMode * perObject - quarterCircle; + final double endRadians = (currentMode + 1) * perObject - quarterCircle; - mnuRgn.x1 = Math.cos( begin_rad ); - mnuRgn.x2 = Math.cos( end_rad ); - mnuRgn.y1 = Math.sin( begin_rad ); - mnuRgn.y2 = Math.sin( end_rad ); + menuRegion.x1 = Math.cos(beginRadians); + menuRegion.x2 = Math.cos(endRadians); + menuRegion.y1 = Math.sin(beginRadians); + menuRegion.y2 = Math.sin(endRadians); - final double x1m1 = Math.cos( begin_rad + fragment ) * ring_inner_edge; - final double x2m1 = Math.cos( end_rad - fragment ) * ring_inner_edge; - final double y1m1 = Math.sin( begin_rad + fragment ) * ring_inner_edge; - final double y2m1 = Math.sin( end_rad - fragment ) * ring_inner_edge; + final double x1m1 = Math.cos(beginRadians + fragment) * ringInnerEdge; + final double x2m1 = Math.cos(endRadians - fragment) * ringInnerEdge; + final double y1m1 = Math.sin(beginRadians + fragment) * ringInnerEdge; + final double y2m1 = Math.sin(endRadians - fragment) * ringInnerEdge; - final double x1m2 = Math.cos( begin_rad + fragment2 ) * ring_outer_edge; - final double x2m2 = Math.cos( end_rad - fragment2 ) * ring_outer_edge; - final double y1m2 = Math.sin( begin_rad + fragment2 ) * ring_outer_edge; - final double y2m2 = Math.sin( end_rad - fragment2 ) * ring_outer_edge; + final double x1m2 = Math.cos(beginRadians + fragment2) * ringOuterEdge; + final double x2m2 = Math.cos(endRadians - fragment2) * ringOuterEdge; + final double y1m2 = Math.sin(beginRadians + fragment2) * ringOuterEdge; + final double y2m2 = Math.sin(endRadians - fragment2) * ringOuterEdge; - final float a = 0.5f; - float f = 0f; + float r = 0.0f; + float g = 0.0f; + float b = 0.0f; + float a = 0.5f; - final boolean quad = inTriangle( - x1m1, y1m1, - x2m2, y2m2, - x2m1, y2m1, - vecX, vecY ) || inTriangle( - x1m1, y1m1, - x1m2, y1m2, - x2m2, y2m2, - vecX, vecY ); - - if ( begin_rad <= radians && radians <= end_rad && quad ) - { - f = 1; - mnuRgn.highlighted = true; - switchTo = mnuRgn.mode; + //check if current mode + int buildMode = ModeSettingsManager.getModeSettings(Minecraft.getMinecraft().player).getBuildMode().ordinal(); + if (buildMode == i) { + r = 0f; + g = 0.5f; + b = 1f; + a = 0.5f; + //menuRegion.highlighted = true; //draw text } - buffer.pos( middle_x + x1m1, middle_y + y1m1, zLevel ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + x2m1, middle_y + y2m1, zLevel ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + x2m2, middle_y + y2m2, zLevel ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + x1m2, middle_y + y1m2, zLevel ).color( f, f, f, a ).endVertex(); + //check if mouse is over this region + final boolean isMouseInQuad = inTriangle(x1m1, y1m1, x2m2, y2m2, x2m1, y2m1, mouseXCenter, mouseYCenter) + || inTriangle(x1m1, y1m1, x1m2, y1m2, x2m2, y2m2, mouseXCenter, mouseYCenter); + + if (beginRadians <= mouseRadians && mouseRadians <= endRadians && isMouseInQuad) { + r = 0.6f;//0.6f; + g = 0.8f;//0.3f; + b = 1f;//0.0f; + a = 0.6f; + menuRegion.highlighted = true; + switchTo = menuRegion.mode; + } + + buffer.pos(middleX + x1m1, middleY + y1m1, zLevel).color(r, g, b, a).endVertex(); + buffer.pos(middleX + x2m1, middleY + y2m1, zLevel).color(r, g, b, a).endVertex(); + buffer.pos(middleX + x2m2, middleY + y2m2, zLevel).color(r, g, b, a).endVertex(); + buffer.pos(middleX + x1m2, middleY + y1m2, zLevel).color(r, g, b, a).endVertex(); currentMode++; } } - for ( final MenuButton btn : btns ) - { + for (final MenuButton btn : buttons) { final float a = 0.5f; float f = 0f; - if ( btn.x1 <= vecX && btn.x2 >= vecX && btn.y1 <= vecY && btn.y2 >= vecY ) - { + if (btn.x1 <= mouseXCenter && btn.x2 >= mouseXCenter && btn.y1 <= mouseYCenter && btn.y2 >= mouseYCenter) { f = 1; btn.highlighted = true; //doAction = btn.action; } - buffer.pos( middle_x + btn.x1, middle_y + btn.y1, zLevel ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + btn.x1, middle_y + btn.y2, zLevel ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + btn.x2, middle_y + btn.y2, zLevel ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + btn.x2, middle_y + btn.y1, zLevel ).color( f, f, f, a ).endVertex(); + buffer.pos(middleX + btn.x1, middleY + btn.y1, zLevel).color(f, f, f, a).endVertex(); + buffer.pos(middleX + btn.x1, middleY + btn.y2, zLevel).color(f, f, f, a).endVertex(); + buffer.pos(middleX + btn.x2, middleY + btn.y2, zLevel).color(f, f, f, a).endVertex(); + buffer.pos(middleX + btn.x2, middleY + btn.y1, zLevel).color(f, f, f, a).endVertex(); } tessellator.draw(); - GlStateManager.shadeModel( GL11.GL_FLAT ); + GlStateManager.shadeModel(GL11.GL_FLAT); - GlStateManager.translate( 0.0F, 0.0F, 5.0F ); + GlStateManager.translate(0f, 0f, 5f); GlStateManager.enableTexture2D(); - GlStateManager.color( 1, 1, 1, 1.0f ); + GlStateManager.color(1f, 1f, 1f, 1f); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); - GlStateManager.bindTexture( Minecraft.getMinecraft().getTextureMapBlocks().getGlTextureId() ); + GlStateManager.bindTexture(Minecraft.getMinecraft().getTextureMapBlocks().getGlTextureId()); - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); - for ( final MenuRegion mnuRgn : modes ) - { - final double x = ( mnuRgn.x1 + mnuRgn.x2 ) * 0.5 * ( ring_outer_edge * 0.6 + 0.4 * ring_inner_edge ); - final double y = ( mnuRgn.y1 + mnuRgn.y2 ) * 0.5 * ( ring_outer_edge * 0.6 + 0.4 * ring_inner_edge ); + for (final MenuRegion mnuRgn : modes) { - final SpriteIconPositioning sip = ClientProxy.getBuildModeIcon(mnuRgn.mode); + final double x = (mnuRgn.x1 + mnuRgn.x2) * 0.5 * (ringOuterEdge * 0.6 + 0.4 * ringInnerEdge); + final double y = (mnuRgn.y1 + mnuRgn.y2) * 0.5 * (ringOuterEdge * 0.6 + 0.4 * ringInnerEdge); - final double scalex = 15 * sip.width * 0.5; - final double scaley = 15 * sip.height * 0.5; + final TextureAtlasSprite sprite = ClientProxy.getBuildModeIcon(mnuRgn.mode); + + final double scalex = 16 * 0.5; + final double scaley = 16 * 0.5; final double x1 = x - scalex; final double x2 = x + scalex; final double y1 = y - scaley; final double y2 = y + scaley; - final TextureAtlasSprite sprite = sip.sprite; + final float f = 1f; + final float a = 1f; - final float f = 1.0f; - final float a = 1.0f; + final double u1 = 0f; + final double u2 = 16f; + final double v1 = 0f; + final double v2 = 16f; - final double u1 = sip.left * 16.0; - final double u2 = ( sip.left + sip.width ) * 16.0; - final double v1 = sip.top * 16.0; - final double v2 = ( sip.top + sip.height ) * 16.0; - - buffer.pos( middle_x + x1, middle_y + y1, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v1 ) ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + x1, middle_y + y2, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v2 ) ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + x2, middle_y + y2, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v2 ) ).color( f, f, f, a ).endVertex(); - buffer.pos( middle_x + x2, middle_y + y1, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v1 ) ).color( f, f, f, a ).endVertex(); + buffer.pos(middleX + x1, middleY + y1, zLevel).tex( sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v1)).color(f, f, f, a).endVertex(); + buffer.pos(middleX + x1, middleY + y2, zLevel).tex( sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v2)).color(f, f, f, a).endVertex(); + buffer.pos(middleX + x2, middleY + y2, zLevel).tex( sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v2)).color(f, f, f, a).endVertex(); + buffer.pos(middleX + x2, middleY + y1, zLevel).tex( sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v1)).color(f, f, f, a).endVertex(); } - for ( final MenuButton btn : btns ) - { + for (final MenuButton btn : buttons) { + final float f = switchTo == null ? 1.0f : 0.5f; final float a = 1.0f; @@ -339,70 +301,69 @@ public class RadialMenu extends GuiScreen final double v1 = 0; final double v2 = 16; - final TextureAtlasSprite sprite = btn.icon == null ? Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( ModelLoader.White.LOCATION.toString() ) : btn.icon; + final TextureAtlasSprite sprite = btn.icon == null ? Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(ModelLoader.White.LOCATION.toString()) : btn.icon; final double btnx1 = btn.x1 + 1; final double btnx2 = btn.x2 - 1; final double btny1 = btn.y1 + 1; final double btny2 = btn.y2 - 1; - final float red = f * ( ( btn.color >> 16 & 0xff ) / 255.0f ); - final float green = f * ( ( btn.color >> 8 & 0xff ) / 255.0f ); - final float blue = f * ( ( btn.color & 0xff ) / 255.0f ); + final float red = f * ((btn.color >> 16 & 0xff) / 255.0f); + final float green = f * ((btn.color >> 8 & 0xff) / 255.0f); + final float blue = f * ((btn.color & 0xff) / 255.0f); - buffer.pos( middle_x + btnx1, middle_y + btny1, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v1 ) ).color( red, green, blue, a ).endVertex(); - buffer.pos( middle_x + btnx1, middle_y + btny2, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v2 ) ).color( red, green, blue, a ).endVertex(); - buffer.pos( middle_x + btnx2, middle_y + btny2, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v2 ) ).color( red, green, blue, a ).endVertex(); - buffer.pos( middle_x + btnx2, middle_y + btny1, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v1 ) ).color( red, green, blue, a ).endVertex(); + buffer.pos(middleX + btnx1, middleY + btny1, zLevel).tex(sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v1)).color(red, green, blue, a).endVertex(); + buffer.pos(middleX + btnx1, middleY + btny2, zLevel).tex(sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v2)).color(red, green, blue, a).endVertex(); + buffer.pos(middleX + btnx2, middleY + btny2, zLevel).tex(sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v2)).color(red, green, blue, a).endVertex(); + buffer.pos(middleX + btnx2, middleY + btny1, zLevel).tex(sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v1)).color(red, green, blue, a).endVertex(); } tessellator.draw(); - for ( final MenuRegion mnuRgn : modes ) - { - if ( mnuRgn.highlighted ) - { - final double x = ( mnuRgn.x1 + mnuRgn.x2 ) * 0.5; - final double y = ( mnuRgn.y1 + mnuRgn.y2 ) * 0.5; + for (final MenuRegion mnuRgn : modes) { - int fixed_x = (int) ( x * text_distnace ); - final int fixed_y = (int) ( y * text_distnace ); + if (mnuRgn.highlighted) { + final double x = (mnuRgn.x1 + mnuRgn.x2) * 0.5; + final double y = (mnuRgn.y1 + mnuRgn.y2) * 0.5; + + int fixed_x = (int) (x * textDistance); + final int fixed_y = (int) (y * textDistance); final String text = mnuRgn.mode.name; - if ( x <= -0.2 ) - { - fixed_x -= fontRenderer.getStringWidth( text ); - } - else if ( -0.2 <= x && x <= 0.2 ) - { - fixed_x -= fontRenderer.getStringWidth( text ) / 2; + if ( x <= -0.2 ) { + fixed_x -= fontRenderer.getStringWidth(text); + } else if ( -0.2 <= x && x <= 0.2 ) { + fixed_x -= fontRenderer.getStringWidth(text) / 2; } - fontRenderer.drawStringWithShadow( text, (int) middle_x + fixed_x, (int) middle_y + fixed_y, 0xffffffff ); + fontRenderer.drawStringWithShadow(text, (int) middleX + fixed_x, (int) middleY + fixed_y, 0xffffffff); } } - for ( final MenuButton btn : btns ) - { - if ( btn.highlighted ) - { + for (final MenuButton btn : buttons) { + if (btn.highlighted) { final String text = btn.name; - if ( btn.textSide == EnumFacing.WEST ) - { - fontRenderer.drawStringWithShadow( text, (int) ( middle_x + btn.x1 - 8 ) - fontRenderer.getStringWidth( text ), (int) ( middle_y + btn.y1 + 6 ), 0xffffffff ); - } - else if ( btn.textSide == EnumFacing.EAST ) - { - fontRenderer.drawStringWithShadow( text, (int) ( middle_x + btn.x2 + 8 ), (int) ( middle_y + btn.y1 + 6 ), 0xffffffff ); - } - else if ( btn.textSide == EnumFacing.UP ) - { - fontRenderer.drawStringWithShadow( text, (int) ( middle_x + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ), (int) ( middle_y + btn.y1 - 14 ), 0xffffffff ); - } - else if ( btn.textSide == EnumFacing.DOWN ) - { - fontRenderer.drawStringWithShadow( text, (int) ( middle_x + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ), (int) ( middle_y + btn.y1 + 24 ), 0xffffffff ); + if (btn.textSide == EnumFacing.WEST) { + + fontRenderer.drawStringWithShadow( text, (int) ( middleX + btn.x1 - 8 ) - fontRenderer.getStringWidth( text ), + (int) ( middleY + btn.y1 + 6 ), 0xffffffff ); + + } else if (btn.textSide == EnumFacing.EAST) { + + fontRenderer.drawStringWithShadow( text, (int) ( middleX + btn.x2 + 8 ), + (int) ( middleY + btn.y1 + 6 ), 0xffffffff ); + + } else if (btn.textSide == EnumFacing.UP) { + + fontRenderer.drawStringWithShadow( text, (int) ( middleX + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ), + (int) ( middleY + btn.y1 - 14 ), 0xffffffff ); + + } else if (btn.textSide == EnumFacing.DOWN) { + + fontRenderer.drawStringWithShadow( text, (int) ( middleX + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ), + (int) ( middleY + btn.y1 + 24 ), 0xffffffff ); + } } @@ -411,42 +372,26 @@ public class RadialMenu extends GuiScreen GlStateManager.popMatrix(); } - private boolean inTriangle( - final double x1, - final double y1, - final double x2, - final double y2, - final double x3, - final double y3, - final double x, - final double y ) - { - final double ab = ( x1 - x ) * ( y2 - y ) - ( x2 - x ) * ( y1 - y ); - final double bc = ( x2 - x ) * ( y3 - y ) - ( x3 - x ) * ( y2 - y ); - final double ca = ( x3 - x ) * ( y1 - y ) - ( x1 - x ) * ( y3 - y ); - return sign( ab ) == sign( bc ) && sign( bc ) == sign( ca ); + private boolean inTriangle(final double x1, final double y1, final double x2, final double y2, + final double x3, final double y3, final double x, final double y ) { + final double ab = (x1 - x) * (y2 - y) - (x2 - x) * (y1 - y); + final double bc = (x2 - x) * (y3 - y) - (x3 - x) * (y2 - y); + final double ca = (x3 - x) * (y1 - y) - (x1 - x) * (y3 - y); + return sign(ab) == sign(bc) && sign(bc) == sign(ca); } - private int sign( - final double n ) - { + private int sign(final double n) { return n > 0 ? 1 : -1; } /** * Called when the mouse is clicked. Args : mouseX, mouseY, clickedButton */ - protected void mouseClicked( - int mouseX, - int mouseY, - int mouseButton ) throws IOException - { - if ( mouseButton == 0 ) - { - this.mc.displayGuiScreen( (GuiScreen) null ); + protected void mouseClicked(int mouseX, int mouseY, int mouseButton ) { + if (mouseButton == 0) { + this.mc.displayGuiScreen(null); - if ( this.mc.currentScreen == null ) - { + if (this.mc.currentScreen == null) { this.mc.setIngameFocus(); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/helper/RenderHelper.java b/src/main/java/nl/requios/effortlessbuilding/helper/RenderHelper.java deleted file mode 100644 index a4741cd..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/helper/RenderHelper.java +++ /dev/null @@ -1,544 +0,0 @@ -package nl.requios.effortlessbuilding.helper; - -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.util.EnumFacing; -import net.minecraft.util.ResourceLocation; -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; -import net.minecraftforge.fml.relauncher.Side; -import nl.requios.effortlessbuilding.BuildConfig; -import nl.requios.effortlessbuilding.EffortlessBuilding; -import nl.requios.effortlessbuilding.buildmode.BuildModes; -import nl.requios.effortlessbuilding.buildmode.IBuildMode; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; -import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; -import nl.requios.effortlessbuilding.buildmodifier.Mirror; -import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; -import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; -import nl.requios.effortlessbuilding.item.ItemRandomizerBag; -import nl.requios.effortlessbuilding.proxy.ClientProxy; -import org.lwjgl.opengl.ARBMultitexture; -import org.lwjgl.opengl.ARBShaderObjects; -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.Collections; -import java.util.List; -import java.util.function.Consumer; - -@Mod.EventBusSubscriber(Side.CLIENT) -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); - private static final Color colorZ = new Color(52, 247, 255); - private static final Color colorRadial = new Color(52, 247, 255); - private static final int lineAlpha = 200; - private static final int planeAlpha = 75; - private static final Vec3d epsilon = new Vec3d(0.001, 0.001, 0.001); //prevents z-fighting - - private static List previousCoordinates; - - private static final int secondaryTextureUnit = 7; - - private static void begin(float partialTicks) { - EntityPlayer player = Minecraft.getMinecraft().player; - double playerX = player.prevPosX + (player.posX - player.prevPosX) * partialTicks; - double playerY = player.prevPosY + (player.posY - player.prevPosY) * partialTicks; - double playerZ = player.prevPosZ + (player.posZ - player.prevPosZ) * partialTicks; - Vec3d playerPos = new Vec3d(playerX, playerY, playerZ); - - GL11.glPushMatrix(); - GL11.glTranslated(-playerPos.x, -playerPos.y, -playerPos.z); - - GL11.glDepthMask(false); - } - - private static void beginLines() { - GL11.glPushAttrib(GL11.GL_ENABLE_BIT); - GL11.glDisable(GL11.GL_CULL_FACE); - GL11.glDisable(GL11.GL_LIGHTING); - GL11.glDisable(GL11.GL_TEXTURE_2D); - - GL11.glEnable(GL11.GL_BLEND); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - - GL11.glLineWidth(2); - } - - private static void endLines() { - GL11.glPopAttrib(); - } - - private static void beginBlockPreviews() { - GL11.glPushAttrib(GL11.GL_ENABLE_BIT); - GL11.glEnable(GL11.GL_CULL_FACE); - GL11.glEnable(GL11.GL_TEXTURE_2D); - Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_color.png")); - Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")); - - Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); - GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GL14.glBlendColor(1F, 1F, 1F, 0.8f); - } - - private static void endBlockPreviews() { - ShaderHelper.releaseShader(); - GlStateManager.disableBlend(); - GL11.glPopAttrib(); - } - - private static void end() { - GL11.glDepthMask(true); - GL11.glPopMatrix(); - } - - private static void renderBlockPreview(BlockRendererDispatcher dispatcher, BlockPos blockPos, IBlockState blockState) { - GlStateManager.pushMatrix(); - GlStateManager.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - 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, 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; - ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - - begin(event.getPartialTicks()); - - beginLines(); - //Mirror lines and areas - Mirror.MirrorSettings m = modifierSettings.getMirrorSettings(); - if (m != null && m.enabled && (m.mirrorX || m.mirrorY || m.mirrorZ)) - { - Vec3d pos = m.position.add(epsilon); - int radius = m.radius; - - if (m.mirrorX) - { - Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z - radius); - Vec3d posB = new Vec3d(pos.x, pos.y + radius, pos.z + radius); - - drawMirrorPlane(posA, posB, colorX, m.drawLines, m.drawPlanes, true); - } - if (m.mirrorY) - { - Vec3d posA = new Vec3d(pos.x - radius, pos.y, pos.z - radius); - Vec3d posB = new Vec3d(pos.x + radius, pos.y, pos.z + radius); - - drawMirrorPlaneY(posA, posB, colorY, m.drawLines, m.drawPlanes); - } - if (m.mirrorZ) - { - Vec3d posA = new Vec3d(pos.x - radius, pos.y - radius, pos.z); - Vec3d posB = new Vec3d(pos.x + radius, pos.y + radius, pos.z); - - drawMirrorPlane(posA, posB, colorZ, m.drawLines, m.drawPlanes, true); - } - - //Draw axis coordinated colors if two or more axes are enabled - //(If only one is enabled the lines are that planes color) - if (m.drawLines && ((m.mirrorX && m.mirrorY) || (m.mirrorX && m.mirrorZ) || (m.mirrorY && m.mirrorZ))) - { - drawMirrorLines(m); - } - } - - //Radial mirror lines and areas - RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings(); - if (r != null && r.enabled) - { - Vec3d pos = r.position.add(epsilon); - int radius = r.radius; - - float angle = 2f * ((float) Math.PI) / r.slices; - Vec3d relStartVec = new Vec3d(radius, 0, 0); - if (r.slices%4 == 2) relStartVec = relStartVec.rotateYaw(angle / 2f); - - for (int i = 0; i < r.slices; i++) { - Vec3d relNewVec = relStartVec.rotateYaw(angle * i); - Vec3d newVec = pos.add(relNewVec); - - Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z); - Vec3d posB = new Vec3d(newVec.x, pos.y + radius, newVec.z); - drawMirrorPlane(posA, posB, colorRadial, r.drawLines, r.drawPlanes, false); - } - } - endLines(); - - //Render block previews - RayTraceResult lookingAt = ClientProxy.getLookingAt(player); - if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.Normal) lookingAt = Minecraft.getMinecraft().objectMouseOver; - - ItemStack mainhand = player.getHeldItemMainhand(); - boolean toolInHand = !(!mainhand.isEmpty() && (mainhand.getItem() instanceof ItemBlock || mainhand.getItem() instanceof ItemRandomizerBag)); - - BlockPos startPos = null; - EnumFacing sideHit = null; - Vec3d hitVec = null; - - //Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS) - if (lookingAt != null && lookingAt.typeOfHit == RayTraceResult.Type.BLOCK) { - startPos = lookingAt.getBlockPos(); - - //Check if tool (or none) in hand - boolean replaceable = player.world.getBlockState(startPos).getBlock().isReplaceable(player.world, startPos); - if (!modifierSettings.doQuickReplace() && !toolInHand && !replaceable) { - startPos = startPos.offset(lookingAt.sideHit); - } - - //Get under tall grass and other replaceable blocks - if (modifierSettings.doQuickReplace() && !toolInHand && replaceable) { - startPos = startPos.down(); - } - - sideHit = lookingAt.sideHit; - hitVec = lookingAt.hitVec; - } - - //Dont render if in normal mode and modifiers are disabled - //Unless alwaysShowBlockPreview is true in config - if (modeSettings.getBuildMode() != BuildModes.BuildModeEnum.Normal || - (startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) || - BuildConfig.visuals.alwaysShowBlockPreview) { - - beginBlockPreviews(); - - IBuildMode buildModeInstance = modeSettings.getBuildMode().instance; - if (buildModeInstance.getSideHit(player) != null) sideHit = buildModeInstance.getSideHit(player); - if (buildModeInstance.getHitVec(player) != null) hitVec = buildModeInstance.getHitVec(player); - - if (sideHit != null) { - BlockRendererDispatcher dispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher(); - float percentile = ClientProxy.ticksInGame / 50f % 1f; - //TODO test - percentile = 1f; - - //get coordinates - List startCoordinates = BuildModes.findCoordinates(player, startPos); - - BlockPos firstPos = BlockPos.ORIGIN, secondPos = BlockPos.ORIGIN; - //remember first and last pos for highlighting - if (!startCoordinates.isEmpty()) { - firstPos = startCoordinates.get(0); - secondPos = startCoordinates.get(startCoordinates.size() - 1); - } - - //Limit number of blocks you can place - int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player); - if (startCoordinates.size() > limit) { - startCoordinates = startCoordinates.subList(0, limit); - } - - List newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates); - - Collections.sort(newCoordinates, (lhs, rhs) -> { - // -1 - less than, 1 - greater than, 0 - equal - double lhsDistanceToPlayer = new Vec3d(lhs).subtract(player.getPositionEyes(1f)).lengthSquared(); - double rhsDistanceToPlayer = new Vec3d(rhs).subtract(player.getPositionEyes(1f)).lengthSquared(); - return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer); - }); - - //check if they are different from previous - if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) { - previousCoordinates = newCoordinates; - //if so, renew randomness of randomizer bag - ItemRandomizerBag.renewRandomness(); - } - - hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), - Math.abs(hitVec.z - ((int) hitVec.z))); - List itemStacks = new ArrayList<>(); - List blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, lookingAt.sideHit, itemStacks); - - //check if valid blockstates - if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) { - for (int i = newCoordinates.size() - 1; i >= 0; i--) { - BlockPos blockPos = newCoordinates.get(i); - IBlockState blockState = blockStates.get(i); - 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)) { - - ShaderHelper.useShader(ShaderHelper.dissolve, generateShaderCallback(percentile, - new Vec3d(blockPos), new Vec3d(firstPos), new Vec3d(secondPos), - /*blockPos == firstPos ||*/ blockPos == secondPos)); - renderBlockPreview(dispatcher, blockPos, blockState); - } - } - } - } - endBlockPreviews(); - - beginLines(); - //Draw outlines if tool in hand - //Find proper raytrace: either normal range or increased range depending on canBreakFar - RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver; - RayTraceResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver; - if (toolInHand && breakingRaytrace != null && breakingRaytrace.typeOfHit == RayTraceResult.Type.BLOCK) { - List breakCoordinates = BuildModifiers.findCoordinates(player, breakingRaytrace.getBlockPos()); - - //Only render first outline if further than normal reach - boolean excludeFirst = objectMouseOver != null && objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK; - for (int i = excludeFirst ? 1 : 0; i < breakCoordinates.size(); i++) { - BlockPos coordinate = breakCoordinates.get(i); - - IBlockState blockState = player.world.getBlockState(coordinate); - if (!blockState.getBlock().isAir(blockState, player.world, coordinate)) { - if (SurvivalHelper.canBreak(player.world, player, coordinate) || i == 0) { - renderBlockOutline(coordinate); - } - } - } - } - endLines(); - } - - end(); - } - - - //----Mirror---- - - public static void drawMirrorPlane(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes, boolean drawVerticalLines) { - - GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - - if (drawPlanes) { - bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); - - bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - bufferBuilder.pos(posA.x, posB.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - bufferBuilder.pos(posB.x, posB.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - - tessellator.draw(); - } - - if (drawLines) { - Vec3d middle = posA.add(posB).scale(0.5); - bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); - - bufferBuilder.pos(posA.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(posB.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - if (drawVerticalLines) { - bufferBuilder.pos(middle.x, posA.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(middle.x, posB.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - } - - tessellator.draw(); - } - } - - public static void drawMirrorPlaneY(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes) { - - GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - - if (drawPlanes) { - bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); - - bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - bufferBuilder.pos(posA.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - bufferBuilder.pos(posB.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); - - tessellator.draw(); - } - - if (drawLines) { - Vec3d middle = posA.add(posB).scale(0.5); - bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); - - bufferBuilder.pos(middle.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(middle.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(posA.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(posB.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); - - tessellator.draw(); - } - } - - public static void drawMirrorLines(Mirror.MirrorSettings m) { - - Vec3d pos = m.position.add(epsilon); - - GL11.glColor4d(100, 100, 100, 255); - GL11.glLineWidth(2); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - - bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); - - bufferBuilder.pos(pos.x - m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(pos.x + m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(pos.x, pos.y - m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(pos.x, pos.y + m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(pos.x, pos.y, pos.z - m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex(); - bufferBuilder.pos(pos.x, pos.y, pos.z + m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex(); - - tessellator.draw(); - } - - private static Consumer generateShaderCallback(final float percentile, final Vec3d blockpos, final Vec3d firstpos, final Vec3d secondpos, final boolean highlight) { - Minecraft mc = Minecraft.getMinecraft(); - return (Integer shader) -> { - int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "percentile"); - int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight"); - int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos"); - int firstposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "firstpos"); - int secondposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "secondpos"); - int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image"); - int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask"); - - //image - OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).getGlTextureId()); - ARBShaderObjects.glUniform1iARB(imageUniform, 0); - - OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit); - - GlStateManager.enableTexture2D(); - GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); - - //mask - GL11.glBindTexture(GL11.GL_TEXTURE_2D, - mc.renderEngine.getTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")).getGlTextureId()); - ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit); - - //blockpos - ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z); - ARBShaderObjects.glUniform3fARB(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z); - ARBShaderObjects.glUniform3fARB(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z); - - //percentile - ARBShaderObjects.glUniform1fARB(percentileUniform, percentile); - //highlight - ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0); - }; - } - - //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(); - - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player); - if (!BuildModifiers.isEnabled(modifierSettings, pos)) return; - - List 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); - } - } - } -} diff --git a/src/main/java/nl/requios/effortlessbuilding/helper/SurvivalHelper.java b/src/main/java/nl/requios/effortlessbuilding/helper/SurvivalHelper.java index 9f57210..7e08a12 100644 --- a/src/main/java/nl/requios/effortlessbuilding/helper/SurvivalHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/helper/SurvivalHelper.java @@ -44,19 +44,9 @@ public class SurvivalHelper { itemstack = ItemRandomizerBag.findStack(bagInventory, Item.getItemFromBlock(blockState.getBlock())); } - //Check if itemstack is correct - if (!(itemstack.getItem() instanceof ItemBlock) || Block.getBlockFromItem(itemstack.getItem()) != blockState.getBlock()) { - EffortlessBuilding.log(player, "Cannot (re)place block", true); - EffortlessBuilding.log("SurvivalHelper#placeBlock: itemstack " + itemstack.toString() + " does not match blockstate " + blockState.toString()); - return false; - } - Block block = ((ItemBlock) itemstack.getItem()).getBlock(); - if (!itemstack.isEmpty() && canPlayerEdit(player, world, pos, itemstack) && - mayPlace(world, block, blockState, pos, skipCollisionCheck, facing.getOpposite(), player) && - canReplace(world, player, pos)) - { + if (canPlace(world, player, pos, blockState, itemstack, skipCollisionCheck, facing.getOpposite())) { //Drop existing block //TODO check if can replace dropBlock(world, player, pos); @@ -108,6 +98,107 @@ public class SurvivalHelper { return false; } + //Gives items directly to player + public static void dropBlock(World world, EntityPlayer player, BlockPos pos){ + if (player.isCreative()) return; + + IBlockState blockState = world.getBlockState(pos); + + int fortune = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, player.getHeldItemMainhand()); + List drops = blockState.getBlock().getDrops(world, pos, blockState, fortune); + for (ItemStack drop : drops) + { + ItemHandlerHelper.giveItemToPlayer(player, drop); + } + } + + /** + * Check if player can place a block. + * Turn randomizer bag into itemstack inside before. + * @param world + * @param player + * @param pos + * @param newBlockState the blockstate that is going to be placed + * @param itemStack the itemstack used for placing + * @param skipCollisionCheck skips collision check with entities + * @param sidePlacedOn + * @return Whether the player may place the block at pos with itemstack + */ + public static boolean canPlace(World world, EntityPlayer player, BlockPos pos, IBlockState newBlockState, ItemStack itemStack, boolean skipCollisionCheck, EnumFacing sidePlacedOn) { + + //Check if itemstack is correct + if (!(itemStack.getItem() instanceof ItemBlock) || Block.getBlockFromItem(itemStack.getItem()) != newBlockState.getBlock()) { + EffortlessBuilding.log(player, "Cannot (re)place block", true); + EffortlessBuilding.log("SurvivalHelper#placeBlock: itemstack " + itemStack.toString() + " does not match blockstate " + newBlockState.toString()); + return false; + } + + Block block = ((ItemBlock) itemStack.getItem()).getBlock(); + + return !itemStack.isEmpty() && canPlayerEdit(player, world, pos, itemStack) && + mayPlace(world, block, newBlockState, pos, skipCollisionCheck, sidePlacedOn, player) && + canReplace(world, player, pos); + } + + //Can be harvested with hand? (or in creative) + private static boolean canReplace(World world, EntityPlayer player, BlockPos pos){ + if (player.isCreative()) return true; + + IBlockState state = world.getBlockState(pos); + state = state.getBlock().getActualState(state, world, pos); + if (state.getMaterial().isToolNotRequired()) return true; + + return false; + } + + //From EntityPlayer#canPlayerEdit + private 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) + { + IBlockState iblockstate1 = world.getBlockState(pos); + AxisAlignedBB axisalignedbb = skipCollisionCheck ? null : blockIn.getDefaultState().getCollisionBoundingBox(world, pos); + + if (axisalignedbb != Block.NULL_AABB && !world.checkNoEntityCollision(axisalignedbb.offset(pos), placer)) + { + return false; + } + + //Check if same block + //Necessary otherwise extra items will be dropped + if (iblockstate1 == newBlockState) { + return false; + } + + if (iblockstate1.getMaterial() == Material.CIRCUITS && blockIn == Blocks.ANVIL) + { + return true; + } + + //Check quickreplace + if (placer instanceof EntityPlayer && ModifierSettingsManager.getModifierSettings(((EntityPlayer) placer)).doQuickReplace()) { + return true; + } + + return iblockstate1.getBlock().isReplaceable(world, pos) && blockIn.canPlaceBlockOnSide(world, pos, sidePlacedOn); + } + + + //Can break using held tool? (or in creative) public static boolean canBreak(World world, EntityPlayer player, BlockPos pos) { IBlockState blockState = world.getBlockState(pos); @@ -151,75 +242,4 @@ public class SurvivalHelper { return toolLevel >= block.getHarvestLevel(state); } - - //Can be harvested with hand? (or in creative) - public static boolean canReplace(World world, EntityPlayer player, BlockPos pos){ - if (player.isCreative()) return true; - - IBlockState state = world.getBlockState(pos); - state = state.getBlock().getActualState(state, world, pos); - if (state.getMaterial().isToolNotRequired()) return true; - - return false; - } - - //Gives items directly to player - public static void dropBlock(World world, EntityPlayer player, BlockPos pos){ - if (player.isCreative()) return; - - IBlockState blockState = world.getBlockState(pos); - - int fortune = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, player.getHeldItemMainhand()); - List drops = blockState.getBlock().getDrops(world, pos, blockState, fortune); - for (ItemStack drop : drops) - { - ItemHandlerHelper.giveItemToPlayer(player, drop); - } - } - - //From EntityPlayer#canPlayerEdit - 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 - 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); - - if (axisalignedbb != Block.NULL_AABB && !world.checkNoEntityCollision(axisalignedbb.offset(pos), placer)) - { - return false; - } - - //Check if same block - //Necessary otherwise extra items will be dropped - if (iblockstate1 == newBlockState) { - return false; - } - - if (iblockstate1.getMaterial() == Material.CIRCUITS && blockIn == Blocks.ANVIL) - { - return true; - } - - //Check quickreplace - if (placer instanceof EntityPlayer && ModifierSettingsManager.getModifierSettings(((EntityPlayer) placer)).doQuickReplace()) { - return true; - } - - return iblockstate1.getBlock().isReplaceable(world, pos) && blockIn.canPlaceBlockOnSide(world, pos, sidePlacedOn); - } } diff --git a/src/main/java/nl/requios/effortlessbuilding/network/BlockBrokenMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/BlockBrokenMessage.java index 48144a5..ea2242b 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/BlockBrokenMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/BlockBrokenMessage.java @@ -13,6 +13,9 @@ import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; +/*** + * Sends a message to the server indicating that a player wants to break a block + */ public class BlockBrokenMessage implements IMessage { private boolean blockHit; diff --git a/src/main/java/nl/requios/effortlessbuilding/network/BlockPlacedMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/BlockPlacedMessage.java index 35315cc..3492dd3 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/BlockPlacedMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/BlockPlacedMessage.java @@ -13,7 +13,12 @@ import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.proxy.ClientProxy; +import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; +/*** + * Sends a message to the server indicating that a player wants to place a block. + * Received clientside: server has placed blocks and its letting the client know. + */ public class BlockPlacedMessage implements IMessage { private boolean blockHit; @@ -81,8 +86,11 @@ public class BlockPlacedMessage implements IMessage { if (ctx.side == Side.CLIENT){ //Received clientside - //Send back your info - return new BlockPlacedMessage(ClientProxy.previousLookAt); + EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> { + //Nod RenderHandler to do the dissolve shader effect + BlockPreviewRenderer.onBlocksPlaced(); + }); + return null; } else { //Received serverside EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> { diff --git a/src/main/java/nl/requios/effortlessbuilding/network/CancelModeMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/CancelModeMessage.java index c3c62d1..9308c43 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/CancelModeMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/CancelModeMessage.java @@ -9,6 +9,9 @@ import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmode.BuildModes; +/** + * Sends a message to the server indicating that a buildmode needs to be canceled for a player + */ public class CancelModeMessage implements IMessage { @Override diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ModeSettingsMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/ModeSettingsMessage.java index 8cb89d7..aaa617c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ModeSettingsMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ModeSettingsMessage.java @@ -3,8 +3,6 @@ package nl.requios.effortlessbuilding.network; import io.netty.buffer.ByteBuf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.IThreadListener; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; @@ -14,6 +12,9 @@ import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.*; +/** + * Shares mode settings (see ModeSettingsManager) between server and client + */ public class ModeSettingsMessage implements IMessage { private ModeSettings modeSettings; diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java index 745ae50..f3aa54e 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java @@ -16,6 +16,9 @@ import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.*; +/** + * Shares modifier settings (see ModifierSettingsManager) between server and client + */ public class ModifierSettingsMessage implements IMessage { private ModifierSettings modifierSettings; diff --git a/src/main/java/nl/requios/effortlessbuilding/network/RequestLookAtMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/RequestLookAtMessage.java new file mode 100644 index 0000000..2b0196f --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/network/RequestLookAtMessage.java @@ -0,0 +1,50 @@ +package nl.requios.effortlessbuilding.network; + +import io.netty.buffer.ByteBuf; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.relauncher.Side; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.buildmode.BuildModes; +import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; +import nl.requios.effortlessbuilding.proxy.ClientProxy; + +/*** + * Sends a message to the client asking for its lookat (objectmouseover) data. + * This is then sent back with a BlockPlacedMessage. + */ +public class RequestLookAtMessage implements IMessage { + + public RequestLookAtMessage() { + } + + @Override + public void toBytes(ByteBuf buf) { + } + + @Override + public void fromBytes(ByteBuf buf) { + } + + // The params of the IMessageHandler are + public static class MessageHandler implements IMessageHandler { + // Do note that the default constructor is required, but implicitly defined in this case + + @Override + public IMessage onMessage(RequestLookAtMessage message, MessageContext ctx) { + //EffortlessBuilding.log("message received on " + ctx.side + " side"); + + if (ctx.side == Side.CLIENT){ + //Received clientside + //Send back your info + return new BlockPlacedMessage(ClientProxy.previousLookAt); + } + return null; + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java index 57bb37d..1033bd2 100644 --- a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java +++ b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java @@ -9,6 +9,7 @@ import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.client.resources.IResource; @@ -52,8 +53,8 @@ import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; import nl.requios.effortlessbuilding.helper.ReachHelper; -import nl.requios.effortlessbuilding.helper.RenderHelper; -import nl.requios.effortlessbuilding.helper.ShaderHelper; +import nl.requios.effortlessbuilding.render.RenderHandler; +import nl.requios.effortlessbuilding.render.ShaderHandler; import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.network.*; import org.lwjgl.input.Keyboard; @@ -72,11 +73,11 @@ public class ClientProxy implements IProxy { public static int ticksInGame = 0; - private static final HashMap buildModeIcons = new HashMap<>(); + private static final HashMap buildModeIcons = new HashMap<>(); @Override public void preInit(FMLPreInitializationEvent event) { - ShaderHelper.init(); + ShaderHandler.init(); } @Override @@ -131,7 +132,7 @@ public class ClientProxy implements IProxy { @SubscribeEvent public static void onEntityJoinWorld(EntityJoinWorldEvent event) { if (event.getEntity() == Minecraft.getMinecraft().player) { - event.getWorld().addEventListener(new RenderHelper()); + event.getWorld().addEventListener(new RenderHandler()); } } @@ -142,67 +143,12 @@ public class ClientProxy implements IProxy { for ( final BuildModes.BuildModeEnum mode : BuildModes.BuildModeEnum.values() ) { - loadIcon( map, mode ); + final ResourceLocation sprite = new ResourceLocation("effortlessbuilding", "icons/" + mode.name().toLowerCase()); + buildModeIcons.put( mode, map.registerSprite(sprite)); } } - /** - * From Chisels and Bits by AlgorithmX2 - * https://github.com/AlgorithmX2/Chisels-and-Bits/blob/1.12/src/main/java/mod/chiselsandbits/core/ClientSide.java - */ - private static void loadIcon(final TextureMap map, final BuildModes.BuildModeEnum mode) { - final RadialMenu.SpriteIconPositioning sip = new RadialMenu.SpriteIconPositioning(); - - final ResourceLocation sprite = new ResourceLocation( "effortlessbuilding", "icons/" + mode.name().toLowerCase() ); - final ResourceLocation png = new ResourceLocation( "effortlessbuilding", "textures/icons/" + mode.name().toLowerCase() + ".png" ); - - sip.sprite = map.registerSprite( sprite ); - - try - { - final IResource iresource = Minecraft.getMinecraft().getResourceManager().getResource( png ); - final BufferedImage bi = TextureUtil.readBufferedImage( iresource.getInputStream() ); - - int bottom = 0; - int right = 0; - sip.left = bi.getWidth(); - sip.top = bi.getHeight(); - - for ( int x = 0; x < bi.getWidth(); x++ ) - { - for ( int y = 0; y < bi.getHeight(); y++ ) - { - final int color = bi.getRGB( x, y ); - final int a = color >> 24 & 0xff; - if ( a > 0 ) - { - sip.left = Math.min( sip.left, x ); - right = Math.max( right, x ); - - sip.top = Math.min( sip.top, y ); - bottom = Math.max( bottom, y ); - } - } - } - - sip.height = bottom - sip.top + 1; - sip.width = right - sip.left + 1; - - sip.left /= bi.getWidth(); - sip.width /= bi.getWidth(); - sip.top /= bi.getHeight(); - sip.height /= bi.getHeight(); - } catch (final IOException e) { - sip.height = 1; - sip.width = 1; - sip.left = 0; - sip.top = 0; - } - - buildModeIcons.put( mode, sip ); - } - - public static RadialMenu.SpriteIconPositioning getBuildModeIcon(BuildModes.BuildModeEnum mode) { + public static TextureAtlasSprite getBuildModeIcon(BuildModes.BuildModeEnum mode) { return buildModeIcons.get(mode); } @@ -295,8 +241,6 @@ public class ClientProxy implements IProxy { //QuickReplace toggle if (keyBindings[1].isPressed()) { - - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace()); EffortlessBuilding.log(player, "Set "+ TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + ( @@ -315,8 +259,10 @@ public class ClientProxy implements IProxy { if (keyBindings[4].isPressed()) { //TODO remove - ShaderHelper.init(); + ShaderHandler.init(); EffortlessBuilding.log(player, "Reloaded shaders"); + //player.playSound(SoundEvents.UI_BUTTON_CLICK, 1f, 1f); + player.playSound(EffortlessBuilding.SOUND_BUILD_CLICK, 1f, 1f); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviewRenderer.java b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviewRenderer.java new file mode 100644 index 0000000..d11bc49 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviewRenderer.java @@ -0,0 +1,285 @@ +package nl.requios.effortlessbuilding.render; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nl.requios.effortlessbuilding.BuildConfig; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.buildmode.BuildModes; +import nl.requios.effortlessbuilding.buildmode.IBuildMode; +import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; +import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; +import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; +import nl.requios.effortlessbuilding.helper.ReachHelper; +import nl.requios.effortlessbuilding.helper.SurvivalHelper; +import nl.requios.effortlessbuilding.item.ItemRandomizerBag; +import nl.requios.effortlessbuilding.proxy.ClientProxy; +import org.lwjgl.opengl.ARBMultitexture; +import org.lwjgl.opengl.ARBShaderObjects; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +@SideOnly(Side.CLIENT) +public class BlockPreviewRenderer { + private static List previousCoordinates; + private static List previousBlockStates; + private static List previousItemStacks; + private static BlockPos previousFirstPos; + private static BlockPos previousSecondPos; + private static int soundTime = 0; + + static class PlacedData { + float time; + List coordinates; + List blockStates; + List itemStacks; + BlockPos firstPos; + BlockPos secondPos; + + public PlacedData(float time, List coordinates, List blockStates, List itemStacks, BlockPos firstPos, BlockPos secondPos) { + this.time = time; + this.coordinates = coordinates; + this.blockStates = blockStates; + this.itemStacks = itemStacks; + this.firstPos = firstPos; + this.secondPos = secondPos; + } + } + + private static List placedDataList = new ArrayList<>(); + + private static final int secondaryTextureUnit = 7; + + public static void render(EntityPlayer player, ModifierSettingsManager.ModifierSettings modifierSettings, ModeSettingsManager.ModeSettings modeSettings) { + + //Render placed blocks with dissolve effect + for (int i = 0; i < placedDataList.size(); i++) { + PlacedData placed = placedDataList.get(i); + if (placed.coordinates != null && !placed.coordinates.isEmpty()) { + + RenderHandler.beginBlockPreviews(); + + float dissolve = (ClientProxy.ticksInGame - placed.time) / (float) BuildConfig.visuals.dissolveTime; + renderBlockPreviews(placed.coordinates, placed.blockStates, placed.itemStacks, dissolve, placed.firstPos, placed.secondPos, false); + + RenderHandler.endBlockPreviews(); + } + } + //Expire + placedDataList.removeIf(placed -> placed.time + BuildConfig.visuals.dissolveTime < ClientProxy.ticksInGame); + + //Render block previews + RayTraceResult lookingAt = ClientProxy.getLookingAt(player); + if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.Normal) lookingAt = Minecraft.getMinecraft().objectMouseOver; + + ItemStack mainhand = player.getHeldItemMainhand(); + boolean toolInHand = !(!mainhand.isEmpty() && (mainhand.getItem() instanceof ItemBlock || mainhand.getItem() instanceof ItemRandomizerBag)); + + BlockPos startPos = null; + EnumFacing sideHit = null; + Vec3d hitVec = null; + + //Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS) + if (lookingAt != null && lookingAt.typeOfHit == RayTraceResult.Type.BLOCK) { + startPos = lookingAt.getBlockPos(); + + //Check if tool (or none) in hand + boolean replaceable = player.world.getBlockState(startPos).getBlock().isReplaceable(player.world, startPos); + if (!modifierSettings.doQuickReplace() && !toolInHand && !replaceable) { + startPos = startPos.offset(lookingAt.sideHit); + } + + //Get under tall grass and other replaceable blocks + if (modifierSettings.doQuickReplace() && !toolInHand && replaceable) { + startPos = startPos.down(); + } + + sideHit = lookingAt.sideHit; + hitVec = lookingAt.hitVec; + } + + //Dont render if in normal mode and modifiers are disabled + //Unless alwaysShowBlockPreview is true in config + if (modeSettings.getBuildMode() != BuildModes.BuildModeEnum.Normal || + (startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) || + BuildConfig.visuals.alwaysShowBlockPreview) { + + RenderHandler.beginBlockPreviews(); + + IBuildMode buildModeInstance = modeSettings.getBuildMode().instance; + if (buildModeInstance.getSideHit(player) != null) sideHit = buildModeInstance.getSideHit(player); + if (buildModeInstance.getHitVec(player) != null) hitVec = buildModeInstance.getHitVec(player); + + if (sideHit != null) { + + //get coordinates + List startCoordinates = BuildModes.findCoordinates(player, startPos); + + BlockPos firstPos = BlockPos.ORIGIN, secondPos = BlockPos.ORIGIN; + //Remember first and last pos for the shader + if (!startCoordinates.isEmpty()) { + firstPos = startCoordinates.get(0); + secondPos = startCoordinates.get(startCoordinates.size() - 1); + } + + //Limit number of blocks you can place + int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player); + if (startCoordinates.size() > limit) { + startCoordinates = startCoordinates.subList(0, limit); + } + + List newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates); + + Collections.sort(newCoordinates, (lhs, rhs) -> { + // -1 - less than, 1 - greater than, 0 - equal + double lhsDistanceToPlayer = new Vec3d(lhs).subtract(player.getPositionEyes(1f)).lengthSquared(); + double rhsDistanceToPlayer = new Vec3d(rhs).subtract(player.getPositionEyes(1f)).lengthSquared(); + return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer); + }); + + hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), + Math.abs(hitVec.z - ((int) hitVec.z))); + List itemStacks = new ArrayList<>(); + List blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks); + + //Check if they are different from previous + //TODO fix triggering when moving player + if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) { + previousCoordinates = newCoordinates; + //remember the rest for placed blocks + previousBlockStates = blockStates; + previousItemStacks = itemStacks; + previousFirstPos = firstPos; + previousSecondPos = secondPos; + + //if so, renew randomness of randomizer bag + ItemRandomizerBag.renewRandomness(); + //and play sound (max once every tick) + if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) { + soundTime = ClientProxy.ticksInGame; + //player.playSound(EffortlessBuilding.SOUND_BUILD_CLICK, 0.2f, 1f); + player.playSound(blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.world, + newCoordinates.get(0), player).getPlaceSound(), 0.3f, 1f); + } + } + + //Render block previews + if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) { + renderBlockPreviews(newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, true); + } + } + + RenderHandler.endBlockPreviews(); + + RenderHandler.beginLines(); + //Draw outlines if tool in hand + //Find proper raytrace: either normal range or increased range depending on canBreakFar + RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver; + RayTraceResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver; + if (toolInHand && breakingRaytrace != null && breakingRaytrace.typeOfHit == RayTraceResult.Type.BLOCK) { + List breakCoordinates = BuildModifiers.findCoordinates(player, breakingRaytrace.getBlockPos()); + + //Only render first outline if further than normal reach + boolean excludeFirst = objectMouseOver != null && objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK; + for (int i = excludeFirst ? 1 : 0; i < breakCoordinates.size(); i++) { + BlockPos coordinate = breakCoordinates.get(i); + + IBlockState blockState = player.world.getBlockState(coordinate); + if (!blockState.getBlock().isAir(blockState, player.world, coordinate)) { + if (SurvivalHelper.canBreak(player.world, player, coordinate) || i == 0) { + RenderHandler.renderBlockOutline(coordinate); + } + } + } + } + RenderHandler.endLines(); + } + } + + protected static void renderBlockPreviews(List coordinates, List blockStates, + List itemStacks, float dissolve, BlockPos firstPos, + BlockPos secondPos, boolean checkCanPlace) { + EntityPlayer player = Minecraft.getMinecraft().player; + BlockRendererDispatcher dispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher(); + + for (int i = coordinates.size() - 1; i >= 0; i--) { + BlockPos blockPos = coordinates.get(i); + IBlockState blockState = blockStates.get(i); + ItemStack itemstack = itemStacks.get(i); + + //Check if can place + //If check is turned off, check if blockstate is the same (for dissolve effect) + if (SurvivalHelper.canPlace(player.world, player, blockPos, blockState, itemstack, true, EnumFacing.UP) || + (!checkCanPlace && player.world.getBlockState(blockPos) == blockState)) { + + ShaderHandler.useShader(ShaderHandler.dissolve, generateShaderCallback(dissolve, + new Vec3d(blockPos), new Vec3d(firstPos), new Vec3d(secondPos), + blockPos == secondPos)); + RenderHandler.renderBlockPreview(dispatcher, blockPos, blockState); + } + } + + } + + public static void onBlocksPlaced() { + //Save current coordinates, blockstates and itemstacks + placedDataList.add(new PlacedData(ClientProxy.ticksInGame, previousCoordinates, previousBlockStates, + previousItemStacks, previousFirstPos, previousSecondPos)); + + } + + private static Consumer generateShaderCallback(final float dissolve, final Vec3d blockpos, final Vec3d firstpos, final Vec3d secondpos, final boolean highlight) { + Minecraft mc = Minecraft.getMinecraft(); + return (Integer shader) -> { + int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "dissolve"); + int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight"); + int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos"); + int firstposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "firstpos"); + int secondposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "secondpos"); + int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image"); + int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask"); + + //image + OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).getGlTextureId()); + ARBShaderObjects.glUniform1iARB(imageUniform, 0); + + OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit); + + GlStateManager.enableTexture2D(); + GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + + //mask + GL11.glBindTexture(GL11.GL_TEXTURE_2D, + mc.renderEngine.getTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")).getGlTextureId()); + ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit); + + //blockpos + ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z); + ARBShaderObjects.glUniform3fARB(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z); + ARBShaderObjects.glUniform3fARB(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z); + + //dissolve + ARBShaderObjects.glUniform1fARB(percentileUniform, dissolve); + //highlight + ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0); + }; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/render/ModifierRenderer.java b/src/main/java/nl/requios/effortlessbuilding/render/ModifierRenderer.java new file mode 100644 index 0000000..7f99656 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/render/ModifierRenderer.java @@ -0,0 +1,175 @@ +package nl.requios.effortlessbuilding.render; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nl.requios.effortlessbuilding.buildmodifier.Mirror; +import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; +import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.Color; + +@SideOnly(Side.CLIENT) +public class ModifierRenderer { + + protected static final Color colorX = new Color(255, 72, 52); + protected static final Color colorY = new Color(67, 204, 51); + protected static final Color colorZ = new Color(52, 247, 255); + protected static final Color colorRadial = new Color(52, 247, 255); + protected static final int lineAlpha = 200; + protected static final int planeAlpha = 75; + protected static final Vec3d epsilon = new Vec3d(0.001, 0.001, 0.001); //prevents z-fighting + + public static void render(ModifierSettingsManager.ModifierSettings modifierSettings) { + RenderHandler.beginLines(); + + //Mirror lines and areas + Mirror.MirrorSettings m = modifierSettings.getMirrorSettings(); + if (m != null && m.enabled && (m.mirrorX || m.mirrorY || m.mirrorZ)) + { + Vec3d pos = m.position.add(epsilon); + int radius = m.radius; + + if (m.mirrorX) + { + Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z - radius); + Vec3d posB = new Vec3d(pos.x, pos.y + radius, pos.z + radius); + + drawMirrorPlane(posA, posB, colorX, m.drawLines, m.drawPlanes, true); + } + if (m.mirrorY) + { + Vec3d posA = new Vec3d(pos.x - radius, pos.y, pos.z - radius); + Vec3d posB = new Vec3d(pos.x + radius, pos.y, pos.z + radius); + + drawMirrorPlaneY(posA, posB, colorY, m.drawLines, m.drawPlanes); + } + if (m.mirrorZ) + { + Vec3d posA = new Vec3d(pos.x - radius, pos.y - radius, pos.z); + Vec3d posB = new Vec3d(pos.x + radius, pos.y + radius, pos.z); + + drawMirrorPlane(posA, posB, colorZ, m.drawLines, m.drawPlanes, true); + } + + //Draw axis coordinated colors if two or more axes are enabled + //(If only one is enabled the lines are that planes color) + if (m.drawLines && ((m.mirrorX && m.mirrorY) || (m.mirrorX && m.mirrorZ) || (m.mirrorY && m.mirrorZ))) + { + drawMirrorLines(m); + } + } + + //Radial mirror lines and areas + RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings(); + if (r != null && r.enabled) + { + Vec3d pos = r.position.add(epsilon); + int radius = r.radius; + + float angle = 2f * ((float) Math.PI) / r.slices; + Vec3d relStartVec = new Vec3d(radius, 0, 0); + if (r.slices%4 == 2) relStartVec = relStartVec.rotateYaw(angle / 2f); + + for (int i = 0; i < r.slices; i++) { + Vec3d relNewVec = relStartVec.rotateYaw(angle * i); + Vec3d newVec = pos.add(relNewVec); + + Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z); + Vec3d posB = new Vec3d(newVec.x, pos.y + radius, newVec.z); + drawMirrorPlane(posA, posB, colorRadial, r.drawLines, r.drawPlanes, false); + } + } + + RenderHandler.endLines(); + } + + + //----Mirror---- + + protected static void drawMirrorPlane(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes, boolean drawVerticalLines) { + + GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferBuilder = tessellator.getBuffer(); + + if (drawPlanes) { + bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); + + bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + bufferBuilder.pos(posA.x, posB.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + bufferBuilder.pos(posB.x, posB.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + + tessellator.draw(); + } + + if (drawLines) { + Vec3d middle = posA.add(posB).scale(0.5); + bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); + + bufferBuilder.pos(posA.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(posB.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + if (drawVerticalLines) { + bufferBuilder.pos(middle.x, posA.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(middle.x, posB.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + } + + tessellator.draw(); + } + } + + protected static void drawMirrorPlaneY(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes) { + + GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferBuilder = tessellator.getBuffer(); + + if (drawPlanes) { + bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); + + bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + bufferBuilder.pos(posA.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + bufferBuilder.pos(posB.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex(); + + tessellator.draw(); + } + + if (drawLines) { + Vec3d middle = posA.add(posB).scale(0.5); + bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); + + bufferBuilder.pos(middle.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(middle.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(posA.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(posB.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex(); + + tessellator.draw(); + } + } + + protected static void drawMirrorLines(Mirror.MirrorSettings m) { + + Vec3d pos = m.position.add(epsilon); + + GL11.glColor4d(100, 100, 100, 255); + GL11.glLineWidth(2); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferBuilder = tessellator.getBuffer(); + + bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); + + bufferBuilder.pos(pos.x - m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(pos.x + m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(pos.x, pos.y - m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(pos.x, pos.y + m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(pos.x, pos.y, pos.z - m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex(); + bufferBuilder.pos(pos.x, pos.y, pos.z + m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex(); + + tessellator.draw(); + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/render/RenderHandler.java b/src/main/java/nl/requios/effortlessbuilding/render/RenderHandler.java new file mode 100644 index 0000000..681798c --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/render/RenderHandler.java @@ -0,0 +1,213 @@ +package nl.requios.effortlessbuilding.render; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; +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.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; +import net.minecraftforge.fml.relauncher.Side; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; +import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; +import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; +import nl.requios.effortlessbuilding.helper.SurvivalHelper; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +import javax.annotation.Nullable; +import java.util.List; + +/*** + * Main render class for Effortless Building + */ +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderHandler implements IWorldEventListener { + + @SubscribeEvent + public static void onRender(RenderWorldLastEvent event) { + EntityPlayer player = Minecraft.getMinecraft().player; + ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); + ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); + + begin(event.getPartialTicks()); + + //Mirror and radial mirror lines and areas + ModifierRenderer.render(modifierSettings); + + //Render block previews + BlockPreviewRenderer.render(player, modifierSettings, modeSettings); + + end(); + } + + private static void begin(float partialTicks) { + EntityPlayer player = Minecraft.getMinecraft().player; + double playerX = player.prevPosX + (player.posX - player.prevPosX) * partialTicks; + double playerY = player.prevPosY + (player.posY - player.prevPosY) * partialTicks; + double playerZ = player.prevPosZ + (player.posZ - player.prevPosZ) * partialTicks; + Vec3d playerPos = new Vec3d(playerX, playerY, playerZ); + + GL11.glPushMatrix(); + GL11.glTranslated(-playerPos.x, -playerPos.y, -playerPos.z); + + GL11.glDepthMask(false); + } + + protected static void beginLines() { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glDisable(GL11.GL_CULL_FACE); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_TEXTURE_2D); + + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + GL11.glLineWidth(2); + } + + protected static void endLines() { + GL11.glPopAttrib(); + } + + protected static void beginBlockPreviews() { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_TEXTURE_2D); + Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_color.png")); + Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")); + + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL14.glBlendColor(1F, 1F, 1F, 0.8f); + } + + protected static void endBlockPreviews() { + ShaderHandler.releaseShader(); + GlStateManager.disableBlend(); + GL11.glPopAttrib(); + } + + private static void end() { + GL11.glDepthMask(true); + GL11.glPopMatrix(); + } + + protected static void renderBlockPreview(BlockRendererDispatcher dispatcher, BlockPos blockPos, IBlockState blockState) { + GlStateManager.pushMatrix(); + GlStateManager.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + 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, 0.85f); + GlStateManager.popMatrix(); + } + + protected static void renderBlockOutline(BlockPos pos) { + renderBlockOutline(pos, pos); + } + + //Renders outline. Pos1 has to be minimal x,y,z and pos2 maximal x,y,z + protected 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); + } + + + + //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(); + + ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player); + if (!BuildModifiers.isEnabled(modifierSettings, pos)) return; + + List 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); + } + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/helper/ShaderHelper.java b/src/main/java/nl/requios/effortlessbuilding/render/ShaderHandler.java similarity index 94% rename from src/main/java/nl/requios/effortlessbuilding/helper/ShaderHelper.java rename to src/main/java/nl/requios/effortlessbuilding/render/ShaderHandler.java index 1994341..1ffde12 100644 --- a/src/main/java/nl/requios/effortlessbuilding/helper/ShaderHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/render/ShaderHandler.java @@ -10,27 +10,22 @@ * * File Created @ [Apr 9, 2014, 11:20:26 PM (GMT)] */ -package nl.requios.effortlessbuilding.helper; +package nl.requios.effortlessbuilding.render; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GLAllocation; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.proxy.ClientProxy; import org.apache.logging.log4j.Level; import org.lwjgl.opengl.*; -import org.lwjgl.util.vector.Matrix4f; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; -import java.nio.FloatBuffer; import java.nio.charset.StandardCharsets; import java.util.function.Consumer; -public final class ShaderHelper { +public final class ShaderHandler { private static final int VERT_ST = ARBVertexShader.GL_VERTEX_SHADER_ARB; private static final int FRAG_ST = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB; @@ -149,7 +144,7 @@ public final class ShaderHelper { private static String readFileAsString(String filename) throws Exception { StringBuilder source = new StringBuilder(); - InputStream in = ShaderHelper.class.getResourceAsStream(filename); + InputStream in = ShaderHandler.class.getResourceAsStream(filename); Exception exception = null; BufferedReader reader; diff --git a/src/main/resources/assets/effortlessbuilding/lang/en_us.lang b/src/main/resources/assets/effortlessbuilding/lang/en_us.lang index d7b8d3b..0353bfe 100644 --- a/src/main/resources/assets/effortlessbuilding/lang/en_us.lang +++ b/src/main/resources/assets/effortlessbuilding/lang/en_us.lang @@ -9,4 +9,6 @@ item.effortlessbuilding:reach_upgrade1.name=Reach Upgrade 1 item.effortlessbuilding:reach_upgrade2.name=Reach Upgrade 2 item.effortlessbuilding:reach_upgrade3.name=Reach Upgrade 3 -commands.reach.usage=/reach \ No newline at end of file +commands.reach.usage=/reach + +effortlessbuilding.subtitle.build_click=Click \ No newline at end of file diff --git a/src/main/resources/assets/effortlessbuilding/shaders/dissolve.frag b/src/main/resources/assets/effortlessbuilding/shaders/dissolve.frag index bf5efb9..2663dff 100644 --- a/src/main/resources/assets/effortlessbuilding/shaders/dissolve.frag +++ b/src/main/resources/assets/effortlessbuilding/shaders/dissolve.frag @@ -2,7 +2,7 @@ uniform int time; // Passed in, see ShaderHelper.java -uniform float percentile; // Passed in via Callback +uniform float dissolve; // Passed in via Callback uniform int highlight; uniform vec3 blockpos; uniform vec3 firstpos; @@ -44,28 +44,28 @@ void main() { vec4 maskColor = texture2D(mask, maskcoord); float maskgs = maskColor.r; - //color.rgb *= gl_Color.rgb; + color.rgb *= gl_Color.rgb; //desaturate color.rgb *= vec3(0.8); //add blueish hue - color.rgb += vec3(-0.2, 0.0, 0.3); + color.rgb += vec3(-0.1, 0.0, 0.2); //add pulsing blue float pulse = (sin(time / 5.0) + 1.0) / 2.0; - color.rgb += (1.0 - color.rgb) * vec3(-0.5, 0.2, 0.6) * pulse; + color.rgb += 0.4 * vec3(-0.5, 0.2, 0.6) * pulse; //add diagonal highlights float diagTime = mod(time / 40.0, 1.4) - 0.2; float diag = smoothstep(diagTime - 0.2, diagTime, place) - smoothstep(diagTime, diagTime + 0.2, place); - color.rgb += (1.0 - color.rgb) * diag * vec3(0.0, 0.2, 0.4); + color.rgb += 0.2 * diag * vec3(0.0, 0.2, 0.4); float diagTime2 = mod(time / 70.0, 1.4) - 0.2; float diag2 = smoothstep(diagTime2 - 0.2, diagTime2, place) - smoothstep(diagTime2, diagTime2 + 0.2, place); - color.rgb += (1.0 - color.rgb) * diag2 * vec3(0.0, 0.4, 0.8); + color.rgb += 0.2 * diag2 * vec3(0.0, 0.4, 0.8); - //add shading + //add edge shading // vec3 p1; // //if (firstpos.x < secondpos.x) // @@ -77,21 +77,16 @@ void main() { // float distToEdge = min(min(distToEdge1, distToEdge2), distToEdge3); // color.rgb += vec3(0.5 - smoothstep(0, 0.5, distToEdge)) * 0.5; + //add flat shading + if (abs(normal.x) > 0.5) + color.rgb -= 0.0; + if (abs(normal.y) > 0.5) + color.rgb += 0.05; + if (abs(normal.z) > 0.5) + color.rgb -= 0.05; -// pulse = 1.0;//pulse / 2.0 + 0.5; -// vec4 pulseColor = texture2D(mask, maskcoord + time / 700.0); -// vec4 pulseColor2 = texture2D(mask, vec2(maskcoord.x + time / 600.0, maskcoord.y - time / 600.0)); -// float pulseGreyScale = pulseColor.r + pulseColor2.r / 2.0; -// -// color.r -= color.r * pulseColor.r * pulse * 0.2; -// color.g += (1.0 - color.g) * pulseColor.r * pulse * 0.2; -// color.b += (1.0 - color.b) * pulseColor.r * pulse * 0.8; -// -// color.r -= color.r * pulseColor2.r * pulse * 0.4; -// color.g += (1.0 - color.g) * pulseColor2.r * pulse * 0.2; -// color.b += (1.0 - color.b) * pulseColor2.r * pulse; - if(highlight == 1) { + if(highlight == 1 && dissolve == 0.0) { color.r += 0.0; color.g += 0.1; color.b -= 0.2; @@ -101,7 +96,7 @@ void main() { color.g = max(0, min(1, color.g)); color.b = max(0, min(1, color.b)); - if (maskgs * 0.3 + place * 0.7 <= percentile) - gl_FragColor = color; - else gl_FragColor = vec4(texcolor.rgb, 0.0); + if (maskgs * 0.3 + place * 0.7 <= dissolve) + gl_FragColor = vec4(texcolor.rgb, 0.0); + else gl_FragColor = color; } \ No newline at end of file diff --git a/src/main/resources/assets/effortlessbuilding/shaders/dissolve.vert b/src/main/resources/assets/effortlessbuilding/shaders/dissolve.vert index 0903b43..ac55820 100644 --- a/src/main/resources/assets/effortlessbuilding/shaders/dissolve.vert +++ b/src/main/resources/assets/effortlessbuilding/shaders/dissolve.vert @@ -2,7 +2,7 @@ uniform int time; // Passed in, see ShaderHelper.java -uniform float percentile; // Passed in via Callback +uniform float dissolve; // Passed in via Callback uniform int highlight; uniform vec3 blockpos; uniform vec3 firstpos; @@ -15,6 +15,8 @@ varying vec3 normal; void main() { gl_Position = ftransform();//gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + gl_FrontColor = gl_Color; + gl_BackColor = gl_Color; position = gl_Vertex; normal = gl_Normal; diff --git a/src/main/resources/assets/effortlessbuilding/sounds.json b/src/main/resources/assets/effortlessbuilding/sounds.json new file mode 100644 index 0000000..7316a5d --- /dev/null +++ b/src/main/resources/assets/effortlessbuilding/sounds.json @@ -0,0 +1,11 @@ +{ + "build_click": { + "category": "block", + "subtitle": "effortlessbuilding.subtitle.build_click", + "sounds": [ + { + "name": "effortlessbuilding:build_click" + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/effortlessbuilding/sounds/build_click.ogg b/src/main/resources/assets/effortlessbuilding/sounds/build_click.ogg new file mode 100644 index 0000000..468f43c Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/sounds/build_click.ogg differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/cube.png b/src/main/resources/assets/effortlessbuilding/textures/icons/cube.png new file mode 100644 index 0000000..c9afbbd Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/cube.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/diagonalline.png b/src/main/resources/assets/effortlessbuilding/textures/icons/diagonalline.png new file mode 100644 index 0000000..69e565e Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/diagonalline.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/diagonalwall.png b/src/main/resources/assets/effortlessbuilding/textures/icons/diagonalwall.png new file mode 100644 index 0000000..ac20e48 Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/diagonalwall.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/floor.png b/src/main/resources/assets/effortlessbuilding/textures/icons/floor.png index bcb950c..bcf4a22 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/floor.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/floor.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/line.png b/src/main/resources/assets/effortlessbuilding/textures/icons/line.png index 4a43a61..8109177 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/line.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/line.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/normal.png b/src/main/resources/assets/effortlessbuilding/textures/icons/normal.png index 6395dc5..2d846ea 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/normal.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/normal.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/normalplus.png b/src/main/resources/assets/effortlessbuilding/textures/icons/normalplus.png index 8eefcc7..96d9d61 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/normalplus.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/normalplus.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/slopefloor.png b/src/main/resources/assets/effortlessbuilding/textures/icons/slopefloor.png new file mode 100644 index 0000000..c786eaf Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/slopefloor.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/wall.png b/src/main/resources/assets/effortlessbuilding/textures/icons/wall.png index 093f9e5..e40ab14 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/wall.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/wall.png differ