diff --git a/.runConfigurations/Generate.run.xml b/.runConfigurations/Generate.run.xml
index 1907bf1..3f6e341 100644
--- a/.runConfigurations/Generate.run.xml
+++ b/.runConfigurations/Generate.run.xml
@@ -4,7 +4,7 @@
-
+
diff --git a/blokk-api/src/main/kotlin/space/blokk/tags/Tag.kt b/blokk-api/src/main/kotlin/space/blokk/tags/Tag.kt
index d1b72c1..78957e1 100644
--- a/blokk-api/src/main/kotlin/space/blokk/tags/Tag.kt
+++ b/blokk-api/src/main/kotlin/space/blokk/tags/Tag.kt
@@ -10,7 +10,7 @@ class Tag(val name: String, val type: Type, val rawValues: List) {
}
val numericIDs: List = when (type) {
- Type.BLOCKS -> values.map { Material.byID.getValue(it).numericID }
+ Type.BLOCKS -> values.map { Material.byID.getValue(it).codec.id }
else -> TODO()
}
diff --git a/blokk-api/src/main/kotlin/space/blokk/tags/TagRegistry.kt b/blokk-api/src/main/kotlin/space/blokk/tags/TagRegistry.kt
index 4615b28..4fe291e 100644
--- a/blokk-api/src/main/kotlin/space/blokk/tags/TagRegistry.kt
+++ b/blokk-api/src/main/kotlin/space/blokk/tags/TagRegistry.kt
@@ -1,5 +1,5 @@
package space.blokk.tags
object TagRegistry {
- val tags: Map = getTags()
+ val tags: Map = MINECRAFT_INTERNAL_TAGS
}
diff --git a/blokk-api/src/main/kotlin/space/blokk/world/block/Air.kt b/blokk-api/src/main/kotlin/space/blokk/world/block/Air.kt
index 27749e9..a9478b5 100644
--- a/blokk-api/src/main/kotlin/space/blokk/world/block/Air.kt
+++ b/blokk-api/src/main/kotlin/space/blokk/world/block/Air.kt
@@ -1,6 +1,17 @@
package space.blokk.world.block
+import space.blokk.NamespacedID
+
/**
* Material: [AIR][Material.AIR]
*/
-object Air : Block(), Block.Meta by meta(0, 0)
+object Air : Block(), Material by material(
+ 0,
+ NamespacedID("minecraft:air"),
+ 0,
+ 0f,
+ true,
+ 0,
+ 0,
+ BLOCK_COLLISION_SHAPES[0]
+)
diff --git a/blokk-api/src/main/kotlin/space/blokk/world/block/Block.kt b/blokk-api/src/main/kotlin/space/blokk/world/block/Block.kt
index c885fa1..2df2534 100644
--- a/blokk-api/src/main/kotlin/space/blokk/world/block/Block.kt
+++ b/blokk-api/src/main/kotlin/space/blokk/world/block/Block.kt
@@ -1,5 +1,6 @@
package space.blokk.world.block
+import space.blokk.NamespacedID
import kotlin.reflect.KClass
/**
@@ -8,23 +9,31 @@ import kotlin.reflect.KClass
* Blocks should always be **immutable**.
*/
abstract class Block internal constructor() {
- /**
- * The [Material] of this block.
- */
- val material: Material get() = Material.byClass.getValue(this::class)
-
- interface Meta {
- val blockClass: KClass
- val codec: BlockCodec
- }
-
companion object {
/**
* See [DaylightDetector] for an example on how this function should be used.
*/
- internal inline fun meta(id: Int, firstStateID: Int) = object : Meta {
+ internal inline fun material(
+ numericID: Int,
+ id: NamespacedID,
+ firstStateID: Int,
+ hardness: Float,
+ transparent: Boolean,
+ filteredLight: Int,
+ emittedLight: Int,
+ collisionShape: CollisionShape
+ ) = object : Material {
override val blockClass: KClass = T::class
- override val codec: BlockCodec = BlockCodec(blockClass, id, firstStateID)
+ override val codec: BlockCodec = BlockCodec(blockClass, numericID, firstStateID)
+ override val id: NamespacedID = id
+ override val hardness: Float = hardness
+ override val transparent: Boolean = transparent
+ override val filteredLight: Int = filteredLight
+ override val emittedLight: Int = emittedLight
+ override val collisionShape: CollisionShape = collisionShape
}
}
}
+
+@Suppress("UNCHECKED_CAST")
+fun T.material(): Material = Material.byClass(this::class) as Material
diff --git a/blokk-api/src/main/kotlin/space/blokk/world/block/BlockCodec.kt b/blokk-api/src/main/kotlin/space/blokk/world/block/BlockCodec.kt
index 405805d..4ebef1d 100644
--- a/blokk-api/src/main/kotlin/space/blokk/world/block/BlockCodec.kt
+++ b/blokk-api/src/main/kotlin/space/blokk/world/block/BlockCodec.kt
@@ -44,7 +44,7 @@ class BlockCodec internal constructor(
}
// If this happens, we did something wrong with adding the attributes or with clamping integer attributes
- if (index == -1) throw Error("The state of block (${block.material}) has no ID")
+ if (index == -1) throw Error("The state of block (${block.material()!!.id}) has no ID")
return firstStateID + index
}
diff --git a/blokk-api/src/main/kotlin/space/blokk/world/block/CaveAir.kt b/blokk-api/src/main/kotlin/space/blokk/world/block/CaveAir.kt
index a5be3b8..898c011 100644
--- a/blokk-api/src/main/kotlin/space/blokk/world/block/CaveAir.kt
+++ b/blokk-api/src/main/kotlin/space/blokk/world/block/CaveAir.kt
@@ -1,6 +1,17 @@
package space.blokk.world.block
+import space.blokk.NamespacedID
+
/**
* Material: [CAVE_AIR][Material.CAVE_AIR]
*/
-object CaveAir : Block(), Block.Meta by meta(617, 9130)
+object CaveAir : Block(), Material by material(
+ 617,
+ NamespacedID("minecraft:cave_air"),
+ 9130,
+ 0f,
+ true,
+ 0,
+ 0,
+ BLOCK_COLLISION_SHAPES[0]
+)
diff --git a/blokk-api/src/main/kotlin/space/blokk/world/block/DaylightDetector.kt b/blokk-api/src/main/kotlin/space/blokk/world/block/DaylightDetector.kt
index bfdbda3..9fe7228 100644
--- a/blokk-api/src/main/kotlin/space/blokk/world/block/DaylightDetector.kt
+++ b/blokk-api/src/main/kotlin/space/blokk/world/block/DaylightDetector.kt
@@ -1,5 +1,7 @@
package space.blokk.world.block
+import space.blokk.NamespacedID
+
/**
* Material: [DAYLIGHT_DETECTOR][Material.DAYLIGHT_DETECTOR]
*/
@@ -9,5 +11,14 @@ data class DaylightDetector(
@Attribute(15)
val power: Int
) : Block() {
- companion object : Meta by meta(1, 6158)
+ companion object : Material by material(
+ 1,
+ NamespacedID("minecraft:daylight_detector"),
+ 6158,
+ 0.2f,
+ true,
+ 0,
+ 0,
+ BLOCK_COLLISION_SHAPES[60]
+ )
}
diff --git a/blokk-api/src/main/kotlin/space/blokk/world/block/Material.kt b/blokk-api/src/main/kotlin/space/blokk/world/block/Material.kt
new file mode 100644
index 0000000..9a4ff1a
--- /dev/null
+++ b/blokk-api/src/main/kotlin/space/blokk/world/block/Material.kt
@@ -0,0 +1,26 @@
+package space.blokk.world.block
+
+import space.blokk.NamespacedID
+import kotlin.reflect.KClass
+
+interface Material {
+ val blockClass: KClass
+ val codec: BlockCodec
+ val id: NamespacedID
+ val hardness: Float
+ val transparent: Boolean
+ val filteredLight: Int
+ val emittedLight: Int
+ val collisionShape: CollisionShape
+
+ companion object {
+ val all = GENERATED_BLOCKS
+ val byID = GENERATED_BLOCKS.map { it.id to it }.toMap()
+
+ private val byClass = GENERATED_BLOCKS.map { it.blockClass to it }.toMap()
+
+ @Suppress("UNCHECKED_CAST")
+ fun byClass(blockClass: KClass): Material? = byClass[blockClass] as Material?
+ inline fun byClass(): Material? = byClass(T::class)
+ }
+}
diff --git a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ChunkDataPacketCodec.kt b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ChunkDataPacketCodec.kt
index ef8d773..53469ca 100644
--- a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ChunkDataPacketCodec.kt
+++ b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ChunkDataPacketCodec.kt
@@ -12,7 +12,7 @@ import space.blokk.world.block.Material
object ChunkDataPacketCodec : OutgoingPacketCodec(0x22, ChunkDataPacket::class) {
private val nonAirHeightmapIgnoredBlocks = setOf(Air::class, CaveAir::class)
- private val solidHeightmapIgnoredBlocks = Material.values().filter {
+ private val solidHeightmapIgnoredBlocks = Material.all.filter {
// TODO
true
}
diff --git a/blokk-packet-codecs/src/main/kotlin/space/blokk/util/GenerateHeightmap.kt b/blokk-packet-codecs/src/main/kotlin/space/blokk/util/GenerateHeightmap.kt
index 8795a45..c6a1ab9 100644
--- a/blokk-packet-codecs/src/main/kotlin/space/blokk/util/GenerateHeightmap.kt
+++ b/blokk-packet-codecs/src/main/kotlin/space/blokk/util/GenerateHeightmap.kt
@@ -2,8 +2,9 @@ package space.blokk.util
import space.blokk.world.Chunk
import space.blokk.world.block.Block
+import space.blokk.world.block.Material
-fun generateHeightmap(sections: Array?>, ignoredBlocks: Iterable>): ByteArray {
+fun generateHeightmap(sections: Array?>, ignoredBlocks: Iterable>): ByteArray {
val array = ByteArray(Chunk.AREA)
for (sectionIndex in sections.indices.reversed()) {
diff --git a/blokk-server/src/main/kotlin/space/blokk/BlokkScheduler.kt b/blokk-server/src/main/kotlin/space/blokk/BlokkScheduler.kt
index e273aba..05c24ed 100644
--- a/blokk-server/src/main/kotlin/space/blokk/BlokkScheduler.kt
+++ b/blokk-server/src/main/kotlin/space/blokk/BlokkScheduler.kt
@@ -113,6 +113,7 @@ class BlokkScheduler : Scheduler {
override fun registerShutdownTask(block: suspend () -> Unit): Scheduler.Task {
shutdownTasks.add(block)
+
return object : Scheduler.Task {
override fun cancel() {
shutdownTasks.remove(block)
diff --git a/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/BlocksAndMaterialGenerator.kt b/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/BlocksAndMaterialGenerator.kt
index e989693..fb7a0f4 100644
--- a/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/BlocksAndMaterialGenerator.kt
+++ b/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/BlocksAndMaterialGenerator.kt
@@ -2,6 +2,7 @@ package space.blokk.mdsp.generator
import com.google.common.base.CaseFormat
import com.jsoniter.JsonIterator
+import com.jsoniter.any.Any
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import space.blokk.mdsp.JsonAny
@@ -18,9 +19,6 @@ class BlocksAndMaterialGenerator(
val MATERIAL_TYPE = ClassName(BLOCK_PACKAGE, "Material")
val NAMESPACED_ID_TYPE = ClassName("space.blokk", "NamespacedID")
val BLOCK_TYPE = ClassName(BLOCK_PACKAGE, "Block")
- val K_CLASS_TYPE = ClassName("kotlin.reflect", "KClass")
- val MAP_TYPE = ClassName("kotlin.collections", "Map")
- val ARRAY_TYPE = ClassName("kotlin", "Array")
val BLOCK_BLACKLIST = listOf(
// Only used on the client side for y values lower than 0 and higher than 255
@@ -39,8 +37,8 @@ class BlocksAndMaterialGenerator(
val dataJson = workingDir.resolve("blocks.json").readText()
val blocks = JsonIterator.deserialize(dataJson).asList()
- generateBlockStubs(blocks)
- generateMaterialEnum(blocks)
+ generateBlockStubs(blocks, collisionShapesData.get("blocks").asMap())
+ generateBlocksList(blocks)
}
private fun generateCollisionShapes(shapes: Map) {
@@ -54,12 +52,12 @@ class BlocksAndMaterialGenerator(
val typeAlias = TypeAliasSpec.builder(
"CollisionShape",
- ARRAY_TYPE.parameterizedBy(ARRAY_TYPE.parameterizedBy(ClassName("kotlin", "Float")))
+ Array::class.asTypeName().parameterizedBy(Array::class.asTypeName().parameterizedBy(ClassName("kotlin", "Float")))
).build()
val property = PropertySpec.builder(
"BLOCK_COLLISION_SHAPES",
- ARRAY_TYPE.parameterizedBy(ClassName(BLOCK_PACKAGE, "CollisionShape"))
+ Array::class.asTypeName().parameterizedBy(ClassName(BLOCK_PACKAGE, "CollisionShape"))
)
.initializer("arrayOf(${items.joinToString()})")
.addKdoc(
@@ -75,18 +73,30 @@ class BlocksAndMaterialGenerator(
.writeTo(outputDir)
}
- private fun generateBlockStubs(blocks: List) {
+ private fun generateBlockStubs(blocks: List, collisionShapes: Map) {
for (block in blocks) {
val lowerUnderscoreName = block.get("name").toString()
if (BLOCK_BLACKLIST.contains(lowerUnderscoreName)) continue
val upperCamelName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, lowerUnderscoreName)
- val upperUnderscoreName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, lowerUnderscoreName)
- val specificMaterialType = MATERIAL_TYPE.nestedClass(upperUnderscoreName)
val filePathRelativeToSourceRoot = "./${BLOCK_PACKAGE.replace(".", "/")}/$upperCamelName.kt"
if (sourcesDir.resolve(filePathRelativeToSourceRoot).exists()) continue
+ val metaLines = listOf("%L", "%T(%S)", "%L", "%Lf", "%L", "%L", "%L", "BLOCK_COLLISION_SHAPES[%L]")
+
+ val metaArgs = arrayOf(
+ block.get("id").toInt(),
+ NAMESPACED_ID_TYPE,
+ "minecraft:$lowerUnderscoreName",
+ block.get("minStateId").toInt(),
+ block.get("hardness").toFloat(),
+ block.get("transparent").toBoolean(),
+ block.get("filterLight").toInt(),
+ block.get("emitLight").toInt(),
+ collisionShapes.getValue(lowerUnderscoreName).toInt()
+ )
+
val type = TypeSpec.classBuilder(upperCamelName)
.apply {
if (block.get("states").asList().isNotEmpty()) {
@@ -97,13 +107,12 @@ class BlocksAndMaterialGenerator(
addProperty(PropertySpec.builder("PLACEHOLDER", Unit::class).initializer("PLACEHOLDER").build())
}
}
- .addKdoc("Material: [$upperUnderscoreName][%T]", specificMaterialType)
.superclass(BLOCK_TYPE)
.addType(
TypeSpec.companionObjectBuilder()
.addSuperinterface(
- BLOCK_TYPE.nestedClass("Meta").parameterizedBy(ClassName(BLOCK_PACKAGE, upperCamelName)),
- CodeBlock.of("meta(${block.get("id").toInt()}, ${block.get("minStateId").toInt()})")
+ MATERIAL_TYPE.parameterizedBy(ClassName(BLOCK_PACKAGE, upperCamelName)),
+ CodeBlock.of("material(\n${metaLines.joinToString(",\n") { " $it" }}\n)", *metaArgs)
)
.build()
)
@@ -120,86 +129,21 @@ class BlocksAndMaterialGenerator(
}
}
- private fun generateMaterialEnum(blocks: List) {
- val cph = ConstructorPropertiesHelper()
+ private fun generateBlocksList(blocks: List) {
+ val names = blocks
+ .map { it.get("name").toString() }
+ .filter { !BLOCK_BLACKLIST.contains(it) }
+ .map { CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, it) }
- val builder = TypeSpec.enumBuilder("Material")
- .primaryConstructor(
- FunSpec.constructorBuilder()
- .addParameters(
- listOf(
- cph.create("numericID", Int::class),
- cph.create("id", NAMESPACED_ID_TYPE),
- cph.create(
- "blockMeta",
- BLOCK_TYPE.nestedClass("Meta").parameterizedBy(STAR)
- ),
- cph.create("hardness", Float::class),
- cph.create("transparent", Boolean::class),
- cph.create("filteredLight", Int::class),
- cph.create("maxStackSize", Byte::class),
- )
- )
- .build()
- )
- .addProperties(cph.getProperties())
-
- for (block in blocks) {
- val name = block.get("name").toString()
- if (BLOCK_BLACKLIST.contains(name)) continue
-
- val materialName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, name)
- val blockClassName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name)
-
- builder.addEnumConstant(
- materialName,
- TypeSpec.anonymousClassBuilder()
- .addSuperclassConstructorParameter("%L", block.get("id").toInt())
- .addSuperclassConstructorParameter("%T(%S)", NAMESPACED_ID_TYPE, "minecraft:$name")
- .addSuperclassConstructorParameter(
- "%T",
- ClassName(
- BLOCK_PACKAGE,
- blockClassName
- )
- )
- .addSuperclassConstructorParameter("%Lf", block.get("hardness").toFloat())
- .addSuperclassConstructorParameter("%L", block.get("transparent").toBoolean())
- .addSuperclassConstructorParameter("%L", block.get("filterLight").toInt().toByte())
- .addSuperclassConstructorParameter("%L", block.get("stackSize").toInt())
- .build()
- )
- }
-
- builder.addType(
- TypeSpec.companionObjectBuilder()
- .addProperty(
- PropertySpec.builder(
- "byClass",
- MAP_TYPE.parameterizedBy(
- K_CLASS_TYPE.parameterizedBy(WildcardTypeName.producerOf(BLOCK_TYPE)),
- MATERIAL_TYPE
- )
- )
- .initializer("values().map { it.blockMeta.blockClass to it }.toMap()")
- .build()
- )
- .addProperty(
- PropertySpec.builder(
- "byID",
- MAP_TYPE.parameterizedBy(
- NAMESPACED_ID_TYPE,
- MATERIAL_TYPE
- )
- )
- .initializer("values().map { it.id to it }.toMap()")
- .build()
- )
- .build()
+ val property = PropertySpec.builder(
+ "GENERATED_BLOCKS",
+ List::class.asTypeName().parameterizedBy(MATERIAL_TYPE.parameterizedBy(STAR))
)
+ .initializer("listOf(\n${names.joinToString(",\n")}\n)")
+ .build()
- FileSpec.builder(BLOCK_PACKAGE, "Material")
- .addType(builder.build())
+ FileSpec.builder(BLOCK_PACKAGE, "Blocks")
+ .addProperty(property)
.build()
.writeTo(outputDir)
}
diff --git a/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/TagsFileGenerator.kt b/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/TagsFileGenerator.kt
index aeda901..5236088 100644
--- a/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/TagsFileGenerator.kt
+++ b/buildSrc/src/main/kotlin/space/blokk/mdsp/generator/TagsFileGenerator.kt
@@ -1,26 +1,25 @@
package space.blokk.mdsp.generator
import com.jsoniter.JsonIterator
-import com.squareup.kotlinpoet.ClassName
-import com.squareup.kotlinpoet.FileSpec
-import com.squareup.kotlinpoet.FunSpec
-import com.squareup.kotlinpoet.KModifier
+import com.squareup.kotlinpoet.*
+import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import java.io.File
-class TagsFileGenerator(val workingDir: File, val outputDir: File) {
+class TagsFileGenerator(private val workingDir: File, private val outputDir: File) {
companion object {
const val TAGS_PACKAGE = "space.blokk.tags"
val TAG_TYPE = ClassName(TAGS_PACKAGE, "Tag")
- val TAG_TYPE_TYPE = TAG_TYPE.nestedClass("Type")
+ private val TAG_TYPE_TYPE = TAG_TYPE.nestedClass("Type")
val TAG_TYPE_TYPES_BY_DIR_NAME = mapOf(
"blocks" to TAG_TYPE_TYPE.nestedClass("BLOCKS"),
"entity_types" to TAG_TYPE_TYPE.nestedClass("ENTITY_TYPES"),
"fluids" to TAG_TYPE_TYPE.nestedClass("FLUIDS"),
"items" to TAG_TYPE_TYPE.nestedClass("ITEMS")
)
+ val MAP_TYPE = ClassName("kotlin.collections", "Map")
}
- val tagsDir = workingDir.resolve("generated/data/minecraft/tags")
+ private val tagsDir = workingDir.resolve("generated/data/minecraft/tags")
fun generate() {
val entries: List>> = TAG_TYPE_TYPES_BY_DIR_NAME.flatMap { (dirName, tagTypeType) ->
@@ -37,16 +36,16 @@ class TagsFileGenerator(val workingDir: File, val outputDir: File) {
}
}
- val function = FunSpec.builder("getTags")
- .addStatement(
- "return mapOf(\n${entries.joinToString(",\n") { it.first.prependIndent(" ") }}\n)",
+ val property = PropertySpec.builder("MINECRAFT_INTERNAL_TAGS", Map::class.asTypeName().parameterizedBy(String::class.asTypeName(), TAG_TYPE))
+ .initializer(
+ "mapOf(\n${entries.joinToString(",\n") { it.first.prependIndent(" ") }}\n)",
*entries.flatMap { it.second.toList() }.toTypedArray()
)
.addModifiers(KModifier.INTERNAL)
.build()
FileSpec.builder(TAGS_PACKAGE, "Tags")
- .addFunction(function)
+ .addProperty(property)
.build()
.writeTo(outputDir)
}