add player edible cake

This commit is contained in:
Guilherme Pereira committed 2025-01-20 18:49:18 -03:00
1 parent 5190bbe723
commit c86103fd31
11 files changed
+481 -225

No files matched your search

@@ -8,6 +8,7 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.PokeCakeBlockEntity
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.block.entity.PCBlockEntity
@@ -105,8 +106,13 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val LURE_CAKE: BlockEntityType<LureCakeBlockEntity> = this.create(
"lure_cake",
BlockEntityType.Builder.of(::LureCakeBlockEntity, CobblemonBlocks.LURE_CAKE).build(null)
"lure_cake",
BlockEntityType.Builder.of(::LureCakeBlockEntity, CobblemonBlocks.LURE_CAKE).build(null)
)
@JvmField
val POKE_CAKE: BlockEntityType<PokeCakeBlockEntity> = this.create(
"poke_cake",
BlockEntityType.Builder.of(::PokeCakeBlockEntity, CobblemonBlocks.POKE_CAKE).build(null)
)
@@ -10,8 +10,8 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.LecternBlock
import com.cobblemon.mod.common.block.CampfireBlock
import com.cobblemon.mod.common.block.LecternBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
@@ -232,6 +232,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val LURE_CAKE = this.create("lure_cake", LureCakeBlock(BlockBehaviour.Properties.of().randomTicks().sound(SoundType.SPONGE).mapColor(MapColor.COLOR_LIGHT_GRAY).noOcclusion()))
@JvmField
val POKE_CAKE = this.create("poke_cake", PokeCakeBlock(BlockBehaviour.Properties.of().randomTicks().sound(SoundType.SPONGE).mapColor(MapColor.COLOR_LIGHT_GRAY).noOcclusion()))
@JvmField
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@@ -333,6 +333,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val LURE_CAKE = blockItem("lure_cake", CobblemonBlocks.LURE_CAKE)
@JvmField
val POKE_CAKE = blockItem("poke_cake", CobblemonBlocks.POKE_CAKE)
val aprijuices = mutableListOf<AprijuiceItem>()
@JvmField
@@ -511,8 +513,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
// todo THE MOCHIS (are they all with their own item classes? Or bundled into one itemclass like some of the berries?
//todo PokeCake the player cake that is not a lure
// todo potato mochi
// todo fried rice
@@ -0,0 +1,117 @@
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.block.entity.PokeCakeBlockEntity
import com.mojang.serialization.MapCodec
import net.minecraft.core.BlockPos
import net.minecraft.world.InteractionHand.MAIN_HAND
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
class PokeCakeBlock(settings: Properties): BaseEntityBlock(settings) {
companion object {
val SHAPE_BY_BITE = arrayOf(
box(1.0, 0.0, 1.0, 15.0, 9.0, 15.0),
box(3.0, 0.0, 1.0, 15.0, 9.0, 15.0),
box(5.0, 0.0, 1.0, 15.0, 9.0, 15.0),
box(7.0, 0.0, 1.0, 15.0, 9.0, 15.0),
box(9.0, 0.0, 1.0, 15.0, 9.0, 15.0),
box(11.0, 0.0, 1.0, 15.0, 9.0, 15.0),
box(13.0, 0.0, 1.0, 15.0, 9.0, 15.0)
)
}
override fun codec(): MapCodec<out BaseEntityBlock?>? {
return simpleCodec(::PokeCakeBlock)
}
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
return PokeCakeBlockEntity(pos, state)
}
override fun setPlacedBy(
level: Level,
pos: BlockPos,
state: BlockState,
placer: LivingEntity?,
stack: ItemStack
) {
super.setPlacedBy(level, pos, state, placer, stack)
val blockEntity = level.getBlockEntity(pos) as? PokeCakeBlockEntity
blockEntity?.initializeFromItemStack(stack)
}
override fun useWithoutItem(
state: BlockState,
level: Level,
pos: BlockPos,
player: Player,
hitResult: BlockHitResult
): InteractionResult? {
if (level.isClientSide) {
if (eat(level, pos, player).consumesAction()) {
return InteractionResult.SUCCESS;
}
if (player.getItemInHand(MAIN_HAND).isEmpty) {
return InteractionResult.CONSUME;
}
}
return eat(level, pos, player);
}
fun eat(level: LevelAccessor, pos: BlockPos, player: Player): InteractionResult {
if (!player.canEat(false)) {
return InteractionResult.PASS;
}
player.getFoodData().eat(2, 0.1F);
level.gameEvent(player, GameEvent.EAT, pos);
var bites = getBites(level, pos)
if (bites < 6) {
setBites(level, pos, bites + 1)
} else {
level.removeBlock(pos, false);
level.gameEvent(player, GameEvent.BLOCK_DESTROY, pos);
}
return InteractionResult.SUCCESS;
}
override fun getShape(
state: BlockState,
level: BlockGetter,
pos: BlockPos,
context: CollisionContext
): VoxelShape? {
return SHAPE_BY_BITE[getBites(level, pos)]
}
override fun getCloneItemStack(
level: LevelReader,
pos: BlockPos,
state: BlockState
): ItemStack? {
val blockEntity = level.getBlockEntity(pos) as? PokeCakeBlockEntity ?: return ItemStack.EMPTY
return blockEntity.toItemStack()
}
fun getBites(level: BlockGetter, pos: BlockPos): Int = (level.getBlockEntity(pos) as? PokeCakeBlockEntity)?.bites ?: 0
fun setBites(level: BlockGetter, pos: BlockPos, bites: Int) = (level.getBlockEntity(pos) as? PokeCakeBlockEntity)?.bites = bites
}
@@ -0,0 +1,81 @@
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.item.components.CookingComponent
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtOps
import net.minecraft.network.protocol.Packet
import net.minecraft.network.protocol.game.ClientGamePacketListener
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
class PokeCakeBlockEntity(
pos: BlockPos,
state: BlockState
) : BlockEntity(CobblemonBlockEntities.POKE_CAKE, pos, state) {
var cookingComponent: CookingComponent? = null
var bites: Int = 0
fun initializeFromItemStack(itemStack: ItemStack) {
cookingComponent = itemStack.get(CobblemonItemComponents.COOKING_COMPONENT)
}
override fun saveAdditional(
tag: CompoundTag,
registries: HolderLookup.Provider
) {
super.saveAdditional(tag, registries)
tag.putInt("Bites", bites)
cookingComponent?.let { component ->
CobblemonItemComponents.COOKING_COMPONENT.codec()
?.encodeStart(NbtOps.INSTANCE, component)
?.result()
?.ifPresent { encodedTag ->
tag.put("CookingComponent", encodedTag)
}
}
}
override fun loadAdditional(
tag: CompoundTag,
registries: HolderLookup.Provider
) {
super.loadAdditional(tag, registries)
bites = tag.getInt("Bites")
if (tag.contains("CookingComponent")) {
CobblemonItemComponents.COOKING_COMPONENT.codec()
?.parse(NbtOps.INSTANCE, tag.getCompound("CookingComponent"))
?.result()
?.ifPresent { component ->
cookingComponent = component
}
}
}
override fun getUpdatePacket(): Packet<ClientGamePacketListener?>? {
return ClientboundBlockEntityDataPacket.create(this)
}
override fun getUpdateTag(registries: HolderLookup.Provider): CompoundTag? {
val tag = CompoundTag()
saveAdditional(tag, registries)
return tag
}
fun toItemStack(): ItemStack {
val stack = ItemStack(this.blockState.block)
cookingComponent?.let { component ->
stack.getComponents().apply {
stack.set(CobblemonItemComponents.COOKING_COMPONENT, component)
}
}
return stack
}
}
@@ -267,6 +267,7 @@ object CobblemonClient {
CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN,
CobblemonBlocks.SACCHARINE_SAPLING,
CobblemonBlocks.LURE_CAKE,
CobblemonBlocks.POKE_CAKE,
CobblemonBlocks.LECTERN,
CobblemonBlocks.CAMPFIRE
)
@@ -304,6 +305,7 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.LECTERN, ::LecternBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.CAMPFIRE, ::CampfireBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.LURE_CAKE, ::LureCakeBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.POKE_CAKE, ::PokeCakeBlockEntityRenderer)
}
private fun registerEntityRenderers() {
@@ -0,0 +1,226 @@
package com.cobblemon.mod.common.client.render.block
import com.cobblemon.mod.common.api.cooking.getColor
import com.cobblemon.mod.common.block.entity.LureCakeBlockEntity
import com.cobblemon.mod.common.item.components.CookingComponent
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.math.Axis
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.InventoryMenu.BLOCK_ATLAS
import net.minecraft.world.level.block.state.BlockState
import org.joml.Vector3d
const val PIXEL_SHIFT = 1.0 / 16.0
const val WHITE_OPAQUE_COLOR = 0xFFFFFFFF.toInt()
const val ATLAS_START = 0.0f
const val ATLAS_END = 1.0f
const val HEIGHT = 0.5f
const val TOP_LAYER_HEIGHT = 0.5625f
const val BOTTOM_LAYER_HEIGHT = 0.0f
val TOP_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_top_layer2")
val CHERRY_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_top_layer3")
val SIDE_LAYER_BOTTOM: TextureAtlasSprite = loadTexture("block/poke_snack_side_layer1")
val SIDE_LAYER_TOP: TextureAtlasSprite = loadTexture("block/poke_snack_side_layer2")
val SIDE_LAYER_MIDDLE: TextureAtlasSprite = loadTexture("block/poke_snack_side_layer3")
val BOTTOM_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_bottom_layer1")
val FIRST_INNER_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_inner_layer1")
val SECOND_INNER_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_inner_layer2")
val THIRD_INNER_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_inner_layer3")
fun loadTexture(textureName: String): TextureAtlasSprite {
return Minecraft.getInstance().getTextureAtlas(BLOCK_ATLAS).apply(ResourceLocation("cobblemon", textureName))
}
fun renderCake(
cookingComponent: CookingComponent?,
poseStack: PoseStack,
multiBufferSource: MultiBufferSource,
light: Int,
bites: Int,
) {
val maxBites = 7f
val cakeIsFull = bites.toFloat() == 0f
val percentageToRender = if (cakeIsFull) 1.0f else PIXEL_SHIFT.toFloat() + (PIXEL_SHIFT.toFloat() * 2f * (maxBites - bites).toFloat())
val clippedWidth = (ATLAS_END - ATLAS_START) * percentageToRender
val uClipped = TOP_LAYER.u0 + (TOP_LAYER.u1 - TOP_LAYER.u0) * percentageToRender
val vertexConsumer = multiBufferSource.getBuffer(RenderType.cutout())
val primaryColor = cookingComponent?.seasoning1?.color?.let { getColor(it) } ?: WHITE_OPAQUE_COLOR
val secondaryColor = cookingComponent?.seasoning2?.color?.let { getColor(it) } ?: WHITE_OPAQUE_COLOR
val tertiaryColor = cookingComponent?.seasoning3?.color?.let { getColor(it) } ?: WHITE_OPAQUE_COLOR
poseStack.pushPose()
poseStack.translate(0.5, 0.5, 0.5)
poseStack.mulPose(Axis.YP.rotationDegrees(180f))
poseStack.translate(-0.5, -0.5, -0.5)
poseStack.pushPose()
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, TOP_LAYER_HEIGHT, ATLAS_START, clippedWidth, TOP_LAYER_HEIGHT, ATLAS_END,
TOP_LAYER.u0, TOP_LAYER.v0, uClipped, TOP_LAYER.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, TOP_LAYER_HEIGHT, ATLAS_START, clippedWidth, TOP_LAYER_HEIGHT, ATLAS_END,
CHERRY_LAYER.u0, CHERRY_LAYER.v0, uClipped, CHERRY_LAYER.v1,
light, primaryColor
)
poseStack.popPose()
val translations = arrayOf(
Vector3d(-1.0, 1.0, 0.5 - PIXEL_SHIFT),
Vector3d(0.0, 1.0, 0.5 - PIXEL_SHIFT),
Vector3d(0.0, 1.0, -0.5 - PIXEL_SHIFT),
Vector3d(-1.0, 1.0, -0.5 - PIXEL_SHIFT),
)
val rotationsY = arrayOf(
Axis.YP.rotationDegrees(90f),
Axis.YP.rotationDegrees(0f),
Axis.YP.rotationDegrees(-90f),
Axis.YP.rotationDegrees(-180f)
)
for (i in translations.indices) {
poseStack.pushPose()
poseStack.mulPose(rotationsY[i])
poseStack.translate(translations[i].x, translations[i].y, translations[i].z)
poseStack.mulPose(Axis.XP.rotationDegrees(90f))
if (i == 0 && !cakeIsFull) {
poseStack.translate(0.0, -bites * PIXEL_SHIFT * 2, 0.0)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
FIRST_INNER_LAYER.u0, FIRST_INNER_LAYER.v0, FIRST_INNER_LAYER.u1, FIRST_INNER_LAYER.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SECOND_INNER_LAYER.u0, SECOND_INNER_LAYER.v0, SECOND_INNER_LAYER.u1, SECOND_INNER_LAYER.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
THIRD_INNER_LAYER.u0, THIRD_INNER_LAYER.v0, THIRD_INNER_LAYER.u1, THIRD_INNER_LAYER.v1,
light, primaryColor
)
} else if (i == 0 || i == 1) {
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, clippedWidth, HEIGHT, ATLAS_END,
SIDE_LAYER_BOTTOM.u0, SIDE_LAYER_BOTTOM.v0, uClipped, SIDE_LAYER_BOTTOM.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, clippedWidth, HEIGHT, ATLAS_END,
SIDE_LAYER_TOP.u0, SIDE_LAYER_TOP.v0, uClipped, SIDE_LAYER_TOP.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, clippedWidth, HEIGHT, ATLAS_END,
SIDE_LAYER_MIDDLE.u0, SIDE_LAYER_MIDDLE.v0, uClipped, SIDE_LAYER_MIDDLE.v1,
light, primaryColor
)
} else if (i == 2) {
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SIDE_LAYER_BOTTOM.u0, SIDE_LAYER_BOTTOM.v0, SIDE_LAYER_BOTTOM.u1, SIDE_LAYER_BOTTOM.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SIDE_LAYER_TOP.u0, SIDE_LAYER_TOP.v0, SIDE_LAYER_TOP.u1, SIDE_LAYER_TOP.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SIDE_LAYER_TOP.u0, SIDE_LAYER_MIDDLE.v0, SIDE_LAYER_MIDDLE.u1, SIDE_LAYER_MIDDLE.v1,
light, primaryColor
)
} else if (i == 3) {
val clippedStartX = ATLAS_START + (ATLAS_END - ATLAS_START) * (1 - percentageToRender)
val clippedUStart = SIDE_LAYER_BOTTOM.u0 + (SIDE_LAYER_BOTTOM.u1 - SIDE_LAYER_BOTTOM.u0) * (1 - percentageToRender)
drawQuad(
vertexConsumer, poseStack,
clippedStartX, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
clippedUStart, SIDE_LAYER_BOTTOM.v0, SIDE_LAYER_BOTTOM.u1, SIDE_LAYER_BOTTOM.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
clippedStartX, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
clippedUStart, SIDE_LAYER_TOP.v0, SIDE_LAYER_TOP.u1, SIDE_LAYER_TOP.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
clippedStartX, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
clippedUStart, SIDE_LAYER_MIDDLE.v0, SIDE_LAYER_MIDDLE.u1, SIDE_LAYER_MIDDLE.v1,
light, primaryColor
)
}
poseStack.popPose()
}
poseStack.pushPose()
poseStack.translate(0.5, 0.0, 0.5)
poseStack.mulPose(Axis.XP.rotationDegrees(180f))
poseStack.translate(-0.5, 0.0, -0.5)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, BOTTOM_LAYER_HEIGHT, ATLAS_START, clippedWidth, BOTTOM_LAYER_HEIGHT, ATLAS_END,
BOTTOM_LAYER.u0, BOTTOM_LAYER.v0, uClipped, BOTTOM_LAYER.v1,
light, tertiaryColor
)
poseStack.popPose()
poseStack.popPose()
}
private fun drawQuad(
builder: VertexConsumer,
poseStack: PoseStack,
x0: Float, y0: Float, z0: Float,
x1: Float, y1: Float, z1: Float,
u0: Float, v0: Float, u1: Float, v1: Float,
packedLight: Int, color: Int,
) {
drawVertex(builder, poseStack, x0, y0, z0, u0, v0, packedLight, color)
drawVertex(builder, poseStack, x0, y1, z1, u0, v1, packedLight, color)
drawVertex(builder, poseStack, x1, y1, z1, u1, v1, packedLight, color)
drawVertex(builder, poseStack, x1, y0, z0, u1, v0, packedLight, color)
}
private fun drawVertex(
builder: VertexConsumer,
poseStack: PoseStack,
x: Float, y: Float, z: Float,
u: Float, v: Float,
packedLight: Int, color: Int
) {
builder.addVertex(poseStack.last().pose(), x, y, z)
.setColor(color)
.setUv(u, v)
.setLight(packedLight)
.setNormal(0f, 1f, 0f)
}
@@ -8,50 +8,15 @@
package com.cobblemon.mod.common.client.render.block
import com.cobblemon.mod.common.api.cooking.getColor
import com.cobblemon.mod.common.block.LureCakeBlock.Companion.BITES
import com.cobblemon.mod.common.block.entity.LureCakeBlockEntity
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.math.Axis
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.InventoryMenu.BLOCK_ATLAS
import net.minecraft.world.level.block.state.BlockState
import org.joml.Vector3d
class LureCakeBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) : BlockEntityRenderer<LureCakeBlockEntity> {
companion object {
const val PIXEL_SHIFT = 1.0 / 16.0
const val WHITE_OPAQUE_COLOR = 0xFFFFFFFF.toInt()
const val ATLAS_START = 0.0f
const val ATLAS_END = 1.0f
const val HEIGHT = 0.5f
const val TOP_LAYER_HEIGHT = 0.5625f
const val BOTTOM_LAYER_HEIGHT = 0.0f
val TOP_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_top_layer2")
val CHERRY_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_top_layer3")
val SIDE_LAYER_BOTTOM: TextureAtlasSprite = loadTexture("block/poke_snack_side_layer1")
val SIDE_LAYER_TOP: TextureAtlasSprite = loadTexture("block/poke_snack_side_layer2")
val SIDE_LAYER_MIDDLE: TextureAtlasSprite = loadTexture("block/poke_snack_side_layer3")
val BOTTOM_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_bottom_layer1")
val FIRST_INNER_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_inner_layer1")
val SECOND_INNER_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_inner_layer2")
val THIRD_INNER_LAYER: TextureAtlasSprite = loadTexture("block/poke_snack_inner_layer3")
fun loadTexture(textureName: String): TextureAtlasSprite {
return Minecraft.getInstance().getTextureAtlas(BLOCK_ATLAS).apply(ResourceLocation("cobblemon", textureName))
}
}
override fun render(
blockEntity: LureCakeBlockEntity,
tickDelta: Float,
@@ -60,190 +25,6 @@ class LureCakeBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) : Bl
light: Int,
overlay: Int
) {
val blockState: BlockState = blockEntity.blockState
if (blockState.isAir) {
return
}
val bites = blockState.getValue(BITES).toFloat()
val maxBites = 7f
val cakeIsFull = bites == 0f
val percentageToRender = if (cakeIsFull) 1.0f else PIXEL_SHIFT.toFloat() + (PIXEL_SHIFT.toFloat() * 2f * (maxBites - bites).toFloat())
val clippedWidth = (ATLAS_END - ATLAS_START) * percentageToRender
val uClipped = TOP_LAYER.u0 + (TOP_LAYER.u1 - TOP_LAYER.u0) * percentageToRender
val vertexConsumer = multiBufferSource.getBuffer(RenderType.cutout())
val cookingComponent = blockEntity.cookingComponent
val primaryColor = cookingComponent?.seasoning1?.color?.let { getColor(it) } ?: WHITE_OPAQUE_COLOR
val secondaryColor = cookingComponent?.seasoning2?.color?.let { getColor(it) } ?: WHITE_OPAQUE_COLOR
val tertiaryColor = cookingComponent?.seasoning3?.color?.let { getColor(it) } ?: WHITE_OPAQUE_COLOR
poseStack.pushPose()
poseStack.translate(0.5, 0.5, 0.5)
poseStack.mulPose(Axis.YP.rotationDegrees(180f))
poseStack.translate(-0.5, -0.5, -0.5)
poseStack.pushPose()
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, TOP_LAYER_HEIGHT, ATLAS_START, clippedWidth, TOP_LAYER_HEIGHT, ATLAS_END,
TOP_LAYER.u0, TOP_LAYER.v0, uClipped, TOP_LAYER.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, TOP_LAYER_HEIGHT, ATLAS_START, clippedWidth, TOP_LAYER_HEIGHT, ATLAS_END,
CHERRY_LAYER.u0, CHERRY_LAYER.v0, uClipped, CHERRY_LAYER.v1,
light, primaryColor
)
poseStack.popPose()
val translations = arrayOf(
Vector3d(-1.0, 1.0, 0.5 - PIXEL_SHIFT),
Vector3d(0.0, 1.0, 0.5 - PIXEL_SHIFT),
Vector3d(0.0, 1.0, -0.5 - PIXEL_SHIFT),
Vector3d(-1.0, 1.0, -0.5 - PIXEL_SHIFT),
)
val rotationsY = arrayOf(
Axis.YP.rotationDegrees(90f),
Axis.YP.rotationDegrees(0f),
Axis.YP.rotationDegrees(-90f),
Axis.YP.rotationDegrees(-180f)
)
for (i in translations.indices) {
poseStack.pushPose()
poseStack.mulPose(rotationsY[i])
poseStack.translate(translations[i].x, translations[i].y, translations[i].z)
poseStack.mulPose(Axis.XP.rotationDegrees(90f))
if (i == 0 && !cakeIsFull) {
poseStack.translate(0.0, -bites * PIXEL_SHIFT * 2, 0.0)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
FIRST_INNER_LAYER.u0, FIRST_INNER_LAYER.v0, FIRST_INNER_LAYER.u1, FIRST_INNER_LAYER.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SECOND_INNER_LAYER.u0, SECOND_INNER_LAYER.v0, SECOND_INNER_LAYER.u1, SECOND_INNER_LAYER.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
THIRD_INNER_LAYER.u0, THIRD_INNER_LAYER.v0, THIRD_INNER_LAYER.u1, THIRD_INNER_LAYER.v1,
light, primaryColor
)
} else if (i == 0 || i == 1) {
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, clippedWidth, HEIGHT, ATLAS_END,
SIDE_LAYER_BOTTOM.u0, SIDE_LAYER_BOTTOM.v0, uClipped, SIDE_LAYER_BOTTOM.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, clippedWidth, HEIGHT, ATLAS_END,
SIDE_LAYER_TOP.u0, SIDE_LAYER_TOP.v0, uClipped, SIDE_LAYER_TOP.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, clippedWidth, HEIGHT, ATLAS_END,
SIDE_LAYER_MIDDLE.u0, SIDE_LAYER_MIDDLE.v0, uClipped, SIDE_LAYER_MIDDLE.v1,
light, primaryColor
)
} else if (i == 2) {
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SIDE_LAYER_BOTTOM.u0, SIDE_LAYER_BOTTOM.v0, SIDE_LAYER_BOTTOM.u1, SIDE_LAYER_BOTTOM.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SIDE_LAYER_TOP.u0, SIDE_LAYER_TOP.v0, SIDE_LAYER_TOP.u1, SIDE_LAYER_TOP.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
SIDE_LAYER_TOP.u0, SIDE_LAYER_MIDDLE.v0, SIDE_LAYER_MIDDLE.u1, SIDE_LAYER_MIDDLE.v1,
light, primaryColor
)
} else if (i == 3) {
val clippedStartX = ATLAS_START + (ATLAS_END - ATLAS_START) * (1 - percentageToRender)
val clippedUStart = SIDE_LAYER_BOTTOM.u0 + (SIDE_LAYER_BOTTOM.u1 - SIDE_LAYER_BOTTOM.u0) * (1 - percentageToRender)
drawQuad(
vertexConsumer, poseStack,
clippedStartX, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
clippedUStart, SIDE_LAYER_BOTTOM.v0, SIDE_LAYER_BOTTOM.u1, SIDE_LAYER_BOTTOM.v1,
light, tertiaryColor
)
drawQuad(
vertexConsumer, poseStack,
clippedStartX, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
clippedUStart, SIDE_LAYER_TOP.v0, SIDE_LAYER_TOP.u1, SIDE_LAYER_TOP.v1,
light, secondaryColor
)
drawQuad(
vertexConsumer, poseStack,
clippedStartX, HEIGHT, ATLAS_START, ATLAS_END, HEIGHT, ATLAS_END,
clippedUStart, SIDE_LAYER_MIDDLE.v0, SIDE_LAYER_MIDDLE.u1, SIDE_LAYER_MIDDLE.v1,
light, primaryColor
)
}
poseStack.popPose()
}
poseStack.pushPose()
poseStack.translate(0.5, 0.0, 0.5)
poseStack.mulPose(Axis.XP.rotationDegrees(180f))
poseStack.translate(-0.5, 0.0, -0.5)
drawQuad(
vertexConsumer, poseStack,
ATLAS_START, BOTTOM_LAYER_HEIGHT, ATLAS_START, clippedWidth, BOTTOM_LAYER_HEIGHT, ATLAS_END,
BOTTOM_LAYER.u0, BOTTOM_LAYER.v0, uClipped, BOTTOM_LAYER.v1,
light, tertiaryColor
)
poseStack.popPose()
poseStack.popPose()
}
private fun drawQuad(
builder: VertexConsumer,
poseStack: PoseStack,
x0: Float, y0: Float, z0: Float,
x1: Float, y1: Float, z1: Float,
u0: Float, v0: Float, u1: Float, v1: Float,
packedLight: Int, color: Int,
) {
drawVertex(builder, poseStack, x0, y0, z0, u0, v0, packedLight, color)
drawVertex(builder, poseStack, x0, y1, z1, u0, v1, packedLight, color)
drawVertex(builder, poseStack, x1, y1, z1, u1, v1, packedLight, color)
drawVertex(builder, poseStack, x1, y0, z0, u1, v0, packedLight, color)
}
private fun drawVertex(
builder: VertexConsumer,
poseStack: PoseStack,
x: Float, y: Float, z: Float,
u: Float, v: Float,
packedLight: Int, color: Int
) {
builder.addVertex(poseStack.last().pose(), x, y, z)
.setColor(color)
.setUv(u, v)
.setLight(packedLight)
.setNormal(0f, 1f, 0f)
renderCake(blockEntity.cookingComponent, poseStack, multiBufferSource, light, blockEntity.blockState.getValue(BITES))
}
}
@@ -0,0 +1,22 @@
package com.cobblemon.mod.common.client.render.block
import com.cobblemon.mod.common.block.entity.PokeCakeBlockEntity
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
class PokeCakeBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) : BlockEntityRenderer<PokeCakeBlockEntity> {
override fun render(
blockEntity: PokeCakeBlockEntity,
partialTick: Float,
poseStack: PoseStack,
bufferSource: MultiBufferSource,
packedLight: Int,
packedOverlay: Int
) {
val cookingComponent = blockEntity.cookingComponent
renderCake(cookingComponent, poseStack, bufferSource, packedLight, blockEntity.bites)
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "builtin/entity"
}
}
}
@@ -0,0 +1,12 @@
{
"type": "cobblemon:cooking_pot_shapeless",
"category": "foods",
"ingredients": [
{
"item": "minecraft:cake"
}
],
"result": {
"id": "cobblemon:poke_cake"
}
}