From 6309bd5fa96921df6c421e8e4dd852154648cc95 Mon Sep 17 00:00:00 2001 From: Seggan Date: Fri, 26 Jan 2024 18:20:28 -0500 Subject: [PATCH] Basic perlin --- .../api/objects/planet/AlienWorld.kt | 8 ++ .../atmosphere/AtmosphereBuilder.kt | 5 + .../galactifun/core/Gf2Command.kt | 1 + .../galactifun/scripting/ScriptDef.kt | 12 +- .../galactifun/scripting/dsl/OrbitBuilder.kt | 4 + .../galactifun/scripting/dsl/PlanetBuilder.kt | 41 ++++-- .../galactifun/scripting/dsl/WorldBuilder.kt | 44 +++++++ .../scripting/dsl/gen/AbstractPerlin.kt | 30 +++++ .../scripting/dsl/gen/GeneratorBuilder.kt | 25 ++++ .../scripting/dsl/gen/PerlinBuilder.kt | 122 ++++++++++++++++++ 10 files changed, 276 insertions(+), 16 deletions(-) create mode 100644 src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/WorldBuilder.kt create mode 100644 src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/AbstractPerlin.kt create mode 100644 src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/GeneratorBuilder.kt create mode 100644 src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/PerlinBuilder.kt diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/planet/AlienWorld.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/planet/AlienWorld.kt index 083c6f0..744373b 100644 --- a/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/planet/AlienWorld.kt +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/planet/AlienWorld.kt @@ -43,4 +43,12 @@ abstract class AlienWorld(name: String, baseItem: ItemStack) : PlanetaryWorld(na return world } + + fun addBlockMapping(material: Material, item: ItemStack) { + blockMappings[material] = item + } + + fun getBlockMapping(material: Material): ItemStack? { + return blockMappings[material] + } } \ No newline at end of file diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/properties/atmosphere/AtmosphereBuilder.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/properties/atmosphere/AtmosphereBuilder.kt index 5585d59..fa5bf6e 100644 --- a/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/properties/atmosphere/AtmosphereBuilder.kt +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/api/objects/properties/atmosphere/AtmosphereBuilder.kt @@ -1,8 +1,10 @@ package io.github.addoncommunity.galactifun.api.objects.properties.atmosphere +import io.github.addoncommunity.galactifun.scripting.PlanetDsl import org.bukkit.World import java.util.* +@PlanetDsl @AtmosphereDsl class AtmosphereBuilder internal constructor() { @@ -14,11 +16,14 @@ class AtmosphereBuilder internal constructor() { internal val composition = EnumMap(Gas::class.java) + @PlanetDsl @AtmosphereDsl inner class CompositionBuilder internal constructor() { infix fun Double.percent(gas: Gas) { this@AtmosphereBuilder.composition[gas] = this } + + infix fun Int.percent(gas: Gas) = this.toDouble() percent gas } } diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/core/Gf2Command.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/core/Gf2Command.kt index a0c3594..a70d0d0 100644 --- a/src/main/kotlin/io/github/addoncommunity/galactifun/core/Gf2Command.kt +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/core/Gf2Command.kt @@ -6,6 +6,7 @@ import io.github.addoncommunity.galactifun.api.objects.planet.PlanetaryWorld import org.bukkit.Location import org.bukkit.entity.Player +@Suppress("unused") @CommandAlias("gf2") object Gf2Command : BaseCommand() { diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/ScriptDef.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/ScriptDef.kt index 8e50333..0e01dfe 100644 --- a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/ScriptDef.kt +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/ScriptDef.kt @@ -4,10 +4,12 @@ import io.github.addoncommunity.galactifun.api.objects.TheUniverse import io.github.addoncommunity.galactifun.api.objects.planet.PlanetaryObject import io.github.addoncommunity.galactifun.api.objects.properties.DayCycle import io.github.addoncommunity.galactifun.api.objects.properties.atmosphere.Atmosphere +import io.github.addoncommunity.galactifun.api.objects.properties.atmosphere.Gas import io.github.addoncommunity.galactifun.base.BaseUniverse import io.github.addoncommunity.galactifun.pluginInstance import org.bukkit.Material import org.bukkit.World +import org.bukkit.block.Biome import kotlin.reflect.KClass import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.* @@ -19,10 +21,10 @@ import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromT import kotlin.script.experimental.jvmhost.createJvmEvaluationConfigurationFromTemplate @KotlinScript( + displayName = "Galactifun2 Planet Definition", fileExtension = "planet.kts", compilationConfiguration = PlanetScriptConfig::class, - evaluationConfiguration = PlanetScriptEval::class, - hostConfiguration = PlanetScriptHost::class + evaluationConfiguration = PlanetScriptEval::class ) abstract class PlanetScript { val eternalDay = DayCycle.ETERNAL_DAY @@ -35,6 +37,7 @@ object PlanetScriptConfig : ScriptCompilationConfiguration({ defaultImports( "io.github.addoncommunity.galactifun.util.*", "io.github.addoncommunity.galactifun.scripting.dsl.*", + "io.github.addoncommunity.galactifun.scripting.dsl.gen.*", "io.github.addoncommunity.galactifun.api.objects.properties.Distance.Companion.lightYears", "io.github.addoncommunity.galactifun.api.objects.properties.Distance.Companion.kilometers", "io.github.addoncommunity.galactifun.api.objects.properties.Distance.Companion.au", @@ -43,10 +46,13 @@ object PlanetScriptConfig : ScriptCompilationConfiguration({ ) defaultImports( Material::class, + World.Environment::class, + Biome::class, + BaseUniverse::class, TheUniverse::class, Atmosphere::class, - World.Environment::class + Gas::class, ) compilerOptions.append("-Xadd-modules=ALL-MODULE-PATH") jvm { diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/OrbitBuilder.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/OrbitBuilder.kt index 30b27a7..bd760eb 100644 --- a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/OrbitBuilder.kt +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/OrbitBuilder.kt @@ -19,4 +19,8 @@ class OrbitBuilder { inline fun orbit(block: OrbitBuilder.() -> Unit): Orbit { return OrbitBuilder().apply(block).build() +} + +inline fun PlanetBuilder.orbit(block: OrbitBuilder.() -> Unit) { + orbit = OrbitBuilder().apply(block).build() } \ No newline at end of file diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/PlanetBuilder.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/PlanetBuilder.kt index 2101837..3ecd6e3 100644 --- a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/PlanetBuilder.kt +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/PlanetBuilder.kt @@ -1,6 +1,7 @@ package io.github.addoncommunity.galactifun.scripting.dsl import io.github.addoncommunity.galactifun.api.objects.UniversalObject +import io.github.addoncommunity.galactifun.api.objects.planet.AlienWorld import io.github.addoncommunity.galactifun.api.objects.planet.PlanetaryObject import io.github.addoncommunity.galactifun.api.objects.planet.PlanetaryWorld import io.github.addoncommunity.galactifun.api.objects.properties.DayCycle @@ -26,18 +27,36 @@ class PlanetBuilder { var dayCycle: DayCycle by RequiredProperty() var atmosphere = Atmosphere.NONE - var world: String? = null + + var worldConfig: WorldBuilder? = null fun build(): PlanetaryObject { - val world = this.world - if (world != null) { - return object : PlanetaryWorld(name, ItemStack(item)) { - override val dayCycle = this@PlanetBuilder.dayCycle - override val orbiting = this@PlanetBuilder.orbiting - override val orbit = this@PlanetBuilder.orbit - override val atmosphere = this@PlanetBuilder.atmosphere + val config = worldConfig + if (config != null) { + val world = config.world + if (world != null) { + return object : PlanetaryWorld(name, ItemStack(item)) { + override val dayCycle = this@PlanetBuilder.dayCycle + override val orbiting = this@PlanetBuilder.orbiting + override val orbit = this@PlanetBuilder.orbit + override val atmosphere = this@PlanetBuilder.atmosphere - override fun loadWorld(): World = Bukkit.getWorld(world) ?: error("World $world does not exist") + override fun loadWorld(): World = Bukkit.getWorld(world) ?: error("World $world does not exist") + } + } else { + return object : AlienWorld(name, ItemStack(item)) { + override val dayCycle = this@PlanetBuilder.dayCycle + override val orbiting = this@PlanetBuilder.orbiting + override val orbit = this@PlanetBuilder.orbit + override val atmosphere = this@PlanetBuilder.atmosphere + override val generator = config.generator + + init { + for ((material, item) in config.blockMappings) { + addBlockMapping(material, item) + } + } + } } } else { return object : PlanetaryObject(name, ItemStack(item)) { @@ -58,10 +77,6 @@ inline fun PlanetScript.planet(block: PlanetBuilder.() -> Unit): PlanetaryObject return planet } -inline fun PlanetBuilder.orbit(block: OrbitBuilder.() -> Unit) { - orbit = OrbitBuilder().apply(block).build() -} - fun PlanetBuilder.eternal(ticks: Int): DayCycle = DayCycle.eternal(ticks) fun PlanetBuilder.atmosphere(block: AtmosphereBuilder.() -> Unit) { diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/WorldBuilder.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/WorldBuilder.kt new file mode 100644 index 0000000..0c8bdb8 --- /dev/null +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/WorldBuilder.kt @@ -0,0 +1,44 @@ +package io.github.addoncommunity.galactifun.scripting.dsl + +import io.github.addoncommunity.galactifun.api.objects.planet.gen.WorldGenerator +import io.github.addoncommunity.galactifun.scripting.PlanetDsl +import io.github.addoncommunity.galactifun.scripting.RequiredProperty +import io.github.addoncommunity.galactifun.scripting.dsl.gen.GeneratorBuilder +import io.github.addoncommunity.galactifun.scripting.dsl.gen.GeneratorBuilderProvider +import org.bukkit.Material +import org.bukkit.inventory.ItemStack +import java.util.* + +@PlanetDsl +class WorldBuilder { + + var world: String? = null + + var generator: WorldGenerator by RequiredProperty() + + var spawnVanillaMobs = false + + internal val blockMappings = EnumMap(Material::class.java) + + @PlanetDsl + inner class MappingBuilder { + infix fun Material.mapTo(item: ItemStack) { + this@WorldBuilder.blockMappings[this] = item + } + + infix fun Material.mapTo(item: Material) { + this mapTo ItemStack(item) + } + } +} + +inline fun WorldBuilder.blockMappings(block: WorldBuilder.MappingBuilder.() -> Unit) { + MappingBuilder().apply(block) +} + +inline fun WorldBuilder.generator( + provider: GeneratorBuilderProvider, + block: T.() -> Unit +) { + generator = provider.provide().apply(block).build() +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/AbstractPerlin.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/AbstractPerlin.kt new file mode 100644 index 0000000..d98a469 --- /dev/null +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/AbstractPerlin.kt @@ -0,0 +1,30 @@ +package io.github.addoncommunity.galactifun.scripting.dsl.gen + +import io.github.addoncommunity.galactifun.scripting.PlanetDsl +import io.github.addoncommunity.galactifun.scripting.RequiredProperty + +@PlanetDsl +abstract class AbstractPerlin : GeneratorBuilder() { + + var config: PerlinConfig by RequiredProperty() + + var generateBedrock = true + + var averageHeight: Int by RequiredProperty() + var minHeight: Int by RequiredProperty() + var surfaceHeight = 10 + + class PerlinConfig { + var octaves: Int = 8 + var scale: Double by RequiredProperty() + var amplitude: Double by RequiredProperty() + var frequency: Double by RequiredProperty() + + var flattenFactor: Double = 1.0 + var smoothen: Boolean = false + } +} + +inline fun AbstractPerlin.noiseConfig(block: AbstractPerlin.PerlinConfig.() -> Unit) { + config = AbstractPerlin.PerlinConfig().apply(block) +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/GeneratorBuilder.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/GeneratorBuilder.kt new file mode 100644 index 0000000..5a3af37 --- /dev/null +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/GeneratorBuilder.kt @@ -0,0 +1,25 @@ +package io.github.addoncommunity.galactifun.scripting.dsl.gen + +import io.github.addoncommunity.galactifun.api.objects.planet.gen.WorldGenerator +import io.github.addoncommunity.galactifun.scripting.RequiredProperty +import org.bukkit.block.Biome +import org.bukkit.generator.BiomeProvider +import org.bukkit.generator.WorldInfo + +abstract class GeneratorBuilder { + + var biomeProvider: BiomeProvider by RequiredProperty() + + abstract fun build(): WorldGenerator +} + +fun GeneratorBuilder.singleBiome(biome: Biome) { + biomeProvider = object : BiomeProvider() { + override fun getBiome(worldInfo: WorldInfo, x: Int, y: Int, z: Int) = biome + override fun getBiomes(worldInfo: WorldInfo) = mutableListOf(biome) + } +} + +interface GeneratorBuilderProvider { + fun provide(): T +} diff --git a/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/PerlinBuilder.kt b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/PerlinBuilder.kt new file mode 100644 index 0000000..d080fd3 --- /dev/null +++ b/src/main/kotlin/io/github/addoncommunity/galactifun/scripting/dsl/gen/PerlinBuilder.kt @@ -0,0 +1,122 @@ +package io.github.addoncommunity.galactifun.scripting.dsl.gen + +import io.github.addoncommunity.galactifun.api.objects.planet.gen.WorldGenerator +import org.bukkit.Material +import org.bukkit.generator.WorldInfo +import org.bukkit.util.noise.SimplexOctaveGenerator +import java.util.* +import kotlin.math.pow + +class PerlinBuilder : AbstractPerlin() { + + var noiseGenerator: (WorldInfo, Random, Int, Int, Int, Int) -> Material = + { _, _, _, _, _, _ -> Material.AIR } + + var surfaceGenerator: (WorldInfo, Random, Int, Int, Int, Int) -> Material = + { _, _, _, _, _, _ -> Material.AIR } + + + override fun build(): WorldGenerator { + // Prevent performance issues by unboxing before building the generator + val octaves = config.octaves + val scale = config.scale + val amplitude = config.amplitude + val frequency = config.frequency + val flattenFactor = config.flattenFactor + val smoothen = config.smoothen + + val averageHeight = averageHeight + val minHeight = minHeight + if (generateBedrock) 1 else 0 + + return object : WorldGenerator() { + override val biomeProvider = this@PerlinBuilder.biomeProvider + + @Volatile + private lateinit var baseNoise: SimplexOctaveGenerator + + fun getMinHeight(worldInfo: WorldInfo): Int = minHeight.coerceAtLeast(worldInfo.minHeight) + + override fun generateNoise( + worldInfo: WorldInfo, + random: Random, + chunkX: Int, + chunkZ: Int, + chunkData: ChunkData + ) { + val cx = chunkX * 16 + val cz = chunkZ * 16 + val min = getMinHeight(worldInfo) + for (x in 0..15) { + for (z in 0..15) { + val height = getHeight(worldInfo, cx + x, cz + z) + for (y in min until height - surfaceHeight) { + chunkData.setBlock(x, y, z, noiseGenerator(worldInfo, random, cx + x, y, cz + z, height)) + } + } + } + } + + override fun generateSurface( + worldInfo: WorldInfo, + random: Random, + chunkX: Int, + chunkZ: Int, + chunkData: ChunkData + ) { + val cx = chunkX * 16 + val cz = chunkZ * 16 + for (x in 0..15) { + for (z in 0..15) { + val height = getHeight(worldInfo, cx + x, cz + z) + for (y in height - surfaceHeight until height) { + chunkData.setBlock(x, y, z, surfaceGenerator(worldInfo, random, cx + x, y, cz + z, height)) + } + } + } + } + + override fun generateBedrock( + worldInfo: WorldInfo, + random: Random, + chunkX: Int, + chunkZ: Int, + chunkData: ChunkData + ) { + if (!generateBedrock) return + val y = getMinHeight(worldInfo) + for (x in 0..15) { + for (z in 0..15) { + chunkData.setBlock(x, y, z, Material.BEDROCK) + } + } + } + + private fun getHeight(worldInfo: WorldInfo, x: Int, z: Int): Int { + if (!::baseNoise.isInitialized) { + baseNoise = SimplexOctaveGenerator(worldInfo.seed, octaves) + baseNoise.setScale(scale) + } + var height = baseNoise.noise(x.toDouble(), z.toDouble(), frequency, amplitude, true) + height = height.pow(flattenFactor) + height = (height + 1) / 2 + return (height * (averageHeight - minHeight)).toInt() + } + } + } +} + +fun PerlinBuilder.generateNoiseBlock( + block: (WorldInfo, Random, Int, Int, Int, Int) -> Material +) { + noiseGenerator = block +} + +fun PerlinBuilder.generateSurfaceBlock( + block: (WorldInfo, Random, Int, Int, Int, Int) -> Material +) { + surfaceGenerator = block +} + +object Perlin : GeneratorBuilderProvider { + override fun provide() = PerlinBuilder() +} \ No newline at end of file