wip block state loading, wip texture resolving

This commit is contained in:
Bixilon 2023-03-23 12:05:39 +01:00
parent 41d7001389
commit f6ef634b69
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 109 additions and 35 deletions

View File

@ -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<String, String> = 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"))
}

View File

@ -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<String, String>): DirectBlockModel = TODO()
private fun loadModel(block: Block, state: String, version: Version = IT.VERSION, files: Map<String, String>): 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<String, String>(
"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<SingleVariantBlockModel>().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
}

View File

@ -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<String, String>) {
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<String, String>): MemoryAssetsManager {
val assets = MemoryAssetsManager()
for ((name, value) in files) {
assets.push(name.toResourceLocation().model(), value)
}
this.block::assets.forceSet(assets)
return assets
}
}

View File

@ -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<ResourceLocation, BlockModel> = 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")
}
}

View File

@ -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<DisplayPositions, ModelDisplay>?,
val elements: List<ModelElement>?,
val textures: Map<String, String>?,
val textures: Map<String, Any>?, // either String or ResourceLocation
val ambientOcclusion: Boolean,
) {
@ -62,16 +64,41 @@ data class BlockModel(
return elements
}
private fun textures(data: JsonObject, parent: Map<String, String>?): Map<String, String>? {
private fun textures(data: JsonObject, parent: Map<String, Any>?): Map<String, Any>? {
if (data.isEmpty()) return parent
val textures: MutableMap<String, String> = parent?.toMutableMap() ?: mutableMapOf()
val textures: MutableMap<String, Any> = 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<String, Any>.resolve(value: Any, output: MutableMap<String, Any>): 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<String, Any>.resolveTextures(): Map<String, Any> {
if (size <= 1) return this // if it has just one element, we can not resolve anything
val output: MutableMap<String, Any> = mutableMapOf()
for ((entry, value) in this) {
output[entry] = resolve(value, output)
}
return output
}
fun deserialize(parent: BlockModel?, data: JsonObject): BlockModel {