Skip to content

Commit

Permalink
feat(flesh-mound): add chamber decorations such as pillars, orifices,…
Browse files Browse the repository at this point in the history
… etc.
  • Loading branch information
Elenterius committed Dec 24, 2023
1 parent 648650c commit 8f0bdb2
Showing 18 changed files with 439 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -197,7 +197,7 @@ public void onSacrifice(ServerLevel level) {
SoundUtil.broadcastBlockSound(level, pos, ModSoundEvents.CREATOR_SPAWN_MOB);
}

if (level.random.nextFloat() >= sacrificeHandler.getTumorFactor() / 2) {
if (level.random.nextFloat() >= sacrificeHandler.getTumorFactor() / 3) {
PrimordialEcosystem.tryToReplaceBlock(level, pos.below(), ModBlocks.PRIMAL_FLESH.get().defaultBlockState());
}

Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@
import com.github.elenterius.biomancy.world.PrimordialEcosystem;
import com.github.elenterius.biomancy.world.mound.MoundChamber;
import com.github.elenterius.biomancy.world.mound.MoundShape;
import com.github.elenterius.biomancy.world.mound.decorator.ChamberDecorator;
import com.github.elenterius.biomancy.world.mound.decorator.ChamberSpecialDecorator;
import com.github.elenterius.biomancy.world.spatial.SpatialShapeManager;
import com.github.elenterius.biomancy.world.spatial.geometry.HasRadius;
import com.github.elenterius.biomancy.world.spatial.geometry.Shape;
@@ -54,9 +56,9 @@

public class FleshVeinsBlock extends MultifaceBlock implements SimpleWaterloggedBlock {

public static final Predicate<BlockState> BLOCKS_TO_AVOID_PREDICATE = blockState -> blockState.is(ModBlocks.MALIGNANT_BLOOM.get());
protected static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
protected static final EnhancedIntegerProperty CHARGE = ModBlockProperties.CHARGE;
public static final Predicate<BlockState> BLOCKS_TO_AVOID_PREDICATE = blockState -> blockState.is(ModBlocks.MALIGNANT_BLOOM.get());
private final MultifaceSpreader spreader = new MultifaceSpreader(new MalignantFleshSpreaderConfig(this));

public FleshVeinsBlock(Properties properties) {
@@ -75,8 +77,8 @@ public static boolean convert(BlockState state, ServerLevel level, BlockPos pos,
facesSet.set(0, hasFace(state, Direction.EAST));

if (mound != null) {
MoundChamber chamber = mound.getChamberAt(pos.getX(), pos.getY(), pos.getZ());
if (chamber != null) {
MoundChamber chamber = mound.getChamberAt(pos);
if (chamber != null && chamber.contains(pos)) {
return convertInsideChamber(level, pos, directNeighbors, mound, chamber, nearBoundingCenterPct, facesSet, energyHandler);
}
}
@@ -124,37 +126,51 @@ protected static boolean convertInsideChamber(ServerLevel level, BlockPos pos, i
ArrayUtil.shuffle(axisDirections, level.random);

for (Direction axisDirection : axisDirections) {
BlockPos posRelative = pos.relative(axisDirection);
BlockState stateRelative = level.getBlockState(posRelative);
BlockPos closeOffsetPos = pos.relative(axisDirection);
BlockState closeOffsetState = level.getBlockState(closeOffsetPos);

if (PrimordialEcosystem.isReplaceable(stateRelative)) {
return destroyBlockAndConvertIntoEnergy(level, posRelative, energyHandler, 15);
if (PrimordialEcosystem.isReplaceable(closeOffsetState)) {
return destroyBlockAndConvertIntoEnergy(level, closeOffsetPos, energyHandler, 15);
}

if (PrimordialEcosystem.FULL_FLESH_BLOCKS.contains(stateRelative.getBlock())) {
if (chamber.contains(posRelative.getX(), posRelative.getY(), posRelative.getZ())) {
return destroyBlockAndConvertIntoEnergy(level, posRelative, energyHandler, 30); //TODO: this might interfere with future room content generation
}
if (PrimordialEcosystem.FULL_FLESH_BLOCKS.contains(closeOffsetState.getBlock())) {
ChamberDecorator chamberDecorator = chamber.getDecorator();

BlockPos posRelative2 = pos.relative(axisDirection, 2);
BlockState stateRelative2 = level.getBlockState(posRelative2);
boolean chamberContainsCloseOffsetPos = chamber.contains(closeOffsetPos);

// create "Door" between two adjacent chambers
MoundChamber neighborChamber = mound.getChamberAt(posRelative2.getX(), posRelative2.getY(), posRelative2.getZ());
if (neighborChamber != null && neighborChamber != chamber) {
return level.setBlock(posRelative, ModBlocks.PRIMAL_PERMEABLE_MEMBRANE.get().defaultBlockState(), Block.UPDATE_CLIENTS);
if (chamberContainsCloseOffsetPos) {
ChamberDecorator.PartOfDecorationResult result = chamberDecorator.isBlockPartOfDecoration(chamber, level, closeOffsetPos, closeOffsetState);
if (result.positionIsValid && !result.materialIsValid && !closeOffsetState.is(ModBlocks.BLOOMLIGHT.get())) {
return destroyBlockAndConvertIntoEnergy(level, closeOffsetPos, energyHandler, 30);
}
}

boolean isFleshBlock = PrimordialEcosystem.FULL_FLESH_BLOCKS.contains(stateRelative2.getBlock());
if (chamberDecorator.canPlace(chamber, level, pos, axisDirection)) {
return chamberDecorator.place(chamber, level, pos, axisDirection);
}

BlockPos farOffsetPos = pos.relative(axisDirection, 2);
BlockState farOffsetState = level.getBlockState(farOffsetPos);

if (!chamberContainsCloseOffsetPos) {
// create "Door" between two adjacent chambers that are separated by a one block thick wall
boolean hasNoChamberAtPos = mound.getChamberAt(closeOffsetPos) == null;
if (hasNoChamberAtPos) {
MoundChamber farChamber = mound.getChamberAt(farOffsetPos);
if (farChamber != null && farChamber != chamber) {
return level.setBlock(closeOffsetPos, ModBlocks.PRIMAL_PERMEABLE_MEMBRANE.get().defaultBlockState(), Block.UPDATE_CLIENTS);
}
}
}

// create light source in dark corners
if (isFleshBlock && axisDirection == Direction.UP && LevelUtil.getMaxBrightness(level, pos) < 5) {
return level.setBlock(posRelative, ModBlocks.BLOOMLIGHT.get().defaultBlockState(), Block.UPDATE_CLIENTS);
// create light source in dark areas
if (ChamberSpecialDecorator.BLOOMLIGHT.canDecorate(chamber, level, pos, axisDirection, closeOffsetPos, closeOffsetState, farOffsetPos, farOffsetState)) {
return ChamberSpecialDecorator.BLOOMLIGHT.decorate(chamber, level, pos, axisDirection, closeOffsetPos, closeOffsetState, farOffsetPos, farOffsetState);
}

if (PrimordialEcosystem.isReplaceable(stateRelative2) && stateRelative2.isCollisionShapeFullBlock(level, posRelative2)) {
if (PrimordialEcosystem.isReplaceable(farOffsetState) && farOffsetState.isCollisionShapeFullBlock(level, farOffsetPos)) {
BlockState replacementState = level.random.nextFloat() < nearBoundingCenterPct ? ModBlocks.PRIMAL_FLESH.get().defaultBlockState() : ModBlocks.MALIGNANT_FLESH.get().defaultBlockState();
return level.setBlock(posRelative2, replacementState, Block.UPDATE_CLIENTS);
return level.setBlock(farOffsetPos, replacementState, Block.UPDATE_CLIENTS);
}
}
}
@@ -502,11 +518,11 @@ public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource
energyHandler = peh;
}

Shape boundingShape = mound.getBoundingShapeAt(pos.getX(), pos.getY(), pos.getZ());
Shape boundingShape = mound.getBoundingShapeAt(pos);
if (boundingShape != null) {
double radius = boundingShape instanceof HasRadius sphere ? sphere.getRadius() : boundingShape.getAABB().getSize() / 2;
double radiusSqr = radius * radius;
double distSqr = boundingShape.distanceToSqr(pos.getX(), pos.getY(), pos.getZ());
double distSqr = boundingShape.distanceToSqr(pos.getX() + 0.5d, pos.getY() + 0.5d, pos.getZ() + 0.5d);
nearBoundingCenterPct = Mth.clamp((float) (1 - distSqr / radiusSqr), 0f, 1f);
}
}
Original file line number Diff line number Diff line change
@@ -34,8 +34,8 @@ public boolean intersectsCuboid(double minX, double minY, double minZ, double ma
}

@Override
public Vec3 getCenter() {
return shape.getCenter();
public Vec3 center() {
return shape.center();
}

@Override
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
package com.github.elenterius.biomancy.world.mound;

import com.github.elenterius.biomancy.world.mound.decorator.ChamberDecorator;
import com.github.elenterius.biomancy.world.spatial.geometry.Shape;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;

public interface Chamber {
Vec3 getOrigin();
public interface Chamber extends Shape {

int seed();

ChamberDecorator getDecorator();

Vec3 origin();

// default boolean containsValidBlock(Level level, BlockPos pos, BlockState blockState) {
// if (!contains(pos)) return false;
// ChamberDecorator.Result result = getDecorator().isBlockPartOfDecoration(this, level, pos, blockState);
// return result == ChamberDecorator.Result.POSITION_IS_VALID_AND_MATERIAL_IS_INVALID;
// }

default boolean contains(BlockPos pos) {
return contains(pos.getX() + 0.5d, pos.getY() + 0.5d, pos.getZ() + 0.5d);
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.github.elenterius.biomancy.world.mound;

import com.github.elenterius.biomancy.world.mound.decorator.ChamberDecorators;
import com.github.elenterius.biomancy.world.spatial.geometry.OctantEllipsoidShape;
import com.github.elenterius.biomancy.world.spatial.geometry.SphereShape;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.SimpleWeightedRandomList;

import java.util.function.Consumer;

public interface ChambersGenerator {
void generate(double x, double y, double z, float chamberRadius, Consumer<MoundChamber> consumer);
public interface ChamberFactory {
void create(double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer);

ChambersGenerator ONE_SPHERE = (double x, double y, double z, float chamberRadius, Consumer<MoundChamber> consumer) -> {
consumer.accept(new MoundChamber(new SphereShape(x, y, z, chamberRadius)));
};
ChamberFactory ONE_SPHERE = (double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer) -> consumer.accept(new MoundChamber(new SphereShape(x, y, z, chamberRadius)));

ChambersGenerator EIGHT_SMALL_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, Consumer<MoundChamber> consumer) -> {
ChamberFactory EIGHT_SMALL_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer) -> {
float halfR = chamberRadius / 2;
float quarterR = halfR / 2;
float p = chamberRadius / 3.8f; // radius / 4.25f
@@ -28,20 +28,7 @@ public interface ChambersGenerator {
consumer.accept(new MoundChamber(new OctantEllipsoidShape(x - p, y - p, z - p, quarterR, quarterR, quarterR, halfR, halfR, halfR)));
};

ChambersGenerator SPECIAL_CRADLE = (double x, double y, double z, float chamberRadius, Consumer<MoundChamber> consumer) -> {
float halfR = chamberRadius / 2;
float quarterR = halfR / 2;
float p = chamberRadius / 3.8f; // radius / 4.25f

consumer.accept(new MoundChamber(new OctantEllipsoidShape(x, y + p - 1, z, halfR, halfR, halfR, halfR, quarterR, halfR)));

consumer.accept(new MoundChamber(new OctantEllipsoidShape(x + p, y - p, z + p, halfR, quarterR, halfR, quarterR, halfR, quarterR)));
consumer.accept(new MoundChamber(new OctantEllipsoidShape(x - p, y - p, z + p, quarterR, quarterR, halfR, halfR, halfR, quarterR)));
consumer.accept(new MoundChamber(new OctantEllipsoidShape(x + p, y - p, z - p, halfR, quarterR, quarterR, quarterR, halfR, halfR)));
consumer.accept(new MoundChamber(new OctantEllipsoidShape(x - p, y - p, z - p, quarterR, quarterR, quarterR, halfR, halfR, halfR)));
};

ChambersGenerator ONE_BIG_FOUR_SMALL_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, Consumer<MoundChamber> consumer) -> {
ChamberFactory ONE_BIG_FOUR_SMALL_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer) -> {
float halfR = chamberRadius / 2;
float quarterR = halfR / 2;
float p = chamberRadius / 3.8f; // radius / 4.25f
@@ -54,7 +41,7 @@ public interface ChambersGenerator {
consumer.accept(new MoundChamber(new OctantEllipsoidShape(x - p, y - p, z - p, quarterR, quarterR, quarterR, halfR, halfR, halfR)));
};

ChambersGenerator FOUR_SMALL_ONE_BIG_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, Consumer<MoundChamber> consumer) -> {
ChamberFactory FOUR_SMALL_ONE_BIG_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer) -> {
float halfR = chamberRadius / 2;
float quarterR = halfR / 2;
float p = chamberRadius / 3.8f; // radius / 4.25f
@@ -67,7 +54,7 @@ public interface ChambersGenerator {
consumer.accept(new MoundChamber(new OctantEllipsoidShape(x, y - p, z, halfR, quarterR, halfR, halfR, halfR, halfR)));
};

ChambersGenerator TWO_BIG_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, Consumer<MoundChamber> consumer) -> {
ChamberFactory TWO_BIG_ELLIPSOIDS = (double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer) -> {
float halfR = chamberRadius / 2;
float quarterR = halfR / 2;
float p = chamberRadius / 3.8f; // radius / 4.25f
@@ -76,12 +63,41 @@ public interface ChambersGenerator {
consumer.accept(new MoundChamber(new OctantEllipsoidShape(x, y - p, z, halfR, quarterR, halfR, halfR, halfR, halfR)));
};

SimpleWeightedRandomList<ChambersGenerator> RANDOM_DEFAULT = SimpleWeightedRandomList.<ChambersGenerator>builder()
ChamberFactory SPECIAL_CRADLE = (double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer) -> {
float halfR = chamberRadius / 2;
float quarterR = halfR / 2;
float p = chamberRadius / 3.8f; // radius / 4.25f

consumer.accept(new MoundChamber(new OctantEllipsoidShape(x, y + p - 1, z, halfR, halfR, halfR, halfR, quarterR, halfR)));

Consumer<MoundChamber> wrappedConsumer = chamber -> {
chamber.setDecorator(ChamberDecorators.PRIMAL_ORIFICE_COMBS, random.nextInt());
consumer.accept(chamber);
};

wrappedConsumer.accept(new MoundChamber(new OctantEllipsoidShape(x + p, y - p, z + p, halfR, quarterR, halfR, quarterR, halfR, quarterR)));
wrappedConsumer.accept(new MoundChamber(new OctantEllipsoidShape(x - p, y - p, z + p, quarterR, quarterR, halfR, halfR, halfR, quarterR)));
wrappedConsumer.accept(new MoundChamber(new OctantEllipsoidShape(x + p, y - p, z - p, halfR, quarterR, quarterR, quarterR, halfR, halfR)));
wrappedConsumer.accept(new MoundChamber(new OctantEllipsoidShape(x - p, y - p, z - p, quarterR, quarterR, quarterR, halfR, halfR, halfR)));
};

SimpleWeightedRandomList<ChamberFactory> RANDOM_DEFAULTS_LIST = SimpleWeightedRandomList.<ChamberFactory>builder()
.add(ONE_SPHERE, 5)
.add(ONE_BIG_FOUR_SMALL_ELLIPSOIDS, 20)
.add(FOUR_SMALL_ONE_BIG_ELLIPSOIDS, 20)
.add(TWO_BIG_ELLIPSOIDS, 10)
.add(EIGHT_SMALL_ELLIPSOIDS, 60)
.build();

ChamberFactory RANDOM_DEFAULT = (double x, double y, double z, float chamberRadius, RandomSource random, Consumer<MoundChamber> consumer) -> {
ChamberFactory factory = RANDOM_DEFAULTS_LIST.getRandomValue(random).orElse(ChamberFactory.EIGHT_SMALL_ELLIPSOIDS);

Consumer<MoundChamber> wrappedConsumer = chamber -> {
chamber.setDecorator(ChamberDecorators.getRandomDefault(random), random.nextInt());
consumer.accept(chamber);
};

factory.create(x, y, z, chamberRadius, random, wrappedConsumer);
};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.github.elenterius.biomancy.world.mound;

enum ChamberFactoryType {
DEFAULT, CRADLE, END_CAP_MAIN_SPIRE, END_CAP_SUB_SPIRE
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.github.elenterius.biomancy.world.mound;

import com.github.elenterius.biomancy.util.serialization.NBTSerializer;
import com.github.elenterius.biomancy.world.mound.decorator.ChamberDecorator;
import com.github.elenterius.biomancy.world.mound.decorator.ChamberDecorators;
import com.github.elenterius.biomancy.world.spatial.geometry.Shape;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;

public class MoundChamber implements Chamber, Shape {
public class MoundChamber implements Chamber {
private final Shape shape;
private final Vec3 origin;
private int seed = 1337;
private ChamberDecorator chamberDecorator = ChamberDecorators.EMPTY;

public MoundChamber(Vec3 origin, Shape shape) {
this.shape = shape;
@@ -16,7 +20,7 @@ public MoundChamber(Vec3 origin, Shape shape) {

public MoundChamber(Shape shape) {
this.shape = shape;
origin = shape.getCenter();
origin = shape.center();
}

@Override
@@ -30,12 +34,27 @@ public boolean intersectsCuboid(double minX, double minY, double minZ, double ma
}

@Override
public Vec3 getCenter() {
return shape.getCenter();
public Vec3 center() {
return shape.center();
}

@Override
public Vec3 getOrigin() {
public int seed() {
return seed;
}

public void setDecorator(ChamberDecorator chamberDecorator, int seed) {
this.chamberDecorator = chamberDecorator;
this.seed = seed;
}

@Override
public ChamberDecorator getDecorator() {
return chamberDecorator;
}

@Override
public Vec3 origin() {
return origin;
}

Loading

0 comments on commit 8f0bdb2

Please sign in to comment.