Archived
1
0
Fork 0

Add block codecs

This commit is contained in:
Moritz Ruth 2020-11-15 21:56:17 +01:00
parent 653f62447c
commit 4cc3d8f17f
10 changed files with 159 additions and 20 deletions

View file

@ -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

View file

@ -0,0 +1,5 @@
package space.blokk.util
import kotlin.reflect.KProperty
data class KPropertyValuePair<V>(val property: KProperty<V>, val value: V)

View file

@ -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
}

View file

@ -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) }
}
}
}
}
}
} }

View file

@ -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

View 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()
}
}

View 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"
)
}
}

View file

@ -0,0 +1,4 @@
package space.blokk.world.block.codec
class AcaciaButtonCodec {
}

View file

@ -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() {

View file

@ -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)
} }
} }