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,33 +16,49 @@ import net.minecraft.world.World;
public class TreeTraverser { public class TreeTraverser {
public static class Remover {
/**
* Removes the tree located at the given position.
*/
public static void removeTree(World w, BlockPos pos) { public static void removeTree(World w, BlockPos pos) {
BlockState log = w.getBlockState(pos); BlockState log = w.getBlockState(pos);
int size = measureTree(w, log, pos); if (Measurer.measureTree(w, log, pos) > 0) {
removeTreePart(w, log, Ascender.ascendTrunk(new HashSet<BlockPos>(), w, pos, log, 0).get(), 0);
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) { private static void removeTreePart(World w, BlockState log, BlockPos pos, int level) {
if (level < 10 && isWoodOrLeaf(w, log, pos)) { if (level < 10 && isWoodOrLeaf(w, log, pos)) {
if (level < 5) { breakBlock(w, pos, level < 5);
w.breakBlock(pos, true);
} else {
Block.dropStacks(w.getBlockState(pos), w, pos);
w.setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
}
PosHelper.all(pos, p -> { PosHelper.all(pos, p -> {
removeTreePart(w, log, p, level + 1); removeTreePart(w, log, p, level + 1);
}, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); }, 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) { 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;
}
if (remove) {
breakBlock(w, pos, breaks++ < 10);
}
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)) { if (level < 3 && !done.contains(pos)) {
done.add(pos); done.add(pos);
@ -60,30 +76,12 @@ public class TreeTraverser {
} }
return Optional.of(pos); 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);
}
breaks++;
}
pos = pos.up();
}
return pos;
} }
public static class Descender {
/**
* Recursively locates the base of the tree.
*/
public static Optional<BlockPos> descendTree(World w, BlockState log, BlockPos 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())); return descendTreePart(new HashSet<BlockPos>(), w, log, new BlockPos.Mutable(pos.getX(), pos.getY(), pos.getZ()));
} }
@ -105,7 +103,12 @@ public class TreeTraverser {
done.add(pos.toImmutable()); done.add(pos.toImmutable());
return Optional.of(pos.toImmutable()); return Optional.of(pos.toImmutable());
} }
}
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) { public static int measureTree(World w, BlockState log, BlockPos pos) {
Set<BlockPos> logs = new HashSet<>(); Set<BlockPos> logs = new HashSet<>();
Set<BlockPos> leaves = new HashSet<>(); Set<BlockPos> leaves = new HashSet<>();
@ -137,6 +140,16 @@ public class TreeTraverser {
}, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); }, 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);
}
}
public static boolean isWoodOrLeaf(World w, BlockState log, BlockPos pos) { public static boolean isWoodOrLeaf(World w, BlockState log, BlockPos pos) {
BlockState state = w.getBlockState(pos); BlockState state = w.getBlockState(pos);

View file

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

View file

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

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.util; package com.minelittlepony.unicopia.util;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -15,62 +14,64 @@ import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box; import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RayTraceContext;
public class RayTraceHelper { public class RayTraceHelper {
public static <T extends Entity> Optional<T> findEntity(Entity e, double distance) { public static <T extends Entity> Optional<T> findEntity(Entity e, double distance, float tickDelta, Predicate<Entity> predicate) {
return doTrace(e, distance, 1).getEntity(); return doTrace(e, distance, tickDelta, EntityPredicates.EXCEPT_SPECTATOR.and(predicate)).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);
} }
/** /**
* 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. * Performs a ray trace from the given entity and returns
* <p> * a result for the first Entity or block that the ray intercepts.
* *
* *
* @param e Entity to start from * @param e Entity to start from
* @param distance Maximum distance * @param distance Maximum distance
* @param partialTick Client partial ticks * @param tickDelta Client partial ticks
* @param predicate Predicate test to filter entities
* *
* @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) { public static Trace doTrace(Entity e, double distance, float tickDelta) {
HitResult tracedBlock = traceBlocks(e, distance, partialTick, false); return doTrace(e, distance, tickDelta, EntityPredicates.EXCEPT_SPECTATOR);
double totalTraceDistance = distance;
Vec3d pos = e.getCameraPosVec(partialTick);
if (tracedBlock != null) {
totalTraceDistance = tracedBlock.getPos().distanceTo(pos);
} }
Vec3d look = e.getRotationVec(partialTick); /**
Vec3d ray = pos.add(look.multiply(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);
final Vec3d start = e.getCameraPosVec(tickDelta);
final double totalTraceDistance = tracedBlock == null ? distance : tracedBlock.getPos().distanceTo(start);
final Vec3d ray = e.getRotationVec(tickDelta).multiply(distance);
final Vec3d end = start.add(ray);
Vec3d hit = null; Vec3d hit = null;
Entity pointedEntity = 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; double traceDistance = totalTraceDistance;
for (Entity entity : entitiesWithinRange) { for (Entity entity : e.world.getOtherEntities(e,
if (entity.collides()) { e.getBoundingBox().expand(ray.x + 1, ray.y + 1, ray.z + 1),
predicate.and(Entity::collides)
)) {
Box entityAABB = entity.getBoundingBox().expand(entity.getTargetingMargin()); 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 (entityAABB.contains(start)) {
if (traceDistance <= 0) { if (traceDistance <= 0) {
pointedEntity = entity; pointedEntity = entity;
hit = intercept.orElse(null); hit = intercept.orElse(null);
@ -78,7 +79,7 @@ public class RayTraceHelper {
} }
} else if (intercept.isPresent()) { } else if (intercept.isPresent()) {
Vec3d inter = intercept.get(); Vec3d inter = intercept.get();
double distanceToHit = pos.distanceTo(inter); double distanceToHit = start.distanceTo(inter);
if (distanceToHit < traceDistance || traceDistance == 0) { if (distanceToHit < traceDistance || traceDistance == 0) {
if (entity.getRootVehicle() == e.getRootVehicle()) { if (entity.getRootVehicle() == e.getRootVehicle()) {
@ -94,7 +95,6 @@ public class RayTraceHelper {
} }
} }
} }
}
if (pointedEntity != null && (traceDistance < totalTraceDistance || tracedBlock == null)) { if (pointedEntity != null && (traceDistance < totalTraceDistance || tracedBlock == null)) {
return new Trace(new EntityHitResult(pointedEntity, hit)); return new Trace(new EntityHitResult(pointedEntity, hit));
@ -103,20 +103,6 @@ public class RayTraceHelper {
return new Trace(tracedBlock); 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 { public static class Trace {
@Nullable @Nullable
private final HitResult result; private final HitResult result;