package eiteam.esteemedinnovation.commons.util;
import com.google.common.base.Predicate;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.state.pattern.BlockMatcher;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.WorldGenMinable;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* A new and improved version of Vanilla's WorldGenMinable.
*
* This version has better performance, by not checking the same block position and re-setting it over and over again.
* Its actual generation speed should be pretty much the same as the vanilla one in most cases, but this one uses
* a bit less memory by using less world calls and not creating a new BlockPos for every iteration.
*
* It also provides a superior API, {@link WorldGenMinableBase#canGenerateInPosition(BlockPos, IBlockAccess)} which
* allows for proper position-sensitive checking. Be sure to remember that caves are generated after ores, though.
*
* Its constructors are the same, and unfortunately Google's predicate still has to be used :(
*/
public class WorldGenMinableBase extends WorldGenMinable {
protected final int blockCount;
protected final IBlockState oreState;
protected final Predicate<IBlockState> predicate;
public WorldGenMinableBase(IBlockState state, int blockCount) {
this(state, blockCount, BlockMatcher.forBlock(Blocks.STONE));
}
public WorldGenMinableBase(IBlockState state, int blockCount, Predicate<IBlockState> predicate) {
super(state, blockCount, predicate);
this.blockCount = blockCount;
oreState = state;
this.predicate = predicate;
}
@Override
public boolean generate(World world, Random rand, BlockPos position) {
float f = rand.nextFloat() * (float) Math.PI;
double x1 = ((position.getX() + 8) + MathHelper.sin(f) * blockCount / 8.0F);
double x2 = ((position.getX() + 8) - MathHelper.sin(f) * blockCount / 8.0F);
double z1 = ((position.getZ() + 8) + MathHelper.cos(f) * blockCount / 8.0F);
double z2 = ((position.getZ() + 8) - MathHelper.cos(f) * blockCount / 8.0F);
double y1 = (position.getY() + rand.nextInt(3) - 2);
double y2 = (position.getY() + rand.nextInt(3) - 2);
Set<BlockPos> validBlockPositions = new HashSet<>(blockCount);
for (int i = 0; i < blockCount; ++i) {
float f1 = (float) i / blockCount;
double x3 = x1 + (x2 - x1) * f1;
double y3 = y1 + (y2 - y1) * f1;
double z3 = z1 + (z2 - z1) * f1;
double d9 = rand.nextDouble() * blockCount / 16.0D;
double d10 = (MathHelper.sin((float) Math.PI * f1) + 1.0F) * d9 + 1.0D;
int minX = MathHelper.floor_double(x3 - d10 / 2.0D);
int minY = MathHelper.floor_double(y3 - d10 / 2.0D);
int minZ = MathHelper.floor_double(z3 - d10 / 2.0D);
int maxX = MathHelper.floor_double(x3 + d10 / 2.0D);
int maxY = MathHelper.floor_double(y3 + d10 / 2.0D);
int maxZ = MathHelper.floor_double(z3 + d10 / 2.0D);
BlockPos.MutableBlockPos posToReplace = new BlockPos.MutableBlockPos();
for (int xBlock = minX; xBlock <= maxX; ++xBlock) {
double xCheck = (xBlock + 0.5D - x3) / (d10 / 2.0D);
if (xCheck * xCheck < 1.0D) {
for (int yBlock = minY; yBlock <= maxY; ++yBlock) {
double yCheck = (yBlock + 0.5D - y3) / (d10 / 2.0D);
if (xCheck * xCheck + yCheck * yCheck < 1.0D) {
for (int zBlock = minZ; zBlock <= maxZ; ++zBlock) {
posToReplace.setPos(xBlock, yBlock, zBlock);
if (!validBlockPositions.contains(posToReplace)) {
double zCheck = (zBlock + 0.5D - z3) / (d10 / 2.0D);
if (xCheck * xCheck + yCheck * yCheck + zCheck * zCheck < 1.0D) {
validBlockPositions.add(posToReplace.toImmutable());
}
}
}
}
}
}
}
}
validBlockPositions.stream()
.filter(pos -> canGenerateInPosition(pos, world))
.forEach(pos -> world.setBlockState(pos, oreState));
return true;
}
/**
* Only override this one if you are not calling the super method and are not getting the block state. If you are
* calling the super method and obtaining the block state, use
* {@link #canGenerateInPosition(BlockPos, IBlockState, IBlockAccess)}, as it already has obtained the block state
* in this position.
* @param position The position that is attempted to be generated in
* @param world The current world
* @return Whether this position is valid for the block to generate in.
*/
protected boolean canGenerateInPosition(BlockPos position, IBlockAccess world) {
return canGenerateInPosition(position, world.getBlockState(position), world);
}
/**
* Overload for {@link #canGenerateInPosition(BlockPos, IBlockAccess)} that already has obtained the block state.
* This is called in the other canGenerateInPosition. Use this when you want a state-specific check and are
* calling the super method.
* @param position The position that is going to be generated in.
* @param positionState The block state at this position.
* @param world The world
* @return Whether this position is valid for the block to generate in.
*/
protected boolean canGenerateInPosition(BlockPos position, IBlockState positionState, IBlockAccess world) {
return positionState.getBlock().isReplaceableOreGen(positionState, world, position, predicate);
}
}