diff --git a/build.gradle.kts b/build.gradle.kts index 812863f..503fe1c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,6 +30,8 @@ dependencies { implementation("de.bixilon:kutil:1.23.2") implementation("de.bixilon:mbf-kotlin:1.0.2") + implementation("it.unimi.dsi", "fastutil-core", "8.5.12") + testImplementation(kotlin("test")) } diff --git a/src/main/kotlin/de.bixilon.minosoft.meta.transpiler/MinosoftMetaTranspiler.kt b/src/main/kotlin/de.bixilon.minosoft.meta.transpiler/MinosoftMetaTranspiler.kt index 97d3779..4cdc47e 100644 --- a/src/main/kotlin/de.bixilon.minosoft.meta.transpiler/MinosoftMetaTranspiler.kt +++ b/src/main/kotlin/de.bixilon.minosoft.meta.transpiler/MinosoftMetaTranspiler.kt @@ -13,7 +13,6 @@ import de.bixilon.mbf.MBFBinaryWriter import de.bixilon.mbf.MBFCompressionTypes import de.bixilon.mbf.MBFData import de.bixilon.mbf.MBFDataInfo -import de.bixilon.minosoft.meta.transpiler.processors.GenericProcessor import de.bixilon.minosoft.meta.transpiler.processors.Processors import java.io.* import java.util.* @@ -45,7 +44,8 @@ object MinosoftMetaTranspiler { if (error.isNotEmpty()) { for (error in error) { - System.err.println("Error in version ${error.version} in type ${error.type}: ${error.cause}") + System.err.println("Error in version ${error.version} in type ${error.type}:") + error.cause!!.printStackTrace() } exitProcess(1) } @@ -93,12 +93,12 @@ object MinosoftMetaTranspiler { } private fun readFile(stream: InputStream, version: String, type: String, output: File) { - val processor = Processors.types[type] ?: GenericProcessor + val processor = Processors.types[type]?.build() try { println("Validating $type ($version)") total.incrementAndGet() val json: JsonObject = Jackson.MAPPER.readValue(stream) - processor.validate(json) + processor?.validate(json) val hash = storeMbf(json, output) val entry = MetaVersionEntry(version, hash) mbf.synchronizedGetOrPut(type) { Collections.synchronizedList(mutableListOf()) } += entry diff --git a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/BlockProcessor.kt b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/BlockProcessor.kt new file mode 100644 index 0000000..9c1bdd5 --- /dev/null +++ b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/BlockProcessor.kt @@ -0,0 +1,51 @@ +package de.bixilon.minosoft.meta.transpiler.processors + +import de.bixilon.kutil.cast.CastUtil.unsafeCast +import de.bixilon.kutil.json.JsonObject +import de.bixilon.kutil.primitive.IntUtil.toInt +import it.unimi.dsi.fastutil.ints.IntOpenHashSet + +class BlockProcessor : Processor { + private val ids = IntOpenHashSet() + + private fun validateId(identifier: String, data: JsonObject): Int { + val id = data["id"]!!.toInt() + if (id < 1) throw IllegalArgumentException("Id < 1: $id for item $identifier") + if (id > 0xFF) throw IllegalArgumentException("Id > 0xFF: $id for item $identifier") + return id + } + + private fun validateMeta(identifier: String, data: JsonObject): Int { + val meta = data["meta"]?.toInt() ?: return 0 + if (meta < 0) throw IllegalArgumentException("Meta < 0: $meta for item $identifier") + if (meta > 0x0F) throw IllegalArgumentException("Meta > 0x0F: $meta for item $identifier") + return meta + } + + override fun validateEntry(identifier: String, data: JsonObject) { + val states = data["states"] + if (states != null) { + return validateStates(identifier, states.unsafeCast()) + } + validateIdAndMeta(identifier, data) + } + + private fun validateStates(identifier: String, states: List) { + for (entry in states) { + validateIdAndMeta(identifier, entry) + } + } + + private fun validateIdAndMeta(identifier: String, data: JsonObject) { + val id = validateId(identifier, data) + val meta = validateMeta(identifier, data) + val combined = id shl 4 or meta + if (!ids.add(combined)) { + throw IllegalStateException("Id duplicated $id (meta=$meta)") + } + } + + companion object : ProcessorBuilder { + override fun build() = BlockProcessor() + } +} diff --git a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/GenericProcessor.kt b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/GenericProcessor.kt deleted file mode 100644 index 4dae100..0000000 --- a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/GenericProcessor.kt +++ /dev/null @@ -1,7 +0,0 @@ -package de.bixilon.minosoft.meta.transpiler.processors - -import de.bixilon.kutil.json.JsonObject - -object GenericProcessor : Processor { - override fun validate(data: JsonObject) = Unit -} diff --git a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/ItemProcessor.kt b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/ItemProcessor.kt new file mode 100644 index 0000000..8488a9f --- /dev/null +++ b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/ItemProcessor.kt @@ -0,0 +1,38 @@ +package de.bixilon.minosoft.meta.transpiler.processors + +import de.bixilon.kutil.json.JsonObject +import de.bixilon.kutil.primitive.IntUtil.toInt +import it.unimi.dsi.fastutil.ints.IntOpenHashSet + +class ItemProcessor : Processor { + private val ids = IntOpenHashSet() + + private fun validateId(identifier: String, data: JsonObject): Int { + val id = data["id"]!!.toInt() + if (id < 1) throw IllegalArgumentException("Id < 1: $id for item $identifier") + if (id > 0xFFFF) throw IllegalArgumentException("Id > 0xFFFF: $id for item $identifier") + + return id + } + + private fun validateMeta(identifier: String, data: JsonObject): Int { + val meta = data["meta"]?.toInt() ?: return 0 + if (meta < 0) throw IllegalArgumentException("Meta < 0: $meta for item $identifier") + if (meta > 0xFFFF) throw IllegalArgumentException("Meta > 0xFFFF: $meta for item $identifier") + + return meta + } + + override fun validateEntry(identifier: String, data: JsonObject) { + val id = validateId(identifier, data) + val meta = validateMeta(identifier, data) + val combined = id shl 16 or meta + if (!this.ids.add(combined)) { + throw IllegalStateException("Id duplicated: $id (meta=$meta)") + } + } + + companion object : ProcessorBuilder { + override fun build() = ItemProcessor() + } +} diff --git a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processor.kt b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processor.kt index f494054..4ef1309 100644 --- a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processor.kt +++ b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processor.kt @@ -1,7 +1,15 @@ package de.bixilon.minosoft.meta.transpiler.processors +import de.bixilon.kutil.cast.CastUtil.unsafeCast import de.bixilon.kutil.json.JsonObject interface Processor { - fun validate(data: JsonObject) + + fun validate(data: JsonObject) { + for ((key, value) in data) { + validateEntry(key.removePrefix("minecraft:"), value.unsafeCast()) + } + } + + fun validateEntry(identifier: String, data: JsonObject) } diff --git a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/ProcessorBuilder.kt b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/ProcessorBuilder.kt new file mode 100644 index 0000000..2d00935 --- /dev/null +++ b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/ProcessorBuilder.kt @@ -0,0 +1,6 @@ +package de.bixilon.minosoft.meta.transpiler.processors + +fun interface ProcessorBuilder { + + fun build(): Processor +} diff --git a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processors.kt b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processors.kt index 4ad4497..277fcc1 100644 --- a/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processors.kt +++ b/src/main/kotlin/de/bixilon/minosoft/meta/transpiler/processors/Processors.kt @@ -1,7 +1,8 @@ package de.bixilon.minosoft.meta.transpiler.processors object Processors { - val types: MutableMap = mutableMapOf( - + val types: MutableMap = mutableMapOf( + "items" to ItemProcessor, + "blocks" to BlockProcessor, ) }