From f6ef634b69c6b381a3aeaee22c614efb2bf6c28c Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 23 Mar 2023 12:05:39 +0100 Subject: [PATCH] wip block state loading, wip texture resolving --- .../gui/rendering/models/BlockModelTest.kt | 23 ++------- .../rendering/models/BlockStateModelTest.kt | 49 +++++++++++++++++-- .../gui/rendering/models/ModelTestUtil.kt | 25 +++++++++- .../rendering/models/loader/BlockLoader.kt | 10 ++-- .../rendering/models/raw/block/BlockModel.kt | 37 ++++++++++++-- 5 files changed, 109 insertions(+), 35 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockModelTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockModelTest.kt index 86a42dfe5..4ad2c7f88 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockModelTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockModelTest.kt @@ -15,13 +15,10 @@ package de.bixilon.minosoft.gui.rendering.models import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec3.Vec3 -import de.bixilon.kutil.reflection.ReflectionUtil.forceSet -import de.bixilon.minosoft.assets.MemoryAssetsManager import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft -import de.bixilon.minosoft.gui.rendering.models.loader.BlockLoader -import de.bixilon.minosoft.gui.rendering.models.loader.ModelLoader -import de.bixilon.minosoft.gui.rendering.models.loader.ModelLoader.Companion.model +import de.bixilon.minosoft.gui.rendering.models.ModelTestUtil.createAssets +import de.bixilon.minosoft.gui.rendering.models.ModelTestUtil.createLoader import de.bixilon.minosoft.gui.rendering.models.raw.block.BlockModel import de.bixilon.minosoft.gui.rendering.models.raw.block.element.ModelElement import de.bixilon.minosoft.gui.rendering.models.raw.block.element.face.FaceUV @@ -30,32 +27,18 @@ import de.bixilon.minosoft.gui.rendering.models.raw.display.DisplayPositions import de.bixilon.minosoft.gui.rendering.models.raw.display.ModelDisplay import de.bixilon.minosoft.gui.rendering.models.raw.light.GUILights import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rad -import de.bixilon.minosoft.test.IT.OBJENESIS -import de.bixilon.minosoft.util.KUtil.toResourceLocation import org.testng.Assert.assertEquals import org.testng.annotations.Test @Test(groups = ["models"]) class BlockModelTest { - private fun createLoader(): ModelLoader { - val instance = OBJENESIS.newInstance(ModelLoader::class.java) - instance::block.forceSet(OBJENESIS.newInstance(BlockLoader::class.java)) - - - return instance - } private fun loadModel(json: String, files: Map = emptyMap()): BlockModel { val loader = createLoader() - - val assets = MemoryAssetsManager() + val assets = loader.createAssets(files) assets.push(minosoft("models/block/named.json"), json) - for ((name, value) in files) { - assets.push(name.toResourceLocation().model(), value) - } - loader.block::assets.forceSet(assets) return loader.block.loadBlock(minosoft("block/named")) } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateModelTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateModelTest.kt index 298ed1eae..f68b0719a 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateModelTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateModelTest.kt @@ -15,16 +15,37 @@ package de.bixilon.minosoft.gui.rendering.models import de.bixilon.kutil.cast.CastUtil.unsafeCast import de.bixilon.kutil.collections.CollectionUtil.extend +import de.bixilon.kutil.reflection.ReflectionUtil.forceSet +import de.bixilon.minosoft.data.registries.blocks.settings.BlockSettings +import de.bixilon.minosoft.data.registries.blocks.types.Block +import de.bixilon.minosoft.data.registries.blocks.types.building.WoolBlock +import de.bixilon.minosoft.data.registries.blocks.types.legacy.CustomBlockModel +import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft +import de.bixilon.minosoft.gui.rendering.models.ModelTestUtil.createAssets +import de.bixilon.minosoft.gui.rendering.models.loader.BlockLoader.Companion.blockState +import de.bixilon.minosoft.gui.rendering.models.raw.block.BlockModel import de.bixilon.minosoft.gui.rendering.models.raw.block.state.DirectBlockModel import de.bixilon.minosoft.gui.rendering.models.raw.block.state.apply.BlockStateModel import de.bixilon.minosoft.gui.rendering.models.raw.block.state.variant.SingleVariantBlockModel +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture +import de.bixilon.minosoft.protocol.versions.Version +import de.bixilon.minosoft.test.IT import org.testng.Assert.assertEquals import org.testng.annotations.Test @Test(groups = ["models"]) class BlockStateModelTest { - private fun loadModel(state: String, files: Map): DirectBlockModel = TODO() + private fun loadModel(block: Block, state: String, version: Version = IT.VERSION, files: Map): DirectBlockModel { + val loader = ModelTestUtil.createLoader() + loader.block::version.forceSet(version) + val assets = loader.createAssets(files) + val modelName = (if (block is CustomBlockModel) block.getModelName(version) else block.identifier)?.blockState() ?: throw NullPointerException("Can not get model name: $block") + assets.push(modelName, state) + + + return loader.block.loadState(block) ?: throw NullPointerException("empty block model!") + } fun redWool() { @@ -32,14 +53,36 @@ class BlockStateModelTest { val models = BlockModelTest.FILES.extend( "block/red_wool" to """{"parent":"minecraft:block/cube_all","textures":{"all":"minecraft:block/red_wool"}}""", ) - val model = loadModel(state, models) + val model = loadModel(WoolBlock.RedWool(settings = BlockSettings()), state, files = models) + val texture = minecraft("block/red_wool").texture() assertEquals(model.unsafeCast().apply, BlockStateModel( - model = BlockModelTest.CUBE_ALL_MODEL, + model = BlockModel( + BlockModelTest.CUBE_ALL_MODEL.guiLight, + BlockModelTest.CUBE_ALL_MODEL.display, + BlockModelTest.CUBE_ALL_MODEL.elements, + textures = mapOf( + "particle" to texture, + "down" to texture, + "up" to texture, + "north" to texture, + "east" to texture, + "south" to texture, + "west" to texture, + "all" to texture, + ), + BlockModelTest.CUBE_ALL_MODEL.ambientOcclusion, + ), x = 0, y = 0, uvLock = false, weight = 1, )) } + + + // TODO: simple, variants, pre-flattening variants (e.g. grass snowy), multipart, multipart pre-flattening + // TODO: model rename (silver wool vs light_gray_wool) + + // TODO: bakery } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/ModelTestUtil.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/ModelTestUtil.kt index 0fef605e6..c12481825 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/ModelTestUtil.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/ModelTestUtil.kt @@ -13,9 +13,32 @@ package de.bixilon.minosoft.gui.rendering.models +import de.bixilon.kutil.reflection.ReflectionUtil.forceSet +import de.bixilon.minosoft.assets.MemoryAssetsManager +import de.bixilon.minosoft.gui.rendering.models.loader.BlockLoader +import de.bixilon.minosoft.gui.rendering.models.loader.ModelLoader +import de.bixilon.minosoft.gui.rendering.models.loader.ModelLoader.Companion.model +import de.bixilon.minosoft.test.IT +import de.bixilon.minosoft.util.KUtil.toResourceLocation + object ModelTestUtil { - fun createAssets(vararg files: Pair) { + fun createLoader(): ModelLoader { + val instance = IT.OBJENESIS.newInstance(ModelLoader::class.java) + instance::block.forceSet(IT.OBJENESIS.newInstance(BlockLoader::class.java)) + + return instance + } + + fun ModelLoader.createAssets(files: Map): MemoryAssetsManager { + val assets = MemoryAssetsManager() + + for ((name, value) in files) { + assets.push(name.toResourceLocation().model(), value) + } + this.block::assets.forceSet(assets) + + return assets } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/loader/BlockLoader.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/loader/BlockLoader.kt index b66a4d6dc..2af86c5b5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/loader/BlockLoader.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/loader/BlockLoader.kt @@ -13,7 +13,6 @@ package de.bixilon.minosoft.gui.rendering.models.loader -import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf import de.bixilon.kutil.latch.CountUpAndDownLatch import de.bixilon.minosoft.assets.util.InputStreamUtil.readJsonObject import de.bixilon.minosoft.data.registries.blocks.types.Block @@ -27,7 +26,6 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation class BlockLoader(private val loader: ModelLoader) { val assets = loader.context.connection.assetsManager val version = loader.context.connection.version - private val cache: MutableMap = synchronizedMapOf() fun loadBlock(name: ResourceLocation): BlockModel { val file = name.model("block/") @@ -39,11 +37,11 @@ class BlockLoader(private val loader: ModelLoader) { return BlockModel.deserialize(parent, data) } - private fun loadState(block: Block) { - val file = (if (block is CustomBlockModel) block.getModelName(version) else block.identifier)?.blockState() ?: return + fun loadState(block: Block): DirectBlockModel? { + val file = (if (block is CustomBlockModel) block.getModelName(version) else block.identifier)?.blockState() ?: return null val data = assets[file].readJsonObject() - val model = DirectBlockModel.deserialize(this, data) + return DirectBlockModel.deserialize(this, data) } fun load(latch: CountUpAndDownLatch) { @@ -53,7 +51,7 @@ class BlockLoader(private val loader: ModelLoader) { companion object { - private fun ResourceLocation.blockState(): ResourceLocation { + fun ResourceLocation.blockState(): ResourceLocation { return ResourceLocation(this.namespace, "blockstates/" + this.path + ".json") } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/raw/block/BlockModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/raw/block/BlockModel.kt index 8ffa2c377..785d3fbbc 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/raw/block/BlockModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/raw/block/BlockModel.kt @@ -23,13 +23,15 @@ import de.bixilon.minosoft.gui.rendering.models.raw.block.element.ModelElement import de.bixilon.minosoft.gui.rendering.models.raw.display.DisplayPositions import de.bixilon.minosoft.gui.rendering.models.raw.display.ModelDisplay import de.bixilon.minosoft.gui.rendering.models.raw.light.GUILights +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture +import de.bixilon.minosoft.util.KUtil.toResourceLocation import java.util.* data class BlockModel( val guiLight: GUILights, val display: Map?, val elements: List?, - val textures: Map?, + val textures: Map?, // either String or ResourceLocation val ambientOcclusion: Boolean, ) { @@ -62,16 +64,41 @@ data class BlockModel( return elements } - private fun textures(data: JsonObject, parent: Map?): Map? { + private fun textures(data: JsonObject, parent: Map?): Map? { if (data.isEmpty()) return parent - val textures: MutableMap = parent?.toMutableMap() ?: mutableMapOf() + val textures: MutableMap = parent?.toMutableMap() ?: mutableMapOf() for ((name, value) in data) { - textures[name] = value.toString() + val string = value.toString() + if (!string.startsWith('#')) { + // not a variable + textures[name] = string.toResourceLocation().texture() + } else { + textures[name] = string.substring(1) + } } - return textures + return textures.resolveTextures() + } + + private fun Map.resolve(value: Any, output: MutableMap): Any { + if (value !is String) return value // texture identifier + val resolved = this[value] ?: return value + output[value] = resolved // cache result, even if not needed + return resolved + } + + private fun Map.resolveTextures(): Map { + if (size <= 1) return this // if it has just one element, we can not resolve anything + + val output: MutableMap = mutableMapOf() + + for ((entry, value) in this) { + output[entry] = resolve(value, output) + } + + return output } fun deserialize(parent: BlockModel?, data: JsonObject): BlockModel {