1 Commits

Author SHA1 Message Date
Christian Knaapen
0f74b107d6 Refactored shader code to use GL20 instead of ARB. 2019-05-12 17:34:26 +02:00
54 changed files with 1412 additions and 1628 deletions

View File

@@ -1,3 +0,0 @@
This is the version for Minecraft 1.12.
1.13 can be found here: https://bitbucket.org/Requios/effortless-building-1.13/src/master/

View File

@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = "1.12.2-2.16"
version = "1.12.2-2.10"
group = "nl.requios.effortlessbuilding" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "effortlessbuilding"

Binary file not shown.

View File

@@ -1,5 +1,6 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip

110
gradlew vendored
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env sh
#!/usr/bin/env bash
##############################################################################
##
@@ -6,6 +6,47 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -20,49 +61,9 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -89,7 +90,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -113,7 +114,6 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,19 +154,11 @@ if $cygwin ; then
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
APP_ARGS=$(save "$@")
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

14
gradlew.bat vendored
View File

@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,9 +46,10 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -59,6 +60,11 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

View File

@@ -55,7 +55,7 @@ public class BuildConfig {
@Comment({"Determines what blocks can be replaced in survival.",
"-1: only blocks that can be harvested by hand (default)",
"0: blocks that can be harvested with wooden or gold tools",
"0: blocks that can be harvested with wooden oref gold tools",
"1: blocks that can be harvested with stone tools",
"2: blocks that can be harvested with iron tools",
"3: blocks that can be harvested with diamond tools",

View File

@@ -39,7 +39,7 @@ public class EffortlessBuilding
{
public static final String MODID = "effortlessbuilding";
public static final String NAME = "Effortless Building";
public static final String VERSION = "1.12.2-2.16";
public static final String VERSION = "1.12.2-2.10";
@Mod.Instance(EffortlessBuilding.MODID)
public static EffortlessBuilding instance;
@@ -93,20 +93,11 @@ public class EffortlessBuilding
EffortlessBuilding.packetHandler.registerMessage(BlockPlacedMessage.MessageHandler.class, BlockPlacedMessage.class, 3, Side.CLIENT);
EffortlessBuilding.packetHandler.registerMessage(BlockBrokenMessage.MessageHandler.class, BlockBrokenMessage.class, 4, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(BlockBrokenMessage.MessageHandler.class, BlockBrokenMessage.class, 4, Side.CLIENT);
EffortlessBuilding.packetHandler.registerMessage(CancelModeMessage.MessageHandler.class, CancelModeMessage.class, 5, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(CancelModeMessage.MessageHandler.class, CancelModeMessage.class, 5, Side.CLIENT);
EffortlessBuilding.packetHandler.registerMessage(RequestLookAtMessage.MessageHandler.class, RequestLookAtMessage.class, 6, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(RequestLookAtMessage.MessageHandler.class, RequestLookAtMessage.class, 6, Side.CLIENT);
EffortlessBuilding.packetHandler.registerMessage(AddUndoMessage.MessageHandler.class, AddUndoMessage.class, 7, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(AddUndoMessage.MessageHandler.class, AddUndoMessage.class, 7, Side.CLIENT);
EffortlessBuilding.packetHandler.registerMessage(ClearUndoMessage.MessageHandler.class, ClearUndoMessage.class, 8, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(ClearUndoMessage.MessageHandler.class, ClearUndoMessage.class, 8, Side.CLIENT);
proxy.preInit(event);
}

View File

@@ -5,7 +5,6 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.ResourceLocation;
@@ -31,9 +30,6 @@ import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.network.AddUndoMessage;
import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
import nl.requios.effortlessbuilding.network.ClearUndoMessage;
import nl.requios.effortlessbuilding.network.RequestLookAtMessage;
import scala.actors.threadpool.Arrays;
@@ -95,20 +91,14 @@ public class EventHandler
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.NORMAL) {
if (buildMode != BuildModes.BuildModeEnum.NORMAL || modifierSettings.doQuickReplace()) {
event.setCanceled(true);
} else if (modifierSettings.doQuickReplace()) {
//Cancel event and send message if QuickReplace
event.setCanceled(true);
EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(true), (EntityPlayerMP) player);
EffortlessBuilding.packetHandler.sendTo(new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()), (EntityPlayerMP) player);
} else {
//NORMAL mode, let vanilla handle block placing
//But modifiers should still work
//But modifiers and QuickReplace should still work
//Send message to client, which sends message back with raytrace info
EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(false), (EntityPlayerMP) player);
EffortlessBuilding.packetHandler.sendTo(new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()), (EntityPlayerMP) player);
EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()), (EntityPlayerMP) player);
}
}
@@ -123,12 +113,9 @@ public class EventHandler
event.setCanceled(true);
} else {
//NORMAL mode, let vanilla handle block breaking
//But modifiers should still work
//But modifiers and QuickReplace should still work
//Dont break the original block yourself, otherwise Tinkers Hammer and Veinminer won't work
BuildModes.onBlockBroken(event.getPlayer(), event.getPos(), false);
//Add to undo stack in client
EffortlessBuilding.packetHandler.sendTo(new AddUndoMessage(event.getPos(), event.getState(), Blocks.AIR.getDefaultState()), (EntityPlayerMP) event.getPlayer());
}
}
@@ -178,11 +165,8 @@ public class EventHandler
@SubscribeEvent
public static void onPlayerLoggedOut(PlayerLoggedOutEvent event) {
EntityPlayer player = event.player;
if (player.getEntityWorld().isRemote) return;
UndoRedo.clear(player);
EffortlessBuilding.packetHandler.sendTo(new ClearUndoMessage(), (EntityPlayerMP) player);
UndoRedo.clear(event.player);
//TODO call clientside
}
@SubscribeEvent
@@ -195,12 +179,10 @@ public class EventHandler
@SubscribeEvent
public static void onPlayerChangedDimension(PlayerChangedDimensionEvent event) {
EntityPlayer player = event.player;
if (player.getEntityWorld().isRemote) return;
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
UndoRedo.clear(player);
EffortlessBuilding.packetHandler.sendTo(new ClearUndoMessage(), (EntityPlayerMP) player);
UndoRedo.clear(event.player);
//TODO call clientside
}
}

View File

@@ -1,40 +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 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());
}
}

View File

