Tags, surface builders, biome API (WIP), processors, features

This commit is contained in:
paulevsGitch 2021-05-23 08:32:45 +03:00
parent 6b0bf593ad
commit 979e2ab92a
15 changed files with 1513 additions and 51 deletions

View file

@ -4,13 +4,18 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import ru.bclib.util.Logger;
import ru.bclib.api.BCLibTags;
import ru.bclib.api.SurfaceBuilders;
public class BCLib implements ModInitializer {
public static final String MOD_ID = "bclib";
public static final Logger LOGGER = new Logger(MOD_ID);
@Override
public void onInitialize() {}
public void onInitialize() {
SurfaceBuilders.register();
BCLibTags.init();
}
public static boolean isDevEnvironment() {
return FabricLoader.getInstance().isDevelopmentEnvironment();

View file

@ -0,0 +1,131 @@
package ru.bclib.api;
import java.util.function.Supplier;
import net.fabricmc.fabric.api.tag.TagRegistry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.Tag;
import net.minecraft.tags.Tag.Named;
import net.minecraft.tags.TagCollection;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import ru.bclib.BCLib;
import ru.bclib.util.TagHelper;
public class BCLibTags {
// Block Tags
public static final Tag.Named<Block> BOOKSHELVES = makeCommonBlockTag("bookshelves");
public static final Tag.Named<Block> GEN_TERRAIN = makeBlockTag(BCLib.MOD_ID, "gen_terrain");
public static final Tag.Named<Block> NETHER_GROUND = makeBlockTag(BCLib.MOD_ID, "nether_ground");
public static final Tag.Named<Block> END_GROUND = makeBlockTag(BCLib.MOD_ID, "end_ground");
public static final Tag.Named<Block> BLOCK_CHEST = makeCommonBlockTag("chest");
public static final Tag.Named<Block> END_STONES = makeCommonBlockTag("end_stones");
public static final Tag.Named<Block> NETHER_STONES = makeCommonBlockTag("nether_stones");
public static final Tag.Named<Block> DRAGON_IMMUNE = getMCBlockTag("dragon_immune");
// Item Tags
public static final Tag.Named<Item> ITEM_CHEST = makeCommonItemTag("chest");
public static final Tag.Named<Item> IRON_INGOTS = makeCommonItemTag("iron_ingots");
public static final Tag.Named<Item> FURNACES = makeCommonItemTag("furnaces");
public final static Tag.Named<Item> HAMMERS = makeItemTag("fabric", "hammers");
/**
* Get or create {@link Tag.Named}.
* @param containerSupplier - {@link TagCollection} {@link Supplier} tag collection;
* @param id - {@link ResourceLocation} tag id.
* @return {@link Tag.Named}.
*/
public static <T> Tag.Named<T> makeTag(Supplier<TagCollection<T>> containerSupplier, ResourceLocation id) {
Tag<T> tag = containerSupplier.get().getTag(id);
return tag == null ? TagRegistry.create(id, containerSupplier) : (Named<T>) tag;
}
/**
* Get or create {@link Block} {@link Tag.Named} with mod namespace.
* @param modID - {@link String} mod namespace (mod id);
* @param name - {@link String} tag name.
* @return {@link Block} {@link Tag.Named}.
*/
public static Tag.Named<Block> makeBlockTag(String modID, String name) {
return makeTag(BlockTags::getAllTags, new ResourceLocation(modID, name));
}
/**
* Get or create {@link Item} {@link Tag.Named} with mod namespace.
* @param modID - {@link String} mod namespace (mod id);
* @param name - {@link String} tag name.
* @return {@link Item} {@link Tag.Named}.
*/
public static Tag.Named<Item> makeItemTag(String modID, String name) {
return makeTag(ItemTags::getAllTags, new ResourceLocation(modID, name));
}
/**
* Get or create {@link Block} {@link Tag.Named}.
* @see <a href="https://fabricmc.net/wiki/tutorial:tags">Fabric Wiki (Tags)</a>
* @param name - {@link String} tag name.
* @return {@link Block} {@link Tag.Named}.
*/
public static Tag.Named<Block> makeCommonBlockTag(String name) {
return makeTag(BlockTags::getAllTags, new ResourceLocation("c", name));
}
/**
* Get or create {@link Item} {@link Tag.Named}.
* @see <a href="https://fabricmc.net/wiki/tutorial:tags">Fabric Wiki (Tags)</a>
* @param name - {@link String} tag name.
* @return {@link Item} {@link Tag.Named}.
*/
public static Tag.Named<Item> makeCommonItemTag(String name) {
return makeTag(ItemTags::getAllTags, new ResourceLocation("c", name));
}
/**
* Get or create Minecraft {@link Block} {@link Tag.Named}.
* @param name - {@link String} tag name.
* @return {@link Block} {@link Tag.Named}.
*/
public static Tag.Named<Block> getMCBlockTag(String name) {
ResourceLocation id = new ResourceLocation(name);
Tag<Block> tag = BlockTags.getAllTags().getTag(id);
return tag == null ? (Named<Block>) TagRegistry.block(id) : (Named<Block>) tag;
}
/**
* Adds {@link Block} to NETHER_GROUND and GEN_TERRAIN tags to process it properly in terrain generators and block logic.
* @param block - {@link Block}.
*/
public static void addNetherGround(Block block) {
TagHelper.addTag(NETHER_GROUND, block);
TagHelper.addTag(GEN_TERRAIN, block);
}
/**
* Adds {@link Block} to END_GROUND and GEN_TERRAIN tags to process it properly in terrain generators and block logic.
* @param block - {@link Block}.
*/
public static void addEndGround(Block block) {
TagHelper.addTag(GEN_TERRAIN, block);
TagHelper.addTag(END_GROUND, block);
}
/**
* Initializes basic tags. Should be called only in BCLib main class.
*/
public static void init() {
TagHelper.addTag(BOOKSHELVES, Blocks.BOOKSHELF);
TagHelper.addTag(GEN_TERRAIN, Blocks.END_STONE, Blocks.NETHERRACK, Blocks.SOUL_SAND, Blocks.SOUL_SOIL);
TagHelper.addTag(NETHER_GROUND, Blocks.NETHERRACK, Blocks.SOUL_SAND, Blocks.SOUL_SOIL);
TagHelper.addTag(END_GROUND, Blocks.END_STONE);
TagHelper.addTag(BLOCK_CHEST, Blocks.CHEST);
TagHelper.addTag(ITEM_CHEST, Items.CHEST);
TagHelper.addTag(IRON_INGOTS, Items.IRON_INGOT);
TagHelper.addTag(FURNACES, Blocks.FURNACE);
}
}

View file

@ -0,0 +1,20 @@
package ru.bclib.api;
import net.minecraft.core.Registry;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilder;
import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderBaseConfiguration;
public class SurfaceBuilders {
public static SurfaceBuilder<SurfaceBuilderBaseConfiguration> register(String name, SurfaceBuilder<SurfaceBuilderBaseConfiguration> builder) {
return Registry.register(Registry.SURFACE_BUILDER, name, builder);
}
public static SurfaceBuilderBaseConfiguration makeSimpleConfig(Block block) {
BlockState state = block.defaultBlockState();
return new SurfaceBuilderBaseConfiguration(state, state, state);
}
public static void register() {}
}

View file

@ -0,0 +1,26 @@
package ru.bclib.mixin.common;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagLoader;
import ru.bclib.util.TagHelper;
@Mixin(TagLoader.class)
public class TagLoaderMixin {
@Shadow
private String name;
@ModifyArg(method = "prepare", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;supplyAsync(Ljava/util/function/Supplier;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
public Supplier<Map<ResourceLocation, Tag.Builder>> be_modifyTags(Supplier<Map<ResourceLocation, Tag.Builder>> supplier, Executor executor) {
return () -> TagHelper.apply(name, supplier.get());
}
}

View file

@ -1,14 +1,15 @@
package ru.bclib.util;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import com.google.common.collect.Maps;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ClipContext.Fluid;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
@ -37,20 +38,6 @@ public class BlocksHelper {
protected static final BlockState AIR = Blocks.AIR.defaultBlockState();
protected static final BlockState WATER = Blocks.WATER.defaultBlockState();
private static final Vec3i[] OFFSETS = new Vec3i[] {
new Vec3i(-1, -1, -1), new Vec3i(-1, -1, 0), new Vec3i(-1, -1, 1),
new Vec3i(-1, 0, -1), new Vec3i(-1, 0, 0), new Vec3i(-1, 0, 1),
new Vec3i(-1, 1, -1), new Vec3i(-1, 1, 0), new Vec3i(-1, 1, 1),
new Vec3i(0, -1, -1), new Vec3i(0, -1, 0), new Vec3i(0, -1, 1),
new Vec3i(0, 0, -1), new Vec3i(0, 0, 0), new Vec3i(0, 0, 1),
new Vec3i(0, 1, -1), new Vec3i(0, 1, 0), new Vec3i(0, 1, 1),
new Vec3i(1, -1, -1), new Vec3i(1, -1, 0), new Vec3i(1, -1, 1),
new Vec3i(1, 0, -1), new Vec3i(1, 0, 0), new Vec3i(1, 0, 1),
new Vec3i(1, 1, -1), new Vec3i(1, 1, 0), new Vec3i(1, 1, 1)
};
public static void addBlockColor(Block block, int color) {
COLOR_BY_BLOCK.put(block, color);
}
@ -107,14 +94,35 @@ public class BlocksHelper {
return (int) pos.distSqr(POS);
}
/**
* Rotates {@link BlockState} horizontally. Used in block classes with {@link Direction} {@link Property} in rotate function.
* @param state - {@link BlockState} to mirror;
* @param rotation - {@link Rotation};
* @param facing - Block {@link Direction} {@link Property}.
* @return Rotated {@link BlockState}.
*/
public static BlockState rotateHorizontal(BlockState state, Rotation rotation, Property<Direction> facing) {
return state.setValue(facing, rotation.rotate(state.getValue(facing)));
}
/**
* Mirrors {@link BlockState} horizontally. Used in block classes with {@link Direction} {@link Property} in mirror function.
* @param state - {@link BlockState} to mirror;
* @param mirror - {@link Mirror};
* @param facing - Block {@link Direction} {@link Property}.
* @return Mirrored {@link BlockState}.
*/
public static BlockState mirrorHorizontal(BlockState state, Mirror mirror, Property<Direction> facing) {
return state.rotate(mirror.getRotation(state.getValue(facing)));
}
/**
* Counts the amount of same block down.
* @param world - {@link LevelAccessor} world;
* @param pos - {@link BlockPos} start position;
* @param block - {@link Block} to count.
* @return Integer amount of blocks.
*/
public static int getLengthDown(LevelAccessor world, BlockPos pos, Block block) {
int count = 1;
while (world.getBlockState(pos.below(count)).getBlock() == block) {
@ -123,49 +131,59 @@ public class BlocksHelper {
return count;
}
public static void cover(LevelAccessor world, BlockPos center, Block ground, BlockState cover, int radius, Random random) {
HashSet<BlockPos> points = new HashSet<BlockPos>();
HashSet<BlockPos> points2 = new HashSet<BlockPos>();
if (world.getBlockState(center).getBlock() == ground) {
points.add(center);
points2.add(center);
for (int i = 0; i < radius; i++) {
Iterator<BlockPos> iterator = points.iterator();
while (iterator.hasNext()) {
BlockPos pos = iterator.next();
for (Vec3i offset : OFFSETS) {
if (random.nextBoolean()) {
BlockPos pos2 = pos.offset(offset);
if (random.nextBoolean() && world.getBlockState(pos2).getBlock() == ground
&& !points.contains(pos2))
points2.add(pos2);
}
}
}
points.addAll(points2);
points2.clear();
}
Iterator<BlockPos> iterator = points.iterator();
while (iterator.hasNext()) {
BlockPos pos = iterator.next();
BlocksHelper.setWithoutUpdate(world, pos, cover);
}
}
}
/**
* Creates a new {@link Direction} array with clockwise order:
* NORTH -> EAST -> SOUTH -> WEST
* @return Array of {@link Direction}.
*/
public static Direction[] makeHorizontal() {
return new Direction[] { Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST };
}
/**
* Get any random horizontal {@link Direction}.
* @param random - {@link Random}.
* @return {@link Direction}.
*/
public static Direction randomHorizontal(Random random) {
return HORIZONTAL[random.nextInt(4)];
}
/**
* Get any random {@link Direction} including vertical and horizontal.
* @param random - {@link Random}.
* @return {@link Direction}.
*/
public static Direction randomDirection(Random random) {
return DIRECTIONS[random.nextInt(6)];
}
public static boolean isFluid(BlockState blockState) {
return !blockState.getFluidState().isEmpty();
/**
* Check if block is {@link Fluid} or not.
* @param state - {@link BlockState} to check.
* @return {@code true} if block is fluid and {@code false} if not.
*/
public static boolean isFluid(BlockState state) {
return !state.getFluidState().isEmpty();
}
/**
* Check if block is "invulnerable" like Bedrock.
* @param state - {@link BlockState} to check;
* @param world - {@link BlockGetter} world where BlockState exist;
* @param pos - {@link BlockPos} where BlockState is.
* @return {@code true} if block is "invulnerable" and {@code false} if not.
*/
public static boolean isInvulnerable(BlockState state, BlockGetter world, BlockPos pos) {
return state.getDestroySpeed(world, pos) < 0;
}
/**
* Check if block is "invulnerable" like Bedrock. Unlike safe function will pass world and position parameters as {@code null}.
* @param state - {@link BlockState} to check.
* @return {@code true} if block is "invulnerable" and {@code false} if not.
*/
public static boolean isInvulnerableUnsafe(BlockState state) {
return isInvulnerable(state, null, null);
}
}

View file

@ -0,0 +1,372 @@
package ru.bclib.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Random;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.google.common.collect.Sets;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.material.Material;
import ru.bclib.api.BCLibTags;
public class StructureHelper {
private static final Direction[] DIR = BlocksHelper.makeHorizontal();
public static StructureTemplate readStructure(ResourceLocation resource) {
String ns = resource.getNamespace();
String nm = resource.getPath();
return readStructure("/data/" + ns + "/structures/" + nm + ".nbt");
}
public static StructureTemplate readStructure(File datapack, String path) {
if (datapack.isDirectory()) {
return readStructure(datapack.toString() + "/" + path);
}
else if (datapack.isFile() && datapack.getName().endsWith(".zip")) {
try {
ZipFile zipFile = new ZipFile(datapack);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String name = entry.getName();
long compressedSize = entry.getCompressedSize();
long normalSize = entry.getSize();
String type = entry.isDirectory() ? "DIR" : "FILE";
System.out.println(name);
System.out.format("\t %s - %d - %d\n", type, compressedSize, normalSize);
}
zipFile.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public static StructureTemplate readStructure(String path) {
try {
InputStream inputstream = StructureHelper.class.getResourceAsStream(path);
return readStructureFromStream(inputstream);
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static StructureTemplate readStructureFromStream(InputStream stream) throws IOException {
CompoundTag nbttagcompound = NbtIo.readCompressed(stream);
StructureTemplate template = new StructureTemplate();
template.load(nbttagcompound);
return template;
}
public static BlockPos offsetPos(BlockPos pos, StructureTemplate structure, Rotation rotation, Mirror mirror) {
BlockPos offset = StructureTemplate.transform(structure.getSize(), mirror, rotation, BlockPos.ZERO);
return pos.offset(-offset.getX() * 0.5, 0, -offset.getZ() * 0.5);
}
public static void placeCenteredBottom(WorldGenLevel world, BlockPos pos, StructureTemplate structure, Rotation rotation, Mirror mirror, Random random) {
placeCenteredBottom(world, pos, structure, rotation, mirror, makeBox(pos), random);
}
public static void placeCenteredBottom(WorldGenLevel world, BlockPos pos, StructureTemplate structure, Rotation rotation, Mirror mirror, BoundingBox bounds, Random random) {
BlockPos offset = offsetPos(pos, structure, rotation, mirror);
StructurePlaceSettings placementData = new StructurePlaceSettings().setRotation(rotation).setMirror(mirror).setBoundingBox(bounds);
structure.placeInWorldChunk(world, offset, placementData, random);
}
private static BoundingBox makeBox(BlockPos pos) {
int sx = ((pos.getX() >> 4) << 4) - 16;
int sz = ((pos.getZ() >> 4) << 4) - 16;
int ex = sx + 47;
int ez = sz + 47;
return BoundingBox.createProper(sx, 0, sz, ex, 255, ez);
}
public static BoundingBox getStructureBounds(BlockPos pos, StructureTemplate structure, Rotation rotation, Mirror mirror) {
BlockPos max = structure.getSize();
BlockPos min = StructureTemplate.transform(structure.getSize(), mirror, rotation, BlockPos.ZERO);
max = max.subtract(min);
return new BoundingBox(min.offset(pos), max.offset(pos));
}
public static BoundingBox intersectBoxes(BoundingBox box1, BoundingBox box2) {
int x1 = MHelper.max(box1.x0, box2.x0);
int y1 = MHelper.max(box1.y0, box2.y0);
int z1 = MHelper.max(box1.z0, box2.z0);
int x2 = MHelper.min(box1.x1, box2.x1);
int y2 = MHelper.min(box1.y1, box2.y1);
int z2 = MHelper.min(box1.z1, box2.z1);
return BoundingBox.createProper(x1, y1, z1, x2, y2, z2);
}
public static void erode(WorldGenLevel world, BoundingBox bounds, int iterations, Random random) {
MutableBlockPos mut = new MutableBlockPos();
boolean canDestruct = true;
for (int i = 0; i < iterations; i++) {
for (int x = bounds.x0; x <= bounds.x1; x++) {
mut.setX(x);
for (int z = bounds.z0; z <= bounds.z1; z++) {
mut.setZ(z);
for (int y = bounds.y1; y >= bounds.y0; y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (canDestruct && BlocksHelper.isInvulnerableUnsafe(state) && random.nextInt(8) == 0 && world.isEmptyBlock(mut.below(2))) {
int r = MHelper.randRange(1, 4, random);
int cx = mut.getX();
int cy = mut.getY();
int cz = mut.getZ();
int x1 = cx - r;
int y1 = cy - r;
int z1 = cz - r;
int x2 = cx + r;
int y2 = cy + r;
int z2 = cz + r;
for (int px = x1; px <= x2; px++) {
int dx = px - cx;
dx *= dx;
mut.setX(px);
for (int py = y1; py <= y2; py++) {
int dy = py - cy;
dy *= dy;
mut.setY(py);
for (int pz = z1; pz <= z2; pz++) {
int dz = pz - cz;
dz *= dz;
mut.setZ(pz);
if (dx + dy + dz <= r && BlocksHelper.isInvulnerableUnsafe(world.getBlockState(mut))) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
}
}
}
}
mut.setX(cx);
mut.setY(cy);
mut.setZ(cz);
canDestruct = false;
continue;
}
else if (ignore(state)) {
continue;
}
if (!state.isAir() && random.nextBoolean()) {
MHelper.shuffle(DIR, random);
for (Direction dir: DIR) {
if (world.isEmptyBlock(mut.relative(dir)) && world.isEmptyBlock(mut.below().relative(dir))) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
mut.move(dir).move(Direction.DOWN);
for (int py = mut.getY(); y >= bounds.y0 - 10; y--) {
mut.setY(py - 1);
if (!world.isEmptyBlock(mut)) {
mut.setY(py);
BlocksHelper.setWithoutUpdate(world, mut, state);
break;
}
}
}
}
break;
}
else if (random.nextInt(8) == 0 && !BlocksHelper.isInvulnerableUnsafe(world.getBlockState(mut.above()))) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
}
}
}
}
}
for (int x = bounds.x0; x <= bounds.x1; x++) {
mut.setX(x);
for (int z = bounds.z0; z <= bounds.z1; z++) {
mut.setZ(z);
for (int y = bounds.y1; y >= bounds.y0; y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state) && world.isEmptyBlock(mut.below())) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
for (int py = mut.getY(); py >= bounds.y0 - 10; py--) {
mut.setY(py - 1);
if (!world.isEmptyBlock(mut)) {
mut.setY(py);
BlocksHelper.setWithoutUpdate(world, mut, state);
break;
}
}
}
}
}
}
}
public static void erodeIntense(WorldGenLevel world, BoundingBox bounds, Random random) {
MutableBlockPos mut = new MutableBlockPos();
MutableBlockPos mut2 = new MutableBlockPos();
int minY = bounds.y0 - 10;
for (int x = bounds.x0; x <= bounds.x1; x++) {
mut.setX(x);
for (int z = bounds.z0; z <= bounds.z1; z++) {
mut.setZ(z);
for (int y = bounds.y1; y >= bounds.y0; y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state)) {
if (random.nextInt(6) == 0) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
if (random.nextBoolean()) {
int px = MHelper.floor(random.nextGaussian() * 2 + x + 0.5);
int pz = MHelper.floor(random.nextGaussian() * 2 + z + 0.5);
mut2.set(px, y, pz);
while (world.getBlockState(mut2).getMaterial().isReplaceable() && mut2.getY() > minY) {
mut2.setY(mut2.getY() - 1);
}
if (!world.getBlockState(mut2).isAir() && state.canSurvive(world, mut2)) {
mut2.setY(mut2.getY() + 1);
BlocksHelper.setWithoutUpdate(world, mut2, state);
}
}
}
else if (random.nextInt(8) == 0) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
}
}
}
}
}
drop(world, bounds);
}
private static boolean isTerrainNear(WorldGenLevel world, BlockPos pos) {
for (Direction dir: BlocksHelper.DIRECTIONS) {
if (world.getBlockState(pos.relative(dir)).is(BCLibTags.GEN_TERRAIN)) {
return true;
}
}
return false;
}
private static void drop(WorldGenLevel world, BoundingBox bounds) {
MutableBlockPos mut = new MutableBlockPos();
Set<BlockPos> blocks = Sets.newHashSet();
Set<BlockPos> edge = Sets.newHashSet();
Set<BlockPos> add = Sets.newHashSet();
for (int x = bounds.x0; x <= bounds.x1; x++) {
mut.setX(x);
for (int z = bounds.z0; z <= bounds.z1; z++) {
mut.setZ(z);
for (int y = bounds.y0; y <= bounds.y1; y++) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state) && isTerrainNear(world, mut)) {
edge.add(mut.immutable());
}
}
}
}
if (edge.isEmpty()) {
return;
}
while (!edge.isEmpty()) {
for (BlockPos center: edge) {
for (Direction dir: BlocksHelper.DIRECTIONS) {
BlockState state = world.getBlockState(center);
if (state.isCollisionShapeFullBlock(world, center)) {
mut.set(center).move(dir);
if (bounds.isInside(mut)) {
state = world.getBlockState(mut);
if (!ignore(state) && !blocks.contains(mut)) {
add.add(mut.immutable());
}
}
}
}
}
blocks.addAll(edge);
edge.clear();
edge.addAll(add);
add.clear();
}
int minY = bounds.y0 - 10;
for (int x = bounds.x0; x <= bounds.x1; x++) {
mut.setX(x);
for (int z = bounds.z0; z <= bounds.z1; z++) {
mut.setZ(z);
for (int y = bounds.y0; y <= bounds.y1; y++) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state) && !blocks.contains(mut)) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
while (world.getBlockState(mut).getMaterial().isReplaceable() && mut.getY() > minY) {
mut.setY(mut.getY() - 1);
}
if (mut.getY() > minY) {
mut.setY(mut.getY() + 1);
BlocksHelper.setWithoutUpdate(world, mut, state);
}
}
}
}
}
}
private static boolean ignore(BlockState state) {
return state.getMaterial().isReplaceable() ||
!state.getFluidState().isEmpty() ||
state.is(BCLibTags.END_GROUND) ||
state.is(BlockTags.LOGS) ||
state.is(BlockTags.LEAVES) ||
state.getMaterial().equals(Material.PLANT) ||
state.getMaterial().equals(Material.LEAVES) ||
BlocksHelper.isInvulnerableUnsafe(state);
}
public static void cover(WorldGenLevel world, BoundingBox bounds, Random random) {
MutableBlockPos mut = new MutableBlockPos();
for (int x = bounds.x0; x <= bounds.x1; x++) {
mut.setX(x);
for (int z = bounds.z0; z <= bounds.z1; z++) {
mut.setZ(z);
BlockState top = world.getBiome(mut).getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial();
for (int y = bounds.y1; y >= bounds.y0; y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (state.is(BCLibTags.END_GROUND) && !world.getBlockState(mut.above()).getMaterial().isSolidBlocking()) {
BlocksHelper.setWithoutUpdate(world, mut, top);
}
}
}
}
}
}

