From a98e8a38b77607a3bcbb0382a5da2e11d68d7a76 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Sun, 22 Oct 2023 01:51:42 +0200 Subject: [PATCH] abstract chest animation, shulker model, more --- ...ationTest.kt => OpenCloseAnimationTest.kt} | 30 ++++--- .../bixilon/minosoft/config/DebugOptions.kt | 2 +- .../minosoft/data/direction/DirectionUtil.kt | 16 ---- .../minosoft/data/direction/Directions.kt | 3 - .../data/entities/block/BeaconBlockEntity.kt | 2 +- .../data/entities/block/BellBlockEntity.kt | 4 +- .../data/entities/block/BlockActionEntity.kt | 2 +- .../entities/block/MobSpawnerBlockEntity.kt | 2 +- .../entities/block/NoteBlockBlockEntity.kt | 6 +- .../storage/ShulkerBoxBlockEntity.kt | 9 ++- .../container/storage/StorageBlockEntity.kt | 9 ++- .../block/end/EndGatewayBlockEntity.kt | 2 +- .../redstone/piston/PistonBlockEntity.kt | 6 +- .../chunk/entities/DefaultEntityModels.kt | 10 +-- .../renderer/storage/OpenCloseAnimation.kt | 67 ++++++++++++++++ .../renderer/storage/chest/ChestAnimation.kt | 51 ++---------- .../renderer/storage/chest/ChestRenderer.kt | 15 +++- .../storage/shulker/ShulkerAnimation.kt | 54 +++++++++++++ .../storage/shulker/ShulkerBoxRenderer.kt | 80 +++++++++++++++++++ .../skeletal/instance/SkeletalInstance.kt | 16 ++-- .../model/elements/SkeletalRotation.kt | 2 +- .../packets/s2c/play/block/BlockActionS2CP.kt | 8 +- .../models/block/entities/shulker_box.smodel | 49 ++++++++++++ 23 files changed, 341 insertions(+), 104 deletions(-) rename src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/{chest/ChestAnimationTest.kt => OpenCloseAnimationTest.kt} (84%) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimation.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerAnimation.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt create mode 100644 src/main/resources/assets/minecraft/models/block/entities/shulker_box.smodel diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestAnimationTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimationTest.kt similarity index 84% rename from src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestAnimationTest.kt rename to src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimationTest.kt index be4c31bd8..40979bbb7 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestAnimationTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimationTest.kt @@ -11,7 +11,7 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.chest +package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.kutil.primitive.FloatUtil.matches @@ -20,6 +20,7 @@ import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalTransform import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.instance.KeyframeInstance.Companion.NOT_OVER import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.instance.KeyframeInstance.Companion.OVER +import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance import de.bixilon.minosoft.gui.rendering.skeletal.mesh.SkeletalMesh import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY import de.bixilon.minosoft.test.IT @@ -28,18 +29,15 @@ import org.testng.Assert.assertTrue import org.testng.annotations.Test @Test(groups = ["skeletal", "block_entity_rendering"]) -class ChestAnimationTest { - private val progress = ChestAnimation::class.java.getDeclaredField("progress").apply { isAccessible = true } +class OpenCloseAnimationTest { - private fun ChestAnimation.getProgress(): Float = progress.getFloat(this) - - private fun create(): ChestAnimation { + private fun create(): Animation { val mesh = IT.OBJENESIS.newInstance(SkeletalMesh::class.java) val context = IT.OBJENESIS.newInstance(RenderContext::class.java) - val model = BakedSkeletalModel(mesh, BakedSkeletalTransform(0, Vec3.EMPTY, mapOf("lid" to BakedSkeletalTransform(1, Vec3.EMPTY, emptyMap()))), 1, emptyMap()) + val model = BakedSkeletalModel(mesh, BakedSkeletalTransform(0, Vec3.EMPTY, emptyMap()), 1, emptyMap()) val instance = model.createInstance(context) - return ChestAnimation(instance) + return Animation(instance) } fun `create animation`() { @@ -84,5 +82,19 @@ class ChestAnimationTest { assertEquals(animation.getProgress(), 0.0f) } - // TODO: test transforming + private class Animation( + instance: SkeletalInstance, + ) : OpenCloseAnimation(instance) { + override val transform = instance.transform + + override val name get() = "dummy" + + override val closingDuration get() = 0.3f + override val openingDuration get() = 0.4f + + + override fun transform() = Unit + + fun getProgress() = this.progress + } } diff --git a/src/main/java/de/bixilon/minosoft/config/DebugOptions.kt b/src/main/java/de/bixilon/minosoft/config/DebugOptions.kt index b4da19ae4..d20c489be 100644 --- a/src/main/java/de/bixilon/minosoft/config/DebugOptions.kt +++ b/src/main/java/de/bixilon/minosoft/config/DebugOptions.kt @@ -25,5 +25,5 @@ object DebugOptions { const val LOG_RAW_CHAT = false - const val FORCE_CHEST_ANIMATION = true + const val FORCE_CHEST_ANIMATION = false } diff --git a/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt b/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt index b906138cf..2df79af37 100644 --- a/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt +++ b/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt @@ -13,11 +13,8 @@ package de.bixilon.minosoft.data.direction -import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.kutil.array.ArrayUtil import de.bixilon.minosoft.data.Axes -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rad object DirectionUtil { @@ -38,17 +35,4 @@ object DirectionUtil { return Directions.INDEXED[1][ArrayUtil.modifyArrayIndex(index.y + count, Directions.SIZE_SIDES)] } - - fun getRotation(direction: Directions): Vec3 { - // north is the base direction - // TODO: verify - return when (direction) { - Directions.NORTH -> Vec3.EMPTY - Directions.SOUTH -> Vec3(0, 180, 0) - Directions.WEST -> Vec3(0, 90, 0) - Directions.EAST -> Vec3(0, 270, 0) - Directions.UP -> Vec3(0, 0, 90) - Directions.DOWN -> Vec3(0, 0, 270) - }.rad - } } diff --git a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt index 658d46969..c16d86e4e 100644 --- a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt +++ b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt @@ -45,7 +45,6 @@ enum class Directions( val vectord = Vec3d(vector) val axis: Axes = unsafeNull() - val rotation: Vec3 = unsafeNull() val inverted: Directions = unsafeNull() private fun invert(): Directions { @@ -157,12 +156,10 @@ enum class Directions( } init { - val rotation = Directions::rotation.javaField!! val inverted = Directions::inverted.javaField!! val axis = Directions::axis.javaField!! for (direction in VALUES) { inverted.forceSet(direction, direction.invert()) - rotation.forceSet(direction, DirectionUtil.getRotation(direction)) axis.forceSet(direction, Axes[direction]) } NAME_MAP.unsafeCast>()["bottom"] = DOWN diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/BeaconBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/BeaconBlockEntity.kt index 57421f95e..8452b54c5 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/BeaconBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/BeaconBlockEntity.kt @@ -19,7 +19,7 @@ import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection class BeaconBlockEntity(connection: PlayConnection) : BlockEntity(connection), BlockActionEntity { - override fun setBlockActionData(data1: Int, data2: Int) { + override fun setBlockActionData(type: Int, data: Int) { // no data used, just recalculates the beam } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/BellBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/BellBlockEntity.kt index eba0261c9..8d300a6e8 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/BellBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/BellBlockEntity.kt @@ -22,8 +22,8 @@ class BellBlockEntity(connection: PlayConnection) : BlockEntity(connection), Blo var shakingDirection: Directions = Directions.NORTH private set - override fun setBlockActionData(data1: Int, data2: Int) { - shakingDirection = Directions[data2.toInt()] + override fun setBlockActionData(type: Int, data: Int) { + shakingDirection = Directions[data.toInt()] } companion object : BlockEntityFactory { diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/BlockActionEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/BlockActionEntity.kt index 643bba4c1..82fb5d848 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/BlockActionEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/BlockActionEntity.kt @@ -14,5 +14,5 @@ package de.bixilon.minosoft.data.entities.block interface BlockActionEntity { - fun setBlockActionData(data1: Int, data2: Int) + fun setBlockActionData(type: Int, data: Int) } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt index e1cebff2e..6bcf99c88 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt @@ -48,7 +48,7 @@ class MobSpawnerBlockEntity(connection: PlayConnection) : BlockEntity(connection flameParticleType?.let { connection.world += FlameParticle(connection, Vec3d(particlePosition), Vec3d.EMPTY, it.default()) } } - override fun setBlockActionData(data1: Int, data2: Int) { + override fun setBlockActionData(type: Int, data: Int) { // ToDo } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt index 6dc004267..3befa8c9d 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt @@ -41,8 +41,8 @@ class NoteBlockBlockEntity(connection: PlayConnection) : BlockEntity(connection) return properties[BlockProperties.NOTE]?.toInt() ?: 0 } - override fun setBlockActionData(data1: Int, data2: Int) { - instrument = when (data1.toInt()) { + override fun setBlockActionData(type: Int, data: Int) { + instrument = when (type.toInt()) { 0 -> Instruments.HARP 1 -> Instruments.BASS 2 -> Instruments.SNARE @@ -51,7 +51,7 @@ class NoteBlockBlockEntity(connection: PlayConnection) : BlockEntity(connection) else -> null } - pitch = data2.toInt() + pitch = data.toInt() showParticleNextTick = true // ToDo: Play sound? diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt index 066c41c06..5bf0cb36b 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt @@ -13,16 +13,23 @@ package de.bixilon.minosoft.data.entities.block.container.storage +import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.minosoft.data.entities.block.BlockEntityFactory +import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.data.registries.identified.AliasedIdentified import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft import de.bixilon.minosoft.data.registries.identified.ResourceLocation +import de.bixilon.minosoft.gui.rendering.RenderContext +import de.bixilon.minosoft.gui.rendering.chunk.entities.BlockEntityRenderer +import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.shulker.ShulkerBoxRenderer import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection -import de.bixilon.minosoft.util.KUtil import de.bixilon.minosoft.util.KUtil.toResourceLocationList class ShulkerBoxBlockEntity(connection: PlayConnection) : StorageBlockEntity(connection) { + override fun createRenderer(context: RenderContext, blockState: BlockState, blockPosition: Vec3i, light: Int): BlockEntityRenderer<*>? { + return ShulkerBoxRenderer(this, context, blockState, blockPosition, context.models.skeletal[ShulkerBoxRenderer.MODEL] ?: return null, light) + } companion object : BlockEntityFactory, AliasedIdentified { override val identifier: ResourceLocation = minecraft("shulker_box") diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/StorageBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/StorageBlockEntity.kt index 33bd553f8..a3a6ed65c 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/StorageBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/StorageBlockEntity.kt @@ -34,8 +34,13 @@ abstract class StorageBlockEntity(connection: PlayConnection) : ContainerBlockEn val closed: Boolean get() = viewing <= 0 - override fun setBlockActionData(data1: Int, data2: Int) { - val viewing = data2 and 0xFF // unsigned + override fun setBlockActionData(type: Int, data: Int) { + when (type) { + 1 -> setViewing(data and 0xFF) + } + } + + protected fun setViewing(viewing: Int) { if (this.viewing == viewing) return val previous = this.viewing this.viewing = viewing diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/end/EndGatewayBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/end/EndGatewayBlockEntity.kt index 7d88f0074..792292186 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/end/EndGatewayBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/end/EndGatewayBlockEntity.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection class EndGatewayBlockEntity(connection: PlayConnection) : BlockEntity(connection), BlockActionEntity { - override fun setBlockActionData(data1: Int, data2: Int) { + override fun setBlockActionData(type: Int, data: Int) { // just emits the beacon like beam } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/redstone/piston/PistonBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/redstone/piston/PistonBlockEntity.kt index fb9c90847..2baf4f981 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/redstone/piston/PistonBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/redstone/piston/PistonBlockEntity.kt @@ -29,9 +29,9 @@ open class PistonBlockEntity(connection: PlayConnection) : BlockEntity(connectio var direction: Directions = Directions.NORTH private set - override fun setBlockActionData(data1: Int, data2: Int) { - state = PistonStates[data1.toInt()] - direction = Directions[data2.toInt()] + override fun setBlockActionData(type: Int, data: Int) { + state = PistonStates[type.toInt()] + direction = Directions[data.toInt()] } companion object : BlockEntityFactory { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/DefaultEntityModels.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/DefaultEntityModels.kt index a70fae309..b154cc13c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/DefaultEntityModels.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/DefaultEntityModels.kt @@ -17,6 +17,7 @@ import de.bixilon.kutil.latch.AbstractLatch import de.bixilon.kutil.latch.AbstractLatch.Companion.child import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.chest.DoubleChestRenderer import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.chest.SingleChestRenderer +import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.shulker.ShulkerBoxRenderer import de.bixilon.minosoft.gui.rendering.models.loader.ModelLoader import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels @@ -24,12 +25,11 @@ import de.bixilon.minosoft.util.logging.LogMessageType object DefaultEntityModels { val MODELS = listOf( - SingleChestRenderer.NormalChest, - SingleChestRenderer.TrappedChest, - SingleChestRenderer.EnderChest, + SingleChestRenderer.NormalChest, SingleChestRenderer.TrappedChest, SingleChestRenderer.EnderChest, - DoubleChestRenderer.NormalChest, - DoubleChestRenderer.TrappedChest, + DoubleChestRenderer.NormalChest, DoubleChestRenderer.TrappedChest, + + ShulkerBoxRenderer, ) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimation.kt new file mode 100644 index 000000000..ff4ac53ab --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimation.kt @@ -0,0 +1,67 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage + +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.AbstractAnimation +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.instance.KeyframeInstance.Companion.NOT_OVER +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.instance.KeyframeInstance.Companion.OVER +import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance +import de.bixilon.minosoft.gui.rendering.skeletal.instance.TransformInstance + +abstract class OpenCloseAnimation( + protected val instance: SkeletalInstance, +) : AbstractAnimation { + protected abstract val transform: TransformInstance + protected var progress = 0.0f + protected var opening = true + + protected abstract val closingDuration: Float + protected abstract val openingDuration: Float + + override fun draw(delta: Float): Boolean { + return if (opening) drawOpening(delta) else drawClosing(delta) + } + + private fun drawOpening(delta: Float): Boolean { + this.progress += delta / openingDuration + if (this.progress > 1.0f) { + this.progress = 1.0f + } + transform() + return NOT_OVER + } + + private fun drawClosing(delta: Float): Boolean { + this.progress -= delta / closingDuration + if (progress <= 0.0f) { + this.progress = 0.0f + return OVER + } + transform() + return NOT_OVER + } + + protected abstract fun transform() + + fun open() { + if (progress <= 0.0f) { + instance.animation.play(this) + } + opening = true + } + + fun close() { + opening = false + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestAnimation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestAnimation.kt index 3ec3156be..027f894e7 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestAnimation.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestAnimation.kt @@ -14,47 +14,24 @@ package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.chest import de.bixilon.kotlinglm.vec3.Vec3 -import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.AbstractAnimation -import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.instance.KeyframeInstance.Companion.NOT_OVER -import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.instance.KeyframeInstance.Companion.OVER +import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.OpenCloseAnimation import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance import de.bixilon.minosoft.gui.rendering.util.mat.mat4.Mat4Util.rotateRadAssign import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.interpolateSine import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rad class ChestAnimation( - private val instance: SkeletalInstance, -) : AbstractAnimation { - private val transform = instance.transform.children[TRANSFORM]!! - private var progress = 0.0f - private var opening = true + instance: SkeletalInstance, +) : OpenCloseAnimation(instance) { + override val transform = instance.transform.children[TRANSFORM]!! override val name get() = NAME - override fun draw(delta: Float): Boolean { - return if (opening) drawOpening(delta) else drawClosing(delta) - } + override val closingDuration get() = 0.3f + override val openingDuration get() = 0.4f - private fun drawOpening(delta: Float): Boolean { - this.progress += delta / OPENING_TIME - if (this.progress > 1.0f) { - this.progress = 1.0f - } - transform() - return NOT_OVER - } - private fun drawClosing(delta: Float): Boolean { - this.progress -= delta / CLOSING_TIME - if (progress <= 0.0f) { - this.progress = 0.0f - return OVER - } - transform() - return NOT_OVER - } - - private fun transform() { + override fun transform() { val rotation = interpolateSine(this.progress, BASE, OPEN) transform.value .translateAssign(transform.pivot) @@ -62,25 +39,11 @@ class ChestAnimation( .translateAssign(-transform.pivot) } - fun open() { - if (progress <= 0.0f) { - instance.animation.play(this) - } - opening = true - } - - fun close() { - opening = false - } - companion object { const val TRANSFORM = "lid" const val NAME = "chest" - const val OPENING_TIME = 0.4f - const val CLOSING_TIME = 0.3f - private val BASE = Vec3(0.0f, 0.0f, 0.0f).rad private val OPEN = Vec3(90.0f, 0.0f, 0.0f).rad } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestRenderer.kt index bba1b8ecc..39c2e0aa1 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/ChestRenderer.kt @@ -13,12 +13,15 @@ package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.chest +import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.entities.block.container.storage.ChestBlockEntity import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties.getFacing import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.data.world.positions.BlockPosition import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.StorageBlockEntityRenderer import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rad abstract class ChestRenderer( state: BlockState, @@ -33,7 +36,8 @@ abstract class ChestRenderer( } override fun update(position: BlockPosition, state: BlockState, light: Int) { - skeletal?.update(position, state.getFacing()) + val rotation = ROTATION[state.getFacing().ordinal - Directions.SIDE_OFFSET] + skeletal?.update(position, rotation) skeletal?.light = light } @@ -44,4 +48,13 @@ abstract class ChestRenderer( override fun close() { animation?.close() } + + private companion object { + val ROTATION = arrayOf( + Vec3(0, 0, 0).rad, + Vec3(0, 180, 0).rad, + Vec3(0, 90, 0).rad, + Vec3(0, 270, 0).rad, + ) + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerAnimation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerAnimation.kt new file mode 100644 index 000000000..7ad9e34ef --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerAnimation.kt @@ -0,0 +1,54 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.shulker + +import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.OpenCloseAnimation +import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance +import de.bixilon.minosoft.gui.rendering.util.mat.mat4.Mat4Util.rotateRadAssign +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.interpolateLinear +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rad + +class ShulkerAnimation( + instance: SkeletalInstance, +) : OpenCloseAnimation(instance) { + override val transform = instance.transform.children[TRANSFORM]!! + + override val name get() = NAME + + override val closingDuration get() = 0.5f + override val openingDuration get() = 0.5f + + override fun transform() { + val rotation = interpolateLinear(this.progress, ROTATION_CLOSED, ROTATION_OPENED) + val translation = interpolateLinear(this.progress, TRANSLATION_CLOSED, TRANSLATION_OPENED) + transform.value + .translateAssign(translation) + .translateAssign(transform.pivot) + .rotateRadAssign(rotation) + .translateAssign(-transform.pivot) + } + + + companion object { + const val TRANSFORM = "lid" + const val NAME = "shulker" + + private val ROTATION_CLOSED = Vec3(0.0f, 0.0f, 0.0f).rad + private val ROTATION_OPENED = Vec3(0.0f, 270.0f, 0.0f).rad + + private val TRANSLATION_CLOSED = Vec3(0.0f, 0.0f, 0.0f) + private val TRANSLATION_OPENED = Vec3(0.0f, 0.5f, 0.0f) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt new file mode 100644 index 000000000..92dd90500 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt @@ -0,0 +1,80 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.shulker + +import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3i +import de.bixilon.minosoft.data.entities.block.container.storage.ShulkerBoxBlockEntity +import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties.getFacing +import de.bixilon.minosoft.data.registries.blocks.state.BlockState +import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft +import de.bixilon.minosoft.data.world.positions.BlockPosition +import de.bixilon.minosoft.gui.rendering.RenderContext +import de.bixilon.minosoft.gui.rendering.chunk.entities.EntityRendererRegister +import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage.StorageBlockEntityRenderer +import de.bixilon.minosoft.gui.rendering.models.loader.ModelLoader +import de.bixilon.minosoft.gui.rendering.models.loader.SkeletalLoader.Companion.sModel +import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rad + +class ShulkerBoxRenderer( + val entity: ShulkerBoxBlockEntity, + context: RenderContext, + state: BlockState, + position: Vec3i, + model: BakedSkeletalModel, + light: Int, +) : StorageBlockEntityRenderer(state, model.createInstance(context)) { + val animation = skeletal?.let { ShulkerAnimation(it) } + + init { + update(position, state, light) + } + + override fun update(position: BlockPosition, state: BlockState, light: Int) { + val facing = state.getFacing() + val rotation = ROTATIONS[facing.ordinal] + skeletal?.update(position, rotation) + skeletal?.light = light + } + + override fun open() { + animation?.open() + } + + override fun close() { + animation?.close() + } + + companion object : EntityRendererRegister { + val MODEL = minecraft("block/entities/shulker_box").sModel() + private val named = minecraft("shulker") + private val texture = minecraft("entity/shulker/shulker").texture() + + private val ROTATIONS = arrayOf( + Vec3(180, 0, 0).rad, + Vec3(0, 0, 0).rad, + Vec3(270, 180, 0).rad, + Vec3(90, 0, 0).rad, + Vec3(90, 0, 90).rad, + Vec3(90, 0, 270).rad, + ) + + override fun register(loader: ModelLoader) { + val texture = loader.context.textures.staticTextures.createTexture(texture) + loader.skeletal.register(MODEL, override = mapOf(this.named to texture)) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt index bb8d7d76b..8fc0f9097 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt @@ -17,11 +17,11 @@ import de.bixilon.kotlinglm.mat4x4.Mat4 import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kotlinglm.vec3.Vec3i -import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.shader.Shader import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel import de.bixilon.minosoft.gui.rendering.util.mat.mat4.Mat4Util.rotateRadAssign +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY_INSTANCE class SkeletalInstance( val context: RenderContext, @@ -34,7 +34,7 @@ class SkeletalInstance( fun draw() { - context.system.reset() + context.system.reset(faceCulling = false) val shader = context.skeletal.shader shader.use() shader.light = light @@ -50,19 +50,25 @@ class SkeletalInstance( model.mesh.draw() } - fun update(position: Vec3, rotation: Vec3) { + fun update(position: Vec3, rotation: Vec3, pivot: Vec3 = Vec3.EMPTY_INSTANCE) { this.position = Mat4() .translateAssign(position) + .translateAssign(pivot) .rotateRadAssign(rotation) + .translateAssign(-pivot) } fun update(position: Vec3d, rotation: Vec3) { update(Vec3(position - context.camera.offset.offset), rotation) } - fun update(position: Vec3i, direction: Directions) { + fun update(position: Vec3i, rotation: Vec3) { val position = Vec3(position - context.camera.offset.offset) position.x += 0.5f; position.z += 0.5f // models origin is the center of block origin - update(position, direction.rotation) + update(position, rotation, BLOCK_PIVOT) + } + + private companion object { + val BLOCK_PIVOT = Vec3(0.0f, 0.5f, 0.0f) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalRotation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalRotation.kt index fcf95c96c..0e090063d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalRotation.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalRotation.kt @@ -23,7 +23,7 @@ data class SkeletalRotation( ) { fun apply(offset: Vec3, from: Vec3, to: Vec3): SkeletalRotation { - val origin = (this.origin ?: ((to - from) / 2.0f)) + offset + val origin = (this.origin ?: ((to + from) / 2.0f)) + offset return SkeletalRotation(value, origin, rescale) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/BlockActionS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/BlockActionS2CP.kt index c3af0bae2..f1c5b7c7b 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/BlockActionS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/BlockActionS2CP.kt @@ -30,8 +30,8 @@ class BlockActionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { } else { buffer.readBlockPosition() } - val data1 = buffer.readByte().toInt() - val data2 = buffer.readByte().toInt() + val type = buffer.readByte().toInt() + val data = buffer.readByte().toInt() val block: Block = if (buffer.versionId < FLATTENING_VERSION) buffer.readRegistryItem(buffer.connection.registries.blockState)!!.block else buffer.readRegistryItem(buffer.connection.registries.block) override fun handle(connection: PlayConnection) { @@ -41,10 +41,10 @@ class BlockActionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { Log.log(LogMessageType.NETWORK_IN, LogLevels.WARN) { "Block entity $blockEntity can not accept block entity actions!" } return } - blockEntity.setBlockActionData(data1, data2) + blockEntity.setBlockActionData(type, data) } override fun log(reducedLog: Boolean) { - Log.log(LogMessageType.NETWORK_IN, level = LogLevels.VERBOSE) { "Block action (position=$position, data1=$data1, data2=$data2, block=$block)" } + Log.log(LogMessageType.NETWORK_IN, level = LogLevels.VERBOSE) { "Block action (position=$position, type=$type, data=$data, block=$block)" } } } diff --git a/src/main/resources/assets/minecraft/models/block/entities/shulker_box.smodel b/src/main/resources/assets/minecraft/models/block/entities/shulker_box.smodel new file mode 100644 index 000000000..3b397a2cd --- /dev/null +++ b/src/main/resources/assets/minecraft/models/block/entities/shulker_box.smodel @@ -0,0 +1,49 @@ +{ + "elements": { + "base": { + "from": [-8, 0, -8], + "to": [8, 8, 8], + "texture": "minecraft:shulker", + "uv": [0, 28], + "rotation": { + "value": [0, 0, 180] + }, + "faces": { + "down": {}, + "up": {}, + "north": {}, + "south": {}, + "west": {}, + "east": {} + } + }, + "lid": { + "transform": "lid", + "from": [-8, 4, -8], + "to": [8, 16, 8], + "texture": "minecraft:shulker", + "rotation": { + "value": [0, 0, 180] + }, + "uv": [0, 0], + "faces": { + "down": {}, + "up": {}, + "north": {}, + "south": {}, + "west": {}, + "east": {} + } + } + }, + "transforms": { + "lid": { + "pivot": [0, 8, 0] + } + }, + "textures": { + "minecraft:shulker": { + "resolution": [64, 64] + } + } +}