-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
eafac1c
commit 64c6d5e
Showing
2 changed files
with
356 additions
and
0 deletions.
There are no files selected for viewing
288 changes: 288 additions & 0 deletions
288
src/main/java/thebetweenlands/common/world/gen/feature/FeatureHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,288 @@ | ||
package thebetweenlands.common.world.gen.feature; | ||
|
||
import com.mojang.serialization.Codec; | ||
import net.minecraft.core.BlockPos; | ||
import net.minecraft.world.level.WorldGenLevel; | ||
import net.minecraft.world.level.block.state.BlockState; | ||
import net.minecraft.world.level.levelgen.feature.Feature; | ||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; | ||
import net.minecraft.world.level.material.Fluids; | ||
import net.minecraft.world.phys.AABB; | ||
|
||
import javax.annotation.Nullable; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.function.Consumer; | ||
import java.util.function.Predicate; | ||
|
||
public abstract class FeatureHelper<FHC extends FeatureHelperConfiguration> extends Feature<FHC> { | ||
// Set in configuration | ||
public boolean doBlockNotify; | ||
|
||
/** | ||
* Enums to get the metadata of a stair with when a structure is rotated | ||
*/ | ||
public enum EnumRotationSequence { | ||
//TODO: This ought to be removed and replaced with the proper block states at some point | ||
//E.g. enum.getRotatedBlockState(IProperty propertyThatContainsTheRotation, IBlockState theBlockStateToRotate) | ||
|
||
STAIR(0, 3, 1, 2), | ||
UPSIDE_DOWN_STAIR(4, 7, 5, 6), | ||
CHEST(3, 5, 2, 4), | ||
LOG_SIDEWAYS(4, 8), | ||
PILLAR_SIDEWAYS(8, 7); | ||
|
||
private int[] sequence; | ||
|
||
EnumRotationSequence(int... sequence) { | ||
this.sequence = sequence; | ||
} | ||
} | ||
|
||
protected int width; | ||
protected int height; | ||
protected int depth; | ||
|
||
public BlockPos.MutableBlockPos checkPos = new BlockPos.MutableBlockPos(); | ||
|
||
public BlockPos.MutableBlockPos getCheckPos(int x, int y, int z) { | ||
this.checkPos.set(x, y, z); | ||
return this.checkPos; | ||
} | ||
|
||
public FeatureHelper(Codec<FHC> p_65786_) { | ||
super(p_65786_); | ||
} | ||
|
||
/** | ||
* @param world | ||
* @param x | ||
* @param y | ||
* @param z | ||
* @param offsetX | ||
* @param offsetY | ||
* @param offsetZ | ||
* @param blockState | ||
* @param sizeWidth | ||
* @param sizeHeight | ||
* @param sizeDepth | ||
* @param rotation | ||
* @param callbacks | ||
*/ | ||
@SafeVarargs | ||
public final void rotatedCubeVolume(WorldGenLevel world, int x, int y, int z, int offsetX, int offsetY, int offsetZ, BlockState blockState, int sizeWidth, int sizeHeight, int sizeDepth, int rotation, Consumer<BlockPos>... callbacks) { | ||
this.rotatedCubeVolume(world, null, x, y, z, offsetX, offsetY, offsetZ, blockState, sizeWidth, sizeHeight, sizeDepth, rotation, callbacks); | ||
} | ||
|
||
/** | ||
* Generates cube volumes and rotates them depending on the given rotation | ||
* | ||
* @param world The world | ||
* @param pred The predicate decides whether a block should be placed or not | ||
* @param x x to generate relative from | ||
* @param y y to generate relative from | ||
* @param z z to generate relative from | ||
* @param offsetX Where to generate relative from the x | ||
* @param offsetY Where to generate relative from the y | ||
* @param offsetZ Where to generate relative from the z | ||
* @param blockState The block to generate | ||
* @param sizeWidth The width of the cube volume | ||
* @param sizeHeight The height of the cube volume | ||
* @param sizeDepth The depth of the cube volume | ||
* @param rotation The rotation for the cube volume (0 to 3) | ||
* @param callbacks All callbacks are called once a block is placed | ||
*/ | ||
@SafeVarargs | ||
public final void rotatedCubeVolume(WorldGenLevel world, @Nullable Predicate<BlockPos> pred, int x, int y, int z, int offsetX, int offsetY, int offsetZ, BlockState blockState, int sizeWidth, int sizeHeight, int sizeDepth, int rotation, Consumer<BlockPos>... callbacks) { | ||
x -= width / 2; | ||
z -= depth / 2; | ||
switch (rotation) { | ||
case 0: | ||
for (int yy = y + offsetY; yy < y + offsetY + sizeHeight; yy++) | ||
for (int xx = x + offsetX; xx < x + offsetX + sizeWidth; xx++) | ||
for (int zz = z + offsetZ; zz < z + offsetZ + sizeDepth; zz++) { | ||
BlockPos pos = new BlockPos(xx, yy, zz); | ||
if(pred == null || pred.test(pos)) { | ||
this.setBlockAndNotifyAdequately(world, pos, blockState); | ||
for(Consumer<BlockPos> callback : callbacks) { | ||
callback.accept(pos); | ||
} | ||
} | ||
} | ||
break; | ||
case 1: | ||
for (int yy = y + offsetY; yy < y + offsetY + sizeHeight; yy++) | ||
for (int zz = z + depth - offsetX - 1; zz > z + depth - offsetX - sizeWidth - 1; zz--) | ||
for (int xx = x + offsetZ; xx < x + offsetZ + sizeDepth; xx++) { | ||
BlockPos pos = new BlockPos(xx, yy, zz); | ||
if(pred == null || pred.test(pos)) { | ||
this.setBlockAndNotifyAdequately(world, pos, blockState); | ||
for(Consumer<BlockPos> callback : callbacks) { | ||
callback.accept(pos); | ||
} | ||
} | ||
} | ||
break; | ||
case 2: | ||
for (int yy = y + offsetY; yy < y + offsetY + sizeHeight; yy++) | ||
for (int xx = x + width - offsetX - 1; xx > x + width - offsetX - sizeWidth - 1; xx--) | ||
for (int zz = z + depth - offsetZ - 1; zz > z + depth - offsetZ - sizeDepth - 1; zz--) { | ||
BlockPos pos = new BlockPos(xx, yy, zz); | ||
if(pred == null || pred.test(pos)) { | ||
this.setBlockAndNotifyAdequately(world, pos, blockState); | ||
for(Consumer<BlockPos> callback : callbacks) { | ||
callback.accept(pos); | ||
} | ||
} | ||
} | ||
break; | ||
case 3: | ||
for (int yy = y + offsetY; yy < y + offsetY + sizeHeight; yy++) | ||
for (int zz = z + offsetX; zz < z + offsetX + sizeWidth; zz++) | ||
for (int xx = x + width - offsetZ - 1; xx > x + width - offsetZ - sizeDepth - 1; xx--) { | ||
BlockPos pos = new BlockPos(xx, yy, zz); | ||
if(pred == null || pred.test(pos)) { | ||
this.setBlockAndNotifyAdequately(world, pos, blockState); | ||
for(Consumer<BlockPos> callback : callbacks) { | ||
callback.accept(pos); | ||
} | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
|
||
/** | ||
* Returns a rotated AABB | ||
* @param world | ||
* @param x | ||
* @param y | ||
* @param z | ||
* @param offsetX | ||
* @param offsetY | ||
* @param offsetZ | ||
* @param sizeWidth | ||
* @param sizeHeight | ||
* @param sizeDepth | ||
* @param rotation | ||
* @return | ||
*/ | ||
public final AABB rotatedAABB(WorldGenLevel world, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double sizeWidth, double sizeHeight, double sizeDepth, int rotation) { | ||
x -= width / 2; | ||
z -= depth / 2; | ||
switch (rotation) { | ||
default: | ||
case 0: | ||
return new AABB( | ||
x + offsetX, y + offsetY, z + offsetZ, | ||
x + offsetX + sizeWidth, y + offsetY + sizeHeight, z + offsetZ + sizeDepth | ||
); | ||
case 1: | ||
return new AABB( | ||
x + offsetZ, y + offsetY, z + depth - offsetX - sizeWidth - 1, | ||
x + offsetZ + sizeDepth, y + offsetY + sizeHeight, z + depth - offsetX - 1 | ||
); | ||
case 2: | ||
return new AABB( | ||
x + width - offsetX - sizeWidth - 1, y + offsetY, z + depth - offsetZ - sizeDepth - 1, | ||
x + width - offsetX - 1, y + offsetY + sizeHeight, z + depth - offsetZ - 1 | ||
); | ||
case 3: | ||
return new AABB( | ||
x + width - offsetZ - sizeDepth - 1, y + offsetY, z + offsetX, | ||
x + width - offsetZ - 1, y + offsetY + sizeHeight, z + offsetX + sizeWidth | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* @param world | ||
* @param x | ||
* @param y | ||
* @param z | ||
* @param offsetA | ||
* @param offsetB | ||
* @param offsetC | ||
* @param sizeWidth | ||
* @param sizeHeight | ||
* @param sizeDepth | ||
* @param direction | ||
* @return | ||
*/ | ||
public boolean rotatedCubeCantReplace(WorldGenLevel world, FeaturePlaceContext<FeatureHelperConfiguration> context, int x, int y, int z, int offsetA, int offsetB, int offsetC, int sizeWidth, int sizeHeight, int sizeDepth, int direction) { | ||
x -= width / 2; | ||
z -= depth / 2; | ||
switch (direction) { | ||
case 0 -> { | ||
for (int yy = y + offsetB; yy < y + offsetB + sizeHeight; yy++) { | ||
for (int xx = x + offsetA; xx < x + offsetA + sizeWidth; xx++) { | ||
for (int zz = z + offsetC; zz < z + offsetC + sizeDepth; zz++) { | ||
if (!world.ensureCanWrite(this.getCheckPos(xx, yy, zz)) || !isReplaceable(world, context, xx, yy, zz, 0, 0, 0, 0)) | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
case 1 -> { | ||
for (int yy = y + offsetB; yy < y + offsetB + sizeHeight; yy++) | ||
for (int zz = z + depth - offsetA - 1; zz > z + depth - offsetA - sizeWidth - 1; zz--) | ||
for (int xx = x + offsetC; xx < x + offsetC + sizeDepth; xx++) { | ||
if (!world.ensureCanWrite(this.getCheckPos(xx, yy, zz)) || !isReplaceable(world, context, xx, yy, zz, 0, 0, 0, 0)) | ||
return true; | ||
} | ||
} | ||
case 2 -> { | ||
for (int yy = y + offsetB; yy < y + offsetB + sizeHeight; yy++) | ||
for (int xx = x + width - offsetA - 1; xx > x + width - offsetA - sizeWidth - 1; xx--) | ||
for (int zz = z + depth - offsetC - 1; zz > z + depth - offsetC - sizeDepth - 1; zz--) { | ||
if (!world.ensureCanWrite(this.getCheckPos(xx, yy, zz)) || !isReplaceable(world, context, xx, yy, zz, 0, 0, 0, 0)) | ||
return true; | ||
} | ||
} | ||
case 3 -> { | ||
for (int yy = y + offsetB; yy < y + offsetB + sizeHeight; yy++) | ||
for (int zz = z + offsetA; zz < z + offsetA + sizeWidth; zz++) | ||
for (int xx = x + width - offsetC - 1; xx > x + width - offsetC - sizeDepth - 1; xx--) { | ||
if (!world.ensureCanWrite(this.getCheckPos(xx, yy, zz)) || !isReplaceable(world, context, xx, yy, zz, 0, 0, 0, 0)) | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
protected void setBlockAndNotifyAdequately(WorldGenLevel worldIn, BlockPos pos, BlockState state) { | ||
if (this.doBlockNotify) { | ||
worldIn.setBlock(pos, state, 3 | 16); | ||
} else { | ||
worldIn.setBlock(pos, state, 2 | 16); | ||
} | ||
} | ||
|
||
// Stand alone isReplaceable check | ||
public boolean isReplaceable(FeaturePlaceContext<FeatureHelperConfiguration> context, BlockState in) { | ||
return context.config().replaceable.stream().anyMatch(predicate -> predicate.target.test(in, context.random())); | ||
} | ||
|
||
public boolean isReplaceable(WorldGenLevel world, FeaturePlaceContext<FeatureHelperConfiguration> context, int x, int y, int z, int offsetX, int offsetY, int offsetZ, int rotation) { | ||
x -= width / 2; | ||
z -= depth / 2; | ||
BlockPos pos; | ||
switch (rotation) { | ||
case 0: | ||
pos = this.getCheckPos(x + offsetX, y + offsetY, z + offsetZ); | ||
return world.ensureCanWrite(pos) && (world.getBlockState(pos).canBeReplaced(Fluids.EMPTY) || (context.config().replaceable != null && isReplaceable(context, world.getBlockState(pos)))); | ||
case 1: | ||
pos = this.getCheckPos(x + offsetZ, y + offsetY, z + depth - offsetX - 1); | ||
return world.ensureCanWrite(pos) && (world.getBlockState(pos).canBeReplaced(Fluids.EMPTY) || (context.config().replaceable != null && isReplaceable(context, world.getBlockState(pos)))); | ||
case 2: | ||
pos = this.getCheckPos(x + width - offsetX - 1, y + offsetY, z + depth - offsetZ - 1); | ||
return world.ensureCanWrite(pos) && (world.getBlockState(pos).canBeReplaced(Fluids.EMPTY) || (context.config().replaceable != null && isReplaceable(context, world.getBlockState(pos)))); | ||
case 3: | ||
pos = this.getCheckPos(x + width - offsetZ - 1, y + offsetY, z + offsetX); | ||
return world.ensureCanWrite(pos) && (world.getBlockState(pos).canBeReplaced(Fluids.EMPTY) || (context.config().replaceable != null && isReplaceable(context, world.getBlockState(pos)))); | ||
} | ||
return false; | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/main/java/thebetweenlands/common/world/gen/feature/FeatureHelperConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package thebetweenlands.common.world.gen.feature; | ||
|
||
import com.mojang.serialization.Codec; | ||
import com.mojang.serialization.codecs.RecordCodecBuilder; | ||
import net.minecraft.world.level.block.state.BlockState; | ||
import net.minecraft.world.level.block.state.predicate.BlockStatePredicate; | ||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; | ||
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockMatchTest; | ||
import net.minecraft.world.level.levelgen.structure.templatesystem.RuleTest; | ||
import thebetweenlands.common.features.SapTreeConfig; | ||
import thebetweenlands.common.registries.BlockRegistry; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.function.Predicate; | ||
|
||
public class FeatureHelperConfiguration implements FeatureConfiguration { | ||
public static FeatureHelperConfiguration NONE = new FeatureHelperConfiguration(List.of()); | ||
public static List<TargetBlockState> SURFACE = List.of( | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.SWAMP_DIRT.get()), BlockRegistry.SWAMP_DIRT.get().defaultBlockState()), | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.SWAMP_GRASS.get()), BlockRegistry.SWAMP_GRASS.get().defaultBlockState()), | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.DEAD_SWAMP_GRASS.get()), BlockRegistry.DEAD_SWAMP_GRASS.get().defaultBlockState()), | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.MUD.get()), BlockRegistry.MUD.get().defaultBlockState()) | ||
); | ||
public static List<TargetBlockState> LEAVES = List.of( | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.LEAVES_NIBBLETWIG_TREE.get()), BlockRegistry.LEAVES_NIBBLETWIG_TREE.get().defaultBlockState()), | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.LEAVES_RUBBER_TREE.get()), BlockRegistry.LEAVES_RUBBER_TREE.get().defaultBlockState()), | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.LEAVES_WEEDWOOD_TREE.get()), BlockRegistry.LEAVES_WEEDWOOD_TREE.get().defaultBlockState()), | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.LEAVES_SAP_TREE.get()), BlockRegistry.LEAVES_SAP_TREE.get().defaultBlockState()) | ||
); | ||
public static List<TargetBlockState> CAVERNS = List.of( | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.BETWEENSTONE.get()), BlockRegistry.BETWEENSTONE.get().defaultBlockState()) | ||
); | ||
public static List<TargetBlockState> PITSTONE = List.of( | ||
new TargetBlockState(new BlockMatchTest(BlockRegistry.PITSTONE.get()), BlockRegistry.PITSTONE.get().defaultBlockState()) | ||
); | ||
|
||
// Replaceable blocks list | ||
public List<TargetBlockState> replaceable; | ||
|
||
public static final Codec<FeatureHelperConfiguration> CODEC = RecordCodecBuilder.create((p_67849_) -> { | ||
return p_67849_.group(Codec.list(FeatureHelperConfiguration.TargetBlockState.CODEC).fieldOf("replaceable").forGetter((p_161027_) -> { | ||
return p_161027_.replaceable; | ||
})).apply(p_67849_, FeatureHelperConfiguration::new); | ||
}); | ||
|
||
public FeatureHelperConfiguration(List<TargetBlockState> replaceable) { | ||
this.replaceable = replaceable; | ||
} | ||
|
||
// Target helper | ||
public static class TargetBlockState { | ||
public static final Codec<FeatureHelperConfiguration.TargetBlockState> CODEC = RecordCodecBuilder.create((p_161039_) -> { | ||
return p_161039_.group(RuleTest.CODEC.fieldOf("target").forGetter((p_161043_) -> { | ||
return p_161043_.target; | ||
}), BlockState.CODEC.fieldOf("state").forGetter((p_161041_) -> { | ||
return p_161041_.state; | ||
})).apply(p_161039_, FeatureHelperConfiguration.TargetBlockState::new); | ||
}); | ||
public final RuleTest target; | ||
public final BlockState state; | ||
|
||
public TargetBlockState(RuleTest p_161036_, BlockState p_161037_) { | ||
this.target = p_161036_; | ||
this.state = p_161037_; | ||
} | ||
} | ||
} |