View file

@ -0,0 +1,204 @@
package ru.bclib.world.biomes;
import java.io.InputStream;
import java.util.List;
import java.util.Random;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import ru.bclib.config.IdConfig;
import ru.bclib.util.JsonFactory;
import ru.bclib.util.StructureHelper;
import ru.bclib.world.features.BCLFeature;
import ru.bclib.world.features.ListFeature;
import ru.bclib.world.features.ListFeature.StructureInfo;
import ru.bclib.world.features.NBTStructureFeature.TerrainMerge;
public class BCLBiome {
protected List<BCLBiome> subbiomes = Lists.newArrayList();
protected final Biome biome;
protected final ResourceLocation mcID;
protected BCLBiome edge;
protected int edgeSize;
protected BCLBiome biomeParent;
protected float maxSubBiomeChance = 1;
protected final float genChanceUnmutable;
protected float genChance = 1;
private final float fogDensity;
private BCLFeature structuresFeature;
private Biome actualBiome;
public BCLBiome(BiomeDefinition definition, IdConfig config) {
this.mcID = definition.getID();
this.readStructureList();
if (structuresFeature != null) {
definition.addFeature(structuresFeature);
}
this.biome = definition.build();
this.fogDensity = config.getFloat(mcID, "fog_density", definition.getFodDensity());
this.genChanceUnmutable = config.getFloat(mcID, "generation_chance", definition.getGenChance());
this.edgeSize = config.getInt(mcID, "edge_size", 32);
}
public BCLBiome(ResourceLocation id, Biome biome, float fogDensity, float genChance, boolean hasCaves, IdConfig config) {
this.mcID = id;
this.readStructureList();
this.biome = biome;
this.fogDensity = config.getFloat(mcID, "fog_density", fogDensity);
this.genChanceUnmutable = config.getFloat(mcID, "generation_chance", genChance);
this.edgeSize = config.getInt(mcID, "edge_size", 32);
}
public BCLBiome getEdge() {
return edge == null ? this : edge;
}
public void setEdge(BCLBiome edge) {
this.edge = edge;
edge.biomeParent = this;
}
public int getEdgeSize() {
return edgeSize;
}
public void setEdgeSize(int size) {
edgeSize = size;
}
public void addSubBiome(BCLBiome biome) {
maxSubBiomeChance += biome.mutateGenChance(maxSubBiomeChance);
biome.biomeParent = this;
subbiomes.add(biome);
}
public boolean containsSubBiome(BCLBiome biome) {
return subbiomes.contains(biome);
}
public BCLBiome getSubBiome(Random random) {
float chance = random.nextFloat() * maxSubBiomeChance;
for (BCLBiome biome : subbiomes)
if (biome.canGenerate(chance))
return biome;
return this;
}
public BCLBiome getParentBiome() {
return this.biomeParent;
}
public boolean hasEdge() {
return edge != null;
}
public boolean hasParentBiome() {
return biomeParent != null;
}
public boolean isSame(BCLBiome biome) {
return biome == this || (biome.hasParentBiome() && biome.getParentBiome() == this);
}
public boolean canGenerate(float chance) {
return chance <= this.genChance;
}
public float mutateGenChance(float chance) {
genChance = genChanceUnmutable;
genChance += chance;
return genChance;
}
public Biome getBiome() {
return biome;
}
@Override
public String toString() {
return mcID.toString();
}
public ResourceLocation getID() {
return mcID;
}
public float getFogDensity() {
return fogDensity;
}
protected void readStructureList() {
String ns = mcID.getNamespace();
String nm = mcID.getPath();
String path = "/data/" + ns + "/structures/biome/" + nm + "/";
InputStream inputstream = StructureHelper.class.getResourceAsStream(path + "structures.json");
if (inputstream != null) {
JsonObject obj = JsonFactory.getJsonObject(inputstream);
JsonArray enties = obj.getAsJsonArray("structures");
if (enties != null) {
List<StructureInfo> list = Lists.newArrayList();
enties.forEach((entry) -> {
JsonObject e = entry.getAsJsonObject();
String structure = path + e.get("nbt").getAsString() + ".nbt";
TerrainMerge terrainMerge = TerrainMerge.getFromString(e.get("terrainMerge").getAsString());
int offsetY = e.get("offsetY").getAsInt();
list.add(new StructureInfo(structure, offsetY, terrainMerge));
});
if (!list.isEmpty()) {
structuresFeature = BCLFeature.makeChansedFeature(new ResourceLocation(ns, nm + "_structures"), new ListFeature(list), 10);
}
}
}
}
public BCLFeature getStructuresFeature() {
return structuresFeature;
}
public Biome getActualBiome() {
return this.actualBiome;
}
public float getGenChance() {
return this.genChance;
}
public float getGenChanceImmutable() {
return this.genChanceUnmutable;
}
public void updateActualBiomes(Registry<Biome> biomeRegistry) {
subbiomes.forEach((sub) -> {
if (sub != this) {
sub.updateActualBiomes(biomeRegistry);
}
});
if (edge != null && edge != this) {
edge.updateActualBiomes(biomeRegistry);
}
this.actualBiome = biomeRegistry.get(mcID);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
BCLBiome biome = (BCLBiome) obj;
return biome == null ? false : biome.mcID.equals(mcID);
}
@Override
public int hashCode() {
return mcID.hashCode();
}
}

