Compare commits

...
22 changed files with 831 additions and 8 deletions
@@ -36,6 +36,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.of(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val STADIUM: BlockEntityType<StadiumBlockEntity> = this.create("stadium_terminal", BlockEntityType.Builder.of(::StadiumBlockEntity, CobblemonBlocks.STADIUM).build(null))
@JvmField
val LECTERN: BlockEntityType<LecternBlockEntity> = this.create("lectern", BlockEntityType.Builder.of(::LecternBlockEntity, CobblemonBlocks.LECTERN).build(null))
@@ -354,6 +354,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }))
@JvmField
val STADIUM = create("stadium_terminal", StadiumBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F)))
@JvmField
val LECTERN = create("lectern", LecternBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.WOOD).strength(2.5F).ignitedByLava()))
@@ -272,6 +272,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val STADIUM = blockItem("stadium_terminal", CobblemonBlocks.STADIUM)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@@ -0,0 +1,113 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.Mirror
import net.minecraft.world.level.block.RenderShape
import net.minecraft.world.level.block.Rotation
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.phys.BlockHitResult
class StadiumBlock(properties: Properties): BaseEntityBlock(properties) {
companion object {
val CODEC = simpleCodec(::StadiumBlock)
}
init {
registerDefaultState(stateDefinition.any().setValue(HorizontalDirectionalBlock.FACING, Direction.NORTH))
}
override fun codec() = CODEC
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return StadiumBlockEntity(pos, state)
}
override fun getStateForPlacement(blockPlaceContext: BlockPlaceContext): BlockState {
return this.defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, blockPlaceContext.horizontalDirection)
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(HorizontalDirectionalBlock.FACING)
}
override fun rotate(blockState: BlockState, rotation: Rotation): BlockState {
return blockState.setValue(
HorizontalDirectionalBlock.FACING, rotation.rotate(blockState.getValue(
HorizontalDirectionalBlock.FACING)))
}
override fun mirror(blockState: BlockState, mirror: Mirror): BlockState {
return blockState.rotate(mirror.getRotation(blockState.getValue(HorizontalDirectionalBlock.FACING)))
}
override fun onRemove(state: BlockState, world: Level, pos: BlockPos, newState: BlockState, moved: Boolean) {
if (!state.`is`(newState.block)) super.onRemove(state, world, pos, newState, moved)
}
//TODO: override getTicker
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
override fun useWithoutItem(
blockState: BlockState,
world: Level,
blockPos: BlockPos,
player: Player,
blockHitResult: BlockHitResult
): InteractionResult {
if (player !is ServerPlayer) return InteractionResult.SUCCESS
val blockEntity = world.getBlockEntity(blockPos)
if (blockEntity !is StadiumBlockEntity) return InteractionResult.SUCCESS
// Toggle isInUse state
blockEntity.isInUse = !blockEntity.isInUse
// debug
val activateMessage = if (blockEntity.isInUse) "Stadium Activated!" else "Stadium Deactivated!"
player.sendSystemMessage(text(activateMessage).red())
if (blockEntity.isInUse) {
// Generate flight path when activated
blockEntity.generateFlightPath(world, radiusX = 5.0, radiusZ = 3.0, height = 10.0, steps = 20)
} else {
// Clear path when deactivated
blockEntity.pathPoints.clear()
}
val message = "Stadium Pos: " + blockEntity.blockPos +
"\nPlayer 1 Pos: " + blockEntity.getPlayer1Pos() +
"\nPoke 1 Pos: " + blockEntity.getPoke1Pos() +
"\nPlayer 2 Pos: " + blockEntity.getPlayer2Pos() +
"\nPoke 2 Pos: " + blockEntity.getPoke2Pos()
player.sendSystemMessage(text(message).red())
blockEntity.setChanged()
world.sendBlockUpdated(blockPos, blockState, blockState, Block.UPDATE_CLIENTS)
return InteractionResult.SUCCESS
}
}
@@ -0,0 +1,132 @@
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneState
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.network.protocol.Packet
import net.minecraft.network.protocol.game.ClientGamePacketListener
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
import net.minecraft.network.protocol.game.ClientboundPlayerLookAtPacket
import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
class StadiumBlockEntity(
pos: BlockPos,
blockState: BlockState
): BlockEntity(
CobblemonBlockEntities.STADIUM,
pos,
blockState
) {
var isInUse = false
val droneState = DroneState()
val pathPoints: MutableList<Vec3> = mutableListOf()
fun generateFlightPath(world: Level, radiusX: Double, radiusZ: Double, height: Double, steps: Int) {
pathPoints.clear()
for (i in 0 until steps) {
val angle = (i.toDouble() / steps) * Math.PI * 2
val xOffset = radiusX * Math.cos(angle)
val zOffset = radiusZ * Math.sin(angle)
val basePos = Vec3(blockPos.x + xOffset, blockPos.y + height, blockPos.z + zOffset)
val adjustedPos = getValidPoint(world, basePos)
pathPoints.add(adjustedPos)
}
}
private fun getValidPoint(world: Level, start: Vec3): Vec3 {
val maxHeight = 40 // Max height for drone path
val stepHeight = 1.0 // Step size for raycast
var adjustedHeight = start.y
for (h in 0..maxHeight step stepHeight.toInt()) {
val checkPos = BlockPos(start.x.toInt(), start.y.toInt() - h, start.z.toInt()) // Convert to BlockPos
if (!world.getBlockState(checkPos).isAir) { // Check if block is solid
return Vec3(start.x, start.y - h - 1, start.z) // Adjust position
}
}
return start // No obstruction found
}
fun getPlayer1Pos(): BlockPos {
return blockPos.north(10)
}
fun getPlayer2Pos(): BlockPos {
return blockPos.south(10)
}
fun getPoke1Pos(): BlockPos {
return blockPos.north(5)
}
fun getPoke2Pos(): BlockPos {
return blockPos.south(5)
}
/**
* Saves data to NBT.
*/
override fun saveAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.saveAdditional(tag, registries)
// Save the isInUse state
tag.putBoolean("IsInUse", isInUse)
// Save path points
val pathTag = ListTag()
for (point in pathPoints) {
val pointTag = CompoundTag()
pointTag.putDouble("x", point.x)
pointTag.putDouble("y", point.y)
pointTag.putDouble("z", point.z)
pathTag.add(pointTag)
}
tag.put("PathPoints", pathTag)
}
/**
* Loads data from NBT.
*/
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.loadAdditional(tag, registries)
// Load the isInUse state
isInUse = tag.getBoolean("IsInUse")
// Load path points
pathPoints.clear()
val pathTag = tag.getList("PathPoints", 10) // 10 is the ID for CompoundTag
for (i in 0 until pathTag.size) {
val pointTag = pathTag.getCompound(i)
val point = Vec3(pointTag.getDouble("x"), pointTag.getDouble("y"), pointTag.getDouble("z"))
pathPoints.add(point)
}
}
override fun getUpdatePacket(): Packet<ClientGamePacketListener>? {
//println("getUpdatePacket called for NestBlockEntity at $blockPos with egg: $eggComponent")
return ClientboundBlockEntityDataPacket.create(this)
}
override fun getUpdateTag(registryLookup: HolderLookup.Provider): CompoundTag {
val tag = saveWithoutMetadata(registryLookup)
//println("getUpdateTag called for NestBlockEntity at $blockPos with tag: $tag")
return tag
}
}
@@ -25,13 +25,7 @@ import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
import com.cobblemon.mod.common.client.render.ClientPlayerIcon
import com.cobblemon.mod.common.client.render.DeferredRenderer
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.DisplayCaseRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.block.LecternBlockEntityRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
@@ -256,7 +250,8 @@ object CobblemonClient {
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST,
CobblemonBlocks.DISPLAY_CASE,
CobblemonBlocks.LECTERN
CobblemonBlocks.LECTERN,
CobblemonBlocks.STADIUM
)
this.createBoatModelLayers()
@@ -290,6 +285,7 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.DISPLAY_CASE, ::DisplayCaseRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.LECTERN, ::LecternBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.STADIUM, ::StadiumBlockRenderer)
}
private fun registerEntityRenderers() {
@@ -0,0 +1,196 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.block
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneModel
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
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.OverlayTexture
import net.minecraft.core.Direction
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.state.BlockState
class StadiumBlockRenderer(ctx: BlockEntityRendererProvider.Context) : BlockEntityRenderer<StadiumBlockEntity> {
val context = RenderContext().also {
it.put(RenderContext.DO_QUIRKS, false)
it.put(RenderContext.RENDER_STATE, RenderContext.RenderState.BLOCK)
}
private var pathIndex = 0
private var animationTime = 0.0
private val droneSpeed = 0.10
override fun render(
blockEntity: StadiumBlockEntity,
tickDelta: Float,
poseStack: PoseStack,
multiBufferSource: MultiBufferSource,
light: Int,
overlay: Int
) {
val blockState = blockEntity.blockState
val yRot = blockState.getValue(HorizontalDirectionalBlock.FACING).toYRot()
val isClientSide = blockEntity.level?.isClientSide == true
if (!isClientSide) return
val stadiumBlockState = blockEntity.level?.getBlockState(blockEntity.blockPos) ?: return
if (stadiumBlockState.block != CobblemonBlocks.STADIUM) {
return
}
val droneState = blockEntity.droneState
poseStack.pushPose()
if (blockEntity.isInUse) {
if (blockEntity.pathPoints.isEmpty()) {
poseStack.popPose()
return
}
spawnDebugParticles(blockEntity) // debug particles
// Center the drone at the block's center
poseStack.translate(0.5, -3.0, 0.5)
//poseStack.mulPose(Axis.XP.rotationDegrees(180F))
//poseStack.mulPose(Axis.YP.rotationDegrees(180F))
val points = blockEntity.pathPoints
val nextIndex = (pathIndex + 1) % points.size
val currentPoint = points[pathIndex]
val nextPoint = points[nextIndex]
animationTime += tickDelta * droneSpeed
if (animationTime >= 1.0) {
animationTime = 0.0
pathIndex = nextIndex
}
val interpolatedPos = currentPoint.lerp(nextPoint, animationTime.toDouble())
println("DEBUG: Drone moving between points:")
println(" - Current Point: ${currentPoint}")
println(" - Next Point: ${nextPoint}")
println(" - Interpolated Position: $interpolatedPos")
poseStack.translate(interpolatedPos.x - blockEntity.blockPos.x,
interpolatedPos.y - blockEntity.blockPos.y,
interpolatedPos.z - blockEntity.blockPos.z)
println("DEBUG: Drone position interpolated to: $interpolatedPos")
poseStack.mulPose(Axis.YP.rotationDegrees(-yRot))
poseStack.mulPose(Axis.ZP.rotationDegrees(180F)) // flip the drone right side up
renderDrone(droneState, "sleep", tickDelta, poseStack, 1.0F, multiBufferSource, light)
} else {
val yRot = blockState.getValue(HorizontalDirectionalBlock.FACING).toYRot()
val poseEntry = poseStack.last()
val matrix = poseEntry.pose()
poseStack.translate(0.5, 0.0, 0.5)
poseStack.mulPose(Axis.YP.rotationDegrees(yRot))
val posX = matrix.m03()
val posY = matrix.m13()
val posZ = matrix.m23()
println("DEBUG: Drone is NOT in use. Rendering default position at: x=$posX, y=$posY, z=$posZ")
poseStack.mulPose(Axis.ZP.rotationDegrees(180F))
renderDrone(droneState, "sleep", tickDelta, poseStack, 1.0F, multiBufferSource, light)
}
poseStack.popPose()
}
fun renderDrone(
state: DroneState,
pose: String,
tickDelta: Float,
poseStack: PoseStack,
scale: Float = 1F,
multiBufferSource: MultiBufferSource,
light: Int,
) {
state.updatePartialTicks(tickDelta)
val droneResource: ResourceLocation = cobblemonResource("rotom_drone")
val model = VaryingModelRepository.getPoser(droneResource, state) as DroneModel
val texture = VaryingModelRepository.getTexture(droneResource, state)
val buffer = multiBufferSource.getBuffer(RenderType.entityCutout(texture))
model.bufferProvider = multiBufferSource
state.currentModel = model
state.setPose(pose)
model.context = context
context.put(RenderContext.TEXTURE, texture)
context.put(RenderContext.RENDER_STATE, RenderContext.RenderState.BLOCK)
context.put(RenderContext.POSABLE_STATE, state)
model.applyAnimations(
entity = null,
state = state,
headYaw = 0F,
headPitch = 0F,
limbSwing = 0F,
limbSwingAmount = 0F,
ageInTicks = state.animationSeconds * 20
)
poseStack.scale(scale, scale, scale)
// TODO: Make drone lighting dynamic (simply using the light arg makes the drone always appear dark)
model.withLayerContext(multiBufferSource, state, VaryingModelRepository.getLayers(droneResource, state)) {
model.render(context, poseStack, buffer, 200, OverlayTexture.NO_OVERLAY, -0x1)
}
model.setDefault()
}
private fun spawnDebugParticles(blockEntity: StadiumBlockEntity) {
val world = blockEntity.level ?: return
if (!world.isClientSide) return // Only run on the client-side
for (point in blockEntity.pathPoints) {
world.addParticle(
net.minecraft.core.particles.ParticleTypes.FLAME, // Test particle (changeable)
point.x, point.y, point.z, // Position of the particle
0.0, 0.02, 0.0 // Slight upward motion
)
}
// Spawn a special particle at the next interpolation point
if (blockEntity.pathPoints.isNotEmpty()) {
val nextPoint = blockEntity.pathPoints[(pathIndex + 1) % blockEntity.pathPoints.size]
world.addParticle(
net.minecraft.core.particles.ParticleTypes.END_ROD, // Different effect for next point
nextPoint.x, nextPoint.y, nextPoint.z,
0.0, 0.05, 0.0
)
}
}
}
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2025 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.drone
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PoseAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
import com.cobblemon.mod.common.entity.PoseType
import com.google.gson.annotations.SerializedName
import net.minecraft.client.model.geom.ModelPart
/**
* A model for rendering the Rotom drone used by the stadium block.
*
* @author Flarkinater
* @since February 14th, 2025
*/
class DroneModel(root: Bone) : PosableModel(root) {
@Transient
@SerializedName("So this name can be literally anything, huh?")
override val rootPart = (root as ModelPart).registerChildWithAllChildren(root.children.entries.first().key)
var droneAnimations: Array<PoseAnimation> = emptyArray()
var droneQuirks: Array<ModelQuirk<*>> = emptyArray()
override fun registerPoses() {
registerPose(
poseType = PoseType.SLEEP,
animations = droneAnimations,
quirks = droneQuirks
)
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2025 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.drone
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
/**
* State for a drone Rotom attached to a stadium block.
*
* @author Flarkinater
* @since February 12th, 2025
*/
class DroneState() : PosableState() {
init {
setPose("sleep")
age = 0
currentPartialTicks = 0F
}
override fun getEntity() = null
override fun updatePartialTicks(partialTicks: Float) {
currentPartialTicks += partialTicks / 2
}
override val schedulingTracker = SchedulingTracker()
}
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.*
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.blockentity.BlockEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.fossil.FossilModel
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.AncientPokeBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.BeastBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PokeBallModel
@@ -79,12 +80,14 @@ object VaryingModelRepository {
"poke_balls",
"generic",
"block_entities",
"drone"
)
val poserDirectories: List<Pair<String, Class<out PosableModel>>> = listOf(
"bedrock/posers" to PosableModel::class.java,
"bedrock/pokemon/posers" to PokemonPosableModel::class.java,
"bedrock/fossils/posers" to FossilModel::class.java,
"bedrock/drone/posers" to DroneModel::class.java,
"bedrock/block_entities/posers" to BlockEntityModel::class.java,
"bedrock/npcs/posers" to PosableModel::class.java,
"bedrock/poke_balls/posers" to PosableModel::class.java,
@@ -116,6 +119,7 @@ object VaryingModelRepository {
.registerTypeAdapter(PosableModel::class.java, JsonModelAdapter(::PosableModel))
.registerTypeAdapter(PokemonPosableModel::class.java, JsonModelAdapter(::PokemonPosableModel))
.registerTypeAdapter(FossilModel::class.java, JsonModelAdapter(::FossilModel))
.registerTypeAdapter(DroneModel::class.java, JsonModelAdapter(::DroneModel))
.registerTypeAdapter(BlockEntityModel::class.java, JsonModelAdapter(::BlockEntityModel))
.registerTypeAdapter(Pose::class.java, PoseAdapter { JsonModelAdapter.model!! })
.registerTypeAdapter(ModelPartTransformation::class.java, ModelPartTransformationAdapter)
@@ -238,6 +238,7 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.PC)
entries.accept(CobblemonItems.HEALING_MACHINE)
entries.accept(CobblemonItems.PASTURE)
entries.accept(CobblemonItems.STADIUM)
entries.accept(CobblemonItems.GILDED_CHEST)
entries.accept(CobblemonItems.YELLOW_GILDED_CHEST)
@@ -0,0 +1,41 @@
{
"format_version": "1.8.0",
"animations": {
"animation.rotom_drone.sleep": {
"loop": true,
"bones": {
"body": {
"rotation": [
"math.sin(query.anim_time * 120) * 6",
0,
"math.cos(query.anim_time * 100) * 4"
],
"position": [
0,
"18 + math.sin(query.anim_time * 90) * 1",
0
]
},
"head": {
"relative_to": {
"rotation": "entity"
},
"rotation": [
0,
0,
0.01
]
}
}
},
"animation.rotom_drone.circle": {
"loop": true,
"bones": {
"rotom_drone": {
"rotation": [30, "90 - q.anim_time*90", 0],
"position": ["48*math.cos(q.anim_time*90)", 64, "48*math.sin(q.anim_time*90)"]
}
}
}
}
}
@@ -0,0 +1,208 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.drone_rotom",
"texture_width": 64,
"texture_height": 32,
"visible_bounds_width": 8,
"visible_bounds_height": 6.5,
"visible_bounds_offset": [0, 2.75, 0]
},
"bones": [
{
"name": "rotom_drone",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "rotom_drone",
"pivot": [0, 8, 0]
},
{
"name": "head",
"parent": "body",
"pivot": [0, 6.5, 0],
"cubes": [
{"origin": [-5.5, 6.5, -3.5], "size": [11, 6, 7], "uv": [0, 0]}
]
},
{
"name": "eyes",
"parent": "head",
"pivot": [0.5, 6.5, -2.5]
},
{
"name": "eye_right",
"parent": "eyes",
"pivot": [-2.9, 9.5, -3.5],
"rotation": [0, 0, -7.5],
"cubes": [
{"origin": [-3.9, 7.5, -3.5], "size": [2, 4, 0], "inflate": 0.01, "uv": [0, 0], "mirror": true},
{"origin": [-3.9, 9, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [0, 6], "mirror": true}
]
},
{
"name": "pupil_right",
"parent": "eye_right",
"pivot": [-2.9, 9.5, -3.5],
"cubes": [
{"origin": [-3.4, 8, -3.5], "size": [1, 3, 0], "inflate": 0.03, "uv": [5, 0], "mirror": true}
]
},
{
"name": "eye_left",
"parent": "eyes",
"pivot": [2.9, 9.5, -3.5],
"rotation": [0, 0, 7.5],
"cubes": [
{"origin": [1.9, 7.5, -3.5], "size": [2, 4, 0], "inflate": 0.01, "uv": [0, 13]},
{"origin": [1.9, 9, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [0, 5]}
]
},
{
"name": "pupil_left",
"parent": "eye_left",
"pivot": [2.9, 9.5, -3.5],
"cubes": [
{"origin": [2.4, 8, -3.5], "size": [1, 3, 0], "inflate": 0.03, "uv": [6, 13]}
]
},
{
"name": "mouth_smile",
"parent": "head",
"pivot": [0, 7.55, -3.5],
"cubes": [
{"origin": [-1, 6.95, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [36, 7]},
{"origin": [-1.5, 7.25, -3.5], "size": [1, 1, 0], "inflate": 0.01, "uv": [40, 7]},
{"origin": [0.5, 7.25, -3.5], "size": [1, 1, 0], "inflate": 0.01, "uv": [42, 7]}
]
},
{
"name": "mouth_closed",
"parent": "head",
"pivot": [0, 7.45, -3.4],
"cubes": [
{"origin": [-0.5, 6.95, -3.4], "size": [1, 1, 0], "inflate": 0.02, "uv": [38, 8]}
]
},
{
"name": "mouth_open",
"parent": "head",
"pivot": [0, 7.45, -3.4],
"cubes": [
{"origin": [-0.5, 6.95, -3.4], "size": [1, 1, 0], "inflate": 0.02, "uv": [36, 8]}
]
},
{
"name": "mouth_sad",
"parent": "head",
"pivot": [0, 7.6, -3.3],
"cubes": [
{"origin": [-1, 7.3, -3.3], "size": [2, 1, 0], "inflate": 0.02, "uv": [36, 9]},
{"origin": [-1.5, 7, -3.3], "size": [1, 1, 0], "inflate": 0.01, "uv": [40, 9]},
{"origin": [0.5, 7, -3.3], "size": [1, 1, 0], "inflate": 0.01, "uv": [42, 9]}
]
},
{
"name": "head_spike1",
"parent": "head",
"pivot": [0, 12.5, 0],
"cubes": [
{"origin": [-1.5, 11.5, -1.5], "size": [3, 4, 3], "uv": [29, 0]}
]
},
{
"name": "head_spike2",
"parent": "head_spike1",
"pivot": [0, 15.5, 0],
"cubes": [
{"origin": [-1, 14.5, -1], "size": [2, 4, 2], "uv": [8, 13]}
]
},
{
"name": "head_spike3",
"parent": "head_spike2",
"pivot": [0, 18.5, 0],
"cubes": [
{"origin": [-0.5, 17.5, -0.5], "size": [1, 3, 1], "uv": [44, 6]}
]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 7, 0],
"cubes": [
{"origin": [-2, 3, -1.5], "size": [4, 4, 3], "uv": [34, 10]}
]
},
{
"name": "camera",
"parent": "torso",
"pivot": [0, 4.65, -1.25],
"cubes": [
{"origin": [-1, 3.65, -2.75], "size": [2, 2, 2], "uv": [24, 13]},
{"origin": [-0.5, 4.15, -2.75], "size": [1, 1, 0], "inflate": 0.01, "uv": [38, 0]}
]
},
{
"name": "propeller_front_right",
"parent": "torso",
"pivot": [-1.5, 5, -1],
"rotation": [0, 45, 0],
"cubes": [
{"origin": [-2, 5, -3.5], "size": [1, 0, 3], "uv": [37, 0]},
{"origin": [-5.5, 5, -11.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "propeller_front_left",
"parent": "torso",
"pivot": [1.5, 5, -1],
"rotation": [0, -45, 0],
"cubes": [
{"origin": [1, 5, -3.5], "size": [1, 0, 3], "uv": [27, 0]},
{"origin": [-2.5, 5, -11.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "propeller_back_right",
"parent": "torso",
"pivot": [-1.5, 5, 1],
"rotation": [0, -45, 0],
"cubes": [
{"origin": [-2, 5, 0.5], "size": [1, 0, 3], "uv": [39, 0]},
{"origin": [-5.5, 5, 3.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "propeller_back_left",
"parent": "torso",
"pivot": [1.5, 5, 1],
"rotation": [0, 45, 0],
"cubes": [
{"origin": [1, 5, 0.5], "size": [1, 0, 3], "uv": [42, 3]},
{"origin": [-2.5, 5, 3.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "tail1",
"parent": "torso",
"pivot": [0, 3, 0],
"cubes": [
{"origin": [-1, 1, -1], "size": [2, 3, 2], "uv": [16, 13]}
]
},
{
"name": "tail2",
"parent": "tail1",
"pivot": [0, 1, 0],
"cubes": [
{"origin": [-0.5, -1, -0.5], "size": [1, 3, 1], "uv": [41, 3]}
]
}
]
}
]
}
@@ -0,0 +1,8 @@
{
"poses": {
"sleep": {
"poseTypes": ["SLEEP"],
"animations": ["q.bedrock('rotom_drone', 'sleep')"]
}
}
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:rotom_drone",
"order": 0,
"variations": [
{
"aspects": [],
"poser": "cobblemon:rotom_drone",
"model": "cobblemon:rotom_drone.geo",
"texture": "cobblemon:textures/drone/rotom_drone.png",
"layers": []
}
]
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "cobblemon:block/stadium_terminal"
}
}
}
@@ -801,6 +801,7 @@
"block.cobblemon.healing_machine.tooltip2": "Charges over time.",
"block.cobblemon.pc": "PC",
"block.cobblemon.lectern": "Lectern",
"block.cobblemon.stadium_terminal": "Stadium Terminal",
"block.cobblemon.restoration_tank": "Restoration Tank",
"block.cobblemon.fossil_analyzer": "Fossil Analyzer",
"block.cobblemon.monitor": "Data Monitor",
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "cobblemon:block/stadium_terminal"
}
}
@@ -0,0 +1,3 @@
{
"parent": "cobblemon:block/stadium_terminal"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,13 @@
{
"type": "minecraft:block",
"pools": [{
"rolls": 1,
"entries": [{
"type": "minecraft:item",
"name": "cobblemon:stadium_terminal"
}],
"conditions": [{
"condition": "minecraft:survives_explosion"
}]
}]
}