mirror of
https://github.com/HbmMods/Hbm-s-Nuclear-Tech-GIT.git
synced 2026-03-14 13:45:36 +00:00
Rewrite autosaw fellTree with 0-1 BFS tree detection
Old approach scanned a fixed 5-direction, 10-block-high column — missed branches, couldn't distinguish adjacent trees. New approach: - Scan working area for valid tree bases with plantable ground below - 0-1 BFS from all bases using 18-connectivity to assign each wood/leaf block to its nearest trunk - Only fell blocks owned by the hit tree's column
This commit is contained in:
parent
c6faa08e73
commit
34f66d0ad9
@ -1,10 +1,14 @@
|
|||||||
package com.hbm.tileentity.machine;
|
package com.hbm.tileentity.machine;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.hbm.blocks.ModBlocks;
|
import com.hbm.blocks.ModBlocks;
|
||||||
|
import com.hbm.util.fauxpointtwelve.BlockPos;
|
||||||
import com.hbm.blocks.generic.BlockTallPlant.EnumTallFlower;
|
import com.hbm.blocks.generic.BlockTallPlant.EnumTallFlower;
|
||||||
import com.hbm.handler.threading.PacketThreading;
|
import com.hbm.handler.threading.PacketThreading;
|
||||||
import com.hbm.inventory.fluid.FluidType;
|
import com.hbm.inventory.fluid.FluidType;
|
||||||
@ -39,6 +43,22 @@ import net.minecraftforge.common.util.ForgeDirection;
|
|||||||
|
|
||||||
public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IBufPacketReceiver, IFluidStandardReceiver, IFluidCopiable {
|
public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IBufPacketReceiver, IFluidStandardReceiver, IFluidCopiable {
|
||||||
|
|
||||||
|
private static final int MIN_DIST = 2;
|
||||||
|
private static final int MAX_DIST = 9;
|
||||||
|
|
||||||
|
private static final int FELL_HORIZONTAL_RANGE = 10;
|
||||||
|
private static final int FELL_BFS_RADIUS = MAX_DIST + FELL_HORIZONTAL_RANGE;
|
||||||
|
private static final int FELL_VERTICAL_RANGE = 32;
|
||||||
|
private static final int FELL_MAX_BASE_DEPTH = FELL_VERTICAL_RANGE / 2;
|
||||||
|
|
||||||
|
// 18-connectivity: 6 face-adjacent + 12 edge-adjacent (exactly one coord diff is 0)
|
||||||
|
private static final int[][] EIGHTEEN_DIRS = {
|
||||||
|
{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1},
|
||||||
|
{1, 1, 0}, {1, -1, 0}, {-1, 1, 0}, {-1, -1, 0},
|
||||||
|
{1, 0, 1}, {1, 0, -1}, {-1, 0, 1}, {-1, 0, -1},
|
||||||
|
{0, 1, 1}, {0, 1, -1}, {0, -1, 1}, {0, -1, -1}
|
||||||
|
};
|
||||||
|
|
||||||
public static final HashSet<FluidType> acceptedFuels = new HashSet();
|
public static final HashSet<FluidType> acceptedFuels = new HashSet();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -134,11 +154,11 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB
|
|||||||
double rotationYawRads = Math.toRadians((rotationYaw + 270) % 360);
|
double rotationYawRads = Math.toRadians((rotationYaw + 270) % 360);
|
||||||
|
|
||||||
outer:
|
outer:
|
||||||
for(int dx = -9; dx <= 9; dx++) {
|
for(int dx = -MAX_DIST; dx <= MAX_DIST; dx++) {
|
||||||
for(int dz = -9; dz <= 9; dz++) {
|
for(int dz = -MAX_DIST; dz <= MAX_DIST; dz++) {
|
||||||
int sqrDst = dx * dx + dz * dz;
|
int sqrDst = dx * dx + dz * dz;
|
||||||
|
|
||||||
if(sqrDst <= 4 || sqrDst > 81)
|
if(sqrDst <= MIN_DIST * MIN_DIST || sqrDst > MAX_DIST * MAX_DIST)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
double angle = Math.atan2(dz, dx);
|
double angle = Math.atan2(dz, dx);
|
||||||
@ -316,41 +336,167 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB
|
|||||||
worldObj.setBlock(x, y, z, replacementBlock, replacementMeta, 3);
|
worldObj.setBlock(x, y, z, replacementBlock, replacementMeta, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fellTree(int x, int y, int z) {
|
protected void fellTree(int hitX, int hitY, int hitZ) {
|
||||||
|
|
||||||
if(worldObj.getBlock(x, y - 1, z).getMaterial() == Material.wood) {
|
int sawY = hitY;
|
||||||
y--;
|
BlockPos hitCol = new BlockPos(hitX, -1, hitZ);
|
||||||
if(worldObj.getBlock(x, y - 2, z).getMaterial() == Material.wood) {
|
|
||||||
y--;
|
// Step A: Scan working area for trunks (column -> trunk base pos)
|
||||||
|
HashMap<BlockPos, BlockPos> trunks = new HashMap<BlockPos, BlockPos>();
|
||||||
|
|
||||||
|
for(int dx = -MAX_DIST; dx <= MAX_DIST; dx++) {
|
||||||
|
for(int dz = -MAX_DIST; dz <= MAX_DIST; dz++) {
|
||||||
|
if(dx * dx + dz * dz > MAX_DIST * MAX_DIST) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int colX = xCoord + dx;
|
||||||
|
int colZ = zCoord + dz;
|
||||||
|
|
||||||
|
if(worldObj.getBlock(colX, sawY, colZ).getMaterial() != Material.wood) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int baseY = sawY;
|
||||||
|
while(sawY - baseY < FELL_MAX_BASE_DEPTH && worldObj.getBlock(colX, baseY - 1, colZ).getMaterial() == Material.wood) {
|
||||||
|
baseY--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!canSupportSapling(worldObj, colX, baseY - 1, colZ)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
trunks.put(new BlockPos(colX, -1, colZ), new BlockPos(colX, baseY, colZ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int meta = -1;
|
// Always include the hit position's trunk
|
||||||
|
if(!trunks.containsKey(hitCol)) {
|
||||||
|
int baseY = hitY;
|
||||||
|
while(sawY - baseY < FELL_MAX_BASE_DEPTH && worldObj.getBlock(hitX, baseY - 1, hitZ).getMaterial() == Material.wood) {
|
||||||
|
baseY--;
|
||||||
|
}
|
||||||
|
trunks.put(hitCol, new BlockPos(hitX, baseY, hitZ));
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = y; i < y + 10; i++) {
|
// Step B: 0-1 BFS from all trunks
|
||||||
|
// Vertical neighbors (same column) have distance 0, horizontal neighbors have distance 1
|
||||||
|
// blockOwner: block pos -> column of owning trunk
|
||||||
|
HashMap<BlockPos, BlockPos> blockOwner = new HashMap<BlockPos, BlockPos>();
|
||||||
|
ArrayDeque<BlockPos[]> deque = new ArrayDeque<BlockPos[]>();
|
||||||
|
int hitColCount = 1;
|
||||||
|
|
||||||
int[][] dir = new int[][] {{0, 0}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}};
|
int minY = Math.max(0, sawY - FELL_MAX_BASE_DEPTH);
|
||||||
|
int maxY = Math.min(255, sawY + FELL_VERTICAL_RANGE);
|
||||||
|
|
||||||
for(int[] d : dir) {
|
for(Map.Entry<BlockPos, BlockPos> trunk : trunks.entrySet()) {
|
||||||
Block b = worldObj.getBlock(x + d[0], i, z + d[1]);
|
deque.addFirst(new BlockPos[] {trunk.getValue(), trunk.getKey()});
|
||||||
|
}
|
||||||
|
|
||||||
if(b.getMaterial() == Material.wood) {
|
while(!deque.isEmpty()) {
|
||||||
worldObj.func_147480_a(x + d[0], i, z + d[1], true);
|
BlockPos[] pair = deque.pollFirst();
|
||||||
} else if(b instanceof BlockLeaves) {
|
BlockPos current = pair[0];
|
||||||
meta = worldObj.getBlockMetadata(x + d[0], i, z + d[1]) & 3;
|
BlockPos currentCol = pair[1];
|
||||||
if(b == Blocks.leaves2) meta += 4;
|
|
||||||
worldObj.func_147480_a(x + d[0], i, z + d[1], true);
|
if(blockOwner.containsKey(current)) {
|
||||||
|
if(currentCol.equals(hitCol)) {
|
||||||
|
hitColCount--;
|
||||||
|
if(hitColCount == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
blockOwner.put(current, currentCol);
|
||||||
|
|
||||||
|
for(int[] dir : EIGHTEEN_DIRS) {
|
||||||
|
int neighborX = current.getX() + dir[0];
|
||||||
|
int neighborY = current.getY() + dir[1];
|
||||||
|
int neighborZ = current.getZ() + dir[2];
|
||||||
|
|
||||||
|
// Bounds check: radius FELL_BFS_RADIUS horizontal, minY to maxY vertical
|
||||||
|
int neighborDx = neighborX - xCoord;
|
||||||
|
int neighborDz = neighborZ - zCoord;
|
||||||
|
if(neighborDx * neighborDx + neighborDz * neighborDz > FELL_BFS_RADIUS * FELL_BFS_RADIUS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(neighborY < minY || neighborY > maxY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos neighborPos = new BlockPos(neighborX, neighborY, neighborZ);
|
||||||
|
if(blockOwner.containsKey(neighborPos)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block b = worldObj.getBlock(neighborX, neighborY, neighborZ);
|
||||||
|
Material mat = b.getMaterial();
|
||||||
|
if(mat != Material.wood && mat != Material.leaves && !(b instanceof BlockLeaves)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasHorizontal = dir[0] != 0 || dir[2] != 0;
|
||||||
|
BlockPos[] entry = new BlockPos[] {neighborPos, currentCol};
|
||||||
|
if(!hasHorizontal) {
|
||||||
|
deque.addFirst(entry);
|
||||||
|
} else {
|
||||||
|
deque.addLast(entry);
|
||||||
|
}
|
||||||
|
if(currentCol.equals(hitCol)) {
|
||||||
|
hitColCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentCol.equals(hitCol)) {
|
||||||
|
hitColCount--;
|
||||||
|
if(hitColCount == 0) {
|
||||||
|
break; // Early exit: all hit-tree blocks processed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(meta >= 0) {
|
// Step C: Cut blocks assigned to the hit trunk
|
||||||
if(Blocks.sapling.canPlaceBlockAt(worldObj, x, y, z)) {
|
for(Map.Entry<BlockPos, BlockPos> entry : blockOwner.entrySet()) {
|
||||||
worldObj.setBlock(x, y, z, Blocks.sapling, meta, 3);
|
if(!entry.getValue().equals(hitCol)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos pos = entry.getKey();
|
||||||
|
int bx = pos.getX();
|
||||||
|
int by = pos.getY();
|
||||||
|
int bz = pos.getZ();
|
||||||
|
|
||||||
|
Block b = worldObj.getBlock(bx, by, bz);
|
||||||
|
|
||||||
|
// Replant sapling at positions within working area
|
||||||
|
if(b.getMaterial() == Material.wood && isWithinWorkingArea(bx, bz) && canSupportSapling(worldObj, bx, by - 1, bz)) {
|
||||||
|
int bmeta = worldObj.getBlockMetadata(bx, by, bz);
|
||||||
|
int sapMeta = 0;
|
||||||
|
if(b == Blocks.log) {
|
||||||
|
sapMeta = bmeta & 3;
|
||||||
|
} else if(b == Blocks.log2) {
|
||||||
|
sapMeta = (bmeta & 3) + 4;
|
||||||
|
}
|
||||||
|
worldObj.func_147480_a(bx, by, bz, true);
|
||||||
|
worldObj.setBlock(bx, by, bz, Blocks.sapling, sapMeta, 3);
|
||||||
|
} else {
|
||||||
|
worldObj.func_147480_a(bx, by, bz, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isWithinWorkingArea(int x, int z) {
|
||||||
|
int dx = x - xCoord;
|
||||||
|
int dz = z - zCoord;
|
||||||
|
int distSq = dx * dx + dz * dz;
|
||||||
|
return distSq > MIN_DIST * MIN_DIST && distSq <= MAX_DIST * MAX_DIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canSupportSapling(World world, int x, int y, int z) {
|
||||||
|
Block block = world.getBlock(x, y, z);
|
||||||
|
return block.canSustainPlant(world, x, y, z, ForgeDirection.UP, (IPlantable) Blocks.sapling);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(ByteBuf buf) {
|
public void serialize(ByteBuf buf) {
|
||||||
buf.writeBoolean(this.isOn);
|
buf.writeBoolean(this.isOn);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user