View file

@ -0,0 +1,358 @@
package ru.bclib.world.biomes;
import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.core.Registry;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.data.worldgen.biome.Biomes;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.Music;
import net.minecraft.sounds.Musics;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.biome.AmbientAdditionsSettings;
import net.minecraft.world.level.biome.AmbientMoodSettings;
import net.minecraft.world.level.biome.AmbientParticleSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biome.BiomeCategory;
import net.minecraft.world.level.biome.Biome.Precipitation;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.biome.BiomeSpecialEffects.Builder;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.GenerationStep.Carving;
import net.minecraft.world.level.levelgen.GenerationStep.Decoration;
import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.feature.configurations.ProbabilityFeatureConfiguration;
import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilder;
import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderBaseConfiguration;
import ru.bclib.util.ColorUtil;
import ru.bclib.world.features.BCLFeature;
import ru.bclib.world.structures.BCLStructureFeature;
import ru.bclib.world.surface.DoubleBlockSurfaceBuilder;
public class BiomeDefinition {
private static final int DEF_FOLIAGE_OVERWORLD = Biomes.PLAINS.getFoliageColor();
private static final int DEF_FOLIAGE_NETHER =ColorUtil.color(117, 10, 10);
private static final int DEF_FOLIAGE_END = ColorUtil.color(197, 210, 112);
private final List<ConfiguredStructureFeature<?, ?>> structures = Lists.newArrayList();
private final List<FeatureInfo> features = Lists.newArrayList();
private final List<CarverInfo> carvers = Lists.newArrayList();
private final List<SpawnInfo> mobs = Lists.newArrayList();
private final List<SpawnerData> spawns = Lists.newArrayList();
private final ResourceLocation id;
private AmbientParticleSettings particleConfig;
private AmbientAdditionsSettings additions;
private AmbientMoodSettings mood;
private SoundEvent music;
private SoundEvent loop;
private int foliageColor = DEF_FOLIAGE_OVERWORLD;
private int grassColor = DEF_FOLIAGE_OVERWORLD;
private int waterFogColor = 329011;
private int waterColor = 4159204;
private int fogColor = 10518688;
private float fogDensity = 1F;
private float depth = 0.1F;
private Precipitation precipitation = Precipitation.NONE;
private BiomeCategory category = BiomeCategory.NONE;
private float temperature = 1F;
private float genChance = 1F;
private float downfall = 0F;
private int edgeSize = 32;
private ConfiguredSurfaceBuilder<?> surface;
/**
* Custom biome definition. Can be extended with new parameters.
* @param id - Biome {@link ResourceLocation} (identifier).
*/
public BiomeDefinition(ResourceLocation id) {
this.id = id;
}
/**
* Create default definition for The Nether biome.
* @param id
* @return
*/
public static BiomeDefinition netherBiome(ResourceLocation id) {
BiomeDefinition def = new BiomeDefinition(id);
def.foliageColor = DEF_FOLIAGE_NETHER;
def.grassColor = DEF_FOLIAGE_NETHER;
def.setCategory(BiomeCategory.NETHER);
return def;
}
/**
* Create default definition for The End biome.
* @param id
* @return
*/
public static BiomeDefinition endBiome(ResourceLocation id) {
BiomeDefinition def = new BiomeDefinition(id);
def.foliageColor = DEF_FOLIAGE_END;
def.grassColor = DEF_FOLIAGE_END;
def.setCategory(BiomeCategory.THEEND);
return def;
}
public BiomeDefinition setCategory(BiomeCategory category) {
this.category = category;
return this;
}
public BiomeDefinition setPrecipitation(Precipitation precipitation) {
this.precipitation = precipitation;
return this;
}
public BiomeDefinition setSurface(Block block) {
setSurface(SurfaceBuilder.DEFAULT.configured(new SurfaceBuilderBaseConfiguration(
block.defaultBlockState(),
Blocks.END_STONE.defaultBlockState(),
Blocks.END_STONE.defaultBlockState()
)));
return this;
}
public BiomeDefinition setSurface(Block block1, Block block2) {
setSurface(DoubleBlockSurfaceBuilder.register("bclib_" + id.getPath() + "_surface").setBlock1(block1).setBlock2(block2).configured());
return this;
}
public BiomeDefinition setSurface(ConfiguredSurfaceBuilder<?> builder) {
this.surface = builder;
return this;
}
public BiomeDefinition setParticles(ParticleOptions particle, float probability) {
this.particleConfig = new AmbientParticleSettings(particle, probability);
return this;
}
public BiomeDefinition setGenChance(float genChance) {
this.genChance = genChance;
return this;
}
public BiomeDefinition setDepth(float depth) {
this.depth = depth;
return this;
}
public BiomeDefinition setTemperature(float temperature) {
this.temperature = temperature;
return this;
}
public BiomeDefinition setDownfall(float downfall) {
this.downfall = downfall;
return this;
}
public BiomeDefinition setEdgeSize(int edgeSize) {
this.edgeSize = edgeSize;
return this;
}
public BiomeDefinition addMobSpawn(EntityType<?> type, int weight, int minGroupSize, int maxGroupSize) {
ResourceLocation eID = Registry.ENTITY_TYPE.getKey(type);
if (eID != Registry.ENTITY_TYPE.getDefaultKey()) {
SpawnInfo info = new SpawnInfo();
info.type = type;
info.weight = weight;
info.minGroupSize = minGroupSize;
info.maxGroupSize = maxGroupSize;
mobs.add(info);
}
return this;
}
public BiomeDefinition addMobSpawn(SpawnerData entry) {
spawns.add(entry);
return this;
}
public BiomeDefinition addStructureFeature(ConfiguredStructureFeature<?, ?> feature) {
structures.add(feature);
return this;
}
public BiomeDefinition addStructureFeature(BCLStructureFeature feature) {
structures.add(feature.getFeatureConfigured());
return this;
}
public BiomeDefinition addFeature(BCLFeature feature) {
FeatureInfo info = new FeatureInfo();
info.featureStep = feature.getFeatureStep();
info.feature = feature.getFeatureConfigured();
features.add(info);
return this;
}
public BiomeDefinition addFeature(Decoration featureStep, ConfiguredFeature<?, ?> feature) {
FeatureInfo info = new FeatureInfo();
info.featureStep = featureStep;
info.feature = feature;
features.add(info);
return this;
}
private int getColor(int r, int g, int b) {
r = Mth.clamp(r, 0, 255);
g = Mth.clamp(g, 0, 255);
b = Mth.clamp(b, 0, 255);
return ColorUtil.color(r, g, b);
}
public BiomeDefinition setFogColor(int r, int g, int b) {
this.fogColor = getColor(r, g, b);
return this;
}
public BiomeDefinition setFogDensity(float density) {
this.fogDensity = density;
return this;
}
public BiomeDefinition setWaterColor(int r, int g, int b) {
this.waterColor = getColor(r, g, b);
return this;
}
public BiomeDefinition setWaterFogColor(int r, int g, int b) {
this.waterFogColor = getColor(r, g, b);
return this;
}
public BiomeDefinition setWaterAndFogColor(int r, int g, int b) {
return setWaterColor(r, g, b).setWaterFogColor(r, g, b);
}
public BiomeDefinition setFoliageColor(int r, int g, int b) {
this.foliageColor = getColor(r, g, b);
return this;
}
public BiomeDefinition setGrassColor(int r, int g, int b) {
this.grassColor = getColor(r, g, b);
return this;
}
public BiomeDefinition setPlantsColor(int r, int g, int b) {
return this.setFoliageColor(r, g, b).setGrassColor(r, g, b);
}
public BiomeDefinition setLoop(SoundEvent loop) {
this.loop = loop;
return this;
}
public BiomeDefinition setMood(SoundEvent mood) {
this.mood = new AmbientMoodSettings(mood, 6000, 8, 2.0D);
return this;
}
public BiomeDefinition setAdditions(SoundEvent additions) {
this.additions = new AmbientAdditionsSettings(additions, 0.0111);
return this;
}
public BiomeDefinition setMusic(SoundEvent music) {
this.music = music;
return this;
}
public Biome build() {
MobSpawnSettings.Builder spawnSettings = new MobSpawnSettings.Builder();
BiomeGenerationSettings.Builder generationSettings = new BiomeGenerationSettings.Builder();
Builder effects = new Builder();
mobs.forEach((spawn) -> {
spawnSettings.addSpawn(spawn.type.getCategory(), new MobSpawnSettings.SpawnerData(spawn.type, spawn.weight, spawn.minGroupSize, spawn.maxGroupSize));
});
spawns.forEach((entry) -> {
spawnSettings.addSpawn(entry.type.getCategory(), entry);
});
generationSettings.surfaceBuilder(surface == null ? net.minecraft.data.worldgen.SurfaceBuilders.END : surface);
structures.forEach((structure) -> generationSettings.addStructureStart(structure));
features.forEach((info) -> generationSettings.addFeature(info.featureStep, info.feature));
carvers.forEach((info) -> generationSettings.addCarver(info.carverStep, info.carver));
effects.skyColor(0).waterColor(waterColor).waterFogColor(waterFogColor).fogColor(fogColor).foliageColorOverride(foliageColor).grassColorOverride(grassColor);
if (loop != null) effects.ambientLoopSound(loop);
if (mood != null) effects.ambientMoodSound(mood);
if (additions != null) effects.ambientAdditionsSound(additions);
if (particleConfig != null) effects.ambientParticle(particleConfig);
effects.backgroundMusic(music != null ? new Music(music, 600, 2400, true) : Musics.END);
return new Biome.BiomeBuilder()
.precipitation(precipitation)
.biomeCategory(category)
.depth(depth)
.scale(0.2F)
.temperature(temperature)
.downfall(downfall)
.specialEffects(effects.build())
.mobSpawnSettings(spawnSettings.build())
.generationSettings(generationSettings.build())
.build();
}
private static final class SpawnInfo {
EntityType<?> type;
int weight;
int minGroupSize;
int maxGroupSize;
}
private static final class FeatureInfo {
Decoration featureStep;
ConfiguredFeature<?, ?> feature;
}
private static final class CarverInfo {
Carving carverStep;
ConfiguredWorldCarver<ProbabilityFeatureConfiguration> carver;
}
public ResourceLocation getID() {
return id;
}
public float getFodDensity() {
return fogDensity;
}
public float getGenChance() {
return genChance;
}
public int getEdgeSize() {
return edgeSize;
}
public BiomeDefinition addCarver(Carving carverStep, ConfiguredWorldCarver<ProbabilityFeatureConfiguration> carver) {
CarverInfo info = new CarverInfo();
info.carverStep = carverStep;
info.carver = carver;
carvers.add(info);
return this;
}
}

