Skip to content

Commit

Permalink
Mooon
Browse files Browse the repository at this point in the history
  • Loading branch information
Seggan committed Jan 23, 2024
1 parent 8a27290 commit 544229f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 63 deletions.
4 changes: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
kotlin("jvm") version "1.9.20"
kotlin("jvm") version "1.9.21"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("net.minecrell.plugin-yml.bukkit") version "0.5.3"
id("xyz.jpenilla.run-paper") version "2.2.0"
Expand All @@ -14,6 +14,8 @@ repositories {

dependencies {
library(kotlin("stdlib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0-RC2")

compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT")
compileOnly("com.github.Slimefun:Slimefun4:RC-36")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ abstract class UniversalObject protected constructor(name: String, baseItem: Ite
get() = if (this is TheUniverse) 0 else orbiting.orbitLevel + 1

private val _orbiters = mutableListOf<UniversalObject>()
val orbiters: List<UniversalObject>
get() = _orbiters.toList()
val orbiters: List<UniversalObject> = _orbiters

fun addOrbiter(orbiter: UniversalObject) {
_orbiters.add(orbiter)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
package io.github.addoncommunity.galactifun.base.objects.earth

import io.github.addoncommunity.galactifun.api.objects.planet.gen.SingleBiomeProvider
import io.github.addoncommunity.galactifun.api.objects.planet.gen.WorldGenerator
import io.github.addoncommunity.galactifun.util.gen.DoubleChunkGrid
import org.bukkit.Material
import org.bukkit.block.Biome
import org.bukkit.generator.BiomeProvider
import org.bukkit.generator.WorldInfo
import org.bukkit.util.noise.SimplexOctaveGenerator
import java.util.*
import kotlin.math.pow

internal class MoonGenerator : WorldGenerator() {

override val biomeProvider = SingleBiomeProvider(Biome.DESERT)
override val biomeProvider: BiomeProvider = MoonBiomeProvider()

@Volatile
private lateinit var baseNoise: SimplexOctaveGenerator

@Volatile
private lateinit var heightNoise: SimplexOctaveGenerator

private val baseNoiseGrid = DoubleChunkGrid(256 * 2)
private val heightNoiseGrid = DoubleChunkGrid(256 * 3)
private val baseNoiseGrid = DoubleChunkGrid()
private val heightNoiseGrid = DoubleChunkGrid()

override fun generateBedrock(worldInfo: WorldInfo, random: Random, chunkX: Int, chunkZ: Int, chunkData: ChunkData) {
for (x in 0..15) {
Expand Down Expand Up @@ -52,24 +52,21 @@ internal class MoonGenerator : WorldGenerator() {
for (z in 0..15) {
val height = getHeight(worldInfo, cx + x, cz + z)
val terrainType = getTerrainType(worldInfo, cx + x, cz + z)
if (terrainType == TerrainType.MARE) {
for (y in height - 2 until height) {
chunkData.setBlock(x, y, z, Material.GRAY_CONCRETE)
chunkData.setBlock(x, height - 2, z, Material.GRAY_CONCRETE_POWDER)
chunkData.setBlock(
x,
height - 1,
z,
when (terrainType) {
is TerrainType.Mare -> Material.GRAY_CONCRETE_POWDER

is TerrainType.Transition ->
if (random.nextDouble() < terrainType.chance) Material.GRAY_CONCRETE_POWDER
else Material.LIGHT_GRAY_CONCRETE_POWDER

is TerrainType.Hills -> Material.LIGHT_GRAY_CONCRETE_POWDER
}
} else {
chunkData.setBlock(x, height - 2, z, Material.GRAY_CONCRETE_POWDER)
chunkData.setBlock(
x,
height - 1,
z,
when (terrainType) {
TerrainType.TRANSITION_25 -> if (random.nextDouble() < 0.25) Material.GRAY_CONCRETE_POWDER else Material.LIGHT_GRAY_CONCRETE_POWDER
TerrainType.TRANSITION_50 -> if (random.nextBoolean()) Material.GRAY_CONCRETE_POWDER else Material.LIGHT_GRAY_CONCRETE_POWDER
TerrainType.TRANSITION_75 -> if (random.nextDouble() < 0.75) Material.GRAY_CONCRETE_POWDER else Material.LIGHT_GRAY_CONCRETE_POWDER
else -> Material.LIGHT_GRAY_CONCRETE_POWDER
}
)
}
)
}
}
}
Expand Down Expand Up @@ -103,19 +100,23 @@ internal class MoonGenerator : WorldGenerator() {
private fun getTerrainType(worldInfo: WorldInfo, x: Int, y: Int): TerrainType {
val height = getHeightValue(worldInfo, x, y)
return when {
height < 3.5 -> TerrainType.HILLS
height < 3.75 -> TerrainType.TRANSITION_25
height < 4.0 -> TerrainType.TRANSITION_50
height < 4.25 -> TerrainType.TRANSITION_75
else -> TerrainType.MARE
height < 2.5 -> TerrainType.Hills
height < 3 -> TerrainType.Transition((height - 2.5) / 0.5)
else -> TerrainType.Mare
}
}

private inner class MoonBiomeProvider : BiomeProvider() {
override fun getBiome(worldInfo: WorldInfo, x: Int, y: Int, z: Int): Biome {
return if (getTerrainType(worldInfo, x, z) == TerrainType.Mare) Biome.BADLANDS else Biome.DESERT
}

override fun getBiomes(worldInfo: WorldInfo): MutableList<Biome> = mutableListOf(Biome.DESERT, Biome.BADLANDS)
}
}

private enum class TerrainType {
HILLS,
TRANSITION_25,
TRANSITION_50,
TRANSITION_75,
MARE
private sealed interface TerrainType {
data object Hills : TerrainType
data class Transition(val chance: Double) : TerrainType
data object Mare : TerrainType
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,54 @@
package io.github.addoncommunity.galactifun.util.gen

import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
import com.google.common.util.concurrent.AtomicDoubleArray
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.LongAdder
import kotlinx.coroutines.*
import java.lang.ref.WeakReference
import java.util.concurrent.locks.ReentrantReadWriteLock

/**
* A grid of double values, stored in chunks.
*
* @param maxAccesses The maximum amount a chunk can be accessed before it is unloaded. Defaults to 256.
*/
class DoubleChunkGrid(private val maxAccesses: Int = 16 * 16) {
* */
class DoubleChunkGrid {

private val chunks = Long2ObjectOpenHashMap<Array<DoubleArray>>()
private val chunks = Long2ObjectOpenHashMap<Array<AtomicDoubleArray>>()

private val chunkAccesses = ConcurrentHashMap<Long, LongAdder>()
private val chunkCreations = Long2LongOpenHashMap()

private val lock = ReentrantReadWriteLock()

init {
val ref = WeakReference(this)
coroScope.launch {
while (true) {
val time = System.currentTimeMillis()
val grid = ref.get() ?: break
grid.lock.writeLock().lock()
val iterator = grid.chunkCreations.long2LongEntrySet().fastIterator()
while (iterator.hasNext()) {
val entry = iterator.next()
if (time - entry.longValue > 3000) {
iterator.remove()
grid.chunks.remove(entry.longKey)
}
}
grid.lock.writeLock().unlock()
delay(2999)
}
}
}

operator fun get(cx: Int, cz: Int, x: Int, y: Int): Double {
val id = cx pack cz

lock.readLock().lock()
val chunk = checkNotNull(chunks[id]) { "Chunk at $cx, $cz not generated" }
val stack = chunk[x][y]
lock.readLock().unlock()
val stack = chunk[x][y]

check(!stack.isNaN()) { "Stack at $x, $y in chunk at $cx, $cz not generated" }
increment(id)
return stack
}

Expand All @@ -37,10 +57,17 @@ class DoubleChunkGrid(private val maxAccesses: Int = 16 * 16) {
operator fun set(cx: Int, cz: Int, x: Int, y: Int, value: Double) {
val id = cx pack cz

lock.writeLock().lock()
val chunk = chunks.computeIfAbsent(id, Long2ObjectFunction { Array(16) { DoubleArray(16) { Double.NaN } } })
val chunk = if (chunks.containsKey(id)) {
chunks[id]!!
} else {
val chunk = Array(16) { AtomicDoubleArray(DoubleArray(16) { Double.NaN }) }
lock.writeLock().lock()
chunks[id] = chunk
chunkCreations[id] = System.currentTimeMillis()
lock.writeLock().unlock()
chunk
}
chunk[x][y] = value
lock.writeLock().unlock()
}

operator fun set(x: Int, y: Int, value: Double) = set(x shr 4, y shr 4, x and 15, y and 15, value)
Expand All @@ -50,17 +77,13 @@ class DoubleChunkGrid(private val maxAccesses: Int = 16 * 16) {

lock.readLock().lock()
val chunk = chunks[id]
lock.readLock().unlock()
if (chunk != null) {
val stack = chunk[x][y]
if (!stack.isNaN()) {
lock.readLock().unlock()
increment(id)
return stack
}
}
lock.readLock().unlock()

increment(id)

val computed = value()
this[cx, cz, x, y] = computed
Expand All @@ -70,16 +93,10 @@ class DoubleChunkGrid(private val maxAccesses: Int = 16 * 16) {
fun getOrSet(x: Int, y: Int, value: () -> Double) =
getOrSet(x shr 4, y shr 4, x and 15, y and 15, value)

private fun increment(id: Long) {
chunkAccesses.computeIfAbsent(id) { _ -> LongAdder() }.increment()
val accesses = chunkAccesses[id] ?: return // in case another thread removes it
if (accesses.sum() >= maxAccesses) {
lock.writeLock().lock()
chunkAccesses.remove(id)
chunks.remove(id)
lock.writeLock().unlock()
}
companion object {
@OptIn(DelicateCoroutinesApi::class)
private val coroScope = CoroutineScope(newFixedThreadPoolContext(4, "Galactifun2-DoubleChunkGrid"))
}
}

private infix fun Int.pack(other: Int) = this.toLong() shl 32 or other.toLong()
private infix fun Int.pack(other: Int) = (this.toLong() shl 32) or (other.toLong() and 0xFFFFFFFFL)

0 comments on commit 544229f

Please sign in to comment.