|
| 1 | +package com.minecrafttas.tasmod.mixin.tickrate; |
| 2 | + |
| 3 | +import org.spongepowered.asm.mixin.Mixin; |
| 4 | +import org.spongepowered.asm.mixin.Shadow; |
| 5 | +import org.spongepowered.asm.mixin.injection.At; |
| 6 | +import org.spongepowered.asm.mixin.injection.ModifyVariable; |
| 7 | + |
| 8 | +import com.minecrafttas.tasmod.TASmodClient; |
| 9 | + |
| 10 | +import net.minecraft.client.Minecraft; |
| 11 | + |
| 12 | +/** |
| 13 | + * This mixin tries to make the animation of the advancement toasts dependent on the tickrate while keeping the code as vanilla as possible<br> |
| 14 | + * <br> |
| 15 | + * While I spent a long amount of time watching this code, I still don't quite fully understand the math behind this...<br> |
| 16 | + * <br> |
| 17 | + * Here's what I could find out: Toasts have 2 different states represented in visibility in the ToastInstance.<br> |
| 18 | + * And if it's set to SHOW the fly in animation and sound will play, the same goes with HIDE where it flies out after a certain amount of time<br> |
| 19 | + * After a lot of trial and error I found out that animationTimer, which was originally "i", is the way to go...<br> |
| 20 | + * <br> |
| 21 | + * So just as RenderItem and GuiSubtitleOverlay, things are done with an offset for tickrate 0 and simple multiplication<br> |
| 22 | + * Also I used a copy of the vanilla ToastInstance-class to make it work for every subtitle on screen... If you seek to make it work for only 1, at the end is a commented code that shows you how to use @ModyfyVarable<br> |
| 23 | + * <br> |
| 24 | + * There is one compromise I had to make... When you change the tickrate while a toast is showing, it will stay at the old tickrate until it's done...<br> |
| 25 | + * Maybe I still fix this and get into this mess once more, but for now this will do and don't make the subtitles stuck in a loop until you change to the old tickrate<br> |
| 26 | + * Am I doing this right with commenting code? I hope so...<br> |
| 27 | + * <br> |
| 28 | + * Update 02.03.21:<br> |
| 29 | + * Well, it's been roughly a year since I have touched this code and I am finally back with updating this. And while I am at it, I removed that compromise mentioned earlier.<br> |
| 30 | + * |
| 31 | + * Update 26.03.26 Unease <br> |
| 32 | + * Reusing 5 year old code for legacy... how fitting |
| 33 | + * |
| 34 | + * @author Scribble |
| 35 | + * @author Unease |
| 36 | + */ |
| 37 | +@Mixin(targets = "net/minecraft/client/gui/toasts/GuiToast$ToastInstance") |
| 38 | +public abstract class MixinGuiToast { |
| 39 | + |
| 40 | + /** |
| 41 | + * Vanilla, current time in ms when the animationBegan. The delta between animationTimer and animation time shows the progress |
| 42 | + */ |
| 43 | + @Shadow |
| 44 | + private long animationTime; |
| 45 | + /** |
| 46 | + * Vanilla, the time the animation is visible. Used in the toast instances (e.g. AdvancementToast) to time their animation. Also used to set the visibility to HIDE and make the toast go away |
| 47 | + */ |
| 48 | + @Shadow |
| 49 | + private long visibleTime; |
| 50 | + |
| 51 | + /** |
| 52 | + * When entering tickrate 0, store is the (ms) time when tickrate 0 was activated. This time replaces the "animationTimer" during tickrate 0 |
| 53 | + */ |
| 54 | + private long store = 0L; |
| 55 | + /** |
| 56 | + * Makes sure the code runs only once when switching between tickrate 0 and not tickrate 0... I have yet to find a more elegant solution... |
| 57 | + */ |
| 58 | + private boolean once = false; |
| 59 | + /** |
| 60 | + * The offset of the ms time when using tickrate 0. This is used to "resume" the animation without any jumps, after exiting tickrate 0 |
| 61 | + */ |
| 62 | + private long offset = 0L; |
| 63 | + /** |
| 64 | + * When changing the tickrate while a toast is on screen, the {@link #animationTime} is not correct. The correct animationTime can be optained by subtracting the current time from this delta<br> |
| 65 | + */ |
| 66 | + private long animationDelta = 0L; |
| 67 | + /** |
| 68 | + * When changing the tickrate while a toast is on screen, the {@link #visibleTime} is not correct. The correct visibleTime can be optained by subtracting the current time from this delta<br> |
| 69 | + */ |
| 70 | + private long visibleDelta = 0L; |
| 71 | + /** |
| 72 | + * Used to detect a change in the tickrate and to run the code on. |
| 73 | + */ |
| 74 | + private float ticksave = TASmodClient.tickratechanger.ticksPerSecond; |
| 75 | + |
| 76 | + @ModifyVariable(method = "render(II)Z", at = @At(value = "STORE", ordinal = 0)) |
| 77 | + public long modifyAnimationTime(long animationTimer) { |
| 78 | + //===========TICKRATE OTHER THAN 0=========== |
| 79 | + if (TASmodClient.tickratechanger.ticksPerSecond != 0) { |
| 80 | + if (once) { |
| 81 | + once = false; |
| 82 | + offset = Minecraft.getSystemTime() - store; |
| 83 | + } |
| 84 | + |
| 85 | + animationTimer = (long) ((Minecraft.getSystemTime() - offset) * (TASmodClient.tickratechanger.ticksPerSecond / 20)); |
| 86 | + |
| 87 | + if (ticksave != TASmodClient.tickratechanger.ticksPerSecond) { |
| 88 | + ticksave = TASmodClient.tickratechanger.ticksPerSecond; |
| 89 | + animationTime = animationTimer - animationDelta; |
| 90 | + visibleTime = animationTimer - visibleDelta; |
| 91 | + } |
| 92 | + animationDelta = animationTimer - animationTime; |
| 93 | + visibleDelta = animationTimer - visibleTime; |
| 94 | + //===========TICKRATE 0=========== |
| 95 | + } else { |
| 96 | + if (!once) { |
| 97 | + once = true; |
| 98 | + store = (long) ((Minecraft.getSystemTime() - offset)); |
| 99 | + } |
| 100 | + animationTimer = (long) (store * (TASmodClient.tickratechanger.tickrateSaved / 20)); |
| 101 | + } |
| 102 | + return animationTimer; |
| 103 | + } |
| 104 | +} |
0 commit comments