View file

@ -0,0 +1,94 @@
package ru.bclib.world.features;
import net.minecraft.core.Registry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.data.worldgen.Features;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.CountConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RangeDecoratorConfiguration;
import net.minecraft.world.level.levelgen.placement.ChanceDecoratorConfiguration;
import net.minecraft.world.level.levelgen.placement.FeatureDecorator;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockMatchTest;
public class BCLFeature {
private Feature<?> feature;
private ConfiguredFeature<?, ?> featureConfigured;
private GenerationStep.Decoration featureStep;
public BCLFeature(Feature<?> feature, ConfiguredFeature<?, ?> configuredFeature, GenerationStep.Decoration featureStep) {
this.featureConfigured = configuredFeature;
this.featureStep = featureStep;
this.feature = feature;
}
public BCLFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, GenerationStep.Decoration featureStep, ConfiguredFeature<?, ?> configuredFeature) {
this.featureConfigured = Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, id, configuredFeature);
this.feature = Registry.register(Registry.FEATURE, id, feature);
this.featureStep = featureStep;
}
public static BCLFeature makeVegetationFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, int density) {
ConfiguredFeature<?, ?> configured = feature.configured(FeatureConfiguration.NONE).decorated(Features.Decorators.HEIGHTMAP_SQUARE).countRandom(density);
return new BCLFeature(id, feature, GenerationStep.Decoration.VEGETAL_DECORATION, configured);
}
public static BCLFeature makeRawGenFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, int chance) {
ConfiguredFeature<?, ?> configured = feature.configured(FeatureConfiguration.NONE).decorated(FeatureDecorator.CHANCE.configured(new ChanceDecoratorConfiguration(chance)));
return new BCLFeature(id, feature, GenerationStep.Decoration.RAW_GENERATION, configured);
}
public static BCLFeature makeLakeFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, int chance) {
ConfiguredFeature<?, ?> configured = feature.configured(FeatureConfiguration.NONE).decorated(FeatureDecorator.WATER_LAKE.configured(new ChanceDecoratorConfiguration(chance)));
return new BCLFeature(id, feature, GenerationStep.Decoration.LAKES, configured);
}
public static BCLFeature makeOreFeature(ResourceLocation id, Block blockOre, int veins, int veinSize, int offset, int minY, int maxY) {
OreConfiguration featureConfig = new OreConfiguration(new BlockMatchTest(Blocks.END_STONE), blockOre.defaultBlockState(), veinSize);
RangeDecoratorConfiguration rangeDecorator = new RangeDecoratorConfiguration(offset, minY, maxY);
ConfiguredFeature<?, ?> oreFeature = Feature.ORE.configured(featureConfig)
.decorated(FeatureDecorator.RANGE.configured(rangeDecorator))
.squared()
.count(veins);
return new BCLFeature(Feature.ORE, Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, id, oreFeature), GenerationStep.Decoration.UNDERGROUND_ORES);
}
public static BCLFeature makeChunkFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature) {
ConfiguredFeature<?, ?> configured = feature.configured(FeatureConfiguration.NONE).decorated(FeatureDecorator.COUNT.configured(new CountConfiguration(1)));
return new BCLFeature(id, feature, GenerationStep.Decoration.LOCAL_MODIFICATIONS, configured);
}
public static BCLFeature makeChansedFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, int chance) {
ConfiguredFeature<?, ?> configured = feature.configured(FeatureConfiguration.NONE).decorated(FeatureDecorator.CHANCE.configured(new ChanceDecoratorConfiguration(chance)));
return new BCLFeature(id, feature, GenerationStep.Decoration.SURFACE_STRUCTURES, configured);
}
public static BCLFeature makeCountRawFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, int chance) {
ConfiguredFeature<?, ?> configured = feature.configured(FeatureConfiguration.NONE).decorated(FeatureDecorator.COUNT.configured(new CountConfiguration(chance)));
return new BCLFeature(id, feature, GenerationStep.Decoration.RAW_GENERATION, configured);
}
public static BCLFeature makeFeatureConfigured(ResourceLocation id, Feature<NoneFeatureConfiguration> feature) {
ConfiguredFeature<?, ?> configured = feature.configured(FeatureConfiguration.NONE);
return new BCLFeature(id, feature, GenerationStep.Decoration.RAW_GENERATION, configured);
}
public Feature<?> getFeature() {
return feature;
}
public ConfiguredFeature<?, ?> getFeatureConfigured() {
return featureConfigured;
}
public GenerationStep.Decoration getFeatureStep() {
return featureStep;
}
}

