Added Diagonal Line, Diagonal Wall, Slope Floor and Cube buildmodes.
Fixed issue #26: Crash attempting to place wall with a stone block. Breaking (in creative) can now be undone as well. Undo/redo now tries to replace the previous blocks, if you have those blocks in your inventory (issue #33). Fixed undo in survival only undoing blocks that can be broken by hand (issue #29). Fixed being able to place randomizer bag inside itself (and prevented a black hole from creating) (issue #31). Randomizer bags can now be placed inside randomizer bags. Fixed crash when placing with empty randomizer bag (issue #32). Fixed diagonal wall and slope being 2 blocks thick.
This commit is contained in:
@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
|
||||
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||
|
||||
|
||||
version = "1.12.2-2.6"
|
||||
version = "1.12.2-2.8"
|
||||
group = "nl.requios.effortlessbuilding" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
archivesBaseName = "effortlessbuilding"
|
||||
|
||||
@@ -21,7 +21,7 @@ compileJava {
|
||||
}
|
||||
|
||||
minecraft {
|
||||
version = "1.12.2-14.23.5.2768"
|
||||
version = "1.12.2-14.23.5.2825"
|
||||
runDir = "run"
|
||||
|
||||
// the mappings can be changed at any time, and must be in the following format.
|
||||
|
||||
@@ -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.6";
|
||||
public static final String VERSION = "1.12.2-2.8";
|
||||
|
||||
@Mod.Instance(EffortlessBuilding.MODID)
|
||||
public static EffortlessBuilding instance;
|
||||
|
||||
@@ -98,7 +98,7 @@ public class EventHandler
|
||||
//But modifiers and QuickReplace should still work
|
||||
|
||||
//Send message to client, which sends message back with raytrace info
|
||||
EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(event.getPos(), event.getState()), (EntityPlayerMP) player);
|
||||
EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()), (EntityPlayerMP) player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,8 +191,9 @@ public class BuildModes {
|
||||
return currentlyBreaking.get(player) != null;
|
||||
}
|
||||
|
||||
|
||||
//Find coordinates on a line bound by a plane
|
||||
protected static Vec3d findXBound(double x, Vec3d start, Vec3d look) {
|
||||
public static Vec3d findXBound(double x, Vec3d start, Vec3d look) {
|
||||
//then y and z are
|
||||
double y = (x - start.x) / look.x * look.y + start.y;
|
||||
double z = (x - start.x) / look.x * look.z + start.z;
|
||||
@@ -200,7 +201,7 @@ public class BuildModes {
|
||||
return new Vec3d(x, y, z);
|
||||
}
|
||||
|
||||
protected static Vec3d findYBound(double y, Vec3d start, Vec3d look) {
|
||||
public static Vec3d findYBound(double y, Vec3d start, Vec3d look) {
|
||||
//then x and z are
|
||||
double x = (y - start.y) / look.y * look.x + start.x;
|
||||
double z = (y - start.y) / look.y * look.z + start.z;
|
||||
@@ -208,7 +209,7 @@ public class BuildModes {
|
||||
return new Vec3d(x, y, z);
|
||||
}
|
||||
|
||||
protected static Vec3d findZBound(double z, Vec3d start, Vec3d look) {
|
||||
public static Vec3d findZBound(double z, Vec3d start, Vec3d look) {
|
||||
//then x and y are
|
||||
double x = (z - start.z) / look.z * look.x + start.x;
|
||||
double y = (z - start.z) / look.z * look.y + start.y;
|
||||
@@ -216,5 +217,4 @@ public class BuildModes {
|
||||
return new Vec3d(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,33 +4,157 @@ 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.List;
|
||||
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) {
|
||||
return new ArrayList<>();
|
||||
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) {
|
||||
return new ArrayList<>();
|
||||
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;
|
||||
|
||||
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 limit = ReachHelper.getMaxBlocksPlacedAtOnce(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;
|
||||
|
||||
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) {
|
||||
|
||||
//check if whole row fits within limit
|
||||
if (Math.abs(y1 - y2) < limit - list.size()) {
|
||||
|
||||
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
|
||||
list.add(new BlockPos(l, m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumFacing getSideHit(EntityPlayer player) {
|
||||
return null;
|
||||
return sideHitTable.get(player.getUniqueID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getHitVec(EntityPlayer player) {
|
||||
return null;
|
||||
return hitVecTable.get(player.getUniqueID());
|
||||
}
|
||||
}
|
||||
@@ -3,34 +3,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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
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;
|
||||
Vec3d lineBound;
|
||||
double distToLineSq;
|
||||
double distToPlayerSq;
|
||||
|
||||
HeightCriteria(Vec3d planeBound, BlockPos secondPos, Vec3d start) {
|
||||
this.planeBound = planeBound;
|
||||
this.lineBound = toLongestLine(this.planeBound, secondPos);
|
||||
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSquared();
|
||||
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
|
||||
}
|
||||
|
||||
//Make it from a plane into a line, on y axis only
|
||||
private Vec3d toLongestLine(Vec3d boundVec, BlockPos secondPos) {
|
||||
BlockPos bound = new BlockPos(boundVec);
|
||||
return new Vec3d(secondPos.getX(), bound.getY(), secondPos.getZ());
|
||||
}
|
||||
|
||||
//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, 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) {
|
||||
|
||||
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) {
|
||||
return new ArrayList<>();
|
||||
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 line 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) {
|
||||
return new ArrayList<>();
|
||||
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 from first to second
|
||||
list.addAll(getDiagonalLineBlocks(player , firstPos, secondPos, 10));
|
||||
|
||||
} else {
|
||||
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
|
||||
BlockPos secondPos = secondPosTable.get(player.getUniqueID());
|
||||
|
||||
BlockPos thirdPos = findHeight(player, secondPos, skipRaytrace);
|
||||
if (thirdPos == null) return list;
|
||||
|
||||
//Add diagonal line from first to third
|
||||
list.addAll(getDiagonalLineBlocks(player , firstPos, thirdPos, 10));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
//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();
|
||||
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
|
||||
|
||||
List<HeightCriteria> criteriaList = new ArrayList<>(3);
|
||||
|
||||
//X
|
||||
Vec3d xBound = BuildModes.findXBound(secondPos.getX(), start, look);
|
||||
criteriaList.add(new HeightCriteria(xBound, secondPos, start));
|
||||
|
||||
//Z
|
||||
Vec3d zBound = BuildModes.findZBound(secondPos.getZ(), start, look);
|
||||
criteriaList.add(new HeightCriteria(zBound, secondPos, 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;
|
||||
|
||||
//If only 1 is valid, choose that one
|
||||
HeightCriteria selected = criteriaList.get(0);
|
||||
|
||||
//If multiple are valid, choose based on criteria
|
||||
if (criteriaList.size() > 1) {
|
||||
//Select the one that is closest (from wall position to its line counterpart)
|
||||
for (int i = 1; i < criteriaList.size(); i++) {
|
||||
HeightCriteria criteria = criteriaList.get(i);
|
||||
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
|
||||
//Both very close to line, choose closest to player
|
||||
if (criteria.distToPlayerSq < selected.distToPlayerSq)
|
||||
selected = criteria;
|
||||
} else {
|
||||
//Pick closest to line
|
||||
if (criteria.distToLineSq < selected.distToLineSq)
|
||||
selected = criteria;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new BlockPos(selected.lineBound);
|
||||
}
|
||||
|
||||
//Add diagonal line from first to second
|
||||
public static List<BlockPos> getDiagonalLineBlocks(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, int 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 null;
|
||||
return sideHitTable.get(player.getUniqueID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getHitVec(EntityPlayer player) {
|
||||
return null;
|
||||
return hitVecTable.get(player.getUniqueID());
|
||||
}
|
||||
}
|
||||
@@ -4,33 +4,135 @@ 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.List;
|
||||
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) {
|
||||
return new ArrayList<>();
|
||||
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) {
|
||||
return new ArrayList<>();
|
||||
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 null;
|
||||
return sideHitTable.get(player.getUniqueID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getHitVec(EntityPlayer player) {
|
||||
return null;
|
||||
return hitVecTable.get(player.getUniqueID());
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ 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.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||
|
||||
import java.util.*;
|
||||
@@ -13,13 +12,13 @@ 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
|
||||
Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
||||
Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
||||
Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
||||
Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
||||
Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
||||
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<>();
|
||||
|
||||
class Criteria {
|
||||
static class Criteria {
|
||||
Vec3d planeBound;
|
||||
double distToPlayerSq;
|
||||
|
||||
@@ -101,32 +100,13 @@ public class Floor implements IBuildMode {
|
||||
if (secondPos == null) return list;
|
||||
|
||||
//Add whole floor
|
||||
//Limit amount of blocks you can place per row
|
||||
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
|
||||
|
||||
int x1 = firstPos.getX(), x2 = secondPos.getX();
|
||||
int y1 = firstPos.getY(), y2 = secondPos.getY();
|
||||
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
|
||||
|
||||
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
|
||||
|
||||
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
|
||||
|
||||
//check if whole row fits within limit
|
||||
if (Math.abs(y1 - y2) < limit - list.size()) {
|
||||
|
||||
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
|
||||
list.add(new BlockPos(l, m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
list.addAll(getFloorBlocks(player, firstPos, secondPos));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public BlockPos findFloor(EntityPlayer player, BlockPos firstPos, boolean 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);
|
||||
|
||||
@@ -149,6 +129,33 @@ public class Floor implements IBuildMode {
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumFacing getSideHit(EntityPlayer player) {
|
||||
return sideHitTable.get(player.getUniqueID());
|
||||
|
||||
@@ -5,7 +5,6 @@ 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.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||
|
||||
import java.util.*;
|
||||
@@ -13,13 +12,13 @@ import java.util.*;
|
||||
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
|
||||
Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
||||
Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
||||
Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
||||
Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
||||
Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
||||
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<>();
|
||||
|
||||
class Criteria {
|
||||
static class Criteria {
|
||||
Vec3d planeBound;
|
||||
Vec3d lineBound;
|
||||
double distToLineSq;
|
||||
@@ -124,31 +123,13 @@ public class Line implements IBuildMode {
|
||||
BlockPos secondPos = findLine(player, firstPos, skipRaytrace);
|
||||
if (secondPos == null) return list;
|
||||
|
||||
//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();
|
||||
|
||||
outerloop:
|
||||
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) {
|
||||
if (list.size() >= axisLimit) break outerloop;
|
||||
list.add(new BlockPos(l, m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
list.addAll(getLineBlocks(player, firstPos, secondPos));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public BlockPos findLine(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||
public static BlockPos findLine(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
|
||||
Vec3d look = player.getLookVec();
|
||||
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
|
||||
|
||||
@@ -197,6 +178,31 @@ public class Line implements IBuildMode {
|
||||
return new BlockPos(selected.lineBound);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
outerloop:
|
||||
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) {
|
||||
if (list.size() >= axisLimit) break outerloop;
|
||||
list.add(new BlockPos(l, m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumFacing getSideHit(EntityPlayer player) {
|
||||
|
||||
@@ -4,33 +4,173 @@ 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.List;
|
||||
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) {
|
||||
return new ArrayList<>();
|
||||
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) {
|
||||
return new ArrayList<>();
|
||||
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 whole cube
|
||||
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());
|
||||
|
||||
//Slope along short edge
|
||||
if (zLength > xLength) onXAxis = false;
|
||||
|
||||
//TODO add option for Slope along long edge
|
||||
//if (zLength > xLength) onXAxis = true;
|
||||
|
||||
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, 1);
|
||||
|
||||
//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, 1);
|
||||
|
||||
//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 null;
|
||||
return sideHitTable.get(player.getUniqueID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getHitVec(EntityPlayer player) {
|
||||
return null;
|
||||
return hitVecTable.get(player.getUniqueID());
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
package nl.requios.effortlessbuilding.buildmode;
|
||||
|
||||
import com.sun.javafx.geom.Vec2d;
|
||||
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.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.helper.ReachHelper;
|
||||
|
||||
import java.util.*;
|
||||
@@ -14,13 +12,13 @@ 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
|
||||
Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
||||
Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
||||
Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
||||
Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
|
||||
Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
|
||||
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<>();
|
||||
|
||||
class Criteria {
|
||||
static class Criteria {
|
||||
Vec3d planeBound;
|
||||
double distToPlayerSq;
|
||||
double angle;
|
||||
@@ -29,9 +27,7 @@ public class Wall implements IBuildMode {
|
||||
this.planeBound = planeBound;
|
||||
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
|
||||
Vec3d wall = this.planeBound.subtract(new Vec3d(firstPos));
|
||||
Vec2d horizontalWall = new Vec2d(wall.x, wall.z);
|
||||
Vec2d horizontalLook = new Vec2d(look.x, look.z);
|
||||
this.angle = horizontalWall.x * horizontalLook.x + horizontalWall.y * horizontalLook.y;
|
||||
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
|
||||
@@ -107,41 +103,13 @@ public class Wall implements IBuildMode {
|
||||
if (secondPos == null) return list;
|
||||
|
||||
//Add whole wall
|
||||
//Limit amount of blocks we can place per row
|
||||
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
|
||||
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;
|
||||
if (x1 - x2 > axisLimit) x2 = x1 - axisLimit;
|
||||
if (y2 - y1 > axisLimit) y2 = y1 + axisLimit;
|
||||
if (y1 - y2 > axisLimit) y2 = y1 - axisLimit;
|
||||
if (z2 - z1 > axisLimit) z2 = z1 + axisLimit;
|
||||
if (z1 - z2 > axisLimit) z2 = z1 - axisLimit;
|
||||
|
||||
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) {
|
||||
|
||||
//check if whole row fits within limit
|
||||
if (Math.abs(y1 - y2) < limit - list.size()) {
|
||||
|
||||
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
|
||||
list.add(new BlockPos(l, m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
list.addAll(getWallBlocks(player, firstPos, secondPos));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public BlockPos findWall(EntityPlayer player, BlockPos firstPos, boolean 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);
|
||||
|
||||
@@ -179,6 +147,42 @@ public class Wall implements IBuildMode {
|
||||
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 limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
|
||||
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;
|
||||
|
||||
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) {
|
||||
|
||||
//check if whole row fits within limit
|
||||
if (Math.abs(y1 - y2) < limit - list.size()) {
|
||||
|
||||
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
|
||||
list.add(new BlockPos(l, m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumFacing getSideHit(EntityPlayer player) {
|
||||
return sideHitTable.get(player.getUniqueID());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package nl.requios.effortlessbuilding.buildmodifier;
|
||||
|
||||
import mod.chiselsandbits.api.IBitLocation;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
@@ -9,15 +9,17 @@ import java.util.List;
|
||||
|
||||
public class BlockSet {
|
||||
private List<BlockPos> coordinates;
|
||||
private List<IBlockState> blockStates;
|
||||
private List<IBlockState> previousBlockStates;
|
||||
private List<IBlockState> newBlockStates;
|
||||
private Vec3d hitVec;
|
||||
private BlockPos firstPos;
|
||||
private BlockPos secondPos;
|
||||
|
||||
public BlockSet(List<BlockPos> coordinates, List<IBlockState> blockStates, Vec3d hitVec,
|
||||
public BlockSet(List<BlockPos> coordinates, List<IBlockState> previousBlockStates, List<IBlockState> newBlockStates, Vec3d hitVec,
|
||||
BlockPos firstPos, BlockPos secondPos) {
|
||||
this.coordinates = coordinates;
|
||||
this.blockStates = blockStates;
|
||||
this.previousBlockStates = previousBlockStates;
|
||||
this.newBlockStates = newBlockStates;
|
||||
this.hitVec = hitVec;
|
||||
this.firstPos = firstPos;
|
||||
this.secondPos = secondPos;
|
||||
@@ -27,8 +29,12 @@ public class BlockSet {
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
public List<IBlockState> getBlockStates() {
|
||||
return blockStates;
|
||||
public List<IBlockState> getPreviousBlockStates() {
|
||||
return previousBlockStates;
|
||||
}
|
||||
|
||||
public List<IBlockState> getNewBlockStates() {
|
||||
return newBlockStates;
|
||||
}
|
||||
|
||||
public Vec3d getHitVec() {
|
||||
|
||||
@@ -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.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
@@ -11,14 +10,10 @@ import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import nl.requios.effortlessbuilding.BuildConfig;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||
import nl.requios.effortlessbuilding.helper.FixedStack;
|
||||
import nl.requios.effortlessbuilding.helper.InventoryHelper;
|
||||
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
|
||||
import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
|
||||
import nl.requios.effortlessbuilding.network.BlockPlacedMessage;
|
||||
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer;
|
||||
|
||||
import java.util.*;
|
||||
@@ -42,10 +37,19 @@ public class BuildModifiers {
|
||||
//check if valid blockstates
|
||||
if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return;
|
||||
|
||||
//remember previous blockstates for undo
|
||||
List<IBlockState> previousBlockStates = new ArrayList<>(coordinates.size());
|
||||
List<IBlockState> newBlockStates = new ArrayList<>(coordinates.size());
|
||||
for (BlockPos coordinate : coordinates) {
|
||||
previousBlockStates.add(world.getBlockState(coordinate));
|
||||
}
|
||||
|
||||
if (world.isRemote) {
|
||||
|
||||
BlockPreviewRenderer.onBlocksPlaced();
|
||||
|
||||
newBlockStates = blockStates;
|
||||
|
||||
} else {
|
||||
|
||||
//place blocks
|
||||
@@ -58,45 +62,75 @@ public class BuildModifiers {
|
||||
//check itemstack empty
|
||||
if (itemStack.isEmpty()) {
|
||||
//try to find new stack, otherwise continue
|
||||
itemStack = InventoryHelper.findItemStackInInventory(player, blockState);
|
||||
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
|
||||
if (itemStack.isEmpty()) continue;
|
||||
}
|
||||
SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, hitVec, false, false);
|
||||
SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, hitVec, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
//find actual new blockstates for undo
|
||||
for (BlockPos coordinate : coordinates) {
|
||||
newBlockStates.add(world.getBlockState(coordinate));
|
||||
}
|
||||
}
|
||||
|
||||
//add to undo stack
|
||||
BlockPos firstPos = startCoordinates.get(0);
|
||||
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
|
||||
UndoRedo.addUndo(player, new BlockSet(coordinates, blockStates, hitVec, firstPos, secondPos));
|
||||
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
|
||||
}
|
||||
|
||||
public static void onBlockBroken(EntityPlayer player, List<BlockPos> posList, boolean breakStartPos) {
|
||||
public static void onBlockBroken(EntityPlayer player, List<BlockPos> startCoordinates, boolean breakStartPos) {
|
||||
World world = player.world;
|
||||
|
||||
List<BlockPos> coordinates = findCoordinates(player, posList);
|
||||
List<BlockPos> coordinates = findCoordinates(player, startCoordinates);
|
||||
|
||||
if (coordinates.isEmpty()) return;
|
||||
|
||||
//remember previous blockstates for undo
|
||||
List<IBlockState> previousBlockStates = new ArrayList<>(coordinates.size());
|
||||
List<IBlockState> newBlockStates = new ArrayList<>(coordinates.size());
|
||||
for (BlockPos coordinate : coordinates) {
|
||||
previousBlockStates.add(world.getBlockState(coordinate));
|
||||
}
|
||||
|
||||
if (world.isRemote) {
|
||||
BlockPreviewRenderer.onBlocksBroken();
|
||||
return;
|
||||
}
|
||||
|
||||
//If the player is going to instabreak grass or a plant, only break other instabreaking things
|
||||
boolean onlyInstaBreaking = !player.isCreative() &&
|
||||
world.getBlockState(posList.get(0)).getBlockHardness(world, posList.get(0)) == 0f;
|
||||
//list of air blockstates
|
||||
for (BlockPos coordinate : coordinates) {
|
||||
newBlockStates.add(Block.getBlockById(0).getDefaultState());
|
||||
}
|
||||
|
||||
//break all those blocks
|
||||
for (int i = breakStartPos ? 0 : 1; i < coordinates.size(); i++) {
|
||||
BlockPos coordinate = coordinates.get(i);
|
||||
if (world.isBlockLoaded(coordinate, false)) {
|
||||
if (!onlyInstaBreaking || world.getBlockState(coordinate).getBlockHardness(world, coordinate) == 0f) {
|
||||
SurvivalHelper.breakBlock(world, player, coordinate);
|
||||
} else {
|
||||
|
||||
//If the player is going to instabreak grass or a plant, only break other instabreaking things
|
||||
boolean onlyInstaBreaking = !player.isCreative() &&
|
||||
world.getBlockState(startCoordinates.get(0)).getBlockHardness(world, startCoordinates.get(0)) == 0f;
|
||||
|
||||
//break all those blocks
|
||||
for (int i = breakStartPos ? 0 : 1; i < coordinates.size(); i++) {
|
||||
BlockPos coordinate = coordinates.get(i);
|
||||
if (world.isBlockLoaded(coordinate, false)) {
|
||||
if (!onlyInstaBreaking || world.getBlockState(coordinate).getBlockHardness(world, coordinate) == 0f) {
|
||||
SurvivalHelper.breakBlock(world, player, coordinate, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//find actual new blockstates for undo
|
||||
for (BlockPos coordinate : coordinates) {
|
||||
newBlockStates.add(world.getBlockState(coordinate));
|
||||
}
|
||||
}
|
||||
|
||||
//add to undo stack
|
||||
BlockPos firstPos = startCoordinates.get(0);
|
||||
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
|
||||
Vec3d hitVec = new Vec3d(0.5, 0.5, 0.5);
|
||||
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
|
||||
|
||||
}
|
||||
|
||||
public static List<BlockPos> findCoordinates(EntityPlayer player, List<BlockPos> posList) {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
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.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import nl.requios.effortlessbuilding.BuildConfig;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.helper.FixedStack;
|
||||
import nl.requios.effortlessbuilding.helper.InventoryHelper;
|
||||
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
|
||||
@@ -16,6 +20,7 @@ import java.util.*;
|
||||
|
||||
public class UndoRedo {
|
||||
|
||||
//Undo and redo stacks per player
|
||||
//Gets added to twice in singleplayer (server and client) if not careful. So separate stacks.
|
||||
private static Map<UUID, FixedStack<BlockSet>> undoStacksClient = new HashMap<>();
|
||||
private static Map<UUID, FixedStack<BlockSet>> undoStacksServer = new HashMap<>();
|
||||
@@ -56,19 +61,39 @@ public class UndoRedo {
|
||||
|
||||
BlockSet blockSet = undoStack.pop();
|
||||
List<BlockPos> coordinates = blockSet.getCoordinates();
|
||||
List<IBlockState> blockStates = blockSet.getBlockStates();
|
||||
List<IBlockState> previousBlockStates = blockSet.getPreviousBlockStates();
|
||||
List<IBlockState> newBlockStates = blockSet.getNewBlockStates();
|
||||
Vec3d hitVec = blockSet.getHitVec();
|
||||
|
||||
//Find up to date itemstacks in player inventory
|
||||
List<ItemStack> itemStacks = findItemStacksInInventory(player, blockStates);
|
||||
List<ItemStack> itemStacks = findItemStacksInInventory(player, previousBlockStates);
|
||||
|
||||
if (player.world.isRemote) {
|
||||
BlockPreviewRenderer.onBlocksBroken(coordinates, itemStacks, blockStates, blockSet.getSecondPos(), blockSet.getFirstPos());
|
||||
BlockPreviewRenderer.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos());
|
||||
} else {
|
||||
//break all those blocks
|
||||
//break all those blocks, reset to what they were
|
||||
for (int i = 0; i < coordinates.size(); i++) {
|
||||
BlockPos coordinate = coordinates.get(i);
|
||||
if (player.world.isBlockLoaded(coordinate, false)) {
|
||||
SurvivalHelper.breakBlock(player.world, player, coordinate);
|
||||
ItemStack itemStack = itemStacks.get(i);
|
||||
|
||||
//get blockstate from itemstack
|
||||
IBlockState previousBlockState = Block.getBlockById(0).getDefaultState();
|
||||
if (itemStack.getItem() instanceof ItemBlock) {
|
||||
previousBlockState = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
|
||||
}
|
||||
|
||||
if (player.world.isBlockLoaded(coordinate, true)) {
|
||||
//check itemstack empty
|
||||
if (itemStack.isEmpty()) {
|
||||
itemStack = findItemStackInInventory(player, previousBlockStates.get(i));
|
||||
//get blockstate from new itemstack
|
||||
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemBlock) {
|
||||
previousBlockState = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
|
||||
}
|
||||
}
|
||||
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true);
|
||||
//if previousBlockState is air, placeBlock will set it to air
|
||||
SurvivalHelper.placeBlock(player.world, player, coordinate, previousBlockState, itemStack, EnumFacing.UP, hitVec, true, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,25 +115,32 @@ public class UndoRedo {
|
||||
|
||||
BlockSet blockSet = redoStack.pop();
|
||||
List<BlockPos> coordinates = blockSet.getCoordinates();
|
||||
List<IBlockState> blockStates = blockSet.getBlockStates();
|
||||
List<IBlockState> newBlockStates = blockSet.getNewBlockStates();
|
||||
Vec3d hitVec = blockSet.getHitVec();
|
||||
|
||||
//Find up to date itemstacks in player inventory
|
||||
List<ItemStack> itemStacks = findItemStacksInInventory(player, blockStates);
|
||||
List<ItemStack> itemStacks = findItemStacksInInventory(player, newBlockStates);
|
||||
|
||||
if (player.world.isRemote) {
|
||||
BlockPreviewRenderer.onBlocksPlaced(coordinates, itemStacks, blockStates, blockSet.getFirstPos(), blockSet.getSecondPos());
|
||||
BlockPreviewRenderer.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos());
|
||||
} else {
|
||||
//place blocks
|
||||
for (int i = 0; i < coordinates.size(); i++) {
|
||||
BlockPos blockPos = coordinates.get(i);
|
||||
IBlockState blockState = blockStates.get(i);
|
||||
BlockPos coordinate = coordinates.get(i);
|
||||
IBlockState newBlockState = newBlockStates.get(i);
|
||||
ItemStack itemStack = itemStacks.get(i);
|
||||
|
||||
if (player.world.isBlockLoaded(blockPos, true)) {
|
||||
if (player.world.isBlockLoaded(coordinate, true)) {
|
||||
//check itemstack empty
|
||||
if (itemStack.isEmpty()) continue;
|
||||
SurvivalHelper.placeBlock(player.world, player, blockPos, blockState, itemStack, EnumFacing.UP, hitVec, false, false);
|
||||
if (itemStack.isEmpty()) {
|
||||
itemStack = findItemStackInInventory(player, newBlockStates.get(i));
|
||||
//get blockstate from new itemstack
|
||||
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemBlock) {
|
||||
newBlockState = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
|
||||
}
|
||||
}
|
||||
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true);
|
||||
SurvivalHelper.placeBlock(player.world, player, coordinate, newBlockState, itemStack, EnumFacing.UP, hitVec, true, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,8 +165,29 @@ public class UndoRedo {
|
||||
private static List<ItemStack> findItemStacksInInventory(EntityPlayer player, List<IBlockState> blockStates) {
|
||||
List<ItemStack> itemStacks = new ArrayList<>(blockStates.size());
|
||||
for (IBlockState blockState : blockStates) {
|
||||
itemStacks.add(InventoryHelper.findItemStackInInventory(player, blockState));
|
||||
itemStacks.add(findItemStackInInventory(player, blockState));
|
||||
}
|
||||
return itemStacks;
|
||||
}
|
||||
|
||||
private static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState blockState) {
|
||||
ItemStack itemStack = ItemStack.EMPTY;
|
||||
|
||||
//First try previousBlockStates
|
||||
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
|
||||
|
||||
//then anything it drops
|
||||
if (itemStack.isEmpty()) {
|
||||
Item itemDropped = blockState.getBlock().getItemDropped(blockState, player.world.rand, 10);
|
||||
if (itemDropped instanceof ItemBlock) {
|
||||
Block block = ((ItemBlock) itemDropped).getBlock();
|
||||
itemStack = InventoryHelper.findItemStackInInventory(player, block);
|
||||
}
|
||||
}
|
||||
|
||||
//then air
|
||||
//(already empty)
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,20 +46,28 @@ public class CompatHelper {
|
||||
|
||||
// Get the block to be placed by this proxy. For the /dank/null, it's the slot stack
|
||||
// pointed to by nbt integer selectedIndex.
|
||||
public static ItemStack getItemBlockFromStack(ItemStack stack) {
|
||||
Item item = stack.getItem();
|
||||
public static ItemStack getItemBlockFromStack(ItemStack proxy) {
|
||||
Item proxyItem = proxy.getItem();
|
||||
|
||||
if (item instanceof ItemBlock)
|
||||
return stack;
|
||||
if (proxyItem instanceof ItemBlock)
|
||||
return proxy;
|
||||
|
||||
if (item instanceof ItemRandomizerBag)
|
||||
return ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(stack));
|
||||
//Randomizer Bag
|
||||
if (proxyItem instanceof ItemRandomizerBag) {
|
||||
ItemStack itemStack = proxy;
|
||||
while (!(itemStack.getItem() instanceof ItemBlock || itemStack.isEmpty())) {
|
||||
if (itemStack.getItem() instanceof ItemRandomizerBag)
|
||||
itemStack = ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(itemStack));
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
if(item == dankNullItem) {
|
||||
//Dank Null
|
||||
if(proxyItem == dankNullItem) {
|
||||
int index = 0;
|
||||
if(stack.hasTagCompound() && stack.getTagCompound().hasKey("selectedIndex"))
|
||||
index = stack.getTagCompound().getInteger("selectedIndex");
|
||||
return stack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
|
||||
if(proxy.hasTagCompound() && proxy.getTagCompound().hasKey("selectedIndex"))
|
||||
index = proxy.getTagCompound().getInteger("selectedIndex");
|
||||
return proxy.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
@@ -109,11 +109,10 @@ public class RandomizerBagContainer extends Container {
|
||||
@Override
|
||||
public ItemStack slotClick(int slot, int dragType, ClickType clickTypeIn, EntityPlayer player) {
|
||||
// this will prevent the player from interacting with the item that opened the inventory:
|
||||
ItemStack clickItemStack = super.slotClick(slot, dragType, clickTypeIn, player);
|
||||
if (slot >= 0 && getSlot(slot) != null && getSlot(slot).getStack() == player.getHeldItem(EnumHand.MAIN_HAND)) {
|
||||
if (slot >= 0 && getSlot(slot) != null && getSlot(slot).getStack().equals(player.getHeldItem(EnumHand.MAIN_HAND))) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
return clickItemStack;
|
||||
return super.slotClick(slot, dragType, clickTypeIn, player);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package nl.requios.effortlessbuilding.helper;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
@@ -7,21 +8,21 @@ import net.minecraft.item.ItemStack;
|
||||
|
||||
public class InventoryHelper {
|
||||
|
||||
public static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState blockState) {
|
||||
public static ItemStack findItemStackInInventory(EntityPlayer player, Block block) {
|
||||
for (ItemStack invStack : player.inventory.mainInventory) {
|
||||
if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock &&
|
||||
((ItemBlock) invStack.getItem()).getBlock().equals(blockState.getBlock())) {
|
||||
((ItemBlock) invStack.getItem()).getBlock().equals(block)) {
|
||||
return invStack;
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
public static int findTotalBlocksInInventory(EntityPlayer player, IBlockState blockState) {
|
||||
public static int findTotalBlocksInInventory(EntityPlayer player, Block block) {
|
||||
int total = 0;
|
||||
for (ItemStack invStack : player.inventory.mainInventory) {
|
||||
if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock &&
|
||||
((ItemBlock) invStack.getItem()).getBlock().equals(blockState.getBlock())) {
|
||||
((ItemBlock) invStack.getItem()).getBlock().equals(block)) {
|
||||
total += invStack.getCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,17 +7,12 @@ import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Enchantments;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.item.ItemSlab;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.stats.StatList;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
@@ -26,17 +21,11 @@ import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SurvivalHelper {
|
||||
|
||||
@@ -44,10 +33,17 @@ public class SurvivalHelper {
|
||||
//Checks if area is loaded, if player has the right permissions, if existing block can be replaced (drops it if so) and consumes an item from the stack.
|
||||
//Based on ItemBlock#onItemUse
|
||||
public static boolean placeBlock(World world, EntityPlayer player, BlockPos pos, IBlockState blockState,
|
||||
ItemStack origstack, EnumFacing facing, Vec3d hitVec, boolean skipCollisionCheck, boolean playSound) {
|
||||
ItemStack origstack, EnumFacing facing, Vec3d hitVec, boolean skipPlaceCheck,
|
||||
boolean skipCollisionCheck, boolean playSound) {
|
||||
if (!world.isBlockLoaded(pos, true)) return false;
|
||||
ItemStack itemstack = origstack;
|
||||
|
||||
if (blockState.getBlock().isAir(blockState, world, pos) || itemstack.isEmpty()) {
|
||||
dropBlock(world, player, pos);
|
||||
world.setBlockToAir(pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Randomizer bag, other proxy item synergy
|
||||
//Preliminary compatibility code for other items that hold blocks
|
||||
if (CompatHelper.isItemBlockProxy(itemstack))
|
||||
@@ -59,7 +55,7 @@ public class SurvivalHelper {
|
||||
|
||||
|
||||
//More manual with ItemBlock#placeBlockAt
|
||||
if (canPlace(world, player, pos, blockState, itemstack, skipCollisionCheck, facing.getOpposite())) {
|
||||
if (skipPlaceCheck || canPlace(world, player, pos, blockState, itemstack, skipCollisionCheck, facing.getOpposite())) {
|
||||
//Drop existing block
|
||||
dropBlock(world, player, pos);
|
||||
|
||||
@@ -108,13 +104,12 @@ public class SurvivalHelper {
|
||||
|
||||
//Used for all breaking of blocks in this mod.
|
||||
//Checks if area is loaded, if appropriate tool is used in survival mode, and drops the block directly into the players inventory
|
||||
public static boolean breakBlock(World world, EntityPlayer player, BlockPos pos) {
|
||||
public static boolean breakBlock(World world, EntityPlayer player, BlockPos pos, boolean skipChecks) {
|
||||
if (!world.isBlockLoaded(pos, false)) return false;
|
||||
|
||||
//Check if can break
|
||||
if (canBreak(world, player, pos))
|
||||
{
|
||||
// player.addStat(StatList.getBlockStats(world.getBlockState(pos).getBlock()));
|
||||
if (skipChecks || canBreak(world, player, pos)) {
|
||||
// player.addStat(StatList.getBlockStats(world.getNewBlockState(pos).getBlock()));
|
||||
// player.addExhaustion(0.005F);
|
||||
|
||||
//Drop existing block
|
||||
|
||||
@@ -73,7 +73,7 @@ public class ItemRandomizerBag extends Item {
|
||||
IBlockState blockState = Block.getBlockFromItem(toPlace.getItem()).getStateForPlacement(world, pos, facing,
|
||||
hitX, hitY, hitZ, toPlace.getMetadata(), player, hand);
|
||||
|
||||
SurvivalHelper.placeBlock(world, player, pos, blockState, toPlace, facing, new Vec3d(hitX, hitY, hitZ), false, true);
|
||||
SurvivalHelper.placeBlock(world, player, pos, blockState, toPlace, facing, new Vec3d(hitX, hitY, hitZ), false, false, true);
|
||||
|
||||
//Synergy
|
||||
//Works without calling
|
||||
|
||||
@@ -3,7 +3,6 @@ package nl.requios.effortlessbuilding.network;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -24,24 +23,31 @@ import java.util.ArrayList;
|
||||
*/
|
||||
public class RequestLookAtMessage implements IMessage {
|
||||
private BlockPos coordinate;
|
||||
private IBlockState blockState;
|
||||
private IBlockState previousBlockState;
|
||||
private IBlockState newBlockState;
|
||||
|
||||
public RequestLookAtMessage() {
|
||||
coordinate = BlockPos.ORIGIN;
|
||||
blockState = null;
|
||||
previousBlockState = null;
|
||||
newBlockState = null;
|
||||
}
|
||||
|
||||
public RequestLookAtMessage(BlockPos coordinate, IBlockState blockState) {
|
||||
public RequestLookAtMessage(BlockPos coordinate, IBlockState previousBlockState, IBlockState newBlockState) {
|
||||
this.coordinate = coordinate;
|
||||
this.blockState = blockState;
|
||||
this.previousBlockState = previousBlockState;
|
||||
this.newBlockState = newBlockState;
|
||||
}
|
||||
|
||||
public BlockPos getCoordinate() {
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
public IBlockState getBlockState() {
|
||||
return blockState;
|
||||
public IBlockState getPreviousBlockState() {
|
||||
return previousBlockState;
|
||||
}
|
||||
|
||||
public IBlockState getNewBlockState() {
|
||||
return newBlockState;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,13 +55,15 @@ public class RequestLookAtMessage implements IMessage {
|
||||
buf.writeInt(this.coordinate.getX());
|
||||
buf.writeInt(this.coordinate.getY());
|
||||
buf.writeInt(this.coordinate.getZ());
|
||||
buf.writeInt(Block.getStateId(this.blockState));
|
||||
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());
|
||||
blockState = Block.getStateById(buf.readInt());
|
||||
previousBlockState = Block.getStateById(buf.readInt());
|
||||
newBlockState = Block.getStateById(buf.readInt());
|
||||
}
|
||||
|
||||
// The params of the IMessageHandler are <REQ, REPLY>
|
||||
@@ -76,7 +84,8 @@ public class RequestLookAtMessage implements IMessage {
|
||||
//Add to undo stack clientside
|
||||
UndoRedo.addUndo(player, new BlockSet(
|
||||
new ArrayList<BlockPos>() {{add(message.getCoordinate());}},
|
||||
new ArrayList<IBlockState>() {{add(message.getBlockState());}},
|
||||
new ArrayList<IBlockState>() {{add(message.getPreviousBlockState());}},
|
||||
new ArrayList<IBlockState>() {{add(message.getNewBlockState());}},
|
||||
new Vec3d(0,0,0),
|
||||
message.getCoordinate(), message.getCoordinate()));
|
||||
});
|
||||
|
||||
@@ -226,6 +226,7 @@ public class ClientProxy implements IProxy {
|
||||
ItemStack currentItemStack = player.getHeldItem(EnumHand.MAIN_HAND);
|
||||
if (currentItemStack.getItem() instanceof ItemBlock ||
|
||||
(CompatHelper.isItemBlockProxy(currentItemStack) && !player.isSneaking())) {
|
||||
|
||||
ItemStack itemStack = CompatHelper.getItemBlockFromStack(currentItemStack);
|
||||
|
||||
//find position in distance
|
||||
@@ -235,7 +236,8 @@ public class ClientProxy implements IProxy {
|
||||
|
||||
//play sound if further than normal
|
||||
if (lookingAt != null && lookingAt.typeOfHit == RayTraceResult.Type.BLOCK &&
|
||||
(lookingAt.hitVec.subtract(player.getPositionEyes(1f))).lengthSquared() > 25f) {
|
||||
(lookingAt.hitVec.subtract(player.getPositionEyes(1f))).lengthSquared() > 25f &&
|
||||
itemStack.getItem() instanceof ItemBlock) {
|
||||
|
||||
IBlockState state = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
|
||||
BlockPos blockPos = lookingAt.getBlockPos();
|
||||
|
||||
@@ -304,7 +304,7 @@ public class BlockPreviewRenderer {
|
||||
|
||||
//Check if can place
|
||||
//If check is turned off, check if blockstate is the same (for dissolve effect)
|
||||
if ((!checkCanPlace /*&& player.world.getBlockState(blockPos) == blockState*/) || //TODO enable (breaks breaking shader)
|
||||
if ((!checkCanPlace /*&& player.world.getNewBlockState(blockPos) == blockState*/) || //TODO enable (breaks breaking shader)
|
||||
SurvivalHelper.canPlace(player.world, player, blockPos, blockState, itemstack, modifierSettings.doQuickReplace(), EnumFacing.UP)) {
|
||||
|
||||
ShaderHandler.useShader(ShaderHandler.dissolve, generateShaderCallback(dissolve,
|
||||
|
||||
@@ -16,10 +16,10 @@ effortlessbuilding.mode.normal_plus=Normal+
|
||||
effortlessbuilding.mode.line=Line
|
||||
effortlessbuilding.mode.wall=Wall
|
||||
effortlessbuilding.mode.floor=Floor
|
||||
effortlessbuilding.mode.diagonal_line=Diagonal Line (WIP)
|
||||
effortlessbuilding.mode.diagonal_wall=Diagonal Wall (WIP)
|
||||
effortlessbuilding.mode.slope_floor=Slope Floor (WIP)
|
||||
effortlessbuilding.mode.cube=Cube (WIP)
|
||||
effortlessbuilding.mode.diagonal_line=Diagonal Line
|
||||
effortlessbuilding.mode.diagonal_wall=Diagonal Wall
|
||||
effortlessbuilding.mode.slope_floor=Slope Floor
|
||||
effortlessbuilding.mode.cube=Cube
|
||||
|
||||
effortlessbuilding.action.undo=Undo
|
||||
effortlessbuilding.action.redo=Redo
|
||||
|
||||
@@ -102,5 +102,5 @@ void main() {
|
||||
|
||||
if (maskgs * 0.3 + place * 0.7 <= dissolve)
|
||||
gl_FragColor = vec4(texcolor.rgb, 0.0);
|
||||
else gl_FragColor = vec4(color.rgb, 0.85);
|
||||
else gl_FragColor = color;
|
||||
}
|
||||
Reference in New Issue
Block a user