1
0
mirror of https://github.com/chylex/Hardcore-Ender-Expansion-2.git synced 2025-04-11 03:15:44 +02:00

Add base classes for blob generation

This commit is contained in:
chylex 2019-04-29 17:15:31 +02:00
parent c9ba15aadb
commit c0df0be37f
4 changed files with 152 additions and 0 deletions
src/main/java/chylex/hee/game/world/feature/basic/blobs

View File

@ -0,0 +1,67 @@
package chylex.hee.game.world.feature.basic.blobs
import chylex.hee.game.world.generation.SegmentedWorld
import chylex.hee.game.world.generation.segments.SegmentFull
import chylex.hee.init.ModBlocks
import chylex.hee.system.collection.WeightedList
import chylex.hee.system.collection.WeightedList.Companion.weightedListOf
import chylex.hee.system.util.Facing6
import chylex.hee.system.util.allInBoxMutable
import chylex.hee.system.util.max
import net.minecraft.init.Blocks
import net.minecraft.util.math.BlockPos
import java.util.Random
class BlobGenerator(private val patterns: WeightedList<BlobPattern>){
constructor(pattern: BlobPattern) : this(weightedListOf(1 to pattern))
private companion object{
private val SCAFFOLDING = ModBlocks.SCAFFOLDING.defaultState
}
fun generate(world: SegmentedWorld, rand: Random, pos: BlockPos): Boolean{
val pattern = patterns.generateItem(rand)
val generator = pattern.pickGenerator(rand)
val populators = pattern.pickPopulators(rand)
val extraSize = populators.fold(BlockPos.ORIGIN){ acc, populator -> acc.max(populator.expandSizeBy) }
val allocatedSize = generator.size.expand(extraSize)
if (!allocatedSize.toBoundingBox(pos).isInside(world.worldSize.toBoundingBox(BlockPos.ORIGIN))){
return false
}
val blobWorld = SegmentedWorld(rand, allocatedSize, allocatedSize){ SegmentFull(allocatedSize, SCAFFOLDING) }
generator.generate(blobWorld, rand)
runSmoothingPass(blobWorld, adjacentAirCount = 4)
runSmoothingPass(blobWorld, adjacentAirCount = 5)
for(populator in populators){
populator.generate(blobWorld, rand)
}
for(offset in allocatedSize.minPos.allInBoxMutable(allocatedSize.maxPos)){
val state = blobWorld.getState(offset)
if (state !== SCAFFOLDING){
world.setState(pos.add(offset), state)
}
}
for((offset, trigger) in blobWorld.getTriggers()){
world.addTrigger(pos.add(offset), trigger)
}
return true
}
private fun runSmoothingPass(blobWorld: SegmentedWorld, adjacentAirCount: Int){
val size = blobWorld.worldSize
for(pos in size.minPos.allInBoxMutable(size.maxPos)){
if (blobWorld.getBlock(pos) === Blocks.END_STONE && Facing6.count { blobWorld.getState(pos.offset(it)) === SCAFFOLDING } >= adjacentAirCount){
blobWorld.setState(pos, SCAFFOLDING)
}
}
}
}

View File

@ -0,0 +1,36 @@
package chylex.hee.game.world.feature.basic.blobs
import chylex.hee.system.collection.WeightedList
import chylex.hee.system.util.nextInt
import java.util.Random
class BlobPattern private constructor(
private val generators: WeightedList<IBlobGenerator>,
private val populators: Pair<WeightedList<IBlobPopulator>, ((Random) -> Int)>?
){
constructor(generators: WeightedList<IBlobGenerator>) : this(generators, null)
constructor(generators: WeightedList<IBlobGenerator>, populators: WeightedList<IBlobPopulator>, populatorAmount: (Random) -> Int) : this(
generators, populators to populatorAmount
)
constructor(generators: WeightedList<IBlobGenerator>, populators: WeightedList<IBlobPopulator>, populatorAmount: IntRange) : this(
generators, populators to { rand -> rand.nextInt(populatorAmount.start, populatorAmount.endInclusive) }
)
fun pickGenerator(rand: Random): IBlobGenerator{
return generators.generateItem(rand)
}
fun pickPopulators(rand: Random): List<IBlobPopulator>{
val (list, amount) = populators ?: return emptyList()
val remaining = list.mutableCopy()
val picked = mutableListOf<IBlobPopulator>()
repeat(amount(rand)){
remaining.removeItem(rand)?.let(picked::add)
}
return picked
}
}

View File

@ -0,0 +1,37 @@
package chylex.hee.game.world.feature.basic.blobs
import chylex.hee.game.world.generation.SegmentedWorld
import chylex.hee.game.world.util.Size
import chylex.hee.system.util.Facing6
import chylex.hee.system.util.allInCenteredBoxMutable
import chylex.hee.system.util.ceilToInt
import chylex.hee.system.util.distanceSqTo
import chylex.hee.system.util.square
import net.minecraft.block.Block
import net.minecraft.init.Blocks
import net.minecraft.util.math.BlockPos
import java.util.Random
interface IBlobGenerator{
val size: Size
fun generate(world: SegmentedWorld, rand: Random)
companion object{
fun placeBlob(world: SegmentedWorld, center: BlockPos, radius: Double, block: Block = Blocks.END_STONE): Boolean{
val offset = radius.ceilToInt()
if (!world.isInside(center) || Facing6.any { !world.isInside(center.offset(it, offset)) }){
return false
}
val radiusSq = square(radius + 0.5)
for(pos in center.allInCenteredBoxMutable(offset, offset, offset)){
if (pos.distanceSqTo(center) <= radiusSq){
world.setBlock(pos, block)
}
}
return true
}
}
}

View File

@ -0,0 +1,12 @@
package chylex.hee.game.world.feature.basic.blobs
import chylex.hee.game.world.generation.SegmentedWorld
import net.minecraft.util.math.BlockPos
import java.util.Random
interface IBlobPopulator{
@JvmDefault
val expandSizeBy: BlockPos
get() = BlockPos.ORIGIN
fun generate(world: SegmentedWorld, rand: Random)
}