View file

@ -0,0 +1,44 @@
package ru.bclib.world.features;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import ru.bclib.util.BlocksHelper;
public abstract class DefaultFeature extends Feature<NoneFeatureConfiguration> {
protected static final BlockState AIR = Blocks.AIR.defaultBlockState();
protected static final BlockState WATER = Blocks.WATER.defaultBlockState();
public DefaultFeature() {
super(NoneFeatureConfiguration.CODEC);
}
public static int getYOnSurface(WorldGenLevel world, int x, int z) {
return world.getHeight(Types.WORLD_SURFACE, x, z);
}
public static int getYOnSurfaceWG(WorldGenLevel world, int x, int z) {
return world.getHeight(Types.WORLD_SURFACE_WG, x, z);
}
public static BlockPos getPosOnSurface(WorldGenLevel world, BlockPos pos) {
return world.getHeightmapPos(Types.WORLD_SURFACE, pos);
}
public static BlockPos getPosOnSurfaceWG(WorldGenLevel world, BlockPos pos) {
return world.getHeightmapPos(Types.WORLD_SURFACE_WG, pos);
}
public static BlockPos getPosOnSurfaceRaycast(WorldGenLevel world, BlockPos pos) {
return getPosOnSurfaceRaycast(world, pos, 256);
}
public static BlockPos getPosOnSurfaceRaycast(WorldGenLevel world, BlockPos pos, int dist) {
int h = BlocksHelper.downRay(world, pos, dist);
return pos.below(h);
}
}

