Add block codecs
This commit is contained in:
parent
653f62447c
commit
4cc3d8f17f
10 changed files with 159 additions and 20 deletions
|
@ -20,7 +20,7 @@ val striktVersion = properties["version.strikt"].toString()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Kotlin
|
// Kotlin
|
||||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.4.10")
|
api("org.jetbrains.kotlin:kotlin-reflect:1.4.10")
|
||||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}")
|
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}")
|
||||||
|
|
||||||
// JSON
|
// JSON
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package space.blokk.util
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
data class KPropertyValuePair<V>(val property: KProperty<V>, val value: V)
|
|
@ -1,13 +0,0 @@
|
||||||
// IF YOU CHANGE THIS FILE, MOVE IT FROM `generatedKotlin` TO `kotlin` OR IT WILL BE OVERWRITTEN.
|
|
||||||
package space.blokk.world.block
|
|
||||||
|
|
||||||
import space.blokk.world.block.interfaces.Button
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A block of type [ACACIA_BUTTON][Material.ACACIA_BUTTON]
|
|
||||||
*/
|
|
||||||
class AcaciaButton(
|
|
||||||
ref: BlockRef
|
|
||||||
) : Block(ref), Button {
|
|
||||||
override var pressed: Boolean = false
|
|
||||||
}
|
|
|
@ -1,5 +1,10 @@
|
||||||
package space.blokk.world.block
|
package space.blokk.world.block
|
||||||
|
|
||||||
|
import space.blokk.util.KPropertyValuePair
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.full.starProjectedType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ref The [BlockRef] referencing this block.
|
* @param ref The [BlockRef] referencing this block.
|
||||||
*/
|
*/
|
||||||
|
@ -26,4 +31,52 @@ abstract class Block internal constructor(val ref: BlockRef) {
|
||||||
internal fun destroy() {
|
internal fun destroy() {
|
||||||
onDestroy()
|
onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class Companion {
|
||||||
|
abstract val codec: Codec<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
class Codec<T : Block> private constructor(
|
||||||
|
val blockClass: KClass<out T>,
|
||||||
|
val id: Int,
|
||||||
|
val firstStateID: Int,
|
||||||
|
val states: List<Array<KPropertyValuePair<*>>>
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
inline fun <reified T : Block> id(id: Int, firstStateID: Int) = id(T::class, id, firstStateID)
|
||||||
|
fun <T : Block> id(blockClass: KClass<out T>, id: Int, firstStateID: Int) =
|
||||||
|
Builder(blockClass, id, firstStateID)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder<T : Block> internal constructor(
|
||||||
|
private val blockClass: KClass<out T>,
|
||||||
|
private val id: Int,
|
||||||
|
private val firstStateID: Int
|
||||||
|
) {
|
||||||
|
private val attributeFields = mutableListOf<KProperty<Any>>()
|
||||||
|
|
||||||
|
fun attribute(property: KProperty<Any>) = this.apply { attributeFields.add(property) }
|
||||||
|
|
||||||
|
fun build() = Codec(blockClass, id, firstStateID, generateStates(attributeFields))
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun generateStates(properties: List<KProperty<Any>>): List<Array<KPropertyValuePair<*>>> {
|
||||||
|
if (properties.isEmpty()) return emptyList()
|
||||||
|
|
||||||
|
val current = properties[0]
|
||||||
|
println(current.returnType)
|
||||||
|
val allowedValues = when (current.returnType) {
|
||||||
|
Boolean::class.starProjectedType -> arrayOf(true, false)
|
||||||
|
else -> TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
val rest = generateStates(properties.drop(1))
|
||||||
|
return allowedValues.flatMap { value ->
|
||||||
|
if (rest.isEmpty()) listOf(arrayOf(KPropertyValuePair(current, value)))
|
||||||
|
else rest.map { arrayOf(KPropertyValuePair(current, value), *it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package space.blokk.world.block.interfaces
|
package space.blokk.world.block
|
||||||
|
|
||||||
interface Button {
|
interface Button {
|
||||||
var pressed: Boolean
|
var pressed: Boolean
|
28
blokk-api/src/main/kotlin/space/blokk/world/block/Hopper.kt
Normal file
28
blokk-api/src/main/kotlin/space/blokk/world/block/Hopper.kt
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package space.blokk.world.block
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Material: [HOPPER][Material.HOPPER]
|
||||||
|
*/
|
||||||
|
class Hopper(
|
||||||
|
ref: BlockRef
|
||||||
|
) : Block(ref) {
|
||||||
|
var enabled: Boolean = false
|
||||||
|
|
||||||
|
var facing: Facing = Facing.DOWN
|
||||||
|
|
||||||
|
enum class Facing {
|
||||||
|
DOWN,
|
||||||
|
NORTH,
|
||||||
|
SOUTH,
|
||||||
|
WEST,
|
||||||
|
EAST
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : Block.Companion() {
|
||||||
|
override val codec = Codec
|
||||||
|
.id<Hopper>(328, 6192)
|
||||||
|
.attribute(Hopper::enabled)
|
||||||
|
.attribute(Hopper::facing)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
25
blokk-block-codecs/build.gradle.kts
Normal file
25
blokk-block-codecs/build.gradle.kts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
group = rootProject.group
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://jitpack.io")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
compileKotlin {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
kotlinOptions.freeCompilerArgs = listOf(
|
||||||
|
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||||
|
"-progressive"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package space.blokk.world.block.codec
|
||||||
|
|
||||||
|
class AcaciaButtonCodec {
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import space.blokk.server.Server
|
||||||
import space.blokk.server.event.ServerEvent
|
import space.blokk.server.event.ServerEvent
|
||||||
import space.blokk.util.EncryptionUtils
|
import space.blokk.util.EncryptionUtils
|
||||||
import space.blokk.util.Ticker
|
import space.blokk.util.Ticker
|
||||||
|
import space.blokk.world.block.Hopper
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
@ -94,6 +95,10 @@ class BlokkServer internal constructor() : Server {
|
||||||
logger info "Listening on ${config.host}:${config.port}"
|
logger info "Listening on ${config.host}:${config.port}"
|
||||||
|
|
||||||
ticker.start()
|
ticker.start()
|
||||||
|
|
||||||
|
Hopper.codec.states.forEach {
|
||||||
|
println(it.map { it.toString() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shutdown() {
|
override fun shutdown() {
|
||||||
|
|
|
@ -11,11 +11,15 @@ typealias JsonAny = com.jsoniter.any.Any
|
||||||
|
|
||||||
class FilesGenerator(private val dataDir: File, private val outputDir: File, private val sourcesDir: File) {
|
class FilesGenerator(private val dataDir: File, private val outputDir: File, private val sourcesDir: File) {
|
||||||
companion object {
|
companion object {
|
||||||
|
const val IMPORT_FOR_REMOVAL_PACKAGE_NAME = "IMPORT_FOR_REMOVAL"
|
||||||
|
const val PROPERTY_TYPE_FOR_REMOVAL_NAME = "PROPERTY_TYPE_FOR_REMOVAL"
|
||||||
|
|
||||||
const val API_PACKAGE = "space.blokk"
|
const val API_PACKAGE = "space.blokk"
|
||||||
const val BLOCK_PACKAGE = "space.blokk.world.block"
|
const val BLOCK_PACKAGE = "space.blokk.world.block"
|
||||||
val MATERIAL_TYPE = ClassName(BLOCK_PACKAGE, "Material")
|
val MATERIAL_TYPE = ClassName(BLOCK_PACKAGE, "Material")
|
||||||
val BLOCK_TYPE = ClassName(BLOCK_PACKAGE, "Block")
|
val BLOCK_TYPE = ClassName(BLOCK_PACKAGE, "Block")
|
||||||
val BLOCK_REF_TYPE = ClassName(BLOCK_PACKAGE, "BlockRef")
|
val BLOCK_REF_TYPE = ClassName(BLOCK_PACKAGE, "BlockRef")
|
||||||
|
val BLOCK_CODEC_TYPE = BLOCK_TYPE.nestedClass("Codec")
|
||||||
val K_CLASS_TYPE = ClassName("kotlin.reflect", "KClass")
|
val K_CLASS_TYPE = ClassName("kotlin.reflect", "KClass")
|
||||||
val MAP_TYPE = ClassName("kotlin.collections", "Map")
|
val MAP_TYPE = ClassName("kotlin.collections", "Map")
|
||||||
}
|
}
|
||||||
|
@ -74,11 +78,11 @@ class FilesGenerator(private val dataDir: File, private val outputDir: File, pri
|
||||||
val upperUnderscoreName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, lowerUnderscoreName)
|
val upperUnderscoreName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, lowerUnderscoreName)
|
||||||
val specificMaterialType = MATERIAL_TYPE.nestedClass(upperUnderscoreName)
|
val specificMaterialType = MATERIAL_TYPE.nestedClass(upperUnderscoreName)
|
||||||
|
|
||||||
if (sourcesDir.resolve("./${BLOCK_PACKAGE.replace(".", "/")}/$upperCamelName.kt").exists())
|
val filePathRelativeToSourceRoot = "./${BLOCK_PACKAGE.replace(".", "/")}/$upperCamelName.kt"
|
||||||
continue
|
if (sourcesDir.resolve(filePathRelativeToSourceRoot).exists()) continue
|
||||||
|
|
||||||
val type = TypeSpec.classBuilder(upperCamelName)
|
val type = TypeSpec.classBuilder(upperCamelName)
|
||||||
.addKdoc("A block of type [$upperUnderscoreName][%T]", specificMaterialType)
|
.addKdoc("Material: [$upperUnderscoreName][%T]", specificMaterialType)
|
||||||
.superclass(BLOCK_TYPE)
|
.superclass(BLOCK_TYPE)
|
||||||
.primaryConstructor(
|
.primaryConstructor(
|
||||||
FunSpec.constructorBuilder()
|
FunSpec.constructorBuilder()
|
||||||
|
@ -86,13 +90,41 @@ class FilesGenerator(private val dataDir: File, private val outputDir: File, pri
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.addSuperclassConstructorParameter("ref")
|
.addSuperclassConstructorParameter("ref")
|
||||||
|
.addType(
|
||||||
|
TypeSpec.companionObjectBuilder()
|
||||||
|
.superclass(BLOCK_TYPE.nestedClass("Companion"))
|
||||||
|
.addProperty(
|
||||||
|
PropertySpec.builder(
|
||||||
|
"codec",
|
||||||
|
ClassName(IMPORT_FOR_REMOVAL_PACKAGE_NAME, PROPERTY_TYPE_FOR_REMOVAL_NAME),
|
||||||
|
KModifier.OVERRIDE
|
||||||
|
)
|
||||||
|
.initializer(
|
||||||
|
"""
|
||||||
|
%T
|
||||||
|
.id<${upperCamelName}>(${block.get("id").toInt()}, ${
|
||||||
|
block.get("minStateId").toInt()
|
||||||
|
})
|
||||||
|
// .attribute(${upperCamelName}::PROPERTY)
|
||||||
|
.build()
|
||||||
|
""".trimIndent(), BLOCK_CODEC_TYPE
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
FileSpec.builder(BLOCK_PACKAGE, upperCamelName)
|
val fileContent = FileSpec.builder(BLOCK_PACKAGE, upperCamelName)
|
||||||
.addComment("IF YOU CHANGE THIS FILE, MOVE IT FROM `generatedKotlin` TO `kotlin` OR IT WILL BE OVERWRITTEN.")
|
.addComment("IF YOU CHANGE THIS FILE, MOVE IT FROM `generatedKotlin` TO `kotlin` OR IT WILL BE OVERWRITTEN.")
|
||||||
.addType(type)
|
.addType(type)
|
||||||
.build()
|
.build()
|
||||||
.writeTo(outputDir)
|
.toString()
|
||||||
|
.replaceFirst("\n\nimport $IMPORT_FOR_REMOVAL_PACKAGE_NAME.$PROPERTY_TYPE_FOR_REMOVAL_NAME", "")
|
||||||
|
.replaceFirst(": $PROPERTY_TYPE_FOR_REMOVAL_NAME", "")
|
||||||
|
.replaceFirst("Block.Codec", "Codec")
|
||||||
|
|
||||||
|
outputDir.resolve(filePathRelativeToSourceRoot).writeText(fileContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue