Tags, surface builders, biome API (WIP), processors, features
This commit is contained in:
parent
6b0bf593ad
commit
979e2ab92a
15 changed files with 1513 additions and 51 deletions
|
@ -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();
|
||||
|
|
131
src/main/java/ru/bclib/api/BCLibTags.java
Normal file
131
src/main/java/ru/bclib/api/BCLibTags.java
Normal 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);
|
||||
}
|
||||
}
|
20
src/main/java/ru/bclib/api/SurfaceBuilders.java
Normal file
20
src/main/java/ru/bclib/api/SurfaceBuilders.java
Normal 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() {}
|
||||
}
|
26
src/main/java/ru/bclib/mixin/common/TagLoaderMixin.java
Normal file
26
src/main/java/ru/bclib/mixin/common/TagLoaderMixin.java
Normal 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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
372
src/main/java/ru/bclib/util/StructureHelper.java
Normal file
372
src/main/java/ru/bclib/util/StructureHelper.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
204
src/main/java/ru/bclib/world/biomes/BCLBiome.java
Normal file
204
src/main/java/ru/bclib/world/biomes/BCLBiome.java
Normal 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();
|
||||
}
|
||||
}
|
358
src/main/java/ru/bclib/world/biomes/BiomeDefinition.java
Normal file
358
src/main/java/ru/bclib/world/biomes/BiomeDefinition.java
Normal 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;
|
||||
}
|
||||
}
|
94
src/main/java/ru/bclib/world/features/BCLFeature.java
Normal file
94
src/main/java/ru/bclib/world/features/BCLFeature.java
Normal 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;
|
||||
}
|
||||
}
|
44
src/main/java/ru/bclib/world/features/DefaultFeature.java
Normal file
44
src/main/java/ru/bclib/world/features/DefaultFeature.java
Normal 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);
|
||||
}
|
||||
}
|
78
src/main/java/ru/bclib/world/features/ListFeature.java
Normal file
78
src/main/java/ru/bclib/world/features/ListFeature.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -3,7 +3,9 @@
|
|||
"minVersion": "0.8",
|
||||
"package": "ru.bclib.mixin.common",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [],
|
||||
"mixins": [
|
||||
"TagLoaderMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue