Skip to content

Commit 2773d6d

Browse files
authored
Animations rework (#136)
* small commit * let nea handle open animation & remove animate argument for closePanel() * fix slot position * compat with the remaining nea animations * draw all backgrounds first, then widget & overlay together * typo * art * only resize widgets before rendering * fixes & animation for SortableListWidget * remove old animator * animated Expandable widget & jei exclusion helper * update * nea client only dep
1 parent 5dbc628 commit 2773d6d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1991
-392
lines changed

TODO.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
* [ ] Pie menu
99

1010
## High Priority
11+
1112
- [ ] merge animations with NEA
12-
- [ ] check JEI click interactions
13+
- [x] check JEI click interactions
1314

1415
## Medium Priority
1516

dependencies.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ dependencies {
2525
embed 'org.mariuszgromada.math:MathParser.org-mXparser:6.1.0'
2626

2727
implementation(rfg.deobf("curse.maven:baubles-227083:2518667"))
28+
implementation rfg.deobf("curse.maven:neverenoughanimation-1062347:6533650-sources-6533651")
29+
//implementation("com.cleanroommc:neverenoughanimations:1.0.6") { transitive false }
2830
}

src/main/java/com/cleanroommc/modularui/ClientProxy.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cleanroommc.modularui;
22

3+
import com.cleanroommc.modularui.animation.AnimatorManager;
34
import com.cleanroommc.modularui.drawable.DrawableSerialization;
45
import com.cleanroommc.modularui.factory.GuiFactories;
56
import com.cleanroommc.modularui.factory.inventory.InventoryTypes;
@@ -44,8 +45,8 @@ void preInit(FMLPreInitializationEvent event) {
4445
super.preInit(event);
4546

4647
MinecraftForge.EVENT_BUS.register(ClientScreenHandler.class);
47-
MinecraftForge.EVENT_BUS.register(OverlayManager.class);
4848
MinecraftForge.EVENT_BUS.register(KeyBindHandler.class);
49+
AnimatorManager.init();
4950

5051
if (ModularUIConfig.enableTestGuis) {
5152
MinecraftForge.EVENT_BUS.register(EventHandler.class);
@@ -75,7 +76,7 @@ void postInit(FMLPostInitializationEvent event) {
7576

7677
@SubscribeEvent
7778
public void onKeyboard(InputEvent.KeyInputEvent event) {
78-
if (testKey.isPressed() && ModularUI.isBaubleLoaded()) {
79+
if (ModularUIConfig.enableTestGuis && testKey.isPressed() && ModularUI.Mods.BAUBLES.isLoaded()) {
7980
InventoryTypes.BAUBLES.visitAll(Minecraft.getMinecraft().player, (type, index, stack) -> {
8081
if (stack.getItem() instanceof TestItem) {
8182
GuiFactories.playerInventory().openFromBaublesClient(index);

src/main/java/com/cleanroommc/modularui/ModularUI.java

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@
22

33
import net.minecraftforge.fml.common.Loader;
44
import net.minecraftforge.fml.common.Mod;
5+
import net.minecraftforge.fml.common.ModContainer;
56
import net.minecraftforge.fml.common.SidedProxy;
67
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
78
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
89
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
910

1011
import org.apache.logging.log4j.LogManager;
1112
import org.apache.logging.log4j.Logger;
13+
import org.jetbrains.annotations.Nullable;
1214
import org.mariuszgromada.math.mxparser.License;
1315

16+
import java.util.function.Predicate;
17+
1418
@Mod(modid = ModularUI.ID,
1519
name = ModularUI.NAME,
1620
version = ModularUI.VERSION,
1721
acceptedMinecraftVersions = "[1.12,)",
1822
dependencies = "required-after:mixinbooter@[8.0,);" +
19-
"after:bogorter@[1.4.0,);")
23+
"after:bogorter@[1.4.0,);" +
24+
"after-client:neverenoughanimations@[1.0.6,)")
2025
public class ModularUI {
2126

2227
public static final String ID = MuiTags.MODID;
@@ -35,22 +40,13 @@ public class ModularUI {
3540
@Mod.Instance
3641
public static ModularUI INSTANCE;
3742

38-
private static boolean blurLoaded = false;
39-
private static boolean sorterLoaded = false;
40-
private static boolean jeiLoaded = false;
41-
private static boolean baubleLoaded = false;
42-
4343
static {
4444
// confirm mXparser license
4545
License.iConfirmNonCommercialUse("CleanroomMC");
4646
}
4747

4848
@Mod.EventHandler
4949
public void preInit(FMLPreInitializationEvent event) {
50-
blurLoaded = Loader.isModLoaded("blur");
51-
sorterLoaded = Loader.isModLoaded(BOGO_SORT);
52-
jeiLoaded = Loader.isModLoaded("jei");
53-
baubleLoaded = Loader.isModLoaded("baubles");
5450
proxy.preInit(event);
5551
}
5652

@@ -64,19 +60,46 @@ public void onServerLoad(FMLServerStartingEvent event) {
6460
proxy.onServerLoad(event);
6561
}
6662

67-
public static boolean isBlurLoaded() {
68-
return blurLoaded;
63+
public enum Mods {
64+
65+
BAUBLES(ModIds.BAUBLES),
66+
BLUR(ModIds.BLUR),
67+
BOGOSORTER(ModIds.BOGOSORTER),
68+
JEI(ModIds.JEI),
69+
NEA(ModIds.NEA);
70+
71+
public final String id;
72+
private boolean loaded = false;
73+
private boolean initialized = false;
74+
private final Predicate<ModContainer> extraLoadedCheck;
75+
76+
Mods(String id) {
77+
this(id, null);
78+
}
79+
80+
Mods(String id, @Nullable Predicate<ModContainer> extraLoadedCheck) {
81+
this.id = id;
82+
this.extraLoadedCheck = extraLoadedCheck;
83+
}
84+
85+
public boolean isLoaded() {
86+
if (!this.initialized) {
87+
this.loaded = Loader.isModLoaded(this.id);
88+
if (this.loaded && this.extraLoadedCheck != null) {
89+
this.loaded = this.extraLoadedCheck.test(Loader.instance().getIndexedModList().get(this.id));
90+
}
91+
this.initialized = true;
92+
}
93+
return this.loaded;
94+
}
6995
}
7096

71-
public static boolean isSortModLoaded() {
72-
return sorterLoaded;
73-
}
74-
75-
public static boolean isJeiLoaded() {
76-
return jeiLoaded;
77-
}
97+
public static class ModIds {
7898

79-
public static boolean isBaubleLoaded() {
80-
return baubleLoaded;
99+
public static final String BLUR = "blur";
100+
public static final String BOGOSORTER = "bogosorter";
101+
public static final String JEI = "jei";
102+
public static final String NEA = "neverenoughanimations";
103+
public static final String BAUBLES = "baubles";
81104
}
82105
}
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
package com.cleanroommc.modularui.animation;
2+
3+
import com.cleanroommc.modularui.api.drawable.IInterpolation;
4+
import com.cleanroommc.modularui.utils.Interpolation;
5+
6+
import java.util.function.DoubleConsumer;
7+
import java.util.function.DoublePredicate;
8+
9+
public class Animator extends BaseAnimator implements IAnimator {
10+
11+
private float min = 0.0f;
12+
private float max = 1.0f;
13+
private int duration = 250;
14+
private IInterpolation curve = Interpolation.LINEAR;
15+
private boolean reverseOnFinish = false;
16+
private int repeats = 0;
17+
private DoublePredicate onUpdate;
18+
private Runnable onFinish;
19+
20+
private int progress = 0;
21+
private boolean startedReverse = false;
22+
private int repeated = 0;
23+
24+
@Override
25+
public void reset(boolean atEnd) {
26+
this.progress = atEnd ? this.duration : 0;
27+
this.startedReverse = atEnd;
28+
this.repeated = 0;
29+
}
30+
31+
@Override
32+
public void stop(boolean force) {
33+
if (isAnimating() && !force) {
34+
if (this.reverseOnFinish && this.startedReverse == isAnimatingReverse()) {
35+
onAnimationFinished(false, false);
36+
// started reverse -> bounce back and animate forward
37+
animate(isAnimatingForward());
38+
return;
39+
}
40+
if (repeats != 0 && (repeated < repeats || repeats < 0)) {
41+
onAnimationFinished(true, false);
42+
// started forward -> full cycle finished -> try repeating
43+
boolean reverse = !this.reverseOnFinish == isAnimatingReverse();
44+
animate(reverse);
45+
repeated++;
46+
return;
47+
}
48+
}
49+
super.stop(force);
50+
}
51+
52+
@Override
53+
public int advance(int elapsedTime) {
54+
if (!isAnimating()) return elapsedTime;
55+
while (elapsedTime > 0) {
56+
int max = isAnimatingForward() ? this.duration - this.progress : this.progress;
57+
int prog = Math.min(max, elapsedTime);
58+
this.progress += prog * getDirection();
59+
elapsedTime -= prog;
60+
if (onUpdate()) {
61+
stop(true);
62+
break;
63+
}
64+
if ((isAnimatingForward() && this.progress >= this.duration) || (isAnimatingReverse() && this.progress <= 0)) {
65+
stop(false);
66+
if (!isAnimating()) {
67+
onAnimationFinished(true, true);
68+
break;
69+
}
70+
}
71+
}
72+
return elapsedTime;
73+
}
74+
75+
protected boolean onUpdate() {
76+
return this.onUpdate != null && this.onUpdate.test(getRawValue());
77+
}
78+
79+
protected void onAnimationFinished(boolean finishedOneCycle, boolean finishedAllRepeats) {
80+
if (this.onFinish != null) {
81+
this.onFinish.run();
82+
}
83+
}
84+
85+
public boolean isAtEnd() {
86+
return this.progress >= this.duration;
87+
}
88+
89+
public boolean isAtStart() {
90+
return this.progress <= 0;
91+
}
92+
93+
public float getMin() {
94+
return min;
95+
}
96+
97+
public float getMax() {
98+
return max;
99+
}
100+
101+
public int getDuration() {
102+
return duration;
103+
}
104+
105+
public IInterpolation getCurve() {
106+
return curve;
107+
}
108+
109+
protected float getRawValue() {
110+
return this.curve.interpolate(this.min, this.max, (float) this.progress / this.duration);
111+
}
112+
113+
public float getValue() {
114+
//advance();
115+
return getRawValue();
116+
}
117+
118+
@Override
119+
public boolean hasProgressed() {
120+
if (!isAnimating()) return false;
121+
return isAnimatingForward() ? this.progress > 0 : this.progress < this.duration;
122+
}
123+
124+
/**
125+
* Sets the min bound of the value that will be interpolated.
126+
*
127+
* @param min min value
128+
* @return this
129+
*/
130+
public Animator min(float min) {
131+
this.min = min;
132+
return this;
133+
}
134+
135+
/**
136+
* Sets the max bound of the value that will be interpolated.
137+
*
138+
* @param max max value
139+
* @return this
140+
*/
141+
public Animator max(float max) {
142+
this.max = max;
143+
return this;
144+
}
145+
146+
/**
147+
* Sets the bounds of the value that will be interpolated.
148+
*
149+
* @param min min value
150+
* @param max max value
151+
* @return this
152+
*/
153+
public Animator bounds(float min, float max) {
154+
this.min = min;
155+
this.max = max;
156+
return this;
157+
}
158+
159+
/**
160+
* The duration of this animation in milliseconds. Note this is not 100% accurate.
161+
* Usually it's plus minus 2ms, but can rarely be more.
162+
*
163+
* @param duration duration in milliseconds
164+
* @return this
165+
*/
166+
public Animator duration(int duration) {
167+
this.duration = duration;
168+
return this;
169+
}
170+
171+
/**
172+
* Sets the interpolation curve, which is used to interpolate between the bounds.
173+
*
174+
* @param curve curve to interpolate on
175+
* @return this
176+
*/
177+
public Animator curve(IInterpolation curve) {
178+
this.curve = curve;
179+
return this;
180+
}
181+
182+
/**
183+
* Sets if the animation should reverse animate once after it finished.
184+
* If the animation started in reverse it will animate forward on finish.
185+
*
186+
* @param reverseOnFinish if animation should bounce back on finish
187+
* @return this
188+
*/
189+
public Animator reverseOnFinish(boolean reverseOnFinish) {
190+
this.reverseOnFinish = reverseOnFinish;
191+
return this;
192+
}
193+
194+
/**
195+
* Sets how often the animation should repeat. If {@link #reverseOnFinish(boolean)} is set to true, it will repeat the whole cycle.
196+
* If the number of repeats is negative, it will repeat infinitely.
197+
*
198+
* @param repeats how often the animation should repeat.
199+
* @return this
200+
*/
201+
public Animator repeatsOnFinish(int repeats) {
202+
this.repeats = repeats;
203+
return this;
204+
}
205+
206+
/**
207+
* Sets a function which is executed everytime the progress updates, that is on every frame.
208+
* The argument of the function is the interpolated value.
209+
*
210+
* @param onUpdate update function
211+
* @return this
212+
*/
213+
public Animator onUpdate(DoublePredicate onUpdate) {
214+
this.onUpdate = onUpdate;
215+
return this;
216+
}
217+
218+
/**
219+
* Sets a function which is executed everytime the progress updates, that is on every frame.
220+
* The argument of the function is the interpolated value.
221+
*
222+
* @param onUpdate update function
223+
* @return this
224+
*/
225+
public Animator onUpdate(DoubleConsumer onUpdate) {
226+
return onUpdate(val -> {
227+
onUpdate.accept(val);
228+
return false;
229+
});
230+
}
231+
232+
/**
233+
* Sets a function which is executed everytime, on animation, cycle or all repeats is finished.
234+
*
235+
* @param onFinish finish function
236+
* @return this
237+
*/
238+
public Animator onFinish(Runnable onFinish) {
239+
this.onFinish = onFinish;
240+
return this;
241+
}
242+
}

0 commit comments

Comments
 (0)