Ssome more cleanup

This commit is contained in:
Sollace 2020-10-10 16:25:49 +02:00
parent 312afe3d46
commit 5c2e156392
4 changed files with 174 additions and 178 deletions

View file

@ -16,125 +16,138 @@ import net.minecraft.world.World;
public class TreeTraverser {
public static void removeTree(World w, BlockPos pos) {
BlockState log = w.getBlockState(pos);
public static class Remover {
/**
* Removes the tree located at the given position.
*/
public static void removeTree(World w, BlockPos pos) {
BlockState log = w.getBlockState(pos);
int size = measureTree(w, log, pos);
if (size > 0) {
removeTreePart(w, log, ascendTrunk(new HashSet<BlockPos>(), w, pos, log, 0).get(), 0);
}
}
private static void removeTreePart(World w, BlockState log, BlockPos pos, int level) {
if (level < 10 && isWoodOrLeaf(w, log, pos)) {
if (level < 5) {
w.breakBlock(pos, true);
} else {
Block.dropStacks(w.getBlockState(pos), w, pos);
w.setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
if (Measurer.measureTree(w, log, pos) > 0) {
removeTreePart(w, log, Ascender.ascendTrunk(new HashSet<BlockPos>(), w, pos, log, 0).get(), 0);
}
}
PosHelper.all(pos, p -> {
removeTreePart(w, log, p, level + 1);
}, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST);
private static void removeTreePart(World w, BlockState log, BlockPos pos, int level) {
if (level < 10 && isWoodOrLeaf(w, log, pos)) {
breakBlock(w, pos, level < 5);
PosHelper.all(pos, p -> {
removeTreePart(w, log, p, level + 1);
}, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST);
}
}
}
private static Optional<BlockPos> ascendTrunk(Set<BlockPos> done, World w, BlockPos pos, BlockState log, int level) {
if (level < 3 && !done.contains(pos)) {
done.add(pos);
BlockPos.Mutable result = new BlockPos.Mutable();
result.set(ascendTree(w, log, pos, true));
PosHelper.all(pos, p -> {
if (variantAndBlockEquals(w.getBlockState(pos.east()), log)) {
ascendTrunk(done, w, pos.east(), log, level + 1).filter(a -> a.getY() > result.getY()).ifPresent(result::set);
public static class Ascender {
/**
* Locates the top of the tree's trunk. Usually the point where wood meets leaves.
*/
public static BlockPos ascendTree(World w, BlockState log, BlockPos pos, boolean remove) {
int breaks = 0;
while (variantAndBlockEquals(w.getBlockState(pos.up()), log)) {
if (PosHelper.any(pos, p -> isLeaves(w.getBlockState(p), log), Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST)) {
break;
}
}, Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH);
done.add(result.toImmutable());
return Optional.of(result.toImmutable());
}
return Optional.of(pos);
}
public static BlockPos ascendTree(World w, BlockState log, BlockPos pos, boolean remove) {
int breaks = 0;
BlockState state;
while (variantAndBlockEquals(w.getBlockState(pos.up()), log)) {
if (PosHelper.some(pos, p -> isLeaves(w.getBlockState(p), log), Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST)) {
break;
}
if (remove) {
if (breaks < 10) {
w.breakBlock(pos, true);
} else {
state = w.getBlockState(pos);
Block.dropStacks(state, w, pos);
w.setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
if (remove) {
breakBlock(w, pos, breaks++ < 10);
}
breaks++;
pos = pos.up();
}
pos = pos.up();
return pos;
}
static Optional<BlockPos> ascendTrunk(Set<BlockPos> done, World w, BlockPos pos, BlockState log, int level) {
if (level < 3 && !done.contains(pos)) {
done.add(pos);
BlockPos.Mutable result = new BlockPos.Mutable();
result.set(ascendTree(w, log, pos, true));
PosHelper.all(pos, p -> {
if (variantAndBlockEquals(w.getBlockState(pos.east()), log)) {
ascendTrunk(done, w, pos.east(), log, level + 1).filter(a -> a.getY() > result.getY()).ifPresent(result::set);
}
}, Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH);
done.add(result.toImmutable());
return Optional.of(result.toImmutable());
}
return Optional.of(pos);
}
return pos;
}
public static Optional<BlockPos> descendTree(World w, BlockState log, BlockPos pos) {
return descendTreePart(new HashSet<BlockPos>(), w, log, new BlockPos.Mutable(pos.getX(), pos.getY(), pos.getZ()));
public static class Descender {
/**
* Recursively locates the base of the tree.
*/
public static Optional<BlockPos> descendTree(World w, BlockState log, BlockPos pos) {
return descendTreePart(new HashSet<BlockPos>(), w, log, new BlockPos.Mutable(pos.getX(), pos.getY(), pos.getZ()));
}
private static Optional<BlockPos> descendTreePart(Set<BlockPos> done, World w, BlockState log, BlockPos.Mutable pos) {
if (done.contains(pos) || !variantAndBlockEquals(w.getBlockState(pos), log)) {
return Optional.empty();
}
done.add(pos.toImmutable());
while (variantAndBlockEquals(w.getBlockState(pos.down()), log)) {
done.add(pos.move(Direction.DOWN).toImmutable());
}
PosHelper.all(pos.toImmutable(), p -> {
descendTreePart(done, w, log, new BlockPos.Mutable(p.getX(), p.getY(), p.getZ())).filter(a -> a.getY() < pos.getY()).ifPresent(pos::set);
}, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST);
done.add(pos.toImmutable());
return Optional.of(pos.toImmutable());
}
}
private static Optional<BlockPos> descendTreePart(Set<BlockPos> done, World w, BlockState log, BlockPos.Mutable pos) {
if (done.contains(pos) || !variantAndBlockEquals(w.getBlockState(pos), log)) {
return Optional.empty();
public static class Measurer {
/**
* Counts the number of logs and leaves present in the targeted tree.
*/
public static int measureTree(World w, BlockState log, BlockPos pos) {
Set<BlockPos> logs = new HashSet<>();
Set<BlockPos> leaves = new HashSet<>();
countParts(logs, leaves, w, log, pos);
return logs.size() <= (leaves.size() / 2) ? logs.size() + leaves.size() : 0;
}
done.add(pos.toImmutable());
while (variantAndBlockEquals(w.getBlockState(pos.down()), log)) {
done.add(pos.move(Direction.DOWN).toImmutable());
private static void countParts(Set<BlockPos> logs, Set<BlockPos> leaves, World w, BlockState log, BlockPos pos) {
if (logs.contains(pos) || leaves.contains(pos)) {
return;
}
BlockState state = w.getBlockState(pos);
boolean yay = false;
if (isLeaves(state, log) && !state.get(LeavesBlock.PERSISTENT)) {
leaves.add(pos);
yay = true;
} else if (variantAndBlockEquals(state, log)) {
logs.add(pos);
yay = true;
}
if (yay) {
PosHelper.all(pos, p -> {
countParts(logs, leaves, w, log, p);
}, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST);
}
}
PosHelper.all(pos.toImmutable(), p -> {
descendTreePart(done, w, log, new BlockPos.Mutable(p.getX(), p.getY(), p.getZ())).filter(a -> a.getY() < pos.getY()).ifPresent(pos::set);
}, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST);
done.add(pos.toImmutable());
return Optional.of(pos.toImmutable());
}
public static int measureTree(World w, BlockState log, BlockPos pos) {
Set<BlockPos> logs = new HashSet<>();
Set<BlockPos> leaves = new HashSet<>();
countParts(logs, leaves, w, log, pos);
return logs.size() <= (leaves.size() / 2) ? logs.size() + leaves.size() : 0;
}
private static void countParts(Set<BlockPos> logs, Set<BlockPos> leaves, World w, BlockState log, BlockPos pos) {
if (logs.contains(pos) || leaves.contains(pos)) {
return;
}
BlockState state = w.getBlockState(pos);
boolean yay = false;
if (isLeaves(state, log) && !state.get(LeavesBlock.PERSISTENT)) {
leaves.add(pos);
yay = true;
} else if (variantAndBlockEquals(state, log)) {
logs.add(pos);
yay = true;
}
if (yay) {
PosHelper.all(pos, p -> {
countParts(logs, leaves, w, log, p);
}, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST);
private static void breakBlock(World w, BlockPos pos, boolean destroy) {
if (destroy) {
w.breakBlock(pos, true);
} else {
Block.dropStacks(w.getBlockState(pos), w, pos);
w.setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
}
}

View file

@ -81,8 +81,8 @@ public class EarthPonyStompAbility implements Ability<Multi> {
BlockState state = player.getWorld().getBlockState(pos);
if (state.getBlock().isIn(BlockTags.LOGS)) {
pos = TreeTraverser.descendTree(player.getWorld(), state, pos).get();
if (TreeTraverser.measureTree(player.getWorld(), state, pos) > 0) {
pos = TreeTraverser.Descender.descendTree(player.getWorld(), state, pos).get();
if (TreeTraverser.Measurer.measureTree(player.getWorld(), state, pos) > 0) {
return new Multi(pos, 1);
}
}
@ -164,7 +164,7 @@ public class EarthPonyStompAbility implements Ability<Multi> {
if (harmed || player.world.random.nextInt(5) == 0) {
if (!harmed || player.world.random.nextInt(30) == 0) {
TreeTraverser.removeTree(player.world, data.pos());
TreeTraverser.Remover.removeTree(player.world, data.pos());
}
iplayer.subtractEnergyCost(3);
@ -223,7 +223,7 @@ public class EarthPonyStompAbility implements Ability<Multi> {
private int dropApples(World w, BlockPos pos) {
BlockState log = w.getBlockState(pos);
int size = TreeTraverser.measureTree(w, log, pos);
int size = TreeTraverser.Measurer.measureTree(w, log, pos);
if (size > 0) {
List<ItemEntity> capturedDrops = Lists.newArrayList();
@ -244,7 +244,7 @@ public class EarthPonyStompAbility implements Ability<Multi> {
private static void dropApplesPart(List<ItemEntity> drops, List<BlockPos> done, World w, BlockState log, BlockPos pos, int level) {
if (!done.contains(pos)) {
done.add(pos);
pos = TreeTraverser.ascendTree(w, log, pos, false);
pos = TreeTraverser.Ascender.ascendTree(w, log, pos, false);
if (level < 10 && TreeTraverser.isWoodOrLeaf(w, log, pos)) {
BlockState state = w.getBlockState(pos);

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.util;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.function.Consumer;
@ -39,7 +38,7 @@ public interface PosHelper {
}
}
static boolean some(BlockPos origin, Predicate<BlockPos> consumer, Direction... directions) {
static boolean any(BlockPos origin, Predicate<BlockPos> consumer, Direction... directions) {
for (Direction facing : directions) {
if (consumer.test(origin.offset(facing))) {
return true;
@ -49,17 +48,15 @@ public interface PosHelper {
}
static Stream<BlockPos> adjacentNeighbours(BlockPos origin) {
BlockPos.Mutable pos = new BlockPos.Mutable(origin.getX(), origin.getY(), origin.getZ());
List<Direction> directions = Lists.newArrayList(Direction.values());
Iterator<Direction> iter = directions.iterator();
return StreamSupport.stream(new AbstractSpliterator<BlockPos>(directions.size(), Spliterator.SIZED) {
return StreamSupport.stream(new AbstractSpliterator<BlockPos>(Direction.values().length, Spliterator.SIZED) {
private final BlockPos.Mutable pos = new BlockPos.Mutable();
private final Iterator<Direction> iter = Lists.newArrayList(Direction.values()).iterator();
@Override
public boolean tryAdvance(Consumer<? super BlockPos> consumer) {
if (iter.hasNext()) {
Direction next = iter.next();
pos.set(origin.getX() + next.getOffsetX(), origin.getY() + next.getOffsetY(), origin.getZ() + next.getOffsetZ());
consumer.accept(pos);
consumer.accept(pos.set(origin.getX() + next.getOffsetX(), origin.getY() + next.getOffsetY(), origin.getZ() + next.getOffsetZ()));
return true;
}
return false;

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.util;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
@ -15,82 +14,83 @@ import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RayTraceContext;
public class RayTraceHelper {
public static <T extends Entity> Optional<T> findEntity(Entity e, double distance) {
return doTrace(e, distance, 1).getEntity();
}
public static <T extends Entity> Optional<T> findEntity(Entity e, double distance, float partialTick, Predicate<Entity> predicate) {
return doTrace(e, distance, partialTick, EntityPredicates.EXCEPT_SPECTATOR.and(predicate)).getEntity();
}
public static Trace doTrace(Entity e, double distance, float partialTick) {
return doTrace(e, distance, partialTick, EntityPredicates.EXCEPT_SPECTATOR);
public static <T extends Entity> Optional<T> findEntity(Entity e, double distance, float tickDelta, Predicate<Entity> predicate) {
return doTrace(e, distance, tickDelta, EntityPredicates.EXCEPT_SPECTATOR.and(predicate)).getEntity();
}
/**
* Performs a ray trace from the given entity and returns a result for the first Entity that passing the given predicate or block that the ray intercepts.
* <p>
* Performs a ray trace from the given entity and returns
* a result for the first Entity or block that the ray intercepts.
*
*
* @param e Entity to start from
* @param distance Maximum distance
* @param partialTick Client partial ticks
* @param predicate Predicate test to filter entities
* @param e Entity to start from
* @param distance Maximum distance
* @param tickDelta Client partial ticks
*
* @return A OptionalHit describing what was found.
* @return A Trace describing what was found.
*/
public static Trace doTrace(Entity e, double distance, float partialTick, Predicate<Entity> predicate) {
HitResult tracedBlock = traceBlocks(e, distance, partialTick, false);
public static Trace doTrace(Entity e, double distance, float tickDelta) {
return doTrace(e, distance, tickDelta, EntityPredicates.EXCEPT_SPECTATOR);
}
double totalTraceDistance = distance;
/**
* Performs a ray trace from the given entity and returns
* a result for the first Entity that passes the given predicate
* or block that the ray intercepts.
*
*
* @param e Entity to start from
* @param distance Maximum distance
* @param tickDelta Client partial ticks
* @param predicate Predicate test to filter entities
*
* @return A Trace describing what was found.
*/
public static Trace doTrace(Entity e, double distance, float tickDelta, Predicate<Entity> predicate) {
HitResult tracedBlock = e.rayTrace(distance, tickDelta, false);
Vec3d pos = e.getCameraPosVec(partialTick);
final Vec3d start = e.getCameraPosVec(tickDelta);
if (tracedBlock != null) {
totalTraceDistance = tracedBlock.getPos().distanceTo(pos);
}
final double totalTraceDistance = tracedBlock == null ? distance : tracedBlock.getPos().distanceTo(start);
Vec3d look = e.getRotationVec(partialTick);
Vec3d ray = pos.add(look.multiply(distance));
final Vec3d ray = e.getRotationVec(tickDelta).multiply(distance);
final Vec3d end = start.add(ray);
Vec3d hit = null;
Entity pointedEntity = null;
List<Entity> entitiesWithinRange = e.world.getOtherEntities(e, e.getBoundingBox()
.expand(look.x * distance, look.y * distance, look.z * distance)
.expand(1, 1, 1), predicate);
double traceDistance = totalTraceDistance;
for (Entity entity : entitiesWithinRange) {
if (entity.collides()) {
Box entityAABB = entity.getBoundingBox().expand(entity.getTargetingMargin());
for (Entity entity : e.world.getOtherEntities(e,
e.getBoundingBox().expand(ray.x + 1, ray.y + 1, ray.z + 1),
predicate.and(Entity::collides)
)) {
Box entityAABB = entity.getBoundingBox().expand(entity.getTargetingMargin());
Optional<Vec3d> intercept = entityAABB.rayTrace(pos, ray);
Optional<Vec3d> intercept = entityAABB.rayTrace(start, end);
if (entityAABB.contains(pos)) {
if (traceDistance <= 0) {
pointedEntity = entity;
hit = intercept.orElse(null);
traceDistance = 0;
}
} else if (intercept.isPresent()) {
Vec3d inter = intercept.get();
double distanceToHit = pos.distanceTo(inter);
if (entityAABB.contains(start)) {
if (traceDistance <= 0) {
pointedEntity = entity;
hit = intercept.orElse(null);
traceDistance = 0;
}
} else if (intercept.isPresent()) {
Vec3d inter = intercept.get();
double distanceToHit = start.distanceTo(inter);
if (distanceToHit < traceDistance || traceDistance == 0) {
if (entity.getRootVehicle() == e.getRootVehicle()) {
if (traceDistance == 0) {
pointedEntity = entity;
hit = inter;
}
} else {
if (distanceToHit < traceDistance || traceDistance == 0) {
if (entity.getRootVehicle() == e.getRootVehicle()) {
if (traceDistance == 0) {
pointedEntity = entity;
hit = inter;
traceDistance = distanceToHit;
}
} else {
pointedEntity = entity;
hit = inter;
traceDistance = distanceToHit;
}
}
}
@ -103,20 +103,6 @@ public class RayTraceHelper {
return new Trace(tracedBlock);
}
/**
* Server-available version of Entity.rayTrace
*/
public static HitResult traceBlocks(Entity e, double maxDistance, float tickDelta, boolean includeFluids) {
Vec3d start = e.getCameraPosVec(tickDelta);
Vec3d end = e.getRotationVec(tickDelta).multiply(maxDistance).add(start);
return e.world.rayTrace(new RayTraceContext(start, end,
RayTraceContext.ShapeType.OUTLINE,
includeFluids ? RayTraceContext.FluidHandling.ANY : RayTraceContext.FluidHandling.NONE,
e)
);
}
public static class Trace {
@Nullable
private final HitResult result;