diff --git a/build.gradle b/build.gradle index 3505fa0..5fceb51 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge' //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -version = "1.12.2-2.4" +version = "1.12.2-2.5" group = "nl.requios.effortlessbuilding" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "effortlessbuilding" diff --git a/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java b/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java index b9fc71f..6b882e4 100644 --- a/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java +++ b/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java @@ -52,6 +52,10 @@ public class BuildConfig { "The block in front of you always counts as 100%."}) @RangeInt(min = 0, max = 200) public int miningTimePercentage = 50; + + @Comment({"How many placements are remembered for the undo functionality."}) + @RequiresMcRestart + public int undoStackSize = 5; } public static class Visuals { diff --git a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java index d914fe4..c3ef1bb 100644 --- a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java +++ b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java @@ -39,7 +39,7 @@ public class EffortlessBuilding { public static final String MODID = "effortlessbuilding"; public static final String NAME = "Effortless Building"; - public static final String VERSION = "1.12.2-2.4"; + public static final String VERSION = "1.12.2-2.5"; @Mod.Instance(EffortlessBuilding.MODID) public static EffortlessBuilding instance; diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java index 1c6b98d..f45d93c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java @@ -119,8 +119,7 @@ public class BuildModes { //Use a network message to break blocks in the distance using clientside mouse input public static void onBlockBrokenMessage(EntityPlayer player, BlockBrokenMessage message) { - if (ReachHelper.canBreakFar(player) && - !CompatHelper.chiselsAndBitsProxy.isHoldingChiselTool(EnumHand.MAIN_HAND)) { + if (ReachHelper.canBreakFar(player)) { BlockPos startPos = message.isBlockHit() ? message.getBlockPos() : null; onBlockBroken(player, startPos, true); @@ -132,7 +131,7 @@ public class BuildModes { //Check if not in the middle of placing Dictionary currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; if (currentlyBreaking.get(player) != null && !currentlyBreaking.get(player)) { - //Cancel placing + //Cancel breaking initializeMode(player); return; } @@ -177,4 +176,20 @@ public class BuildModes { ModeSettingsManager.getModeSettings(player).getBuildMode().instance.initialize(player); } + + public static boolean isCurrentlyPlacing(EntityPlayer player) { + Dictionary currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; + return currentlyBreaking.get(player) != null && !currentlyBreaking.get(player); + } + + public static boolean isCurrentlyBreaking(EntityPlayer player) { + Dictionary currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; + return currentlyBreaking.get(player) != null && currentlyBreaking.get(player); + } + + //Either placing or breaking + public static boolean isActive(EntityPlayer player) { + Dictionary currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; + return currentlyBreaking.get(player) != null; + } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java index 6fd2858..34f3f31 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java @@ -7,6 +7,7 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; +import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; @@ -21,12 +22,15 @@ public class ModeOptions { //Called on both client and server public static void performAction(EntityPlayer player, ActionEnum action) { - EffortlessBuilding.log("Doing "+action.name()); switch (action) { case UNDO: + UndoRedo.undo(player); + EffortlessBuilding.log(player, "Undo", true); break; case REDO: + UndoRedo.redo(player); + EffortlessBuilding.log(player, "Redo", true); break; case REPLACE: ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BlockSet.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BlockSet.java new file mode 100644 index 0000000..6098f2e --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BlockSet.java @@ -0,0 +1,45 @@ +package nl.requios.effortlessbuilding.buildmodifier; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +import java.util.List; + +public class BlockSet { + private List coordinates; + private List blockStates; + private Vec3d hitVec; + private BlockPos firstPos; + private BlockPos secondPos; + + public BlockSet(List coordinates, List blockStates, Vec3d hitVec, + BlockPos firstPos, BlockPos secondPos) { + this.coordinates = coordinates; + this.blockStates = blockStates; + this.hitVec = hitVec; + this.firstPos = firstPos; + this.secondPos = secondPos; + } + + public List getCoordinates() { + return coordinates; + } + + public List getBlockStates() { + return blockStates; + } + + public Vec3d getHitVec() { + return hitVec; + } + + public BlockPos getFirstPos() { + return firstPos; + } + + public BlockPos getSecondPos() { + return secondPos; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java index f154e98..32916a7 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java @@ -11,19 +11,21 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.compatibility.CompatHelper; +import nl.requios.effortlessbuilding.helper.FixedStack; +import nl.requios.effortlessbuilding.helper.InventoryHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.network.BlockPlacedMessage; import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; public class BuildModifiers { + //Called from BuildModes public static void onBlockPlaced(EntityPlayer player, List startCoordinates, EnumFacing sideHit, Vec3d hitVec, boolean placeStartPos) { World world = player.world; @@ -41,23 +43,33 @@ public class BuildModifiers { if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return; if (world.isRemote) { + BlockPreviewRenderer.onBlocksPlaced(); - return; - } - //place blocks - for (int i = placeStartPos ? 0 : 1; i < coordinates.size(); i++) { - BlockPos blockPos = coordinates.get(i); - IBlockState blockState = blockStates.get(i); - ItemStack itemStack = itemStacks.get(i); + } else { - if (world.isBlockLoaded(blockPos, true)) { - //check itemstack empty - if (itemStack.isEmpty()) continue; - SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, hitVec, false, false); + //place blocks + for (int i = placeStartPos ? 0 : 1; i < coordinates.size(); i++) { + BlockPos blockPos = coordinates.get(i); + IBlockState blockState = blockStates.get(i); + ItemStack itemStack = itemStacks.get(i); + + if (world.isBlockLoaded(blockPos, true)) { + //check itemstack empty + if (itemStack.isEmpty()) { + //try to find new stack, otherwise continue + itemStack = InventoryHelper.findItemStackInInventory(player, blockState); + if (itemStack.isEmpty()) continue; + } + SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, hitVec, false, false); + } } } + //add to undo stack + BlockPos firstPos = startCoordinates.get(0); + BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1); + UndoRedo.addUndo(player, new BlockSet(coordinates, blockStates, hitVec, firstPos, secondPos)); } public static void onBlockBroken(EntityPlayer player, List posList, boolean breakStartPos) { @@ -73,7 +85,8 @@ public class BuildModifiers { } //If the player is going to instabreak grass or a plant, only break other instabreaking things - boolean onlyInstaBreaking = world.getBlockState(posList.get(0)).getBlockHardness(world, posList.get(0)) == 0f; + boolean onlyInstaBreaking = !player.isCreative() && + world.getBlockState(posList.get(0)).getBlockHardness(world, posList.get(0)) == 0f; //break all those blocks for (int i = breakStartPos ? 0 : 1; i < coordinates.size(); i++) { diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java new file mode 100644 index 0000000..dba5dd5 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java @@ -0,0 +1,118 @@ +package nl.requios.effortlessbuilding.buildmodifier; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import nl.requios.effortlessbuilding.BuildConfig; +import nl.requios.effortlessbuilding.helper.FixedStack; +import nl.requios.effortlessbuilding.helper.InventoryHelper; +import nl.requios.effortlessbuilding.helper.SurvivalHelper; +import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; + +import java.util.*; + +public class UndoRedo { + + private static Map> undoStacks = new HashMap<>(); + private static Map> redoStacks = new HashMap<>(); + + //add to undo stack + public static void addUndo(EntityPlayer player, BlockSet blockSet) { + + //If no stack exists, make one + if (!undoStacks.containsKey(player.getUniqueID())) { + undoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize])); + } + + undoStacks.get(player.getUniqueID()).push(blockSet); + } + + private static void addRedo(EntityPlayer player, BlockSet blockSet) { + + //If no stack exists, make one + if (!redoStacks.containsKey(player.getUniqueID())) { + redoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize])); + } + + redoStacks.get(player.getUniqueID()).push(blockSet); + } + + public static boolean undo(EntityPlayer player) { + if (!undoStacks.containsKey(player.getUniqueID())) return false; + + FixedStack undoStack = undoStacks.get(player.getUniqueID()); + + if (undoStack.isEmpty()) return false; + + BlockSet blockSet = undoStack.pop(); + List coordinates = blockSet.getCoordinates(); + List blockStates = blockSet.getBlockStates(); + + //Find up to date itemstacks in player inventory + List itemStacks = findItemStacksInInventory(player, blockStates); + + //break all those blocks + for (int i = 0; i < coordinates.size(); i++) { + BlockPos coordinate = coordinates.get(i); + if (player.world.isBlockLoaded(coordinate, false)) { + SurvivalHelper.breakBlock(player.world, player, coordinate); + } + } + + if (player.world.isRemote) + BlockPreviewRenderer.onBlocksBroken(coordinates, itemStacks, blockStates, blockSet.getSecondPos(), blockSet.getFirstPos()); + + //add to redo + addRedo(player, blockSet); + + return true; + } + + public static boolean redo(EntityPlayer player) { + if (!redoStacks.containsKey(player.getUniqueID())) return false; + + FixedStack redoStack = redoStacks.get(player.getUniqueID()); + + if (redoStack.isEmpty()) return false; + + BlockSet blockSet = redoStack.pop(); + List coordinates = blockSet.getCoordinates(); + List blockStates = blockSet.getBlockStates(); + Vec3d hitVec = blockSet.getHitVec(); + + //Find up to date itemstacks in player inventory + List itemStacks = findItemStacksInInventory(player, blockStates); + + //place blocks + for (int i = 0; i < coordinates.size(); i++) { + BlockPos blockPos = coordinates.get(i); + IBlockState blockState = blockStates.get(i); + ItemStack itemStack = itemStacks.get(i); + + if (player.world.isBlockLoaded(blockPos, true)) { + //check itemstack empty + if (itemStack.isEmpty()) continue; + SurvivalHelper.placeBlock(player.world, player, blockPos, blockState, itemStack, EnumFacing.UP, hitVec, false, false); + } + } + + if (player.world.isRemote) + BlockPreviewRenderer.onBlocksPlaced(coordinates, itemStacks, blockStates, blockSet.getFirstPos(), blockSet.getSecondPos()); + + //add to undo + addUndo(player, blockSet); + + return true; + } + + private static List findItemStacksInInventory(EntityPlayer player, List blockStates) { + List itemStacks = new ArrayList<>(blockStates.size()); + for (IBlockState blockState : blockStates) { + itemStacks.add(InventoryHelper.findItemStackInInventory(player, blockState)); + } + return itemStacks; + } +} 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 f4e5aac..d4b966b 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java @@ -265,12 +265,10 @@ public class RadialMenu extends GuiScreen { final TextureAtlasSprite sprite = ClientProxy.getBuildModeIcon(menuRegion.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 double x1 = x - 8; + final double x2 = x + 8; + final double y1 = y - 8; + final double y2 = y + 8; final float f = 1f; final float a = 1f; @@ -298,8 +296,8 @@ public class RadialMenu extends GuiScreen { final TextureAtlasSprite sprite = ClientProxy.getModeOptionIcon(button.action); - final double btnmiddleX = (button.x1 + button.x2) / 2.0; - final double btnmiddleY = (button.y1 + button.y2) / 2.0; + final double btnmiddleX = (button.x1 + button.x2) / 2 + 0.01; + final double btnmiddleY = (button.y1 + button.y2) / 2 + 0.01; final double btnx1 = btnmiddleX - 8; final double btnx2 = btnmiddleX + 8; final double btny1 = btnmiddleY - 8; @@ -337,15 +335,23 @@ public class RadialMenu extends GuiScreen { if (button.highlighted) { String text = TextFormatting.AQUA + button.name; int wrap = 120; - String keybind = TextFormatting.GRAY + "(None)"; + String keybind = "None"; //Add keybind in brackets + if (button.action == ModeOptions.ActionEnum.UNDO) { + keybind = ClientProxy.keyBindings[4].getDisplayName(); + } + if (button.action == ModeOptions.ActionEnum.REDO) { + String sneak = Minecraft.getMinecraft().gameSettings.keyBindSneak.getDisplayName(); + keybind = sneak + " + " + ClientProxy.keyBindings[4].getDisplayName(); + } if (button.action == ModeOptions.ActionEnum.REPLACE) { - keybind = TextFormatting.GRAY + " (" + WordUtils.capitalizeFully(ClientProxy.keyBindings[1].getDisplayName().toLowerCase()) + ")"; + keybind = ClientProxy.keyBindings[1].getDisplayName(); } if (button.action == ModeOptions.ActionEnum.OPEN_MODIFIER_SETTINGS) { - keybind = TextFormatting.GRAY + " (" + WordUtils.capitalizeFully(ClientProxy.keyBindings[0].getDisplayName()) + ")"; + keybind = ClientProxy.keyBindings[0].getDisplayName(); } + String keybindFormatted = TextFormatting.GRAY + " (" + WordUtils.capitalizeFully(keybind) + ")"; if (button.textSide == EnumFacing.WEST) { @@ -362,7 +368,7 @@ public class RadialMenu extends GuiScreen { fontRenderer.drawSplitString( text, (int) (middleX + (button.x1 + button.x2) * 0.5 - fontRenderer.getStringWidth(text) * 0.5), (int) (middleY + button.y1 - 26), wrap,0xffffffff); - fontRenderer.drawSplitString( keybind, (int) (middleX + (button.x1 + button.x2) * 0.5 - fontRenderer.getStringWidth(keybind) * 0.5), + fontRenderer.drawSplitString( keybindFormatted, (int) (middleX + (button.x1 + button.x2) * 0.5 - fontRenderer.getStringWidth(keybindFormatted) * 0.5), (int) (middleY + button.y1 - 14), wrap,0xffffffff); } else if (button.textSide == EnumFacing.DOWN || button.textSide == EnumFacing.SOUTH) { @@ -370,7 +376,7 @@ public class RadialMenu extends GuiScreen { fontRenderer.drawSplitString(text, (int) (middleX + (button.x1 + button.x2) * 0.5 - fontRenderer.getStringWidth(text) * 0.5), (int) (middleY + button.y1 + 24), wrap, 0xffffffff); - fontRenderer.drawSplitString(keybind, (int) (middleX + (button.x1 + button.x2) * 0.5 - fontRenderer.getStringWidth(keybind) * 0.5), + fontRenderer.drawSplitString(keybindFormatted, (int) (middleX + (button.x1 + button.x2) * 0.5 - fontRenderer.getStringWidth(keybindFormatted) * 0.5), (int) (middleY + button.y1 + 36), wrap, 0xffffffff); } diff --git a/src/main/java/nl/requios/effortlessbuilding/helper/FixedStack.java b/src/main/java/nl/requios/effortlessbuilding/helper/FixedStack.java new file mode 100644 index 0000000..473ade2 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/helper/FixedStack.java @@ -0,0 +1,52 @@ +package nl.requios.effortlessbuilding.helper; + +//Stack with fixed size. Removes (overwrites) oldest element on push. +public class FixedStack { + private T[] stack; + private int size; + private int top; + private int filled = 0; //how many valid items are in the stack + + public FixedStack(T[] stack) { + this.stack = stack; + this.top = 0; + this.size = stack.length; + } + + public void push(T object) { + if (top == stack.length) + top = 0; + + stack[top] = object; + top++; + + if (filled < size - 1) + filled++; + } + + public T pop() { + if (filled <= 0) return null; + + if (top - 1 < 0) + top = size; + + top--; + T object = stack[top]; + filled--; + + return object; + } + + public void clear() { + top = 0; + filled = 0; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return filled <= 0; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/helper/InventoryHelper.java b/src/main/java/nl/requios/effortlessbuilding/helper/InventoryHelper.java new file mode 100644 index 0000000..4471647 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/helper/InventoryHelper.java @@ -0,0 +1,30 @@ +package nl.requios.effortlessbuilding.helper; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +public class InventoryHelper { + + public static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState blockState) { + for (ItemStack invStack : player.inventory.mainInventory) { + if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock && + ((ItemBlock) invStack.getItem()).getBlock().equals(blockState.getBlock())) { + return invStack; + } + } + return ItemStack.EMPTY; + } + + public static int findTotalBlocksInInventory(EntityPlayer player, IBlockState blockState) { + int total = 0; + for (ItemStack invStack : player.inventory.mainInventory) { + if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock && + ((ItemBlock) invStack.getItem()).getBlock().equals(blockState.getBlock())) { + total += invStack.getCount(); + } + } + return total; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java index 2869ea6..cfed703 100644 --- a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java +++ b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java @@ -77,14 +77,15 @@ public class ClientProxy implements IProxy { @Override public void init(FMLInitializationEvent event) { // register key bindings - keyBindings = new KeyBinding[4]; + keyBindings = new KeyBinding[5]; // instantiate the key bindings keyBindings[0] = new KeyBinding("key.effortlessbuilding.hud.desc", Keyboard.KEY_ADD, "key.effortlessbuilding.category"); keyBindings[1] = new KeyBinding("key.effortlessbuilding.replace.desc", Keyboard.KEY_SUBTRACT, "key.effortlessbuilding.category"); keyBindings[2] = new KeyBinding("key.effortlessbuilding.creative.desc", Keyboard.KEY_NONE, "key.effortlessbuilding.category"); keyBindings[3] = new KeyBinding("key.effortlessbuilding.mode.desc", Keyboard.KEY_LMENU, "key.effortlessbuilding.category"); -// keyBindings[4] = new KeyBinding("Reload shaders", Keyboard.KEY_TAB, "key.effortlessbuilding.category"); + keyBindings[4] = new KeyBinding("key.effortlessbuilding.undo.desc", Keyboard.KEY_U, "key.effortlessbuilding.category"); +// keyBindings[5] = new KeyBinding("Reload shaders", Keyboard.KEY_TAB, "key.effortlessbuilding.category"); // register all the key bindings for (int i = 0; i < keyBindings.length; ++i) { @@ -318,8 +319,16 @@ public class ClientProxy implements IProxy { } } -// if (keyBindings[4].isPressed()) { -// //TODO remove + //Undo + if (keyBindings[4].isPressed()) { + ModeOptions.ActionEnum action = ModeOptions.ActionEnum.UNDO; + if (player.isSneaking()) action = ModeOptions.ActionEnum.REDO; + ModeOptions.performAction(player, action); + EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(action)); + } + + //For shader development +// if (keyBindings[5].isPressed()) { // ShaderHandler.init(); // EffortlessBuilding.log(player, "Reloaded shaders"); // } diff --git a/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviewRenderer.java b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviewRenderer.java index 0992932..36deedf 100644 --- a/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviewRenderer.java +++ b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviewRenderer.java @@ -26,6 +26,7 @@ import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings; import nl.requios.effortlessbuilding.compatibility.CompatHelper; +import nl.requios.effortlessbuilding.helper.InventoryHelper; import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.item.ItemRandomizerBag; @@ -158,12 +159,7 @@ public class BlockPreviewRenderer { 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); - }); + sortOnDistanceToPlayer(newCoordinates, player); hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), Math.abs(hitVec.z - ((int) hitVec.z))); @@ -206,12 +202,14 @@ public class BlockPreviewRenderer { //Render block previews if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) { + int blockCount; + //Use fancy shader if config allows, otherwise outlines if (BuildConfig.visuals.useShaders && newCoordinates.size() < BuildConfig.visuals.shaderTreshold) { RenderHandler.beginBlockPreviews(); - renderBlockPreviews(newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, !breaking, breaking); + blockCount = renderBlockPreviews(newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, !breaking, breaking); RenderHandler.endBlockPreviews(); } else { @@ -227,8 +225,27 @@ public class BlockPreviewRenderer { } RenderHandler.endLines(); + + blockCount = newCoordinates.size(); + } + + //Display block count and dimensions in actionbar + if (BuildModes.isActive(player)) { + BlockPos dim = secondPos.subtract(firstPos); + dim = new BlockPos(Math.abs(dim.getX()) + 1, Math.abs(dim.getY()) + 1, Math.abs(dim.getZ()) + 1); + + String dimensions = "("; + if (dim.getX() > 1) dimensions += dim.getX() + "x"; + if (dim.getZ() > 1) dimensions += dim.getZ() + "x"; + if (dim.getY() > 1) dimensions += dim.getY() + "x"; + dimensions = dimensions.substring(0, dimensions.length() - 1); + if (dimensions.length() > 1) dimensions += ")"; + + EffortlessBuilding.log(player, blockCount + " blocks " + dimensions, true); } } + + } RenderHandler.beginLines(); @@ -264,14 +281,15 @@ public class BlockPreviewRenderer { BuildConfig.visuals.alwaysShowBlockPreview; } - protected static void renderBlockPreviews(List coordinates, List blockStates, + protected static int renderBlockPreviews(List coordinates, List blockStates, List itemStacks, float dissolve, BlockPos firstPos, BlockPos secondPos, boolean checkCanPlace, boolean red) { EntityPlayer player = Minecraft.getMinecraft().player; ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); BlockRendererDispatcher dispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher(); + int blocksValid = 0; - if (coordinates.isEmpty()) return; + if (coordinates.isEmpty()) return blocksValid; for (int i = coordinates.size() - 1; i >= 0; i--) { BlockPos blockPos = coordinates.get(i); @@ -289,43 +307,57 @@ public class BlockPreviewRenderer { new Vec3d(blockPos), new Vec3d(firstPos), new Vec3d(secondPos), blockPos == secondPos, red)); RenderHandler.renderBlockPreview(dispatcher, blockPos, blockState); + blocksValid++; } } + return blocksValid; } public static void onBlocksPlaced() { + onBlocksPlaced(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos); + } + + public static void onBlocksPlaced(List coordinates, List itemStacks, List blockStates, + BlockPos firstPos, BlockPos secondPos) { EntityPlayerSP player = Minecraft.getMinecraft().player; ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); //Check if block previews are enabled - if (doRenderBlockPreviews(modifierSettings, modeSettings, previousFirstPos)) { + if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) { //Save current coordinates, blockstates and itemstacks - if (!previousCoordinates.isEmpty() && previousBlockStates.size() == previousCoordinates.size() && - previousCoordinates.size() > 1 && previousCoordinates.size() < BuildConfig.visuals.shaderTreshold) { + if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() && + coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderTreshold) { - placedDataList.add(new PlacedData(ClientProxy.ticksInGame, previousCoordinates, previousBlockStates, - previousItemStacks, previousFirstPos, previousSecondPos, false)); + placedDataList.add(new PlacedData(ClientProxy.ticksInGame, coordinates, blockStates, + itemStacks, firstPos, secondPos, false)); } } } public static void onBlocksBroken() { + onBlocksBroken(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos); + } + + public static void onBlocksBroken(List coordinates, List itemStacks, List blockStates, + BlockPos firstPos, BlockPos secondPos) { EntityPlayerSP player = Minecraft.getMinecraft().player; ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); //Check if block previews are enabled - if (doRenderBlockPreviews(modifierSettings, modeSettings, previousFirstPos)) { + if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) { //Save current coordinates, blockstates and itemstacks - if (!previousCoordinates.isEmpty() && previousBlockStates.size() == previousCoordinates.size() && - previousCoordinates.size() > 1 && previousCoordinates.size() < BuildConfig.visuals.shaderTreshold) { + if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() && + coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderTreshold) { - placedDataList.add(new PlacedData(ClientProxy.ticksInGame, previousCoordinates, previousBlockStates, - previousItemStacks, previousFirstPos, previousSecondPos, true)); + sortOnDistanceToPlayer(coordinates, player); + + placedDataList.add(new PlacedData(ClientProxy.ticksInGame, coordinates, blockStates, + itemStacks, firstPos, secondPos, true)); } } @@ -373,4 +405,15 @@ public class BlockPreviewRenderer { ARBShaderObjects.glUniform1iARB(redUniform, red ? 1 : 0); }; } + + private static void sortOnDistanceToPlayer(List coordinates, EntityPlayer player) { + + Collections.sort(coordinates, (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); + }); + + } } diff --git a/src/main/resources/assets/effortlessbuilding/lang/en_us.lang b/src/main/resources/assets/effortlessbuilding/lang/en_us.lang index 5dada4d..83a945e 100644 --- a/src/main/resources/assets/effortlessbuilding/lang/en_us.lang +++ b/src/main/resources/assets/effortlessbuilding/lang/en_us.lang @@ -3,6 +3,7 @@ key.effortlessbuilding.hud.desc=Modifier Menu key.effortlessbuilding.replace.desc=Toggle QuickReplace key.effortlessbuilding.creative.desc=Toggle Survival/Creative Mode key.effortlessbuilding.mode.desc=Radial Menu +key.effortlessbuilding.undo.desc=Undo item.effortlessbuilding:randomizer_bag.name=Randomizer Bag item.effortlessbuilding:reach_upgrade1.name=Reach Upgrade 1 @@ -19,8 +20,8 @@ effortlessbuilding.mode.diagonal_wall=Diagonal Wall (WIP) effortlessbuilding.mode.slope_floor=Slope Floor (WIP) effortlessbuilding.mode.cube=Cube (WIP) -effortlessbuilding.action.undo=Undo (WIP) -effortlessbuilding.action.redo=Redo (WIP) +effortlessbuilding.action.undo=Undo +effortlessbuilding.action.redo=Redo effortlessbuilding.action.replace=Replace effortlessbuilding.action.open_modifier_settings=Open Modifier Settings diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/open_modifier_settings.png b/src/main/resources/assets/effortlessbuilding/textures/icons/open_modifier_settings.png index 2d846ea..80c2180 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/open_modifier_settings.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/open_modifier_settings.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/redo.png b/src/main/resources/assets/effortlessbuilding/textures/icons/redo.png index 2d846ea..c26d8f7 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/redo.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/redo.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/replace.png b/src/main/resources/assets/effortlessbuilding/textures/icons/replace.png index 2d846ea..6df2b2b 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/replace.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/replace.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/undo.png b/src/main/resources/assets/effortlessbuilding/textures/icons/undo.png index 2d846ea..8882682 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/icons/undo.png and b/src/main/resources/assets/effortlessbuilding/textures/icons/undo.png differ