Enhance ability animation handling: track ability animation state, clear orphaned animations on login, and ensure proper animation continuation

This commit is contained in:
Kam committed 2026-02-15 22:03:32 -05:00
1 parent 3beaf68815
commit 248dbf66da
2 files changed
+40 -5

No files matched your search

@@ -54,6 +54,13 @@ public class PlayerAbilityData implements IPlayerAbilityData {
*/
private int selectedIndex = 0;
/**
* Tracks whether the current animation was started by an ability.
* Persisted to NBT so orphaned ability animations can be detected and
* cleared on login (ability state is transient, but animation state is not).
*/
private boolean playingAbilityAnimation = false;
// ═══════════════════════════════════════════════════════════════════
// RUNTIME STATE (not saved)
// ═══════════════════════════════════════════════════════════════════
@@ -779,6 +786,7 @@ public class PlayerAbilityData implements IPlayerAbilityData {
playerData.animationData.setEnabled(true);
playerData.animationData.setAnimation(animation);
playerData.animationData.updateClient();
playingAbilityAnimation = true;
}
public void playAbilityAnimation(int animation) {
@@ -800,6 +808,23 @@ public class PlayerAbilityData implements IPlayerAbilityData {
private void stopAbilityAnimation() {
playerData.animationData.setAnimation(null);
playerData.animationData.updateClient();
playingAbilityAnimation = false;
}
/**
* Returns true if an ability-driven animation is currently playing.
* Used by PlayerData.onLogin() to detect orphaned ability animations.
*/
public boolean isPlayingAbilityAnimation() {
return playingAbilityAnimation;
}
/**
* Clears an orphaned ability animation (e.g. after relog when the ability is gone).
* Stops the animation and resets the tracking flag.
*/
public void clearOrphanedAbilityAnimation() {
stopAbilityAnimation();
}
private void playAbilitySound(EntityPlayer player, String sound) {
@@ -819,6 +844,7 @@ public class PlayerAbilityData implements IPlayerAbilityData {
}
compound.setTag("PlayerAbilities", list);
compound.setInteger("PlayerAbilitySelected", selectedIndex);
compound.setBoolean("AbilityAnimating", playingAbilityAnimation);
}
public void readFromNBT(NBTTagCompound compound) {
@@ -836,5 +862,6 @@ public class PlayerAbilityData implements IPlayerAbilityData {
if (selectedIndex >= unlockedAbilities.size()) {
selectedIndex = Math.max(0, unlockedAbilities.size() - 1);
}
playingAbilityAnimation = compound.getBoolean("AbilityAnimating");
}
}
@@ -95,13 +95,21 @@ public class PlayerData implements IExtendedEntityProperties, IPlayerData {
private boolean specialKeyDown = false;
public void onLogin() {
// Continue playing animation for self when re-logging
// Handle animation state from previous session
AnimationData animationData = this.animationData;
if (animationData != null && animationData.isClientAnimating()) {
Animation currentAnimation = animationData.currentClientAnimation;
NBTTagCompound compound = currentAnimation.writeToNBT();
animationData.viewAnimation(currentAnimation, animationData, compound,
animationData.isClientAnimating(), currentAnimation.currentFrame, currentAnimation.currentFrameTime);
if (abilityData.isPlayingAbilityAnimation()) {
// Ability animation was playing when player disconnected.
// Ability state is transient (lost on disconnect), so this animation
// is orphaned - clear it instead of replaying a stuck animation.
abilityData.clearOrphanedAbilityAnimation();
} else {
// Non-ability animation (e.g. script-driven) - continue playing
Animation currentAnimation = animationData.currentClientAnimation;
NBTTagCompound compound = currentAnimation.writeToNBT();
animationData.viewAnimation(currentAnimation, animationData, compound,
animationData.isClientAnimating(), currentAnimation.currentFrame, currentAnimation.currentFrameTime);
}
}
CustomEffectController controller = CustomEffectController.getInstance();