Compare commits

...
18 changed files with 2498 additions and 46 deletions
+2
View File
@@ -21,6 +21,8 @@
### Additions
- Added `/cobblemonconfig reload` command to reload `main.json` configuration. **Note:** Some settings require a server restart to take effect; use this command cautiously.
- Added the Model Appendages system, allowing for resolver-based bedrock model attachments to Pokémon models based on Locators.
- View the `egg` examples in `assets/cobblemon/bedrock/appendage` for an example of how to use this system.
## [1.6.1 (January 26th, 2025)](#1-6-1)
@@ -21,12 +21,10 @@ import com.cobblemon.mod.common.client.render.models.blockbench.ExcludedLabels
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.animation.*
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.repository.appendage.ModelAppendageModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import com.cobblemon.mod.common.util.getStringOrNull
import com.cobblemon.mod.common.util.*
import java.util.function.Function
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.sounds.SimpleSoundInstance
@@ -53,7 +51,7 @@ object ClientMoLangFunctions {
"say" to java.util.function.Function { params -> Minecraft.getInstance().player?.sendSystemMessage(params.getString(0).text()) ?: Unit },
)
val animationFunctions = hashMapOf<String, Function<PosableModel, Function<MoParams, Any>>>(
val posableModelFunctions = hashMapOf<String, Function<PosableModel, Function<MoParams, Any>>>(
"exclude_labels" to Function { model -> Function { params ->
val labels = params.params.map { it.asString() }
ObjectValue(ExcludedLabels(labels))
@@ -244,6 +242,18 @@ object ClientMoLangFunctions {
)
}
},
"appendage_model" to Function {
model -> Function { params ->
val name = params.getString(0)
ObjectValue((ModelAppendageModelRepository to name.asResource()))
}
},
"vanilla_model" to Function {
model -> Function { params ->
val id = params.getString(0).asResource()
ObjectValue(id)
}
},
"primary_animation" to Function { model ->
Function { params ->
val animation = params.get<ObjectValue<ActiveAnimation>>(0)?.obj ?: return@Function DoubleValue.ZERO
@@ -344,7 +354,7 @@ object ClientMoLangFunctions {
}
)
fun PosableModel.animationFunctions(): HashMap<String, Function<MoParams, Any>> = animationFunctions.map { (k, v) -> k to v.apply(this) }.toHashMap()
fun PosableModel.animationFunctions(): HashMap<String, Function<MoParams, Any>> = posableModelFunctions.map { (k, v) -> k to v.apply(this) }.toHashMap()
fun MoLangRuntime.setupClient(): MoLangRuntime {
environment.query.addFunctions(clientFunctions)
@@ -47,6 +47,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscM
import com.cobblemon.mod.common.client.render.models.blockbench.repository.NPCModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.appendage.ModelAppendageModelRepository
import com.cobblemon.mod.common.client.render.npc.NPCRenderer
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer
@@ -100,7 +101,8 @@ object CobblemonClient {
NPCModelRepository,
FossilModelRepository,
BlockEntityModelRepository,
GenericBedrockEntityModelRepository
GenericBedrockEntityModelRepository,
ModelAppendageModelRepository
)
val overlay: PartyOverlay by lazy { PartyOverlay() }
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.render
import com.cobblemon.mod.common.util.math.geometry.getOrigin
import com.cobblemon.mod.common.util.math.geometry.transformPosition
import com.mojang.blaze3d.vertex.PoseStack
import net.fabricmc.loader.impl.lib.sat4j.core.Vec
import org.joml.Matrix4f
import net.minecraft.world.phys.Vec3
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.client.CobblemonBakingOverrides
import com.cobblemon.mod.common.client.render.layer.CobblemonRenderLayers
import com.cobblemon.mod.common.client.render.layer.CobblemonRenderTypes
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.setPosition
import com.cobblemon.mod.common.util.math.geometry.Axis
@@ -54,7 +54,7 @@ class BerryBlockRenderer(private val context: BlockEntityRendererProvider.Contex
if (entity.renderState == null) {
entity.renderState = BerryBlockEntityRenderState()
}
val bf = vertexConsumers.getBuffer(CobblemonRenderLayers.BERRY_LAYER)
val bf = vertexConsumers.getBuffer(CobblemonRenderTypes.BERRY_LAYER)
val renderState = entity.renderState as BerryBlockEntityRenderState
// if (renderState.needsRebuild || renderState.vboLightLevel != light) {
renderToBuffer(entity, matrices, light, overlay, renderState, bf)
@@ -19,7 +19,7 @@ import net.minecraft.Util
import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderStateShard.*
object CobblemonRenderLayers {
object CobblemonRenderTypes {
val BERRY_LAYER = run {
val multiPhaseParameters = RenderType.CompositeState.builder()
.setLightmapState(LIGHTMAP)
@@ -0,0 +1,129 @@
package com.cobblemon.mod.common.client.render.layer
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
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.client.render.models.blockbench.repository.appendage.ModelAppendageModelRepository
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.mojang.blaze3d.vertex.PoseStack
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.OverlayTexture
import net.minecraft.client.resources.model.ModelResourceLocation
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemDisplayContext
import org.joml.Vector3f
object ModelAppendageRenderer {
fun <T> render(
poseStack: PoseStack,
bufferSource: MultiBufferSource,
packedLight: Int,
livingEntity: T,
limbSwing: Float,
limbSwingAmount: Float,
ageInTicks: Float,
netHeadYaw: Float,
headPitch: Float,
locator: String,
context: RenderContext,
parentModel: ResourceLocation
) where T : PokemonEntity {
val clientDelegate = livingEntity.delegate as PokemonClientDelegate
val appendages = ModelAppendageModelRepository.getAppendagesForModelAndTarget(parentModel, locator) ?: return
// avoid editing the original context
val clonedContext = context.clone()
appendages.forEach { appendage ->
val modelObj = appendage.model.resolveObject(clientDelegate.runtime).obj
if (modelObj is ResourceLocation) {
poseStack.pushPose()
clientDelegate.locatorStates[locator]?.let { bone ->
val stack = if(modelObj.toString() == "cobblemon:held_item") livingEntity.pokemon.heldItemNoCopy() else BuiltInRegistries.ITEM.get(modelObj).defaultInstance
val pos = bone.getOrigin().subtract(livingEntity.position())
val scale = Vector3f()
bone.matrix.getScale(scale)
poseStack.scale(scale.x(), scale.y(), scale.z())
poseStack.translate(pos.x, pos.y, pos.z)
poseStack.mulPose(bone.clone().matrix.setTranslation(0.0f, 0.0f, 0.0f))
poseStack.scale(
appendage.scale.x().toFloat(), appendage.scale.y().toFloat(),
appendage.scale.z().toFloat()
)
poseStack.mulPose(Axis.XP.rotationDegrees(appendage.rotation.x().toFloat()))
poseStack.mulPose(Axis.YP.rotationDegrees(appendage.rotation.y().toFloat()))
poseStack.mulPose(Axis.ZP.rotationDegrees(appendage.rotation.z().toFloat()))
poseStack.translate(appendage.offset.x(), appendage.offset.y(), appendage.offset.z())
Minecraft.getInstance().itemRenderer.renderStatic(stack, ItemDisplayContext.THIRD_PERSON_RIGHT_HAND, packedLight, OverlayTexture.NO_OVERLAY, poseStack, bufferSource, livingEntity.level(), 0)
}
poseStack.popPose()
} else if (modelObj is Pair<*, *>) {
val repo = modelObj.first as ModelAppendageModelRepository
val resLoc = modelObj.second as ResourceLocation
val model =
repo.getPoserNullable(resLoc, clientDelegate) ?: return
model.context = clonedContext
model.setLayerContext(
bufferSource,
clientDelegate,
ModelAppendageModelRepository.getLayers(resLoc, clientDelegate)
)
poseStack.pushPose()
clientDelegate.locatorStates[locator]?.let { bone ->
val pos = bone.getOrigin().subtract(livingEntity.position())
val scale = Vector3f()
bone.matrix.getScale(scale)
poseStack.scale(scale.x(), scale.y(), scale.z())
poseStack.translate(pos.x, pos.y, pos.z)
poseStack.mulPose(bone.clone().matrix.setTranslation(0.0f, 0.0f, 0.0f))
poseStack.mulPose(Axis.XP.rotationDegrees(180f))
poseStack.translate(0.0, -1.75, 0.0)
poseStack.scale(
appendage.scale.x().toFloat(), appendage.scale.y().toFloat(),
appendage.scale.z().toFloat()
)
poseStack.mulPose(Axis.XP.rotationDegrees(appendage.rotation.x().toFloat()))
poseStack.mulPose(Axis.YP.rotationDegrees(appendage.rotation.y().toFloat()))
poseStack.mulPose(Axis.ZP.rotationDegrees(appendage.rotation.z().toFloat()))
poseStack.translate(appendage.offset.x(), appendage.offset.y(), appendage.offset.z())
model.applyAnimations(
livingEntity,
clientDelegate,
limbSwing,
limbSwingAmount,
ageInTicks,
netHeadYaw,
headPitch
)
val buffer = bufferSource.getBuffer(
RenderType.entityCutout(
ModelAppendageModelRepository.getTexture(
resLoc,
clientDelegate
)
)
)
model.withLayerContext(
bufferSource,
clientDelegate,
ModelAppendageModelRepository.getLayers(resLoc, clientDelegate)
) {
model.render(clonedContext, poseStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
}
}
model.green = 1F
model.blue = 1F
model.red = 1F
model.resetLayerContext()
poseStack.popPose()
}
}
}
}
@@ -0,0 +1,15 @@
package com.cobblemon.mod.common.client.render.layer.appendage
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.google.gson.annotations.SerializedName
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
data class ModelAppendage(
@SerializedName("target_model") val targetModel: ResourceLocation?,
@SerializedName("model") val model: ExpressionLike,
@SerializedName("target_locator") val targetLocator: String,
@SerializedName("scale") val scale: Vec3 = Vec3(1.0, 1.0, 1.0),
@SerializedName("rotation") val rotation: Vec3 = Vec3(0.0, 0.0, 0.0),
@SerializedName("offset") val offset: Vec3 = Vec3(0.0, 0.0, 0.0)
)
@@ -80,6 +80,12 @@ class RenderContext {
this.context.remove(key)
}
fun clone(): RenderContext {
val newContext = RenderContext()
newContext.context.putAll(this.context)
return newContext
}
/**
* Represents a key used for accessing values in the context.
*
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.repository.Varyi
import com.cobblemon.mod.common.client.util.exists
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.endsWith
@@ -72,6 +73,7 @@ abstract class VaryingModelRepository<T : PosableModel> {
GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(Vec3::class.java, Vec3dAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
@@ -213,7 +215,7 @@ abstract class VaryingModelRepository<T : PosableModel> {
Cobblemon.LOGGER.info("Loaded $models $title models.")
}
fun reload(resourceManager: ResourceManager) {
open fun reload(resourceManager: ResourceManager) {
Cobblemon.LOGGER.info("Loading $title assets...")
this.variations.clear()
this.posers.clear()
@@ -222,7 +224,7 @@ abstract class VaryingModelRepository<T : PosableModel> {
registerVariations(resourceManager)
}
fun getPoser(name: ResourceLocation, state: PosableState): T {
open fun getPoser(name: ResourceLocation, state: PosableState): T {
try {
val poser = this.variations[name]?.getPoser(state)
if (poser != null) {
@@ -0,0 +1,73 @@
package com.cobblemon.mod.common.client.render.models.blockbench.repository.appendage
import com.cobblemon.mod.common.client.render.layer.appendage.ModelAppendage
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.endsWith
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.packs.resources.ResourceManager
import java.io.File
import java.nio.charset.StandardCharsets
object ModelAppendageModelRepository : VaryingModelRepository<PosableModel>() {
override val poserClass: Class<PosableModel>
get() = PosableModel::class.java
override val title: String
get() = "Model Appendage"
override val type: String
get() = "appendage"
override val variationDirectories: List<String>
get() = listOf("bedrock/$type/variations")
override val poserDirectories: List<String>
get() = listOf("bedrock/$type/posers")
override val modelDirectories: List<String>
get() = listOf("bedrock/$type/models")
override val animationDirectories: List<String>
get() = listOf("bedrock/$type/animations")
val appendageDirectories: List<String>
get() = listOf("bedrock/$type/appendages")
val appendages = mutableMapOf<ResourceLocation, ModelAppendage>()
override val fallback: ResourceLocation = cobblemonResource("substitute")
override val isForLivingEntityRenderer: Boolean
get() = true
override fun registerInBuiltPosers() {}
override fun reload(resourceManager: ResourceManager) {
super.reload(resourceManager)
this.appendages.clear()
registerJsonAppendages(resourceManager)
}
private fun registerJsonAppendages(resourceManager: ResourceManager) {
for (directory in appendageDirectories) {
resourceManager
.listResources(directory) { path -> path.endsWith(".json") }
.forEach { (identifier, resource) ->
resource.open().use { stream ->
val json = String(stream.readAllBytes(), StandardCharsets.UTF_8)
val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension)
appendages[resolvedIdentifier] = gson.fromJson(json, ModelAppendage::class.java)
}
}
}
}
fun getAppendagesForModelAndTarget(model: ResourceLocation, target: String): List<ModelAppendage> {
return appendages.entries.filter { (it.value.targetModel == model || it.value.targetModel == null) && it.value.targetLocator == target }.map { it.value }
}
fun getPoserNullable(name: ResourceLocation, state: PosableState): PosableModel? {
try {
val poser = this.variations[name]?.getPoser(state)
if (poser != null) {
return poser
}
} catch(e: IllegalStateException) {
// e.printStackTrace()
}
return this.variations[fallback]?.getPoser(state)
}
}
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BE
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BEAM_SHRINK_TIME
import com.cobblemon.mod.common.client.keybind.boundKey
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
import com.cobblemon.mod.common.client.render.layer.ModelAppendageRenderer
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PosablePokemonEntityModel
@@ -41,7 +42,6 @@ import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.remap
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
import kotlin.math.*
import net.minecraft.ChatFormatting
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font.DisplayMode
@@ -61,15 +61,17 @@ import org.joml.Math
import org.joml.Quaternionf
import org.joml.Vector3f
import org.joml.Vector4f
import kotlin.math.*
class PokemonRenderer(
context: EntityRendererProvider.Context
var context: EntityRendererProvider.Context
) : MobRenderer<PokemonEntity, PosablePokemonEntityModel>(context, PosablePokemonEntityModel(), 0.5f) {
companion object {
val recallBeamColour = Vector4f(1F, 0.1F, 0.1F, 1F)
fun ease(x: Double): Double {
return 1 - (1 - x).pow(3)
}
private val LEVEL_LABEL_STYLE = Style.EMPTY.withColor(ChatFormatting.WHITE)
.withBold(false)
.withItalic(false)
@@ -88,7 +90,10 @@ class PokemonRenderer(
}
override fun getTextureLocation(entity: PokemonEntity): ResourceLocation {
return PokemonModelRepository.getTexture(entity.pokemon.species.resourceIdentifier, entity.delegate as PokemonClientDelegate)
return PokemonModelRepository.getTexture(
entity.pokemon.species.resourceIdentifier,
entity.delegate as PokemonClientDelegate
)
}
override fun render(
@@ -100,7 +105,10 @@ class PokemonRenderer(
packedLight: Int
) {
val clientDelegate = entity.delegate as PokemonClientDelegate
shadowRadius = min((entity.boundingBox.maxX - entity.boundingBox.minX), (entity.boundingBox.maxZ) - (entity.boundingBox.minZ)).toFloat() / 1.5F * (entity.delegate as PokemonClientDelegate).entityScaleModifier
shadowRadius = min(
(entity.boundingBox.maxX - entity.boundingBox.minX),
(entity.boundingBox.maxZ) - (entity.boundingBox.minZ)
).toFloat() / 1.5F * (entity.delegate as PokemonClientDelegate).entityScaleModifier
model.posableModel = PokemonModelRepository.getPoser(entity.pokemon.species.resourceIdentifier, clientDelegate)
model.posableModel.context = model.context
model.setupEntityTypeContext(entity)
@@ -126,7 +134,7 @@ class PokemonRenderer(
clientDelegate
)
}
if(entity.platform != PlatformType.NONE) {
if (entity.platform != PlatformType.NONE) {
drawPlatform(
poseMatrix,
entity,
@@ -138,10 +146,34 @@ class PokemonRenderer(
poseMatrix.translate(0.0, 0.25 * (entity.delegate as PokemonClientDelegate).entityScaleModifier, 0.0)
}
modelNow.setLayerContext(buffer, clientDelegate, PokemonModelRepository.getLayers(entity.pokemon.species.resourceIdentifier, clientDelegate))
modelNow.setLayerContext(
buffer,
clientDelegate,
PokemonModelRepository.getLayers(entity.pokemon.species.resourceIdentifier, clientDelegate)
)
super.render(entity, entityYaw, partialTicks, poseMatrix, buffer, packedLight)
PokemonModelRepository.variations[entity.pokemon.species.resourceIdentifier]?.getResolvedModel(clientDelegate).let { parentModel ->
clientDelegate.locatorStates.keys.forEach { locatorKey ->
if (parentModel != null) {
ModelAppendageRenderer.render(
poseMatrix,
buffer,
packedLight,
entity,
0f,
0f,
entity.age.toFloat() + partialTicks,
entityYaw,
entity.lookAngle.x.toFloat(),
locatorKey,
model.context,
parentModel
)
}
}
}
modelNow.green = 1F
modelNow.blue = 1F
@@ -165,7 +197,7 @@ class PokemonRenderer(
val s = clientDelegate.secondsSinceBeamEffectStarted
if (beamMode == 3) {
if (s > BEAM_EXTEND_TIME) {
val value = (s - BEAM_EXTEND_TIME) / BEAM_SHRINK_TIME
val value = (s - BEAM_EXTEND_TIME) / BEAM_SHRINK_TIME
val colourValue = 1F - min(0.6F, value)
modelNow.green = colourValue
modelNow.blue = colourValue
@@ -181,7 +213,9 @@ class PokemonRenderer(
val lookVec = phaseTarget.lookAngle.yRot((PI / 2).toFloat()).multiply(1.0, 0.0, 1.0).normalize()
phaseTarget.getEyePosition(partialTicks).subtract(0.0, 0.4, 0.0).subtract(lookVec.scale(0.3))
} else {
val lookVec = phaseTarget.lookAngle.yRot((PI / 2 - (phaseTarget.visualRotationYInDegrees - phaseTarget.xRot).toRadians()).toFloat()).multiply(1.0, 0.0, 1.0).normalize()
val lookVec =
phaseTarget.lookAngle.yRot((PI / 2 - (phaseTarget.visualRotationYInDegrees - phaseTarget.xRot).toRadians()).toFloat())
.multiply(1.0, 0.0, 1.0).normalize()
phaseTarget.getEyePosition(partialTicks).subtract(0.0, 0.7, 0.0).subtract(lookVec.scale(0.4))
}
}
@@ -192,7 +226,8 @@ class PokemonRenderer(
clientDelegate.sendOutPosition = clientDelegate.sendOutPosition!!.add(0.0, 0.04, 0.0)
beamSourcePosition = clientDelegate.sendOutPosition!!
}
val offsetDirection = beamSourcePosition.subtract(entity.position()).normalize().scale(-clientDelegate.ballOffset.toDouble())
val offsetDirection =
beamSourcePosition.subtract(entity.position()).normalize().scale(-clientDelegate.ballOffset.toDouble())
val facingDir: Vec3
with(beamSourcePosition.subtract(entity.position())) {
var newOffset = offsetDirection.scale(2.0)
@@ -200,16 +235,17 @@ class PokemonRenderer(
newOffset = newOffset.scale((distance / 10.0) * 5)
facingDir = newOffset.normalize()
clientDelegate.sendOutOffset = newOffset
poseMatrix.translate(x+newOffset.x, y+newOffset.y, z+newOffset.z)
poseMatrix.translate(x + newOffset.x, y + newOffset.y, z + newOffset.z)
}
val dir = beamSourcePosition.subtract(entity.position()).normalize()
val angle = Mth.atan2(dir.z, dir.x) - PI / 2
poseMatrix.mulPose(Axis.YP.rotation(-angle.toFloat() + (180 * Math.PI / 180).toFloat()))
if (beamMode == 1 && !clientDelegate.ballDone){
if(entity.pokemon.caughtBall.name.toString().contains("beast")){
if (beamMode == 1 && !clientDelegate.ballDone) {
if (entity.pokemon.caughtBall.name.toString().contains("beast")) {
// get rotation angle on x-axis for facingDir
val xAngleFacingDir = Mth.atan2(facingDir.y, sqrt(facingDir.x * facingDir.x + facingDir.z * facingDir.z))
val xAngleFacingDir =
Mth.atan2(facingDir.y, sqrt(facingDir.x * facingDir.x + facingDir.z * facingDir.z))
poseMatrix.mulPose(Axis.XP.rotation(-xAngleFacingDir.toFloat()))
}
drawPokeBall(
@@ -221,7 +257,7 @@ class PokemonRenderer(
packedLight = packedLight,
ball = CobblemonClient.storage.myParty.firstOrNull { it?.uuid == entity.pokemon.uuid }?.caughtBall
?: clientDelegate.currentEntity.pokemon.caughtBall,
distance = ceil(beamSourcePosition.distanceTo(entity.position())/4f).toInt()
distance = ceil(beamSourcePosition.distanceTo(entity.position()) / 4f).toInt()
)
}
poseMatrix.popPose()
@@ -231,7 +267,8 @@ class PokemonRenderer(
}
override fun scale(pEntity: PokemonEntity, pPoseStack: PoseStack, pPartialTickTime: Float) {
val scale = pEntity.pokemon.form.baseScale * pEntity.pokemon.scaleModifier * (pEntity.delegate as PokemonClientDelegate).entityScaleModifier
val scale =
pEntity.pokemon.form.baseScale * pEntity.pokemon.scaleModifier * (pEntity.delegate as PokemonClientDelegate).entityScaleModifier
pPoseStack.scale(scale, scale, scale)
}
@@ -245,9 +282,17 @@ class PokemonRenderer(
* @param colour The colour of the beam.
* @param buffer The vertex consumer provider.
*/
fun renderBeam(matrixStack: PoseStack, partialTicks: Float, entity: PokemonEntity, beamTarget: Entity, buffer: MultiBufferSource, offset: Vec3) {
fun renderBeam(
matrixStack: PoseStack,
partialTicks: Float,
entity: PokemonEntity,
beamTarget: Entity,
buffer: MultiBufferSource,
offset: Vec3
) {
val clientDelegate = entity.delegate as PokemonClientDelegate
val pokemonPosition = entity.position().add(0.0, entity.bbHeight / 2.0 * clientDelegate.entityScaleModifier.toDouble(), 0.0)
val pokemonPosition =
entity.position().add(0.0, entity.bbHeight / 2.0 * clientDelegate.entityScaleModifier.toDouble(), 0.0)
var beamSourcePosition = if (beamTarget is EmptyPokeBallEntity) {
(beamTarget.delegate as PokeBallPosableState).locatorStates["beam"]?.getOrigin() ?: beamTarget.position()
} else {
@@ -257,7 +302,9 @@ class PokemonRenderer(
} else if (beamTarget is NPCEntity) {
(beamTarget.delegate as NPCClientDelegate).locatorStates["beam"]?.getOrigin() ?: beamTarget.position()
} else {
val lookVec = beamTarget.lookAngle.yRot((PI / 2 - (beamTarget.visualRotationYInDegrees - beamTarget.xRot).toRadians()).toFloat()).multiply(1.0, 0.0, 1.0).normalize()
val lookVec =
beamTarget.lookAngle.yRot((PI / 2 - (beamTarget.visualRotationYInDegrees - beamTarget.xRot).toRadians()).toFloat())
.multiply(1.0, 0.0, 1.0).normalize()
beamTarget.getEyePosition(partialTicks).subtract(0.0, 0.7, 0.0).subtract(lookVec.scale(0.4))
}
}
@@ -272,8 +319,9 @@ class PokemonRenderer(
// the further away the source position is, the smaller the newOffset should be. Max distance is 20 blocks
val distance = beamSourcePosition.distanceTo(entity.position())
newOffset = newOffset.scale((distance / 10.0) * 5)
newOffset = newOffset.multiply(0.0, 1+ease(clientDelegate.ballOffset.toDouble()), 0.0)
val direction = pokemonPosition.subtract(beamSourcePosition.add(newOffset)).let { Vector3f(it.x.toFloat(), it.y.toFloat(), it.z.toFloat()) }
newOffset = newOffset.multiply(0.0, 1 + ease(clientDelegate.ballOffset.toDouble()), 0.0)
val direction = pokemonPosition.subtract(beamSourcePosition.add(newOffset))
.let { Vector3f(it.x.toFloat(), it.y.toFloat(), it.z.toFloat()) }
matrixStack.pushPose()
with(beamSourcePosition.subtract(entity.position())) {
@@ -349,10 +397,10 @@ class PokemonRenderer(
}
val player = Minecraft.getInstance().player ?: return
val d = this.entityRenderDispatcher.distanceToSqr(entity)
if (d <= 4096.0){
if (d <= 4096.0) {
val scale = min(1.5, max(0.65, d.remap(DoubleRange(-16.0, 96.0), DoubleRange(0.0, 1.0))))
val sizeScale = Mth.lerp(scale.remap(DoubleRange(0.65, 1.5), DoubleRange(0.0,1.0)), 0.5, 1.0)
val offsetScale = Mth.lerp(scale.remap(DoubleRange(0.65, 1.5), DoubleRange(0.0,1.0)), 0.0,1.0)
val sizeScale = Mth.lerp(scale.remap(DoubleRange(0.65, 1.5), DoubleRange(0.0, 1.0)), 0.5, 1.0)
val offsetScale = Mth.lerp(scale.remap(DoubleRange(0.65, 1.5), DoubleRange(0.0, 1.0)), 0.0, 1.0)
val entityHeight = entity.boundingBox.ysize + 0.5f
matrices.pushPose()
matrices.translate(0.0, entityHeight, 0.0)
@@ -374,15 +422,48 @@ class PokemonRenderer(
var h = (-this.font.width(label) / 2).toFloat()
val y = 0F
val packedLight = LightTexture.pack(15, 15)
this.font.drawInBatch(label, h, y, 0x20FFFFFF, false, matrix4f, vertexConsumers, DisplayMode.SEE_THROUGH, opacity, packedLight)
this.font.drawInBatch(
label,
h,
y,
0x20FFFFFF,
false,
matrix4f,
vertexConsumers,
DisplayMode.SEE_THROUGH,
opacity,
packedLight
)
this.font.drawInBatch(label, h, y, -1, false, matrix4f, vertexConsumers, DisplayMode.NORMAL, 0, packedLight)
if (CobblemonClient.clientPlayerData.showChallengeLabel && entity.canBattle(player)) {
val sendOutBinding = PartySendBinding.boundKey().displayName
val battlePrompt = lang("challenge_label", sendOutBinding)
h = (-this.font.width(battlePrompt) / 2).toFloat()
this.font.drawInBatch(battlePrompt, h, y + 10, 0x20FFFFFF, false, matrix4f, vertexConsumers, DisplayMode.SEE_THROUGH, opacity, packedLight)
this.font.drawInBatch(battlePrompt, h, y + 10, -1, false, matrix4f, vertexConsumers, DisplayMode.NORMAL, 0, packedLight)
this.font.drawInBatch(
battlePrompt,
h,
y + 10,
0x20FFFFFF,
false,
matrix4f,
vertexConsumers,
DisplayMode.SEE_THROUGH,
opacity,
packedLight
)
this.font.drawInBatch(
battlePrompt,
h,
y + 10,
-1,
false,
matrix4f,
vertexConsumers,
DisplayMode.NORMAL,
0,
packedLight
)
}
matrices.popPose()
}
@@ -391,7 +472,10 @@ class PokemonRenderer(
private fun resolveBaseLabel(entity: PokemonEntity): MutableComponent {
return when {
!ServerSettings.displayEntityNameLabel -> Component.empty()
Cobblemon.config.displayNameForUnknownPokemon || CobblemonClient.clientPokedexData.getKnowledgeForSpecies(entity.pokemon.species.resourceIdentifier) != PokedexEntryProgress.NONE -> entity.name.copy()
Cobblemon.config.displayNameForUnknownPokemon || CobblemonClient.clientPokedexData.getKnowledgeForSpecies(
entity.pokemon.species.resourceIdentifier
) != PokedexEntryProgress.NONE -> entity.name.copy()
else -> Component.literal(HIDDEN_NAME)
}
}
@@ -416,7 +500,7 @@ class PokemonRenderer(
} else {
matrixStack.translate(0.0, -0.2, 0.0)
val rot = 360F * distance
if(ball.name.toString().contains("beast")){
if (ball.name.toString().contains("beast")) {
matrixStack.mulPose(Axis.ZN.rotationDegrees(Math.lerp(0F, rot, scale)))
} else {
matrixStack.mulPose(Axis.XN.rotationDegrees(Math.lerp(0F, rot, scale)))
@@ -440,12 +524,12 @@ class PokemonRenderer(
}
private fun drawPlatform(
matrixStack: PoseStack,
entity: PokemonEntity,
scale: Float = 1F,
buff: MultiBufferSource,
packedLight: Int,
) {
matrixStack: PoseStack,
entity: PokemonEntity,
scale: Float = 1F,
buff: MultiBufferSource,
packedLight: Int,
) {
val (modelResource, textureResource) = PlatformType.getModelWithTexture(entity.platform)
val model = MiscModelRepository.modelOf(modelResource) ?: return
matrixStack.pushPose()
@@ -0,0 +1,564 @@
{
"format_version": "1.8.0",
"animations": {
"animation.egg.idle": {
"loop": true,
"bones": {
"egg": {
"rotation": [0, 0, 0],
"position": [0, 0, 0]
},
"body": {
"rotation": [0, 0, 0],
"position": [0, 0, 0]
},
"egg_shell1": {
"position": [0, "math.sin(q.anim_time*90+1)", 0]
},
"egg_shell2": {
"position": [0, "math.sin(q.anim_time*90+2)", 0]
},
"egg_shell3": {
"position": [0, "math.sin(q.anim_time*90+3)", 0]
},
"egg_shell4": {
"position": [0, "math.sin(q.anim_time*90+4)", 0]
},
"egg_shell5": {
"position": [0, "math.sin(q.anim_time*90+5)", 0]
},
"egg_shell6": {
"position": [0, "math.sin(q.anim_time*90+6)", 0]
},
"egg_shell7": {
"position": [0, "math.sin(q.anim_time*90+7)", 0]
},
"egg_shell8": {
"position": [0, "math.sin(q.anim_time*90+8)", 0]
},
"egg_shell9": {
"position": [0, "math.sin(q.anim_time*90+9)", 0]
},
"egg_shell10": {
"position": [0, "math.sin(q.anim_time*90+10)", 0]
},
"egg_shell11": {
"position": [0, "math.sin(q.anim_time*90+11)", 0]
},
"egg_shell12": {
"position": [0, "math.sin(q.anim_time*90+12)", 0]
},
"egg_shell13": {
"position": [0, "math.sin(q.anim_time*90+13)", 0]
},
"egg_shell14": {
"position": [0, "math.sin(q.anim_time*90+14)", 0]
},
"egg_shell15": {
"position": [0, "math.sin(q.anim_time*90+15)", 0]
},
"egg_shell16": {
"position": [0, "math.sin(q.anim_time*90+16)", 0]
},
"egg_shell17": {
"position": [0, "math.sin(q.anim_time*90+17)", 0]
},
"egg_shell18": {
"position": [0, "math.sin(q.anim_time*90+18)", 0]
},
"egg_shell19": {
"position": [0, "math.sin(q.anim_time*90+19)", 0]
},
"egg_shell20": {
"position": [0, "math.sin(q.anim_time*90+20)", 0]
},
"egg_shell21": {
"position": [0, "math.sin(q.anim_time*90+21)", 0]
},
"egg_shell22": {
"position": [0, "math.sin(q.anim_time*90+22)", 0]
},
"egg_shell23": {
"position": [0, "math.sin(q.anim_time*90+23)", 0]
},
"egg_shell24": {
"position": [0, "math.sin(q.anim_time*90+24)", 0]
},
"egg_shell25": {
"position": [0, "math.sin(q.anim_time*90+25)", 0]
},
"egg_shell26": {
"position": [0, "math.sin(q.anim_time*90+26)", 0]
},
"egg_shell27": {
"position": [0, "math.sin(q.anim_time*90+27)", 0]
},
"egg_shell28": {
"position": [0, "math.sin(q.anim_time*90+28)", 0]
},
"egg_shell29": {
"position": [0, "math.sin(q.anim_time*90+29)", 0]
},
"egg_shell30": {
"position": [0, "math.sin(q.anim_time*90+30)", 0]
},
"egg_shell31": {
"position": [0, "math.sin(q.anim_time*90+31)", 0]
},
"egg_shell32": {
"position": [0, "math.sin(q.anim_time*90+32)", 0]
},
"egg_shell33": {
"position": [0, "math.sin(q.anim_time*90+33)", 0]
},
"egg_shell34": {
"position": [0, "math.sin(q.anim_time*90+34)", 0]
},
"egg_shell35": {
"position": [0, "math.sin(q.anim_time*90+35)", 0]
},
"egg_shell36": {
"position": [0, "math.sin(q.anim_time*90+36)", 0]
},
"egg_shell37": {
"position": [0, "math.sin(q.anim_time*90+37)", 0]
},
"egg_shell38": {
"position": [0, "math.sin(q.anim_time*90+38)", 0]
},
"egg_shell39": {
"position": [0, "math.sin(q.anim_time*90+39)", 0]
},
"egg_shell40": {
"position": [0, "math.sin(q.anim_time*90+40)", 0]
},
"egg_shell41": {
"position": [0, "math.sin(q.anim_time*90+41)", 0]
},
"egg_shell42": {
"position": [0, "math.sin(q.anim_time*90+42)", 0]
},
"egg_shell43": {
"position": [0, "math.sin(q.anim_time*90+43)", 0]
},
"egg_shell44": {
"position": [0, "math.sin(q.anim_time*90+44)", 0]
},
"egg_shell45": {
"position": [0, "math.sin(q.anim_time*90+45)", 0]
},
"egg_shell46": {
"position": [0, "math.sin(q.anim_time*90+46)", 0]
},
"egg_shell47": {
"position": [0, "math.sin(q.anim_time*90+47)", 0]
},
"egg_shell48": {
"position": [0, "math.sin(q.anim_time*90+48)", 0]
},
"egg_shell49": {
"position": [0, "math.sin(q.anim_time*90+49)", 0]
},
"egg_shell50": {
"position": [0, "math.sin(q.anim_time*90+50)", 0]
},
"egg_shell51": {
"position": [0, "math.sin(q.anim_time*90+51)", 0]
},
"egg_shell52": {
"position": [0, "math.sin(q.anim_time*90+52)", 0]
},
"egg_shell53": {
"position": [0, "math.sin(q.anim_time*90+53)", 0]
},
"egg_shell54": {
"position": [0, "math.sin(q.anim_time*90+54)", 0]
},
"egg_shell55": {
"position": [0, "math.sin(q.anim_time*90+55)", 0]
},
"egg_shell56": {
"position": [0, "math.sin(q.anim_time*90+56)", 0]
},
"egg_shell57": {
"position": [0, "math.sin(q.anim_time*90+57)", 0]
},
"egg_shell58": {
"position": [0, "math.sin(q.anim_time*90+58)", 0]
},
"egg_shell59": {
"position": [0, "math.sin(q.anim_time*90+59)", 0]
},
"egg_shell60": {
"position": [0, "math.sin(q.anim_time*90+60)", 0]
},
"egg_shell61": {
"position": [0, "math.sin(q.anim_time*90+61)", 0]
},
"egg_shell62": {
"position": [0, "math.sin(q.anim_time*90+62)", 0]
},
"egg_shell63": {
"position": [0, "math.sin(q.anim_time*90+63)", 0]
},
"egg_shell64": {
"position": [0, "math.sin(q.anim_time*90+64)", 0]
},
"egg_shell65": {
"position": [0, "math.sin(q.anim_time*90+65)", 0]
},
"egg_shell66": {
"position": [0, "math.sin(q.anim_time*90+66)", 0]
},
"egg_shell67": {
"position": [0, "math.sin(q.anim_time*90+67)", 0]
},
"egg_shell68": {
"position": [0, "math.sin(q.anim_time*90+68)", 0]
},
"egg_shell69": {
"position": [0, "math.sin(q.anim_time*90+69)", 0]
},
"egg_shell70": {
"position": [0, "math.sin(q.anim_time*90+70)", 0]
},
"egg_shell71": {
"position": [0, "math.sin(q.anim_time*90+71)", 0]
},
"egg_shell72": {
"position": [0, "math.sin(q.anim_time*90+72)", 0]
},
"egg_shell73": {
"position": [0, "math.sin(q.anim_time*90+73)", 0]
},
"egg_shell74": {
"position": [0, "math.sin(q.anim_time*90+74)", 0]
},
"egg_shell75": {
"position": [0, "math.sin(q.anim_time*90+75)", 0]
},
"egg_shell76": {
"position": [0, "math.sin(q.anim_time*90+76)", 0]
},
"egg_shell77": {
"position": [0, "math.sin(q.anim_time*90+77)", 0]
},
"egg_shell78": {
"position": [0, "math.sin(q.anim_time*90+78)", 0]
},
"egg_shell79": {
"position": [0, "math.sin(q.anim_time*90+79)", 0]
},
"egg_shell80": {
"position": [0, "math.sin(q.anim_time*90+80)", 0]
},
"egg_shell81": {
"position": [0, "math.sin(q.anim_time*90+81)", 0]
},
"egg_shell82": {
"position": [0, "math.sin(q.anim_time*90+82)", 0]
},
"egg_shell83": {
"position": [0, "math.sin(q.anim_time*90+83)", 0]
},
"egg_shell84": {
"position": [0, "math.sin(q.anim_time*90+84)", 0]
},
"egg_shell85": {
"position": [0, "math.sin(q.anim_time*90+85)", 0]
},
"egg_shell86": {
"position": [0, "math.sin(q.anim_time*90+86)", 0]
},
"egg_shell87": {
"position": [0, "math.sin(q.anim_time*90+87)", 0]
},
"egg_shell88": {
"position": [0, "math.sin(q.anim_time*90+88)", 0]
},
"egg_shell89": {
"position": [0, "math.sin(q.anim_time*90+89)", 0]
},
"egg_shell90": {
"position": [0, "math.sin(q.anim_time*90+90)", 0]
},
"egg_shell91": {
"position": [0, "math.sin(q.anim_time*90+91)", 0]
},
"egg_shell92": {
"position": [0, "math.sin(q.anim_time*90+92)", 0]
},
"egg_shell93": {
"position": [0, "math.sin(q.anim_time*90+93)", 0]
},
"egg_shell94": {
"position": [0, "math.sin(q.anim_time*90+94)", 0]
},
"egg_shell95": {
"position": [0, "math.sin(q.anim_time*90+95)", 0]
},
"egg_shell96": {
"position": [0, "math.sin(q.anim_time*90+96)", 0]
},
"egg_shell97": {
"position": [0, "math.sin(q.anim_time*90+97)", 0]
},
"egg_shell98": {
"position": [0, "math.sin(q.anim_time*90+98)", 0]
},
"egg_shell99": {
"position": [0, "math.sin(q.anim_time*90+99)", 0]
},
"egg_shell100": {
"position": [0, "math.sin(q.anim_time*90+100)", 0]
},
"egg_shell105": {
"position": [0, "math.sin(q.anim_time*90+105+1)", 0]
},
"egg_shell106": {
"position": [0, "math.sin(q.anim_time*90+106+1)", 0]
},
"egg_shell107": {
"position": [0, "math.sin(q.anim_time*90+107+1)", 0]
},
"egg_shell108": {
"position": [0, "math.sin(q.anim_time*90+108+1)", 0]
},
"egg_shell109": {
"position": [0, "math.sin(q.anim_time*90+109+1)", 0]
},
"egg_shell110": {
"position": [0, "math.sin(q.anim_time*90+110+1)", 0]
},
"egg_shell111": {
"position": [0, "math.sin(q.anim_time*90+111+1)", 0]
},
"egg_shell112": {
"position": [0, "math.sin(q.anim_time*90+112+1)", 0]
},
"egg_shell113": {
"position": [0, "math.sin(q.anim_time*90+113+1)", 0]
},
"egg_shell114": {
"position": [0, "math.sin(q.anim_time*90+114+1)", 0]
},
"egg_shell115": {
"position": [0, "math.sin(q.anim_time*90+115+1)", 0]
},
"egg_shell116": {
"position": [0, "math.sin(q.anim_time*90+116+1)", 0]
},
"egg_shell117": {
"position": [0, "math.sin(q.anim_time*90+117+1)", 0]
},
"egg_shell118": {
"position": [0, "math.sin(q.anim_time*90+118+1)", 0]
},
"egg_shell119": {
"position": [0, "math.sin(q.anim_time*90+119+1)", 0]
},
"egg_shell120": {
"position": [0, "math.sin(q.anim_time*90+120+1)", 0]
},
"egg_shell121": {
"position": [0, "math.sin(q.anim_time*90+121+1)", 0]
},
"egg_shell123": {
"position": [0, "math.sin(q.anim_time*90+123+1)", 0]
},
"egg_shell124": {
"position": [0, "math.sin(q.anim_time*90+124+1)", 0]
},
"egg_shell125": {
"position": [0, "math.sin(q.anim_time*90+125+1)", 0]
},
"egg_shell126": {
"position": [0, "math.sin(q.anim_time*90+126+1)", 0]
},
"egg_shell127": {
"position": [0, "math.sin(q.anim_time*90+127+1)", 0]
},
"egg_shell128": {
"position": [0, "math.sin(q.anim_time*90+128+1)", 0]
},
"egg_shell129": {
"position": [0, "math.sin(q.anim_time*90+129+1)", 0]
},
"egg_shell130": {
"position": [0, "math.sin(q.anim_time*90+130+1)", 0]
},
"egg_shell131": {
"position": [0, "math.sin(q.anim_time*90+131+1)", 0]
},
"egg_shell132": {
"position": [0, "math.sin(q.anim_time*90+132+1)", 0]
},
"egg_shell133": {
"position": [0, "math.sin(q.anim_time*90+133+1)", 0]
},
"egg_shell134": {
"position": [0, "math.sin(q.anim_time*90+134+1)", 0]
},
"egg_shell135": {
"position": [0, "math.sin(q.anim_time*90+135+1)", 0]
},
"egg_shell136": {
"position": [0, "math.sin(q.anim_time*90+136+1)", 0]
},
"egg_shell137": {
"position": [0, "math.sin(q.anim_time*90+137+1)", 0]
},
"egg_shell138": {
"position": [0, "math.sin(q.anim_time*90+138+1)", 0]
},
"egg_shell139": {
"position": [0, "math.sin(q.anim_time*90+139+1)", 0]
},
"egg_shell140": {
"position": [0, "math.sin(q.anim_time*90+140+1)", 0]
},
"egg_shell141": {
"position": [0, "math.sin(q.anim_time*90+141+1)", 0]
},
"egg_shell142": {
"position": [0, "math.sin(q.anim_time*90+142+1)", 0]
},
"egg_shell143": {
"position": [0, "math.sin(q.anim_time*90+143+1)", 0]
},
"egg_shell144": {
"position": [0, "math.sin(q.anim_time*90+144+1)", 0]
},
"egg_shell145": {
"position": [0, "math.sin(q.anim_time*90+145+1)", 0]
},
"egg_shell146": {
"position": [0, "math.sin(q.anim_time*90+146+1)", 0]
},
"egg_shell147": {
"position": [0, "math.sin(q.anim_time*90+147+1)", 0]
},
"egg_shell148": {
"position": [0, "math.sin(q.anim_time*90+148+1)", 0]
},
"egg_shell149": {
"position": [0, "math.sin(q.anim_time*90+149+1)", 0]
},
"egg_shell150": {
"position": [0, "math.sin(q.anim_time*90+150+1)", 0]
},
"egg_shell151": {
"position": [0, "math.sin(q.anim_time*90+151+1)", 0]
},
"egg_shell152": {
"position": [0, "math.sin(q.anim_time*90+152+1)", 0]
},
"egg_shell153": {
"position": [0, "math.sin(q.anim_time*90+153+1)", 0]
},
"egg_shell154": {
"position": [0, "math.sin(q.anim_time*90+154+1)", 0]
},
"egg_shell155": {
"position": [0, "math.sin(q.anim_time*90+155+1)", 0]
},
"egg_shell156": {
"position": [0, "math.sin(q.anim_time*90+156+1)", 0]
},
"egg_shell157": {
"position": [0, "math.sin(q.anim_time*90+157+1)", 0]
},
"egg_shell158": {
"position": [0, "math.sin(q.anim_time*90+158+1)", 0]
},
"egg_shell159": {
"position": [0, "math.sin(q.anim_time*90+159+1)", 0]
},
"egg_shell160": {
"position": [0, "math.sin(q.anim_time*90+160+1)", 0]
},
"egg_shell161": {
"position": [0, "math.sin(q.anim_time*90+161+1)", 0]
},
"egg_shell162": {
"position": [0, "math.sin(q.anim_time*90+162+1)", 0]
},
"egg_shell163": {
"position": [0, "math.sin(q.anim_time*90+163+1)", 0]
},
"egg_shell164": {
"position": [0, "math.sin(q.anim_time*90+164+1)", 0]
},
"egg_shell165": {
"position": [0, "math.sin(q.anim_time*90+165+1)", 0]
},
"egg_shell166": {
"position": [0, "math.sin(q.anim_time*90+166+1)", 0]
},
"egg_shell167": {
"position": [0, "math.sin(q.anim_time*90+167+1)", 0]
},
"egg_shell168": {
"position": [0, "math.sin(q.anim_time*90+168+1)", 0]
},
"egg_shell169": {
"position": [0, "math.sin(q.anim_time*90+169+1)", 0]
},
"egg_shell170": {
"position": [0, "math.sin(q.anim_time*90+170+1)", 0]
},
"egg_shell171": {
"position": [0, "math.sin(q.anim_time*90+171+1)", 0]
},
"egg_shell172": {
"position": [0, "math.sin(q.anim_time*90+172+1)", 0]
},
"egg_shell173": {
"position": [0, "math.sin(q.anim_time*90+173+1)", 0]
},
"egg_shell174": {
"position": [0, "math.sin(q.anim_time*90+174+1)", 0]
},
"egg_shell175": {
"position": [0, "math.sin(q.anim_time*90+175+1)", 0]
},
"egg_shell176": {
"position": [0, "math.sin(q.anim_time*90+176+1)", 0]
},
"egg_shell177": {
"position": [0, "math.sin(q.anim_time*90+177+1)", 0]
},
"egg_shell178": {
"position": [0, "math.sin(q.anim_time*90+178+1)", 0]
},
"egg_shell179": {
"position": [0, "math.sin(q.anim_time*90+179+1)", 0]
},
"egg_shell180": {
"position": [0, "math.sin(q.anim_time*90+180+1)", 0]
},
"egg_shell181": {
"position": [0, "math.sin(q.anim_time*90+181+1)", 0]
},
"egg_shell182": {
"position": [0, "math.sin(q.anim_time*90+182+1)", 0]
},
"egg_shell183": {
"position": [0, "math.sin(q.anim_time*90+183+1)", 0]
},
"egg_shell184": {
"position": [0, "math.sin(q.anim_time*90+184+1)", 0]
},
"egg_shell185": {
"position": [0, "math.sin(q.anim_time*90+185+1)", 0]
},
"egg_body": {
"position": [0, 0, 0]
},
"egg_body185": {
"position": [0, 0, 5]
}
}
}
}
}
@@ -0,0 +1,7 @@
{
"model": "q.appendage_model('cobblemon:egg');",
"target_locator": "head",
"scale": [1.0, 1.0, 1.0],
"offset": [0.0, 0, 0.0],
"rotation": [0.0, 45.0, 0.0]
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,12 @@
{
"poses": {
"standing": {
"poseName": "standing",
"transformTicks": 0,
"poseTypes": ["STAND", "WALK", "SLEEP", "HOVER", "FLY", "FLOAT", "SWIM", "PORTRAIT", "PROFILE"],
"animations": [
"q.bedrock('egg', 'idle')"
]
}
}
}
@@ -0,0 +1,15 @@
{
"name": "cobblemon:egg",
"order": 0,
"variations": [
{
"aspects": [
"shiny"
],
"poser": "cobblemon:egg",
"model": "cobblemon:egg.geo",
"texture": "cobblemon:textures/appendage/egg.png",
"layers": []
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B