This commit is contained in:
Aleksey 2020-11-02 17:08:58 +03:00
commit d1830827cb
8 changed files with 356 additions and 148 deletions

View file

@ -8,7 +8,7 @@
loader_version = 0.10.5+build.213
# Mod Properties
mod_version = 0.5.0-beta
mod_version = 0.5.1-beta
maven_group = ru.betterend
archives_base_name = better-end

View file

@ -19,7 +19,6 @@ import ru.betterend.world.features.EndLakeFeature;
import ru.betterend.world.features.EndLilyFeature;
import ru.betterend.world.features.EndLotusFeature;
import ru.betterend.world.features.EndLotusLeafFeature;
import ru.betterend.world.features.EternalPortalFeature;
import ru.betterend.world.features.LacugroveFeature;
import ru.betterend.world.features.MossyGlowshroomFeature;
import ru.betterend.world.features.PythadendronBushFeature;
@ -70,7 +69,7 @@ public class EndFeatures {
public static final EndFeature FLAVOLITE_LAYER = EndFeature.makeLayerFeature("flavolite_layer", EndBlocks.FLAVOLITE, 12, 4, 96, 6);
// Other //
public static final EndFeature ETERNAL_PORTAL = EndFeature.makeChansedFeature("eternal_portal", new EternalPortalFeature(), 500);
//public static final EndFeature ETERNAL_PORTAL = EndFeature.makeChansedFeature("eternal_portal", new EternalPortalFeature(), 500);
public static void registerBiomeFeatures(Identifier id, Biome biome, List<List<Supplier<ConfiguredFeature<?, ?>>>> features) {
if (id.getNamespace().equals("minecraft")) {
@ -91,7 +90,7 @@ public class EndFeatures {
addFeature(ENDER_ORE, features);
addFeature(ROUND_CAVE_RARE, features);
addFeature(CAVE_GRASS, features);
addFeature(ETERNAL_PORTAL, features);
//addFeature(ETERNAL_PORTAL, features);
}
private static void addFeature(EndFeature feature, List<List<Supplier<ConfiguredFeature<?, ?>>>> features) {

View file

@ -11,6 +11,7 @@ import net.minecraft.world.gen.GenerationStep.Feature;
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
import ru.betterend.BetterEnd;
import ru.betterend.world.structures.EndStructureFeature;
import ru.betterend.world.structures.features.StructureEternalPortal;
import ru.betterend.world.structures.features.StructureGiantMossyGlowshroom;
import ru.betterend.world.structures.features.StructureMegaLake;
import ru.betterend.world.structures.features.StructureMountain;
@ -18,6 +19,7 @@ import ru.betterend.world.structures.features.StructurePaintedMountain;
import ru.betterend.world.structures.piece.CavePiece;
import ru.betterend.world.structures.piece.LakePiece;
import ru.betterend.world.structures.piece.MountainPiece;
import ru.betterend.world.structures.piece.NBTPiece;
import ru.betterend.world.structures.piece.PaintedMountainPiece;
import ru.betterend.world.structures.piece.VoxelPiece;
@ -27,11 +29,13 @@ public class EndStructures {
public static final StructurePieceType CAVE_PIECE = register("cave_piece", CavePiece::new);
public static final StructurePieceType LAKE_PIECE = register("lake_piece", LakePiece::new);
public static final StructurePieceType PAINTED_MOUNTAIN_PIECE = register("painted_mountain_piece", PaintedMountainPiece::new);
public static final StructurePieceType NBT_PIECE = register("nbt_piece", NBTPiece::new);
public static final EndStructureFeature GIANT_MOSSY_GLOWSHROOM = new EndStructureFeature("giant_mossy_glowshroom", new StructureGiantMossyGlowshroom(), Feature.SURFACE_STRUCTURES, 16, 8);
public static final EndStructureFeature MEGALAKE = new EndStructureFeature("megalake", new StructureMegaLake(), Feature.RAW_GENERATION, 4, 1);
public static final EndStructureFeature MOUNTAIN = new EndStructureFeature("mountain", new StructureMountain(), Feature.RAW_GENERATION, 3, 2);
public static final EndStructureFeature PAINTED_MOUNTAIN = new EndStructureFeature("painted_mountain", new StructurePaintedMountain(), Feature.RAW_GENERATION, 3, 2);
public static final EndStructureFeature ETERNAL_PORTAL = new EndStructureFeature("eternal_portal", new StructureEternalPortal(), Feature.SURFACE_STRUCTURES, 16, 6);
public static void register() {}
@ -40,15 +44,12 @@ public class EndStructures {
}
public static void registerBiomeStructures(Identifier id, Biome biome, Collection<Supplier<ConfiguredStructureFeature<?, ?>>> structures) {
/*if (id.getNamespace().equals("minecraft")) {
if (id.getPath().equals("end_highlands")) {
structures.clear();
addStructure(MOUNTAIN, structures);
if (!id.getPath().contains("mountain")) {
addStructure(ETERNAL_PORTAL, structures);
}
}*/
}
protected static void addStructure(EndStructureFeature feature, Collection<Supplier<ConfiguredStructureFeature<?, ?>>> collection) {
collection.add(() -> { return feature.getFeatureConfigured(); });
private static void addStructure(EndStructureFeature feature, Collection<Supplier<ConfiguredStructureFeature<?, ?>>> structures) {
structures.add(() -> { return feature.getFeatureConfigured(); });
}
}

View file

@ -1,74 +1,217 @@
package ru.betterend.util;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.Material;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.server.MinecraftServer;
import net.minecraft.structure.Structure;
import net.minecraft.structure.StructurePlacementData;
import net.minecraft.tag.BlockTags;
import net.minecraft.util.BlockMirror;
import net.minecraft.util.BlockRotation;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.Heightmap;
import net.minecraft.world.gen.ChunkRandom;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.chunk.StructureConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import net.minecraft.util.math.BlockPos.Mutable;
import net.minecraft.util.math.Direction;
import net.minecraft.world.StructureWorldAccess;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndTags;
public class StructureHelper {
private static final Set<ChunkPos> POSITIONS = new HashSet<ChunkPos>(64);
private static final Direction[] DIR = BlocksHelper.makeHorizontal();
private static void collectNearby(ServerWorld world, StructureFeature<?> feature, int chunkX, int chunkZ, int radius, StructureConfig config, long worldSeed, ChunkRandom chunkRandom) {
int x1 = chunkX - radius;
int x2 = chunkX + radius;
int z1 = chunkZ - radius;
int z2 = chunkZ + radius;
public static Structure readStructure(Identifier resource) {
String ns = resource.getNamespace();
String nm = resource.getPath();
POSITIONS.clear();
ChunkGenerator generator = world.getChunkManager().getChunkGenerator();
for (int x = x1; x <= x2; x += 8) {
for (int z = z1; z <= z2; z += 8) {
ChunkPos chunk = feature.getStartChunk(config, worldSeed, chunkRandom, x, z);
if (world.getBiome(chunk.getStartPos()).getGenerationSettings().hasStructureFeature(feature))
{
if (feature.getName().equals("endcity")) {
if (generator.getHeight((x << 16) | 8, (z << 16) | 8, Heightmap.Type.WORLD_SURFACE_WG) > 60) {
POSITIONS.add(chunk);
}
}
else {
POSITIONS.add(chunk);
}
}
}
try {
InputStream inputstream = MinecraftServer.class.getResourceAsStream("/data/" + ns + "/structures/" + nm + ".nbt");
return readStructureFromStream(inputstream);
}
catch (IOException e) {
e.printStackTrace();
}
private static long sqr(int x) {
return (long) x * (long) x;
}
public static BlockPos getNearestStructure(StructureFeature<?> feature, ServerWorld world, BlockPos pos, int radius) {
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
StructureConfig config = world.getChunkManager().getChunkGenerator().getStructuresConfig().getForType(feature);
if (config == null)
return null;
collectNearby(world, feature, cx, cz, radius, config, world.getSeed(), new ChunkRandom());
Iterator<ChunkPos> iterator = POSITIONS.iterator();
if (iterator.hasNext()) {
ChunkPos nearest = POSITIONS.iterator().next();
long d = sqr(nearest.x - cx) + sqr(nearest.z - cz);
while (iterator.hasNext()) {
ChunkPos n = iterator.next();
long d2 = sqr(n.x - cx) + sqr(n.z - cz);
if (d2 < d) {
d = d2;
nearest = n;
}
}
return nearest.getStartPos();
}
return null;
}
private static Structure readStructureFromStream(InputStream stream) throws IOException {
CompoundTag nbttagcompound = NbtIo.readCompressed(stream);
Structure template = new Structure();
template.fromTag(nbttagcompound);
return template;
}
public static BlockPos offsetPos(BlockPos pos, Structure structure, BlockRotation rotation, BlockMirror mirror) {
BlockPos offset = Structure.transformAround(structure.getSize(), mirror, rotation, BlockPos.ORIGIN);
return pos.add(-offset.getX() * 0.5, 0, -offset.getZ() * 0.5);
}
public static void placeCenteredBottom(StructureWorldAccess world, BlockPos pos, Structure structure, BlockRotation rotation, BlockMirror mirror, Random random) {
placeCenteredBottom(world, pos, structure, rotation, mirror, makeBox(pos), random);
}
public static void placeCenteredBottom(StructureWorldAccess world, BlockPos pos, Structure structure, BlockRotation rotation, BlockMirror mirror, BlockBox bounds, Random random) {
BlockPos offset = offsetPos(pos, structure, rotation, mirror);
StructurePlacementData placementData = new StructurePlacementData().setRotation(rotation).setMirror(mirror).setBoundingBox(bounds);
structure.place(world, offset, placementData, random);
}
private static BlockBox 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 BlockBox.create(sx, 0, sz, ex, 255, ez);
}
public static BlockBox getStructureBounds(BlockPos pos, Structure structure, BlockRotation rotation, BlockMirror mirror) {
BlockPos max = structure.getSize();
BlockPos min = Structure.transformAround(structure.getSize(), mirror, rotation, BlockPos.ORIGIN);
max = max.subtract(min);
return new BlockBox(min.add(pos), max.add(pos));
}
public static void erode(StructureWorldAccess world, BlockBox bounds, int iterations, Random random) {
Mutable mut = new Mutable();
boolean canDestruct = true;
for (int i = 0; i < iterations; i++) {
for (int x = bounds.minX; x <= bounds.maxX; x++) {
mut.setX(x);
for (int z = bounds.minZ; z <= bounds.maxZ; z++) {
mut.setZ(z);
for (int y = bounds.maxY; y >= bounds.minY; y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (canDestruct && state.isOf(EndBlocks.FLAVOLITE_RUNED_ETERNAL) && random.nextInt(8) == 0 && world.isAir(mut.down(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 && world.getBlockState(mut).isOf(EndBlocks.FLAVOLITE_RUNED_ETERNAL)) {
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()) {
shuffle(random);
for (Direction dir: DIR) {
if (world.isAir(mut.offset(dir)) && world.isAir(mut.down().offset(dir))) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
mut.move(dir).move(Direction.DOWN);
for (int py = mut.getY(); y >= bounds.minY - 10; y--) {
mut.setY(py - 1);
if (!world.isAir(mut)) {
mut.setY(py);
BlocksHelper.setWithoutUpdate(world, mut, state);
break;
}
}
}
}
break;
}
else if (random.nextInt(8) == 0 && !world.getBlockState(mut.up()).isOf(EndBlocks.ETERNAL_PEDESTAL)) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
}
}
}
}
}
for (int x = bounds.minX; x <= bounds.maxX; x++) {
mut.setX(x);
for (int z = bounds.minZ; z <= bounds.maxZ; z++) {
mut.setZ(z);
for (int y = bounds.maxY; y >= bounds.minY; y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state) && world.isAir(mut.down())) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
for (int py = mut.getY(); y >= bounds.minY - 10; y--) {
mut.setY(py - 1);
if (!world.isAir(mut)) {
mut.setY(py);
BlocksHelper.setWithoutUpdate(world, mut, state);
break;
}
}
}
}
}
}
}
private static boolean ignore(BlockState state) {
return state.isAir()
|| state.isIn(EndTags.END_GROUND)
|| state.isOf(EndBlocks.ETERNAL_PEDESTAL)
|| state.isOf(EndBlocks.FLAVOLITE_RUNED_ETERNAL)
|| state.isIn(BlockTags.LOGS)
|| state.isIn(BlockTags.LEAVES)
|| state.getMaterial().equals(Material.PLANT);
}
private static void shuffle(Random random) {
for (int i = 0; i < 4; i++) {
int j = random.nextInt(4);
Direction d = DIR[i];
DIR[i] = DIR[j];
DIR[j] = d;
}
}
public static void cover(StructureWorldAccess world, BlockBox bounds, Random random) {
Mutable mut = new Mutable();
for (int x = bounds.minX; x <= bounds.maxX; x++) {
mut.setX(x);
for (int z = bounds.minZ; z <= bounds.maxZ; z++) {
mut.setZ(z);
BlockState top = world.getBiome(mut).getGenerationSettings().getSurfaceConfig().getTopMaterial();
for (int y = bounds.maxY; y >= bounds.minY; y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (state.isIn(EndTags.END_GROUND) && !world.getBlockState(mut.up()).getMaterial().blocksLight()) {
BlocksHelper.setWithoutUpdate(world, mut, top);
}
}
}
}
}
}

View file

@ -1,64 +0,0 @@
package ru.betterend.world.features;
import java.util.Random;
import net.minecraft.structure.Structure;
import net.minecraft.structure.StructurePlacementData;
import net.minecraft.util.BlockMirror;
import net.minecraft.util.BlockRotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
import ru.betterend.BetterEnd;
import ru.betterend.registry.EndTags;
import ru.betterend.util.MHelper;
public class EternalPortalFeature extends NBTStructureFeature {
private static final Structure PORTAL = readStructure(BetterEnd.makeID("portal/eternal_portal"));
@Override
protected Structure getStructure() {
return PORTAL;
}
@Override
protected boolean canSpawn(StructureWorldAccess world, BlockPos pos) {
if (world.getBlockState(pos.down()).isIn(EndTags.END_GROUND)) {
return world.getBlockState(pos.north(2)).getMaterial().isReplaceable()
&& world.getBlockState(pos.south(2)).getMaterial().isReplaceable()
&& world.getBlockState(pos.east(2)).getMaterial().isReplaceable()
&& world.getBlockState(pos.west(2)).getMaterial().isReplaceable();
}
return false;
}
@Override
protected BlockRotation getRotation(StructureWorldAccess world, BlockPos pos, Random random) {
return BlockRotation.random(random);
}
@Override
protected BlockMirror getMirror(StructureWorldAccess world, BlockPos pos, Random random) {
return BlockMirror.values()[random.nextInt(3)];
}
@Override
protected int getYOffset(Structure structure, StructureWorldAccess world, BlockPos pos, Random random) {
return -3;
}
@Override
protected void addProcessors(StructurePlacementData placementData, Random random) {
DESTRUCTION.setChance(MHelper.randRange(4, 16, random));
placementData.addProcessor(DESTRUCTION);
}
@Override
protected boolean hasErosion() {
return true;
}
@Override
protected boolean hasTerrainOverlay() {
return true;
}
}

View file

@ -0,0 +1,45 @@
package ru.betterend.world.structures.features;
import net.minecraft.structure.Structure;
import net.minecraft.structure.StructureManager;
import net.minecraft.structure.StructureStart;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.world.Heightmap.Type;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import ru.betterend.BetterEnd;
import ru.betterend.util.MHelper;
import ru.betterend.util.StructureHelper;
import ru.betterend.world.structures.piece.NBTPiece;
public class StructureEternalPortal extends StructureFeatureBase {
private static final Identifier STRUCTURE_ID = BetterEnd.makeID("portal/eternal_portal");
private static final Structure STRUCTURE = StructureHelper.readStructure(STRUCTURE_ID);
@Override
public StructureFeature.StructureStartFactory<DefaultFeatureConfig> getStructureStartFactory() {
return SDFStructureStart::new;
}
public static class SDFStructureStart extends StructureStart<DefaultFeatureConfig> {
public SDFStructureStart(StructureFeature<DefaultFeatureConfig> feature, int chunkX, int chunkZ, BlockBox box, int references, long seed) {
super(feature, chunkX, chunkZ, box, references, seed);
}
@Override
public void init(DynamicRegistryManager registryManager, ChunkGenerator chunkGenerator, StructureManager manager, int chunkX, int chunkZ, Biome biome, DefaultFeatureConfig config) {
int x = (chunkX << 4) | MHelper.randRange(4, 12, random);
int z = (chunkZ << 4) | MHelper.randRange(4, 12, random);
int y = chunkGenerator.getHeight(x, z, Type.WORLD_SURFACE_WG);
if (y > 50) {
this.children.add(new NBTPiece(STRUCTURE_ID, STRUCTURE, new BlockPos(x, y - 3, z), random.nextInt(5), true, random));
}
this.setBoundingBoxFromChildren();
}
}
}

View file

@ -125,16 +125,7 @@ public class LakePiece extends BasePiece {
BlockState state = chunk.getBlockState(pos);
if (state.getMaterial().isReplaceable() || state.isIn(EndTags.GEN_TERRAIN)) {
if (pos.getY() > 56) {
pos.setY(pos.getY() + 1);
state = chunk.getBlockState(pos);
pos.setY(pos.getY() - 1);
if (state.getMaterial().isReplaceable()) {
state = world.getBiome(pos.add(sx, 0, sz)).getGenerationSettings().getSurfaceConfig().getTopMaterial();
}
else {
state = EndBlocks.ENDSTONE_DUST.getDefaultState();
}
chunk.setBlockState(pos, state, false);
chunk.setBlockState(pos, AIR, false);
}
else if (pos.getY() == 56) {
if (random.nextBoolean()) {

View file

@ -0,0 +1,93 @@
package ru.betterend.world.structures.piece;
import java.util.Random;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.structure.Structure;
import net.minecraft.structure.StructureManager;
import net.minecraft.structure.StructurePlacementData;
import net.minecraft.util.BlockMirror;
import net.minecraft.util.BlockRotation;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import ru.betterend.registry.EndStructures;
import ru.betterend.util.MHelper;
import ru.betterend.util.StructureHelper;
public class NBTPiece extends BasePiece {
private Identifier structureID;
private BlockRotation rotation;
private BlockMirror mirror;
private Structure structure;
private BlockPos pos;
private int erosion;
private boolean cover;
public NBTPiece(Identifier structureID, Structure structure, BlockPos pos, int erosion, boolean cover, Random random) {
super(EndStructures.NBT_PIECE, random.nextInt());
this.structureID = structureID;
this.structure = structure;
this.rotation = BlockRotation.random(random);
this.mirror = BlockMirror.values()[random.nextInt(3)];
this.pos = StructureHelper.offsetPos(pos, structure, rotation, mirror);
this.erosion = erosion;
this.cover = cover;
makeBoundingBox();
}
public NBTPiece(StructureManager manager, CompoundTag tag) {
super(EndStructures.NBT_PIECE, tag);
makeBoundingBox();
}
@Override
protected void toNbt(CompoundTag tag) {
tag.putString("id", structureID.toString());
tag.putInt("rotation", rotation.ordinal());
tag.putInt("mirror", mirror.ordinal());
tag.putInt("erosion", erosion);
tag.put("pos", NbtHelper.fromBlockPos(pos));
tag.putBoolean("cover", cover);
}
@Override
protected void fromNbt(CompoundTag tag) {
structureID = new Identifier(tag.getString("id"));
rotation = BlockRotation.values()[tag.getInt("rotation")];
mirror = BlockMirror.values()[tag.getInt("mirror")];
erosion = tag.getInt("erosion");
pos = NbtHelper.toBlockPos(tag.getCompound("pos"));
cover = tag.getBoolean("cover");
structure = StructureHelper.readStructure(structureID);
}
@Override
public boolean generate(StructureWorldAccess world, StructureAccessor arg, ChunkGenerator chunkGenerator, Random random, BlockBox blockBox, ChunkPos chunkPos, BlockPos blockPos) {
BlockBox bounds = new BlockBox(blockBox);
bounds.maxY = this.boundingBox.maxY;
bounds.minY = this.boundingBox.minY;
StructurePlacementData placementData = new StructurePlacementData().setRotation(rotation).setMirror(mirror).setBoundingBox(bounds);
structure.place(world, pos, placementData, random);
if (erosion > 0) {
bounds.maxX = MHelper.min(bounds.maxX, boundingBox.maxX);
bounds.minX = MHelper.max(bounds.minX, boundingBox.minX);
bounds.maxZ = MHelper.min(bounds.maxZ, boundingBox.maxZ);
bounds.minZ = MHelper.max(bounds.minZ, boundingBox.minZ);
StructureHelper.erode(world, bounds, erosion, random);
}
if (cover) {
StructureHelper.cover(world, bounds, random);
}
return true;
}
private void makeBoundingBox() {
this.boundingBox = StructureHelper.getStructureBounds(pos, structure, rotation, mirror);
}
}