@@ -4,14 +4,11 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.EffortlessBuilding;
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.buildmode.ModeOptions.ActionEnum;
import nl.requios.effortlessbuilding.buildmodifier.*;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
@@ -22,8 +19,6 @@ import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*;
public class BuildModes {
//Static variables are shared between client and server in singleplayer
@@ -32,24 +27,21 @@ public class BuildModes {
public static Dictionary<EntityPlayer, Boolean> currentlyBreakingServer = new Hashtable<>();
public enum BuildModeEnum {
NORMAL("effortlessbuilding.mode.normal", new Normal()),
NORMAL_PLUS("effortlessbuilding.mode.normal_plus", new NormalPlus(), OptionEnum.BUILD_SPEED),
LINE("effortlessbuilding.mode.line", new Line() /*, OptionEnum.THICKNESS*/),
WALL("effortlessbuilding.mode.wall", new Wall(), OptionEnum.FILL),
FLOOR("effortlessbuilding.mode.floor", new Floor(), OptionEnum.FILL),
DIAGONAL_LINE("effortlessbuilding.mode.diagonal_line", new DiagonalLine() /*, OptionEnum.THICKNESS*/),
DIAGONAL_WALL("effortlessbuilding.mode.diagonal_wall", new DiagonalWall() /*, OptionEnum.FILL*/),
SLOPE_FLOOR("effortlessbuilding.mode.slope_floor", new SlopeFloor(), OptionEnum.RAISED_EDGE),
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);
NORMAL("effortlessbuilding.mode.normal", new Normal(), new ActionEnum[]{}),
NORMAL_PLUS("effortlessbuilding.mode.normal_plus", new NormalPlus(), new ActionEnum[]{ActionEnum.NORMAL_SPEED, ActionEnum.FAST_SPEED}),
LINE("effortlessbuilding.mode.line", new Line(), new ActionEnum[]{/*ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5*/}),
WALL("effortlessbuilding.mode.wall", new Wall(), new ActionEnum[]{ActionEnum.FULL, ActionEnum.HOLLOW}),
FLOOR("effortlessbuilding.mode.floor", new Floor(), new ActionEnum[]{ActionEnum.FULL, ActionEnum.HOLLOW}),
DIAGONAL_LINE("effortlessbuilding.mode.diagonal_line", new DiagonalLine(), new ActionEnum[]{/*ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5*/}),
DIAGONAL_WALL("effortlessbuilding.mode.diagonal_wall", new DiagonalWall(), new ActionEnum[]{/*ActionEnum.FULL, ActionEnum.HOLLOW*/}),
SLOPE_FLOOR("effortlessbuilding.mode.slope_floor", new SlopeFloor(), new ActionEnum[]{ActionEnum.SHORT_EDGE, ActionEnum.LONG_EDGE}),
CUBE("effortlessbuilding.mode.cube", new Cube(), new ActionEnum[]{ActionEnum.CUBE_FULL, ActionEnum.CUBE_HOLLOW, ActionEnum.CUBE_SKELETON});
public String name;
public IBuildMode instance;
public OptionEnum[] options;
public ActionEnum[] options;
BuildModeEnum(String name, IBuildMode instance, OptionEnum... options) {
BuildModeEnum(String name, IBuildMode instance, ActionEnum[] options) {
this.name = name;
this.instance = instance;
this.options = options;
@@ -143,16 +135,16 @@ public class BuildModes {
return;
}
if (!ReachHelper.canBreakFar(player)) return;
//If first click
if (currentlyBreaking.get(player) == null) {
//If startpos is null, dont do anything
if (startPos == null) return;
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Get coordinates
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
BuildModeEnum buildMode = modeSettings.getBuildMode();
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, EnumFacing.UP, Vec3d.ZERO, true);
@@ -228,18 +220,4 @@ public class BuildModes {
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;
}
}

View File

@@ -0,0 +1,208 @@
package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.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());
}
}

View File

@@ -3,15 +3,21 @@ 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.buildmode.buildmodes.DiagonalLine;
import nl.requios.effortlessbuilding.buildmode.buildmodes.Floor;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.*;
public abstract class ThreeClicksBuildMode extends BaseBuildMode {
protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
public class DiagonalLine 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<>();
static class HeightCriteria {
Vec3d planeBound;
@@ -36,14 +42,27 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
//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, lineBound, planeBound, 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;
}
}
@Override
public void initialize(EntityPlayer player) {
super.initialize(player);
secondPosTable.put(player.getUniqueID(), BlockPos.ORIGIN);
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
@@ -70,7 +89,7 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
} else if (rightClickNr == 2) {
//Second click, find other floor point
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
BlockPos secondPos = findSecondPos(player, firstPos, true);
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
if (secondPos == null) {
rightClickTable.put(player.getUniqueID(), 1);
@@ -80,7 +99,7 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
secondPosTable.put(player.getUniqueID(), secondPos);
} else {
//Third click, place diagonal wall with height
//Third click, place diagonal line with height
list = findCoordinates(player, blockPos, skipRaytrace);
rightClickTable.put(player.getUniqueID(), 0);
}
@@ -100,75 +119,26 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
} else if (rightClickNr == 1) {
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
BlockPos secondPos = findSecondPos(player, firstPos, true);
BlockPos secondPos = Floor.findFloor(player, firstPos, true);
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
list.addAll(getIntermediateBlocks(player, x1, y1, z1, x2, y2, z2));
list.addAll(getDiagonalLineBlocks(player , firstPos, secondPos, 10));
} else {
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
BlockPos secondPos = secondPosTable.get(player.getUniqueID());
BlockPos thirdPos = findThirdPos(player, firstPos, secondPos, skipRaytrace);
BlockPos thirdPos = findHeight(player, secondPos, skipRaytrace);
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
list.addAll(getFinalBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3));
list.addAll(getDiagonalLineBlocks(player , firstPos, thirdPos, 10));
}
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
public static BlockPos findHeight(EntityPlayer player, BlockPos secondPos, boolean skipRaytrace) {
Vec3d look = player.getLookVec();
@@ -212,4 +182,47 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
}
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());
}
}

View File

@@ -0,0 +1,138 @@
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());
}
}

View File

@@ -0,0 +1,183 @@
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());
}
}

View File

@@ -1,16 +1,22 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
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.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public class Line extends TwoClicksBuildMode {
public class Line 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;
@@ -49,14 +55,78 @@ public class Line extends TwoClicksBuildMode {
//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, lineBound, planeBound, 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;
}
}
@Override
protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
return findLine(player, firstPos, skipRaytrace);
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 = 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) {
@@ -108,14 +178,25 @@ public class Line extends TwoClicksBuildMode {
return new BlockPos(selected.lineBound);
}
@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) {
public static List<BlockPos> getLineBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos) {
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) {
addXLineBlocks(list, x1, x2, y1, z1);
} else if (y1 != y2) {
@@ -144,4 +225,15 @@ public class Line extends TwoClicksBuildMode {
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());
}
}

View File

@@ -30,10 +30,7 @@ public class ModeOptions {
THICKNESS_1("effortlessbuilding.action.thickness_1"),
THICKNESS_3("effortlessbuilding.action.thickness_3"),
THICKNESS_5("effortlessbuilding.action.thickness_5"),
CIRCLE_START_CORNER("effortlessbuilding.action.start_corner"),
CIRCLE_START_CENTER("effortlessbuilding.action.start_center");
THICKNESS_5("effortlessbuilding.action.thickness_5");
public String name;
@@ -42,48 +39,11 @@ 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 fill = ActionEnum.FULL;
private static ActionEnum cubeFill = ActionEnum.CUBE_FULL;
private static ActionEnum raisedEdge = ActionEnum.SHORT_EDGE;
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() {
return buildSpeed;
@@ -105,10 +65,6 @@ public class ModeOptions {
return lineThickness;
}
public static ActionEnum getCircleStart() {
return circleStart;
}
//Called on both client and server
public static void performAction(EntityPlayer player, ActionEnum action) {
if (action == null) return;
@@ -167,12 +123,6 @@ public class ModeOptions {
case THICKNESS_5:
lineThickness = ActionEnum.THICKNESS_5;
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) {

View File

@@ -1,10 +1,9 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
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.buildmode.IBuildMode;
import java.util.ArrayList;
import java.util.List;

View File

@@ -1,10 +1,9 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
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.buildmode.IBuildMode;
import java.util.ArrayList;
import java.util.List;

View File

@@ -0,0 +1,178 @@
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());
}
}

View File

@@ -1,86 +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.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);
}

View File

@@ -0,0 +1,226 @@
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());
}
}

View File

@@ -1,88 +0,0 @@
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);
}
}

View File

@@ -1,104 +0,0 @@
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);
}
}

View File

@@ -1,50 +0,0 @@
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;
}
}

View File

@@ -1,54 +0,0 @@
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;
}
}

View File

@@ -1,52 +0,0 @@
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;
}
}

View File

@@ -1,93 +0,0 @@
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);
}
}

View File

@@ -1,95 +0,0 @@
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;
}
}

View File

@@ -1,110 +0,0 @@
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);
}
}

View File

@@ -1,134 +0,0 @@
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);
}
}

View File

@@ -3,7 +3,6 @@ package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
@@ -21,6 +20,7 @@ import java.util.*;
public class BuildModifiers {
//Called from BuildModes
public static void onBlockPlaced(EntityPlayer player, List<BlockPos> startCoordinates, EnumFacing sideHit, Vec3d hitVec, boolean placeStartPos) {
World world = player.world;
@@ -75,21 +75,12 @@ public class BuildModifiers {
}
}
//Set first previousBlockState to empty if in NORMAL mode, to make undo/redo work
//(Block is placed by the time it gets here, and unplaced after this)
if (!placeStartPos) previousBlockStates.set(0, Blocks.AIR.getDefaultState());
//If all new blockstates are air then no use in adding it, no block was actually placed
//Can happen when e.g. placing one block in yourself
if (Collections.frequency(newBlockStates, Blocks.AIR.getDefaultState()) != newBlockStates.size()) {
//add to undo stack
BlockPos firstPos = startCoordinates.get(0);
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
}
}
public static void onBlockBroken(EntityPlayer player, List<BlockPos> startCoordinates, boolean breakStartPos) {
World world = player.world;
@@ -109,7 +100,7 @@ public class BuildModifiers {
//list of air blockstates
for (BlockPos coordinate : coordinates) {
newBlockStates.add(Blocks.AIR.getDefaultState());
newBlockStates.add(Block.getBlockById(0).getDefaultState());
}
} else {
@@ -134,10 +125,6 @@ public class BuildModifiers {
}
}
//Set first newBlockState to empty if in NORMAL mode, to make undo/redo work
//(Block isn't broken yet by the time it gets here, and broken after this)
if (!breakStartPos) newBlockStates.set(0, Blocks.AIR.getDefaultState());
//add to undo stack
BlockPos firstPos = startCoordinates.get(0);
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
@@ -244,16 +231,6 @@ public class BuildModifiers {
if (coordinates1 == null && coordinates2 == null) return true;
if (coordinates1 == null || coordinates2 == null) return false;
//Check count, not actual values
if (coordinates1.size() == coordinates2.size()){
if (coordinates1.size() == 1){
return coordinates1.get(0).equals(coordinates2.get(0));
}
return true;
} else {
return false;
}
// return coordinates1.equals(coordinates2);
return coordinates1.equals(coordinates2);
}
}

View File