View file

@ -0,0 +1,78 @@
package ru.bclib.world.features;
import java.util.List;
import java.util.Random;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import ru.bclib.util.StructureHelper;
public class ListFeature extends NBTStructureFeature {
private final List<StructureInfo> list;
private StructureInfo selected;
public ListFeature(List<StructureInfo> list) {
this.list = list;
}
@Override
protected StructureTemplate getStructure(WorldGenLevel world, BlockPos pos, Random random) {
selected = list.get(random.nextInt(list.size()));
return selected.getStructure();
}
@Override
protected boolean canSpawn(WorldGenLevel world, BlockPos pos, Random random) {
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
return ((cx + cz) & 1) == 0 && pos.getY() > 58;// && world.getBlockState(pos.below()).is(EndTags.GEN_TERRAIN);
}
@Override
protected Rotation getRotation(WorldGenLevel world, BlockPos pos, Random random) {
return Rotation.getRandom(random);
}
@Override
protected Mirror getMirror(WorldGenLevel world, BlockPos pos, Random random) {
return Mirror.values()[random.nextInt(3)];
}
@Override
protected int getYOffset(StructureTemplate structure, WorldGenLevel world, BlockPos pos, Random random) {
return selected.offsetY;
}
@Override
protected TerrainMerge getTerrainMerge(WorldGenLevel world, BlockPos pos, Random random) {
return selected.terrainMerge;
}
@Override
protected void addStructureData(StructurePlaceSettings data) {}
public static final class StructureInfo {
public final TerrainMerge terrainMerge;
public final String structurePath;
public final int offsetY;
private StructureTemplate structure;
public StructureInfo(String structurePath, int offsetY, TerrainMerge terrainMerge) {
this.terrainMerge = terrainMerge;
this.structurePath = structurePath;
this.offsetY = offsetY;
}
public StructureTemplate getStructure() {
if (structure == null) {
structure = StructureHelper.readStructure(structurePath);
}
return structure;
}
}
}

