tweak the card take animation

This commit is contained in:
trunksbomb
2026-03-23 17:45:28 -04:00
parent a60b41a774
commit b845d76cd0
2 changed files with 152 additions and 0 deletions

View File

@@ -48,9 +48,11 @@ public class DuelTableBlockEntity extends BlockEntity {
private static final int CAPTURE_DURATION = 10; private static final int CAPTURE_DURATION = 10;
private static final int OVERVIEW_SWEEP_DURATION = 18; private static final int OVERVIEW_SWEEP_DURATION = 18;
private static final int CLEAR_WAVE_DURATION = 10; private static final int CLEAR_WAVE_DURATION = 10;
private static final int REWARD_TAKE_DURATION = 14;
private final NonNullList<ItemStack> boardCards = NonNullList.withSize(SLOT_COUNT, ItemStack.EMPTY); private final NonNullList<ItemStack> boardCards = NonNullList.withSize(SLOT_COUNT, ItemStack.EMPTY);
private final NonNullList<ItemStack> rewardCards = NonNullList.withSize(REWARD_SLOT_COUNT, ItemStack.EMPTY); private final NonNullList<ItemStack> rewardCards = NonNullList.withSize(REWARD_SLOT_COUNT, ItemStack.EMPTY);
private final List<RewardTakeAnimation> rewardTakeAnimations = new ArrayList<>();
private final int[] ownerSlots = new int[SLOT_COUNT]; private final int[] ownerSlots = new int[SLOT_COUNT];
private final int[] slotAges = new int[SLOT_COUNT]; private final int[] slotAges = new int[SLOT_COUNT];
private final ArrayDeque<AnimationStep> pendingAnimations = new ArrayDeque<>(); private final ArrayDeque<AnimationStep> pendingAnimations = new ArrayDeque<>();
@@ -88,6 +90,10 @@ public class DuelTableBlockEntity extends BlockEntity {
return count; return count;
} }
public List<RewardTakeAnimation> rewardTakeAnimations() {
return List.copyOf(rewardTakeAnimations);
}
public int ownerAt(int slot) { public int ownerAt(int slot) {
return ownerSlots[slot]; return ownerSlots[slot];
} }
@@ -253,6 +259,15 @@ public class DuelTableBlockEntity extends BlockEntity {
if (taken.isEmpty()) { if (taken.isEmpty()) {
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
int visibleIndex = visibleRewardIndex(slot);
int rewardCountBeforeTake = rewardCardCount();
if (visibleIndex >= 0 && rewardCountBeforeTake > 0) {
BoardLocalSpace.SlotCenter center = BoardLocalSpace.rewardCenter(
visibleIndex,
getBlockState().getValue(DuelTableBlock.FACING),
rewardCountBeforeTake);
rewardTakeAnimations.add(new RewardTakeAnimation(taken.copyWithCount(1), center.x(), center.z(), 0, REWARD_TAKE_DURATION));
}
rewardCards.set(slot, ItemStack.EMPTY); rewardCards.set(slot, ItemStack.EMPTY);
refreshRewardInteractions(); refreshRewardInteractions();
sync(); sync();
@@ -263,6 +278,7 @@ public class DuelTableBlockEntity extends BlockEntity {
for (int index = 0; index < rewardCards.size(); index++) { for (int index = 0; index < rewardCards.size(); index++) {
rewardCards.set(index, ItemStack.EMPTY); rewardCards.set(index, ItemStack.EMPTY);
} }
rewardTakeAnimations.clear();
removeRewardInteractions(); removeRewardInteractions();
} }
@@ -274,6 +290,7 @@ public class DuelTableBlockEntity extends BlockEntity {
rewardCards.set(slot, ItemStack.EMPTY); rewardCards.set(slot, ItemStack.EMPTY);
} }
} }
rewardTakeAnimations.clear();
removeRewardInteractions(); removeRewardInteractions();
} }
@@ -431,6 +448,21 @@ public class DuelTableBlockEntity extends BlockEntity {
blockEntity.slotAges[slot] = 0; blockEntity.slotAges[slot] = 0;
} }
} }
if (!blockEntity.rewardTakeAnimations.isEmpty()) {
boolean changed = false;
for (int index = blockEntity.rewardTakeAnimations.size() - 1; index >= 0; index--) {
RewardTakeAnimation animation = blockEntity.rewardTakeAnimations.get(index);
animation.age++;
if (animation.age >= animation.duration) {
blockEntity.rewardTakeAnimations.remove(index);
changed = true;
}
}
if (!level.isClientSide && changed) {
blockEntity.sync();
}
}
} }
@Override @Override
@@ -440,6 +472,7 @@ public class DuelTableBlockEntity extends BlockEntity {
CompoundTag rewardTag = new CompoundTag(); CompoundTag rewardTag = new CompoundTag();
ContainerHelper.saveAllItems(rewardTag, rewardCards, registries); ContainerHelper.saveAllItems(rewardTag, rewardCards, registries);
tag.put("RewardCards", rewardTag); tag.put("RewardCards", rewardTag);
saveRewardTakeAnimations(tag, registries);
tag.putIntArray("OwnerSlots", ownerSlots); tag.putIntArray("OwnerSlots", ownerSlots);
tag.putIntArray("SlotAges", slotAges); tag.putIntArray("SlotAges", slotAges);
saveAnimation(tag); saveAnimation(tag);
@@ -460,6 +493,7 @@ public class DuelTableBlockEntity extends BlockEntity {
if (tag.contains("RewardCards", Tag.TAG_COMPOUND)) { if (tag.contains("RewardCards", Tag.TAG_COMPOUND)) {
ContainerHelper.loadAllItems(tag.getCompound("RewardCards"), rewardCards, registries); ContainerHelper.loadAllItems(tag.getCompound("RewardCards"), rewardCards, registries);
} }
loadRewardTakeAnimations(tag, registries);
loadOwnerData(tag); loadOwnerData(tag);
loadAnimation(tag); loadAnimation(tag);
loadTableAnimation(tag); loadTableAnimation(tag);
@@ -472,6 +506,7 @@ public class DuelTableBlockEntity extends BlockEntity {
CompoundTag rewardTag = new CompoundTag(); CompoundTag rewardTag = new CompoundTag();
ContainerHelper.saveAllItems(rewardTag, rewardCards, registries); ContainerHelper.saveAllItems(rewardTag, rewardCards, registries);
tag.put("RewardCards", rewardTag); tag.put("RewardCards", rewardTag);
saveRewardTakeAnimations(tag, registries);
tag.putIntArray("OwnerSlots", ownerSlots); tag.putIntArray("OwnerSlots", ownerSlots);
tag.putIntArray("SlotAges", slotAges); tag.putIntArray("SlotAges", slotAges);
saveAnimation(tag); saveAnimation(tag);
@@ -499,6 +534,7 @@ public class DuelTableBlockEntity extends BlockEntity {
if (tag.contains("RewardCards", Tag.TAG_COMPOUND)) { if (tag.contains("RewardCards", Tag.TAG_COMPOUND)) {
ContainerHelper.loadAllItems(tag.getCompound("RewardCards"), rewardCards, registries); ContainerHelper.loadAllItems(tag.getCompound("RewardCards"), rewardCards, registries);
} }
loadRewardTakeAnimations(tag, registries);
loadOwnerData(tag); loadOwnerData(tag);
loadAnimation(tag); loadAnimation(tag);
loadTableAnimation(tag); loadTableAnimation(tag);
@@ -531,6 +567,44 @@ public class DuelTableBlockEntity extends BlockEntity {
secondParticipantId = tag.hasUUID("SecondParticipantId") ? tag.getUUID("SecondParticipantId") : null; secondParticipantId = tag.hasUUID("SecondParticipantId") ? tag.getUUID("SecondParticipantId") : null;
} }
private void saveRewardTakeAnimations(CompoundTag tag, HolderLookup.Provider registries) {
CompoundTag animationsTag = new CompoundTag();
for (int index = 0; index < rewardTakeAnimations.size(); index++) {
RewardTakeAnimation animation = rewardTakeAnimations.get(index);
CompoundTag animationTag = new CompoundTag();
animationTag.put("Stack", animation.stack.saveOptional(registries));
animationTag.putFloat("LocalX", animation.localX);
animationTag.putFloat("LocalZ", animation.localZ);
animationTag.putInt("Age", animation.age);
animationTag.putInt("Duration", animation.duration);
animationsTag.put("Animation" + index, animationTag);
}
animationsTag.putInt("Count", rewardTakeAnimations.size());
tag.put("RewardTakeAnimations", animationsTag);
}
private void loadRewardTakeAnimations(CompoundTag tag, HolderLookup.Provider registries) {
rewardTakeAnimations.clear();
if (!tag.contains("RewardTakeAnimations", Tag.TAG_COMPOUND)) {
return;
}
CompoundTag animationsTag = tag.getCompound("RewardTakeAnimations");
int count = animationsTag.getInt("Count");
for (int index = 0; index < count; index++) {
CompoundTag animationTag = animationsTag.getCompound("Animation" + index);
ItemStack stack = ItemStack.parseOptional(registries, animationTag.getCompound("Stack"));
if (stack.isEmpty()) {
continue;
}
rewardTakeAnimations.add(new RewardTakeAnimation(
stack,
animationTag.getFloat("LocalX"),
animationTag.getFloat("LocalZ"),
animationTag.getInt("Age"),
animationTag.getInt("Duration")));
}
}
private void saveAnimation(CompoundTag tag) { private void saveAnimation(CompoundTag tag) {
tag.putString("AnimationType", animationType.name()); tag.putString("AnimationType", animationType.name());
tag.putIntArray("AnimationSlots", animationSlots); tag.putIntArray("AnimationSlots", animationSlots);
@@ -672,4 +746,54 @@ public class DuelTableBlockEntity extends BlockEntity {
private record AnimationStep(AnimationType type, int[] slots, int targetOwner) { private record AnimationStep(AnimationType type, int[] slots, int targetOwner) {
} }
public static final class RewardTakeAnimation {
private final ItemStack stack;
private final float localX;
private final float localZ;
private int age;
private final int duration;
private RewardTakeAnimation(ItemStack stack, float localX, float localZ, int age, int duration) {
this.stack = stack;
this.localX = localX;
this.localZ = localZ;
this.age = age;
this.duration = duration;
}
public ItemStack stack() {
return stack;
}
public float localX() {
return localX;
}
public float localZ() {
return localZ;
}
public int age() {
return age;
}
public int duration() {
return duration;
}
}
private int visibleRewardIndex(int slot) {
int visibleIndex = 0;
for (int index = 0; index < rewardCards.size(); index++) {
if (rewardCards.get(index).isEmpty()) {
continue;
}
if (index == slot) {
return visibleIndex;
}
visibleIndex++;
}
return -1;
}
} }

View File

@@ -78,6 +78,7 @@ public class DuelTableBlockEntityRenderer implements BlockEntityRenderer<DuelTab
} }
renderRewardCards(blockEntity, partialTick, poseStack, buffer); renderRewardCards(blockEntity, partialTick, poseStack, buffer);
renderRewardTakeAnimations(blockEntity, partialTick, poseStack, buffer);
renderRewardProxyDebug(blockEntity, poseStack, buffer); renderRewardProxyDebug(blockEntity, poseStack, buffer);
} }
@@ -128,6 +129,33 @@ public class DuelTableBlockEntityRenderer implements BlockEntityRenderer<DuelTab
return Math.floorMod(blockEntity.getBlockPos().hashCode() * 31 + slot * 17, 97); return Math.floorMod(blockEntity.getBlockPos().hashCode() * 31 + slot * 17, 97);
} }
private static void renderRewardTakeAnimations(DuelTableBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource buffer) {
var facing = blockEntity.getBlockState().getValue(DuelTableBlock.FACING);
float forwardX = facing.getStepX() * 0.33F;
float forwardZ = facing.getStepZ() * 0.33F;
for (DuelTableBlockEntity.RewardTakeAnimation animation : blockEntity.rewardTakeAnimations()) {
float progress = Math.clamp((animation.age() + partialTick) / animation.duration(), 0.0F, 1.0F);
float riseProgress = Math.min(1.0F, progress / 0.45F);
float arcProgress = progress <= 0.45F ? 0.0F : (progress - 0.45F) / 0.55F;
float x = animation.localX() + forwardX * arcProgress;
float y = REWARD_CARD_Y
+ riseProgress * 0.26F
+ (float) Math.sin(arcProgress * Math.PI) * 0.08F
- arcProgress * 0.26F;
float z = animation.localZ() + forwardZ * arcProgress;
float spin = progress * 720.0F;
poseStack.pushPose();
poseStack.translate(x, y, z);
poseStack.mulPose(Axis.YP.rotationDegrees(facing.toYRot()));
poseStack.mulPose(Axis.YP.rotationDegrees(spin));
poseStack.scale(0.3F, 0.3F, 0.3F);
TriadCardItemRenderer.renderCard(animation.stack(), poseStack, buffer, perspectivePalette(blockEntity, DuelTableBlockEntity.OWNER_SECOND));
poseStack.popPose();
}
}
private static void renderRewardProxyDebug(DuelTableBlockEntity blockEntity, PoseStack poseStack, MultiBufferSource buffer) { private static void renderRewardProxyDebug(DuelTableBlockEntity blockEntity, PoseStack poseStack, MultiBufferSource buffer) {
if (Minecraft.getInstance().level == null) { if (Minecraft.getInstance().level == null) {
return; return;