Added circle, cylinder and sphere buildmodes. Refactored buildmodes to use hierarchy classes, much less code duplication. Added support for multiple options per build mode.
Added alternative placement key (ctrl) that toggles between first two actions of first option. Fixed crash when placing ladders.
This commit is contained in:
@@ -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.
|
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||||
|
|
||||||
|
|
||||||
version = "1.12.2-2.15"
|
version = "1.12.2-2.16"
|
||||||
group = "nl.requios.effortlessbuilding" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
group = "nl.requios.effortlessbuilding" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
archivesBaseName = "effortlessbuilding"
|
archivesBaseName = "effortlessbuilding"
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class EffortlessBuilding
|
|||||||
{
|
{
|
||||||
public static final String MODID = "effortlessbuilding";
|
public static final String MODID = "effortlessbuilding";
|
||||||
public static final String NAME = "Effortless Building";
|
public static final String NAME = "Effortless Building";
|
||||||
public static final String VERSION = "1.12.2-2.15";
|
public static final String VERSION = "1.12.2-2.16";
|
||||||
|
|
||||||
@Mod.Instance(EffortlessBuilding.MODID)
|
@Mod.Instance(EffortlessBuilding.MODID)
|
||||||
public static EffortlessBuilding instance;
|
public static EffortlessBuilding instance;
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
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.Dictionary;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public abstract class BaseBuildMode implements IBuildMode {
|
||||||
|
//In singleplayer client and server variables are shared
|
||||||
|
//Split everything that needs separate values and may not be called twice in one click
|
||||||
|
protected Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
||||||
|
protected Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
||||||
|
protected Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
||||||
|
protected Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
||||||
|
protected Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(EntityPlayer player) {
|
||||||
|
rightClickClientTable.put(player.getUniqueID(), 0);
|
||||||
|
rightClickServerTable.put(player.getUniqueID(), 0);
|
||||||
|
firstPosTable.put(player.getUniqueID(), BlockPos.ORIGIN);
|
||||||
|
sideHitTable.put(player.getUniqueID(), EnumFacing.UP);
|
||||||
|
hitVecTable.put(player.getUniqueID(), Vec3d.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumFacing getSideHit(EntityPlayer player) {
|
||||||
|
return sideHitTable.get(player.getUniqueID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec3d getHitVec(EntityPlayer player) {
|
||||||
|
return hitVecTable.get(player.getUniqueID());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,11 +4,14 @@ import net.minecraft.entity.player.EntityPlayer;
|
|||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeOptions.ActionEnum;
|
import nl.requios.effortlessbuilding.buildmode.buildmodes.*;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.buildmodes.Circle;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.buildmodes.Cylinder;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.buildmodes.Sphere;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.*;
|
import nl.requios.effortlessbuilding.buildmodifier.*;
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
|
||||||
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
|
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
|
||||||
import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
|
import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
|
||||||
@@ -19,6 +22,8 @@ import java.util.Dictionary;
|
|||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*;
|
||||||
|
|
||||||
public class BuildModes {
|
public class BuildModes {
|
||||||
|
|
||||||
//Static variables are shared between client and server in singleplayer
|
//Static variables are shared between client and server in singleplayer
|
||||||
@@ -27,21 +32,24 @@ public class BuildModes {
|
|||||||
public static Dictionary<EntityPlayer, Boolean> currentlyBreakingServer = new Hashtable<>();
|
public static Dictionary<EntityPlayer, Boolean> currentlyBreakingServer = new Hashtable<>();
|
||||||
|
|
||||||
public enum BuildModeEnum {
|
public enum BuildModeEnum {
|
||||||
NORMAL("effortlessbuilding.mode.normal", new Normal(), new ActionEnum[]{}),
|
NORMAL("effortlessbuilding.mode.normal", new Normal()),
|
||||||
NORMAL_PLUS("effortlessbuilding.mode.normal_plus", new NormalPlus(), new ActionEnum[]{ActionEnum.NORMAL_SPEED, ActionEnum.FAST_SPEED}),
|
NORMAL_PLUS("effortlessbuilding.mode.normal_plus", new NormalPlus(), OptionEnum.BUILD_SPEED),
|
||||||
LINE("effortlessbuilding.mode.line", new Line(), new ActionEnum[]{/*ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5*/}),
|
LINE("effortlessbuilding.mode.line", new Line() /*, OptionEnum.THICKNESS*/),
|
||||||
WALL("effortlessbuilding.mode.wall", new Wall(), new ActionEnum[]{ActionEnum.FULL, ActionEnum.HOLLOW}),
|
WALL("effortlessbuilding.mode.wall", new Wall(), OptionEnum.FILL),
|
||||||
FLOOR("effortlessbuilding.mode.floor", new Floor(), new ActionEnum[]{ActionEnum.FULL, ActionEnum.HOLLOW}),
|
FLOOR("effortlessbuilding.mode.floor", new Floor(), OptionEnum.FILL),
|
||||||
DIAGONAL_LINE("effortlessbuilding.mode.diagonal_line", new DiagonalLine(), new ActionEnum[]{/*ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5*/}),
|
DIAGONAL_LINE("effortlessbuilding.mode.diagonal_line", new DiagonalLine() /*, OptionEnum.THICKNESS*/),
|
||||||
DIAGONAL_WALL("effortlessbuilding.mode.diagonal_wall", new DiagonalWall(), new ActionEnum[]{/*ActionEnum.FULL, ActionEnum.HOLLOW*/}),
|
DIAGONAL_WALL("effortlessbuilding.mode.diagonal_wall", new DiagonalWall() /*, OptionEnum.FILL*/),
|
||||||
SLOPE_FLOOR("effortlessbuilding.mode.slope_floor", new SlopeFloor(), new ActionEnum[]{ActionEnum.SHORT_EDGE, ActionEnum.LONG_EDGE}),
|
SLOPE_FLOOR("effortlessbuilding.mode.slope_floor", new SlopeFloor(), OptionEnum.RAISED_EDGE),
|
||||||
CUBE("effortlessbuilding.mode.cube", new Cube(), new ActionEnum[]{ActionEnum.CUBE_FULL, ActionEnum.CUBE_HOLLOW, ActionEnum.CUBE_SKELETON});
|
CIRCLE("effortlessbuilding.mode.circle", new Circle(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
|
||||||
|
CYLINDER("effortlessbuilding.mode.cylinder", new Cylinder(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
|
||||||
|
SPHERE("effortlessbuilding.mode.sphere", new Sphere(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
|
||||||
|
CUBE("effortlessbuilding.mode.cube", new Cube(), OptionEnum.CUBE_FILL);
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
public IBuildMode instance;
|
public IBuildMode instance;
|
||||||
public ActionEnum[] options;
|
public OptionEnum[] options;
|
||||||
|
|
||||||
BuildModeEnum(String name, IBuildMode instance, ActionEnum[] options) {
|
BuildModeEnum(String name, IBuildMode instance, OptionEnum... options) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
@@ -220,4 +228,18 @@ public class BuildModes {
|
|||||||
return new Vec3d(x, y, z);
|
return new Vec3d(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isCriteriaValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace, Vec3d lineBound, Vec3d planeBound, double distToPlayerSq) {
|
||||||
|
boolean intersects = false;
|
||||||
|
if (!skipRaytrace) {
|
||||||
|
//collision within a 1 block radius to selected is fine
|
||||||
|
RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, lineBound, false, true, false);
|
||||||
|
intersects = rayTraceResult != null && rayTraceResult.typeOfHit == RayTraceResult.Type.BLOCK &&
|
||||||
|
planeBound.subtract(rayTraceResult.hitVec).lengthSquared() > 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return planeBound.subtract(start).dotProduct(look) > 0 &&
|
||||||
|
distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
|
||||||
|
!intersects;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
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 nl.requios.effortlessbuilding.helper.ReachHelper;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Cube implements IBuildMode {
|
|
||||||
//In singleplayer client and server variables are shared
|
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
|
||||||
private Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(EntityPlayer player) {
|
|
||||||
rightClickClientTable.put(player.getUniqueID(), 0);
|
|
||||||
rightClickServerTable.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<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
rightClickNr++;
|
|
||||||
rightClickTable.put(player.getUniqueID(), rightClickNr);
|
|
||||||
|
|
||||||
if (rightClickNr == 1) {
|
|
||||||
//If clicking in air, reset and try again
|
|
||||||
if (blockPos == null) {
|
|
||||||
rightClickTable.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 if (rightClickNr == 2) {
|
|
||||||
//Second click, find other floor point
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, skipRaytrace);
|
|
||||||
|
|
||||||
if (secondPos == null) {
|
|
||||||
rightClickTable.put(player.getUniqueID(), 1);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
secondPosTable.put(player.getUniqueID(), secondPos);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//Third click, place cube with height
|
|
||||||
list = findCoordinates(player, blockPos, skipRaytrace);
|
|
||||||
rightClickTable.put(player.getUniqueID(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
if (rightClickNr == 0) {
|
|
||||||
if (blockPos != null)
|
|
||||||
list.add(blockPos);
|
|
||||||
} else if (rightClickNr == 1) {
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, skipRaytrace);
|
|
||||||
if (secondPos == null) return list;
|
|
||||||
|
|
||||||
//Add whole floor
|
|
||||||
//Limit amount of blocks you can place per row
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
|
||||||
int y = firstPos.getY();
|
|
||||||
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
|
||||||
|
|
||||||
//limit axis
|
|
||||||
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
|
||||||
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
|
||||||
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
|
||||||
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
|
||||||
|
|
||||||
if (ModeOptions.getCubeFill() == ModeOptions.ActionEnum.CUBE_SKELETON) {
|
|
||||||
//Hollow floor
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y, z1);
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y, z2);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x1, y);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x2, y);
|
|
||||||
} else {
|
|
||||||
//Filled floor
|
|
||||||
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) {
|
|
||||||
|
|
||||||
list.add(new BlockPos(l, y, n));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
BlockPos secondPos = secondPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
BlockPos thirdPos = DiagonalLine.findHeight(player, secondPos, skipRaytrace);
|
|
||||||
if (thirdPos == null) return list;
|
|
||||||
|
|
||||||
//Add whole cube
|
|
||||||
//Limit amount of blocks you can place per row
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
int x1 = firstPos.getX(), x2 = thirdPos.getX();
|
|
||||||
int y1 = firstPos.getY(), y2 = thirdPos.getY();
|
|
||||||
int z1 = firstPos.getZ(), z2 = thirdPos.getZ();
|
|
||||||
|
|
||||||
//limit axis
|
|
||||||
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
|
||||||
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
|
||||||
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
|
|
||||||
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
|
|
||||||
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
|
||||||
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
|
||||||
|
|
||||||
switch (ModeOptions.getCubeFill()) {
|
|
||||||
case CUBE_FULL:
|
|
||||||
addCubeBlocks(list, x1, x2, y1, y2, z1, z2);
|
|
||||||
break;
|
|
||||||
case CUBE_HOLLOW:
|
|
||||||
addHollowCubeBlocks(list, x1, x2, y1, y2, z1, z2);
|
|
||||||
break;
|
|
||||||
case CUBE_SKELETON:
|
|
||||||
addSkeletonCubeBlocks(list, x1, x2, y1, y2, z1, z2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addHollowCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
|
|
||||||
Wall.addXWallBlocks(list, x1, y1, y2, z1, z2);
|
|
||||||
Wall.addXWallBlocks(list, x2, y1, y2, z1, z2);
|
|
||||||
|
|
||||||
Wall.addZWallBlocks(list, x1, x2, y1, y2, z1);
|
|
||||||
Wall.addZWallBlocks(list, x1, x2, y1, y2, z2);
|
|
||||||
|
|
||||||
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
|
|
||||||
Floor.addFloorBlocks(list, x1, x2, y2, z1, z2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSkeletonCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y1, z1);
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y1, z2);
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y2, z1);
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y2, z2);
|
|
||||||
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x1, z1);
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x1, z2);
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x2, z1);
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x2, z2);
|
|
||||||
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x1, y1);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x1, y2);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x2, y1);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x2, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumFacing getSideHit(EntityPlayer player) {
|
|
||||||
return sideHitTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3d getHitVec(EntityPlayer player) {
|
|
||||||
return hitVecTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
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 nl.requios.effortlessbuilding.helper.ReachHelper;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class DiagonalWall implements IBuildMode {
|
|
||||||
//In singleplayer client and server variables are shared
|
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
|
||||||
private Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(EntityPlayer player) {
|
|
||||||
rightClickClientTable.put(player.getUniqueID(), 0);
|
|
||||||
rightClickServerTable.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<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
rightClickNr++;
|
|
||||||
rightClickTable.put(player.getUniqueID(), rightClickNr);
|
|
||||||
|
|
||||||
if (rightClickNr == 1) {
|
|
||||||
//If clicking in air, reset and try again
|
|
||||||
if (blockPos == null) {
|
|
||||||
rightClickTable.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 if (rightClickNr == 2) {
|
|
||||||
//Second click, find other floor point
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
|
|
||||||
|
|
||||||
if (secondPos == null) {
|
|
||||||
rightClickTable.put(player.getUniqueID(), 1);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
secondPosTable.put(player.getUniqueID(), secondPos);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//Third click, place diagonal wall with height
|
|
||||||
list = findCoordinates(player, blockPos, skipRaytrace);
|
|
||||||
rightClickTable.put(player.getUniqueID(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
if (rightClickNr == 0) {
|
|
||||||
if (blockPos != null)
|
|
||||||
list.add(blockPos);
|
|
||||||
} else if (rightClickNr == 1) {
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
|
|
||||||
if (secondPos == null) return list;
|
|
||||||
|
|
||||||
//Add diagonal line
|
|
||||||
list.addAll(DiagonalLine.getDiagonalLineBlocks(player, firstPos, secondPos, 1));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
BlockPos secondPos = secondPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
BlockPos thirdPos = DiagonalLine.findHeight(player, secondPos, skipRaytrace);
|
|
||||||
if (thirdPos == null) return list;
|
|
||||||
|
|
||||||
//Add diagonal wall
|
|
||||||
list.addAll(getDiagonalWallBlocks(player, firstPos, secondPos, thirdPos));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add diagonal wall from first to second
|
|
||||||
public static List<BlockPos> getDiagonalWallBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, BlockPos thirdPos) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
//Get diagonal line blocks
|
|
||||||
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, firstPos, secondPos, 1);
|
|
||||||
|
|
||||||
//Limit amount of blocks we can place
|
|
||||||
int lowest = Math.min(firstPos.getY(), thirdPos.getY());
|
|
||||||
int highest = Math.max(firstPos.getY(), thirdPos.getY());
|
|
||||||
|
|
||||||
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
|
|
||||||
|
|
||||||
//Copy diagonal line on y axis
|
|
||||||
for (int y = lowest; y <= highest; y++) {
|
|
||||||
for (BlockPos blockPos : diagonalLineBlocks) {
|
|
||||||
list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumFacing getSideHit(EntityPlayer player) {
|
|
||||||
return sideHitTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3d getHitVec(EntityPlayer player) {
|
|
||||||
return hitVecTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
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 nl.requios.effortlessbuilding.helper.ReachHelper;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Floor implements IBuildMode {
|
|
||||||
//In singleplayer client and server variables are shared
|
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
|
||||||
private Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
static class Criteria {
|
|
||||||
Vec3d planeBound;
|
|
||||||
double distToPlayerSq;
|
|
||||||
|
|
||||||
Criteria(Vec3d planeBound, Vec3d start) {
|
|
||||||
this.planeBound = planeBound;
|
|
||||||
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
|
|
||||||
}
|
|
||||||
|
|
||||||
//check if its not behind the player and its not too close and not too far
|
|
||||||
//also check if raytrace from player to block does not intersect blocks
|
|
||||||
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
|
||||||
|
|
||||||
boolean intersects = false;
|
|
||||||
if (!skipRaytrace) {
|
|
||||||
//collision within a 1 block radius to selected is fine
|
|
||||||
RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, planeBound, false, true, false);
|
|
||||||
intersects = rayTraceResult != null && rayTraceResult.typeOfHit == RayTraceResult.Type.BLOCK &&
|
|
||||||
planeBound.subtract(rayTraceResult.hitVec).lengthSquared() > 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return planeBound.subtract(start).dotProduct(look) > 0 &&
|
|
||||||
distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
|
|
||||||
!intersects;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(EntityPlayer player) {
|
|
||||||
rightClickClientTable.put(player.getUniqueID(), 0);
|
|
||||||
rightClickServerTable.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<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
rightClickNr++;
|
|
||||||
rightClickTable.put(player.getUniqueID(), rightClickNr);
|
|
||||||
|
|
||||||
if (rightClickNr == 1) {
|
|
||||||
//If clicking in air, reset and try again
|
|
||||||
if (blockPos == null) {
|
|
||||||
rightClickTable.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, skipRaytrace);
|
|
||||||
rightClickTable.put(player.getUniqueID(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
if (rightClickNr == 0) {
|
|
||||||
if (blockPos != null)
|
|
||||||
list.add(blockPos);
|
|
||||||
} else {
|
|
||||||
BlockPos secondPos = findFloor(player, firstPos, skipRaytrace);
|
|
||||||
if (secondPos == null) return list;
|
|
||||||
|
|
||||||
//Add whole floor
|
|
||||||
list.addAll(getFloorBlocks(player, firstPos, secondPos));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockPos findFloor(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
|
||||||
Vec3d look = player.getLookVec();
|
|
||||||
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
|
|
||||||
|
|
||||||
List<Criteria> criteriaList = new ArrayList<>(3);
|
|
||||||
|
|
||||||
//Y
|
|
||||||
Vec3d yBound = BuildModes.findYBound(firstPos.getY(), start, look);
|
|
||||||
criteriaList.add(new Criteria(yBound, start));
|
|
||||||
|
|
||||||
//Remove invalid criteria
|
|
||||||
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
|
|
||||||
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
|
|
||||||
|
|
||||||
//If none are valid, return empty list of blocks
|
|
||||||
if (criteriaList.isEmpty()) return null;
|
|
||||||
|
|
||||||
//Then only 1 can be valid, return that one
|
|
||||||
Criteria selected = criteriaList.get(0);
|
|
||||||
|
|
||||||
return new BlockPos(selected.planeBound);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<BlockPos> getFloorBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
//Limit amount of blocks you can place per row
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
|
||||||
int y = firstPos.getY();
|
|
||||||
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
|
||||||
|
|
||||||
//limit axis
|
|
||||||
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
|
||||||
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
|
||||||
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
|
||||||
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
|
||||||
|
|
||||||
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
|
||||||
addFloorBlocks(list, x1, x2, y, z1, z2);
|
|
||||||
else
|
|
||||||
addHollowFloorBlocks(list, x1, x2, y, z1, z2);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
|
|
||||||
|
|
||||||
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) {
|
|
||||||
|
|
||||||
list.add(new BlockPos(l, y, n));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addHollowFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y, z1);
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y, z2);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x1, y);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x2, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumFacing getSideHit(EntityPlayer player) {
|
|
||||||
return sideHitTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3d getHitVec(EntityPlayer player) {
|
|
||||||
return hitVecTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,7 +30,10 @@ public class ModeOptions {
|
|||||||
|
|
||||||
THICKNESS_1("effortlessbuilding.action.thickness_1"),
|
THICKNESS_1("effortlessbuilding.action.thickness_1"),
|
||||||
THICKNESS_3("effortlessbuilding.action.thickness_3"),
|
THICKNESS_3("effortlessbuilding.action.thickness_3"),
|
||||||
THICKNESS_5("effortlessbuilding.action.thickness_5");
|
THICKNESS_5("effortlessbuilding.action.thickness_5"),
|
||||||
|
|
||||||
|
CIRCLE_START_CORNER("effortlessbuilding.action.start_corner"),
|
||||||
|
CIRCLE_START_CENTER("effortlessbuilding.action.start_center");
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
@@ -39,11 +42,48 @@ public class ModeOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum OptionEnum {
|
||||||
|
BUILD_SPEED("effortlessbuilding.action.build_speed", ActionEnum.NORMAL_SPEED, ActionEnum.FAST_SPEED),
|
||||||
|
FILL("effortlessbuilding.action.filling", ActionEnum.FULL, ActionEnum.HOLLOW),
|
||||||
|
CUBE_FILL("effortlessbuilding.action.filling", ActionEnum.CUBE_FULL, ActionEnum.CUBE_HOLLOW, ActionEnum.CUBE_SKELETON),
|
||||||
|
RAISED_EDGE("effortlessbuilding.action.raised_edge", ActionEnum.SHORT_EDGE, ActionEnum.LONG_EDGE),
|
||||||
|
LINE_THICKNESS("effortlessbuilding.action.thickness", ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5),
|
||||||
|
CIRCLE_START("effortlessbuilding.action.circle_start", ActionEnum.CIRCLE_START_CORNER, ActionEnum.CIRCLE_START_CENTER);
|
||||||
|
|
||||||
|
public String name;
|
||||||
|
public ActionEnum[] actions;
|
||||||
|
|
||||||
|
OptionEnum(String name, ActionEnum... actions){
|
||||||
|
this.name = name;
|
||||||
|
this.actions = actions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED;
|
private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED;
|
||||||
private static ActionEnum fill = ActionEnum.FULL;
|
private static ActionEnum fill = ActionEnum.FULL;
|
||||||
private static ActionEnum cubeFill = ActionEnum.CUBE_FULL;
|
private static ActionEnum cubeFill = ActionEnum.CUBE_FULL;
|
||||||
private static ActionEnum raisedEdge = ActionEnum.SHORT_EDGE;
|
private static ActionEnum raisedEdge = ActionEnum.SHORT_EDGE;
|
||||||
private static ActionEnum lineThickness = ActionEnum.THICKNESS_1;
|
private static ActionEnum lineThickness = ActionEnum.THICKNESS_1;
|
||||||
|
private static ActionEnum circleStart = ActionEnum.CIRCLE_START_CORNER;
|
||||||
|
|
||||||
|
public static ActionEnum getOptionSetting(OptionEnum option) {
|
||||||
|
switch (option) {
|
||||||
|
case BUILD_SPEED:
|
||||||
|
return getBuildSpeed();
|
||||||
|
case FILL:
|
||||||
|
return getFill();
|
||||||
|
case CUBE_FILL:
|
||||||
|
return getCubeFill();
|
||||||
|
case RAISED_EDGE:
|
||||||
|
return getRaisedEdge();
|
||||||
|
case LINE_THICKNESS:
|
||||||
|
return getLineThickness();
|
||||||
|
case CIRCLE_START:
|
||||||
|
return getCircleStart();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static ActionEnum getBuildSpeed() {
|
public static ActionEnum getBuildSpeed() {
|
||||||
return buildSpeed;
|
return buildSpeed;
|
||||||
@@ -65,6 +105,10 @@ public class ModeOptions {
|
|||||||
return lineThickness;
|
return lineThickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ActionEnum getCircleStart() {
|
||||||
|
return circleStart;
|
||||||
|
}
|
||||||
|
|
||||||
//Called on both client and server
|
//Called on both client and server
|
||||||
public static void performAction(EntityPlayer player, ActionEnum action) {
|
public static void performAction(EntityPlayer player, ActionEnum action) {
|
||||||
if (action == null) return;
|
if (action == null) return;
|
||||||
@@ -123,6 +167,12 @@ public class ModeOptions {
|
|||||||
case THICKNESS_5:
|
case THICKNESS_5:
|
||||||
lineThickness = ActionEnum.THICKNESS_5;
|
lineThickness = ActionEnum.THICKNESS_5;
|
||||||
break;
|
break;
|
||||||
|
case CIRCLE_START_CENTER:
|
||||||
|
circleStart = ActionEnum.CIRCLE_START_CENTER;
|
||||||
|
break;
|
||||||
|
case CIRCLE_START_CORNER:
|
||||||
|
circleStart = ActionEnum.CIRCLE_START_CORNER;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.world.isRemote && action != ActionEnum.REPLACE && action != ActionEnum.OPEN_MODIFIER_SETTINGS) {
|
if (player.world.isRemote && action != ActionEnum.REPLACE && action != ActionEnum.OPEN_MODIFIER_SETTINGS) {
|
||||||
|
|||||||
@@ -1,178 +0,0 @@
|
|||||||
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 nl.requios.effortlessbuilding.helper.ReachHelper;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class SlopeFloor implements IBuildMode {
|
|
||||||
//In singleplayer client and server variables are shared
|
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
|
||||||
private Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(EntityPlayer player) {
|
|
||||||
rightClickClientTable.put(player.getUniqueID(), 0);
|
|
||||||
rightClickServerTable.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<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
rightClickNr++;
|
|
||||||
rightClickTable.put(player.getUniqueID(), rightClickNr);
|
|
||||||
|
|
||||||
if (rightClickNr == 1) {
|
|
||||||
//If clicking in air, reset and try again
|
|
||||||
if (blockPos == null) {
|
|
||||||
rightClickTable.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 if (rightClickNr == 2) {
|
|
||||||
//Second click, find other floor point
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
|
|
||||||
|
|
||||||
if (secondPos == null) {
|
|
||||||
rightClickTable.put(player.getUniqueID(), 1);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
secondPosTable.put(player.getUniqueID(), secondPos);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//Third click, place slope floor with height
|
|
||||||
list = findCoordinates(player, blockPos, skipRaytrace);
|
|
||||||
rightClickTable.put(player.getUniqueID(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
if (rightClickNr == 0) {
|
|
||||||
if (blockPos != null)
|
|
||||||
list.add(blockPos);
|
|
||||||
} else if (rightClickNr == 1) {
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
|
|
||||||
if (secondPos == null) return list;
|
|
||||||
|
|
||||||
//Add whole floor
|
|
||||||
list.addAll(Floor.getFloorBlocks(player, firstPos, secondPos));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
BlockPos secondPos = secondPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
BlockPos thirdPos = DiagonalLine.findHeight(player, secondPos, skipRaytrace);
|
|
||||||
if (thirdPos == null) return list;
|
|
||||||
|
|
||||||
//Add slope floor blocks
|
|
||||||
list.addAll(getSlopeFloorBlocks(player, firstPos, secondPos, thirdPos));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add slope floor from first to second
|
|
||||||
public static List<BlockPos> getSlopeFloorBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, BlockPos thirdPos) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
//Determine whether to use x or z axis to slope up
|
|
||||||
boolean onXAxis = true;
|
|
||||||
|
|
||||||
int xLength = Math.abs(secondPos.getX() - firstPos.getX());
|
|
||||||
int zLength = Math.abs(secondPos.getZ() - firstPos.getZ());
|
|
||||||
|
|
||||||
if (ModeOptions.getRaisedEdge() == ModeOptions.ActionEnum.SHORT_EDGE) {
|
|
||||||
//Slope along short edge
|
|
||||||
if (zLength > xLength) onXAxis = false;
|
|
||||||
} else {
|
|
||||||
//Slope along long edge
|
|
||||||
if (zLength <= xLength) onXAxis = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onXAxis) {
|
|
||||||
//Along X goes up
|
|
||||||
|
|
||||||
//Get diagonal line blocks
|
|
||||||
BlockPos linePoint = new BlockPos(secondPos.getX(), thirdPos.getY(), firstPos.getZ());
|
|
||||||
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, firstPos, linePoint, 1f);
|
|
||||||
|
|
||||||
//Limit amount of blocks we can place
|
|
||||||
int lowest = Math.min(firstPos.getZ(), secondPos.getZ());
|
|
||||||
int highest = Math.max(firstPos.getZ(), secondPos.getZ());
|
|
||||||
|
|
||||||
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
|
|
||||||
|
|
||||||
//Copy diagonal line on x axis
|
|
||||||
for (int z = lowest; z <= highest; z++) {
|
|
||||||
for (BlockPos blockPos : diagonalLineBlocks) {
|
|
||||||
list.add(new BlockPos(blockPos.getX(), blockPos.getY(), z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//Along Z goes up
|
|
||||||
|
|
||||||
//Get diagonal line blocks
|
|
||||||
BlockPos linePoint = new BlockPos(firstPos.getX(), thirdPos.getY(), secondPos.getZ());
|
|
||||||
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, firstPos, linePoint, 1f);
|
|
||||||
|
|
||||||
//Limit amount of blocks we can place
|
|
||||||
int lowest = Math.min(firstPos.getX(), secondPos.getX());
|
|
||||||
int highest = Math.max(firstPos.getX(), secondPos.getX());
|
|
||||||
|
|
||||||
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
|
|
||||||
|
|
||||||
//Copy diagonal line on x axis
|
|
||||||
for (int x = lowest; x <= highest; x++) {
|
|
||||||
for (BlockPos blockPos : diagonalLineBlocks) {
|
|
||||||
list.add(new BlockPos(x, blockPos.getY(), blockPos.getZ()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumFacing getSideHit(EntityPlayer player) {
|
|
||||||
return sideHitTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3d getHitVec(EntityPlayer player) {
|
|
||||||
return hitVecTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,21 +3,15 @@ package nl.requios.effortlessbuilding.buildmode;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.buildmodes.DiagonalLine;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.buildmodes.Floor;
|
||||||
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class DiagonalLine implements IBuildMode {
|
public abstract class ThreeClicksBuildMode extends BaseBuildMode {
|
||||||
//In singleplayer client and server variables are shared
|
protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
|
||||||
private Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
static class HeightCriteria {
|
static class HeightCriteria {
|
||||||
Vec3d planeBound;
|
Vec3d planeBound;
|
||||||
@@ -42,27 +36,14 @@ public class DiagonalLine implements IBuildMode {
|
|||||||
//also check if raytrace from player to block does not intersect blocks
|
//also check if raytrace from player to block does not intersect blocks
|
||||||
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
||||||
|
|
||||||
boolean intersects = false;
|
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq);
|
||||||
if (!skipRaytrace) {
|
|
||||||
//collision within a 1 block radius to selected is fine
|
|
||||||
RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, lineBound, false, true, false);
|
|
||||||
intersects = rayTraceResult != null && rayTraceResult.typeOfHit == RayTraceResult.Type.BLOCK &&
|
|
||||||
planeBound.subtract(rayTraceResult.hitVec).lengthSquared() > 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return planeBound.subtract(start).dotProduct(look) > 0 &&
|
|
||||||
distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
|
|
||||||
!intersects;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(EntityPlayer player) {
|
public void initialize(EntityPlayer player) {
|
||||||
rightClickClientTable.put(player.getUniqueID(), 0);
|
super.initialize(player);
|
||||||
rightClickServerTable.put(player.getUniqueID(), 0);
|
secondPosTable.put(player.getUniqueID(), BlockPos.ORIGIN);
|
||||||
firstPosTable.put(player.getUniqueID(), BlockPos.ORIGIN);
|
|
||||||
sideHitTable.put(player.getUniqueID(), EnumFacing.UP);
|
|
||||||
hitVecTable.put(player.getUniqueID(), Vec3d.ZERO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -89,7 +70,7 @@ public class DiagonalLine implements IBuildMode {
|
|||||||
} else if (rightClickNr == 2) {
|
} else if (rightClickNr == 2) {
|
||||||
//Second click, find other floor point
|
//Second click, find other floor point
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
|
BlockPos secondPos = findSecondPos(player, firstPos, true);
|
||||||
|
|
||||||
if (secondPos == null) {
|
if (secondPos == null) {
|
||||||
rightClickTable.put(player.getUniqueID(), 1);
|
rightClickTable.put(player.getUniqueID(), 1);
|
||||||
@@ -99,7 +80,7 @@ public class DiagonalLine implements IBuildMode {
|
|||||||
secondPosTable.put(player.getUniqueID(), secondPos);
|
secondPosTable.put(player.getUniqueID(), secondPos);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//Third click, place diagonal line with height
|
//Third click, place diagonal wall with height
|
||||||
list = findCoordinates(player, blockPos, skipRaytrace);
|
list = findCoordinates(player, blockPos, skipRaytrace);
|
||||||
rightClickTable.put(player.getUniqueID(), 0);
|
rightClickTable.put(player.getUniqueID(), 0);
|
||||||
}
|
}
|
||||||
@@ -119,26 +100,75 @@ public class DiagonalLine implements IBuildMode {
|
|||||||
} else if (rightClickNr == 1) {
|
} else if (rightClickNr == 1) {
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
||||||
|
|
||||||
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
|
BlockPos secondPos = findSecondPos(player, firstPos, true);
|
||||||
if (secondPos == null) return list;
|
if (secondPos == null) return list;
|
||||||
|
|
||||||
|
//Limit amount of blocks you can place per row
|
||||||
|
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
||||||
|
|
||||||
|
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
||||||
|
int y1 = firstPos.getY(), y2 = secondPos.getY();
|
||||||
|
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
||||||
|
|
||||||
|
//limit axis
|
||||||
|
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
||||||
|
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
||||||
|
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
|
||||||
|
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
|
||||||
|
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
||||||
|
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
||||||
|
|
||||||
//Add diagonal line from first to second
|
//Add diagonal line from first to second
|
||||||
list.addAll(getDiagonalLineBlocks(player , firstPos, secondPos, 10));
|
list.addAll(getIntermediateBlocks(player, x1, y1, z1, x2, y2, z2));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
||||||
BlockPos secondPos = secondPosTable.get(player.getUniqueID());
|
BlockPos secondPos = secondPosTable.get(player.getUniqueID());
|
||||||
|
|
||||||
BlockPos thirdPos = findHeight(player, secondPos, skipRaytrace);
|
BlockPos thirdPos = findThirdPos(player, firstPos, secondPos, skipRaytrace);
|
||||||
if (thirdPos == null) return list;
|
if (thirdPos == null) return list;
|
||||||
|
|
||||||
|
//Limit amount of blocks you can place per row
|
||||||
|
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
||||||
|
|
||||||
|
int x1 = firstPos.getX(), x2 = secondPos.getX(), x3 = thirdPos.getX();
|
||||||
|
int y1 = firstPos.getY(), y2 = secondPos.getY(), y3 = thirdPos.getY();
|
||||||
|
int z1 = firstPos.getZ(), z2 = secondPos.getZ(), z3 = thirdPos.getZ();
|
||||||
|
|
||||||
|
//limit axis
|
||||||
|
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
||||||
|
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
||||||
|
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
|
||||||
|
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
|
||||||
|
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
||||||
|
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
||||||
|
|
||||||
|
if (x3 - x1 >= axisLimit) x3 = x1 + axisLimit - 1;
|
||||||
|
if (x1 - x3 >= axisLimit) x3 = x1 - axisLimit + 1;
|
||||||
|
if (y3 - y1 >= axisLimit) y3 = y1 + axisLimit - 1;
|
||||||
|
if (y1 - y3 >= axisLimit) y3 = y1 - axisLimit + 1;
|
||||||
|
if (z3 - z1 >= axisLimit) z3 = z1 + axisLimit - 1;
|
||||||
|
if (z1 - z3 >= axisLimit) z3 = z1 - axisLimit + 1;
|
||||||
|
|
||||||
//Add diagonal line from first to third
|
//Add diagonal line from first to third
|
||||||
list.addAll(getDiagonalLineBlocks(player , firstPos, thirdPos, 10));
|
list.addAll(getFinalBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3));
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Finds the place of the second block pos
|
||||||
|
protected abstract BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace);
|
||||||
|
|
||||||
|
//Finds the place of the third block pos
|
||||||
|
protected abstract BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace);
|
||||||
|
|
||||||
|
//After first and second pos are known, we want to visualize the blocks in a way (like floor for cube)
|
||||||
|
protected abstract List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2);
|
||||||
|
|
||||||
|
//After first, second and third pos are known, we want all the blocks
|
||||||
|
protected abstract List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3);
|
||||||
|
|
||||||
//Finds height after floor has been chosen in buildmodes with 3 clicks
|
//Finds height after floor has been chosen in buildmodes with 3 clicks
|
||||||
public static BlockPos findHeight(EntityPlayer player, BlockPos secondPos, boolean skipRaytrace) {
|
public static BlockPos findHeight(EntityPlayer player, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
Vec3d look = player.getLookVec();
|
Vec3d look = player.getLookVec();
|
||||||
@@ -182,47 +212,4 @@ public class DiagonalLine implements IBuildMode {
|
|||||||
}
|
}
|
||||||
return new BlockPos(selected.lineBound);
|
return new BlockPos(selected.lineBound);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//Add diagonal line from first to second
|
|
||||||
public static List<BlockPos> getDiagonalLineBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, float sampleMultiplier) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
|
||||||
int y1 = firstPos.getY(), y2 = secondPos.getY();
|
|
||||||
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
|
||||||
|
|
||||||
//limit axis
|
|
||||||
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
|
||||||
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
|
||||||
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
|
|
||||||
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
|
|
||||||
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
|
||||||
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
|
||||||
|
|
||||||
Vec3d first = new Vec3d(x1, y1, z1).add(0.5, 0.5, 0.5);
|
|
||||||
Vec3d second = new Vec3d(x2, y2, z2).add(0.5, 0.5, 0.5);
|
|
||||||
|
|
||||||
int iterations = (int) Math.ceil(first.distanceTo(second) * sampleMultiplier);
|
|
||||||
for (double t = 0; t <= 1.0; t += 1.0/iterations) {
|
|
||||||
Vec3d lerp = first.add(second.subtract(first).scale(t));
|
|
||||||
BlockPos candidate = new BlockPos(lerp);
|
|
||||||
//Only add if not equal to the last in the list
|
|
||||||
if (list.isEmpty() || !list.get(list.size() - 1).equals(candidate))
|
|
||||||
list.add(candidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumFacing getSideHit(EntityPlayer player) {
|
|
||||||
return sideHitTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3d getHitVec(EntityPlayer player) {
|
|
||||||
return hitVecTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
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 nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Dictionary;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public abstract class TwoClicksBuildMode extends BaseBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
||||||
|
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
||||||
|
rightClickNr++;
|
||||||
|
rightClickTable.put(player.getUniqueID(), rightClickNr);
|
||||||
|
|
||||||
|
if (rightClickNr == 1) {
|
||||||
|
//If clicking in air, reset and try again
|
||||||
|
if (blockPos == null) {
|
||||||
|
rightClickTable.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 blocks
|
||||||
|
list = findCoordinates(player, blockPos, skipRaytrace);
|
||||||
|
rightClickTable.put(player.getUniqueID(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
||||||
|
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
||||||
|
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
||||||
|
|
||||||
|
if (rightClickNr == 0) {
|
||||||
|
if (blockPos != null)
|
||||||
|
list.add(blockPos);
|
||||||
|
} else {
|
||||||
|
BlockPos secondPos = findSecondPos(player, firstPos, skipRaytrace);
|
||||||
|
if (secondPos == null) return list;
|
||||||
|
|
||||||
|
//Limit amount of blocks we can place per row
|
||||||
|
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
||||||
|
|
||||||
|
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
||||||
|
int y1 = firstPos.getY(), y2 = secondPos.getY();
|
||||||
|
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
||||||
|
|
||||||
|
//limit axis
|
||||||
|
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
||||||
|
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
||||||
|
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
|
||||||
|
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
|
||||||
|
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
||||||
|
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
||||||
|
|
||||||
|
list.addAll(getAllBlocks(player, x1, y1, z1, x2, y2, z2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Finds the place of the second block pos based on criteria (floor must be on same height as first click, wall on same plane etc)
|
||||||
|
protected abstract BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace);
|
||||||
|
|
||||||
|
//After first and second pos are known, we want all the blocks
|
||||||
|
protected abstract List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2);
|
||||||
|
}
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
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 nl.requios.effortlessbuilding.helper.ReachHelper;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Wall implements IBuildMode {
|
|
||||||
//In singleplayer client and server variables are shared
|
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
|
||||||
private Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
static class Criteria {
|
|
||||||
Vec3d planeBound;
|
|
||||||
double distToPlayerSq;
|
|
||||||
double angle;
|
|
||||||
|
|
||||||
Criteria(Vec3d planeBound, BlockPos firstPos, Vec3d start, Vec3d look) {
|
|
||||||
this.planeBound = planeBound;
|
|
||||||
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
|
|
||||||
Vec3d wall = this.planeBound.subtract(new Vec3d(firstPos));
|
|
||||||
this.angle = wall.x * look.x + wall.z * look.z; //dot product ignoring y (looking up/down should not affect this angle)
|
|
||||||
}
|
|
||||||
|
|
||||||
//check if its not behind the player and its not too close and not too far
|
|
||||||
//also check if raytrace from player to block does not intersect blocks
|
|
||||||
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
|
||||||
|
|
||||||
boolean intersects = false;
|
|
||||||
if (!skipRaytrace) {
|
|
||||||
//collision within a 1 block radius to selected is fine
|
|
||||||
RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, planeBound, false, true, false);
|
|
||||||
intersects = rayTraceResult != null && rayTraceResult.typeOfHit == RayTraceResult.Type.BLOCK &&
|
|
||||||
planeBound.subtract(rayTraceResult.hitVec).lengthSquared() > 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return planeBound.subtract(start).dotProduct(look) > 0 &&
|
|
||||||
distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
|
|
||||||
!intersects;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(EntityPlayer player) {
|
|
||||||
rightClickClientTable.put(player.getUniqueID(), 0);
|
|
||||||
rightClickServerTable.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<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
rightClickNr++;
|
|
||||||
rightClickTable.put(player.getUniqueID(), rightClickNr);
|
|
||||||
|
|
||||||
if (rightClickNr == 1) {
|
|
||||||
//If clicking in air, reset and try again
|
|
||||||
if (blockPos == null) {
|
|
||||||
rightClickTable.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, skipRaytrace);
|
|
||||||
rightClickTable.put(player.getUniqueID(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
if (rightClickNr == 0) {
|
|
||||||
if (blockPos != null)
|
|
||||||
list.add(blockPos);
|
|
||||||
} else {
|
|
||||||
BlockPos secondPos = findWall(player, firstPos, skipRaytrace);
|
|
||||||
if (secondPos == null) return list;
|
|
||||||
|
|
||||||
//Add whole wall
|
|
||||||
list.addAll(getWallBlocks(player, firstPos, secondPos));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockPos findWall(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
|
||||||
Vec3d look = player.getLookVec();
|
|
||||||
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
|
|
||||||
|
|
||||||
List<Criteria> criteriaList = new ArrayList<>(3);
|
|
||||||
|
|
||||||
//X
|
|
||||||
Vec3d xBound = BuildModes.findXBound(firstPos.getX(), start, look);
|
|
||||||
criteriaList.add(new Criteria(xBound, firstPos, start, look));
|
|
||||||
|
|
||||||
//Z
|
|
||||||
Vec3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look);
|
|
||||||
criteriaList.add(new Criteria(zBound, firstPos, start, look));
|
|
||||||
|
|
||||||
//Remove invalid criteria
|
|
||||||
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
|
|
||||||
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
|
|
||||||
|
|
||||||
//If none are valid, return empty list of blocks
|
|
||||||
if (criteriaList.isEmpty()) return null;
|
|
||||||
|
|
||||||
//If only 1 is valid, choose that one
|
|
||||||
Criteria selected = criteriaList.get(0);
|
|
||||||
|
|
||||||
//If multiple are valid, choose based on criteria
|
|
||||||
if (criteriaList.size() > 1) {
|
|
||||||
//Select the one that is closest
|
|
||||||
//Limit the angle to not be too extreme
|
|
||||||
for (int i = 1; i < criteriaList.size(); i++) {
|
|
||||||
Criteria criteria = criteriaList.get(i);
|
|
||||||
if (criteria.distToPlayerSq < selected.distToPlayerSq && Math.abs(criteria.angle) - Math.abs(selected.angle) < 3)
|
|
||||||
selected = criteria;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BlockPos(selected.planeBound);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<BlockPos> getWallBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
//Limit amount of blocks we can place per row
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
|
||||||
int y1 = firstPos.getY(), y2 = secondPos.getY();
|
|
||||||
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
|
||||||
|
|
||||||
//limit axis
|
|
||||||
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
|
||||||
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
|
||||||
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
|
|
||||||
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
|
|
||||||
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
|
||||||
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
|
||||||
|
|
||||||
if (x1 == x2) {
|
|
||||||
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
|
||||||
addXWallBlocks(list, x1, y1, y2, z1, z2);
|
|
||||||
else
|
|
||||||
addXHollowWallBlocks(list, x1, y1, y2, z1, z2);
|
|
||||||
} else {
|
|
||||||
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
|
||||||
addZWallBlocks(list, x1, x2, y1, y2, z1);
|
|
||||||
else
|
|
||||||
addZHollowWallBlocks(list, x1, x2, y1, y2, z1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addXWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
|
|
||||||
|
|
||||||
for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) {
|
|
||||||
|
|
||||||
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
|
|
||||||
list.add(new BlockPos(x, y, z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addZWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
|
|
||||||
|
|
||||||
for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) {
|
|
||||||
|
|
||||||
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
|
|
||||||
list.add(new BlockPos(x, y, z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addXHollowWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x, y1);
|
|
||||||
Line.addZLineBlocks(list, z1, z2, x, y2);
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x, z1);
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x, z2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addZHollowWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y1, z);
|
|
||||||
Line.addXLineBlocks(list, x1, x2, y2, z);
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x1, z);
|
|
||||||
Line.addYLineBlocks(list, y1, y2, x2, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumFacing getSideHit(EntityPlayer player) {
|
|
||||||
return sideHitTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3d getHitVec(EntityPlayer player) {
|
|
||||||
return hitVecTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Circle extends TwoClicksBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return Floor.findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getCircleBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
float centerX = x1;
|
||||||
|
float centerZ = z1;
|
||||||
|
|
||||||
|
//Adjust for CIRCLE_START
|
||||||
|
if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) {
|
||||||
|
centerX = x1 + (x2 - x1) / 2f;
|
||||||
|
centerZ = z1 + (z2 - z1) / 2f;
|
||||||
|
} else {
|
||||||
|
x1 = (int) (centerX - (x2 - centerX));
|
||||||
|
z1 = (int) (centerZ - (z2 - centerZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
float radiusX = MathHelper.abs(x2 - centerX);
|
||||||
|
float radiusZ = MathHelper.abs(z2 - centerZ);
|
||||||
|
|
||||||
|
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
||||||
|
addCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
|
||||||
|
else
|
||||||
|
addHollowCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
float distance = distance(l, n, centerX, centerZ);
|
||||||
|
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
|
||||||
|
if (distance < radius + 0.4f)
|
||||||
|
list.add(new BlockPos(l, y1, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addHollowCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
float distance = distance(l, n, centerX, centerZ);
|
||||||
|
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
|
||||||
|
if (distance < radius + 0.4f && distance > radius - 0.6f)
|
||||||
|
list.add(new BlockPos(l, y1, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float distance(float x1, float z1, float x2, float z2) {
|
||||||
|
return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (z2 - z1) * (z2 - z1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float calculateEllipseRadius(float centerX, float centerZ, float radiusX, float radiusZ, int x, int z) {
|
||||||
|
//https://math.stackexchange.com/questions/432902/how-to-get-the-radius-of-an-ellipse-at-a-specific-angle-by-knowing-its-semi-majo
|
||||||
|
float theta = (float) MathHelper.atan2(z - centerZ, x - centerX);
|
||||||
|
float part1 = radiusX * radiusX * MathHelper.sin(theta) * MathHelper.sin(theta);
|
||||||
|
float part2 = radiusZ * radiusZ * MathHelper.cos(theta) * MathHelper.cos(theta);
|
||||||
|
return radiusX * radiusZ / MathHelper.sqrt(part1 + part2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Cube extends ThreeClicksBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return Floor.findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
|
return findHeight(player, secondPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return getFloorBlocksUsingCubeFill(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
return getCubeBlocks(player, x1, y1, z1, x3, y3, z3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getFloorBlocksUsingCubeFill(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
if (ModeOptions.getCubeFill() == ModeOptions.ActionEnum.CUBE_SKELETON)
|
||||||
|
Floor.addHollowFloorBlocks(list, x1, x2, y1, z1, z2);
|
||||||
|
else
|
||||||
|
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getCubeBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
switch (ModeOptions.getCubeFill()) {
|
||||||
|
case CUBE_FULL:
|
||||||
|
addCubeBlocks(list, x1, x2, y1, y2, z1, z2);
|
||||||
|
break;
|
||||||
|
case CUBE_HOLLOW:
|
||||||
|
addHollowCubeBlocks(list, x1, x2, y1, y2, z1, z2);
|
||||||
|
break;
|
||||||
|
case CUBE_SKELETON:
|
||||||
|
addSkeletonCubeBlocks(list, x1, x2, y1, y2, z1, z2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addHollowCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
|
||||||
|
Wall.addXWallBlocks(list, x1, y1, y2, z1, z2);
|
||||||
|
Wall.addXWallBlocks(list, x2, y1, y2, z1, z2);
|
||||||
|
|
||||||
|
Wall.addZWallBlocks(list, x1, x2, y1, y2, z1);
|
||||||
|
Wall.addZWallBlocks(list, x1, x2, y1, y2, z2);
|
||||||
|
|
||||||
|
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
|
||||||
|
Floor.addFloorBlocks(list, x1, x2, y2, z1, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addSkeletonCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y1, z1);
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y1, z2);
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y2, z1);
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y2, z2);
|
||||||
|
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x1, z1);
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x1, z2);
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x2, z1);
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x2, z2);
|
||||||
|
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x1, y1);
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x1, y2);
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x2, y1);
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x2, y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Cylinder extends ThreeClicksBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return Floor.findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
|
return findHeight(player, secondPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
return getCylinderBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getCylinderBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
//Get circle blocks (using CIRCLE_START and FILL options built-in)
|
||||||
|
List<BlockPos> circleBlocks = Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
|
||||||
|
int lowest = Math.min(y1, y3);
|
||||||
|
int highest = Math.max(y1, y3);
|
||||||
|
|
||||||
|
//Copy circle on y axis
|
||||||
|
for (int y = lowest; y <= highest; y++) {
|
||||||
|
for (BlockPos blockPos : circleBlocks) {
|
||||||
|
list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DiagonalLine extends ThreeClicksBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return Floor.findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
|
return findHeight(player, secondPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
//Add diagonal line from first to second
|
||||||
|
return getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
//Add diagonal line from first to third
|
||||||
|
return getDiagonalLineBlocks(player, x1, y1, z1, x3, y3, z3, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add diagonal line from first to second
|
||||||
|
public static List<BlockPos> getDiagonalLineBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, float sampleMultiplier) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
Vec3d first = new Vec3d(x1, y1, z1).add(0.5, 0.5, 0.5);
|
||||||
|
Vec3d second = new Vec3d(x2, y2, z2).add(0.5, 0.5, 0.5);
|
||||||
|
|
||||||
|
int iterations = (int) Math.ceil(first.distanceTo(second) * sampleMultiplier);
|
||||||
|
for (double t = 0; t <= 1.0; t += 1.0/iterations) {
|
||||||
|
Vec3d lerp = first.add(second.subtract(first).scale(t));
|
||||||
|
BlockPos candidate = new BlockPos(lerp);
|
||||||
|
//Only add if not equal to the last in the list
|
||||||
|
if (list.isEmpty() || !list.get(list.size() - 1).equals(candidate))
|
||||||
|
list.add(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DiagonalWall extends ThreeClicksBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return Floor.findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
|
return findHeight(player, secondPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
return getDiagonalWallBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add diagonal wall from first to second
|
||||||
|
public static List<BlockPos> getDiagonalWallBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
//Get diagonal line blocks
|
||||||
|
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1);
|
||||||
|
|
||||||
|
int lowest = Math.min(y1, y3);
|
||||||
|
int highest = Math.max(y1, y3);
|
||||||
|
|
||||||
|
//Copy diagonal line on y axis
|
||||||
|
for (int y = lowest; y <= highest; y++) {
|
||||||
|
for (BlockPos blockPos : diagonalLineBlocks) {
|
||||||
|
list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||||
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Floor extends TwoClicksBuildMode {
|
||||||
|
|
||||||
|
static class Criteria {
|
||||||
|
Vec3d planeBound;
|
||||||
|
double distToPlayerSq;
|
||||||
|
|
||||||
|
Criteria(Vec3d planeBound, Vec3d start) {
|
||||||
|
this.planeBound = planeBound;
|
||||||
|
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if its not behind the player and its not too close and not too far
|
||||||
|
//also check if raytrace from player to block does not intersect blocks
|
||||||
|
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
||||||
|
|
||||||
|
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockPos findFloor(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
Vec3d look = player.getLookVec();
|
||||||
|
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
|
||||||
|
|
||||||
|
List<Criteria> criteriaList = new ArrayList<>(3);
|
||||||
|
|
||||||
|
//Y
|
||||||
|
Vec3d yBound = BuildModes.findYBound(firstPos.getY(), start, look);
|
||||||
|
criteriaList.add(new Criteria(yBound, start));
|
||||||
|
|
||||||
|
//Remove invalid criteria
|
||||||
|
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
|
||||||
|
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
|
||||||
|
|
||||||
|
//If none are valid, return empty list of blocks
|
||||||
|
if (criteriaList.isEmpty()) return null;
|
||||||
|
|
||||||
|
//Then only 1 can be valid, return that one
|
||||||
|
Criteria selected = criteriaList.get(0);
|
||||||
|
|
||||||
|
return new BlockPos(selected.planeBound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getFloorBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
||||||
|
addFloorBlocks(list, x1, x2, y1, z1, z2);
|
||||||
|
else
|
||||||
|
addHollowFloorBlocks(list, x1, x2, y1, z1, z2);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
list.add(new BlockPos(l, y, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addHollowFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y, z1);
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y, z2);
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x1, y);
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x2, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +1,16 @@
|
|||||||
package nl.requios.effortlessbuilding.buildmode;
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.util.EnumFacing;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
|
||||||
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Line implements IBuildMode {
|
public class Line extends TwoClicksBuildMode {
|
||||||
//In singleplayer client and server variables are shared
|
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
|
||||||
private Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
|
||||||
private Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
static class Criteria {
|
static class Criteria {
|
||||||
Vec3d planeBound;
|
Vec3d planeBound;
|
||||||
@@ -55,78 +49,14 @@ public class Line implements IBuildMode {
|
|||||||
//also check if raytrace from player to block does not intersect blocks
|
//also check if raytrace from player to block does not intersect blocks
|
||||||
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
||||||
|
|
||||||
boolean intersects = false;
|
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq);
|
||||||
if (!skipRaytrace) {
|
|
||||||
//collision within a 1 block radius to selected is fine
|
|
||||||
RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, lineBound, false, true, false);
|
|
||||||
intersects = rayTraceResult != null && rayTraceResult.typeOfHit == RayTraceResult.Type.BLOCK &&
|
|
||||||
planeBound.subtract(rayTraceResult.hitVec).lengthSquared() > 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return planeBound.subtract(start).dotProduct(look) > 0 &&
|
|
||||||
distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
|
|
||||||
!intersects;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(EntityPlayer player) {
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
rightClickClientTable.put(player.getUniqueID(), 0);
|
return findLine(player, firstPos, skipRaytrace);
|
||||||
rightClickServerTable.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<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
rightClickNr++;
|
|
||||||
rightClickTable.put(player.getUniqueID(), rightClickNr);
|
|
||||||
|
|
||||||
if (rightClickNr == 1) {
|
|
||||||
//If clicking in air, reset and try again
|
|
||||||
if (blockPos == null) {
|
|
||||||
rightClickTable.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, skipRaytrace);
|
|
||||||
rightClickTable.put(player.getUniqueID(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> list = new ArrayList<>();
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
|
|
||||||
int rightClickNr = rightClickTable.get(player.getUniqueID());
|
|
||||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
|
||||||
|
|
||||||
if (rightClickNr == 0) {
|
|
||||||
if (blockPos != null)
|
|
||||||
list.add(blockPos);
|
|
||||||
} else {
|
|
||||||
BlockPos secondPos = findLine(player, firstPos, skipRaytrace);
|
|
||||||
if (secondPos == null) return list;
|
|
||||||
|
|
||||||
list.addAll(getLineBlocks(player, firstPos, secondPos));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockPos findLine(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
public static BlockPos findLine(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
@@ -178,25 +108,14 @@ public class Line implements IBuildMode {
|
|||||||
return new BlockPos(selected.lineBound);
|
return new BlockPos(selected.lineBound);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<BlockPos> getLineBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos) {
|
@Override
|
||||||
|
protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return getLineBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getLineBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
List<BlockPos> list = new ArrayList<>();
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
//Limit amount of blocks we can place
|
|
||||||
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
|
||||||
|
|
||||||
//Add whole line
|
|
||||||
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
|
||||||
int y1 = firstPos.getY(), y2 = secondPos.getY();
|
|
||||||
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
|
||||||
|
|
||||||
//limit axis
|
|
||||||
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
|
|
||||||
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
|
|
||||||
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
|
|
||||||
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
|
|
||||||
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
|
|
||||||
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
|
|
||||||
|
|
||||||
if (x1 != x2) {
|
if (x1 != x2) {
|
||||||
addXLineBlocks(list, x1, x2, y1, z1);
|
addXLineBlocks(list, x1, x2, y1, z1);
|
||||||
} else if (y1 != y2) {
|
} else if (y1 != y2) {
|
||||||
@@ -225,15 +144,4 @@ public class Line implements IBuildMode {
|
|||||||
list.add(new BlockPos(x, y, z));
|
list.add(new BlockPos(x, y, z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumFacing getSideHit(EntityPlayer player) {
|
|
||||||
return sideHitTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3d getHitVec(EntityPlayer player) {
|
|
||||||
return hitVecTable.get(player.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package nl.requios.effortlessbuilding.buildmode;
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package nl.requios.effortlessbuilding.buildmode;
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SlopeFloor extends ThreeClicksBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return Floor.findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
|
return findHeight(player, secondPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
return getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add slope floor from first to second
|
||||||
|
public static List<BlockPos> getSlopeFloorBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
|
||||||
|
|
||||||
|
//Determine whether to use x or z axis to slope up
|
||||||
|
boolean onXAxis = true;
|
||||||
|
|
||||||
|
int xLength = Math.abs(x2 - x1);
|
||||||
|
int zLength = Math.abs(z2 - z1);
|
||||||
|
|
||||||
|
if (ModeOptions.getRaisedEdge() == ModeOptions.ActionEnum.SHORT_EDGE) {
|
||||||
|
//Slope along short edge
|
||||||
|
if (zLength > xLength) onXAxis = false;
|
||||||
|
} else {
|
||||||
|
//Slope along long edge
|
||||||
|
if (zLength <= xLength) onXAxis = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onXAxis) {
|
||||||
|
//Along X goes up
|
||||||
|
|
||||||
|
//Get diagonal line blocks
|
||||||
|
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y3, z1, 1f);
|
||||||
|
|
||||||
|
//Limit amount of blocks we can place
|
||||||
|
int lowest = Math.min(z1, z2);
|
||||||
|
int highest = Math.max(z1, z2);
|
||||||
|
|
||||||
|
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
|
||||||
|
|
||||||
|
//Copy diagonal line on x axis
|
||||||
|
for (int z = lowest; z <= highest; z++) {
|
||||||
|
for (BlockPos blockPos : diagonalLineBlocks) {
|
||||||
|
list.add(new BlockPos(blockPos.getX(), blockPos.getY(), z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//Along Z goes up
|
||||||
|
|
||||||
|
//Get diagonal line blocks
|
||||||
|
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x1, y3, z2, 1f);
|
||||||
|
|
||||||
|
//Limit amount of blocks we can place
|
||||||
|
int lowest = Math.min(x1, x2);
|
||||||
|
int highest = Math.max(x1, x2);
|
||||||
|
|
||||||
|
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
|
||||||
|
|
||||||
|
//Copy diagonal line on x axis
|
||||||
|
for (int x = lowest; x <= highest; x++) {
|
||||||
|
for (BlockPos blockPos : diagonalLineBlocks) {
|
||||||
|
list.add(new BlockPos(x, blockPos.getY(), blockPos.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Sphere extends ThreeClicksBuildMode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return Floor.findFloor(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
|
return findHeight(player, secondPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
return getSphereBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getSphereBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
float centerX = x1;
|
||||||
|
float centerY = y1;
|
||||||
|
float centerZ = z1;
|
||||||
|
|
||||||
|
//Adjust for CIRCLE_START
|
||||||
|
if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) {
|
||||||
|
centerX = x1 + (x2 - x1) / 2f;
|
||||||
|
centerY = y1 + (y3 - y1) / 2f;
|
||||||
|
centerZ = z1 + (z2 - z1) / 2f;
|
||||||
|
} else {
|
||||||
|
x1 = (int) (centerX - (x2 - centerX));
|
||||||
|
y1 = (int) (centerY - (y3 - centerY));
|
||||||
|
z1 = (int) (centerZ - (z2 - centerZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
float radiusX = MathHelper.abs(x2 - centerX);
|
||||||
|
float radiusY = MathHelper.abs(y3 - centerY);
|
||||||
|
float radiusZ = MathHelper.abs(z2 - centerZ);
|
||||||
|
|
||||||
|
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
||||||
|
addSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
|
||||||
|
else
|
||||||
|
addHollowSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2,
|
||||||
|
float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) {
|
||||||
|
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) {
|
||||||
|
|
||||||
|
float distance = distance(l, m, n, centerX, centerY, centerZ);
|
||||||
|
float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n);
|
||||||
|
if (distance < radius + 0.4f)
|
||||||
|
list.add(new BlockPos(l, m, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addHollowSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2,
|
||||||
|
float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) {
|
||||||
|
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) {
|
||||||
|
|
||||||
|
float distance = distance(l, m, n, centerX, centerY, centerZ);
|
||||||
|
float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n);
|
||||||
|
if (distance < radius + 0.4f && distance > radius - 0.6f)
|
||||||
|
list.add(new BlockPos(l, m, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float distance(float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||||
|
return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float calculateSpheroidRadius(float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ, int x, int y, int z) {
|
||||||
|
//Twice ellipse radius
|
||||||
|
float radiusXZ = Circle.calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, x, z);
|
||||||
|
|
||||||
|
//TODO project x to plane
|
||||||
|
|
||||||
|
return Circle.calculateEllipseRadius(centerX, centerY, radiusXZ, radiusY, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package nl.requios.effortlessbuilding.buildmode.buildmodes;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||||
|
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Wall extends TwoClicksBuildMode {
|
||||||
|
|
||||||
|
static class Criteria {
|
||||||
|
Vec3d planeBound;
|
||||||
|
double distToPlayerSq;
|
||||||
|
double angle;
|
||||||
|
|
||||||
|
Criteria(Vec3d planeBound, BlockPos firstPos, Vec3d start, Vec3d look) {
|
||||||
|
this.planeBound = planeBound;
|
||||||
|
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
|
||||||
|
Vec3d wall = this.planeBound.subtract(new Vec3d(firstPos));
|
||||||
|
this.angle = wall.x * look.x + wall.z * look.z; //dot product ignoring y (looking up/down should not affect this angle)
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if its not behind the player and its not too close and not too far
|
||||||
|
//also check if raytrace from player to block does not intersect blocks
|
||||||
|
public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
|
||||||
|
|
||||||
|
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
return findWall(player, firstPos, skipRaytrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockPos findWall(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||||
|
Vec3d look = player.getLookVec();
|
||||||
|
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
|
||||||
|
|
||||||
|
List<Criteria> criteriaList = new ArrayList<>(3);
|
||||||
|
|
||||||
|
//X
|
||||||
|
Vec3d xBound = BuildModes.findXBound(firstPos.getX(), start, look);
|
||||||
|
criteriaList.add(new Criteria(xBound, firstPos, start, look));
|
||||||
|
|
||||||
|
//Z
|
||||||
|
Vec3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look);
|
||||||
|
criteriaList.add(new Criteria(zBound, firstPos, start, look));
|
||||||
|
|
||||||
|
//Remove invalid criteria
|
||||||
|
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
|
||||||
|
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
|
||||||
|
|
||||||
|
//If none are valid, return empty list of blocks
|
||||||
|
if (criteriaList.isEmpty()) return null;
|
||||||
|
|
||||||
|
//If only 1 is valid, choose that one
|
||||||
|
Criteria selected = criteriaList.get(0);
|
||||||
|
|
||||||
|
//If multiple are valid, choose based on criteria
|
||||||
|
if (criteriaList.size() > 1) {
|
||||||
|
//Select the one that is closest
|
||||||
|
//Limit the angle to not be too extreme
|
||||||
|
for (int i = 1; i < criteriaList.size(); i++) {
|
||||||
|
Criteria criteria = criteriaList.get(i);
|
||||||
|
if (criteria.distToPlayerSq < selected.distToPlayerSq && Math.abs(criteria.angle) - Math.abs(selected.angle) < 3)
|
||||||
|
selected = criteria;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BlockPos(selected.planeBound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
return getWallBlocks(player, x1, y1, z1, x2, y2, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockPos> getWallBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||||
|
List<BlockPos> list = new ArrayList<>();
|
||||||
|
|
||||||
|
if (x1 == x2) {
|
||||||
|
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
||||||
|
addXWallBlocks(list, x1, y1, y2, z1, z2);
|
||||||
|
else
|
||||||
|
addXHollowWallBlocks(list, x1, y1, y2, z1, z2);
|
||||||
|
} else {
|
||||||
|
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
|
||||||
|
addZWallBlocks(list, x1, x2, y1, y2, z1);
|
||||||
|
else
|
||||||
|
addZHollowWallBlocks(list, x1, x2, y1, y2, z1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addXWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
|
||||||
|
|
||||||
|
for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) {
|
||||||
|
|
||||||
|
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
|
||||||
|
list.add(new BlockPos(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addZWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
|
||||||
|
|
||||||
|
for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) {
|
||||||
|
|
||||||
|
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
|
||||||
|
list.add(new BlockPos(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addXHollowWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x, y1);
|
||||||
|
Line.addZLineBlocks(list, z1, z2, x, y2);
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x, z1);
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addZHollowWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y1, z);
|
||||||
|
Line.addXLineBlocks(list, x1, x2, y2, z);
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x1, z);
|
||||||
|
Line.addYLineBlocks(list, y1, y2, x2, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -206,6 +206,7 @@ public class UndoRedo {
|
|||||||
|
|
||||||
private static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState blockState) {
|
private static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState blockState) {
|
||||||
ItemStack itemStack = ItemStack.EMPTY;
|
ItemStack itemStack = ItemStack.EMPTY;
|
||||||
|
if (blockState == null) return itemStack;
|
||||||
|
|
||||||
//First try previousBlockStates
|
//First try previousBlockStates
|
||||||
//TODO try to find itemstack with right blockstate first
|
//TODO try to find itemstack with right blockstate first
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import net.minecraft.util.EnumFacing;
|
|||||||
import net.minecraftforge.client.model.ModelLoader;
|
import net.minecraftforge.client.model.ModelLoader;
|
||||||
|
|
||||||
import static nl.requios.effortlessbuilding.buildmode.BuildModes.*;
|
import static nl.requios.effortlessbuilding.buildmode.BuildModes.*;
|
||||||
|
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From Chisels and Bits by AlgorithmX2
|
* From Chisels and Bits by AlgorithmX2
|
||||||
@@ -39,7 +40,7 @@ public class RadialMenu extends GuiScreen {
|
|||||||
private float visibility = 0.0f;
|
private float visibility = 0.0f;
|
||||||
private Stopwatch lastChange = Stopwatch.createStarted();
|
private Stopwatch lastChange = Stopwatch.createStarted();
|
||||||
public BuildModeEnum switchTo = null;
|
public BuildModeEnum switchTo = null;
|
||||||
public ModeOptions.ActionEnum doAction = null;
|
public ActionEnum doAction = null;
|
||||||
public boolean actionUsed = false;
|
public boolean actionUsed = false;
|
||||||
|
|
||||||
private float clampVis(final float f) {
|
private float clampVis(final float f) {
|
||||||
@@ -77,11 +78,11 @@ public class RadialMenu extends GuiScreen {
|
|||||||
public double y1, y2;
|
public double y1, y2;
|
||||||
public boolean highlighted;
|
public boolean highlighted;
|
||||||
|
|
||||||
public final ModeOptions.ActionEnum action;
|
public final ActionEnum action;
|
||||||
public String name;
|
public String name;
|
||||||
public EnumFacing textSide;
|
public EnumFacing textSide;
|
||||||
|
|
||||||
public MenuButton(final String name, final ModeOptions.ActionEnum action, final double x, final double y,
|
public MenuButton(final String name, final ActionEnum action, final double x, final double y,
|
||||||
final EnumFacing textSide) {
|
final EnumFacing textSide) {
|
||||||
this.name = I18n.format(name);
|
this.name = I18n.format(name);
|
||||||
this.action = action;
|
this.action = action;
|
||||||
@@ -138,10 +139,10 @@ public class RadialMenu extends GuiScreen {
|
|||||||
final double mouseYCenter = mouseY - middleY;
|
final double mouseYCenter = mouseY - middleY;
|
||||||
double mouseRadians = Math.atan2(mouseYCenter, mouseXCenter);
|
double mouseRadians = Math.atan2(mouseYCenter, mouseXCenter);
|
||||||
|
|
||||||
final double ringInnerEdge = 20;
|
final double ringInnerEdge = 30;
|
||||||
final double ringOuterEdge = 50;
|
final double ringOuterEdge = 65;
|
||||||
final double textDistance = 60;
|
final double textDistance = 75;
|
||||||
final double buttonDistance = 90;
|
final double buttonDistance = 105;
|
||||||
final double quarterCircle = Math.PI / 2.0;
|
final double quarterCircle = Math.PI / 2.0;
|
||||||
|
|
||||||
if ( mouseRadians < -quarterCircle ) {
|
if ( mouseRadians < -quarterCircle ) {
|
||||||
@@ -157,16 +158,18 @@ public class RadialMenu extends GuiScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Add actions
|
//Add actions
|
||||||
buttons.add(new MenuButton(ModeOptions.ActionEnum.UNDO.name, ModeOptions.ActionEnum.UNDO, -buttonDistance - 26, -13, EnumFacing.UP));
|
buttons.add(new MenuButton(ActionEnum.UNDO.name, ActionEnum.UNDO, -buttonDistance - 26, -13, EnumFacing.UP));
|
||||||
buttons.add(new MenuButton(ModeOptions.ActionEnum.REDO.name, ModeOptions.ActionEnum.REDO, -buttonDistance, -13, EnumFacing.UP));
|
buttons.add(new MenuButton(ActionEnum.REDO.name, ActionEnum.REDO, -buttonDistance, -13, EnumFacing.UP));
|
||||||
buttons.add(new MenuButton(ModeOptions.ActionEnum.OPEN_MODIFIER_SETTINGS.name, ModeOptions.ActionEnum.OPEN_MODIFIER_SETTINGS, -buttonDistance - 26, 13, EnumFacing.DOWN));
|
buttons.add(new MenuButton(ActionEnum.OPEN_MODIFIER_SETTINGS.name, ActionEnum.OPEN_MODIFIER_SETTINGS, -buttonDistance - 26, 13, EnumFacing.DOWN));
|
||||||
buttons.add(new MenuButton(ModeOptions.ActionEnum.REPLACE.name, ModeOptions.ActionEnum.REPLACE, -buttonDistance, 13, EnumFacing.DOWN));
|
buttons.add(new MenuButton(ActionEnum.REPLACE.name, ActionEnum.REPLACE, -buttonDistance, 13, EnumFacing.DOWN));
|
||||||
|
|
||||||
//Add buildmode dependent options
|
//Add buildmode dependent options
|
||||||
ModeOptions.ActionEnum[] options = currentBuildMode.options;
|
OptionEnum[] options = currentBuildMode.options;
|
||||||
for (int i = 0; i < options.length; i++) {
|
for (int i = 0; i < options.length; i++) {
|
||||||
ModeOptions.ActionEnum action = options[i];
|
for (int j = 0; j < options[i].actions.length; j++) {
|
||||||
buttons.add(new MenuButton(action.name, action, buttonDistance + i * 26, -13, EnumFacing.DOWN));
|
ActionEnum action = options[i].actions[j];
|
||||||
|
buttons.add(new MenuButton(action.name, action, buttonDistance + j * 26, -13 + i * 39, EnumFacing.DOWN));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switchTo = null;
|
switchTo = null;
|
||||||
@@ -245,11 +248,12 @@ public class RadialMenu extends GuiScreen {
|
|||||||
float a = 0.5f;
|
float a = 0.5f;
|
||||||
|
|
||||||
//highlight when active option
|
//highlight when active option
|
||||||
if (btn.action == ModeOptions.getBuildSpeed() ||
|
if (btn.action == getBuildSpeed() ||
|
||||||
btn.action == ModeOptions.getFill() ||
|
btn.action == getFill() ||
|
||||||
btn.action == ModeOptions.getCubeFill() ||
|
btn.action == getCubeFill() ||
|
||||||
btn.action == ModeOptions.getRaisedEdge() ||
|
btn.action == getRaisedEdge() ||
|
||||||
btn.action == ModeOptions.getLineThickness()) {
|
btn.action == getLineThickness() ||
|
||||||
|
btn.action == getCircleStart()) {
|
||||||
r = 0.0f;
|
r = 0.0f;
|
||||||
g = 0.5f;
|
g = 0.5f;
|
||||||
b = 1f;
|
b = 1f;
|
||||||
@@ -342,32 +346,12 @@ public class RadialMenu extends GuiScreen {
|
|||||||
|
|
||||||
//Draw strings
|
//Draw strings
|
||||||
//fontRenderer.drawStringWithShadow("Actions", (int) (middleX - buttonDistance - 13) - fontRenderer.getStringWidth("Actions") * 0.5f, (int) middleY - 38, 0xffffffff);
|
//fontRenderer.drawStringWithShadow("Actions", (int) (middleX - buttonDistance - 13) - fontRenderer.getStringWidth("Actions") * 0.5f, (int) middleY - 38, 0xffffffff);
|
||||||
String title = "";
|
|
||||||
if (currentBuildMode.options.length > 0) {
|
//Draw option strings
|
||||||
switch (currentBuildMode.options[0]) {
|
for (int i = 0; i < currentBuildMode.options.length; i++) {
|
||||||
case NORMAL_SPEED:
|
OptionEnum option = options[i];
|
||||||
case FAST_SPEED:
|
fontRenderer.drawStringWithShadow(I18n.format(option.name), (int) (middleX + buttonDistance - 9), (int) middleY - 37 + i * 39, 0xeeeeeeff);
|
||||||
title = I18n.format("effortlessbuilding.action.build_speed");
|
|
||||||
break;
|
|
||||||
case FULL:
|
|
||||||
case HOLLOW:
|
|
||||||
case CUBE_FULL:
|
|
||||||
case CUBE_HOLLOW:
|
|
||||||
case CUBE_SKELETON:
|
|
||||||
title = I18n.format("effortlessbuilding.action.filling");
|
|
||||||
break;
|
|
||||||
case SHORT_EDGE:
|
|
||||||
case LONG_EDGE:
|
|
||||||
title = I18n.format("effortlessbuilding.action.raised_edge");
|
|
||||||
break;
|
|
||||||
case THICKNESS_1:
|
|
||||||
case THICKNESS_3:
|
|
||||||
case THICKNESS_5:
|
|
||||||
title = I18n.format("effortlessbuilding.action.thickness");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fontRenderer.drawStringWithShadow(title, (int) (middleX + buttonDistance - 9), (int) middleY - 37, 0xeeeeeeff);
|
|
||||||
|
|
||||||
String credits = "Effortless Building";
|
String credits = "Effortless Building";
|
||||||
fontRenderer.drawStringWithShadow(credits, width - fontRenderer.getStringWidth(credits) - 4, height - 10, 0x88888888);
|
fontRenderer.drawStringWithShadow(credits, width - fontRenderer.getStringWidth(credits) - 4, height - 10, 0x88888888);
|
||||||
@@ -402,18 +386,26 @@ public class RadialMenu extends GuiScreen {
|
|||||||
String keybindFormatted = "";
|
String keybindFormatted = "";
|
||||||
|
|
||||||
//Add keybind in brackets
|
//Add keybind in brackets
|
||||||
if (button.action == ModeOptions.ActionEnum.UNDO) {
|
if (button.action == ActionEnum.UNDO) {
|
||||||
keybind = ClientProxy.keyBindings[4].getDisplayName();
|
keybind = ClientProxy.keyBindings[4].getDisplayName();
|
||||||
}
|
}
|
||||||
if (button.action == ModeOptions.ActionEnum.REDO) {
|
if (button.action == ActionEnum.REDO) {
|
||||||
keybind = ClientProxy.keyBindings[5].getDisplayName();
|
keybind = ClientProxy.keyBindings[5].getDisplayName();
|
||||||
}
|
}
|
||||||
if (button.action == ModeOptions.ActionEnum.REPLACE) {
|
if (button.action == ActionEnum.REPLACE) {
|
||||||
keybind = ClientProxy.keyBindings[1].getDisplayName();
|
keybind = ClientProxy.keyBindings[1].getDisplayName();
|
||||||
}
|
}
|
||||||
if (button.action == ModeOptions.ActionEnum.OPEN_MODIFIER_SETTINGS) {
|
if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) {
|
||||||
keybind = ClientProxy.keyBindings[0].getDisplayName();
|
keybind = ClientProxy.keyBindings[0].getDisplayName();
|
||||||
}
|
}
|
||||||
|
if (currentBuildMode.options.length > 0) {
|
||||||
|
//Add (ctrl) to first two actions of first option
|
||||||
|
if (button.action == currentBuildMode.options[0].actions[0]
|
||||||
|
|| button.action == currentBuildMode.options[0].actions[1]) {
|
||||||
|
keybind = ClientProxy.keyBindings[6].getDisplayName();
|
||||||
|
if (keybind.equals("LCONTROL")) keybind = "Ctrl";
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!keybind.isEmpty()) keybindFormatted = TextFormatting.GRAY + "(" + WordUtils.capitalizeFully(keybind) + ")";
|
if (!keybind.isEmpty()) keybindFormatted = TextFormatting.GRAY + "(" + WordUtils.capitalizeFully(keybind) + ")";
|
||||||
|
|
||||||
if (button.textSide == EnumFacing.WEST) {
|
if (button.textSide == EnumFacing.WEST) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class ClientProxy implements IProxy {
|
|||||||
@Override
|
@Override
|
||||||
public void init(FMLInitializationEvent event) {
|
public void init(FMLInitializationEvent event) {
|
||||||
// register key bindings
|
// register key bindings
|
||||||
keyBindings = new KeyBinding[6];
|
keyBindings = new KeyBinding[7];
|
||||||
|
|
||||||
// instantiate the key bindings
|
// instantiate the key bindings
|
||||||
keyBindings[0] = new KeyBinding("key.effortlessbuilding.hud.desc", KeyConflictContext.UNIVERSAL, Keyboard.KEY_ADD, "key.effortlessbuilding.category");
|
keyBindings[0] = new KeyBinding("key.effortlessbuilding.hud.desc", KeyConflictContext.UNIVERSAL, Keyboard.KEY_ADD, "key.effortlessbuilding.category");
|
||||||
@@ -97,7 +97,8 @@ public class ClientProxy implements IProxy {
|
|||||||
};
|
};
|
||||||
keyBindings[4] = new KeyBinding("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, Keyboard.KEY_Z, "key.effortlessbuilding.category");
|
keyBindings[4] = new KeyBinding("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, Keyboard.KEY_Z, "key.effortlessbuilding.category");
|
||||||
keyBindings[5] = new KeyBinding("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, Keyboard.KEY_Y, "key.effortlessbuilding.category");
|
keyBindings[5] = new KeyBinding("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, Keyboard.KEY_Y, "key.effortlessbuilding.category");
|
||||||
// keyBindings[6] = new KeyBinding("Reload shaders", Keyboard.KEY_TAB, "key.effortlessbuilding.category");
|
keyBindings[6] = new KeyBinding("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, Keyboard.KEY_LCONTROL, "key.effortlessbuilding.category");
|
||||||
|
// keyBindings[7] = new KeyBinding("Reload shaders", Keyboard.KEY_TAB, "key.effortlessbuilding.category");
|
||||||
|
|
||||||
// register all the key bindings
|
// register all the key bindings
|
||||||
for (int i = 0; i < keyBindings.length; ++i) {
|
for (int i = 0; i < keyBindings.length; ++i) {
|
||||||
@@ -344,8 +345,26 @@ public class ClientProxy implements IProxy {
|
|||||||
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(action));
|
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(action));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Change placement mode
|
||||||
|
if (keyBindings[6].isPressed()) {
|
||||||
|
//Toggle between first two actions of the first option of the current build mode
|
||||||
|
BuildModes.BuildModeEnum currentBuildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
|
||||||
|
if (currentBuildMode.options.length > 0) {
|
||||||
|
ModeOptions.OptionEnum option = currentBuildMode.options[0];
|
||||||
|
if (option.actions.length >= 2) {
|
||||||
|
if (ModeOptions.getOptionSetting(option) == option.actions[0]) {
|
||||||
|
ModeOptions.performAction(player, option.actions[1]);
|
||||||
|
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(option.actions[1]));
|
||||||
|
} else {
|
||||||
|
ModeOptions.performAction(player, option.actions[0]);
|
||||||
|
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(option.actions[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//For shader development
|
//For shader development
|
||||||
if (keyBindings.length >= 7 && keyBindings[6].isPressed()) {
|
if (keyBindings.length >= 8 && keyBindings[7].isPressed()) {
|
||||||
ShaderHandler.init();
|
ShaderHandler.init();
|
||||||
EffortlessBuilding.log(player, "Reloaded shaders");
|
EffortlessBuilding.log(player, "Reloaded shaders");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,13 +195,15 @@ public class BlockPreviewRenderer {
|
|||||||
//if so, renew randomness of randomizer bag
|
//if so, renew randomness of randomizer bag
|
||||||
ItemRandomizerBag.renewRandomness();
|
ItemRandomizerBag.renewRandomness();
|
||||||
//and play sound (max once every tick)
|
//and play sound (max once every tick)
|
||||||
if (startCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) {
|
if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) {
|
||||||
soundTime = ClientProxy.ticksInGame;
|
soundTime = ClientProxy.ticksInGame;
|
||||||
|
|
||||||
SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.world,
|
if (blockStates.get(0) != null) {
|
||||||
newCoordinates.get(0), player);
|
SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.world,
|
||||||
player.world.playSound(player, player.getPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(),
|
newCoordinates.get(0), player);
|
||||||
SoundCategory.BLOCKS, 0.3f, 0.8f);
|
player.world.playSound(player, player.getPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(),
|
||||||
|
SoundCategory.BLOCKS, 0.3f, 0.8f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +238,20 @@ public class BlockPreviewRenderer {
|
|||||||
|
|
||||||
//Display block count and dimensions in actionbar
|
//Display block count and dimensions in actionbar
|
||||||
if (BuildModes.isActive(player)) {
|
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);
|
//Find min and max values (not simply firstPos and secondPos because that doesn't work with circles)
|
||||||
|
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
|
||||||
|
int minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE;
|
||||||
|
int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE;
|
||||||
|
for (BlockPos pos : startCoordinates) {
|
||||||
|
if (pos.getX() < minX) minX = pos.getX();
|
||||||
|
if (pos.getX() > maxX) maxX = pos.getX();
|
||||||
|
if (pos.getY() < minY) minY = pos.getY();
|
||||||
|
if (pos.getY() > maxY) maxY = pos.getY();
|
||||||
|
if (pos.getZ() < minZ) minZ = pos.getZ();
|
||||||
|
if (pos.getZ() > maxZ) maxZ = pos.getZ();
|
||||||
|
}
|
||||||
|
BlockPos dim = new BlockPos(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1);
|
||||||
|
|
||||||
String dimensions = "(";
|
String dimensions = "(";
|
||||||
if (dim.getX() > 1) dimensions += dim.getX() + "x";
|
if (dim.getX() > 1) dimensions += dim.getX() + "x";
|
||||||
|
|||||||
@@ -206,6 +206,8 @@ public class RenderHandler implements IWorldEventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static void renderBlockPreview(BlockRendererDispatcher dispatcher, BlockPos blockPos, IBlockState blockState) {
|
protected static void renderBlockPreview(BlockRendererDispatcher dispatcher, BlockPos blockPos, IBlockState blockState) {
|
||||||
|
if (blockState == null) return;
|
||||||
|
|
||||||
GlStateManager.pushMatrix();
|
GlStateManager.pushMatrix();
|
||||||
GlStateManager.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
GlStateManager.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||||
GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F);
|
GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F);
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ key.effortlessbuilding.category=Effortless Building
|
|||||||
key.effortlessbuilding.hud.desc=Modifier Menu
|
key.effortlessbuilding.hud.desc=Modifier Menu
|
||||||
key.effortlessbuilding.replace.desc=Toggle QuickReplace
|
key.effortlessbuilding.replace.desc=Toggle QuickReplace
|
||||||
key.effortlessbuilding.creative.desc=Toggle Survival/Creative Mode
|
key.effortlessbuilding.creative.desc=Toggle Survival/Creative Mode
|
||||||
key.effortlessbuilding.mode.desc=Radial Menu (C&B compatible)
|
key.effortlessbuilding.mode.desc=Radial Menu
|
||||||
key.effortlessbuilding.undo.desc=Undo
|
key.effortlessbuilding.undo.desc=Undo
|
||||||
key.effortlessbuilding.redo.desc=Redo
|
key.effortlessbuilding.redo.desc=Redo
|
||||||
|
key.effortlessbuilding.altplacement.desc=Alternative placement
|
||||||
|
|
||||||
item.effortlessbuilding:randomizer_bag.name=Randomizer Bag
|
item.effortlessbuilding:randomizer_bag.name=Randomizer Bag
|
||||||
item.effortlessbuilding:reach_upgrade1.name=Reach Upgrade 1
|
item.effortlessbuilding:reach_upgrade1.name=Reach Upgrade 1
|
||||||
@@ -20,6 +21,9 @@ effortlessbuilding.mode.diagonal_line=Diagonal Line
|
|||||||
effortlessbuilding.mode.diagonal_wall=Diagonal Wall
|
effortlessbuilding.mode.diagonal_wall=Diagonal Wall
|
||||||
effortlessbuilding.mode.slope_floor=Slope Floor
|
effortlessbuilding.mode.slope_floor=Slope Floor
|
||||||
effortlessbuilding.mode.cube=Cube
|
effortlessbuilding.mode.cube=Cube
|
||||||
|
effortlessbuilding.mode.circle=Circle
|
||||||
|
effortlessbuilding.mode.cylinder=Cylinder
|
||||||
|
effortlessbuilding.mode.sphere=Sphere
|
||||||
|
|
||||||
effortlessbuilding.action.undo=Undo
|
effortlessbuilding.action.undo=Undo
|
||||||
effortlessbuilding.action.redo=Redo
|
effortlessbuilding.action.redo=Redo
|
||||||
@@ -30,6 +34,7 @@ effortlessbuilding.action.build_speed=Build Speed
|
|||||||
effortlessbuilding.action.filling=Filling
|
effortlessbuilding.action.filling=Filling
|
||||||
effortlessbuilding.action.raised_edge=Raised Edge
|
effortlessbuilding.action.raised_edge=Raised Edge
|
||||||
effortlessbuilding.action.thickness=Line Thickness
|
effortlessbuilding.action.thickness=Line Thickness
|
||||||
|
effortlessbuilding.action.circle_start=Start Point
|
||||||
|
|
||||||
effortlessbuilding.action.normal_speed=Normal
|
effortlessbuilding.action.normal_speed=Normal
|
||||||
effortlessbuilding.action.fast_speed=Fast
|
effortlessbuilding.action.fast_speed=Fast
|
||||||
@@ -41,5 +46,7 @@ effortlessbuilding.action.long_edge=Long Edge
|
|||||||
effortlessbuilding.action.thickness_1=1 Block Thick
|
effortlessbuilding.action.thickness_1=1 Block Thick
|
||||||
effortlessbuilding.action.thickness_3=3 Blocks Thick
|
effortlessbuilding.action.thickness_3=3 Blocks Thick
|
||||||
effortlessbuilding.action.thickness_5=5 Blocks Thick
|
effortlessbuilding.action.thickness_5=5 Blocks Thick
|
||||||
|
effortlessbuilding.action.start_center=Middle
|
||||||
|
effortlessbuilding.action.start_corner=Corner
|
||||||
|
|
||||||
commands.reach.usage=/reach <level>
|
commands.reach.usage=/reach <level>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 273 B |
Binary file not shown.
|
After Width: | Height: | Size: 232 B |
Binary file not shown.
|
After Width: | Height: | Size: 222 B |
Binary file not shown.
|
After Width: | Height: | Size: 292 B |
Binary file not shown.
|
After Width: | Height: | Size: 361 B |
Reference in New Issue
Block a user