View file

@ -0,0 +1,31 @@
package ru.bclib.world.processors;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorType;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import ru.bclib.util.BlocksHelper;
import ru.bclib.util.MHelper;
public class DestructionStructureProcessor extends StructureProcessor {
private int chance = 4;
public void setChance(int chance) {
this.chance = chance;
}
@Override
public StructureBlockInfo processBlock(LevelReader worldView, BlockPos pos, BlockPos blockPos, StructureBlockInfo structureBlockInfo, StructureBlockInfo structureBlockInfo2, StructurePlaceSettings structurePlacementData) {
if (!BlocksHelper.isInvulnerable(structureBlockInfo2.state, worldView, structureBlockInfo2.pos) && MHelper.RANDOM.nextInt(chance) == 0) {
return null;
}
return structureBlockInfo2;
}
@Override
protected StructureProcessorType<?> getType() {
return StructureProcessorType.RULE;
}
}

View file

@ -0,0 +1,27 @@
package ru.bclib.world.processors;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorType;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
public class TerrainStructureProcessor extends StructureProcessor {
@Override
public StructureBlockInfo processBlock(LevelReader worldView, BlockPos pos, BlockPos blockPos, StructureBlockInfo structureBlockInfo, StructureBlockInfo structureBlockInfo2, StructurePlaceSettings structurePlacementData) {
BlockPos bpos = structureBlockInfo2.pos;
if (structureBlockInfo2.state.is(Blocks.END_STONE) && worldView.isEmptyBlock(bpos.above())) {
BlockState top = worldView.getBiome(structureBlockInfo2.pos).getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial();
return new StructureBlockInfo(bpos, top, structureBlockInfo2.nbt);
}
return structureBlockInfo2;
}
@Override
protected StructureProcessorType<?> getType() {
return StructureProcessorType.RULE;
}
}

