Giant Mushroom

This commit is contained in:
paulevsGitch 2020-10-06 12:26:13 +03:00
parent 2afdc1e2eb
commit 150b005257
12 changed files with 288 additions and 6 deletions

View file

@ -14,6 +14,7 @@ import ru.betterend.registry.FeatureRegistry;
import ru.betterend.registry.ItemRegistry; import ru.betterend.registry.ItemRegistry;
import ru.betterend.registry.ItemTagRegistry; import ru.betterend.registry.ItemTagRegistry;
import ru.betterend.registry.SoundRegistry; import ru.betterend.registry.SoundRegistry;
import ru.betterend.registry.StructureRegistry;
import ru.betterend.util.Logger; import ru.betterend.util.Logger;
import ru.betterend.world.generator.BetterEndBiomeSource; import ru.betterend.world.generator.BetterEndBiomeSource;
import ru.betterend.world.surface.DoubleBlockSurfaceBuilder; import ru.betterend.world.surface.DoubleBlockSurfaceBuilder;
@ -38,6 +39,7 @@ public class BetterEnd implements ModInitializer {
BlockTagRegistry.register(); BlockTagRegistry.register();
CraftingRecipes.register(); CraftingRecipes.register();
AlloyingRecipes.register(); AlloyingRecipes.register();
StructureRegistry.register();
} }
public static Identifier makeID(String path) { public static Identifier makeID(String path) {

View file

@ -2,11 +2,18 @@ package ru.betterend.registry;
import net.minecraft.structure.StructurePieceType; import net.minecraft.structure.StructurePieceType;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import net.minecraft.world.gen.GenerationStep.Feature;
import ru.betterend.BetterEnd; import ru.betterend.BetterEnd;
import ru.betterend.world.structures.EndStructureFeature;
import ru.betterend.world.structures.features.StructureGiantMossyGlowshroom;
import ru.betterend.world.structures.piece.VoxelPiece; import ru.betterend.world.structures.piece.VoxelPiece;
public class StructureRegistry { public class StructureRegistry {
public static final StructurePieceType VOXEL_PIECE = register("sdf", VoxelPiece::new); public static final StructurePieceType VOXEL_PIECE = register("voxel", VoxelPiece::new);
public static final EndStructureFeature GIANT_MOSSY_GLOWSHROOM = new EndStructureFeature("giant_mossy_glowshroom", new StructureGiantMossyGlowshroom(), Feature.RAW_GENERATION, 32, 8);
public static void register() {}
private static StructurePieceType register(String id, StructurePieceType pieceType) { private static StructurePieceType register(String id, StructurePieceType pieceType) {
return Registry.register(Registry.STRUCTURE_PIECE, BetterEnd.makeID(id), pieceType); return Registry.register(Registry.STRUCTURE_PIECE, BetterEnd.makeID(id), pieceType);

View file

@ -12,6 +12,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.world.ServerWorldAccess; import net.minecraft.world.ServerWorldAccess;
import ru.betterend.util.BlocksHelper; import ru.betterend.util.BlocksHelper;
import ru.betterend.world.structures.StructureWorld;
public abstract class SDF { public abstract class SDF {
private Function<PosInfo, BlockState> postProcess = (info) -> { private Function<PosInfo, BlockState> postProcess = (info) -> {
@ -120,4 +121,44 @@ public abstract class SDF {
return mapWorld.keySet(); return mapWorld.keySet();
} }
public Set<BlockPos> fillRecursive(StructureWorld world, BlockPos start) {
Map<BlockPos, PosInfo> mapWorld = Maps.newHashMap();
Set<BlockPos> blocks = Sets.newHashSet();
Set<BlockPos> ends = Sets.newHashSet();
Set<BlockPos> add = Sets.newHashSet();
ends.add(new BlockPos(0, 0, 0));
boolean run = true;
while (run) {
for (BlockPos center: ends) {
for (Direction dir: Direction.values()) {
BlockPos pos = center.offset(dir);
BlockPos wpos = pos.add(start);
if (!blocks.contains(pos)) {
if (this.getDistance(pos.getX(), pos.getY(), pos.getZ()) < 0) {
BlockState state = getBlockState(wpos);
PosInfo.create(mapWorld, wpos).setState(state);
add.add(pos);
}
}
}
}
blocks.addAll(ends);
ends.clear();
ends.addAll(add);
add.clear();
run &= !ends.isEmpty();
}
mapWorld.forEach((pos, info) -> {
BlockState state = postProcess.apply(info);
world.setBlock(pos, state);
});
return mapWorld.keySet();
}
} }

View file

@ -0,0 +1,15 @@
package ru.betterend.util.sdf.operator;
public class SDFRound extends SDFUnary {
private float radius;
public SDFRound setRadius(float radius) {
this.radius = radius;
return this;
}
@Override
public float getDistance(float x, float y, float z) {
return this.source.getDistance(x, y, z) - radius;
}
}

View file

@ -33,6 +33,7 @@ import net.minecraft.world.gen.surfacebuilder.TernarySurfaceConfig;
import ru.betterend.BetterEnd; import ru.betterend.BetterEnd;
import ru.betterend.util.MHelper; import ru.betterend.util.MHelper;
import ru.betterend.world.features.EndFeature; import ru.betterend.world.features.EndFeature;
import ru.betterend.world.structures.EndStructureFeature;
import ru.betterend.world.surface.DoubleBlockSurfaceBuilder; import ru.betterend.world.surface.DoubleBlockSurfaceBuilder;
public class BiomeDefinition { public class BiomeDefinition {
@ -112,6 +113,11 @@ public class BiomeDefinition {
return this; return this;
} }
public BiomeDefinition addStructureFeature(EndStructureFeature feature) {
structures.add(feature.getFeatureConfigured());
return this;
}
public BiomeDefinition addFeature(EndFeature feature) { public BiomeDefinition addFeature(EndFeature feature) {
FeatureInfo info = new FeatureInfo(); FeatureInfo info = new FeatureInfo();
info.featureStep = feature.getFeatureStep(); info.featureStep = feature.getFeatureStep();

View file

@ -6,6 +6,7 @@ import ru.betterend.registry.EntityRegistry;
import ru.betterend.registry.FeatureRegistry; import ru.betterend.registry.FeatureRegistry;
import ru.betterend.registry.ParticleRegistry; import ru.betterend.registry.ParticleRegistry;
import ru.betterend.registry.SoundRegistry; import ru.betterend.registry.SoundRegistry;
import ru.betterend.registry.StructureRegistry;
public class BiomeFoggyMushroomland extends EndBiome { public class BiomeFoggyMushroomland extends EndBiome {
public BiomeFoggyMushroomland() { public BiomeFoggyMushroomland() {
@ -18,6 +19,7 @@ public class BiomeFoggyMushroomland extends EndBiome {
.setParticles(ParticleRegistry.GLOWING_SPHERE, 0.001F) .setParticles(ParticleRegistry.GLOWING_SPHERE, 0.001F)
.setLoop(SoundRegistry.AMBIENT_FOGGY_MUSHROOMLAND) .setLoop(SoundRegistry.AMBIENT_FOGGY_MUSHROOMLAND)
.setMusic(SoundRegistry.MUSIC_FOGGY_MUSHROOMLAND) .setMusic(SoundRegistry.MUSIC_FOGGY_MUSHROOMLAND)
.addStructureFeature(StructureRegistry.GIANT_MOSSY_GLOWSHROOM)
.addFeature(FeatureRegistry.ENDER_ORE) .addFeature(FeatureRegistry.ENDER_ORE)
.addFeature(FeatureRegistry.END_LAKE) .addFeature(FeatureRegistry.END_LAKE)
.addFeature(FeatureRegistry.MOSSY_GLOWSHROOM) .addFeature(FeatureRegistry.MOSSY_GLOWSHROOM)

View file

@ -78,10 +78,6 @@ public class MossyGlowshroomFeature extends DefaultFeature {
Vector3f pos = spline.get(spline.size() - 1); Vector3f pos = spline.get(spline.size() - 1);
float scale = MHelper.randRange(0.75F, 1.1F, random); float scale = MHelper.randRange(0.75F, 1.1F, random);
if (featureConfig != null && random.nextInt(32) == 0) {
scale *= MHelper.randRange(2F, 3F, random);
}
Vector3f vec = spline.get(0); Vector3f vec = spline.get(0);
float x1 = blockPos.getX() + vec.getX() * scale; float x1 = blockPos.getX() + vec.getX() * scale;
float y1 = blockPos.getY() + vec.getY() * scale; float y1 = blockPos.getY() + vec.getY() * scale;

View file

@ -21,7 +21,7 @@ public class VineFeature extends InvertedScatterFeature {
@Override @Override
public boolean canGenerate(StructureWorldAccess world, Random random, BlockPos center, BlockPos blockPos, float radius) { public boolean canGenerate(StructureWorldAccess world, Random random, BlockPos center, BlockPos blockPos, float radius) {
return vineBlock.canPlaceAt(AIR, world, blockPos); return world.isAir(blockPos) && vineBlock.canPlaceAt(AIR, world, blockPos);
} }
@Override @Override

View file

@ -0,0 +1,46 @@
package ru.betterend.world.structures;
import java.util.Random;
import net.fabricmc.fabric.api.structure.v1.FabricStructureBuilder;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import ru.betterend.BetterEnd;
public class EndStructureFeature {
private static final Random RANDOM = new Random(354);
private final StructureFeature<DefaultFeatureConfig> structure;
private final ConfiguredStructureFeature<?, ?> featureConfigured;
private final GenerationStep.Feature featureStep;
public EndStructureFeature(String name, StructureFeature<DefaultFeatureConfig> structure, GenerationStep.Feature step, int spacing, int separation) {
Identifier id = BetterEnd.makeID(name);
this.featureStep = step;
this.structure = FabricStructureBuilder.create(id, structure)
.step(step)
.defaultConfig(spacing, separation, RANDOM.nextInt(8192))
.adjustsSurface()
.register();
this.featureConfigured = this.structure.configure(DefaultFeatureConfig.DEFAULT);
BuiltinRegistries.add(BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE, id, this.featureConfigured);
}
public StructureFeature<DefaultFeatureConfig> getStructure() {
return structure;
}
public ConfiguredStructureFeature<?, ?> getFeatureConfigured() {
return featureConfigured;
}
public GenerationStep.Feature getFeatureStep() {
return featureStep;
}
}

View file

@ -0,0 +1,47 @@
package ru.betterend.world.structures.features;
import java.util.Random;
import net.minecraft.structure.StructureManager;
import net.minecraft.structure.StructureStart;
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.util.MHelper;
import ru.betterend.util.sdf.SDF;
import ru.betterend.world.structures.piece.VoxelPiece;
public abstract class SDFStructureFeature extends StructureFeature<DefaultFeatureConfig> {
public SDFStructureFeature() {
super(DefaultFeatureConfig.CODEC);
}
protected abstract SDF getSDF(BlockPos pos, Random random);
@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);
BlockPos start = new BlockPos(x, y, z);
VoxelPiece piece = new VoxelPiece((world) -> { ((SDFStructureFeature) this.getFeature()).getSDF(start, this.random).fillRecursive(world, start); }, random.nextInt());
this.children.add(piece);
this.boundingBox = piece.getBoundingBox();
}
}
}

View file

@ -0,0 +1,119 @@
package ru.betterend.world.structures.features;
import java.util.List;
import java.util.Random;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import ru.betterend.blocks.BlockMossyGlowshroomCap;
import ru.betterend.noise.OpenSimplexNoise;
import ru.betterend.registry.BlockRegistry;
import ru.betterend.util.MHelper;
import ru.betterend.util.SplineHelper;
import ru.betterend.util.sdf.SDF;
import ru.betterend.util.sdf.operator.SDFBinary;
import ru.betterend.util.sdf.operator.SDFCoordModify;
import ru.betterend.util.sdf.operator.SDFFlatWave;
import ru.betterend.util.sdf.operator.SDFRound;
import ru.betterend.util.sdf.operator.SDFScale;
import ru.betterend.util.sdf.operator.SDFScale3D;
import ru.betterend.util.sdf.operator.SDFSmoothUnion;
import ru.betterend.util.sdf.operator.SDFSubtraction;
import ru.betterend.util.sdf.operator.SDFTranslate;
import ru.betterend.util.sdf.operator.SDFUnion;
import ru.betterend.util.sdf.primitive.SDFCapedCone;
import ru.betterend.util.sdf.primitive.SDFPrimitive;
import ru.betterend.util.sdf.primitive.SDFSphere;
public class StructureGiantMossyGlowshroom extends SDFStructureFeature {
private static final BlockState AIR = Blocks.AIR.getDefaultState();
@Override
protected SDF getSDF(BlockPos center, Random random) {
System.out.println(center);
SDFCapedCone cone1 = new SDFCapedCone().setHeight(2.5F).setRadius1(1.5F).setRadius2(2.5F);
SDFCapedCone cone2 = new SDFCapedCone().setHeight(3F).setRadius1(2.5F).setRadius2(13F);
SDF posedCone2 = new SDFTranslate().setTranslate(0, 5, 0).setSource(cone2);
SDF posedCone3 = new SDFTranslate().setTranslate(0, 12F, 0).setSource(new SDFScale().setScale(2).setSource(cone2));
SDF upCone = new SDFSubtraction().setSourceA(posedCone2).setSourceB(posedCone3);
SDF wave = new SDFFlatWave().setRaysCount(12).setIntensity(1.3F).setSource(upCone);
SDF cones = new SDFSmoothUnion().setRadius(3).setSourceA(cone1).setSourceB(wave);
SDF innerCone = new SDFTranslate().setTranslate(0, 1.25F, 0).setSource(upCone);
innerCone = new SDFScale3D().setScale(1.2F, 1F, 1.2F).setSource(innerCone);
cones = new SDFUnion().setSourceA(cones).setSourceB(innerCone);
SDF glowCone = new SDFCapedCone().setHeight(3F).setRadius1(2F).setRadius2(12.5F);
SDFPrimitive priGlowCone = (SDFPrimitive) glowCone;
glowCone = new SDFTranslate().setTranslate(0, 4.25F, 0).setSource(glowCone);
glowCone = new SDFSubtraction().setSourceA(glowCone).setSourceB(posedCone3);
cones = new SDFUnion().setSourceA(cones).setSourceB(glowCone);
OpenSimplexNoise noise = new OpenSimplexNoise(1234);
cones = new SDFCoordModify().setFunction((pos) -> {
float dist = MHelper.length(pos.getX(), pos.getZ());
float y = pos.getY() + (float) noise.eval(pos.getX() * 0.1 + center.getX(), pos.getZ() * 0.1 + center.getZ()) * dist * 0.3F - dist * 0.15F;
pos.set(pos.getX(), y, pos.getZ());
}).setSource(cones);
SDFTranslate HEAD_POS = (SDFTranslate) new SDFTranslate().setSource(new SDFTranslate().setTranslate(0, 2.5F, 0).setSource(cones));
SDF roots = new SDFSphere().setRadius(4F);
SDFPrimitive primRoots = (SDFPrimitive) roots;
roots = new SDFScale3D().setScale(1, 0.7F, 1).setSource(roots);
SDFFlatWave rotRoots = (SDFFlatWave) new SDFFlatWave().setRaysCount(5).setIntensity(1.5F).setSource(roots);
SDFBinary function = new SDFSmoothUnion().setRadius(4).setSourceB(new SDFUnion().setSourceA(HEAD_POS).setSourceB(rotRoots));
cone1.setBlock(BlockRegistry.MOSSY_GLOWSHROOM_CAP);
cone2.setBlock(BlockRegistry.MOSSY_GLOWSHROOM_CAP);
priGlowCone.setBlock(BlockRegistry.MOSSY_GLOWSHROOM_HYMENOPHORE);
primRoots.setBlock(BlockRegistry.MOSSY_GLOWSHROOM.bark);
float height = MHelper.randRange(10F, 25F, random);
int count = MHelper.floor(height / 4);
List<Vector3f> spline = SplineHelper.makeSpline(0, 0, 0, 0, height, 0, count);
SplineHelper.offsetParts(spline, random, 1F, 0, 1F);
SDF sdf = SplineHelper.buildSDF(spline, 2.1F, 1.5F, (pos) -> {
return BlockRegistry.MOSSY_GLOWSHROOM.log.getDefaultState();
});
Vector3f pos = spline.get(spline.size() - 1);
float scale = MHelper.randRange(2F, 3.5F, random);
HEAD_POS.setTranslate(pos.getX(), pos.getY(), pos.getZ());
rotRoots.setAngle(random.nextFloat() * MHelper.PI2);
function.setSourceA(sdf);
return new SDFRound().setRadius(1.5F).setSource(new SDFScale()
.setScale(scale)
.setSource(function)
.setPostProcess((info) -> {
if (BlockRegistry.MOSSY_GLOWSHROOM.isTreeLog(info.getState())) {
if (!BlockRegistry.MOSSY_GLOWSHROOM.isTreeLog(info.getStateUp()) || !BlockRegistry.MOSSY_GLOWSHROOM.isTreeLog(info.getStateDown())) {
return BlockRegistry.MOSSY_GLOWSHROOM.bark.getDefaultState();
}
}
else if (info.getState().getBlock() == BlockRegistry.MOSSY_GLOWSHROOM_CAP) {
if (BlockRegistry.MOSSY_GLOWSHROOM.isTreeLog(info.getStateDown())) {
return info.getState().with(BlockMossyGlowshroomCap.TRANSITION, true);
}
int air = 0;
for (Direction dir: Direction.values()) {
if (info.getState(dir).isAir()) {
air ++;
}
}
if (air > 4) {
info.setState(AIR);
return AIR;
}
}
return info.getState();
}));
}
}

View file

@ -39,6 +39,7 @@ public class VoxelPiece extends BasePiece {
@Override @Override
public boolean generate(StructureWorldAccess world, StructureAccessor arg, ChunkGenerator chunkGenerator, Random random, BlockBox blockBox, ChunkPos chunkPos, BlockPos blockPos) { public boolean generate(StructureWorldAccess world, StructureAccessor arg, ChunkGenerator chunkGenerator, Random random, BlockBox blockBox, ChunkPos chunkPos, BlockPos blockPos) {
this.world.placeChunk(world, chunkPos);
return true; return true;
} }
} }