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

Work on Forgotten Tombs territory (entrance cave generation & WIP environment)

This commit is contained in:
chylex 2019-06-11 20:39:53 +02:00
parent 0f0ac01a9d
commit 9ac23a0cdf
3 changed files with 291 additions and 3 deletions
src/main/java/chylex/hee/game/world/territory

View File

@ -1,5 +1,7 @@
package chylex.hee.game.world.territory
import chylex.hee.game.world.territory.descriptions.Territory_ForgottenTombs
import chylex.hee.game.world.territory.descriptions.Territory_TheHub
import chylex.hee.game.world.territory.generators.Generator_ForgottenTombs
import chylex.hee.game.world.territory.generators.Generator_TheHub
import chylex.hee.game.world.util.Size
import kotlin.math.abs
@ -21,10 +23,10 @@ enum class TerritoryType(
FORGOTTEN_TOMBS(
title = "forgotten_tombs",
desc = Territory_TheHub, // TODO
gen = Generator_TheHub, // TODO
desc = Territory_ForgottenTombs,
gen = Generator_ForgottenTombs,
chunks = 28,
height = 0 until 256
height = 64 until 256
);
companion object{

View File

@ -0,0 +1,67 @@
package chylex.hee.game.world.territory.descriptions
import chylex.hee.client.util.MC
import chylex.hee.game.world.territory.ITerritoryDescription
import chylex.hee.game.world.territory.properties.TerritoryColors
import chylex.hee.game.world.territory.properties.TerritoryEnvironment
import chylex.hee.system.util.Pos
import chylex.hee.system.util.color.RGB
import chylex.hee.system.util.lookPosVec
import chylex.hee.system.util.math.LerpedFloat
import chylex.hee.system.util.nextFloat
import net.minecraft.util.math.Vec3d
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
import java.util.Random
import kotlin.math.pow
object Territory_ForgottenTombs : ITerritoryDescription{
override val colors = object : TerritoryColors(){
override val tokenTop = RGB(211, 212, 152)
override val tokenBottom = RGB(160, 151, 116)
override val portalSeed = 410L
override fun nextPortalColor(rand: Random, color: FloatArray){
if (rand.nextBoolean()){
color[0] = rand.nextFloat(0.65F, 0.9F)
color[1] = rand.nextFloat(0.45F, 0.7F)
color[2] = rand.nextFloat(0.15F, 0.4F)
}
else{
color.fill(rand.nextFloat(0.95F, 1F))
}
}
}
private const val MAX_FOG_DENSITY = 0.087F
override val environment = object : TerritoryEnvironment(){
override val fogColor
get() = (fogDensity / 0.275F).let { Vec3d(0.14 + it, 0.11 + it, 0.02) }
override val fogDensity
get() = currentFogDensity.get(MC.partialTicks)
override val voidRadiusMpXZ = 0.975F
override val voidRadiusMpY = 0.975F
override val voidCenterOffset = Vec3d(0.0, -8.0, 0.0)
private val currentFogDensity = LerpedFloat(MAX_FOG_DENSITY)
@SideOnly(Side.CLIENT)
override fun setupClient(){
tickClient()
currentFogDensity.updateImmediately(currentFogDensity.currentValue)
}
@SideOnly(Side.CLIENT)
override fun tickClient(){
val light = (MC.player?.let { it.world.getLight(Pos(it.lookPosVec)) } ?: 15) / 15F // TODO skylight
val prev = currentFogDensity.currentValue
val next = MAX_FOG_DENSITY - (light.pow(0.2F) * 0.85F * MAX_FOG_DENSITY)
currentFogDensity.update(prev + (next - prev) * 0.05F)
}
}
}

View File

@ -0,0 +1,219 @@
package chylex.hee.game.world.territory.generators
import chylex.hee.game.world.feature.basic.NoiseGenerator
import chylex.hee.game.world.feature.basic.PortalGenerator
import chylex.hee.game.world.feature.basic.ores.OreGenerator
import chylex.hee.game.world.feature.basic.ores.impl.OreTechniqueAdjacent
import chylex.hee.game.world.feature.basic.ores.impl.withAdjacentAirCheck
import chylex.hee.game.world.generation.IBlockPlacer.BlockReplacer
import chylex.hee.game.world.generation.SegmentedWorld
import chylex.hee.game.world.generation.TerritoryGenerationInfo
import chylex.hee.game.world.territory.ITerritoryGenerator
import chylex.hee.game.world.util.BoundingBox
import chylex.hee.game.world.util.PosXZ
import chylex.hee.game.world.util.Size
import chylex.hee.init.ModBlocks
import chylex.hee.system.util.Facing6
import chylex.hee.system.util.Pos
import chylex.hee.system.util.allInBoxMutable
import chylex.hee.system.util.allInCenteredBoxMutable
import chylex.hee.system.util.component1
import chylex.hee.system.util.component2
import chylex.hee.system.util.component3
import chylex.hee.system.util.floorToInt
import chylex.hee.system.util.nextBiasedFloat
import chylex.hee.system.util.nextFloat
import chylex.hee.system.util.nextInt
import chylex.hee.system.util.offsetUntil
import chylex.hee.system.util.remapRange
import chylex.hee.system.util.square
import net.minecraft.block.Block
import net.minecraft.init.Blocks
import net.minecraft.util.EnumFacing.DOWN
import net.minecraft.util.EnumFacing.UP
import net.minecraft.util.math.BlockPos
import java.util.Random
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.sqrt
object Generator_ForgottenTombs : ITerritoryGenerator{
override val segmentSize = Size(32, 16, 32)
override val defaultBlock: Block
get() = Blocks.END_STONE
override fun provide(world: SegmentedWorld): TerritoryGenerationInfo{
val rand = world.rand
val size = world.worldSize
val spawnPoint = EntranceCave.generate(world, rand, size)
PortalGenerator.VoidPortalReturnActive.place(world, spawnPoint)
// TODO tomb dungeon
return TerritoryGenerationInfo(spawnPoint)
}
private object EntranceCave{
private const val RADIUS_XZ = 65
private const val RADIUS_Y = 35
private const val EXTRA_ELEVATION = 2
fun generate(world: SegmentedWorld, rand: Random, size: Size): BlockPos{
val ellipsoidBottom = size.maxY + EXTRA_ELEVATION - (2 * RADIUS_Y)
val ellipsoidCenter = Pos(size.centerX, ellipsoidBottom + RADIUS_Y, size.centerZ + (size.z / 6))
Cutout.generate(world, rand, ellipsoidCenter)
EndPowderOre.generate(world, size, ellipsoidCenter)
for(chunkX in -3..3) for(chunkZ in -3..3){
if ((chunkX == 0 && chunkZ == 0) || (square(chunkX) + square(chunkZ) > 10)){
continue
}
val centerPos = PosXZ(ellipsoidCenter.add(chunkX * 20, 0, chunkZ * 20))
for(attempt in 1..10){
if (Stalactite.generate(world, rand, size, centerPos.add(rand.nextInt(-9, 9), rand.nextInt(-9, 9)))){
break
}
}
}
return ellipsoidCenter.add(0, -RADIUS_Y, 0)
}
private object Cutout{
private const val SKYVIEW_RADIUS = 11
fun generate(world: SegmentedWorld, rand: Random, center: BlockPos){
generateEllipsoid(world, rand, center)
generateRoughness(world, rand, center)
generateSkyview(world, rand, Pos(center.x, world.worldSize.maxY, center.z))
}
private fun generateEllipsoid(world: SegmentedWorld, rand: Random, center: BlockPos){
val radXZ = RADIUS_XZ.toFloat()
val radY = RADIUS_Y.toFloat()
val noiseXZ = NoiseGenerator.PerlinNormalized(rand, scale = 24.0, octaves = 2)
val noiseY = NoiseGenerator.PerlinNormalized(rand, scale = 48.0, octaves = 2)
for((x, y, z) in BlockPos.ORIGIN.allInCenteredBoxMutable(RADIUS_XZ, RADIUS_Y, RADIUS_XZ)){
val normalizedY = remapRange(y.toFloat(), -radY..radY, 0F..1F)
val powerY = remapRange(sqrt(normalizedY), 0F..1F, (4.8F)..(1.6F))
val powerXZ = powerY * 0.8F
val corner = 1 + ((abs(x) + abs(z)) / (3F * radXZ)).pow(2F)
val edge = 1F - noiseXZ.getValue(x, z){
multiply(0.25 * (0.8 + (0.2 * corner * noiseY.getRawValue(y, x + z))))
if (normalizedY < 0.1F){
multiply(0.2 + (0.8 * (normalizedY / 0.1)))
}
}
if ((abs(x) / radXZ).pow(powerXZ) + (abs(y) / radY).pow(powerY) + (abs(z) / radXZ).pow(powerXZ) <= edge){
world.setAir(center.add(x, y, z))
}
}
}
private fun generateRoughness(world: SegmentedWorld, rand: Random, center: BlockPos){
for(attempt in 1..25000){
val pos1 = rand.nextInt(-RADIUS_XZ, RADIUS_XZ)
val pos2 = rand.nextInt(RADIUS_XZ / 2, RADIUS_XZ) * (if (rand.nextBoolean()) 1 else -1)
val posY = rand.nextInt(-RADIUS_Y, RADIUS_Y - EXTRA_ELEVATION - 1)
val randomPos = if (rand.nextBoolean())
center.add(pos1, posY, pos2)
else
center.add(pos2, posY, pos1)
if (world.isInside(randomPos) && world.getBlock(randomPos) == Blocks.END_STONE && Facing6.count { world.isAir(randomPos.offset(it)) } >= 3){
world.setAir(randomPos)
}
}
}
private fun generateSkyview(world: SegmentedWorld, rand: Random, top: BlockPos){
val topOffset = 1 - (SKYVIEW_RADIUS / 2)
for((x, y, z) in Pos(-SKYVIEW_RADIUS, -SKYVIEW_RADIUS, -SKYVIEW_RADIUS).allInBoxMutable(Pos(SKYVIEW_RADIUS, 0, SKYVIEW_RADIUS))){
if (square(x) + square(y * 2) + square(z) <= square(SKYVIEW_RADIUS - rand.nextFloat(0F, 0.1F))){
val finalPos = top.add(x, topOffset - y, z)
if (world.isInside(finalPos)){
world.setAir(finalPos)
}
}
}
}
}
private object Stalactite{
fun generate(world: SegmentedWorld, rand: Random, size: Size, pos: PosXZ): Boolean{
var top = pos.withY(size.maxY).offsetUntil(DOWN, 0..(RADIUS_Y / 2), world::isAir) ?: return false
for(x in -3..3) for(z in -3..3){
val max = top.add(x, 0, z).offsetUntil(UP, 0..3){ !world.isAir(it) } ?: return false
if (max.y > top.y){
top = Pos(top.x, max.y, top.z)
}
}
val radius = rand.nextInt(1, 2)
val height = rand.nextInt(15, 45)
val spikiness = rand.nextInt(0, 5) + (height / 5)
for(x in -2..2) for(z in -2..2){
if (square(x) + square(z) <= square(radius) + rand.nextInt(0, 1)){
val h = height - (spikiness * (abs(x) + abs(z))) - rand.nextInt(spikiness)
for(y in 1..h){
world.setBlock(top.add(x, -y, z), Blocks.END_STONE)
}
}
}
return true
}
}
private object EndPowderOre{
private const val CHUNK_SIZE = 33
private const val CENTER_OFFSET_XZ = CHUNK_SIZE * 2
private val PASS = OreGenerator(
OreTechniqueAdjacent(
oresPerCluster = { rand -> 3 + (5 * rand.nextBiasedFloat(4F)).floorToInt() },
allowDiagonals = true
).withAdjacentAirCheck(
checkDistance = 1,
chanceIfNoAir = 0.01F
),
BlockReplacer(
fill = ModBlocks.END_POWDER_ORE,
replace = Blocks.END_STONE
),
chunkSize = CHUNK_SIZE,
attemptsPerChunk = 400,
clustersPerChunk = { 3 }
)
fun generate(world: SegmentedWorld, size: Size, center: BlockPos){
val bounds = BoundingBox(
Pos(center.x - CENTER_OFFSET_XZ, center.y - RADIUS_Y - 1, center.z - CENTER_OFFSET_XZ),
Pos(center.x + CENTER_OFFSET_XZ - 1, size.maxY - 4, center.z + CENTER_OFFSET_XZ - 1)
)
PASS.generate(world, bounds)
}
}
}
}