@@ -3,7 +3,6 @@ package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
@@ -32,36 +31,17 @@ public class UndoRedo {
public static void addUndo(EntityPlayer player, BlockSet blockSet) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.world.isRemote ? undoStacksClient : undoStacksServer;
//Assert coordinates is as long as previous and new blockstate lists
if (blockSet.getCoordinates().size() != blockSet.getPreviousBlockStates().size() ||
blockSet.getCoordinates().size() != blockSet.getNewBlockStates().size()) {
EffortlessBuilding.logger.error("Coordinates and blockstate lists are not equal length. Coordinates: {}. Previous blockstates: {}. New blockstates: {}.",
blockSet.getCoordinates().size(), blockSet.getPreviousBlockStates().size(), blockSet.getNewBlockStates().size());
}
//Warn if previous and new blockstate are equal
//Can happen in a lot of valid cases
// for (int i = 0; i < blockSet.getCoordinates().size(); i++) {
// if (blockSet.getPreviousBlockStates().get(i).equals(blockSet.getNewBlockStates().get(i))) {
// EffortlessBuilding.logger.warn("Previous and new blockstates are equal at index {}. Blockstate: {}.",
// i, blockSet.getPreviousBlockStates().get(i));
// }
// }
//If no stack exists, make one
if (!undoStacks.containsKey(player.getUniqueID())) {
undoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize]));
}
undoStacks.get(player.getUniqueID()).push(blockSet);
}
private static void addRedo(EntityPlayer player, BlockSet blockSet) {
Map<UUID, FixedStack<BlockSet>> redoStacks = player.world.isRemote ? redoStacksClient : redoStacksServer;
//(No asserts necessary, it's private)
//If no stack exists, make one
if (!redoStacks.containsKey(player.getUniqueID())) {
redoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize]));
@@ -96,12 +76,10 @@ public class UndoRedo {
BlockPos coordinate = coordinates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack
IBlockState previousBlockState = Blocks.AIR.getDefaultState();
IBlockState previousBlockState = Block.getBlockById(0).getDefaultState();
if (itemStack.getItem() instanceof ItemBlock) {
previousBlockState = previousBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
previousBlockState = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
}
if (player.world.isBlockLoaded(coordinate, true)) {
@@ -110,9 +88,7 @@ public class UndoRedo {
itemStack = findItemStackInInventory(player, previousBlockStates.get(i));
//get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemBlock) {
previousBlockState = previousBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
} else {
previousBlockState = Blocks.AIR.getDefaultState();
previousBlockState = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
}
}
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true);
@@ -139,7 +115,6 @@ public class UndoRedo {
BlockSet blockSet = redoStack.pop();
List<BlockPos> coordinates = blockSet.getCoordinates();
List<IBlockState> previousBlockStates = blockSet.getPreviousBlockStates();
List<IBlockState> newBlockStates = blockSet.getNewBlockStates();
Vec3d hitVec = blockSet.getHitVec();
@@ -152,25 +127,16 @@ public class UndoRedo {
//place blocks
for (int i = 0; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
IBlockState newBlockState = newBlockStates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack
IBlockState newBlockState = Blocks.AIR.getDefaultState();
if (itemStack.getItem() instanceof ItemBlock) {
newBlockState = newBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
}
if (player.world.isBlockLoaded(coordinate, true)) {
//check itemstack empty
if (itemStack.isEmpty()) {
itemStack = findItemStackInInventory(player, newBlockStates.get(i));
//get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemBlock) {
newBlockState = newBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
} else {
newBlockState = Blocks.AIR.getDefaultState();
newBlockState = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
}
}
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true);
@@ -206,11 +172,8 @@ public class UndoRedo {
private static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState blockState) {
ItemStack itemStack = ItemStack.EMPTY;
if (blockState == null) return itemStack;
//First try previousBlockStates
//TODO try to find itemstack with right blockstate first
// then change line 103 back (get state from item)
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
//then anything it drops

View File

@@ -1,11 +1,9 @@
package nl.requios.effortlessbuilding.compatibility;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.items.CapabilityItemHandler;
@@ -65,9 +63,9 @@ public class CompatHelper {
}
//Dank Null
if (proxyItem == dankNullItem) {
if(proxyItem == dankNullItem) {
int index = 0;
if (proxy.hasTagCompound() && proxy.getTagCompound().hasKey("selectedIndex"))
if(proxy.hasTagCompound() && proxy.getTagCompound().hasKey("selectedIndex"))
index = proxy.getTagCompound().getInteger("selectedIndex");
return proxy.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
}
@@ -77,14 +75,14 @@ public class CompatHelper {
public static ItemStack getItemBlockByState(ItemStack stack, IBlockState state) {
Item blockItem = Item.getItemFromBlock(state.getBlock());
if (stack.getItem() instanceof ItemBlock)
if(stack.getItem() instanceof ItemBlock)
return stack;
else if (stack.getItem() instanceof ItemRandomizerBag) {
else if(stack.getItem() instanceof ItemRandomizerBag) {
IItemHandler bagInventory = ItemRandomizerBag.getBagInventory(stack);
return ItemRandomizerBag.findStack(bagInventory, blockItem);
} else if (stack.getItem() == dankNullItem) {
} else if(stack.getItem() == dankNullItem) {
int index = itemHandlerSlotForItem(stack, blockItem);
if (index >= 0)
if(index >= 0)
return stack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
}
return ItemStack.EMPTY;
@@ -92,11 +90,8 @@ public class CompatHelper {
// Handle IItemHandler slot stacks not being modifiable. We must call IItemHandler#extractItem,
// because the ItemStack returned by IItemHandler#getStackInSlot isn't modifiable.
public static void shrinkStack(ItemStack origStack, ItemStack curStack, EntityPlayer player) {
//Hacky way to get the origstack, because given origStack is itemblock stack and never a proxy
origStack = player.getHeldItem(EnumHand.MAIN_HAND);
if (origStack.getItem() == dankNullItem) {
public static void shrinkStack(ItemStack origStack, ItemStack curStack) {
if(origStack.getItem() == dankNullItem) {
int index = itemHandlerSlotForItem(origStack, curStack.getItem());
origStack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).extractItem(index, 1, false);
} else
@@ -105,10 +100,10 @@ public class CompatHelper {
private static int itemHandlerSlotForItem(ItemStack stack, Item blockItem) {
IItemHandler handler = stack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
for (int i = 0; i < handler.getSlots(); i++) {
for(int i = 0; i < handler.getSlots(); i++) {
ItemStack ref = handler.getStackInSlot(i);
if (ref.getItem() instanceof ItemBlock)
if (ref.getItem() == blockItem)
if(ref.getItem() instanceof ItemBlock)
if(ref.getItem() == blockItem)
return i;
}
return -1;

View File

@@ -118,13 +118,16 @@ public class RandomizerBagContainer extends Container {
/**
* Callback for when the crafting gui is closed.
*/
@Override
public void onContainerClosed(EntityPlayer player)
{
super.onContainerClosed(player);
if(!player.world.isRemote)
{
detectAndSendChanges();
}
}
// @Override
// public void onContainerClosed(EntityPlayer player)
// {
// if(player.inventory.getItemStack() != null)
// {
// player.entityDropItem(player.inventory.getItemStack(), 0.5f);
// }
// if(!player.world.isRemote)
// {
// detectAndSendChanges();
// }
// }
}

View File

@@ -26,7 +26,6 @@ import net.minecraft.util.EnumFacing;
import net.minecraftforge.client.model.ModelLoader;
import static nl.requios.effortlessbuilding.buildmode.BuildModes.*;
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*;
/**
* From Chisels and Bits by AlgorithmX2
@@ -40,7 +39,7 @@ public class RadialMenu extends GuiScreen {
private float visibility = 0.0f;
private Stopwatch lastChange = Stopwatch.createStarted();
public BuildModeEnum switchTo = null;
public ActionEnum doAction = null;
public ModeOptions.ActionEnum doAction = null;
public boolean actionUsed = false;
private float clampVis(final float f) {
@@ -78,11 +77,11 @@ public class RadialMenu extends GuiScreen {
public double y1, y2;
public boolean highlighted;
public final ActionEnum action;
public final ModeOptions.ActionEnum action;
public String name;
public EnumFacing textSide;
public MenuButton(final String name, final ActionEnum action, final double x, final double y,
public MenuButton(final String name, final ModeOptions.ActionEnum action, final double x, final double y,
final EnumFacing textSide) {
this.name = I18n.format(name);
this.action = action;
@@ -139,10 +138,10 @@ public class RadialMenu extends GuiScreen {
final double mouseYCenter = mouseY - middleY;
double mouseRadians = Math.atan2(mouseYCenter, mouseXCenter);
final double ringInnerEdge = 30;
final double ringOuterEdge = 65;
final double textDistance = 75;
final double buttonDistance = 105;
final double ringInnerEdge = 20;
final double ringOuterEdge = 50;
final double textDistance = 60;
final double buttonDistance = 90;
final double quarterCircle = Math.PI / 2.0;
if ( mouseRadians < -quarterCircle ) {
@@ -158,18 +157,16 @@ public class RadialMenu extends GuiScreen {
}
//Add actions
buttons.add(new MenuButton(ActionEnum.UNDO.name, ActionEnum.UNDO, -buttonDistance - 26, -13, EnumFacing.UP));
buttons.add(new MenuButton(ActionEnum.REDO.name, ActionEnum.REDO, -buttonDistance, -13, EnumFacing.UP));
buttons.add(new MenuButton(ActionEnum.OPEN_MODIFIER_SETTINGS.name, ActionEnum.OPEN_MODIFIER_SETTINGS, -buttonDistance - 26, 13, EnumFacing.DOWN));
buttons.add(new MenuButton(ActionEnum.REPLACE.name, ActionEnum.REPLACE, -buttonDistance, 13, EnumFacing.DOWN));
buttons.add(new MenuButton(ModeOptions.ActionEnum.UNDO.name, ModeOptions.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(ModeOptions.ActionEnum.OPEN_MODIFIER_SETTINGS.name, ModeOptions.ActionEnum.OPEN_MODIFIER_SETTINGS, -buttonDistance - 26, 13, EnumFacing.DOWN));
buttons.add(new MenuButton(ModeOptions.ActionEnum.REPLACE.name, ModeOptions.ActionEnum.REPLACE, -buttonDistance, 13, EnumFacing.DOWN));
//Add buildmode dependent options
OptionEnum[] options = currentBuildMode.options;
ModeOptions.ActionEnum[] options = currentBuildMode.options;
for (int i = 0; i < options.length; i++) {
for (int j = 0; j < options[i].actions.length; j++) {
ActionEnum action = options[i].actions[j];
buttons.add(new MenuButton(action.name, action, buttonDistance + j * 26, -13 + i * 39, EnumFacing.DOWN));
}
ModeOptions.ActionEnum action = options[i];
buttons.add(new MenuButton(action.name, action, buttonDistance + i * 26, -13, EnumFacing.DOWN));
}
switchTo = null;
@@ -248,12 +245,11 @@ public class RadialMenu extends GuiScreen {
float a = 0.5f;
//highlight when active option
if (btn.action == getBuildSpeed() ||
btn.action == getFill() ||
btn.action == getCubeFill() ||
btn.action == getRaisedEdge() ||
btn.action == getLineThickness() ||
btn.action == getCircleStart()) {
if (btn.action == ModeOptions.getBuildSpeed() ||
btn.action == ModeOptions.getFill() ||
btn.action == ModeOptions.getCubeFill() ||
btn.action == ModeOptions.getRaisedEdge() ||
btn.action == ModeOptions.getLineThickness()) {
r = 0.0f;
g = 0.5f;
b = 1f;
@@ -346,12 +342,32 @@ public class RadialMenu extends GuiScreen {
//Draw strings
//fontRenderer.drawStringWithShadow("Actions", (int) (middleX - buttonDistance - 13) - fontRenderer.getStringWidth("Actions") * 0.5f, (int) middleY - 38, 0xffffffff);
//Draw option strings
for (int i = 0; i < currentBuildMode.options.length; i++) {
OptionEnum option = options[i];
fontRenderer.drawStringWithShadow(I18n.format(option.name), (int) (middleX + buttonDistance - 9), (int) middleY - 37 + i * 39, 0xeeeeeeff);
String title = "";
if (currentBuildMode.options.length > 0) {
switch (currentBuildMode.options[0]) {
case NORMAL_SPEED:
case FAST_SPEED:
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";
fontRenderer.drawStringWithShadow(credits, width - fontRenderer.getStringWidth(credits) - 4, height - 10, 0x88888888);
@@ -386,26 +402,18 @@ public class RadialMenu extends GuiScreen {
String keybindFormatted = "";
//Add keybind in brackets
if (button.action == ActionEnum.UNDO) {
if (button.action == ModeOptions.ActionEnum.UNDO) {
keybind = ClientProxy.keyBindings[4].getDisplayName();
}
if (button.action == ActionEnum.REDO) {
if (button.action == ModeOptions.ActionEnum.REDO) {
keybind = ClientProxy.keyBindings[5].getDisplayName();
}
if (button.action == ActionEnum.REPLACE) {
if (button.action == ModeOptions.ActionEnum.REPLACE) {
keybind = ClientProxy.keyBindings[1].getDisplayName();
}
if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) {
if (button.action == ModeOptions.ActionEnum.OPEN_MODIFIER_SETTINGS) {
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 (button.textSide == EnumFacing.WEST) {

View File

@@ -10,7 +10,6 @@ import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.input.Mouse;

View File

@@ -28,20 +28,12 @@ public class ReachHelper {
public static int getMaxBlocksPlacedAtOnce(EntityPlayer player) {
if (player.isCreative()) return 1000000;
return MathHelper.ceil(Math.pow(getMaxReach(player), 1.6));
//Level 0: 121
//Level 1: 523
//Level 2: 1585
//Level 3: 4805
return getMaxReach(player) * 5;
}
public static int getMaxBlocksPerAxis(EntityPlayer player) {
if (player.isCreative()) return 2000;
return MathHelper.ceil(getMaxReach(player) * 0.3);
//Level 0: 6
//Level 1: 15
//Level 2: 30
//Level 3: 60
return MathHelper.ceil(MathHelper.sqrt(getMaxReach(player)));
}
public static boolean canBreakFar(EntityPlayer player) {

View File

@@ -71,7 +71,7 @@ public class SurvivalHelper {
}
if (!player.isCreative() && Block.getBlockFromItem(itemstack.getItem()) == block) {
CompatHelper.shrinkStack(origstack, itemstack, player);
CompatHelper.shrinkStack(origstack, itemstack);
}
return true;

View File

@@ -20,9 +20,6 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.capability.ItemHandlerCapabilityProvider;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
@@ -55,14 +52,6 @@ public class ItemRandomizerBag extends Item {
player.openGui(EffortlessBuilding.instance, EffortlessBuilding.RANDOMIZER_BAG_GUI, world, 0, 0, 0);
} else {
if (world.isRemote) return EnumActionResult.SUCCESS;
//Only place manually if in normal vanilla mode
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.NORMAL || modifierSettings.doQuickReplace()) {
return EnumActionResult.FAIL;
}
//Use item
//Get bag inventory
ItemStack bag = player.getHeldItem(hand);

View File

@@ -1,94 +0,0 @@
package nl.requios.effortlessbuilding.network;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import java.util.ArrayList;
/***
* Sends a message to the client asking to add a block to the undo stack.
*/
public class AddUndoMessage implements IMessage {
private BlockPos coordinate;
private IBlockState previousBlockState;
private IBlockState newBlockState;
public AddUndoMessage() {
coordinate = BlockPos.ORIGIN;
previousBlockState = null;
newBlockState = null;
}
public AddUndoMessage(BlockPos coordinate, IBlockState previousBlockState, IBlockState newBlockState) {
this.coordinate = coordinate;
this.previousBlockState = previousBlockState;
this.newBlockState = newBlockState;
}
public BlockPos getCoordinate() {
return coordinate;
}
public IBlockState getPreviousBlockState() {
return previousBlockState;
}
public IBlockState getNewBlockState() {
return newBlockState;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.coordinate.getX());
buf.writeInt(this.coordinate.getY());
buf.writeInt(this.coordinate.getZ());
buf.writeInt(Block.getStateId(this.previousBlockState));
buf.writeInt(Block.getStateId(this.newBlockState));
}
@Override
public void fromBytes(ByteBuf buf) {
coordinate = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
previousBlockState = Block.getStateById(buf.readInt());
newBlockState = Block.getStateById(buf.readInt());
}
// The params of the IMessageHandler are <REQ, REPLY>
public static class MessageHandler implements IMessageHandler<AddUndoMessage, IMessage> {
// Do note that the default constructor is required, but implicitly defined in this case
@Override
public IMessage onMessage(AddUndoMessage message, MessageContext ctx) {
//EffortlessBuilding.log("message received on " + ctx.side + " side");
if (ctx.side == Side.CLIENT){
//Received clientside
EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
//Add to undo stack clientside
UndoRedo.addUndo(player, new BlockSet(
new ArrayList<BlockPos>() {{add(message.getCoordinate());}},
new ArrayList<IBlockState>() {{add(message.getPreviousBlockState());}},
new ArrayList<IBlockState>() {{add(message.getNewBlockState());}},
new Vec3d(0,0,0),
message.getCoordinate(), message.getCoordinate()));
});
}
return null;
}
}
}

View File

@@ -1,57 +0,0 @@
package nl.requios.effortlessbuilding.network;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import java.util.ArrayList;
/***
* Sends a message to the client asking to clear the undo and redo stacks.
*/
public class ClearUndoMessage implements IMessage {
public ClearUndoMessage() {
}
@Override
public void toBytes(ByteBuf buf) {
}
@Override
public void fromBytes(ByteBuf buf) {
}
// The params of the IMessageHandler are <REQ, REPLY>
public static class MessageHandler implements IMessageHandler<ClearUndoMessage, IMessage> {
// Do note that the default constructor is required, but implicitly defined in this case
@Override
public IMessage onMessage(ClearUndoMessage message, MessageContext ctx) {
//EffortlessBuilding.log("message received on " + ctx.side + " side");
if (ctx.side == Side.CLIENT){
//Received clientside
EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
//Add to undo stack clientside
UndoRedo.clear(player);
});
}
return null;
}
}
}

View File

@@ -22,28 +22,48 @@ import java.util.ArrayList;
* This is then sent back with a BlockPlacedMessage.
*/
public class RequestLookAtMessage implements IMessage {
private boolean placeStartPos;
private BlockPos coordinate;
private IBlockState previousBlockState;
private IBlockState newBlockState;
public RequestLookAtMessage() {
placeStartPos = false;
coordinate = BlockPos.ORIGIN;
previousBlockState = null;
newBlockState = null;
}
public RequestLookAtMessage(boolean placeStartPos) {
this.placeStartPos = placeStartPos;
public RequestLookAtMessage(BlockPos coordinate, IBlockState previousBlockState, IBlockState newBlockState) {
this.coordinate = coordinate;
this.previousBlockState = previousBlockState;
this.newBlockState = newBlockState;
}
public boolean getPlaceStartPos() {
return placeStartPos;
public BlockPos getCoordinate() {
return coordinate;
}
public IBlockState getPreviousBlockState() {
return previousBlockState;
}
public IBlockState getNewBlockState() {
return newBlockState;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeBoolean(this.placeStartPos);
buf.writeInt(this.coordinate.getX());
buf.writeInt(this.coordinate.getY());
buf.writeInt(this.coordinate.getZ());
buf.writeInt(Block.getStateId(this.previousBlockState));
buf.writeInt(Block.getStateId(this.newBlockState));
}
@Override
public void fromBytes(ByteBuf buf) {
placeStartPos = buf.readBoolean();
coordinate = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
previousBlockState = Block.getStateById(buf.readInt());
newBlockState = Block.getStateById(buf.readInt());
}
// The params of the IMessageHandler are <REQ, REPLY>
@@ -58,14 +78,20 @@ public class RequestLookAtMessage implements IMessage {
//Received clientside
//Send back your info
// EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
// EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
//
// });
EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
//Prevent double placing in normal mode with placeStartPos false.
//Unless QuickReplace is on, then we do need to place start pos.
return new BlockPlacedMessage(ClientProxy.previousLookAt, message.getPlaceStartPos());
//Add to undo stack clientside
UndoRedo.addUndo(player, new BlockSet(
new ArrayList<BlockPos>() {{add(message.getCoordinate());}},
new ArrayList<IBlockState>() {{add(message.getPreviousBlockState());}},
new ArrayList<IBlockState>() {{add(message.getNewBlockState());}},
new Vec3d(0,0,0),
message.getCoordinate(), message.getCoordinate()));
});
//Prevent double placing in normal mode with placeStartPos false
return new BlockPlacedMessage(ClientProxy.previousLookAt, false);
}
return null;
}

View File

@@ -97,8 +97,7 @@ 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[5] = new KeyBinding("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, Keyboard.KEY_Y, "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");
keyBindings[6] = new KeyBinding("Reload shaders", Keyboard.KEY_TAB, "key.effortlessbuilding.category");
// register all the key bindings
for (int i = 0; i < keyBindings.length; ++i) {
@@ -262,14 +261,8 @@ public class ClientProxy implements IProxy {
//Break block in distance in creative (or survival if enabled in config)
if (breakCooldown <= 0) {
breakCooldown = 4;
//Early out if cant break far, coming from own mouse event (not block broken event)
//To make breaking blocks in survival possible like array
//TODO this causes not being able to cancel placement in survival
// moving it to after buildmodes fixes that, but introduces this bug
if (!ReachHelper.canBreakFar(player)) return;
RayTraceResult lookingAt = getLookingAt(player);
BuildModes.onBlockBrokenMessage(player, lookingAt == null ? new BlockBrokenMessage() : new BlockBrokenMessage(lookingAt));
EffortlessBuilding.packetHandler.sendToServer(lookingAt == null ? new BlockBrokenMessage() : new BlockBrokenMessage(lookingAt));
@@ -345,26 +338,8 @@ public class ClientProxy implements IProxy {
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
if (keyBindings.length >= 8 && keyBindings[7].isPressed()) {
if (keyBindings.length >= 7 && keyBindings[6].isPressed()) {
ShaderHandler.init();
EffortlessBuilding.log(player, "Reloaded shaders");
}
@@ -372,8 +347,7 @@ public class ClientProxy implements IProxy {
}
public static void openModifierSettings() {
Minecraft mc = Minecraft.getMinecraft();
EntityPlayerSP player = mc.player;
EntityPlayerSP player = Minecraft.getMinecraft().player;
RadialMenu.instance.setVisibility(0f);
@@ -381,8 +355,8 @@ public class ClientProxy implements IProxy {
if (ReachHelper.getMaxReach(player) == 0) {
EffortlessBuilding.log(player, "Build modifiers are disabled until your reach has increased. Increase your reach with craftable reach upgrades.");
} else {
if (mc.currentScreen == null) {
mc.displayGuiScreen(new ModifierSettingsGui());
if (Minecraft.getMinecraft().currentScreen == null) {
Minecraft.getMinecraft().displayGuiScreen(new ModifierSettingsGui());
} else {
player.closeScreen();
}

View File

@@ -5,13 +5,11 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.*;
import net.minecraftforge.fml.relauncher.Side;
@@ -26,14 +24,13 @@ import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.InventoryHelper;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import org.lwjgl.opengl.ARBMultitexture;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import java.util.ArrayList;
import java.util.Collections;
@@ -73,7 +70,7 @@ public class BlockPreviewRenderer {
private static List<PlacedData> placedDataList = new ArrayList<>();
private static final int primaryTextureUnit = 0;
private static final int secondaryTextureUnit = 2;
private static final int secondaryTextureUnit = 1;
public static void render(EntityPlayer player, ModifierSettings modifierSettings, ModeSettings modeSettings) {
@@ -195,17 +192,15 @@ public class BlockPreviewRenderer {
//if so, renew randomness of randomizer bag
ItemRandomizerBag.renewRandomness();
//and play sound (max once every tick)
if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) {
if (startCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) {
soundTime = ClientProxy.ticksInGame;
if (blockStates.get(0) != null) {
SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.world,
newCoordinates.get(0), player);
player.world.playSound(player, player.getPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(),
SoundCategory.BLOCKS, 0.3f, 0.8f);
}
}
}
//Render block previews
if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) {
@@ -238,20 +233,8 @@ public class BlockPreviewRenderer {
//Display block count and dimensions in actionbar
if (BuildModes.isActive(player)) {
//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);
BlockPos dim = secondPos.subtract(firstPos);
dim = new BlockPos(Math.abs(dim.getX()) + 1, Math.abs(dim.getY()) + 1, Math.abs(dim.getZ()) + 1);
String dimensions = "(";
if (dim.getX() > 1) dimensions += dim.getX() + "x";
@@ -387,39 +370,40 @@ public class BlockPreviewRenderer {
final boolean highlight, final boolean red) {
Minecraft mc = Minecraft.getMinecraft();
return (Integer shader) -> {
int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "dissolve");
int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight");
int redUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "red");
int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos");
int firstposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "firstpos");
int secondposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "secondpos");
int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image");
int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask");
int percentileUniform = GL20.glGetUniformLocation(shader, "dissolve");
int highlightUniform = GL20.glGetUniformLocation(shader, "highlight");
int redUniform = GL20.glGetUniformLocation(shader, "red");
int blockposUniform = GL20.glGetUniformLocation(shader, "blockpos");
int firstposUniform = GL20.glGetUniformLocation(shader, "firstpos");
int secondposUniform = GL20.glGetUniformLocation(shader, "secondpos");
int imageUniform = GL20.glGetUniformLocation(shader, "image");
int maskUniform = GL20.glGetUniformLocation(shader, "mask");
GlStateManager.enableTexture2D();
GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
//image
GL20.glUniform1i(imageUniform, primaryTextureUnit);
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + primaryTextureUnit);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).getGlTextureId());
// GlStateManager.enableTexture2D();
// GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
//mask
ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit);
GL20.glUniform1i(maskUniform, secondaryTextureUnit);
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(ShaderHandler.shaderMaskTextureLocation).getGlTextureId());
//image
ARBShaderObjects.glUniform1iARB(imageUniform, primaryTextureUnit);
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + primaryTextureUnit);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).getGlTextureId());
//blockpos
ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z);
ARBShaderObjects.glUniform3fARB(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z);
ARBShaderObjects.glUniform3fARB(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z);
GL20.glUniform3f(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z);
GL20.glUniform3f(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z);
GL20.glUniform3f(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z);
//dissolve
ARBShaderObjects.glUniform1fARB(percentileUniform, dissolve);
GL20.glUniform1f(percentileUniform, dissolve);
//highlight
ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0);
GL20.glUniform1i(highlightUniform, highlight ? 1 : 0);
//red
ARBShaderObjects.glUniform1iARB(redUniform, red ? 1 : 0);
GL20.glUniform1i(redUniform, red ? 1 : 0);
};
}

View File

@@ -185,7 +185,7 @@ public class RenderHandler implements IWorldEventListener {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
// Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
Minecraft.getMinecraft().renderEngine.bindTexture(ShaderHandler.shaderMaskTextureLocation);
GlStateManager.enableBlend();
@@ -206,8 +206,6 @@ public class RenderHandler implements IWorldEventListener {
}
protected static void renderBlockPreview(BlockRendererDispatcher dispatcher, BlockPos blockPos, IBlockState blockState) {
if (blockState == null) return;
GlStateManager.pushMatrix();
GlStateManager.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ());
GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F);

View File

@@ -28,8 +28,9 @@ import java.util.function.Consumer;
public final class ShaderHandler {
private static final int VERT_ST = ARBVertexShader.GL_VERTEX_SHADER_ARB;
private static final int FRAG_ST = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB;
private static final int VERT_ST = GL20.GL_VERTEX_SHADER;
private static final int FRAG_ST = GL20.GL_FRAGMENT_SHADER;
private static final int VERT = 1;
private static final int FRAG = 2;
@@ -54,11 +55,11 @@ public final class ShaderHandler {
if(!doUseShaders())
return;
ARBShaderObjects.glUseProgramObjectARB(shader);
GL20.glUseProgram(shader);
if(shader != 0) {
int time = ARBShaderObjects.glGetUniformLocationARB(shader, "time");
ARBShaderObjects.glUniform1iARB(time, ClientProxy.ticksInGame);
int time = GL20.glGetUniformLocation(shader, "time");
GL20.glUniform1i(time, ClientProxy.ticksInGame);
if(callback != null)
callback.accept(shader);
@@ -74,7 +75,7 @@ public final class ShaderHandler {
}
public static boolean doUseShaders() {
return BuildConfig.visuals.useShaders && OpenGlHelper.shadersSupported;
return BuildConfig.visuals.useShaders && OpenGlHelper.shadersSupported && OpenGlHelper.openGL21; //Only GL2.1 shaders
}
private static int createProgram(String s, int sides) {
@@ -94,24 +95,24 @@ public final class ShaderHandler {
if(frag != null)
fragId = createShader(frag, FRAG_ST);
program = ARBShaderObjects.glCreateProgramObjectARB();
program = GL20.glCreateProgram();
if(program == 0)
return 0;
if(vert != null)
ARBShaderObjects.glAttachObjectARB(program, vertId);
GL20.glAttachShader(program, vertId);
if(frag != null)
ARBShaderObjects.glAttachObjectARB(program, fragId);
GL20.glAttachShader(program, fragId);
ARBShaderObjects.glLinkProgramARB(program);
if(ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) {
EffortlessBuilding.logger.log(Level.ERROR, getLogInfo(program));
GL20.glLinkProgram(program);
if(GL20.glGetProgrami(program, GL20.GL_LINK_STATUS) == GL11.GL_FALSE) {
EffortlessBuilding.logger.log(Level.ERROR, getProgramLogInfo(program));
return 0;
}
ARBShaderObjects.glValidateProgramARB(program);
if (ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_VALIDATE_STATUS_ARB) == GL11.GL_FALSE) {
EffortlessBuilding.logger.log(Level.ERROR, getLogInfo(program));
GL20.glValidateProgram(program);
if (GL20.glGetProgrami(program, GL20.GL_VALIDATE_STATUS) == GL11.GL_FALSE) {
EffortlessBuilding.logger.log(Level.ERROR, getProgramLogInfo(program));
return 0;
}
@@ -121,28 +122,32 @@ public final class ShaderHandler {
private static int createShader(String filename, int shaderType){
int shader = 0;
try {
shader = ARBShaderObjects.glCreateShaderObjectARB(shaderType);
shader = GL20.glCreateShader(shaderType);
if(shader == 0)
return 0;
ARBShaderObjects.glShaderSourceARB(shader, readFileAsString(filename));
ARBShaderObjects.glCompileShaderARB(shader);
GL20.glShaderSource(shader, readFileAsString(filename));
GL20.glCompileShader(shader);
if (ARBShaderObjects.glGetObjectParameteriARB(shader, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE)
throw new RuntimeException("Error creating shader: " + getLogInfo(shader));
if (GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE)
throw new RuntimeException("Error creating shader: " + getShaderLogInfo(shader));
return shader;
}
catch(Exception e) {
ARBShaderObjects.glDeleteObjectARB(shader);
GL20.glDeleteShader(shader);
e.printStackTrace();
return -1;
}
}
private static String getLogInfo(int obj) {
return ARBShaderObjects.glGetInfoLogARB(obj, ARBShaderObjects.glGetObjectParameteriARB(obj, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB));
private static String getProgramLogInfo(int program) {
return GL20.glGetProgramInfoLog(program, GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH));
}
private static String getShaderLogInfo(int shader) {
return GL20.glGetShaderInfoLog(shader, GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH));
}
private static String readFileAsString(String filename) throws Exception {

View File

@@ -2,10 +2,9 @@ key.effortlessbuilding.category=Effortless Building
key.effortlessbuilding.hud.desc=Modifier Menu
key.effortlessbuilding.replace.desc=Toggle QuickReplace
key.effortlessbuilding.creative.desc=Toggle Survival/Creative Mode
key.effortlessbuilding.mode.desc=Radial Menu
key.effortlessbuilding.mode.desc=Radial Menu (C&B compatible)
key.effortlessbuilding.undo.desc=Undo
key.effortlessbuilding.redo.desc=Redo
key.effortlessbuilding.altplacement.desc=Alternative placement
item.effortlessbuilding:randomizer_bag.name=Randomizer Bag
item.effortlessbuilding:reach_upgrade1.name=Reach Upgrade 1
@@ -21,9 +20,6 @@ effortlessbuilding.mode.diagonal_line=Diagonal Line
effortlessbuilding.mode.diagonal_wall=Diagonal Wall
effortlessbuilding.mode.slope_floor=Slope Floor
effortlessbuilding.mode.cube=Cube
effortlessbuilding.mode.circle=Circle
effortlessbuilding.mode.cylinder=Cylinder
effortlessbuilding.mode.sphere=Sphere
effortlessbuilding.action.undo=Undo
effortlessbuilding.action.redo=Redo
@@ -34,7 +30,6 @@ effortlessbuilding.action.build_speed=Build Speed
effortlessbuilding.action.filling=Filling
effortlessbuilding.action.raised_edge=Raised Edge
effortlessbuilding.action.thickness=Line Thickness
effortlessbuilding.action.circle_start=Start Point
effortlessbuilding.action.normal_speed=Normal
effortlessbuilding.action.fast_speed=Fast
@@ -46,7 +41,5 @@ effortlessbuilding.action.long_edge=Long Edge
effortlessbuilding.action.thickness_1=1 Block Thick
effortlessbuilding.action.thickness_3=3 Blocks Thick
effortlessbuilding.action.thickness_5=5 Blocks Thick
effortlessbuilding.action.start_center=Middle
effortlessbuilding.action.start_corner=Corner
commands.reach.usage=/reach <level>

View File

@@ -31,7 +31,9 @@ void main() {
float placeFromFirst = length(worldpos - firstposc) / firstToSecond;
float placeFromSecond = length(worldpos - secondposc) / firstToSecond;
place = (placeFromFirst + (1.0 - placeFromSecond)) / 2.0;
} //else only one block
} else {
//only one block
}
//find 2d texture coordinate for noise texture based on world position
vec2 maskcoord = vec2(worldpos.y, worldpos.z);
@@ -78,8 +80,8 @@ void main() {
// color.rgb += vec3(0.5 - smoothstep(0, 0.5, distToEdge)) * 0.5;
//add flat shading
// if (abs(normal.x) > 0.5)
// color.rgb -= 0.0;
if (abs(normal.x) > 0.5)
color.rgb -= 0.0;
if (abs(normal.y) > 0.5)
color.rgb += 0.05;
if (abs(normal.z) > 0.5)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B