View file

@ -0,0 +1,52 @@
package ru.bclib.world.surface;
import java.util.Random;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilder;
import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderBaseConfiguration;
import ru.bclib.noise.OpenSimplexNoise;
import ru.bclib.util.MHelper;
public class DoubleBlockSurfaceBuilder extends SurfaceBuilder<SurfaceBuilderBaseConfiguration> {
private static final OpenSimplexNoise NOISE = new OpenSimplexNoise(4141);
private SurfaceBuilderBaseConfiguration config1;
private SurfaceBuilderBaseConfiguration config2;
private DoubleBlockSurfaceBuilder() {
super(SurfaceBuilderBaseConfiguration.CODEC);
}
public DoubleBlockSurfaceBuilder setBlock1(Block block) {
BlockState stone = Blocks.END_STONE.defaultBlockState();
config1 = new SurfaceBuilderBaseConfiguration(block.defaultBlockState(), stone, stone);
return this;
}
public DoubleBlockSurfaceBuilder setBlock2(Block block) {
BlockState stone = Blocks.END_STONE.defaultBlockState();
config2 = new SurfaceBuilderBaseConfiguration(block.defaultBlockState(), stone, stone);
return this;
}
@Override
public void apply(Random random, ChunkAccess chunk, Biome biome, int x, int z, int height, double noise, BlockState defaultBlock, BlockState defaultFluid, int seaLevel, long seed, SurfaceBuilderBaseConfiguration surfaceBlocks) {
noise = NOISE.eval(x * 0.1, z * 0.1) + MHelper.randRange(-0.4, 0.4, random);
SurfaceBuilder.DEFAULT.apply(random, chunk, biome, x, z, height, noise, defaultBlock, defaultFluid, seaLevel, seed, noise > 0 ? config1 : config2);
}
public static DoubleBlockSurfaceBuilder register(String name) {
return Registry.register(Registry.SURFACE_BUILDER, name, new DoubleBlockSurfaceBuilder());
}
public ConfiguredSurfaceBuilder<SurfaceBuilderBaseConfiguration> configured() {
BlockState stone = Blocks.END_STONE.defaultBlockState();
return this.configured(new SurfaceBuilderBaseConfiguration(config1.getTopMaterial(), stone, stone));
}
}

View file

@ -3,7 +3,9 @@
"minVersion": "0.8",
"package": "ru.bclib.mixin.common",
"compatibilityLevel": "JAVA_8",
"mixins": [],
"mixins": [
"TagLoaderMixin"
],
"injectors": {
"defaultRequire": 1
}