More cleanup

This commit is contained in:
Plastered_Crab
2026-06-19 23:36:40 -07:00
parent ca8ae8f999
commit 1d8c3df1ab
5 changed files with 31 additions and 43 deletions
@@ -99,9 +99,7 @@ public class HumanoidModelMixin {
}
}
// Raise the right arm forward while the player is recalling a Pokémon, so the held Poké Ball
// (rendered by PlayerRecallBallRenderer) is held out in front of them. Eases in/out via the
// tracker's raise factor and holds until the recall beam is finished.
// Pose the right arm forward while recalling so the held Poké Ball sits out in front.
@Inject(method = "setupAnim*", at = @At("TAIL"))
public void cobblemon$poseRecallArm(
LivingEntity entity,
@@ -113,12 +111,12 @@ public class HumanoidModelMixin {
CallbackInfo ci
) {
if (!(entity instanceof AbstractClientPlayer player)) return;
// Don't fight the mounted-riding arm animation.... this could look weird lol
// Skip while riding so we don't override the mounted-riding arm animation.
if (entity.getVehicle() instanceof PokemonEntity) return;
float raise = RecallArmAnimationTracker.INSTANCE.raiseFactor(player.getUUID());
if (raise <= 0f) return;
// -90° about X points the arm straight forward.
this.rightArm.xRot = Mth.lerp(raise, this.rightArm.xRot, -1.5708f);
float armForwardXRot = (float) (-Math.PI / 2.0);
this.rightArm.xRot = Mth.lerp(raise, this.rightArm.xRot, armForwardXRot);
this.rightArm.yRot = Mth.lerp(raise, this.rightArm.yRot, 0f);
this.rightArm.zRot = Mth.lerp(raise, this.rightArm.zRot, 0f);
}
@@ -22,9 +22,8 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* Hides the item normally held in a player's right hand (third person, for everyone) while they are
* recalling a Pokémon, so the recall Poké Ball rendered by PlayerRecallBallRenderer takes its place
* cleanly instead of clipping through the held item.
* Hides the player's right-hand item while recalling so it doesn't overlap the recall Poké Ball
* drawn by PlayerRecallBallRenderer.
*/
@Mixin(ItemInHandLayer.class)
public class ItemInHandLayerMixin {
@@ -27,13 +27,12 @@ import net.minecraft.world.phys.Vec3
import org.joml.Vector3f
/**
* Renders the matching Poké Ball in a recalling player's right hand and reports the world-space point
* the recall beam should emit from. Driven entirely by [RecallArmAnimationTracker]; the right arm is
* posed forward separately in HumanoidModelMixin so [PlayerModel.translateToHand] lands at the
* extended hand.
* Draws the matching Poké Ball in a recalling player's right hand and records where the recall beam
* should start. Driven by [RecallArmAnimationTracker]; the right arm is posed forward in
* HumanoidModelMixin so [PlayerModel.translateToHand] lands on the extended hand.
*
* The local player in first person is skipped here and handled by the first-person ball renderer
* (see ItemInHandRendererMixin) instead.
* The local player in first person is handled by FirstPersonRecallBallRenderer instead, so it's
* skipped here.
*/
class PlayerRecallBallRenderer<T : Player>(
renderLayerParent: RenderLayerParent<T, PlayerModel<T>>
@@ -19,12 +19,11 @@ import net.minecraft.client.renderer.entity.ItemRenderer
import net.minecraft.client.renderer.texture.OverlayTexture
/**
* Renders the recalling player's Poké Ball in first person, rising up from the bottom of the screen
* in place of whatever they were holding. The world-space recall beam still originates near the
* player's hand (handled by the eye/look fallback in PokemonRenderer) — this is purely cosmetic.
* Draws the recalling player's Poké Ball in first person, rising into view from the bottom of the
* screen in place of their held item. The world-space beam still starts near the hand (the eye/look
* fallback in PokemonRenderer), so this is cosmetic only.
*
* Invoked from ItemInHandRendererMixin, which cancels the vanilla main-hand item render while a
* recall is active.
* Called from ItemInHandRendererMixin, which cancels the vanilla main-hand item while recalling.
*/
object FirstPersonRecallBallRenderer {
@@ -11,28 +11,26 @@ package com.cobblemon.mod.common.client.render.player
import com.cobblemon.mod.common.client.battle.ClientBallDisplay
import com.cobblemon.mod.common.pokeball.PokeBall
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
/**
* Client-side bookkeeping for the "recall pose": when a player recalls a Pokémon we want them to
* hold the matching Poké Ball out in their right hand and have the recall beam originate from it.
* Tracks which players are recalling a Pokémon so we can pose their arm, draw the Poké Ball in their
* hand, and start the recall beam from it.
*
* Entries are keyed by the recalling player's UUID and self-expire once the beam effect is over, so
* the arm automatically lowers without anything having to explicitly clear it (and a re-recall just
* resets the timer).
* Keyed by player UUID. Entries time out on their own once the beam is done, and a new recall resets
* the timer, so nothing has to clear them.
*
* Populated from [com.cobblemon.mod.common.client.entity.PokemonClientDelegate] when a Pokémon
* enters recall (beamMode 3). Read by the player arm pose (HumanoidModelMixin), the held-ball render
* layer, the first-person ball renderer, and the beam origin in PokemonRenderer.
* Written by PokemonClientDelegate on recall (beamMode 3); read by HumanoidModelMixin, the ball
* renderers, and PokemonRenderer.
*/
object RecallArmAnimationTracker {
// How long the arm stays raised in seconds
// How long the arm stays raised, in seconds.
const val ARM_HOLD_SECONDS = 0.8
// Portion of time spent easing the arm up / ball in at the start and down at the end
// Fraction of the hold spent easing the arm up at the start and down at the end.
private const val EASE_SECONDS = 0.15
class RecallAnim(
@@ -44,17 +42,17 @@ object RecallArmAnimationTracker {
var beamOrigin: Vec3? = null
}
private val active = mutableMapOf<UUID, RecallAnim>()
private val activeRecalls = ConcurrentHashMap<UUID, RecallAnim>()
fun start(playerUuid: UUID, ball: PokeBall, aspects: Set<String>) {
active[playerUuid] = RecallAnim(ball, aspects, System.currentTimeMillis())
activeRecalls[playerUuid] = RecallAnim(ball, aspects, System.currentTimeMillis())
}
/** Returns the active recall for the player, or null if there is none or if it has expired */
/** Returns the active recall for the player, or null if there is none or if it has expired. */
fun get(playerUuid: UUID): RecallAnim? {
val anim = active[playerUuid] ?: return null
val anim = activeRecalls[playerUuid] ?: return null
if (secondsSince(anim) > ARM_HOLD_SECONDS) {
active.remove(playerUuid)
activeRecalls.remove(playerUuid)
return null
}
return anim
@@ -64,17 +62,12 @@ object RecallArmAnimationTracker {
private fun secondsSince(anim: RecallAnim) = (System.currentTimeMillis() - anim.startTimeMs) / 1000.0
/**
* 0..1 ramp for how raised the arm and how risen the ball should be. eases up at the start, holds
* at 1, then eases back down at the very end. Returns 0 when the player is not recalling.
*/
/** 0..1 ramp: eases in at the start, holds at 1, eases out at the end. 0 when not recalling. */
fun raiseFactor(playerUuid: UUID): Float {
val anim = get(playerUuid) ?: return 0F
val elapsed = secondsSince(anim)
val riseIn = Mth.clamp((elapsed / EASE_SECONDS).toFloat(), 0F, 1F)
val fallOut = Mth.clamp(((ARM_HOLD_SECONDS - elapsed) / EASE_SECONDS).toFloat(), 0F, 1F)
return min(riseIn, fallOut)
return minOf(riseIn, fallOut)
}
private fun min(a: Float, b: Float) = if (a < b) a else b
}