Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.fouristhenumber.utilitiesinexcess.common.items;

import static com.fouristhenumber.utilitiesinexcess.utils.ArchitectsWandUtils.getItemStackToPlace;

import java.util.List;
import java.util.Set;

Expand All @@ -8,10 +10,12 @@
import net.minecraft.entity.Entity;
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.EnumChatFormatting;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.StatCollector;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;

Expand Down Expand Up @@ -50,47 +54,52 @@ public void onUpdate(ItemStack stack, World world, Entity entity, int slot, bool
return;
}

if (!isSelected) return;
if (!isSelected) {
return;
}

MovingObjectPosition mop = Minecraft.getMinecraft().objectMouseOver;
// I'm pretty sure this will never determine whether we render or not but I'm not certain
MovingObjectPosition movingObjectPosition = Minecraft.getMinecraft().objectMouseOver;

// Check if player is looking at a block.
if (mop == null || mop.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) {
if (movingObjectPosition == null
|| movingObjectPosition.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) {
WireframeRenderer.clearCandidatePositions();
return;
}

int x = mop.blockX;
int y = mop.blockY;
int z = mop.blockZ;
int side = mop.sideHit;
// 1. Target block location
BlockPos target = new BlockPos(
movingObjectPosition.blockX,
movingObjectPosition.blockY,
movingObjectPosition.blockZ);

// 2. Side
int side = movingObjectPosition.sideHit;
ForgeDirection forgeSide = ForgeDirection.getOrientation(side);
if (forgeSide == ForgeDirection.UNKNOWN) {
UtilitiesInExcess.LOG
.warn("Architect wand onUpdate was called with invalid facing direction: {}", forgeSide);
return;
}

Block blockToPlace = world.getBlock(x, y, z);
if (blockToPlace == null) return;
int metaToPlace = world.getBlockMetadata(x, y, z);
ItemStack itemStack = new ItemStack(Item.getItemFromBlock(blockToPlace), 1, metaToPlace);

int inventoryBlockCount = ArchitectsWandUtils.countItemInInventory(player, itemStack);
if (!player.capabilities.isCreativeMode && inventoryBlockCount == 0) {
// 4. Target block to place
ItemStack itemStackToPlace = getItemStackToPlace(world, target, movingObjectPosition, player);
if (itemStackToPlace == null || !(itemStackToPlace.getItem() instanceof ItemBlock)) {
WireframeRenderer.clearCandidatePositions();
return;
}

// 3. Total amount to place
int placeCount = player.capabilities.isCreativeMode ? this.buildLimit
: Math.min(inventoryBlockCount, this.buildLimit);
: Math.min(ArchitectsWandUtils.countItemInInventory(player, itemStackToPlace), this.buildLimit);

Set<BlockPos> blocksToPlace = ArchitectsWandUtils
.findAdjacentBlocks(world, blockToPlace, metaToPlace, placeCount, forgeSide, new BlockPos(x, y, z));
.findAdjacentBlocks(world, itemStackToPlace, placeCount, forgeSide, target, movingObjectPosition, player);
WireframeRenderer.clearCandidatePositions();
for (BlockPos pos : blocksToPlace) {
WireframeRenderer.addCandidatePosition(pos.offset(forgeSide.offsetX, forgeSide.offsetY, forgeSide.offsetZ));
}

}

@Override
Expand All @@ -104,28 +113,44 @@ public boolean onItemUse(ItemStack itemstack, EntityPlayer player, World world,
return false;
}

Block blockToPlace = world.getBlock(x, y, z);
if (blockToPlace == null) return false;
int metaToPlace = world.getBlockMetadata(x, y, z);
ItemStack itemStack = new ItemStack(Item.getItemFromBlock(blockToPlace), 1, metaToPlace);
BlockPos target = new BlockPos(x, y, z);
MovingObjectPosition mop = new MovingObjectPosition(x, y, z, side, Vec3.createVectorHelper(hitX, hitY, hitZ));
ItemStack itemStackToPlace = getItemStackToPlace(world, target, mop, player);
if (itemStackToPlace == null || !(itemStackToPlace.getItem() instanceof ItemBlock)) return false;

// This block is here because some mods want to use TEs to
Block comparisonBlock = world.getBlock(x, y, z);
int comparisonMeta = world.getBlockMetadata(x, y, z);
ItemStack comparisonItemStack = new ItemStack(comparisonBlock, 1, comparisonMeta);

int inventoryBlockCount = ArchitectsWandUtils.countItemInInventory(player, itemStack);
boolean useCompatPlacement = !ItemStack.areItemStacksEqual(itemStackToPlace, comparisonItemStack);

int inventoryBlockCount = ArchitectsWandUtils.countItemInInventory(player, itemStackToPlace);
if (!player.capabilities.isCreativeMode && inventoryBlockCount == 0) return false;
int placeCount = player.capabilities.isCreativeMode ? this.buildLimit
: Math.min(inventoryBlockCount, this.buildLimit);

Set<BlockPos> blocksToPlace = ArchitectsWandUtils
.findAdjacentBlocks(world, blockToPlace, metaToPlace, placeCount, forgeSide, new BlockPos(x, y, z));
.findAdjacentBlocks(world, itemStackToPlace, placeCount, forgeSide, target, mop, player);
itemStackToPlace.stackSize = blocksToPlace.size(); // Since now, we actually create a stack we have to set the
// size. Strange kinda...

for (BlockPos pos : blocksToPlace) {
// TODO: Group these by a bigger number instead of decreasing by 1 every time.
if (player.capabilities.isCreativeMode || ArchitectsWandUtils.decreaseFromInventory(player, itemStack)) {
world.setBlock(
pos.x + forgeSide.offsetX,
pos.y + forgeSide.offsetY,
pos.z + forgeSide.offsetZ,
blockToPlace,
metaToPlace,
3);
if (player.capabilities.isCreativeMode
|| ArchitectsWandUtils.decreaseFromInventory(player, itemStackToPlace)) {
if (useCompatPlacement) {
itemStackToPlace.getItem()
.onItemUse(itemStackToPlace, player, world, pos.x, pos.y, pos.z, side, hitX, hitY, hitZ);
} else {
world.setBlock(
pos.x + forgeSide.offsetX,
pos.y + forgeSide.offsetY,
pos.z + forgeSide.offsetZ,
comparisonBlock,
comparisonMeta,
3);
}
}
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static void addCandidatePosition(BlockPos pos) {
}

public static void clearCandidatePositions() {
if (!candidatePositions.isEmpty()) candidatePositions.clear();
candidatePositions.clear();
}

@EventBusSubscriber.Condition
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.fouristhenumber.utilitiesinexcess.utils;

import static com.fouristhenumber.utilitiesinexcess.utils.MovingObjectPositionUtil.TranslateMovingObjectPoistionToLocation;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
Expand All @@ -8,6 +10,7 @@
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;

Expand Down Expand Up @@ -60,19 +63,18 @@ public static boolean decreaseFromInventory(EntityPlayer player, ItemStack itemS
}

/**
* Finds the blocks adjacent to the start position that are connected cardinally
* and have air infront of them relative to the side clicked on.
* Finds the blocks adjacent to the start position that are connected cardinally, or diagonally
* and have air in front of them relative to the side clicked on.
*
* @param world The world in which to place
* @param blockToFind The block that is being found
* @param metaToFind The metadata of the block that is being found
* @param
* @param findCount The maximum amount of blocks it should search
* @param clickedSide The side of the block that was clicked
* @param startPos The position to start
* @return The set of 1<=x<=findCount adjacent blocks with air on their face
*/
public static Set<BlockPos> findAdjacentBlocks(World world, Block blockToFind, int metaToFind, int findCount,
ForgeDirection clickedSide, BlockPos startPos) {
public static Set<BlockPos> findAdjacentBlocks(World world, ItemStack itemStackToPlace, int findCount,
ForgeDirection clickedSide, BlockPos startPos, MovingObjectPosition mop, EntityPlayer player) {
Set<BlockPos> region = new HashSet<>();
if (findCount <= 0) {
return region;
Expand All @@ -84,27 +86,26 @@ public static Set<BlockPos> findAdjacentBlocks(World world, Block blockToFind, i
int[][] allowedOffsets = switch (clickedSide) {
case UP, DOWN ->
// Plane: x/z plane (y remains constant)
new int[][] { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 0, 1 }, { 0, 0, -1 } };
new int[][] { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 0, 1 }, { 0, 0, -1 }, // Cardinal
{ 1, 0, 1 }, { 1, 0, -1 }, { -1, 0, 1 }, { -1, 0, -1 } }; // Diagonal
case NORTH, SOUTH ->
// Plane: x/y plane (z remains constant)
new int[][] { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 } };
new int[][] { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 }, // Cardinal
{ 1, 1, 0 }, { 1, -1, 0 }, { -1, 1, 0 }, { -1, -1, 0 } }; // Diagonal
case EAST, WEST ->
// Plane: y/z plane (x remains constant)
new int[][] { { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 }, { 0, 0, -1 } };
new int[][] { { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 }, { 0, 0, -1 }, // Cardinal
{ 0, 1, 1 }, { 0, 1, -1 }, { 0, -1, 1 }, { 0, -1, -1 } }; // Diagonal
default -> throw new RuntimeException("UE's BuilderWand's findAdjacentBlocks called with invalid side");
};

int sx = startPos.x;
int sy = startPos.y;
int sz = startPos.z;
// translate the mop
TranslateMovingObjectPoistionToLocation(mop, startPos);

// Base case
if (world.getBlock(sx, sy, sz) == blockToFind && world.getBlockMetadata(sx, sy, sz) == metaToFind
&& world.isAirBlock(sx + clickedSide.offsetX, sy + clickedSide.offsetY, sz + clickedSide.offsetZ)) {

BlockPos neighbor = new BlockPos(sx, sy, sz);
region.add(neighbor);
queue.add(neighbor);
if (IsValidForWireFrame(world, itemStackToPlace, startPos, mop, player, clickedSide)) {
region.add(startPos);
queue.add(startPos);
visited.add(startPos);
} else {
return region;
Expand All @@ -113,38 +114,65 @@ public static Set<BlockPos> findAdjacentBlocks(World world, Block blockToFind, i
// Flood-fill the contiguous region in the allowed plane.
while (!queue.isEmpty() && region.size() < findCount) {
BlockPos current = queue.poll();
int cx = current.x;
int cy = current.y;
int cz = current.z;

for (int[] off : allowedOffsets) {
// Check if already visited
int nx = cx + off[0];
int ny = cy + off[1];
int nz = cz + off[2];
if (region.size() >= findCount) {
break;
}

BlockPos key = new BlockPos(nx, ny, nz);
BlockPos key = current.offset(off[0], off[1], off[2]);
if (visited.contains(key)) {
continue;
}
visited.add(key);

// Check and add to region+queue
int airx = nx + clickedSide.offsetX;
int airy = ny + clickedSide.offsetY;
int airz = nz + clickedSide.offsetZ;

if (world.getBlock(nx, ny, nz) == blockToFind && world.getBlockMetadata(nx, ny, nz) == metaToFind
&& world.isAirBlock(airx, airy, airz)) {

BlockPos neighbor = new BlockPos(nx, ny, nz);
region.add(neighbor);
queue.add(neighbor);
// translate the mop
TranslateMovingObjectPoistionToLocation(mop, key);
if (IsValidForWireFrame(world, itemStackToPlace, key, mop, player, clickedSide)) {
region.add(key);
queue.add(key);
}
}
}

return region;
}

private static boolean IsValidForWireFrame(World world, ItemStack itemStackToPlace, BlockPos targetLocation,
MovingObjectPosition movingObjectPosition, EntityPlayer player, ForgeDirection clickedSide) {
ItemStack stack = getItemStackToPlace(world, targetLocation, movingObjectPosition, player);
if (stack != null) {
Block block = Block.getBlockFromItem(stack.getItem());
return ItemStack.areItemStacksEqual(stack, itemStackToPlace)
&& world.isAirBlock(
targetLocation.x + clickedSide.offsetX,
targetLocation.y + clickedSide.offsetY,
targetLocation.z + clickedSide.offsetZ)
&& block.canPlaceBlockOnSide(
world,
targetLocation.x + clickedSide.offsetX,
targetLocation.y + clickedSide.offsetY,
targetLocation.z + clickedSide.offsetZ,
clickedSide.ordinal())
&& world.canPlaceEntityOnSide(
block,
targetLocation.x + clickedSide.offsetX,
targetLocation.y + clickedSide.offsetY,
targetLocation.z + clickedSide.offsetZ,
false,
clickedSide.ordinal(),
null,
stack);
}
return false;
}

public static ItemStack getItemStackToPlace(World world, BlockPos pos, MovingObjectPosition movingObjectPosition,
EntityPlayer player) {
Block block = world.getBlock(pos.x, pos.y, pos.z);
if (block != null) {
return block.getPickBlock(movingObjectPosition, world, pos.x, pos.y, pos.z, player);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.fouristhenumber.utilitiesinexcess.utils;

import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;

import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;

public class MovingObjectPositionUtil {

public static void TranslateMovingObjectPoistionToLocation(MovingObjectPosition movingObjectPosition,
BlockPos location) {
double offsetXn = movingObjectPosition.hitVec.xCoord - movingObjectPosition.blockX;
double offsetYn = movingObjectPosition.hitVec.yCoord - movingObjectPosition.blockY;
double offsetZn = movingObjectPosition.hitVec.zCoord - movingObjectPosition.blockZ;

movingObjectPosition.blockX = location.x;
movingObjectPosition.blockY = location.y;
movingObjectPosition.blockZ = location.z;

movingObjectPosition.hitVec = Vec3
.createVectorHelper(location.x + offsetXn, location.y + offsetYn, location.z + offsetZn);
}
}