diff --git a/build.gradle b/build.gradle
index 1e340af..0e1089b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id 'dev.architectury.loom' version '1.11-SNAPSHOT' apply false
+ id 'dev.architectury.loom' version '1.13.467' apply false
id 'architectury-plugin' version '3.4-SNAPSHOT'
id 'com.gradleup.shadow' version '8.3.6' apply false
}
diff --git a/common/src/main/java/net/weyne1/easegui/client/config/ScreenGroup.java b/common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenGroup.java
similarity index 77%
rename from common/src/main/java/net/weyne1/easegui/client/config/ScreenGroup.java
rename to common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenGroup.java
index 26963b7..b32afbd 100644
--- a/common/src/main/java/net/weyne1/easegui/client/config/ScreenGroup.java
+++ b/common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenGroup.java
@@ -1,6 +1,6 @@
-package net.weyne1.easegui.client.config;
+package net.weyne1.easegui.api;
-public enum ScreenGroup {
+public enum EaseGUIScreenGroup {
BASIC("easegui.screen_group.basic"),
EDITORS("easegui.screen_group.editors"),
WORLDS("easegui.screen_group.worlds"),
@@ -9,7 +9,7 @@ public enum ScreenGroup {
private final String translationKey;
- ScreenGroup(String translationKey) {
+ EaseGUIScreenGroup(String translationKey) {
this.translationKey = translationKey;
}
diff --git a/common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenRegistry.java b/common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenRegistry.java
new file mode 100644
index 0000000..86d07f5
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenRegistry.java
@@ -0,0 +1,243 @@
+package net.weyne1.easegui.api;
+
+import com.mojang.realmsclient.RealmsMainScreen;
+import net.minecraft.client.gui.screens.*;
+import net.minecraft.client.gui.screens.achievement.StatsScreen;
+import net.minecraft.client.gui.screens.advancements.AdvancementsScreen;
+import net.minecraft.client.gui.screens.inventory.*;
+import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen;
+import net.minecraft.client.gui.screens.multiplayer.ServerReconfigScreen;
+import net.minecraft.client.gui.screens.multiplayer.WarningScreen;
+import net.minecraft.client.gui.screens.options.OptionsScreen;
+import net.minecraft.client.gui.screens.options.OptionsSubScreen;
+import net.minecraft.client.gui.screens.packs.PackSelectionScreen;
+import net.minecraft.client.gui.screens.social.SocialInteractionsScreen;
+import net.minecraft.client.gui.screens.worldselection.*;
+import net.weyne1.easegui.api.animation.AnimationProfile;
+import net.weyne1.easegui.client.config.EaseGUIConfig;
+import net.weyne1.easegui.client.gui.screens.EaseGUIAbstractSplitScreen;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+/**
+ * Registry that maps Minecraft Screen classes to ScreenType definitions.
+ *
+ *
This is used by EaseGUI to decide how different screens should be categorized
+ * and animated. Matching works in two steps:
+ *
+ * - Fast exact class lookup (cache)
+ * - Fallback hierarchy scan using isAssignableFrom
+ *
+ *
+ * Mod developers can register custom screens and default animation parameters
+ * to integrate them into the EaseGUI animation system.
+ */
+public final class EaseGUIScreenRegistry {
+
+ private static final Map, EaseGUIScreenType> EXACT_MATCH_CACHE = new ConcurrentHashMap<>();
+ private static final Map> DEFAULT_CONFIGURATORS = new ConcurrentHashMap<>();
+ private static final List HIERARCHY_LIST = new ArrayList<>();
+
+ public static final EaseGUIScreenType OTHER = new EaseGUIScreenType("other", Screen.class, Integer.MIN_VALUE, EaseGUIScreenGroup.OTHER, false);
+
+ static {
+ // Vanilla UI screens
+ register("title", TitleScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("options", OptionsScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("options_sub", OptionsSubScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("pack_selection", PackSelectionScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("advancements", AdvancementsScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("statistics", StatsScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("warning", WarningScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("pause", PauseScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("share_to_lan", ShareToLanScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("death", DeathScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+ register("social_interactions", SocialInteractionsScreen.class, 1000, EaseGUIScreenGroup.BASIC);
+
+ // Editors
+ register("sign_edit", AbstractSignEditScreen.class, 1000, EaseGUIScreenGroup.EDITORS);
+ register("book_edit", BookEditScreen.class, 1000, EaseGUIScreenGroup.EDITORS);
+ register("book_view", BookViewScreen.class, 1000, EaseGUIScreenGroup.EDITORS);
+ register("command_block_edit", AbstractCommandBlockEditScreen.class, 1000, EaseGUIScreenGroup.EDITORS);
+ register("structure_block_edit", StructureBlockEditScreen.class, 1000, EaseGUIScreenGroup.EDITORS);
+ register("jigsaw_block_edit", JigsawBlockEditScreen.class, 1000, EaseGUIScreenGroup.EDITORS);
+
+ // World / multiplayer menus
+ register("world_selection", SelectWorldScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("server_selection", JoinMultiplayerScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("realms_main", RealmsMainScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("create_world", CreateWorldScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("create_flat_world", CreateFlatWorldScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("direct_join_server", DirectJoinServerScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("edit_world", EditWorldScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("edit_server", ManageServerScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("edit_game_rules", EditGameRulesScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("experiments", ExperimentsScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("connecting", ConnectScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("disconnected", DisconnectedScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("server_reconfig", ServerReconfigScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+ register("credits", CreditsAndAttributionScreen.class, 1000, EaseGUIScreenGroup.WORLDS);
+
+ // Containers / inventories
+ register("creative_inventory", CreativeModeInventoryScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("survival_inventory", InventoryScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("anvil", AnvilScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("enchanting_table", EnchantmentScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("container", ContainerScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("smithing", SmithingScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("dispenser", DispenserScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("beacon", BeaconScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("crafter", CrafterScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("crafting", CraftingScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("brewing_stand", BrewingStandScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("cartography_table", CartographyTableScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("furnace", AbstractFurnaceScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("grindstone", GrindstoneScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("hopper", HopperScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("horse_inventory", HorseInventoryScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("lectern", LecternScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("loom", LoomScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("shulker_box", ShulkerBoxScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("stonecutter", StonecutterScreen.class, 500, EaseGUIScreenGroup.CONTAINERS);
+ register("other_containers", AbstractContainerScreen.class, 100, EaseGUIScreenGroup.CONTAINERS);
+
+ // Internal config UI
+ register("ease_gui_config", EaseGUIAbstractSplitScreen.class, 100, EaseGUIScreenGroup.OTHER);
+
+ // Optional mod integration (Mod Menu)
+ try {
+ Class> modMenuScreenClass = Class.forName("com.terraformersmc.modmenu.gui.ModsScreen");
+ register("modmenu", modMenuScreenClass.asSubclass(Screen.class), 1000, EaseGUIScreenGroup.BASIC, false);
+ } catch (ClassNotFoundException ignored) {
+ // Mod Menu is not installed — safely skip registration
+ }
+ }
+
+ /**
+ * Registers a custom configurator callback for a specific screen ID.
+ * This is intended for third-party developers to populate custom default configurations.
+ *
+ * @param id the unique screen ID (e.g. "mymod:grinder")
+ * @param configurator the consumer that configures the default {@link EaseGUIConfig.ScreenSettings}
+ */
+ @SuppressWarnings("unused")
+ public static void registerConfigurator(String id, Consumer configurator) {
+ DEFAULT_CONFIGURATORS.put(id, configurator);
+ }
+
+ /**
+ * Configures the screen settings with registered developer defaults.
+ * Primarily called by the config factory during clean setup initialization.
+ *
+ * @param id the screen identifier
+ * @param settings the target settings to configure
+ */
+ public static void configureDefaults(String id, EaseGUIConfig.ScreenSettings settings) {
+ Consumer configurator = DEFAULT_CONFIGURATORS.get(id);
+ if (configurator != null) {
+ configurator.accept(settings);
+ }
+ }
+
+ /**
+ * Patches the existing screen settings with newly introduced developer defaults.
+ * Ensures that new categories or default entries are added safely without
+ * overwriting any manual modifications made by the user in the config file.
+ *
+ * @param id the screen identifier
+ * @param settings the user's existing settings
+ * @return true if the settings were modified and need to be saved
+ */
+ public static boolean patchDefaults(String id, EaseGUIConfig.ScreenSettings settings) {
+ Consumer configurator = DEFAULT_CONFIGURATORS.get(id);
+ if (configurator == null) return false;
+
+ EaseGUIConfig.ScreenSettings defaultSettings = new EaseGUIConfig.ScreenSettings();
+ configurator.accept(defaultSettings);
+
+ boolean changed = false;
+
+ for (Map.Entry entry : defaultSettings.customProfiles.entrySet()) {
+ if (!settings.customProfiles.containsKey(entry.getKey())) {
+ settings.customProfiles.put(entry.getKey(), entry.getValue());
+ changed = true;
+ }
+ }
+
+ return changed;
+ }
+
+ /**
+ * Registers a screen type with default enabled state (true).
+ */
+ public static synchronized void register(
+ String id,
+ Class extends Screen> screenClass,
+ int priority,
+ EaseGUIScreenGroup category
+ ) {
+ register(id, screenClass, priority, category, true);
+ }
+
+ /**
+ * Registers a screen type for animation classification.
+ *
+ * @param id unique identifier (e.g. "inventory" or "modid:screen")
+ * @param screenClass target screen class
+ * @param priority matching priority (higher = checked earlier)
+ * @param category logical grouping of screen type
+ * @param enabledByDefault whether this screen type is enabled on first config creation
+ */
+ public static synchronized void register(
+ String id,
+ Class extends Screen> screenClass,
+ int priority,
+ EaseGUIScreenGroup category,
+ boolean enabledByDefault
+ ) {
+ EaseGUIScreenType type = new EaseGUIScreenType(id, screenClass, priority, category, enabledByDefault);
+
+ EXACT_MATCH_CACHE.put(screenClass, type);
+
+ HIERARCHY_LIST.removeIf(t -> t.getId().equals(id));
+ HIERARCHY_LIST.add(type);
+ HIERARCHY_LIST.sort(Comparator.comparingInt(EaseGUIScreenType::getPriority).reversed());
+ }
+
+ /**
+ * Finds a ScreenType for a runtime screen instance.
+ *
+ * Resolution order:
+ *
+ * - Exact class match (fast path)
+ * - Assignable-from hierarchy scan
+ * - Fallback to OTHER
+ *
+ */
+ public static EaseGUIScreenType from(Screen screen) {
+ if (screen == null) return OTHER;
+
+ Class extends Screen> screenClass = screen.getClass();
+
+ EaseGUIScreenType exact = EXACT_MATCH_CACHE.get(screenClass);
+ if (exact != null) return exact;
+
+ for (EaseGUIScreenType type : HIERARCHY_LIST) {
+ if (type.getScreenClass().isAssignableFrom(screenClass)) {
+ EXACT_MATCH_CACHE.put(screenClass, type);
+ return type;
+ }
+ }
+
+ return OTHER;
+ }
+
+ /**
+ * Returns all registered screen types (read-only view).
+ */
+ public static Collection getRegisteredTypes() {
+ return Collections.unmodifiableList(HIERARCHY_LIST);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/config/ScreenType.java b/common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenType.java
similarity index 87%
rename from common/src/main/java/net/weyne1/easegui/client/config/ScreenType.java
rename to common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenType.java
index 4c12e7d..346bf9b 100644
--- a/common/src/main/java/net/weyne1/easegui/client/config/ScreenType.java
+++ b/common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenType.java
@@ -1,4 +1,4 @@
-package net.weyne1.easegui.client.config;
+package net.weyne1.easegui.api;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
@@ -17,13 +17,13 @@
* UI grouping
*
*/
-public final class ScreenType {
+public final class EaseGUIScreenType {
private final String id;
private final Class extends Screen> screenClass;
private final String translationKey;
private final int priority;
- private final ScreenGroup group;
+ private final EaseGUIScreenGroup group;
private final boolean enabledByDefault;
/**
@@ -35,11 +35,11 @@ public final class ScreenType {
* "modid:screen" → "modid.screen_type.screen"
*
*/
- public ScreenType(
+ public EaseGUIScreenType(
String id,
Class extends Screen> screenClass,
int priority,
- ScreenGroup group,
+ EaseGUIScreenGroup group,
boolean enabledByDefault
) {
this.id = id;
@@ -59,11 +59,12 @@ public ScreenType(
/**
* Creates a screen type enabled by default.
*/
- public ScreenType(
+ @SuppressWarnings("unused")
+ public EaseGUIScreenType(
String id,
Class extends Screen> screenClass,
int priority,
- ScreenGroup group
+ EaseGUIScreenGroup group
) {
this(id, screenClass, priority, group, true);
}
@@ -80,7 +81,7 @@ public int getPriority() {
return priority;
}
- public ScreenGroup getGroup() {
+ public EaseGUIScreenGroup getGroup() {
return group;
}
diff --git a/common/src/main/java/net/weyne1/easegui/api/WidgetCategory.java b/common/src/main/java/net/weyne1/easegui/api/WidgetCategory.java
new file mode 100644
index 0000000..d1f4309
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/api/WidgetCategory.java
@@ -0,0 +1,82 @@
+package net.weyne1.easegui.api;
+
+import net.minecraft.client.gui.components.*;
+import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
+import net.weyne1.easegui.client.config.ProfileFeature;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Represents the logical category of a UI element, defining which animation features
+ * are permitted and how classes map to these categories.
+ */
+public enum WidgetCategory {
+ BUTTON_LIKE(EnumSet.allOf(ProfileFeature.class)),
+ TEXT(EnumSet.of(ProfileFeature.OFFSET, ProfileFeature.SCALE, ProfileFeature.ALPHA, ProfileFeature.PIVOT)),
+ SCROLLABLE(EnumSet.of(ProfileFeature.OFFSET, ProfileFeature.SCALE, ProfileFeature.ALPHA)),
+ LIST_ENTRY(EnumSet.allOf(ProfileFeature.class)),
+ CONTAINERS(EnumSet.of(ProfileFeature.OFFSET, ProfileFeature.SCALE, ProfileFeature.ALPHA, ProfileFeature.PIVOT)),
+ UNKNOWN(EnumSet.noneOf(ProfileFeature.class));
+
+ private static final Map, WidgetCategory> CUSTOM_MAPPINGS = new ConcurrentHashMap<>();
+
+ private final EnumSet allowedFeatures;
+
+ WidgetCategory(EnumSet allowedFeatures) {
+ this.allowedFeatures = allowedFeatures;
+ }
+
+ public EnumSet getAllowedFeatures() {
+ return EnumSet.copyOf(this.allowedFeatures);
+ }
+
+ /**
+ * Registers a custom class mapping to a specific UI element category.
+ * This allows third-party mods with custom UI frameworks to support EaseGUI animations.
+ *
+ * @param clazz the target widget class to map
+ * @param category the category to assign to this class and its descendants
+ */
+ @SuppressWarnings("unused")
+ public static void registerMapping(@NotNull Class> clazz, @NotNull WidgetCategory category) {
+ CUSTOM_MAPPINGS.put(clazz, category);
+ }
+
+ /**
+ * Resolves a UIElementCategory for a given class type.
+ * Evaluates custom developer mappings first, then falls back to standard vanilla rules.
+ *
+ * @param clazz the class of the active UI element
+ * @return the matched category, or {@link #UNKNOWN} if no match is found
+ */
+ @NotNull
+ public static WidgetCategory fromClass(Class> clazz) {
+ if (clazz == null) return UNKNOWN;
+
+ for (Map.Entry, WidgetCategory> entry : CUSTOM_MAPPINGS.entrySet()) {
+ if (entry.getKey().isAssignableFrom(clazz)) {
+ return entry.getValue();
+ }
+ }
+
+ if (AbstractButton.class.isAssignableFrom(clazz) ||
+ AbstractSliderButton.class.isAssignableFrom(clazz) ||
+ EditBox.class.isAssignableFrom(clazz)) {
+ return BUTTON_LIKE;
+ }
+ if (AbstractStringWidget.class.isAssignableFrom(clazz)) {
+ return TEXT;
+ }
+ if (AbstractSelectionList.class.isAssignableFrom(clazz)) {
+ return SCROLLABLE;
+ }
+ if (AbstractContainerScreen.class.isAssignableFrom(clazz)) {
+ return CONTAINERS;
+ }
+
+ return UNKNOWN;
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/api/animation/AnimationProfile.java b/common/src/main/java/net/weyne1/easegui/api/animation/AnimationProfile.java
new file mode 100644
index 0000000..a0da75d
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/api/animation/AnimationProfile.java
@@ -0,0 +1,177 @@
+package net.weyne1.easegui.api.animation;
+
+import org.joml.Vector2f;
+
+/**
+ * Configuration profile holding animation properties and fluent builder methods.
+ */
+@SuppressWarnings({"unused", "UnusedReturnValue"})
+public class AnimationProfile {
+
+ private boolean enabled = true;
+ private long duration = 400;
+ private final Vector2f offset = new Vector2f();
+ private final Vector2f startScale = new Vector2f(1f, 1f);
+ private float startAlpha = 0.0f;
+ private long cascadeDelay = 0L;
+
+ private PivotPoint pivot = PivotPoint.CENTER;
+ private EasingType easing = EasingType.EASE_OUT_QUAD;
+ private CascadeDirection cascadeDirection = CascadeDirection.TOP_TO_BOTTOM;
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public float getOffsetX() {
+ return offset.x;
+ }
+
+ public float getOffsetY() {
+ return offset.y;
+ }
+
+ public float getStartScaleX() {
+ return startScale.x;
+ }
+
+ public float getStartScaleY() {
+ return startScale.y;
+ }
+
+ public float getStartAlpha() {
+ return startAlpha;
+ }
+
+ public long getCascadeDelay() {
+ return cascadeDelay;
+ }
+
+ public PivotPoint getPivot() {
+ return pivot;
+ }
+
+ public EasingType getEasing() {
+ return easing;
+ }
+
+ public CascadeDirection getCascadeDirection() {
+ return cascadeDirection;
+ }
+
+ public AnimationProfile enabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ public AnimationProfile duration(long duration) {
+ if (duration < 0) {
+ throw new IllegalArgumentException("Duration must be non-negative.");
+ }
+
+ this.duration = duration;
+ return this;
+ }
+
+ public AnimationProfile offset(float x, float y) {
+ this.offset.set(x, y);
+ return this;
+ }
+
+ public AnimationProfile offsetX(float x) {
+ this.offset.x = x;
+ return this;
+ }
+
+ public AnimationProfile offsetY(float y) {
+ this.offset.y = y;
+ return this;
+ }
+
+ public AnimationProfile startAlpha(float startAlpha) {
+ if (startAlpha < 0.0f || startAlpha > 1.0f) {
+ throw new IllegalArgumentException("Start alpha must be between 0.0 and 1.0.");
+ }
+
+ this.startAlpha = startAlpha;
+ return this;
+ }
+
+ public AnimationProfile startScale(float x, float y) {
+ this.startScale.set(x, y);
+ return this;
+ }
+
+ public AnimationProfile startScale(float scale) {
+ return startScale(scale, scale);
+ }
+
+ public AnimationProfile startScaleX(float x) {
+ this.startScale.x = x;
+ return this;
+ }
+
+ public AnimationProfile startScaleY(float y) {
+ this.startScale.y = y;
+ return this;
+ }
+
+ public AnimationProfile cascadeDelay(long cascadeDelay) {
+ if (cascadeDelay < 0) {
+ throw new IllegalArgumentException("Cascade delay must be non-negative.");
+ }
+
+ this.cascadeDelay = cascadeDelay;
+ return this;
+ }
+
+ public AnimationProfile pivot(PivotPoint pivot) {
+ if (pivot == null) {
+ throw new NullPointerException("Pivot point cannot be null.");
+ }
+
+ this.pivot = pivot;
+ return this;
+ }
+
+ public AnimationProfile easing(EasingType easing) {
+ if (easing == null) {
+ throw new NullPointerException("Easing type cannot be null.");
+ }
+
+ this.easing = easing;
+ return this;
+ }
+
+ public AnimationProfile cascadeDirection(CascadeDirection cascadeDirection) {
+ if (cascadeDirection == null) {
+ throw new NullPointerException("Cascade direction cannot be null.");
+ }
+
+ this.cascadeDirection = cascadeDirection;
+ return this;
+ }
+
+ /**
+ * Creates a deep copy of this animation profile.
+ */
+ public AnimationProfile copy() {
+ AnimationProfile copy = new AnimationProfile();
+
+ copy.enabled = this.enabled;
+ copy.duration = this.duration;
+ copy.offset.set(this.offset);
+ copy.startScale.set(this.startScale);
+ copy.startAlpha = this.startAlpha;
+ copy.cascadeDelay = this.cascadeDelay;
+ copy.pivot = this.pivot;
+ copy.easing = this.easing;
+ copy.cascadeDirection = this.cascadeDirection;
+
+ return copy;
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/api/animation/CascadeDirection.java b/common/src/main/java/net/weyne1/easegui/api/animation/CascadeDirection.java
new file mode 100644
index 0000000..ba8a36c
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/api/animation/CascadeDirection.java
@@ -0,0 +1,8 @@
+package net.weyne1.easegui.api.animation;
+
+public enum CascadeDirection {
+ TOP_TO_BOTTOM,
+ BOTTOM_TO_TOP,
+ LEFT_TO_RIGHT,
+ RIGHT_TO_LEFT
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/api/animation/EasingType.java b/common/src/main/java/net/weyne1/easegui/api/animation/EasingType.java
new file mode 100644
index 0000000..8c465f1
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/api/animation/EasingType.java
@@ -0,0 +1,65 @@
+package net.weyne1.easegui.api.animation;
+
+import net.weyne1.easegui.client.animation.EasingFunction;
+
+public enum EasingType {
+ LINEAR(t -> t),
+
+ EASE_IN_QUAD(t -> t * t),
+ EASE_OUT_QUAD(t -> 1f - (1f - t) * (1f - t)),
+ EASE_IN_OUT_QUAD(t -> t < 0.5f ? 2f * t * t : 1f - (float) Math.pow(-2f * t + 2f, 2) / 2f),
+
+ EASE_IN_CUBIC(t -> t * t * t),
+ EASE_OUT_CUBIC(t -> 1f - (float) Math.pow(1f - t, 3)),
+ EASE_IN_OUT_CUBIC(t -> t < 0.5f ? 4f * t * t * t : 1f - (float) Math.pow(-2f * t + 2f, 3) / 2f),
+
+ EASE_OUT_QUINT(t -> 1f - (float) Math.pow(1f - t, 5)),
+ EASE_OUT_EXPO(t -> t == 1f ? 1f : 1f - (float) Math.pow(2, -10f * t)),
+
+ EASE_IN_BACK(t -> {
+ float c1 = 1.70158f;
+ float c3 = c1 + 1f;
+ return c3 * t * t * t - c1 * t * t;
+ }),
+
+ EASE_OUT_BACK(t -> {
+ float c1 = 1.70158f;
+ float c3 = c1 + 1f;
+ return 1f + c3 * (float) Math.pow(t - 1f, 3) + c1 * (float) Math.pow(t - 1f, 2);
+ }),
+
+ EASE_OUT_ELASTIC(t -> {
+ if (t == 0f) return 0f;
+ if (t == 1f) return 1f;
+ float c4 = (2f * (float) Math.PI) / 3f;
+ return (float) Math.pow(2, -10f * t) * (float) Math.sin((t * 10f - 0.75f) * c4) + 1f;
+ }),
+
+ EASE_OUT_BOUNCE(t -> {
+ float n1 = 7.5625f;
+ float d1 = 2.75f;
+
+ if (t < 1f / d1) {
+ return n1 * t * t;
+ } else if (t < 2f / d1) {
+ float t2 = t - 1.5f / d1;
+ return n1 * t2 * t2 + 0.75f;
+ } else if (t < 2.5f / d1) {
+ float t2 = t - 2.25f / d1;
+ return n1 * t2 * t2 + 0.9375f;
+ } else {
+ float t2 = t - 2.625f / d1;
+ return n1 * t2 * t2 + 0.984375f;
+ }
+ });
+
+ private final EasingFunction function;
+
+ EasingType(EasingFunction function) {
+ this.function = function;
+ }
+
+ public float ease(float t) {
+ return function.apply(t);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/api/animation/PivotPoint.java b/common/src/main/java/net/weyne1/easegui/api/animation/PivotPoint.java
new file mode 100644
index 0000000..7958764
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/api/animation/PivotPoint.java
@@ -0,0 +1,29 @@
+package net.weyne1.easegui.api.animation;
+
+public enum PivotPoint {
+ TOP_LEFT(0.0f, 0.0f),
+ TOP_CENTER(0.5f, 0.0f),
+ TOP_RIGHT(1.0f, 0.0f),
+ CENTER_LEFT(0.0f, 0.5f),
+ CENTER(0.5f, 0.5f),
+ CENTER_RIGHT(1.0f, 0.5f),
+ BOTTOM_LEFT(0.0f, 1.0f),
+ BOTTOM_CENTER(0.5f, 1.0f),
+ BOTTOM_RIGHT(1.0f, 1.0f);
+
+ private final float xFactor;
+ private final float yFactor;
+
+ PivotPoint(float xFactor, float yFactor) {
+ this.xFactor = xFactor;
+ this.yFactor = yFactor;
+ }
+
+ public float getX(float x, float width) {
+ return x + (width * this.xFactor);
+ }
+
+ public float getY(float y, float height) {
+ return y + (height * this.yFactor);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/EaseGUIWidget.java b/common/src/main/java/net/weyne1/easegui/client/EaseGUIWidget.java
deleted file mode 100644
index e600718..0000000
--- a/common/src/main/java/net/weyne1/easegui/client/EaseGUIWidget.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.weyne1.easegui.client;
-
-import net.weyne1.easegui.client.config.UIElementCategory;
-
-public interface EaseGUIWidget {
- UIElementCategory easeGUI$getCategory();
-
- float easeGUI$getAlpha();
-}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/accessor/RecipeBookAccessor.java b/common/src/main/java/net/weyne1/easegui/client/accessor/RecipeBookAccessor.java
deleted file mode 100644
index 36939bd..0000000
--- a/common/src/main/java/net/weyne1/easegui/client/accessor/RecipeBookAccessor.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package net.weyne1.easegui.client.accessor;
-
-public interface RecipeBookAccessor {
- boolean easeGUI$isVisible();
- int easeGUI$getXOffset();
- int easeGUI$getBookWidth();
- int easeGUI$getBookHeight();
-}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/accessor/ScreenAnimationAccessor.java b/common/src/main/java/net/weyne1/easegui/client/accessor/ScreenAnimationAccessor.java
deleted file mode 100644
index e469b26..0000000
--- a/common/src/main/java/net/weyne1/easegui/client/accessor/ScreenAnimationAccessor.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.weyne1.easegui.client.accessor;
-
-import net.weyne1.easegui.client.animation.AnimationScope;
-
-public interface ScreenAnimationAccessor {
- AnimationScope easeGUI$getContainerScope();
-}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationContext.java b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationContext.java
index a3809f8..1018ce1 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationContext.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationContext.java
@@ -6,39 +6,54 @@
import java.util.Deque;
public final class AnimationContext {
- private static final Deque ALPHA_STACK = new ArrayDeque<>();
- private static int suspensionDepth = 0;
+ private static final Deque SCOPE_STACK = new ArrayDeque<>();
private static int parentAnimationDepth = 0;
- public static void pushAnimation(float alpha) {
- ALPHA_STACK.push(alpha);
+ public static void pushScope(AnimationScope scope) {
+ SCOPE_STACK.push(scope);
}
- public static void popAnimation() {
- if (!ALPHA_STACK.isEmpty()) {
- ALPHA_STACK.pop();
+ public static void popScope(AnimationScope scope) {
+ if (SCOPE_STACK.isEmpty()) {
+ EaseGUIDebug.reportError("scope_underflow", () -> "Attempt to close a scope when the stack is empty!");
+ return;
}
- }
- public static void suspend() {
- suspensionDepth++;
+ if (SCOPE_STACK.peek() == scope) {
+ SCOPE_STACK.pop();
+ } else {
+ EaseGUIDebug.reportError("scope_mismatch", () -> "Animation closing order violated! Attempted to close the wrong scope.");
+ }
}
- public static void resume() {
- if (suspensionDepth > 0) {
- suspensionDepth--;
- }
+ public static AnimationScope getCurrentScope() {
+ return SCOPE_STACK.peek();
}
- public static boolean isAnimating() {
- return suspensionDepth == 0 && !ALPHA_STACK.isEmpty();
+ public static boolean isActive() {
+ if (SCOPE_STACK.isEmpty()) return false;
+ for (AnimationScope scope : SCOPE_STACK) {
+ if (!scope.isSuspended()) return true;
+ }
+ return false;
}
public static float getCurrentAlpha() {
- if (suspensionDepth > 0 || ALPHA_STACK.isEmpty()) {
+ if (SCOPE_STACK.isEmpty()) {
return 1.0f;
}
- return ALPHA_STACK.peek();
+
+ float totalAlpha = 1.0f;
+ boolean hasActiveScope = false;
+
+ for (AnimationScope scope : SCOPE_STACK) {
+ if (!scope.isSuspended()) {
+ totalAlpha *= scope.getAlpha();
+ hasActiveScope = true;
+ }
+ }
+
+ return hasActiveScope ? totalAlpha : 1.0f;
}
public static void pushParentAnimation() {
@@ -59,8 +74,7 @@ public static boolean hasParentAnimation() {
}
public static void resetFrameState() {
- ALPHA_STACK.clear();
- suspensionDepth = 0;
+ SCOPE_STACK.clear();
parentAnimationDepth = 0;
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationMath.java b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationMath.java
index 21a38ea..6ad3b46 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationMath.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationMath.java
@@ -1,5 +1,7 @@
package net.weyne1.easegui.client.animation;
+import net.weyne1.easegui.api.animation.EasingType;
+
public final class AnimationMath {
private AnimationMath() { }
@@ -20,7 +22,7 @@ public static float calculateCurrentOffset(float baseOffset, float progress) {
public static float calculateProgress(
long elapsed,
long duration,
- AnimationProfile.EasingType easing
+ EasingType easing
) {
if (elapsed <= 0) return 0f;
if (elapsed >= duration) return 1f;
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationProfile.java b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationProfile.java
deleted file mode 100644
index 71b7585..0000000
--- a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationProfile.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package net.weyne1.easegui.client.animation;
-
-import org.joml.Vector2f;
-
-@SuppressWarnings("UnusedReturnValue")
-public class AnimationProfile {
- public boolean enabled = true;
- public long duration = 400;
- public final Vector2f offset = new Vector2f(0f, 0f);
- public final Vector2f startScale = new Vector2f(1f, 1f);
- public float startAlpha = 0.0f;
- public long cascadeDelay = 0L;
- public PivotPoint pivot = PivotPoint.CENTER;
- public EasingType easing = EasingType.EASE_OUT_QUAD;
- public CascadeDirection cascadeDirection = CascadeDirection.TOP_TO_BOTTOM;
-
- public AnimationProfile enabled(boolean enabled) { this.enabled = enabled; return this; }
- public AnimationProfile duration(long duration) { this.duration = duration; return this; }
- public AnimationProfile offset(float x, float y) { this.offset.set(x, y); return this; }
- public AnimationProfile offsetX(float x) { this.offset.x = x; return this; }
- public AnimationProfile offsetY(float y) { this.offset.y = y; return this; }
- public AnimationProfile startAlpha(float startAlpha) { this.startAlpha = startAlpha; return this; }
- public AnimationProfile startScale(float x, float y) { this.startScale.set(x, y); return this; }
- public AnimationProfile startScale(float scale) { this.startScale.set(scale, scale); return this; }
- public AnimationProfile startScaleX(float x) { this.startScale.x = x; return this; }
- public AnimationProfile startScaleY(float y) { this.startScale.y = y; return this; }
- public AnimationProfile cascadeDelay(long cascadeDelay) { this.cascadeDelay = cascadeDelay; return this; }
- public AnimationProfile pivot(PivotPoint pivot) { this.pivot = pivot; return this; }
- public AnimationProfile easing(EasingType easing) { this.easing = easing; return this; }
- public AnimationProfile cascadeDirection(CascadeDirection cascadeDirection) { this.cascadeDirection = cascadeDirection; return this; }
-
- @FunctionalInterface
- public interface EasingFunction {
- float apply(float t);
- }
-
- public enum PivotPoint {
- TOP_LEFT(0.0f, 0.0f), TOP_CENTER(0.5f, 0.0f), TOP_RIGHT(1.0f, 0.0f),
- CENTER_LEFT(0.0f, 0.5f), CENTER(0.5f, 0.5f), CENTER_RIGHT(1.0f, 0.5f),
- BOTTOM_LEFT(0.0f, 1.0f), BOTTOM_CENTER(0.5f, 1.0f), BOTTOM_RIGHT(1.0f, 1.0f);
-
- private final float xFactor;
- private final float yFactor;
-
- PivotPoint(float xFactor, float yFactor) {
- this.xFactor = xFactor;
- this.yFactor = yFactor;
- }
-
- public float getX(float x, float width) {
- return x + (width * this.xFactor);
- }
-
- public float getY(float y, float height) {
- return y + (height * this.yFactor);
- }
- }
-
- public enum EasingType {
- LINEAR(t -> t),
-
- EASE_IN_QUAD(t -> t * t),
- EASE_OUT_QUAD(t -> 1f - (1f - t) * (1f - t)),
- EASE_IN_OUT_QUAD(t -> t < 0.5f ? 2f * t * t : 1f - (float) Math.pow(-2f * t + 2f, 2) / 2f),
-
- EASE_IN_CUBIC(t -> t * t * t),
- EASE_OUT_CUBIC(t -> 1f - (float) Math.pow(1f - t, 3)),
- EASE_IN_OUT_CUBIC(t -> t < 0.5f ? 4f * t * t * t : 1f - (float) Math.pow(-2f * t + 2f, 3) / 2f),
-
- EASE_OUT_QUINT(t -> 1f - (float) Math.pow(1f - t, 5)),
-
- EASE_OUT_EXPO(t -> t == 1f ? 1f : 1f - (float) Math.pow(2, -10f * t)),
-
- EASE_IN_BACK(t -> {
- float c1 = 1.70158f;
- float c3 = c1 + 1f;
- return c3 * t * t * t - c1 * t * t;
- }),
-
- EASE_OUT_BACK(t -> {
- float c1 = 1.70158f;
- float c3 = c1 + 1f;
- return 1f + c3 * (float) Math.pow(t - 1f, 3) + c1 * (float) Math.pow(t - 1f, 2);
- }),
-
- EASE_OUT_ELASTIC(t -> {
- if (t == 0f) return 0f;
- if (t == 1f) return 1f;
- float c4 = (2f * (float) Math.PI) / 3f;
- return (float) Math.pow(2, -10f * t) * (float) Math.sin((t * 10f - 0.75f) * c4) + 1f;
- }),
-
- EASE_OUT_BOUNCE(t -> {
- float n1 = 7.5625f;
- float d1 = 2.75f;
-
- if (t < 1f / d1) {
- return n1 * t * t;
- } else if (t < 2f / d1) {
- float t2 = t - 1.5f / d1;
- return n1 * t2 * t2 + 0.75f;
- } else if (t < 2.5f / d1) {
- float t2 = t - 2.25f / d1;
- return n1 * t2 * t2 + 0.9375f;
- } else {
- float t2 = t - 2.625f / d1;
- return n1 * t2 * t2 + 0.984375f;
- }
- });
-
- private final EasingFunction function;
-
- EasingType(EasingFunction function) {
- this.function = function;
- }
-
- public float ease(float t) {
- return function.apply(t);
- }
- }
-
- public enum CascadeDirection {
- TOP_TO_BOTTOM,
- BOTTOM_TO_TOP,
- LEFT_TO_RIGHT,
- RIGHT_TO_LEFT
- }
-}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationScope.java b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationScope.java
index 72ceb7c..a0d5c29 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationScope.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationScope.java
@@ -2,11 +2,13 @@
import net.minecraft.client.gui.GuiGraphics;
import net.weyne1.easegui.client.EaseGUIDebug;
+import org.joml.Matrix3x2fStack;
public final class AnimationScope implements AutoCloseable {
private static final float MIN_SCALE = 0.001f;
private final GuiGraphics guiGraphics;
+ private final float alpha;
private boolean isClosed = false;
private boolean isSuspended = false;
@@ -15,11 +17,32 @@ public final class AnimationScope implements AutoCloseable {
private float scaleX = 1.0f, scaleY = 1.0f;
private float pivotX, pivotY;
+ public float getOffsetX() { return offsetX; }
+ public float getOffsetY() { return offsetY; }
+
+ public float getScaleX() { return scaleX; }
+ public float getScaleY() { return scaleY; }
+
+ public float getPivotX() { return pivotX; }
+ public float getPivotY() { return pivotY; }
+
+ public float getAlpha() {
+ return alpha;
+ }
+
+ public boolean isClosed() {
+ return isClosed;
+ }
+ public boolean isSuspended() {
+ return isSuspended;
+ }
+
public AnimationScope(GuiGraphics guiGraphics, float alpha) {
this.guiGraphics = guiGraphics;
- this.guiGraphics.flush();
- AnimationContext.pushAnimation(alpha);
- this.guiGraphics.pose().pushPose();
+ this.alpha = alpha;
+
+ AnimationContext.pushScope(this);
+ this.guiGraphics.pose().pushMatrix();
}
public void setTransformParams(float offsetX, float offsetY, float scaleX, float scaleY, float pivotX, float pivotY) {
@@ -30,29 +53,29 @@ public void setTransformParams(float offsetX, float offsetY, float scaleX, float
this.pivotX = pivotX;
this.pivotY = pivotY;
+ Matrix3x2fStack poseStack = guiGraphics.pose();
+
if (this.scaleX != 1.0f || this.scaleY != 1.0f) {
- guiGraphics.pose().translate(offsetX + pivotX, offsetY + pivotY, 0.0f);
- guiGraphics.pose().scale(this.scaleX, this.scaleY, 1.0f);
- guiGraphics.pose().translate(-pivotX, -pivotY, 0.0f);
+ poseStack.translate(offsetX + pivotX, offsetY + pivotY);
+ poseStack.scale(this.scaleX, this.scaleY);
+ poseStack.translate(-pivotX, -pivotY);
} else {
- guiGraphics.pose().translate(offsetX, offsetY, 0.0f);
+ poseStack.translate(offsetX, offsetY);
}
}
public void suspend() {
if (isClosed || isSuspended) return;
- this.guiGraphics.flush();
- AnimationContext.suspend();
-
- guiGraphics.pose().pushPose();
+ Matrix3x2fStack poseStack = guiGraphics.pose();
+ poseStack.pushMatrix();
if (scaleX != 1.0f || scaleY != 1.0f) {
- guiGraphics.pose().translate(pivotX, pivotY, 0.0f);
- guiGraphics.pose().scale(1.0f / scaleX, 1.0f / scaleY, 1.0f);
- guiGraphics.pose().translate(-(offsetX + pivotX), -(offsetY + pivotY), 0.0f);
+ poseStack.translate(pivotX, pivotY);
+ poseStack.scale(1.0f / scaleX, 1.0f / scaleY);
+ poseStack.translate(-(offsetX + pivotX), -(offsetY + pivotY));
} else {
- guiGraphics.pose().translate(-offsetX, -offsetY, 0.0f);
+ poseStack.translate(-offsetX, -offsetY);
}
isSuspended = true;
@@ -61,9 +84,7 @@ public void suspend() {
public void resume() {
if (isClosed || !isSuspended) return;
- this.guiGraphics.flush();
- guiGraphics.pose().popPose();
- AnimationContext.resume();
+ guiGraphics.pose().popMatrix();
isSuspended = false;
}
@@ -73,25 +94,18 @@ public void close() {
if (isClosed) return;
isClosed = true;
- this.guiGraphics.flush();
-
if (isSuspended) {
- guiGraphics.pose().popPose();
- AnimationContext.resume();
+ guiGraphics.pose().popMatrix();
isSuspended = false;
}
try {
- guiGraphics.pose().popPose();
+ guiGraphics.pose().popMatrix();
} catch (IllegalStateException e) {
EaseGUIDebug.reportError("pose_stack_underflow", () -> "PoseStack underflow inside AnimationScope close!");
}
- AnimationContext.popAnimation();
- }
-
- public boolean isClosed() {
- return isClosed;
+ AnimationContext.popScope(this);
}
private static float clampScale(float scale) {
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationState.java b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationState.java
index 378b817..4be2f5a 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationState.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationState.java
@@ -1,11 +1,8 @@
package net.weyne1.easegui.client.animation;
-public class AnimationState {
-
- public static final class AnimationData {
- public long startTime = -1;
- public long delay = 0;
- public boolean init = false;
- public int lastRenderFrame = -1;
- }
+public final class AnimationState {
+ public long startTime = -1;
+ public long delay = 0;
+ public boolean init = false;
+ public int lastRenderFrame = -1;
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationSystem.java b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationSystem.java
index a6ed5e0..317da5b 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animation/AnimationSystem.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animation/AnimationSystem.java
@@ -1,9 +1,33 @@
package net.weyne1.easegui.client.animation;
import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.util.Util;
+import net.weyne1.easegui.api.animation.AnimationProfile;
public final class AnimationSystem {
+ /**
+ * An entry point for animations with automatic timing and progress calculation.
+ */
+ public static AnimationScope begin(
+ GuiGraphics gg,
+ int x, int y, int width, int height,
+ AnimationProfile profile,
+ long startTime,
+ long delay,
+ float baseAlpha
+ ) {
+ long elapsed = Util.getMillis() - startTime - delay;
+
+ if (elapsed >= profile.getDuration()) {
+ return null;
+ }
+
+ float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.getDuration(), profile.getEasing());
+
+ return begin(gg, x, y, width, height, profile, progress, baseAlpha);
+ }
+
public static AnimationScope begin(
GuiGraphics gg,
int x, int y, int width, int height,
@@ -12,17 +36,17 @@ public static AnimationScope begin(
float baseAlpha
) {
float alphaProgress = AnimationMath.clamp(progress, 0.0f, 1.0f);
- float lerpedAlpha = AnimationMath.lerp(profile.startAlpha, 1.0f, alphaProgress);
+ float lerpedAlpha = AnimationMath.lerp(profile.getStartAlpha(), 1.0f, alphaProgress);
float finalAlpha = AnimationMath.clamp(baseAlpha * lerpedAlpha, 0.0f, 1.0f);
AnimationScope scope = new AnimationScope(gg, finalAlpha);
scope.setTransformParams(
- AnimationMath.calculateCurrentOffset(profile.offset.x, progress),
- AnimationMath.calculateCurrentOffset(profile.offset.y, progress),
- AnimationMath.lerp(profile.startScale.x, 1.0f, progress),
- AnimationMath.lerp(profile.startScale.y, 1.0f, progress),
- profile.pivot.getX(x, width),
- profile.pivot.getY(y, height)
+ AnimationMath.calculateCurrentOffset(profile.getOffsetX(), progress),
+ AnimationMath.calculateCurrentOffset(profile.getOffsetY(), progress),
+ AnimationMath.lerp(profile.getStartScaleX(), 1.0f, progress),
+ AnimationMath.lerp(profile.getStartScaleY(), 1.0f, progress),
+ profile.getPivot().getX(x, width),
+ profile.getPivot().getY(y, height)
);
return scope;
}
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/EasingFunction.java b/common/src/main/java/net/weyne1/easegui/client/animation/EasingFunction.java
new file mode 100644
index 0000000..0f4af49
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/animation/EasingFunction.java
@@ -0,0 +1,6 @@
+package net.weyne1.easegui.client.animation;
+
+@FunctionalInterface
+public interface EasingFunction {
+ float apply(float t);
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animation/PipTransform.java b/common/src/main/java/net/weyne1/easegui/client/animation/PipTransform.java
new file mode 100644
index 0000000..9e83dd2
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/animation/PipTransform.java
@@ -0,0 +1,52 @@
+package net.weyne1.easegui.client.animation;
+
+/**
+ * Utility for applying UI animation transformations (scale, offset)
+ * to Minecraft's Picture-in-Picture (PiP) render states.
+ *
+ * Used to smoothly animate 3D models (skins, books, banners, etc.)
+ * relative to the current {@link AnimationScope} pivot.
+ */
+public final class PipTransform {
+ private PipTransform() {}
+
+ private static final int MIN_SIZE = 1;
+
+ public static int[] transformRangeX(int x0, int x1) {
+ return transformRange(x0, x1, true);
+ }
+
+ public static int[] transformRangeY(int y0, int y1) {
+ return transformRange(y0, y1, false);
+ }
+
+ private static int[] transformRange(int start, int end, boolean horizontal) {
+ AnimationScope scope = AnimationContext.getCurrentScope();
+ if (scope == null || scope.isSuspended()) {
+ return new int[]{start, end};
+ }
+
+ float pivot = horizontal ? scope.getPivotX() : scope.getPivotY();
+ float offset = horizontal ? scope.getOffsetX() : scope.getOffsetY();
+ float scale = horizontal ? scope.getScaleX() : scope.getScaleY();
+
+ float newStart = pivot + offset + (start - pivot) * scale;
+ float newEnd = pivot + offset + (end - pivot) * scale;
+
+ int roundedStart = Math.round(newStart);
+ int roundedEnd = Math.round(newEnd);
+
+ if (Math.abs(roundedEnd - roundedStart) < MIN_SIZE) {
+ int sign = (newEnd >= newStart) ? 1 : -1;
+ roundedEnd = roundedStart + sign * MIN_SIZE;
+ }
+
+ return new int[]{roundedStart, roundedEnd};
+ }
+
+ public static float scale(float scale) {
+ AnimationScope scope = AnimationContext.getCurrentScope();
+ if (scope == null || scope.isSuspended()) return scale;
+ return scale * (scope.getScaleX() + scope.getScaleY()) * 0.5f;
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animator/AdvancementsAnimator.java b/common/src/main/java/net/weyne1/easegui/client/animator/AdvancementsAnimator.java
index c540cfb..e745b49 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animator/AdvancementsAnimator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animator/AdvancementsAnimator.java
@@ -1,6 +1,6 @@
package net.weyne1.easegui.client.animator;
-import net.minecraft.Util;
+import net.minecraft.util.Util;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.advancements.AdvancementsScreen;
@@ -9,22 +9,17 @@
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animation.AnimationSystem;
import net.weyne1.easegui.client.config.ConfigManager;
-import net.weyne1.easegui.client.config.EaseGUIScreenRegistry;
-import net.weyne1.easegui.client.config.ScreenType;
+import net.weyne1.easegui.api.EaseGUIScreenRegistry;
+import net.weyne1.easegui.api.EaseGUIScreenType;
import net.weyne1.easegui.client.state.ScreenStateTracker;
public class AdvancementsAnimator {
- /**
- * Starts the animation.
- *
- * @return an {@link AnimationScope} that must be closed, or {@code null} if no animation is needed
- */
public static AnimationScope beginRenderWindow(AdvancementsScreen screen, GuiGraphics gg) {
- ScreenType type = EaseGUIScreenRegistry.from(screen);
+ EaseGUIScreenType type = EaseGUIScreenRegistry.from(screen);
var titleSettings = ConfigManager.getConfig().screens.get(type.getId());
- if (titleSettings == null || !titleSettings.enabled || titleSettings.advancements == null || !titleSettings.advancements.windowProfile.enabled) {
+ if (titleSettings == null || !titleSettings.enabled || titleSettings.advancements == null || !titleSettings.advancements.windowProfile.isEnabled()) {
return null;
}
@@ -32,23 +27,18 @@ public static AnimationScope beginRenderWindow(AdvancementsScreen screen, GuiGra
long startTime = ScreenStateTracker.getScreenOpenTime();
long elapsed = Util.getMillis() - startTime;
- if (elapsed >= profile.duration) return null;
+ if (elapsed >= profile.getDuration()) return null;
- float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
+ float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.getDuration(), profile.getEasing());
return AnimationSystem.begin(gg, 0, 0, screen.width, screen.height, profile, progress, 1.0f);
}
- /**
- * Starts the animation.
- *
- * @return an {@link AnimationScope} that must be closed, or {@code null} if no animation is needed
- */
public static AnimationScope beginRenderTab(Screen screen, GuiGraphics gg, int tabIndex) {
- ScreenType type = EaseGUIScreenRegistry.from(screen);
+ EaseGUIScreenType type = EaseGUIScreenRegistry.from(screen);
var titleSettings = ConfigManager.getConfig().screens.get(type.getId());
- if (titleSettings == null || !titleSettings.enabled || titleSettings.advancements == null || !titleSettings.advancements.tabsProfile.enabled) {
+ if (titleSettings == null || !titleSettings.enabled || titleSettings.advancements == null || !titleSettings.advancements.tabsProfile.isEnabled()) {
return null;
}
@@ -60,15 +50,15 @@ public static AnimationScope beginRenderTab(Screen screen, GuiGraphics gg, int t
var profile = titleSettings.advancements.tabsProfile;
long startTime = ScreenStateTracker.getScreenOpenTime();
- long tabDelay = tabIndex * profile.cascadeDelay;
+ long tabDelay = tabIndex * profile.getCascadeDelay();
long elapsed = Util.getMillis() - startTime - tabDelay;
- if (elapsed >= profile.duration) return null;
+ if (elapsed >= profile.getDuration()) return null;
float progress = 0.0f;
if (elapsed > 0) {
- progress = AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
+ progress = AnimationMath.calculateProgress(elapsed, profile.getDuration(), profile.getEasing());
}
return AnimationSystem.begin(gg, 0, 0, 28, 32, profile, progress, parentAlpha);
diff --git a/common/src/main/java/net/weyne1/easegui/client/animator/BackgroundAnimator.java b/common/src/main/java/net/weyne1/easegui/client/animator/BackgroundAnimator.java
index 5e41d12..3db1d5e 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animator/BackgroundAnimator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animator/BackgroundAnimator.java
@@ -1,36 +1,40 @@
package net.weyne1.easegui.client.animator;
-import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.*;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animation.AnimationSystem;
import net.weyne1.easegui.client.config.ConfigManager;
import net.weyne1.easegui.client.config.EaseGUIConfig;
-import net.weyne1.easegui.client.config.EaseGUIScreenRegistry;
-import net.weyne1.easegui.client.config.ScreenType;
+import net.weyne1.easegui.api.EaseGUIScreenRegistry;
+import net.weyne1.easegui.api.EaseGUIScreenType;
import net.weyne1.easegui.client.state.ScreenAnimationTracker;
import net.weyne1.easegui.client.state.ScreenStateTracker;
-/**
- * Handles background fade animations.
- */
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
public class BackgroundAnimator {
public static boolean skipBackgroundFade = false;
- public static boolean isLoadingScreen(Screen screen) {
- return screen instanceof LevelLoadingScreen
- || screen instanceof ProgressScreen
- || screen instanceof ConnectScreen
- || screen instanceof ReceivingLevelScreen
- || screen instanceof GenericWaitingScreen
- || screen instanceof BackupConfirmScreen;
+ private static final Set> IGNORED_SCREEN_CLASSES = ConcurrentHashMap.newKeySet();
+
+ static {
+ IGNORED_SCREEN_CLASSES.add(TitleScreen.class);
+ IGNORED_SCREEN_CLASSES.add(LevelLoadingScreen.class);
+ IGNORED_SCREEN_CLASSES.add(ProgressScreen.class);
+ IGNORED_SCREEN_CLASSES.add(ConnectScreen.class);
+ IGNORED_SCREEN_CLASSES.add(GenericWaitingScreen.class);
+ IGNORED_SCREEN_CLASSES.add(BackupConfirmScreen.class);
+ }
+
+ @SuppressWarnings("unused")
+ public static void registerIgnoredScreen(Class extends Screen> screenClass) {
+ IGNORED_SCREEN_CLASSES.add(screenClass);
}
- public static boolean isScreenBlurred(Screen screen) {
- if (screen == null
- || screen instanceof TitleScreen
- || isLoadingScreen(screen)) {
+ public static boolean shouldAnimateBackground(Screen screen) {
+ if (screen == null || isIgnoredScreen(screen)) {
return false;
}
@@ -38,7 +42,7 @@ public static boolean isScreenBlurred(Screen screen) {
if (!config.global.enableSmoothBlur) return false;
try {
- ScreenType screenType = EaseGUIScreenRegistry.from(screen);
+ EaseGUIScreenType screenType = EaseGUIScreenRegistry.from(screen);
if (screenType == null) return true;
EaseGUIConfig.ScreenSettings screenSettings = config.screens.get(screenType.getId());
@@ -48,15 +52,8 @@ public static boolean isScreenBlurred(Screen screen) {
}
}
- public static boolean shouldAnimate() {
- return isScreenBlurred(Minecraft.getInstance().screen);
- }
-
- /**
- * Returns whether background animations are enabled.
- */
- public static int getAnimatedColor(int originalColor) {
- if (!shouldAnimate() || skipBackgroundFade) {
+ public static int getAnimatedColor(Screen screen, int originalColor) {
+ if (!shouldAnimateBackground(screen) || skipBackgroundFade) {
return originalColor;
}
@@ -73,13 +70,10 @@ public static int getAnimatedColor(int originalColor) {
return (originalColor & 0x00FFFFFF) | (finalAlpha << 24);
}
- /**
- * Starts the animation.
- *
- * @return an {@link AnimationScope} that must be closed, or {@code null} if no animation is needed
- */
- public static AnimationScope beginRenderMenu(GuiGraphics gg) {
- if (!shouldAnimate() || skipBackgroundFade) return null;
+ public static AnimationScope beginRenderMenu(Screen screen, GuiGraphics gg) {
+ if (!shouldAnimateBackground(screen) || skipBackgroundFade) {
+ return null;
+ }
long elapsed = ScreenStateTracker.getScreenElapsed();
long duration = ConfigManager.getConfig().global.blurDuration;
@@ -90,4 +84,14 @@ public static AnimationScope beginRenderMenu(GuiGraphics gg) {
float progress = Math.max(0.0f, Math.min(1.0f, ScreenAnimationTracker.getProgress()));
return AnimationSystem.beginAlphaOnly(gg, progress);
}
+
+ private static boolean isIgnoredScreen(Screen screen) {
+ Class extends Screen> screenClass = screen.getClass();
+ for (Class extends Screen> ignored : IGNORED_SCREEN_CLASSES) {
+ if (ignored.isAssignableFrom(screenClass)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animator/ContainerAnimator.java b/common/src/main/java/net/weyne1/easegui/client/animator/ContainerAnimator.java
index 0fae467..7ce80a1 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animator/ContainerAnimator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animator/ContainerAnimator.java
@@ -1,29 +1,21 @@
package net.weyne1.easegui.client.animator;
-import net.minecraft.Util;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
-import net.minecraft.client.gui.screens.recipebook.RecipeUpdateListener;
-import net.weyne1.easegui.client.accessor.ContainerScreenAccessor;
-import net.weyne1.easegui.client.accessor.RecipeBookAccessor;
-import net.weyne1.easegui.client.animation.AnimationContext;
-import net.weyne1.easegui.client.animation.AnimationMath;
+import net.weyne1.easegui.client.extension.ContainerScreenExtension;
+import net.weyne1.easegui.client.extension.RecipeBookComponentExtension;
+import net.weyne1.easegui.client.extension.RecipeBookScreenExtension;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animation.AnimationSystem;
import net.weyne1.easegui.client.config.ConfigManager;
-import net.weyne1.easegui.client.config.UIElementCategory;
+import net.weyne1.easegui.api.WidgetCategory;
import net.weyne1.easegui.client.state.ScreenStateTracker;
public class ContainerAnimator {
- /**
- * Evaluates container bounds (integrating the Recipe Book if open) and instantiates
- * a localized context-aware AnimationScope.
- *
- * @return a new {@link AnimationScope} mapped to the screen matrix, or {@code null} if transitions are disabled
- */
- public static AnimationScope beginScreenAnimation(Screen screen, GuiGraphics gg) {
- if (!(screen instanceof ContainerScreenAccessor container)) {
+
+ public static AnimationScope beginAnimation(Screen screen, GuiGraphics gg) {
+ if (!(screen instanceof ContainerScreenExtension container)) {
return null;
}
@@ -32,67 +24,21 @@ public static AnimationScope beginScreenAnimation(Screen screen, GuiGraphics gg)
int maxX = minX + container.easeGUI$getImageWidth();
int maxY = minY + container.easeGUI$getImageHeight();
- if (screen instanceof RecipeUpdateListener listener) {
- RecipeBookComponent book = listener.getRecipeBookComponent();
-
- if (((RecipeBookAccessor) book).easeGUI$isVisible()) {
- RecipeBookAccessor accessor = (RecipeBookAccessor) book;
-
- int bookWidth = accessor.easeGUI$getBookWidth();
- int bookHeight = accessor.easeGUI$getBookHeight();
-
- int bookX = (screen.width - bookWidth) / 2 - accessor.easeGUI$getXOffset();
- int bookY = (screen.height - bookHeight) / 2;
-
- minX = Math.min(minX, bookX);
- minY = Math.min(minY, bookY);
- maxX = Math.max(maxX, bookX + bookWidth);
- maxY = Math.max(maxY, bookY + bookHeight);
+ if (screen instanceof RecipeBookScreenExtension recipeScreen) {
+ RecipeBookComponent> book = recipeScreen.easeGUI$getRecipeBookComponent();
+ if (book != null && ((RecipeBookComponentExtension) book).easeGUI$isVisible()) {
+ RecipeBookComponentExtension accessor = (RecipeBookComponentExtension) book;
+ minX = Math.min(minX, accessor.easeGUI$getXOrigin());
+ minY = Math.min(minY, accessor.easeGUI$getYOrigin());
+ maxX = Math.max(maxX, accessor.easeGUI$getXOrigin() + RecipeBookComponent.IMAGE_WIDTH);
+ maxY = Math.max(maxY, accessor.easeGUI$getYOrigin() + RecipeBookComponent.IMAGE_HEIGHT);
}
}
- AnimationScope scope = beginAnimation(gg, minX, minY, maxX - minX, maxY - minY);
- if (scope != null) {
- AnimationContext.pushParentAnimation();
- }
- return scope;
- }
-
- /**
- * Safely closes the provided animation scope and cleanly balances the global animation context depth.
- *
- * @param scope Target scope to dissolve
- */
- public static void closeScope(AnimationScope scope) {
- if (scope != null) {
- try {
- if (!scope.isClosed()) {
- scope.close();
- }
- } finally {
- if (AnimationContext.hasParentAnimation()) {
- AnimationContext.popParentAnimation();
- }
- }
- }
- }
-
- /**
- * Looks up user configurations and computes tween progress mapping to generate the core AnimationScope.
- *
- * @return an active {@link AnimationScope} or {@code null} if config conditions are unmet or duration expired
- */
- public static AnimationScope beginAnimation(GuiGraphics gg, int x, int y, int width, int height) {
- var profile = ConfigManager.getProfileForCurrentContext(UIElementCategory.CONTAINERS);
- if (profile == null || !profile.enabled) return null;
+ var profile = ConfigManager.getProfileForCurrentContext(WidgetCategory.CONTAINERS);
+ if (profile == null || !profile.isEnabled()) return null;
long startTime = ScreenStateTracker.getScreenOpenTime();
- long elapsed = Util.getMillis() - startTime;
-
- if (elapsed >= profile.duration) return null;
-
- float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
-
- return AnimationSystem.begin(gg, x, y, width, height, profile, progress, 1.0f);
+ return AnimationSystem.begin(gg, minX, minY, maxX - minX, maxY - minY, profile, startTime, 0L, 1.0f);
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animator/ListItemAnimator.java b/common/src/main/java/net/weyne1/easegui/client/animator/ListItemAnimator.java
index 093e3e4..c4c10be 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animator/ListItemAnimator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animator/ListItemAnimator.java
@@ -1,43 +1,24 @@
package net.weyne1.easegui.client.animator;
-import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
-import net.weyne1.easegui.client.animation.AnimationMath;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animation.AnimationSystem;
import net.weyne1.easegui.client.config.ConfigManager;
-import net.weyne1.easegui.client.config.UIElementCategory;
+import net.weyne1.easegui.api.WidgetCategory;
import net.weyne1.easegui.client.state.ScreenStateTracker;
-/**
- * Animates list entries using cascade timing.
- */
public class ListItemAnimator {
- /**
- * Starts the animation.
- *
- * @return an {@link AnimationScope} that must be closed, or {@code null} if no animation is needed
- */
public static AnimationScope beginRender(GuiGraphics gg, int top, int left, int width, int height) {
- var profile = ConfigManager.getProfileForCurrentContext(UIElementCategory.LIST_ENTRY);
- if (profile == null || !profile.enabled) return null;
+ var profile = ConfigManager.getProfileForCurrentContext(WidgetCategory.LIST_ENTRY);
+ if (profile == null || !profile.isEnabled()) return null;
long delay = getDelay(top, left, profile);
long startTime = ScreenStateTracker.getScreenOpenTime();
- long elapsed = Util.getMillis() - startTime - delay;
-
- if (elapsed >= profile.duration) return null;
-
- float progress = 0.0f;
- if (elapsed > 0) {
- progress = AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
- }
-
- return AnimationSystem.begin(gg, left, top, width, height, profile, progress, 1.0f);
+ return AnimationSystem.begin(gg, left, top, width, height, profile, startTime, delay, 1.0f);
}
private static long getDelay(int top, int left, AnimationProfile profile) {
@@ -45,13 +26,13 @@ private static long getDelay(int top, int left, AnimationProfile profile) {
int screenHeight = window.getGuiScaledHeight();
int screenWidth = window.getGuiScaledWidth();
- float distance = switch (profile.cascadeDirection) {
+ float distance = switch (profile.getCascadeDirection()) {
case TOP_TO_BOTTOM -> top;
case BOTTOM_TO_TOP -> Math.max(0f, screenHeight - top);
case LEFT_TO_RIGHT -> left;
case RIGHT_TO_LEFT -> Math.max(0f, screenWidth - left);
};
- return (long) (distance * (profile.cascadeDelay / 100.0f));
+ return (long) (distance * (profile.getCascadeDelay() / 100.0f));
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animator/LogoAnimator.java b/common/src/main/java/net/weyne1/easegui/client/animator/LogoAnimator.java
index cffb2bd..8125fa5 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animator/LogoAnimator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animator/LogoAnimator.java
@@ -1,11 +1,12 @@
package net.weyne1.easegui.client.animator;
-import net.minecraft.Util;
+import net.minecraft.client.renderer.RenderPipelines;
+import net.minecraft.util.Util;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.LogoRenderer;
-import net.minecraft.resources.ResourceLocation;
+import net.minecraft.resources.Identifier;
import net.weyne1.easegui.client.animation.AnimationMath;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animation.AnimationSystem;
import net.weyne1.easegui.client.config.ConfigManager;
@@ -18,16 +19,16 @@
*/
public class LogoAnimator {
- private static final ResourceLocation[] LETTER_TEXTURES = new ResourceLocation[] {
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/m.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/i.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/n.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/e.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/t.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/f.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/a.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/r.png"),
- ResourceLocation.fromNamespaceAndPath("easegui", "textures/gui/title/letters/c.png")
+ private static final Identifier[] LETTER_TEXTURES = new Identifier[] {
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/m.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/i.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/n.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/e.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/t.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/f.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/a.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/r.png"),
+ Identifier.fromNamespaceAndPath("easegui", "textures/gui/title/letters/c.png")
};
/**
@@ -36,22 +37,17 @@ public class LogoAnimator {
*/
private static final int[] LOGICAL_INDICES = new int[] { 0, 1, 2, 3, 8, 7, 6, 5, 4 };
- private static long lastTrackedSessionTime = -1L;
- private static long actualStartTime = -1L;
-
public static boolean render(GuiGraphics gg, int screenWidth, float transparency, int height, boolean showEasterEgg, boolean keepLogoThroughFade) {
var titleSettings = ConfigManager.getConfig().screens.get("title");
if (titleSettings == null || !titleSettings.enabled || titleSettings.logo == null) {
return false;
}
- trackSessionTime();
-
var logoConfig = titleSettings.logo;
float finalAlpha = keepLogoThroughFade ? 1.0f : transparency;
int startX = screenWidth / 2 - (LogoRendererAccessor.easeGUI$getLogoWidth() / 2);
- ResourceLocation logoTexture = showEasterEgg ? LogoRenderer.EASTER_EGG_LOGO : LogoRenderer.MINECRAFT_LOGO;
+ Identifier logoTexture = showEasterEgg ? LogoRenderer.EASTER_EGG_LOGO : LogoRenderer.MINECRAFT_LOGO;
if (logoConfig.animateWholeText) {
renderWholeLogo(gg, logoTexture, logoConfig.logoProfile, startX, height, finalAlpha);
} else {
@@ -63,53 +59,51 @@ public static boolean render(GuiGraphics gg, int screenWidth, float transparency
return true;
}
- private static void renderWholeLogo(GuiGraphics gg, ResourceLocation texture, AnimationProfile profile, int startX, int height, float finalAlpha) {
+ private static void renderWholeLogo(GuiGraphics gg, Identifier texture, AnimationProfile profile, int startX, int height, float finalAlpha) {
+ long actualStartTime = ScreenStateTracker.getTitleActualStartTime();
long elapsed = Util.getMillis() - actualStartTime;
int logoWidth = LogoRendererAccessor.easeGUI$getLogoWidth();
int logoHeight = LogoRendererAccessor.easeGUI$getLogoHeight();
- if (elapsed >= profile.duration) {
+ if (elapsed >= profile.getDuration()) {
try (AnimationScope ignored = AnimationSystem.beginAlphaOnly(gg, finalAlpha)) {
drawLogoTexture(gg, texture, startX, height);
- gg.flush();
}
return;
}
- float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
+ float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.getDuration(), profile.getEasing());
try (AnimationScope ignored = AnimationSystem.begin(gg, startX, height, logoWidth, logoHeight, profile, progress, finalAlpha)) {
drawLogoTexture(gg, texture, startX, height);
- gg.flush();
}
}
private static void renderCascadedLetters(GuiGraphics gg, AnimationProfile profile, int startX, int height, float finalAlpha) {
long now = Util.getMillis();
- long maxLogoDelay = (LETTER_TEXTURES.length - 1) * profile.cascadeDelay;
+ long actualStartTime = ScreenStateTracker.getTitleActualStartTime();
+ long maxLogoDelay = (LETTER_TEXTURES.length - 1) * profile.getCascadeDelay();
int logoWidth = LogoRendererAccessor.easeGUI$getLogoWidth();
int logoHeight = LogoRendererAccessor.easeGUI$getLogoHeight();
- if (now - actualStartTime >= maxLogoDelay + profile.duration) {
+ if (now - actualStartTime >= maxLogoDelay + profile.getDuration()) {
try (AnimationScope ignored = AnimationSystem.beginAlphaOnly(gg, finalAlpha)) {
- for (ResourceLocation texture : LETTER_TEXTURES) {
+ for (Identifier texture : LETTER_TEXTURES) {
drawLogoTexture(gg, texture, startX, height);
}
- gg.flush();
}
return;
}
for (int i = 0; i < LETTER_TEXTURES.length; i++) {
int logicalIndex = LOGICAL_INDICES[i];
- ResourceLocation texture = LETTER_TEXTURES[i];
+ Identifier texture = LETTER_TEXTURES[i];
long cascadeDelay = calculateCascadeDelay(profile, logicalIndex);
long elapsed = now - actualStartTime - cascadeDelay;
- float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
+ float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.getDuration(), profile.getEasing());
try (AnimationScope ignored = AnimationSystem.begin(gg, startX, height, logoWidth, logoHeight, profile, progress, finalAlpha)) {
drawLogoTexture(gg, texture, startX, height);
- gg.flush();
}
}
}
@@ -122,58 +116,49 @@ private static void renderEditionText(GuiGraphics gg, EaseGUIConfig.LogoSettings
int y = height + logoHeight - 7;
var profile = config.editionProfile;
- if (profile == null || !profile.enabled) {
+ if (profile == null || !profile.isEnabled()) {
drawStaticEdition(gg, x, y, finalAlpha);
return;
}
long elapsed = getEditionElapsed(config);
- if (elapsed >= profile.duration) {
+ if (elapsed >= profile.getDuration()) {
drawStaticEdition(gg, x, y, finalAlpha);
return;
}
- float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
+ float progress = elapsed <= 0 ? 0.0f : AnimationMath.calculateProgress(elapsed, profile.getDuration(), profile.getEasing());
try (AnimationScope ignored = AnimationSystem.begin(gg, x, y, editionWidth, editionHeight, profile, progress, finalAlpha)) {
drawEditionTexture(gg, x, y);
- gg.flush();
}
}
private static void drawStaticEdition(GuiGraphics gg, int x, int y, float finalAlpha) {
try (AnimationScope ignored = AnimationSystem.beginAlphaOnly(gg, finalAlpha)) {
drawEditionTexture(gg, x, y);
- gg.flush();
}
}
private static long calculateCascadeDelay(AnimationProfile profile, int logicalIndex) {
- return switch (profile.cascadeDirection) {
- case LEFT_TO_RIGHT -> logicalIndex * profile.cascadeDelay;
- case RIGHT_TO_LEFT -> (LETTER_TEXTURES.length - 1 - logicalIndex) * profile.cascadeDelay;
+ return switch (profile.getCascadeDirection()) {
+ case LEFT_TO_RIGHT -> logicalIndex * profile.getCascadeDelay();
+ case RIGHT_TO_LEFT -> (LETTER_TEXTURES.length - 1 - logicalIndex) * profile.getCascadeDelay();
case TOP_TO_BOTTOM, BOTTOM_TO_TOP -> 0L;
};
}
private static long getEditionElapsed(EaseGUIConfig.LogoSettings config) {
- long maxLogoDelay = config.animateWholeText ? 0L : switch (config.logoProfile.cascadeDirection) {
- case LEFT_TO_RIGHT, RIGHT_TO_LEFT -> (LETTER_TEXTURES.length - 1) * config.logoProfile.cascadeDelay;
+ long actualStartTime = ScreenStateTracker.getTitleActualStartTime();
+ long maxLogoDelay = config.animateWholeText ? 0L : switch (config.logoProfile.getCascadeDirection()) {
+ case LEFT_TO_RIGHT, RIGHT_TO_LEFT -> (LETTER_TEXTURES.length - 1) * config.logoProfile.getCascadeDelay();
case TOP_TO_BOTTOM, BOTTOM_TO_TOP -> 0L;
};
return Util.getMillis() - actualStartTime - maxLogoDelay;
}
- private static void trackSessionTime() {
- long currentSessionTime = ScreenStateTracker.getScreenOpenTime();
- if (lastTrackedSessionTime != currentSessionTime) {
- lastTrackedSessionTime = currentSessionTime;
- actualStartTime = Util.getMillis();
- }
- }
-
- private static void drawLogoTexture(GuiGraphics gg, ResourceLocation texture, int x, int y) {
- gg.blit(texture, x, y, 0.0f, 0.0f,
+ private static void drawLogoTexture(GuiGraphics gg, Identifier texture, int x, int y) {
+ gg.blit(RenderPipelines.GUI_TEXTURED, texture, x, y, 0.0f, 0.0f,
LogoRendererAccessor.easeGUI$getLogoWidth(),
LogoRendererAccessor.easeGUI$getLogoHeight(),
LogoRendererAccessor.easeGUI$getLogoWidth(),
@@ -181,7 +166,7 @@ private static void drawLogoTexture(GuiGraphics gg, ResourceLocation texture, in
}
private static void drawEditionTexture(GuiGraphics gg, int x, int y) {
- gg.blit(LogoRenderer.MINECRAFT_EDITION, x, y, 0.0f, 0.0f,
+ gg.blit(RenderPipelines.GUI_TEXTURED, LogoRenderer.MINECRAFT_EDITION, x, y, 0.0f, 0.0f,
LogoRendererAccessor.easeGUI$getEditionWidth(),
LogoRendererAccessor.easeGUI$getEditionHeight(),
LogoRendererAccessor.easeGUI$getEditionWidth(),
diff --git a/common/src/main/java/net/weyne1/easegui/client/animator/SplashAnimator.java b/common/src/main/java/net/weyne1/easegui/client/animator/SplashAnimator.java
index 94806db..4f5c43d 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animator/SplashAnimator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animator/SplashAnimator.java
@@ -1,44 +1,39 @@
package net.weyne1.easegui.client.animator;
-import net.minecraft.Util;
-import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.ActiveTextCollector;
+import net.minecraft.util.Util;
+import net.weyne1.easegui.client.animation.AnimationContext;
import net.weyne1.easegui.client.animation.AnimationMath;
-import net.weyne1.easegui.client.animation.AnimationScope;
-import net.weyne1.easegui.client.animation.AnimationSystem;
import net.weyne1.easegui.client.config.ConfigManager;
import net.weyne1.easegui.client.state.ScreenStateTracker;
-/**
- * Animates the title screen splash text.
- */
public class SplashAnimator {
- /**
- * Starts the animation.
- *
- * @return an {@link AnimationScope} that must be closed, or {@code null} if no animation is needed
- */
- public static AnimationScope beginRender(GuiGraphics gg, int color) {
+
+ public static ActiveTextCollector.Parameters getAnimatedParameters(ActiveTextCollector.Parameters parameters) {
var screenConfig = ConfigManager.getConfig().screens.get("title");
+
if (screenConfig == null || !screenConfig.enabled || screenConfig.splash == null || !screenConfig.splash.enabled) {
- return null;
+ return parameters.withOpacity(AnimationContext.getCurrentAlpha());
}
var splashConfig = screenConfig.splash;
- long startTime = ScreenStateTracker.getScreenOpenTime();
- long elapsed = Util.getMillis() - startTime - splashConfig.splashDelay;
+ long actualStartTime = ScreenStateTracker.getTitleActualStartTime();
+ long elapsed = Util.getMillis() - actualStartTime - splashConfig.splashDelay;
+ float parentAlpha = AnimationContext.getCurrentAlpha();
- if (elapsed >= splashConfig.splashDuration) {
+ if (elapsed <= 0) {
return null;
}
- float progress = AnimationMath.calculateProgress(elapsed, splashConfig.splashDuration, splashConfig.splashEasing);
-
- float baseAlpha = ((color >> 24) & 255) / 255.0f;
- float finalAlpha = baseAlpha * progress;
- AnimationScope scope = AnimationSystem.beginAlphaOnly(gg, finalAlpha);
+ if (elapsed >= splashConfig.splashDuration) {
+ return parameters.withOpacity(parentAlpha);
+ }
- gg.pose().scale(progress, progress, 1.0f);
+ float progress = AnimationMath.calculateProgress(elapsed, splashConfig.splashDuration, splashConfig.splashEasing);
+ float finalAlpha = AnimationMath.clamp(progress * parentAlpha, 0f, 1f);
- return scope;
+ return parameters
+ .withOpacity(finalAlpha)
+ .withScale(progress);
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/animator/WidgetAnimator.java b/common/src/main/java/net/weyne1/easegui/client/animator/WidgetAnimator.java
index 7629c4c..e2054dc 100644
--- a/common/src/main/java/net/weyne1/easegui/client/animator/WidgetAnimator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/animator/WidgetAnimator.java
@@ -1,14 +1,15 @@
package net.weyne1.easegui.client.animator;
-import net.minecraft.Util;
+import net.minecraft.util.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
-import net.weyne1.easegui.client.EaseGUIWidget;
+import net.weyne1.easegui.api.animation.AnimationProfile;
+import net.weyne1.easegui.client.extension.WidgetExtension;
import net.weyne1.easegui.client.animation.*;
import net.weyne1.easegui.client.config.ConfigManager;
-import net.weyne1.easegui.client.config.UIElementCategory;
+import net.weyne1.easegui.api.WidgetCategory;
import net.weyne1.easegui.client.state.ScreenStateTracker;
/**
@@ -16,54 +17,32 @@
*/
public class WidgetAnimator {
- /**
- * Starts the animation.
- *
- * @return an {@link AnimationScope} that must be closed, or {@code null} if no animation is needed
- */
- public static AnimationScope beginRender(AbstractWidget widget, GuiGraphics gg, UIElementCategory category, AnimationState.AnimationData state) {
+ public static AnimationScope beginRender(AbstractWidget widget, GuiGraphics gg, WidgetCategory category, AnimationState state) {
if (Minecraft.getInstance().screen instanceof AbstractContainerScreen) {
return null;
}
var profile = ConfigManager.getProfileForCurrentContext(category);
- if (profile == null || !profile.enabled) return null;
+ if (profile == null || !profile.isEnabled()) return null;
long now = Util.getMillis();
updateAnimationState(widget, state, now, profile);
if (ScreenStateTracker.isResizeFrame() || AnimationContext.hasParentAnimation()) {
- state.startTime = now - profile.duration - state.delay;
+ state.startTime = now - profile.getDuration() - state.delay;
return null;
}
- long elapsed = now - state.startTime - state.delay;
-
- if (elapsed >= profile.duration) return null;
-
- float progress = 0.0f;
- if (elapsed > 0) {
- progress = AnimationMath.calculateProgress(elapsed, profile.duration, profile.easing);
- }
-
- return AnimationSystem.begin(
- gg,
- widget.getX(),
- widget.getY(),
- widget.getWidth(),
- widget.getHeight(),
- profile,
- progress,
- ((EaseGUIWidget) widget).easeGUI$getAlpha()
- );
+ return AnimationSystem.begin(gg, widget.getX(), widget.getY(), widget.getWidth(), widget.getHeight(), profile,
+ state.startTime, state.delay, ((WidgetExtension) widget).easeGUI$getAlpha());
}
/**
* Initializes animation state when a widget appears and
* recalculates cascade timing if needed.
*/
- private static void updateAnimationState(AbstractWidget widget, AnimationState.AnimationData state, long now, AnimationProfile profile) {
+ private static void updateAnimationState(AbstractWidget widget, AnimationState state, long now, AnimationProfile profile) {
int currentFrame = ScreenStateTracker.getCurrentFrameId();
if (state.init && currentFrame > state.lastRenderFrame + 1) {
@@ -76,7 +55,7 @@ private static void updateAnimationState(AbstractWidget widget, AnimationState.A
float distance = getDistance(widget, profile);
- float delayMultiplier = profile.cascadeDelay / 100.0f;
+ float delayMultiplier = profile.getCascadeDelay() / 100.0f;
state.delay = (long) (distance * delayMultiplier);
}
@@ -84,8 +63,8 @@ private static void updateAnimationState(AbstractWidget widget, AnimationState.A
}
/**
- * Вычисляет расстояние до виджета в виртуальной шкале координат,
- * делая скорость каскада независимой от GUI Scale и разрешения монитора.
+ * Calculates the distance to the widget in a virtual coordinate scale,
+ * making the cascade speed independent of the GUI scale and monitor resolution.
*/
private static float getDistance(AbstractWidget widget, AnimationProfile profile) {
var window = Minecraft.getInstance().getWindow();
@@ -98,7 +77,7 @@ private static float getDistance(AbstractWidget widget, AnimationProfile profile
final float BASELINE_WIDTH = 960.0f;
final float BASELINE_HEIGHT = 540.0f;
- return switch (profile.cascadeDirection) {
+ return switch (profile.getCascadeDirection()) {
case TOP_TO_BOTTOM -> (Math.max(0, y) / (float) screenHeight) * BASELINE_HEIGHT;
case BOTTOM_TO_TOP -> (Math.max(0f, screenHeight - y) / (float) screenHeight) * BASELINE_HEIGHT;
case LEFT_TO_RIGHT -> (Math.max(0, x) / (float) screenWidth) * BASELINE_WIDTH;
diff --git a/common/src/main/java/net/weyne1/easegui/client/config/ConfigManager.java b/common/src/main/java/net/weyne1/easegui/client/config/ConfigManager.java
index b01618e..c35fdd6 100644
--- a/common/src/main/java/net/weyne1/easegui/client/config/ConfigManager.java
+++ b/common/src/main/java/net/weyne1/easegui/client/config/ConfigManager.java
@@ -5,7 +5,10 @@
import com.google.gson.JsonObject;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.WidgetCategory;
+import net.weyne1.easegui.api.EaseGUIScreenRegistry;
+import net.weyne1.easegui.api.EaseGUIScreenType;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import java.io.File;
import java.io.FileReader;
@@ -19,11 +22,11 @@ public class ConfigManager {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
- private static EaseGUIConfig currentConfig = new EaseGUIConfig();
+ private static EaseGUIConfig currentConfig = EaseGUIConfigFactory.createDefaultConfig();
private static boolean isLoaded = false;
private static Screen cachedScreenInstance = null;
- private static ScreenType cachedScreenType = EaseGUIScreenRegistry.OTHER;
+ private static EaseGUIScreenType cachedScreenType = EaseGUIScreenRegistry.OTHER;
public static void load() {
if (isLoaded) return;
@@ -54,12 +57,12 @@ public static void load() {
currentConfig = GSON.fromJson(jsonConfig, EaseGUIConfig.class);
if (currentConfig == null) {
- currentConfig = new EaseGUIConfig();
+ currentConfig = EaseGUIConfigFactory.createDefaultConfig();
}
currentConfig.schemaVersion = EaseGUIConfig.CURRENT_SCHEMA_VERSION;
- if (currentConfig.mergeDefaults() || migrated) {
+ if (EaseGUIConfigFactory.mergeDefaults(currentConfig) || migrated) {
LOGGER.info("[EaseGUI] Config schema updated from version {} to {}.", version, EaseGUIConfig.CURRENT_SCHEMA_VERSION);
save();
}
@@ -67,7 +70,7 @@ public static void load() {
LOGGER.info("[EaseGUI] Config successfully loaded from disk.");
} catch (Exception e) {
LOGGER.error("[EaseGUI] Failed to read config, creating default... Error: {}", e.getMessage());
- currentConfig = new EaseGUIConfig();
+ currentConfig = EaseGUIConfigFactory.createDefaultConfig();
save();
}
} else {
@@ -91,8 +94,8 @@ public static EaseGUIConfig getConfig() {
return currentConfig;
}
- public static AnimationProfile getProfileForCurrentContext(UIElementCategory category) {
- if (category == null || category == UIElementCategory.UNKNOWN) return null;
+ public static AnimationProfile getProfileForCurrentContext(WidgetCategory category) {
+ if (category == null || category == WidgetCategory.UNKNOWN) return null;
if (!isLoaded) load();
Screen currentScreen = Minecraft.getInstance().screen;
@@ -109,7 +112,7 @@ public static AnimationProfile getProfileForCurrentContext(UIElementCategory cat
AnimationProfile customProfile = screenSettings.customProfiles.get(category);
if (customProfile != null) {
- return customProfile.enabled ? customProfile : null;
+ return customProfile.isEnabled() ? customProfile : null;
}
}
diff --git a/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIConfig.java b/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIConfig.java
index bb667ba..d1a740c 100644
--- a/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIConfig.java
+++ b/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIConfig.java
@@ -1,134 +1,33 @@
package net.weyne1.easegui.client.config;
-import net.weyne1.easegui.client.animation.AnimationProfile;
-import net.weyne1.easegui.client.animation.AnimationProfile.EasingType;
+import net.weyne1.easegui.api.WidgetCategory;
+import net.weyne1.easegui.api.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.EasingType;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
-import static net.weyne1.easegui.client.animation.AnimationProfile.CascadeDirection.BOTTOM_TO_TOP;
-import static net.weyne1.easegui.client.animation.AnimationProfile.CascadeDirection.LEFT_TO_RIGHT;
-import static net.weyne1.easegui.client.animation.AnimationProfile.EasingType.*;
+import static net.weyne1.easegui.api.animation.EasingType.EASE_OUT_CUBIC;
public class EaseGUIConfig {
public static final int CURRENT_SCHEMA_VERSION = 2;
- public int schemaVersion = CURRENT_SCHEMA_VERSION;
- public final GlobalSettings global = new GlobalSettings();
+ public int schemaVersion = CURRENT_SCHEMA_VERSION;
+ public GlobalSettings global = new GlobalSettings();
public Map screens = new HashMap<>();
- public EaseGUIConfig() {
- global.elementProfiles.put(UIElementCategory.BUTTON_LIKE, createButtonProfile());
- global.elementProfiles.put(UIElementCategory.TEXT, createTextProfile());
- global.elementProfiles.put(UIElementCategory.SCROLLABLE, createScrollableProfile());
- global.elementProfiles.put(UIElementCategory.LIST_ENTRY, createListEntryProfile());
- global.elementProfiles.put(UIElementCategory.CONTAINERS, createContainerProfile());
-
- for (ScreenType type : EaseGUIScreenRegistry.getRegisteredTypes()) {
- screens.put(type.getId(), createDefaultSettingsFor(type));
- }
- screens.put(EaseGUIScreenRegistry.OTHER.getId(), createDefaultSettingsFor(EaseGUIScreenRegistry.OTHER));
- }
-
- /**
- * Patches missing structure and runs schema migrations.
- *
- * @return true if config was modified and should be saved back to disk
- */
- public boolean mergeDefaults() {
- boolean changed = false;
-
- if (this.schemaVersion < CURRENT_SCHEMA_VERSION) {
- this.schemaVersion = CURRENT_SCHEMA_VERSION;
- changed = true;
- }
-
- if (this.screens == null) {
- this.screens = new HashMap<>();
- changed = true;
- }
-
- for (ScreenType type : EaseGUIScreenRegistry.getRegisteredTypes()) {
- if (!this.screens.containsKey(type.getId())) {
- this.screens.put(type.getId(), createDefaultSettingsFor(type));
- changed = true;
- } else {
- changed |= patchScreenSettings(type, this.screens.get(type.getId()));
- }
- }
-
- if (!this.screens.containsKey(EaseGUIScreenRegistry.OTHER.getId())) {
- this.screens.put(EaseGUIScreenRegistry.OTHER.getId(), createDefaultSettingsFor(EaseGUIScreenRegistry.OTHER));
- changed = true;
- }
-
- return changed;
- }
-
- /**
- * Applies structural defaults for an existing screen entry.
- * This only fills missing nested sections, not arbitrary primitive fields.
- */
- private boolean patchScreenSettings(ScreenType type, ScreenSettings settings) {
- boolean changed = false;
-
- if (settings == null) {
- this.screens.put(type.getId(), createDefaultSettingsFor(type));
- return true;
- }
-
- if ("title".equals(type.getId())) {
- if (settings.logo == null) {
- settings.logo = createLogoSettings();
- changed = true;
- }
- if (settings.splash == null) {
- settings.splash = new SplashSettings();
- changed = true;
- }
- } else if ("advancements".equals(type.getId())) {
- if (settings.advancements == null) {
- settings.advancements = createAdvancementsSettings();
- changed = true;
- }
- }
-
- if (settings.customProfiles == null) {
- settings.customProfiles = new EnumMap<>(UIElementCategory.class);
- changed = true;
- }
-
- return changed;
- }
-
- private ScreenSettings createDefaultSettingsFor(ScreenType type) {
- ScreenSettings settings = new ScreenSettings();
- settings.enabled = type.isEnabledByDefault();
-
- switch (type.getId()) {
- case "title" -> {
- settings.logo = createLogoSettings();
- settings.splash = new SplashSettings();
- }
- case "advancements" -> settings.advancements = createAdvancementsSettings();
- }
-
- return settings;
- }
-
public static class GlobalSettings {
public boolean enableSmoothBlur = true;
public long blurDuration = 300L;
public boolean blurContainers = true;
public EasingType dimmingEasing = EASE_OUT_CUBIC;
- public final Map elementProfiles = new EnumMap<>(UIElementCategory.class);
+ public final Map elementProfiles = new EnumMap<>(WidgetCategory.class);
}
public static class ScreenSettings {
public boolean enabled = true;
- public Map customProfiles =
- new EnumMap<>(UIElementCategory.class);
+ public Map customProfiles = new EnumMap<>(WidgetCategory.class);
public LogoSettings logo = null;
public SplashSettings splash = null;
@@ -137,95 +36,19 @@ public static class ScreenSettings {
public static class LogoSettings {
public boolean animateWholeText = false;
-
- public AnimationProfile logoProfile = new AnimationProfile()
- .duration(400L)
- .offsetY(10f)
- .startScale(0.8f)
- .startAlpha(0.0f)
- .cascadeDelay(60L)
- .cascadeDirection(LEFT_TO_RIGHT)
- .easing(EASE_OUT_BACK)
- .pivot(AnimationProfile.PivotPoint.CENTER);
-
- public AnimationProfile editionProfile = new AnimationProfile()
- .duration(400L)
- .offsetY(5f)
- .startScale(0.9f)
- .startAlpha(0.0f)
- .easing(EASE_OUT_QUAD)
- .pivot(AnimationProfile.PivotPoint.CENTER);
+ public AnimationProfile logoProfile;
+ public AnimationProfile editionProfile;
}
public static class SplashSettings {
public boolean enabled = true;
public long splashDelay = 500L;
public long splashDuration = 500L;
- public EasingType splashEasing = EASE_OUT_BACK;
+ public EasingType splashEasing;
}
public static class AdvancementsSettings {
- public AnimationProfile windowProfile = new AnimationProfile()
- .duration(250)
- .startAlpha(0.0f)
- .startScale(0.8f)
- .easing(EASE_OUT_CUBIC);
-
- public AnimationProfile tabsProfile = new AnimationProfile()
- .duration(400L)
- .offsetX(-40f)
- .startAlpha(0.0f)
- .cascadeDelay(45L)
- .cascadeDirection(LEFT_TO_RIGHT)
- .easing(EASE_OUT_BACK);
- }
-
- private static AnimationProfile createButtonProfile() {
- return new AnimationProfile()
- .duration(400)
- .offsetY(15f)
- .startAlpha(0.0f)
- .cascadeDelay(45L)
- .cascadeDirection(BOTTOM_TO_TOP)
- .easing(EASE_OUT_BACK);
- }
-
- private static AnimationProfile createTextProfile() {
- return new AnimationProfile()
- .duration(300)
- .startAlpha(0.0f)
- .easing(LINEAR);
- }
-
- private static AnimationProfile createScrollableProfile() {
- return new AnimationProfile()
- .duration(300)
- .startAlpha(0.0f)
- .easing(EASE_OUT_BACK);
- }
-
- private static AnimationProfile createListEntryProfile() {
- return new AnimationProfile()
- .duration(350)
- .offsetY(15f)
- .startAlpha(0.0f)
- .cascadeDelay(45L)
- .easing(EASE_OUT_CUBIC);
- }
-
- private static AnimationProfile createContainerProfile() {
- return new AnimationProfile()
- .duration(250)
- .offsetY(20f)
- .startAlpha(0.0f)
- .easing(EASE_OUT_CUBIC);
- }
-
- private static LogoSettings createLogoSettings() {
- return new LogoSettings();
- }
-
- private static AdvancementsSettings createAdvancementsSettings() {
- return new AdvancementsSettings();
+ public AnimationProfile windowProfile;
+ public AnimationProfile tabsProfile;
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIConfigFactory.java b/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIConfigFactory.java
new file mode 100644
index 0000000..26cd38e
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIConfigFactory.java
@@ -0,0 +1,217 @@
+package net.weyne1.easegui.client.config;
+
+import net.weyne1.easegui.api.WidgetCategory;
+import net.weyne1.easegui.api.EaseGUIScreenRegistry;
+import net.weyne1.easegui.api.EaseGUIScreenType;
+import net.weyne1.easegui.api.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.PivotPoint;
+import java.util.EnumMap;
+import java.util.HashMap;
+
+import static net.weyne1.easegui.api.animation.CascadeDirection.BOTTOM_TO_TOP;
+import static net.weyne1.easegui.api.animation.CascadeDirection.LEFT_TO_RIGHT;
+import static net.weyne1.easegui.api.animation.EasingType.*;
+
+/**
+ * Factory responsible for creating default configurations, applying structural patches,
+ * and handling schema migrations.
+ */
+public final class EaseGUIConfigFactory {
+
+ public static EaseGUIConfig createDefaultConfig() {
+ EaseGUIConfig config = new EaseGUIConfig();
+
+ config.global.elementProfiles.put(WidgetCategory.BUTTON_LIKE, createButtonProfile());
+ config.global.elementProfiles.put(WidgetCategory.TEXT, createTextProfile());
+ config.global.elementProfiles.put(WidgetCategory.SCROLLABLE, createScrollableProfile());
+ config.global.elementProfiles.put(WidgetCategory.LIST_ENTRY, createListEntryProfile());
+ config.global.elementProfiles.put(WidgetCategory.CONTAINERS, createContainerProfile());
+
+ for (EaseGUIScreenType type : EaseGUIScreenRegistry.getRegisteredTypes()) {
+ config.screens.put(type.getId(), createDefaultSettingsFor(type));
+ }
+ config.screens.put(EaseGUIScreenRegistry.OTHER.getId(), createDefaultSettingsFor(EaseGUIScreenRegistry.OTHER));
+
+ return config;
+ }
+
+ /**
+ * Patches missing structures in an existing config and bumps the schema version if needed.
+ * Replaces the old non-SRP mergeDefaults() inside the config class.
+ *
+ * @return true if config was modified and should be saved back to disk
+ */
+ public static boolean mergeDefaults(EaseGUIConfig config) {
+ boolean changed = false;
+
+ if (config.schemaVersion < EaseGUIConfig.CURRENT_SCHEMA_VERSION) {
+ config.schemaVersion = EaseGUIConfig.CURRENT_SCHEMA_VERSION;
+ changed = true;
+ }
+
+ if (config.screens == null) {
+ config.screens = new HashMap<>();
+ changed = true;
+ }
+
+ for (EaseGUIScreenType type : EaseGUIScreenRegistry.getRegisteredTypes()) {
+ if (!config.screens.containsKey(type.getId())) {
+ config.screens.put(type.getId(), createDefaultSettingsFor(type));
+ changed = true;
+ } else {
+ changed |= patchScreenSettings(type, config.screens.get(type.getId()), config);
+ }
+ }
+
+ if (!config.screens.containsKey(EaseGUIScreenRegistry.OTHER.getId())) {
+ config.screens.put(EaseGUIScreenRegistry.OTHER.getId(), createDefaultSettingsFor(EaseGUIScreenRegistry.OTHER));
+ changed = true;
+ }
+
+ return changed;
+ }
+
+ private static boolean patchScreenSettings(EaseGUIScreenType type, EaseGUIConfig.ScreenSettings settings, EaseGUIConfig config) {
+ boolean changed = false;
+
+ if (settings == null) {
+ config.screens.put(type.getId(), createDefaultSettingsFor(type));
+ return true;
+ }
+
+ if ("title".equals(type.getId())) {
+ if (settings.logo == null) {
+ settings.logo = createLogoSettings();
+ changed = true;
+ }
+ if (settings.splash == null) {
+ settings.splash = createSplashSettings();
+ changed = true;
+ }
+ } else if ("advancements".equals(type.getId())) {
+ if (settings.advancements == null) {
+ settings.advancements = createAdvancementsSettings();
+ changed = true;
+ }
+ }
+
+ if (settings.customProfiles == null) {
+ settings.customProfiles = new EnumMap<>(WidgetCategory.class);
+ changed = true;
+ }
+
+ // Apply external developer animation defaults over user settings
+ changed |= EaseGUIScreenRegistry.patchDefaults(type.getId(), settings);
+
+ return changed;
+ }
+
+ private static EaseGUIConfig.ScreenSettings createDefaultSettingsFor(EaseGUIScreenType type) {
+ EaseGUIConfig.ScreenSettings settings = new EaseGUIConfig.ScreenSettings();
+ settings.enabled = type.isEnabledByDefault();
+
+ switch (type.getId()) {
+ case "title" -> {
+ settings.logo = createLogoSettings();
+ settings.splash = createSplashSettings();
+ }
+ case "advancements" -> settings.advancements = createAdvancementsSettings();
+ }
+
+ // Allow external mods to apply their default profile configurations on screen creation
+ EaseGUIScreenRegistry.configureDefaults(type.getId(), settings);
+
+ return settings;
+ }
+
+ private static EaseGUIConfig.LogoSettings createLogoSettings() {
+ EaseGUIConfig.LogoSettings settings = new EaseGUIConfig.LogoSettings();
+ settings.animateWholeText = false;
+ settings.logoProfile = new AnimationProfile()
+ .duration(400L)
+ .offsetY(10f)
+ .startScale(0.8f)
+ .startAlpha(0.0f)
+ .cascadeDelay(60L)
+ .cascadeDirection(LEFT_TO_RIGHT)
+ .easing(EASE_OUT_BACK)
+ .pivot(PivotPoint.CENTER);
+
+ settings.editionProfile = new AnimationProfile()
+ .duration(400L)
+ .offsetY(5f)
+ .startScale(0.9f)
+ .startAlpha(0.0f)
+ .easing(EASE_OUT_QUAD)
+ .pivot(PivotPoint.CENTER);
+ return settings;
+ }
+
+ private static EaseGUIConfig.SplashSettings createSplashSettings() {
+ EaseGUIConfig.SplashSettings settings = new EaseGUIConfig.SplashSettings();
+ settings.enabled = true;
+ settings.splashDelay = 500L;
+ settings.splashDuration = 500L;
+ settings.splashEasing = EASE_OUT_BACK;
+ return settings;
+ }
+
+ private static EaseGUIConfig.AdvancementsSettings createAdvancementsSettings() {
+ EaseGUIConfig.AdvancementsSettings settings = new EaseGUIConfig.AdvancementsSettings();
+ settings.windowProfile = new AnimationProfile()
+ .duration(250)
+ .startAlpha(0.0f)
+ .startScale(0.8f)
+ .easing(EASE_OUT_CUBIC);
+
+ settings.tabsProfile = new AnimationProfile()
+ .duration(400L)
+ .offsetX(-40f)
+ .startAlpha(0.0f)
+ .cascadeDelay(45L)
+ .cascadeDirection(LEFT_TO_RIGHT)
+ .easing(EASE_OUT_BACK);
+ return settings;
+ }
+
+ private static AnimationProfile createButtonProfile() {
+ return new AnimationProfile()
+ .duration(400)
+ .offsetY(15f)
+ .startAlpha(0.0f)
+ .cascadeDelay(45L)
+ .cascadeDirection(BOTTOM_TO_TOP)
+ .easing(EASE_OUT_BACK);
+ }
+
+ private static AnimationProfile createTextProfile() {
+ return new AnimationProfile()
+ .duration(300)
+ .startAlpha(0.0f)
+ .easing(LINEAR);
+ }
+
+ private static AnimationProfile createScrollableProfile() {
+ return new AnimationProfile()
+ .duration(300)
+ .startAlpha(0.0f)
+ .easing(EASE_OUT_BACK);
+ }
+
+ private static AnimationProfile createListEntryProfile() {
+ return new AnimationProfile()
+ .duration(350)
+ .offsetY(15f)
+ .startAlpha(0.0f)
+ .cascadeDelay(45L)
+ .easing(EASE_OUT_CUBIC);
+ }
+
+ private static AnimationProfile createContainerProfile() {
+ return new AnimationProfile()
+ .duration(250)
+ .offsetY(20f)
+ .startAlpha(0.0f)
+ .easing(EASE_OUT_CUBIC);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIScreenRegistry.java b/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIScreenRegistry.java
deleted file mode 100644
index 2e34667..0000000
--- a/common/src/main/java/net/weyne1/easegui/client/config/EaseGUIScreenRegistry.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package net.weyne1.easegui.client.config;
-
-import com.mojang.realmsclient.RealmsMainScreen;
-import net.minecraft.client.gui.screens.*;
-import net.minecraft.client.gui.screens.achievement.StatsScreen;
-import net.minecraft.client.gui.screens.advancements.AdvancementsScreen;
-import net.minecraft.client.gui.screens.inventory.*;
-import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen;
-import net.minecraft.client.gui.screens.multiplayer.ServerReconfigScreen;
-import net.minecraft.client.gui.screens.multiplayer.WarningScreen;
-import net.minecraft.client.gui.screens.options.OptionsScreen;
-import net.minecraft.client.gui.screens.options.OptionsSubScreen;
-import net.minecraft.client.gui.screens.packs.PackSelectionScreen;
-import net.minecraft.client.gui.screens.social.SocialInteractionsScreen;
-import net.minecraft.client.gui.screens.worldselection.*;
-import net.weyne1.easegui.client.gui.screens.EaseGUIAbstractSplitScreen;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Registry that maps Minecraft Screen classes to ScreenType definitions.
- *
- * This is used by EaseGUI to decide how different screens should be categorized
- * and animated. Matching works in two steps:
- *
- * - Fast exact class lookup (cache)
- * - Fallback hierarchy scan using isAssignableFrom
- *
- *
- * Mod developers can register custom screens to integrate them into animation system.
- */
-public final class EaseGUIScreenRegistry {
-
- /** Cache for exact class → ScreenType mapping to avoid hierarchy checks */
- private static final Map, ScreenType> EXACT_MATCH_CACHE = new ConcurrentHashMap<>();
-
- /** Sorted list of screen types used for inheritance-based matching */
- private static final List HIERARCHY_LIST = new ArrayList<>();
-
- /** Fallback type used when no match is found */
- public static final ScreenType OTHER = new ScreenType("other", Screen.class, Integer.MIN_VALUE, ScreenGroup.OTHER, false);
-
- static {
- // Vanilla UI screens
- register("title", TitleScreen.class, 1000, ScreenGroup.BASIC);
- register("options", OptionsScreen.class, 1000, ScreenGroup.BASIC);
- register("options_sub", OptionsSubScreen.class, 1000, ScreenGroup.BASIC);
- register("pack_selection", PackSelectionScreen.class, 1000, ScreenGroup.BASIC);
- register("advancements", AdvancementsScreen.class, 1000, ScreenGroup.BASIC);
- register("statistics", StatsScreen.class, 1000, ScreenGroup.BASIC);
- register("warning", WarningScreen.class, 1000, ScreenGroup.BASIC);
- register("pause", PauseScreen.class, 1000, ScreenGroup.BASIC);
- register("share_to_lan", ShareToLanScreen.class, 1000, ScreenGroup.BASIC);
- register("death", DeathScreen.class, 1000, ScreenGroup.BASIC);
- register("social_interactions", SocialInteractionsScreen.class, 1000, ScreenGroup.BASIC);
-
- // Editors
- register("sign_edit", AbstractSignEditScreen.class, 1000, ScreenGroup.EDITORS);
- register("book_edit", BookEditScreen.class, 1000, ScreenGroup.EDITORS);
- register("book_view", BookViewScreen.class, 1000, ScreenGroup.EDITORS);
- register("command_block_edit", AbstractCommandBlockEditScreen.class, 1000, ScreenGroup.EDITORS);
- register("structure_block_edit", StructureBlockEditScreen.class, 1000, ScreenGroup.EDITORS);
- register("jigsaw_block_edit", JigsawBlockEditScreen.class, 1000, ScreenGroup.EDITORS);
-
- // World / multiplayer menus
- register("world_selection", SelectWorldScreen.class, 1000, ScreenGroup.WORLDS);
- register("server_selection", JoinMultiplayerScreen.class, 1000, ScreenGroup.WORLDS);
- register("realms_main", RealmsMainScreen.class, 1000, ScreenGroup.WORLDS);
- register("create_world", CreateWorldScreen.class, 1000, ScreenGroup.WORLDS);
- register("create_flat_world", CreateFlatWorldScreen.class, 1000, ScreenGroup.WORLDS);
- register("direct_join_server", DirectJoinServerScreen.class, 1000, ScreenGroup.WORLDS);
- register("edit_world", EditWorldScreen.class, 1000, ScreenGroup.WORLDS);
- register("edit_server", EditServerScreen.class, 1000, ScreenGroup.WORLDS);
- register("edit_game_rules", EditGameRulesScreen.class, 1000, ScreenGroup.WORLDS);
- register("experiments", ExperimentsScreen.class, 1000, ScreenGroup.WORLDS);
- register("connecting", ConnectScreen.class, 1000, ScreenGroup.WORLDS);
- register("disconnected", DisconnectedScreen.class, 1000, ScreenGroup.WORLDS);
- register("server_reconfig", ServerReconfigScreen.class, 1000, ScreenGroup.WORLDS);
- register("credits", CreditsAndAttributionScreen.class, 1000, ScreenGroup.WORLDS);
-
- // Containers / inventories
- register("creative_inventory", CreativeModeInventoryScreen.class, 500, ScreenGroup.CONTAINERS);
- register("survival_inventory", InventoryScreen.class, 500, ScreenGroup.CONTAINERS);
- register("anvil", AnvilScreen.class, 500, ScreenGroup.CONTAINERS);
- register("enchanting_table", EnchantmentScreen.class, 500, ScreenGroup.CONTAINERS);
- register("container", ContainerScreen.class, 500, ScreenGroup.CONTAINERS);
- register("smithing", SmithingScreen.class, 500, ScreenGroup.CONTAINERS);
- register("dispenser", DispenserScreen.class, 500, ScreenGroup.CONTAINERS);
- register("beacon", BeaconScreen.class, 500, ScreenGroup.CONTAINERS);
- register("crafter", CrafterScreen.class, 500, ScreenGroup.CONTAINERS);
- register("crafting", CraftingScreen.class, 500, ScreenGroup.CONTAINERS);
- register("brewing_stand", BrewingStandScreen.class, 500, ScreenGroup.CONTAINERS);
- register("cartography_table", CartographyTableScreen.class, 500, ScreenGroup.CONTAINERS);
- register("furnace", AbstractFurnaceScreen.class, 500, ScreenGroup.CONTAINERS);
- register("grindstone", GrindstoneScreen.class, 500, ScreenGroup.CONTAINERS);
- register("hopper", HopperScreen.class, 500, ScreenGroup.CONTAINERS);
- register("horse_inventory", HorseInventoryScreen.class, 500, ScreenGroup.CONTAINERS);
- register("lectern", LecternScreen.class, 500, ScreenGroup.CONTAINERS);
- register("loom", LoomScreen.class, 500, ScreenGroup.CONTAINERS);
- register("shulker_box", ShulkerBoxScreen.class, 500, ScreenGroup.CONTAINERS);
- register("stonecutter", StonecutterScreen.class, 500, ScreenGroup.CONTAINERS);
- register("other_containers", AbstractContainerScreen.class, 100, ScreenGroup.CONTAINERS);
-
- // Internal config UI
- register("ease_gui_config", EaseGUIAbstractSplitScreen.class, 100, ScreenGroup.OTHER);
-
- // Optional mod integration (Mod Menu)
- try {
- Class> modMenuScreenClass = Class.forName("com.terraformersmc.modmenu.gui.ModsScreen");
- register("modmenu", modMenuScreenClass.asSubclass(Screen.class), 1000, ScreenGroup.BASIC, false);
- } catch (ClassNotFoundException ignored) {
- // Mod Menu is not installed — safely skip registration
- }
- }
-
- /**
- * Registers a screen type with default enabled state (true).
- */
- public static synchronized void register(
- String id,
- Class extends Screen> screenClass,
- int priority,
- ScreenGroup category
- ) {
- register(id, screenClass, priority, category, true);
- }
-
- /**
- * Registers a screen type for animation classification.
- *
- * @param id unique identifier (e.g. "inventory" or "modid:screen")
- * @param screenClass target screen class
- * @param priority matching priority (higher = checked earlier)
- * @param category logical grouping of screen type
- * @param enabledByDefault whether this screen type is enabled on first config creation
- */
- public static synchronized void register(
- String id,
- Class extends Screen> screenClass,
- int priority,
- ScreenGroup category,
- boolean enabledByDefault
- ) {
- ScreenType type = new ScreenType(id, screenClass, priority, category, enabledByDefault);
-
- EXACT_MATCH_CACHE.put(screenClass, type);
-
- HIERARCHY_LIST.removeIf(t -> t.getId().equals(id));
- HIERARCHY_LIST.add(type);
- HIERARCHY_LIST.sort(Comparator.comparingInt(ScreenType::getPriority).reversed());
- }
-
- /**
- * Finds a ScreenType for a runtime screen instance.
- *
- * Resolution order:
- *
- * - Exact class match (fast path)
- * - Assignable-from hierarchy scan
- * - Fallback to OTHER
- *
- */
- public static ScreenType from(Screen screen) {
- if (screen == null) return OTHER;
-
- Class extends Screen> screenClass = screen.getClass();
-
- ScreenType exact = EXACT_MATCH_CACHE.get(screenClass);
- if (exact != null) return exact;
-
- for (ScreenType type : HIERARCHY_LIST) {
- if (type.getScreenClass().isAssignableFrom(screenClass)) {
- EXACT_MATCH_CACHE.put(screenClass, type);
- return type;
- }
- }
-
- return OTHER;
- }
-
- /**
- * Returns all registered screen types (read-only view).
- */
- public static Collection getRegisteredTypes() {
- return Collections.unmodifiableList(HIERARCHY_LIST);
- }
-}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/config/UIElementCategory.java b/common/src/main/java/net/weyne1/easegui/client/config/UIElementCategory.java
deleted file mode 100644
index 996dc55..0000000
--- a/common/src/main/java/net/weyne1/easegui/client/config/UIElementCategory.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.weyne1.easegui.client.config;
-
-import java.util.EnumSet;
-
-public enum UIElementCategory {
- BUTTON_LIKE(EnumSet.allOf(ProfileFeature.class)),
- TEXT(EnumSet.of(ProfileFeature.OFFSET, ProfileFeature.SCALE, ProfileFeature.ALPHA, ProfileFeature.PIVOT)),
- SCROLLABLE(EnumSet.of(ProfileFeature.OFFSET, ProfileFeature.SCALE, ProfileFeature.ALPHA)),
- LIST_ENTRY(EnumSet.allOf(ProfileFeature.class)),
- CONTAINERS(EnumSet.of(ProfileFeature.OFFSET, ProfileFeature.SCALE, ProfileFeature.ALPHA, ProfileFeature.PIVOT)),
- UNKNOWN(EnumSet.noneOf(ProfileFeature.class));
-
- private final EnumSet allowedFeatures;
-
- UIElementCategory(EnumSet allowedFeatures) {
- this.allowedFeatures = allowedFeatures;
- }
-
- public EnumSet getAllowedFeatures() {
- return EnumSet.copyOf(this.allowedFeatures);
- }
-}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/accessor/ContainerScreenAccessor.java b/common/src/main/java/net/weyne1/easegui/client/extension/ContainerScreenExtension.java
similarity index 58%
rename from common/src/main/java/net/weyne1/easegui/client/accessor/ContainerScreenAccessor.java
rename to common/src/main/java/net/weyne1/easegui/client/extension/ContainerScreenExtension.java
index a2bc48e..3eb953f 100644
--- a/common/src/main/java/net/weyne1/easegui/client/accessor/ContainerScreenAccessor.java
+++ b/common/src/main/java/net/weyne1/easegui/client/extension/ContainerScreenExtension.java
@@ -1,6 +1,6 @@
-package net.weyne1.easegui.client.accessor;
+package net.weyne1.easegui.client.extension;
-public interface ContainerScreenAccessor {
+public interface ContainerScreenExtension {
int easeGUI$getLeftPos();
int easeGUI$getTopPos();
int easeGUI$getImageWidth();
diff --git a/common/src/main/java/net/weyne1/easegui/client/extension/ItemExtension.java b/common/src/main/java/net/weyne1/easegui/client/extension/ItemExtension.java
new file mode 100644
index 0000000..ff4084b
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/extension/ItemExtension.java
@@ -0,0 +1,5 @@
+package net.weyne1.easegui.client.extension;
+
+public interface ItemExtension {
+ float easegui$getAlpha();
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/extension/RecipeBookComponentExtension.java b/common/src/main/java/net/weyne1/easegui/client/extension/RecipeBookComponentExtension.java
new file mode 100644
index 0000000..eb57916
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/extension/RecipeBookComponentExtension.java
@@ -0,0 +1,7 @@
+package net.weyne1.easegui.client.extension;
+
+public interface RecipeBookComponentExtension {
+ boolean easeGUI$isVisible();
+ int easeGUI$getXOrigin();
+ int easeGUI$getYOrigin();
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/extension/RecipeBookScreenExtension.java b/common/src/main/java/net/weyne1/easegui/client/extension/RecipeBookScreenExtension.java
new file mode 100644
index 0000000..9e5e1dd
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/extension/RecipeBookScreenExtension.java
@@ -0,0 +1,7 @@
+package net.weyne1.easegui.client.extension;
+
+import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
+
+public interface RecipeBookScreenExtension {
+ RecipeBookComponent> easeGUI$getRecipeBookComponent();
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/extension/WidgetExtension.java b/common/src/main/java/net/weyne1/easegui/client/extension/WidgetExtension.java
new file mode 100644
index 0000000..3e0cc9c
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/extension/WidgetExtension.java
@@ -0,0 +1,9 @@
+package net.weyne1.easegui.client.extension;
+
+import net.weyne1.easegui.api.WidgetCategory;
+
+public interface WidgetExtension {
+ WidgetCategory easeGUI$getCategory();
+
+ float easeGUI$getAlpha();
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/FieldValidator.java b/common/src/main/java/net/weyne1/easegui/client/gui/components/FieldValidator.java
similarity index 92%
rename from common/src/main/java/net/weyne1/easegui/client/gui/FieldValidator.java
rename to common/src/main/java/net/weyne1/easegui/client/gui/components/FieldValidator.java
index de2f9be..d5b0449 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/FieldValidator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/components/FieldValidator.java
@@ -1,4 +1,4 @@
-package net.weyne1.easegui.client.gui;
+package net.weyne1.easegui.client.gui.components;
import net.minecraft.client.gui.components.EditBox;
@@ -9,8 +9,8 @@ public class FieldValidator {
public static final String REGEX_INT = "\\d*";
public static final String REGEX_FLOAT = "-?\\d*\\.?\\d*";
- private static final int COLOR_VALID = 0xE0E0E0;
- private static final int COLOR_INVALID = 0xFF5555;
+ private static final int COLOR_VALID = 0xFFE0E0E0;
+ private static final int COLOR_INVALID = 0xFFFF5555;
public static void registerLongValidator(EditBox editBox, long min, long max, Consumer onSuccess) {
editBox.setFilter(s -> s.matches(REGEX_INT));
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/components/SettingsScrollList.java b/common/src/main/java/net/weyne1/easegui/client/gui/components/SettingsScrollList.java
index 817fe16..7d336a5 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/components/SettingsScrollList.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/components/SettingsScrollList.java
@@ -1,6 +1,5 @@
package net.weyne1.easegui.client.gui.components;
-import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
@@ -11,6 +10,7 @@
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NonNull;
import java.util.List;
@@ -32,21 +32,13 @@ public int getRowWidth() {
return Math.min(this.width - 40, MAX_ROW_WIDTH);
}
- @Override
- protected int getScrollbarPosition() {
- return this.getX() + this.width - 6;
- }
-
public void addHeader(String text) { this.addEntry(new HeaderEntry(text)); }
-
- public void addButton(Button btn) { this.addEntry(new ButtonEntry(btn)); }
- public void addTwoButtons(Button btn1, Button btn2) {this.addTwoButtons(btn1, btn2, 0.60f); }
+ public void addButton(Button btn) { this.addEntry(new ButtonEntry(this.getRowWidth(), btn)); }
+ public void addTwoButtons(Button btn1, Button btn2) { this.addTwoButtons(btn1, btn2, 0.60f); }
public void addTwoButtons(Button btn1, Button btn2, float firstButtonRatio) { this.addEntry(new TwoButtonsEntry(this.getRowWidth(), btn1, btn2, firstButtonRatio)); }
-
public void addField(String label, EditBox box) { this.addEntry(new FieldEntry(this.getRowWidth(), label, box)); }
public void addTwoFields(String label, EditBox box1, EditBox box2) { this.addEntry(new TwoFieldsEntry(this.getRowWidth(), label, box1, box2)); }
-
public abstract static class Entry extends ContainerObjectSelectionList.Entry { }
public static class HeaderEntry extends Entry {
@@ -57,10 +49,9 @@ public HeaderEntry(String text) {
}
@Override
- public void render(GuiGraphics gg, int index, int top, int left, int width, int height,
- int mouseX, int mouseY, boolean isHovered, float partialTick) {
+ public void renderContent(GuiGraphics gg, int mouseX, int mouseY, boolean isHovered, float partialTick) {
Font font = Minecraft.getInstance().font;
- gg.drawCenteredString(font, this.text, left + width / 2, top + (height - 9) / 2, COLOR_HEADER);
+ gg.drawCenteredString(font, this.text, this.getContentXMiddle(), this.getContentYMiddle() - 4, COLOR_HEADER);
}
@Override
@@ -72,16 +63,16 @@ public void render(GuiGraphics gg, int index, int top, int left, int width, int
public static class ButtonEntry extends Entry {
private final Button button;
- public ButtonEntry(Button button) {
+ public ButtonEntry(int listWidth, Button button) {
this.button = button;
+ this.button.setWidth(listWidth - SCROLLBAR_WIDTH_GAP);
+ this.button.setHeight(WIDGET_HEIGHT);
}
@Override
- public void render(GuiGraphics gg, int index, int top, int left, int width, int height,
- int mouseX, int mouseY, boolean isHovered, float partialTick) {
- button.setWidth(width - SCROLLBAR_WIDTH_GAP);
- button.setX(left + (SCROLLBAR_WIDTH_GAP / 2));
- button.setY(top);
+ public void renderContent(@NonNull GuiGraphics gg, int mouseX, int mouseY, boolean isHovered, float partialTick) {
+ button.setX(this.getContentX() + SCROLLBAR_WIDTH_GAP / 2);
+ button.setY(this.getContentY());
button.render(gg, mouseX, mouseY, partialTick);
}
@@ -112,13 +103,12 @@ public TwoButtonsEntry(int listWidth, Button button1, Button button2, float rati
}
@Override
- public void render(GuiGraphics gg, int index, int top, int left, int width, int height,
- int mouseX, int mouseY, boolean isHovered, float partialTick) {
- button1.setX(left + (SCROLLBAR_WIDTH_GAP / 2));
- button1.setY(top);
+ public void renderContent(@NonNull GuiGraphics gg, int mouseX, int mouseY, boolean isHovered, float partialTick) {
+ button1.setX(this.getContentX() + SCROLLBAR_WIDTH_GAP / 2);
+ button1.setY(this.getContentY());
button2.setX(button1.getX() + button1.getWidth() + ELEMENT_SPACING);
- button2.setY(top);
+ button2.setY(this.getContentY());
button1.render(gg, mouseX, mouseY, partialTick);
button2.render(gg, mouseX, mouseY, partialTick);
@@ -151,15 +141,13 @@ public FieldEntry(int listWidth, String labelText, EditBox field) {
}
@Override
- public void render(GuiGraphics gg, int index, int top, int left, int width, int height,
- int mouseX, int mouseY, boolean isHovered, float partialTick) {
- label.setX(left + (SCROLLBAR_WIDTH_GAP / 2));
- label.setY(top);
+ public void renderContent(@NonNull GuiGraphics gg, int mouseX, int mouseY, boolean isHovered, float partialTick) {
+ label.setX(this.getContentX() + SCROLLBAR_WIDTH_GAP / 2);
+ label.setY(this.getContentY());
field.setX(label.getX() + label.getWidth() + ELEMENT_SPACING);
- field.setY(top);
+ field.setY(this.getContentY());
label.render(gg, mouseX, mouseY, partialTick);
- RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
field.render(gg, mouseX, mouseY, partialTick);
}
@@ -197,19 +185,17 @@ public TwoFieldsEntry(int listWidth, String labelText, EditBox field1, EditBox f
}
@Override
- public void render(GuiGraphics gg, int index, int top, int left, int width, int height,
- int mouseX, int mouseY, boolean isHovered, float partialTick) {
- label.setX(left + (SCROLLBAR_WIDTH_GAP / 2));
- label.setY(top);
+ public void renderContent(@NonNull GuiGraphics gg, int mouseX, int mouseY, boolean isHovered, float partialTick) {
+ label.setX(this.getContentX() + SCROLLBAR_WIDTH_GAP / 2);
+ label.setY(this.getContentY());
field1.setX(label.getX() + label.getWidth() + ELEMENT_SPACING);
- field1.setY(top);
+ field1.setY(this.getContentY());
field2.setX(field1.getX() + field1.getWidth() + ELEMENT_SPACING);
- field2.setY(top);
+ field2.setY(this.getContentY());
label.render(gg, mouseX, mouseY, partialTick);
- RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
field1.render(gg, mouseX, mouseY, partialTick);
field2.render(gg, mouseX, mouseY, partialTick);
}
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/configurator/AdvancementsScreenConfigurator.java b/common/src/main/java/net/weyne1/easegui/client/gui/configurator/AdvancementsScreenConfigurator.java
index 914ad72..b550167 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/configurator/AdvancementsScreenConfigurator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/configurator/AdvancementsScreenConfigurator.java
@@ -4,7 +4,7 @@
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import net.weyne1.easegui.client.config.ConfigManager;
import net.weyne1.easegui.client.config.EaseGUIConfig;
import net.weyne1.easegui.client.config.ProfileFeature;
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/configurator/IScreenConfigurator.java b/common/src/main/java/net/weyne1/easegui/client/gui/configurator/IScreenConfigurator.java
index be66d9d..8aae04b 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/configurator/IScreenConfigurator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/configurator/IScreenConfigurator.java
@@ -5,7 +5,7 @@
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.weyne1.easegui.client.config.EaseGUIConfig;
-import net.weyne1.easegui.client.gui.FieldValidator;
+import net.weyne1.easegui.client.gui.components.FieldValidator;
import net.weyne1.easegui.client.gui.components.SettingsScrollList;
import java.util.HashMap;
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/configurator/TitleScreenConfigurator.java b/common/src/main/java/net/weyne1/easegui/client/gui/configurator/TitleScreenConfigurator.java
index 433304b..9e9351b 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/configurator/TitleScreenConfigurator.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/configurator/TitleScreenConfigurator.java
@@ -5,8 +5,9 @@
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-import net.weyne1.easegui.client.StringUtils;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.EasingType;
+import net.weyne1.easegui.client.util.StringUtils;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import net.weyne1.easegui.client.config.ConfigManager;
import net.weyne1.easegui.client.config.EaseGUIConfig;
import net.weyne1.easegui.client.config.ProfileFeature;
@@ -78,7 +79,7 @@ public void populate(SettingsScrollList list, EaseGUIConfig.ScreenSettings setti
// Интерполяция сплеша
Component easingComp = Component.literal(StringUtils.toTitleCase(splash.splashEasing));
list.addButton(Button.builder(Component.translatable("easegui.config.title.splash.easing", easingComp), btn -> {
- AnimationProfile.EasingType[] values = AnimationProfile.EasingType.values();
+ EasingType[] values = EasingType.values();
splash.splashEasing = values[(splash.splashEasing.ordinal() + 1) % values.length];
Component updatedEasing = Component.literal(StringUtils.toTitleCase(splash.splashEasing));
btn.setMessage(Component.translatable("easegui.config.title.splash.easing", updatedEasing));
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/preview/ProfilePreviewRenderer.java b/common/src/main/java/net/weyne1/easegui/client/gui/preview/ProfilePreviewRenderer.java
index 17d4e99..fb34573 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/preview/ProfilePreviewRenderer.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/preview/ProfilePreviewRenderer.java
@@ -3,10 +3,9 @@
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
-import net.weyne1.easegui.client.animation.AnimationMath;
-import net.weyne1.easegui.client.animation.AnimationProfile;
-import net.weyne1.easegui.client.animation.AnimationScope;
-import net.weyne1.easegui.client.animation.AnimationSystem;
+import net.weyne1.easegui.api.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.CascadeDirection;
+import net.weyne1.easegui.client.animation.*;
import net.weyne1.easegui.client.config.ProfileFeature;
import java.util.EnumSet;
@@ -39,10 +38,10 @@ public static void render(GuiGraphics gg, Font font, int screenWidth, int screen
boolean isCascadeActive = activeFeatures.contains(ProfileFeature.CASCADE_DELAY);
int itemCount = isCascadeActive ? 3 : 1;
- boolean isEnabled = profile.enabled;
+ boolean isEnabled = profile.isEnabled();
- boolean isHorizontal = profile.cascadeDirection == AnimationProfile.CascadeDirection.LEFT_TO_RIGHT ||
- profile.cascadeDirection == AnimationProfile.CascadeDirection.RIGHT_TO_LEFT;
+ boolean isHorizontal = profile.getCascadeDirection() == CascadeDirection.LEFT_TO_RIGHT ||
+ profile.getCascadeDirection() == CascadeDirection.RIGHT_TO_LEFT;
int boxWidth = (isHorizontal && isCascadeActive) ? 40 : 120;
@@ -64,9 +63,9 @@ private static void renderStaticBounds(GuiGraphics gg, int centerX, int centerY,
}
private static void renderAnimatedElements(GuiGraphics gg, Font font, int centerX, int centerY, AnimationProfile profile, boolean isCascade, int count, boolean isHorizontal, int boxWidth) {
- boolean isEnabled = profile.enabled;
- long duration = Math.max(profile.duration, 50L);
- long totalLoopTime = duration + (isCascade ? (2 * profile.cascadeDelay) : 0L) + LOOP_PADDING_MS;
+ boolean isEnabled = profile.isEnabled();
+ long duration = Math.max(profile.getDuration(), 50L);
+ long totalLoopTime = duration + (isCascade ? (2 * profile.getCascadeDelay()) : 0L) + LOOP_PADDING_MS;
long currentTime = isEnabled ? (System.currentTimeMillis() % totalLoopTime) : 0L;
int halfW = boxWidth / 2;
@@ -81,7 +80,7 @@ private static void renderAnimatedElements(GuiGraphics gg, Font font, int center
long itemDelay = isCascade ? calculateCascadeDelay(profile, i) : 0L;
long itemTime = currentTime - itemDelay;
float progress = itemTime >= duration ? 1.0f : (itemTime > 0 ? (float) itemTime / duration : 0.0f);
- easedProgress = profile.easing != null ? profile.easing.ease(progress) : progress;
+ easedProgress = profile.getEasing() != null ? profile.getEasing().ease(progress) : progress;
}
int targetX = getTargetX(centerX, isCascade, isHorizontal, i);
@@ -91,7 +90,7 @@ private static void renderAnimatedElements(GuiGraphics gg, Font font, int center
int y = targetY - halfH;
try (AnimationScope ignored = AnimationSystem.begin(gg, x, y, boxWidth, BOX_HEIGHT, profile, easedProgress, 1.0f)) {
- int bgAlpha = calcAlphaColor(profile.startAlpha, easedProgress);
+ int bgAlpha = calcAlphaColor(profile.getStartAlpha(), easedProgress);
int boxColor = isEnabled ? 0x353535 : 0x222222;
gg.fill(x, y, x + boxWidth, y + BOX_HEIGHT, (bgAlpha << 24) | boxColor);
@@ -99,7 +98,7 @@ private static void renderAnimatedElements(GuiGraphics gg, Font font, int center
? (isHorizontal ? CASCADE_SHORT_LABELS[i] : CASCADE_LABELS[i])
: STATIC_LABEL;
- int fontAlpha = calcAlphaColor(profile.startAlpha, easedProgress);
+ int fontAlpha = calcAlphaColor(profile.getStartAlpha(), easedProgress);
int textColor = isEnabled ? 0xE0E0E0 : 0x888888;
gg.drawCenteredString(font, label, targetX, targetY - 4, (fontAlpha << 24) | textColor);
@@ -172,10 +171,10 @@ private static int calcAlphaColor(float startAlpha, float progress) {
}
private static long calculateCascadeDelay(AnimationProfile profile, int i) {
- boolean reverse = profile.cascadeDirection == AnimationProfile.CascadeDirection.BOTTOM_TO_TOP ||
- profile.cascadeDirection == AnimationProfile.CascadeDirection.RIGHT_TO_LEFT;
+ boolean reverse = profile.getCascadeDirection() == CascadeDirection.BOTTOM_TO_TOP ||
+ profile.getCascadeDirection() == CascadeDirection.RIGHT_TO_LEFT;
int factor = reverse ? (2 - i) : i;
- return factor * profile.cascadeDelay;
+ return factor * profile.getCascadeDelay();
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/screens/EaseGUIAbstractSplitScreen.java b/common/src/main/java/net/weyne1/easegui/client/gui/screens/EaseGUIAbstractSplitScreen.java
index 0cc43bb..464b457 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/screens/EaseGUIAbstractSplitScreen.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/screens/EaseGUIAbstractSplitScreen.java
@@ -1,10 +1,12 @@
package net.weyne1.easegui.client.gui.screens;
+import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.StringWidget;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
+import org.jspecify.annotations.NonNull;
public abstract class EaseGUIAbstractSplitScreen extends Screen {
protected final Screen parent;
@@ -13,7 +15,6 @@ public abstract class EaseGUIAbstractSplitScreen extends Screen {
protected int listHeight;
protected int leftX;
protected int rightX;
- protected int stringColor;
private static final int LINE_COLOR = 0x33FFFFFF;
@@ -32,34 +33,35 @@ protected void init() {
this.leftX = 0;
this.rightX = halfWidth;
- this.stringColor = 0xAAAAAA;
-
initScreen();
// Главный заголовок экрана (в самом верху по центру)
- StringWidget titleWidget = new StringWidget(this.title, this.font);
+ Component titleColored = this.title.copy().withStyle(ChatFormatting.WHITE);
+ StringWidget titleWidget = new StringWidget(titleColored, this.font);
+
titleWidget.setX(this.halfWidth - titleWidget.getWidth() / 2);
titleWidget.setY(15);
- titleWidget.setColor(0xFFFFFF);
this.addRenderableWidget(titleWidget);
// Левый подзаголовок
Component leftSub = getLeftSubtitle();
if (leftSub != null) {
- StringWidget leftSubWidget = new StringWidget(leftSub, this.font);
+ Component leftSubColored = leftSub.copy().withStyle(ChatFormatting.GRAY);
+ StringWidget leftSubWidget = new StringWidget(leftSubColored, this.font);
+
leftSubWidget.setX((this.halfWidth / 2) - (leftSubWidget.getWidth() / 2));
leftSubWidget.setY(35);
- leftSubWidget.setColor(this.stringColor);
this.addRenderableWidget(leftSubWidget);
}
// Правый подзаголовок
Component rightSub = getRightSubtitle();
if (rightSub != null) {
- StringWidget rightSubWidget = new StringWidget(rightSub, this.font);
+ Component rightSubColored = rightSub.copy().withStyle(ChatFormatting.GRAY);
+ StringWidget rightSubWidget = new StringWidget(rightSubColored, this.font);
+
rightSubWidget.setX((this.halfWidth + (this.halfWidth / 2)) - (rightSubWidget.getWidth() / 2));
rightSubWidget.setY(35);
- rightSubWidget.setColor(this.stringColor);
this.addRenderableWidget(rightSubWidget);
}
}
@@ -73,7 +75,7 @@ protected void init() {
protected void renderOverlay(GuiGraphics gg, int mouseX, int mouseY, float partialTick) {}
@Override
- public void render(GuiGraphics gg, int mouseX, int mouseY, float partialTick) {
+ public void render(@NonNull GuiGraphics gg, int mouseX, int mouseY, float partialTick) {
super.render(gg, mouseX, mouseY, partialTick);
// Вертикальный разделитель по центру экрана
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/screens/MainConfigScreen.java b/common/src/main/java/net/weyne1/easegui/client/gui/screens/MainConfigScreen.java
index 7ae6bf3..5debbc7 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/screens/MainConfigScreen.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/screens/MainConfigScreen.java
@@ -5,9 +5,13 @@
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.WidgetCategory;
+import net.weyne1.easegui.api.EaseGUIScreenRegistry;
+import net.weyne1.easegui.api.EaseGUIScreenGroup;
+import net.weyne1.easegui.api.EaseGUIScreenType;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import net.weyne1.easegui.client.config.*;
-import net.weyne1.easegui.client.gui.FieldValidator;
+import net.weyne1.easegui.client.gui.components.FieldValidator;
import net.weyne1.easegui.client.gui.components.SettingsScrollList;
import java.util.Comparator;
@@ -77,11 +81,11 @@ protected void initScreen() {
leftList.addHeader(Component.translatable("easegui.config.title.elements").getString());
- addGlobalProfileButton(leftList, config, mc, UIElementCategory.BUTTON_LIKE, "easegui.main.button.button_like");
- addGlobalProfileButton(leftList, config, mc, UIElementCategory.TEXT, "easegui.main.button.text");
- addGlobalProfileButton(leftList, config, mc, UIElementCategory.SCROLLABLE, "easegui.main.button.scrollable");
- addGlobalProfileButton(leftList, config, mc, UIElementCategory.LIST_ENTRY, "easegui.main.button.list_entry");
- addGlobalProfileButton(leftList, config, mc, UIElementCategory.CONTAINERS, "easegui.main.button.containers");
+ addGlobalProfileButton(leftList, config, mc, WidgetCategory.BUTTON_LIKE, "easegui.main.button.button_like");
+ addGlobalProfileButton(leftList, config, mc, WidgetCategory.TEXT, "easegui.main.button.text");
+ addGlobalProfileButton(leftList, config, mc, WidgetCategory.SCROLLABLE, "easegui.main.button.scrollable");
+ addGlobalProfileButton(leftList, config, mc, WidgetCategory.LIST_ENTRY, "easegui.main.button.list_entry");
+ addGlobalProfileButton(leftList, config, mc, WidgetCategory.CONTAINERS, "easegui.main.button.containers");
this.addRenderableWidget(leftList);
@@ -91,8 +95,8 @@ protected void initScreen() {
rightList.setX(rightX);
rightList.setY(50);
- for (ScreenGroup category : ScreenGroup.values()) {
- List categoryScreens = EaseGUIScreenRegistry.getRegisteredTypes().stream()
+ for (EaseGUIScreenGroup category : EaseGUIScreenGroup.values()) {
+ List categoryScreens = EaseGUIScreenRegistry.getRegisteredTypes().stream()
.filter(type -> type.getGroup() == category)
.sorted(Comparator.comparing(type -> type.getDisplayName().getString()))
.toList();
@@ -100,7 +104,7 @@ protected void initScreen() {
if (!categoryScreens.isEmpty()) {
rightList.addHeader(Component.translatable(category.getTranslationKey()).getString());
- for (ScreenType type : categoryScreens) {
+ for (EaseGUIScreenType type : categoryScreens) {
rightList.addButton(Button.builder(
type.getDisplayName(),
b -> mc.setScreen(new ScreenSpecificConfigScreen(this, type))
@@ -124,7 +128,7 @@ protected void initScreen() {
).bounds(halfWidth - 100, this.height - 30, 200, 20).build());
}
- private void addGlobalProfileButton(SettingsScrollList list, EaseGUIConfig config, Minecraft mc, UIElementCategory category, String translationKey) {
+ private void addGlobalProfileButton(SettingsScrollList list, EaseGUIConfig config, Minecraft mc, WidgetCategory category, String translationKey) {
AnimationProfile cleanDefault = new EaseGUIConfig().global.elementProfiles.get(category);
if (cleanDefault == null) cleanDefault = new AnimationProfile();
AnimationProfile finalCleanDefault = cleanDefault;
@@ -145,7 +149,6 @@ private void addGlobalProfileButton(SettingsScrollList list, EaseGUIConfig confi
}
private EditBox createTextField(String value) {
- assert this.minecraft != null;
EditBox editBox = new EditBox(this.minecraft.font, 0, 0, 60, 16, Component.empty());
editBox.setValue(value);
return editBox;
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/screens/ProfileEditorScreen.java b/common/src/main/java/net/weyne1/easegui/client/gui/screens/ProfileEditorScreen.java
index a4129ac..89896fb 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/screens/ProfileEditorScreen.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/screens/ProfileEditorScreen.java
@@ -5,10 +5,13 @@
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-import net.weyne1.easegui.client.StringUtils;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.animation.CascadeDirection;
+import net.weyne1.easegui.api.animation.EasingType;
+import net.weyne1.easegui.api.animation.PivotPoint;
+import net.weyne1.easegui.client.util.StringUtils;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import net.weyne1.easegui.client.config.ProfileFeature;
-import net.weyne1.easegui.client.gui.FieldValidator;
+import net.weyne1.easegui.client.gui.components.FieldValidator;
import net.weyne1.easegui.client.gui.components.SettingsScrollList;
import net.weyne1.easegui.client.gui.preview.ProfilePreviewRenderer;
@@ -42,12 +45,12 @@ protected void initScreen() {
leftScrollList.setY(50);
// --- 0. Переключатель "Включено / Выключено" + кнопка "Reset" ---
- Component statusComp = workingCopy.enabled ? Component.translatable("easegui.generic.on") : Component.translatable("easegui.generic.off");
+ Component statusComp = workingCopy.isEnabled() ? Component.translatable("easegui.generic.on") : Component.translatable("easegui.generic.off");
Button toggleBtn = Button.builder(
Component.translatable("easegui.editor.button.enabled", statusComp),
button -> {
- workingCopy.enabled(!workingCopy.enabled);
- Component newStatus = workingCopy.enabled ? Component.translatable("easegui.generic.on") : Component.translatable("easegui.generic.off");
+ workingCopy.enabled(!workingCopy.isEnabled());
+ Component newStatus = workingCopy.isEnabled() ? Component.translatable("easegui.generic.on") : Component.translatable("easegui.generic.off");
button.setMessage(Component.translatable("easegui.editor.button.enabled", newStatus));
}
).build();
@@ -56,25 +59,23 @@ protected void initScreen() {
Component.translatable("easegui.generic.reset"),
button -> {
applyProfileValues(this.workingCopy, this.defaultProfile);
- if (this.minecraft != null) {
- this.init(this.minecraft, this.width, this.height);
- }
+ this.init(this.width, this.height);
}
).build();
leftScrollList.addTwoButtons(toggleBtn, resetBtn, 0.70f);
// --- 1. Длительность (Лимит: от 0 до 5000 мс) ---
- EditBox durationField = createTextField(String.valueOf(workingCopy.duration));
+ EditBox durationField = createTextField(String.valueOf(workingCopy.getDuration()));
FieldValidator.registerLongValidator(durationField, 0L, 5000L, workingCopy::duration);
leftScrollList.addField(Component.translatable("easegui.editor.field.duration").getString(), durationField);
// --- 2. Смещение (Лимит: от -1000 до 1000 пикселей) ---
if (activeFeatures.contains(ProfileFeature.OFFSET)) {
- EditBox ox = createTextField(String.valueOf(workingCopy.offset.x));
+ EditBox ox = createTextField(String.valueOf(workingCopy.getOffsetX()));
FieldValidator.registerFloatValidator(ox, -1000f, 1000f, workingCopy::offsetX);
- EditBox oy = createTextField(String.valueOf(workingCopy.offset.y));
+ EditBox oy = createTextField(String.valueOf(workingCopy.getOffsetY()));
FieldValidator.registerFloatValidator(oy, -1000f, 1000f, workingCopy::offsetY);
leftScrollList.addTwoFields(Component.translatable("easegui.editor.field.offset").getString(), ox, oy);
@@ -82,10 +83,10 @@ protected void initScreen() {
// --- 3. Масштаб (Лимит: от 0.0 до 10.0 крат) ---
if (activeFeatures.contains(ProfileFeature.SCALE)) {
- EditBox sx = createTextField(String.valueOf(workingCopy.startScale.x));
+ EditBox sx = createTextField(String.valueOf(workingCopy.getStartScaleX()));
FieldValidator.registerFloatValidator(sx, 0.0f, 10.0f, workingCopy::startScaleX);
- EditBox sy = createTextField(String.valueOf(workingCopy.startScale.y));
+ EditBox sy = createTextField(String.valueOf(workingCopy.getStartScaleY()));
FieldValidator.registerFloatValidator(sy, 0.0f, 10.0f, workingCopy::startScaleY);
leftScrollList.addTwoFields(Component.translatable("easegui.editor.field.scale").getString(), sx, sy);
@@ -93,47 +94,47 @@ protected void initScreen() {
// --- 4. Прозрачность (Лимит: от 0.0 до 1.0) ---
if (activeFeatures.contains(ProfileFeature.ALPHA)) {
- EditBox alphaField = createTextField(String.valueOf(workingCopy.startAlpha));
+ EditBox alphaField = createTextField(String.valueOf(workingCopy.getStartAlpha()));
FieldValidator.registerFloatValidator(alphaField, 0.0f, 1.0f, workingCopy::startAlpha);
leftScrollList.addField(Component.translatable("easegui.editor.field.alpha").getString(), alphaField);
}
// --- 5. Каскадность (Лимит: от 0 до 1000 мс) ---
if (activeFeatures.contains(ProfileFeature.CASCADE_DELAY)) {
- EditBox cascadeField = createTextField(String.valueOf(workingCopy.cascadeDelay));
+ EditBox cascadeField = createTextField(String.valueOf(workingCopy.getCascadeDelay()));
FieldValidator.registerLongValidator(cascadeField, 0L, 1000L, workingCopy::cascadeDelay);
leftScrollList.addField(Component.translatable("easegui.editor.field.cascade_delay").getString(), cascadeField);
}
// --- 5.1. Направление каскада
if (activeFeatures.contains(ProfileFeature.CASCADE_DIRECTION)) {
- Component dirComp = getCascadeDirectionComponent(workingCopy.cascadeDirection);
+ Component dirComp = getCascadeDirectionComponent(workingCopy.getCascadeDirection());
leftScrollList.addButton(Button.builder(Component.translatable("easegui.editor.button.cascade_dir", dirComp), b -> {
- AnimationProfile.CascadeDirection[] v = AnimationProfile.CascadeDirection.values();
- workingCopy.cascadeDirection(v[(workingCopy.cascadeDirection.ordinal() + 1) % v.length]);
- b.setMessage(Component.translatable("easegui.editor.button.cascade_dir", getCascadeDirectionComponent(workingCopy.cascadeDirection)));
+ CascadeDirection[] v = CascadeDirection.values();
+ workingCopy.cascadeDirection(v[(workingCopy.getCascadeDirection().ordinal() + 1) % v.length]);
+ b.setMessage(Component.translatable("easegui.editor.button.cascade_dir", getCascadeDirectionComponent(workingCopy.getCascadeDirection())));
}).build());
}
// --- 6. Точка опоры (Pivot) ---
if (activeFeatures.contains(ProfileFeature.PIVOT)) {
- Component pivotComp = Component.translatable("easegui.pivot." + workingCopy.pivot.name().toLowerCase());
+ Component pivotComp = Component.translatable("easegui.pivot." + workingCopy.getPivot().name().toLowerCase());
leftScrollList.addButton(Button.builder(Component.translatable("easegui.editor.button.pivot", pivotComp), b -> {
- AnimationProfile.PivotPoint[] v = AnimationProfile.PivotPoint.values();
- workingCopy.pivot(v[(workingCopy.pivot.ordinal() + 1) % v.length]);
- Component updatedPivot = Component.translatable("easegui.pivot." + workingCopy.pivot.name().toLowerCase());
+ PivotPoint[] v = PivotPoint.values();
+ workingCopy.pivot(v[(workingCopy.getPivot().ordinal() + 1) % v.length]);
+ Component updatedPivot = Component.translatable("easegui.pivot." + workingCopy.getPivot().name().toLowerCase());
b.setMessage(Component.translatable("easegui.editor.button.pivot", updatedPivot));
}).build());
}
// --- 7. Интерполяция (Easing) ---
- Component easingComp = Component.literal(StringUtils.toTitleCase(workingCopy.easing));
+ Component easingComp = Component.literal(StringUtils.toTitleCase(workingCopy.getEasing()));
leftScrollList.addButton(Button.builder(
Component.translatable("easegui.editor.button.easing", easingComp),
button -> {
- AnimationProfile.EasingType[] values = AnimationProfile.EasingType.values();
- workingCopy.easing(values[(workingCopy.easing.ordinal() + 1) % values.length]);
- Component updatedEasing = Component.literal(StringUtils.toTitleCase(workingCopy.easing));
+ EasingType[] values = EasingType.values();
+ workingCopy.easing(values[(workingCopy.getEasing().ordinal() + 1) % values.length]);
+ Component updatedEasing = Component.literal(StringUtils.toTitleCase(workingCopy.getEasing()));
button.setMessage(Component.translatable("easegui.editor.button.easing", updatedEasing));
}
).build());
@@ -146,13 +147,12 @@ protected void initScreen() {
}
private EditBox createTextField(String value) {
- assert this.minecraft != null;
EditBox editBox = new EditBox(this.minecraft.font, 0, 0, 60, 16, Component.empty());
editBox.setValue(value);
return editBox;
}
- private Component getCascadeDirectionComponent(AnimationProfile.CascadeDirection dir) {
+ private Component getCascadeDirectionComponent(CascadeDirection dir) {
return Component.translatable(switch (dir) {
case TOP_TO_BOTTOM -> "easegui.cascade.top_to_bottom";
case BOTTOM_TO_TOP -> "easegui.cascade.bottom_to_top";
@@ -180,14 +180,14 @@ private AnimationProfile cloneProfile(AnimationProfile s) {
private AnimationProfile applyProfileValues(AnimationProfile target, AnimationProfile source) {
return target
- .enabled(source.enabled)
- .duration(source.duration)
- .offset(source.offset.x, source.offset.y)
- .startScale(source.startScale.x, source.startScale.y)
- .startAlpha(source.startAlpha)
- .cascadeDelay(source.cascadeDelay)
- .easing(source.easing)
- .pivot(source.pivot)
- .cascadeDirection(source.cascadeDirection);
+ .enabled(source.isEnabled())
+ .duration(source.getDuration())
+ .offset(source.getOffsetX(), source.getOffsetY())
+ .startScale(source.getStartScaleX(), source.getStartScaleY())
+ .startAlpha(source.getStartAlpha())
+ .cascadeDelay(source.getCascadeDelay())
+ .easing(source.getEasing())
+ .pivot(source.getPivot())
+ .cascadeDirection(source.getCascadeDirection());
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/gui/screens/ScreenSpecificConfigScreen.java b/common/src/main/java/net/weyne1/easegui/client/gui/screens/ScreenSpecificConfigScreen.java
index 49b8be5..82912a5 100644
--- a/common/src/main/java/net/weyne1/easegui/client/gui/screens/ScreenSpecificConfigScreen.java
+++ b/common/src/main/java/net/weyne1/easegui/client/gui/screens/ScreenSpecificConfigScreen.java
@@ -6,7 +6,9 @@
import net.minecraft.client.gui.components.StringWidget;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-import net.weyne1.easegui.client.animation.AnimationProfile;
+import net.weyne1.easegui.api.WidgetCategory;
+import net.weyne1.easegui.api.EaseGUIScreenType;
+import net.weyne1.easegui.api.animation.AnimationProfile;
import net.weyne1.easegui.client.config.*;
import net.weyne1.easegui.client.gui.components.SettingsScrollList;
import net.weyne1.easegui.client.gui.configurator.IScreenConfigurator;
@@ -15,9 +17,9 @@
import java.util.EnumSet;
public class ScreenSpecificConfigScreen extends EaseGUIAbstractSplitScreen {
- private final ScreenType screenType;
+ private final EaseGUIScreenType screenType;
- public ScreenSpecificConfigScreen(Screen parent, ScreenType type) {
+ public ScreenSpecificConfigScreen(Screen parent, EaseGUIScreenType type) {
super(type.getDisplayName(), parent);
this.screenType = type;
}
@@ -63,11 +65,12 @@ protected void initScreen() {
this.addRenderableWidget(warningWidget);
} else {
- StringWidget noOptionsWidget = new StringWidget(Component.translatable("easegui.gui.no_unique_options"), this.font);
+ Component noOptionsText = Component.translatable("easegui.gui.no_unique_options")
+ .withStyle(style -> style.withColor(0x55FFFFFF));
+ StringWidget noOptionsWidget = new StringWidget(noOptionsText, this.font);
int leftBlockCenterX = leftX + (listWidth / 2);
noOptionsWidget.setX(leftBlockCenterX - (noOptionsWidget.getWidth() / 2));
noOptionsWidget.setY(this.height / 2 - 4);
- noOptionsWidget.setColor(0x55FFFFFF);
this.addRenderableWidget(noOptionsWidget);
}
}
@@ -106,9 +109,9 @@ protected void initScreen() {
}
private void setupCategoryButtons(SettingsScrollList rightScrollList, EaseGUIConfig.ScreenSettings settings, EaseGUIConfig config) {
- EnumSet overridableCategories = EnumSet.complementOf(EnumSet.of(UIElementCategory.UNKNOWN));
+ EnumSet overridableCategories = EnumSet.complementOf(EnumSet.of(WidgetCategory.UNKNOWN));
- for (UIElementCategory category : overridableCategories) {
+ for (WidgetCategory category : overridableCategories) {
boolean hasCustom = settings.customProfiles.containsKey(category);
Component categoryLabel = Component.translatable("easegui.category." + category.name().toLowerCase());
@@ -156,14 +159,14 @@ private AnimationProfile cloneProfile(AnimationProfile src) {
AnimationProfile dest = new AnimationProfile();
if (src == null) return dest;
return dest
- .enabled(src.enabled)
- .duration(src.duration)
- .offset(src.offset.x, src.offset.y)
- .startScale(src.startScale.x, src.startScale.y)
- .startAlpha(src.startAlpha)
- .cascadeDelay(src.cascadeDelay)
- .easing(src.easing)
- .pivot(src.pivot)
- .cascadeDirection(src.cascadeDirection);
+ .enabled(src.isEnabled())
+ .duration(src.getDuration())
+ .offset(src.getOffsetX(), src.getOffsetY())
+ .startScale(src.getStartScaleX(), src.getStartScaleY())
+ .startAlpha(src.getStartAlpha())
+ .cascadeDelay(src.getCascadeDelay())
+ .easing(src.getEasing())
+ .pivot(src.getPivot())
+ .cascadeDirection(src.getCascadeDirection());
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/GameRendererMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/GameRendererMixin.java
index bee4a7d..672f0d5 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/GameRendererMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/GameRendererMixin.java
@@ -3,34 +3,15 @@
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.renderer.GameRenderer;
import net.weyne1.easegui.client.animation.AnimationContext;
-import net.weyne1.easegui.client.animator.BackgroundAnimator;
-import net.weyne1.easegui.client.config.ConfigManager;
-import net.weyne1.easegui.client.state.ScreenAnimationTracker;
import net.weyne1.easegui.client.state.ScreenStateTracker;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
public class GameRendererMixin {
- @ModifyArg(
- method = "processBlurEffect",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/PostChain;setUniform(Ljava/lang/String;F)V"),
- index = 1
- )
- private float easeGUI$animateBlurRadiusArg(float originalRadius) {
- boolean enableSmoothBlur = ConfigManager.getConfig().global.enableSmoothBlur;
-
- if (!enableSmoothBlur || BackgroundAnimator.skipBackgroundFade) {
- return originalRadius;
- }
-
- return originalRadius * ScreenAnimationTracker.getProgress();
- }
-
@Inject(method = "render", at = @At("HEAD"))
private void easeGUI$onFrameStart(DeltaTracker deltaTracker, boolean renderLevel, CallbackInfo ci) {
ScreenStateTracker.incrementFrame();
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/MinecraftMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/MinecraftMixin.java
index 75b5968..d53b874 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/MinecraftMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/MinecraftMixin.java
@@ -18,13 +18,13 @@ public class MinecraftMixin {
private void easeGUI$onScreenTransition(Screen guiScreen, CallbackInfo ci) {
Screen oldScreen = this.screen;
- if (BackgroundAnimator.isLoadingScreen(guiScreen)) {
+ if (!BackgroundAnimator.shouldAnimateBackground(guiScreen)) {
BackgroundAnimator.skipBackgroundFade = true;
return;
}
- boolean wasBlurred = BackgroundAnimator.isScreenBlurred(oldScreen);
- boolean willBeBlurred = BackgroundAnimator.isScreenBlurred(guiScreen);
+ boolean wasBlurred = BackgroundAnimator.shouldAnimateBackground(oldScreen);
+ boolean willBeBlurred = BackgroundAnimator.shouldAnimateBackground(guiScreen);
BackgroundAnimator.skipBackgroundFade = wasBlurred && willBeBlurred;
}
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/OptionsMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/OptionsMixin.java
new file mode 100644
index 0000000..0dd3c6e
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/OptionsMixin.java
@@ -0,0 +1,28 @@
+package net.weyne1.easegui.client.mixin;
+
+import net.minecraft.client.Options;
+import net.weyne1.easegui.client.animator.BackgroundAnimator;
+import net.weyne1.easegui.client.config.ConfigManager;
+import net.weyne1.easegui.client.state.ScreenAnimationTracker;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(Options.class)
+public class OptionsMixin {
+
+ @Inject(method = "getMenuBackgroundBlurriness", at = @At("RETURN"), cancellable = true)
+ private void easeGUI$animateMenuBlurriness(CallbackInfoReturnable cir) {
+ boolean enableSmoothBlur = ConfigManager.getConfig().global.enableSmoothBlur;
+
+ if (!enableSmoothBlur || BackgroundAnimator.skipBackgroundFade) {
+ return;
+ }
+
+ int originalValue = cir.getReturnValue();
+ int animatedValue = Math.round(originalValue * ScreenAnimationTracker.getProgress());
+
+ cir.setReturnValue(animatedValue);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/blaze3d/VertexBufferMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/blaze3d/VertexBufferMixin.java
deleted file mode 100644
index b415748..0000000
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/blaze3d/VertexBufferMixin.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package net.weyne1.easegui.client.mixin.blaze3d;
-
-import com.mojang.blaze3d.systems.RenderSystem;
-import com.mojang.blaze3d.vertex.VertexBuffer;
-import net.minecraft.client.renderer.ShaderInstance;
-import net.weyne1.easegui.client.animation.AnimationContext;
-import org.joml.Matrix4f;
-import org.lwjgl.opengl.GL11;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Unique;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-@Mixin(VertexBuffer.class)
-public class VertexBufferMixin {
- @Unique private float easeGUI$savedR;
- @Unique private float easeGUI$savedG;
- @Unique private float easeGUI$savedB;
- @Unique private float easeGUI$savedA;
- @Unique private boolean easeGUI$hasSavedColor = false;
- @Unique private boolean easeGUI$wasBlendEnabled;
-
- @Inject(method = "_drawWithShader", at = @At("HEAD"))
- private void easeGUI$injectAlphaBeforeShader(Matrix4f modelViewMatrix, Matrix4f projectionMatrix, ShaderInstance shader, CallbackInfo ci) {
- if (AnimationContext.isAnimating()) {
- float[] currentColor = RenderSystem.getShaderColor();
-
- this.easeGUI$savedR = currentColor[0];
- this.easeGUI$savedG = currentColor[1];
- this.easeGUI$savedB = currentColor[2];
- this.easeGUI$savedA = currentColor[3];
- this.easeGUI$hasSavedColor = true;
-
- this.easeGUI$wasBlendEnabled = GL11.glIsEnabled(GL11.GL_BLEND);
-
- float animationAlpha = AnimationContext.getCurrentAlpha();
- float finalAlpha = this.easeGUI$savedA * animationAlpha;
-
- if (!this.easeGUI$wasBlendEnabled && finalAlpha < 1.0f) {
- RenderSystem.enableBlend();
- RenderSystem.defaultBlendFunc();
- }
-
- RenderSystem.setShaderColor(this.easeGUI$savedR, this.easeGUI$savedG, this.easeGUI$savedB, finalAlpha);
- }
- }
-
- @Inject(method = "_drawWithShader", at = @At("TAIL"))
- private void easeGUI$restoreAlphaAfterShader(Matrix4f modelViewMatrix, Matrix4f projectionMatrix, ShaderInstance shader, CallbackInfo ci) {
- if (this.easeGUI$hasSavedColor) {
- RenderSystem.setShaderColor(this.easeGUI$savedR, this.easeGUI$savedG, this.easeGUI$savedB, this.easeGUI$savedA);
-
- if (!this.easeGUI$wasBlendEnabled) {
- RenderSystem.disableBlend();
- }
-
- this.easeGUI$hasSavedColor = false;
- }
- }
-}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/compat/EmiCompatMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/compat/EmiCompatMixin.java
index 36e3039..974b73d 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/compat/EmiCompatMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/compat/EmiCompatMixin.java
@@ -1,12 +1,10 @@
package net.weyne1.easegui.client.mixin.compat;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.screens.Screen;
-import net.weyne1.easegui.client.accessor.ScreenAnimationAccessor;
+import net.weyne1.easegui.client.animation.AnimationContext;
import net.weyne1.easegui.client.animation.AnimationScope;
+import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
-import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -19,26 +17,17 @@
@Mixin(targets = "dev.emi.emi.screen.EmiScreenManager", remap = false)
public class EmiCompatMixin {
- @Unique
- private static AnimationScope easeGUI$getCurrentScope() {
- Screen currentScreen = Minecraft.getInstance().screen;
- if (currentScreen instanceof ScreenAnimationAccessor accessor) {
- return accessor.easeGUI$getContainerScope();
- }
- return null;
- }
-
+ @Dynamic
@Inject(method = {"render", "drawBackground", "drawForeground"}, at = @At("HEAD"), require = 0)
private static void easeGUI$onEmiRenderStart(CallbackInfo ci) {
- AnimationScope scope = easeGUI$getCurrentScope();
- if (scope != null) {
- scope.suspend();
- }
+ AnimationScope scope = AnimationContext.getCurrentScope();
+ if (scope != null) scope.suspend();
}
+ @Dynamic
@Inject(method = {"render", "drawBackground", "drawForeground"}, at = @At("TAIL"), require = 0)
private static void easeGUI$onEmiRenderEnd(CallbackInfo ci) {
- AnimationScope scope = easeGUI$getCurrentScope();
+ AnimationScope scope = AnimationContext.getCurrentScope();
if (scope != null) scope.resume();
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractSelectionListMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractSelectionListMixin.java
index b54c174..0bfac78 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractSelectionListMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractSelectionListMixin.java
@@ -1,42 +1,44 @@
package net.weyne1.easegui.client.mixin.gui;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractSelectionList;
+import net.minecraft.client.gui.layouts.LayoutElement;
import net.weyne1.easegui.client.animation.AnimationContext;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animator.ListItemAnimator;
import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.Coerce;
@Mixin(AbstractSelectionList.class)
-public class AbstractSelectionListMixin {
+public abstract class AbstractSelectionListMixin {
+
+ @Shadow public abstract int getRowLeft();
+ @Shadow public abstract int getRowWidth();
+
+ @WrapOperation(
+ method = "renderListItems",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/client/gui/components/AbstractSelectionList;renderItem(Lnet/minecraft/client/gui/GuiGraphics;IIFLnet/minecraft/client/gui/components/AbstractSelectionList$Entry;)V"
+ )
+ )
+ private void easeGUI$wrapRenderItem(AbstractSelectionList> instance, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, @Coerce Object item, Operation original) {
+ LayoutElement element = (LayoutElement) item;
+ int left = this.getRowLeft();
+ int width = this.getRowWidth();
+ int top = element.getY();
+ int height = element.getHeight();
- @Unique
- private AnimationScope easeGUI$itemScope = null;
-
- @Inject(method = "renderItem", at = @At("HEAD"))
- private void easeGUI$onPreRenderItem(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick,
- int index, int left, int top, int width, int height, CallbackInfo ci) {
AnimationContext.pushParentAnimation();
- if (this.easeGUI$itemScope != null) {
- this.easeGUI$itemScope.close();
- }
-
- this.easeGUI$itemScope = ListItemAnimator.beginRender(guiGraphics, top, left, width, height);
- }
-
- @Inject(method = "renderItem", at = @At("RETURN"))
- private void easeGUI$onPostRenderItem(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick,
- int index, int left, int top, int width, int height, CallbackInfo ci) {
- if (this.easeGUI$itemScope != null) {
- this.easeGUI$itemScope.close();
- this.easeGUI$itemScope = null;
+ try (AnimationScope ignored = ListItemAnimator.beginRender(guiGraphics, top, left, width, height)) {
+ original.call(instance, guiGraphics, mouseX, mouseY, partialTick, item);
+ } finally {
+ AnimationContext.popParentAnimation();
}
-
- AnimationContext.popParentAnimation();
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractWidgetMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractWidgetMixin.java
index 2e18aa1..32422e5 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractWidgetMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AbstractWidgetMixin.java
@@ -1,30 +1,28 @@
package net.weyne1.easegui.client.mixin.gui;
-import net.minecraft.Util;
+import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import net.minecraft.util.Util;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.*;
-import net.weyne1.easegui.client.EaseGUIWidget;
+import net.weyne1.easegui.client.extension.WidgetExtension;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animation.AnimationState;
import net.weyne1.easegui.client.animator.WidgetAnimator;
import net.weyne1.easegui.client.config.ConfigManager;
-import net.weyne1.easegui.client.config.UIElementCategory;
+import net.weyne1.easegui.api.WidgetCategory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(AbstractWidget.class)
-public abstract class AbstractWidgetMixin implements EaseGUIWidget {
+public abstract class AbstractWidgetMixin implements WidgetExtension {
@Shadow protected float alpha;
@Shadow protected boolean isHovered;
- @Unique private final AnimationState.AnimationData easeGUI$animationData = new AnimationState.AnimationData();
- @Unique private UIElementCategory easeGUI$cachedCategory = null;
- @Unique private AnimationScope easeGUI$widgetScope = null;
+ @Unique private final AnimationState easeGUI$animationState = new AnimationState();
+ @Unique private WidgetCategory easeGUI$cachedCategory = null;
@Override
public float easeGUI$getAlpha() {
@@ -32,57 +30,50 @@ public abstract class AbstractWidgetMixin implements EaseGUIWidget {
}
@Override
- public UIElementCategory easeGUI$getCategory() {
+ public WidgetCategory easeGUI$getCategory() {
if (this.easeGUI$cachedCategory == null) {
- Class> clazz = this.getClass();
- if (AbstractButton.class.isAssignableFrom(clazz) || AbstractSliderButton.class.isAssignableFrom(clazz) || EditBox.class.isAssignableFrom(clazz)) {
- this.easeGUI$cachedCategory = UIElementCategory.BUTTON_LIKE;
- }
- else if (AbstractSelectionList.class.isAssignableFrom(clazz)) {
- this.easeGUI$cachedCategory = UIElementCategory.SCROLLABLE;
- }
- else if (StringWidget.class.isAssignableFrom(clazz) || MultiLineTextWidget.class.isAssignableFrom(clazz)) {
- this.easeGUI$cachedCategory = UIElementCategory.TEXT;
- }
- else {
- this.easeGUI$cachedCategory = UIElementCategory.UNKNOWN;
- }
+ this.easeGUI$cachedCategory = WidgetCategory.fromClass(this.getClass());
}
return this.easeGUI$cachedCategory;
}
- @Inject(method = "render", at = @At("HEAD"))
- private void easeGUI$onPreRender(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) {
- if (this.easeGUI$widgetScope != null) {
- this.easeGUI$widgetScope.close();
- this.easeGUI$widgetScope = null;
- }
-
+ @WrapMethod(method = "render")
+ private void easeGUI$wrapWidgetRender(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, Operation original) {
AbstractWidget widget = (AbstractWidget) (Object) this;
if (!widget.visible) {
+ original.call(guiGraphics, mouseX, mouseY, partialTick);
return;
}
var category = this.easeGUI$getCategory();
- if (category == null || category == UIElementCategory.UNKNOWN) return;
+ if (category == null || category == WidgetCategory.UNKNOWN) {
+ original.call(guiGraphics, mouseX, mouseY, partialTick);
+ return;
+ }
- this.easeGUI$widgetScope = WidgetAnimator.beginRender(widget, guiGraphics, category, this.easeGUI$animationData);
+ try (AnimationScope ignored = WidgetAnimator.beginRender(widget, guiGraphics, category, this.easeGUI$animationState)) {
- var profile = ConfigManager.getProfileForCurrentContext(category);
- if (profile != null && profile.enabled && this.easeGUI$animationData.init) {
- long elapsed = Util.getMillis() - this.easeGUI$animationData.startTime - this.easeGUI$animationData.delay;
- if (elapsed < profile.duration) {
- this.isHovered = false;
+ var profile = ConfigManager.getProfileForCurrentContext(category);
+ boolean shouldBypassHover = false;
+
+ if (profile != null && profile.isEnabled() && this.easeGUI$animationState.init) {
+ long elapsed = Util.getMillis() - this.easeGUI$animationState.startTime - this.easeGUI$animationState.delay;
+ if (elapsed < profile.getDuration()) {
+ shouldBypassHover = true;
+ }
}
- }
- }
- @Inject(method = "render", at = @At("RETURN"))
- private void easeGUI$onPostRender(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) {
- if (this.easeGUI$widgetScope != null) {
- this.easeGUI$widgetScope.close();
- this.easeGUI$widgetScope = null;
+ if (shouldBypassHover) {
+ boolean savedHover = this.isHovered;
+ this.isHovered = false;
+
+ original.call(guiGraphics, mouseX, mouseY, partialTick);
+
+ this.isHovered = savedHover;
+ } else {
+ original.call(guiGraphics, mouseX, mouseY, partialTick);
+ }
}
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AdvancementsScreenMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AdvancementsScreenMixin.java
index 3020069..d37df27 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AdvancementsScreenMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/AdvancementsScreenMixin.java
@@ -5,6 +5,7 @@
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.advancements.AdvancementTab;
import net.minecraft.client.gui.screens.advancements.AdvancementsScreen;
+import net.weyne1.easegui.client.animation.AnimationContext;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animator.AdvancementsAnimator;
import net.weyne1.easegui.client.mixin.accessor.AdvancementTabAccessor;
@@ -17,20 +18,24 @@
@Mixin(AdvancementsScreen.class)
public class AdvancementsScreenMixin {
- @Unique
- private AnimationScope easeGUI$windowScope = null;
+ @Unique private AnimationScope easeGUI$windowScope = null;
- // === АНИМАЦИЯ ГЛАВНОГО ОКНА ===
+ // Main window animation
@Inject(
method = "render",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementsScreen;renderInside(Lnet/minecraft/client/gui/GuiGraphics;IIII)V")
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementsScreen;renderInside(Lnet/minecraft/client/gui/GuiGraphics;II)V")
)
private void easeGUI$preRenderWindow(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) {
if (this.easeGUI$windowScope != null) {
this.easeGUI$windowScope.close();
+ AnimationContext.popParentAnimation();
}
this.easeGUI$windowScope = AdvancementsAnimator.beginRenderWindow((AdvancementsScreen) (Object) this, guiGraphics);
+
+ if (this.easeGUI$windowScope != null) {
+ AnimationContext.pushParentAnimation();
+ }
}
@Inject(method = "render", at = @At("RETURN"))
@@ -38,29 +43,25 @@ public class AdvancementsScreenMixin {
if (this.easeGUI$windowScope != null) {
this.easeGUI$windowScope.close();
this.easeGUI$windowScope = null;
+ AnimationContext.popParentAnimation();
}
}
- // === АНИМАЦИЯ ВКЛАДОК (ФОН) ===
+ // Tab animation (bg)
@WrapOperation(
method = "renderWindow",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementTab;drawTab(Lnet/minecraft/client/gui/GuiGraphics;IIZ)V")
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementTab;drawTab(Lnet/minecraft/client/gui/GuiGraphics;IIIIZ)V")
)
- private void easeGUI$wrapDrawTab(AdvancementTab tab, GuiGraphics guiGraphics, int offsetX, int offsetY, boolean isSelected, Operation original) {
+ private void easeGUI$wrapDrawTab(AdvancementTab tab, GuiGraphics guiGraphics, int x, int y, int mouseX, int mouseY, boolean selected, Operation original) {
AdvancementsScreen screen = (AdvancementsScreen) (Object) this;
int index = ((AdvancementTabAccessor) tab).easeGUI$getIndex();
- AnimationScope scope = AdvancementsAnimator.beginRenderTab(screen, guiGraphics, index);
- if (scope != null) {
- try (scope) {
- original.call(tab, guiGraphics, offsetX, offsetY, isSelected);
- }
- } else {
- original.call(tab, guiGraphics, offsetX, offsetY, isSelected);
+ try (AnimationScope ignored = AdvancementsAnimator.beginRenderTab(screen, guiGraphics, index)) {
+ original.call(tab, guiGraphics, x, y, mouseX, mouseY, selected);
}
}
- // === АНИМАЦИЯ ВКЛАДОК (ИКОНКИ) ===
+ // Tab animation (fg/icons)
@WrapOperation(
method = "renderWindow",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementTab;drawIcon(Lnet/minecraft/client/gui/GuiGraphics;II)V")
@@ -69,12 +70,7 @@ public class AdvancementsScreenMixin {
AdvancementsScreen screen = (AdvancementsScreen) (Object) this;
int index = ((AdvancementTabAccessor) tab).easeGUI$getIndex();
- AnimationScope scope = AdvancementsAnimator.beginRenderTab(screen, guiGraphics, index);
- if (scope != null) {
- try (scope) {
- original.call(tab, guiGraphics, offsetX, offsetY);
- }
- } else {
+ try (AnimationScope ignored = AdvancementsAnimator.beginRenderTab(screen, guiGraphics, index)) {
original.call(tab, guiGraphics, offsetX, offsetY);
}
}
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiGraphicsMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiGraphicsMixin.java
index e579264..1780077 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiGraphicsMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiGraphicsMixin.java
@@ -1,53 +1,138 @@
package net.weyne1.easegui.client.mixin.gui;
-import com.mojang.blaze3d.vertex.PoseStack;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.navigation.ScreenRectangle;
+import net.minecraft.client.gui.render.state.pip.*;
+import net.minecraft.client.model.Model;
+import net.minecraft.client.model.object.banner.BannerFlagModel;
+import net.minecraft.client.model.object.book.BookModel;
+import net.minecraft.client.model.player.PlayerModel;
+import net.minecraft.client.renderer.entity.state.EntityRenderState;
+import net.minecraft.resources.Identifier;
+import net.minecraft.world.item.DyeColor;
+import net.minecraft.world.level.block.entity.BannerPatternLayers;
+import net.minecraft.world.level.block.state.properties.WoodType;
import net.weyne1.easegui.client.animation.AnimationContext;
-import org.joml.Matrix4f;
+import net.weyne1.easegui.client.animation.PipTransform;
+import net.weyne1.easegui.client.util.ColorUtils;
+import org.joml.Quaternionf;
+import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.ModifyArgs;
-import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
+@SuppressWarnings("ModifyVariableMayUseName")
@Mixin(GuiGraphics.class)
-public abstract class GuiGraphicsMixin {
+public class GuiGraphicsMixin {
- @Shadow public abstract PoseStack pose();
+ @ModifyVariable(method = "submitColoredRectangle", at = @At("HEAD"), argsOnly = true, ordinal = 4)
+ private int easeGUI$modifyColorFrom(int colorFrom) {
+ if (!AnimationContext.isActive()) return colorFrom;
+ return ColorUtils.getAnimatedColor(colorFrom);
+ }
+
+ @ModifyVariable(method = "submitColoredRectangle", at = @At("HEAD"), argsOnly = true, ordinal = 0)
+ private Integer easeGUI$modifyColorTo(Integer colorTo) {
+ if (!AnimationContext.isActive() || colorTo == null) return colorTo;
+ return ColorUtils.getAnimatedColor(colorTo);
+ }
+
+ @ModifyVariable(method = "submitBlit", at = @At("HEAD"), argsOnly = true, ordinal = 4)
+ private int easeGUI$modifyBlitColor(int color) {
+ if (!AnimationContext.isActive()) return color;
+ return ColorUtils.getAnimatedColor(color);
+ }
+
+ @ModifyVariable(method = "submitTiledBlit", at = @At("HEAD"), argsOnly = true, ordinal = 6)
+ private int easeGUI$modifyTiledBlitColor(int color) {
+ if (!AnimationContext.isActive()) return color;
+ return ColorUtils.getAnimatedColor(color);
+ }
- @ModifyArgs(
- method = "enableScissor",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/navigation/ScreenRectangle;(IIII)V")
+ @WrapOperation(
+ method = "submitEntityRenderState",
+ at = @At(value = "NEW", target = "Lnet/minecraft/client/gui/render/state/pip/GuiEntityRenderState;")
)
- private void easeGUI$transformScissorBounds(Args args) {
- if (!AnimationContext.isAnimating()) {
- return;
- }
-
- int minX = args.get(0);
- int minY = args.get(1);
- int width = args.get(2);
- int height = args.get(3);
- int maxX = minX + width;
- int maxY = minY + height;
-
- Matrix4f matrix = this.pose().last().pose();
- float sx = matrix.m00();
- float sy = matrix.m11();
- float tx = matrix.m30();
- float ty = matrix.m31();
-
- int newMinX = Math.round(minX * sx + tx);
- int newMinY = Math.round(minY * sy + ty);
- int newMaxX = Math.round(maxX * sx + tx);
- int newMaxY = Math.round(maxY * sy + ty);
-
- int newWidth = newMaxX - newMinX;
- int newHeight = newMaxY - newMinY;
-
- args.set(0, newMinX);
- args.set(1, newMinY);
- args.set(2, Math.max(0, newWidth));
- args.set(3, Math.max(0, newHeight));
+ private GuiEntityRenderState easeGUI$transformEntity(
+ EntityRenderState renderState, Vector3f translation, Quaternionf rotation, Quaternionf overrideCameraAngle,
+ int x0, int y0, int x1, int y1, float scale, ScreenRectangle scissorArea,
+ Operation original) {
+
+ int[] xs = PipTransform.transformRangeX(x0, x1);
+ int[] ys = PipTransform.transformRangeY(y0, y1);
+
+ return original.call(
+ renderState, translation, rotation, overrideCameraAngle,
+ xs[0], ys[0], xs[1], ys[1], PipTransform.scale(scale), scissorArea
+ );
+ }
+
+ @WrapOperation(
+ method = "submitBookModelRenderState",
+ at = @At(value = "NEW", target = "Lnet/minecraft/client/gui/render/state/pip/GuiBookModelRenderState;")
+ )
+ private GuiBookModelRenderState easeGUI$transformBook(
+ BookModel bookModel, Identifier texture, float _open, float flip,
+ int x0, int y0, int x1, int y1, float scale, ScreenRectangle scissorArea, Operation original) {
+
+ int[] xs = PipTransform.transformRangeX(x0, x1);
+ int[] ys = PipTransform.transformRangeY(y0, y1);
+
+ return original.call(
+ bookModel, texture, _open, flip,
+ xs[0], ys[0], xs[1], ys[1], PipTransform.scale(scale), scissorArea
+ );
+ }
+
+ @WrapOperation(
+ method = "submitSkinRenderState",
+ at = @At(value = "NEW", target = "Lnet/minecraft/client/gui/render/state/pip/GuiSkinRenderState;")
+ )
+ private GuiSkinRenderState easeGUI$transformSkin(
+ PlayerModel playerModel, Identifier texture, float rotationX, float rotationY, float pivotY,
+ int x0, int y0, int x1, int y1, float scale, ScreenRectangle scissorArea, Operation original) {
+
+ int[] xs = PipTransform.transformRangeX(x0, x1);
+ int[] ys = PipTransform.transformRangeY(y0, y1);
+
+ return original.call(
+ playerModel, texture, rotationY, pivotY,
+ (float) xs[0], ys[0], xs[1], ys[1], Math.round(PipTransform.scale(scale)), rotationX, scissorArea
+ );
+ }
+
+ @WrapOperation(
+ method = "submitBannerPatternRenderState",
+ at = @At(value = "NEW", target = "Lnet/minecraft/client/gui/render/state/pip/GuiBannerResultRenderState;")
+ )
+ private GuiBannerResultRenderState easeGUI$transformBanner(
+ BannerFlagModel flag, DyeColor baseColor, BannerPatternLayers resultBannerPatterns,
+ int x0, int y0, int x1, int y1, ScreenRectangle scissorArea,
+ Operation original) {
+
+ int[] xs = PipTransform.transformRangeX(x0, x1);
+ int[] ys = PipTransform.transformRangeY(y0, y1);
+
+ return original.call(flag, baseColor, resultBannerPatterns, xs[0], ys[0], xs[1], ys[1], scissorArea);
+ }
+
+ @WrapOperation(
+ method = "submitSignRenderState",
+ at = @At(value = "NEW", target = "Lnet/minecraft/client/gui/render/state/pip/GuiSignRenderState;")
+ )
+ private GuiSignRenderState easeGUI$transformSign(
+ Model.Simple signModel, WoodType woodType, int x0, int y0, int x1, int y1, float scale, ScreenRectangle scissorArea,
+ Operation original) {
+
+ int[] xs = PipTransform.transformRangeX(x0, x1);
+ int[] ys = PipTransform.transformRangeY(y0, y1);
+
+ return original.call(
+ signModel, woodType,
+ xs[0], ys[0], xs[1], ys[1],
+ PipTransform.scale(scale), scissorArea
+ );
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiItemRenderStateMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiItemRenderStateMixin.java
new file mode 100644
index 0000000..3447d8f
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiItemRenderStateMixin.java
@@ -0,0 +1,28 @@
+package net.weyne1.easegui.client.mixin.gui;
+
+import net.minecraft.client.gui.render.state.GuiItemRenderState;
+import net.weyne1.easegui.client.animation.AnimationContext;
+import net.weyne1.easegui.client.extension.ItemExtension;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(GuiItemRenderState.class)
+public class GuiItemRenderStateMixin implements ItemExtension {
+ @Unique
+ private float easegui$alpha = 1.0f;
+
+ @Inject(method = "", at = @At("RETURN"))
+ private void easeGUI$captureAlphaOnCreation(CallbackInfo ci) {
+ if (AnimationContext.isActive()) {
+ this.easegui$alpha = AnimationContext.getCurrentAlpha();
+ }
+ }
+
+ @Override
+ public float easegui$getAlpha() {
+ return this.easegui$alpha;
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiRendererMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiRendererMixin.java
new file mode 100644
index 0000000..abe81df
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiRendererMixin.java
@@ -0,0 +1,42 @@
+package net.weyne1.easegui.client.mixin.gui;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.mojang.blaze3d.pipeline.RenderPipeline;
+import net.minecraft.client.gui.navigation.ScreenRectangle;
+import net.minecraft.client.gui.render.TextureSetup;
+import net.minecraft.client.gui.render.state.BlitRenderState;
+import net.minecraft.client.gui.render.state.GuiItemRenderState;
+import net.minecraft.client.gui.render.GuiRenderer;
+import net.weyne1.easegui.client.extension.ItemExtension;
+import org.joml.Matrix3x2f;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+@Mixin(GuiRenderer.class)
+public class GuiRendererMixin {
+
+ @SuppressWarnings("NameDoesntMatchTargetClass")
+ @WrapOperation(
+ method = "submitBlitFromItemAtlas",
+ at = @At(value = "NEW", target = "Lnet/minecraft/client/gui/render/state/BlitRenderState;")
+ )
+ private BlitRenderState easeGUI$applyStoredAlphaToItems(
+ RenderPipeline pipeline, TextureSetup textureSetup, Matrix3x2f pose,
+ int x0, int y0, int x1, int y1, float u0, float u1, float v0, float v1, int color,
+ ScreenRectangle scissorArea, ScreenRectangle bounds,
+ Operation original,
+ GuiItemRenderState renderState, float x, float y, int itemSize, int atlasSize) {
+ float alpha = ((ItemExtension) (Object) renderState).easegui$getAlpha();
+
+ if (alpha >= 1.0f) {
+ return original.call(pipeline, textureSetup, pose, x0, y0, x1, y1, u0, u1, v0, v1, color, scissorArea, bounds);
+ }
+
+ int a = (int) (alpha * 255) & 0xFF;
+
+ int premultipliedColor = (a << 24) | (a << 16) | (a << 8) | a;
+
+ return original.call(pipeline, textureSetup, pose, x0, y0, x1, y1, u0, u1, v0, v1, premultipliedColor, scissorArea, bounds);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiTextRenderStateMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiTextRenderStateMixin.java
new file mode 100644
index 0000000..00a091a
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/GuiTextRenderStateMixin.java
@@ -0,0 +1,19 @@
+package net.weyne1.easegui.client.mixin.gui;
+
+import net.minecraft.client.gui.render.state.GuiTextRenderState;
+import net.weyne1.easegui.client.animation.AnimationContext;
+import net.weyne1.easegui.client.util.ColorUtils;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
+
+@SuppressWarnings("ModifyVariableMayUseName")
+@Mixin(GuiTextRenderState.class)
+public class GuiTextRenderStateMixin {
+
+ @ModifyVariable(method = "", at = @At("HEAD"), argsOnly = true, ordinal = 2)
+ private static int easeGUI$modifyTextStateColor(int color) {
+ if (!AnimationContext.isActive()) return color;
+ return ColorUtils.getAnimatedColor(color);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenLifecycleMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenLifecycleMixin.java
index d86f766..59b7dbf 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenLifecycleMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenLifecycleMixin.java
@@ -1,6 +1,5 @@
package net.weyne1.easegui.client.mixin.gui;
-import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.weyne1.easegui.client.state.ScreenStateTracker;
import org.spongepowered.asm.mixin.Mixin;
@@ -9,10 +8,10 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Screen.class)
-
public class ScreenLifecycleMixin {
- @Inject(method = "init(Lnet/minecraft/client/Minecraft;II)V", at = @At("HEAD"))
- private void easeGUI$onScreenInit(Minecraft minecraft, int width, int height, CallbackInfo ci) {
+
+ @Inject(method = "added()V", at = @At("HEAD"))
+ private void easeGUI$onScreenAdded(CallbackInfo ci) {
Screen currentScreen = (Screen) (Object) this;
if (ScreenStateTracker.checkAndTrackNewScreen(currentScreen)) {
ScreenStateTracker.markScreenOpened();
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenMixin.java
index d287e0a..db9d04e 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/ScreenMixin.java
@@ -1,173 +1,98 @@
package net.weyne1.easegui.client.mixin.gui;
+import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.Screen;
-import net.weyne1.easegui.client.accessor.ContainerScreenAccessor;
-import net.weyne1.easegui.client.accessor.ScreenAnimationAccessor;
+import net.weyne1.easegui.client.extension.ContainerScreenExtension;
+import net.weyne1.easegui.client.animation.AnimationContext;
import net.weyne1.easegui.client.animation.AnimationScope;
import net.weyne1.easegui.client.animator.BackgroundAnimator;
import net.weyne1.easegui.client.animator.ContainerAnimator;
import net.weyne1.easegui.client.config.ConfigManager;
-import net.weyne1.easegui.client.config.EaseGUIConfig;
-import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.ModifyArg;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-/**
- * Injects custom animation behavior into the global Screen rendering pipeline.
- * Manages container transition lifecycles, menu textures, and background dimming.
- */
+import org.spongepowered.asm.mixin.injection.ModifyArgs;
+import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
+
@Mixin(Screen.class)
-public abstract class ScreenMixin implements ScreenAnimationAccessor {
+@SuppressWarnings("ConstantConditions")
+public abstract class ScreenMixin {
- @Unique private AnimationScope easeGUI$containerScreenScope = null;
- @Unique private AnimationScope easeGUI$menuBackgroundScope = null;
+ @Final @Shadow protected Minecraft minecraft;
+ @Shadow protected abstract void renderBlurredBackground(GuiGraphics guiGraphics);
- @Shadow @Nullable protected Minecraft minecraft;
- @Shadow protected abstract void renderBlurredBackground(float partialTick);
+ // Container lifecycle
- @Override
- @Unique
- public AnimationScope easeGUI$getContainerScope() {
- return this.easeGUI$containerScreenScope;
- }
+ @WrapMethod(method = "renderWithTooltipAndSubtitles")
+ private void easeGUI$wrapScreenRender(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, Operation original) {
+ if (RenderSystem.isOnRenderThread() && this instanceof ContainerScreenExtension) {
- @Unique
- private boolean easeGUI$isWorldLoadingScreen() {
- return BackgroundAnimator.isLoadingScreen((Screen) (Object) this);
- }
+ try (AnimationScope ignored = ContainerAnimator.beginAnimation((Screen) (Object) this, guiGraphics)) {
+ AnimationContext.pushParentAnimation();
- // CONTAINER SCREEN ANIMATION LIFECYCLE
-
- /**
- * Initializes the container animation scope at the absolute beginning of the screen
- * rendering pipeline, ensuring both widgets and late-rendered tooltips are captured.
- */
- @Inject(method = "renderWithTooltip", at = @At("HEAD"))
- private void easeGUI$beforeScreenRenderWithTooltip(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) {
- if (RenderSystem.isOnRenderThread() && this instanceof ContainerScreenAccessor) {
- if (this.easeGUI$containerScreenScope != null) {
- ContainerAnimator.closeScope(this.easeGUI$containerScreenScope);
- }
+ original.call(guiGraphics, mouseX, mouseY, partialTick);
- this.easeGUI$containerScreenScope = ContainerAnimator.beginScreenAnimation((Screen) (Object) this, guiGraphics);
- }
- }
+ AnimationContext.popParentAnimation();
+ }
- /**
- * Safely collapses and closes the container animation scope at the end of the rendering
- * pipeline to prevent matrix stack underflows.
- */
- @Inject(method = "renderWithTooltip", at = @At("RETURN"))
- private void easeGUI$afterScreenRenderWithTooltip(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) {
- if (RenderSystem.isOnRenderThread() && this.easeGUI$containerScreenScope != null) {
- ContainerAnimator.closeScope(this.easeGUI$containerScreenScope);
- this.easeGUI$containerScreenScope = null;
+ } else {
+ original.call(guiGraphics, mouseX, mouseY, partialTick);
}
}
- // BACKGROUND RENDERING ISOLATION (SUSPEND / RESUME)
+ // Transparent background (blur / dim)
- /**
- * Suspends active container scaling/translation right before the transparent background
- * gradient is drawn, keeping the background tint absolute and static.
- */
- @Inject(method = "renderTransparentBackground", at = @At("HEAD"))
- private void easeGUI$suspendBeforeTransparentBackground(GuiGraphics guiGraphics, CallbackInfo ci) {
- if (this.easeGUI$containerScreenScope != null) {
- this.easeGUI$containerScreenScope.suspend();
- }
+ @WrapMethod(method = "renderTransparentBackground")
+ private void easeGUI$wrapTransparentBackground(GuiGraphics guiGraphics, Operation original) {
+ AnimationScope currentScope = AnimationContext.getCurrentScope();
+ if (currentScope != null) currentScope.suspend();
- boolean blurContainers = ConfigManager.getConfig().global.blurContainers;
+ try {
+ Screen currentScreen = (Screen) (Object) this;
+ boolean blurContainers = ConfigManager.getConfig().global.blurContainers;
- if (this.minecraft != null && this.minecraft.level != null && blurContainers) {
- float partialTick = this.minecraft.getTimer().getGameTimeDeltaTicks();
- this.renderBlurredBackground(partialTick);
- }
- }
+ if (this.minecraft != null && this.minecraft.level != null && blurContainers && BackgroundAnimator.shouldAnimateBackground(currentScreen)) {
+ this.renderBlurredBackground(guiGraphics);
+ }
- /**
- * Resumes the container animation transformations immediately after the transparent
- * background gradient has finished rendering.
- */
- @Inject(method = "renderTransparentBackground", at = @At("RETURN"))
- private void easeGUI$resumeAfterTransparentBackground(GuiGraphics guiGraphics, CallbackInfo ci) {
- if (this.easeGUI$containerScreenScope != null) {
- this.easeGUI$containerScreenScope.resume();
+ original.call(guiGraphics);
+ } finally {
+ if (currentScope != null) currentScope.resume();
}
}
- /**
- * Isolates the main menu background rendering from container transformations and
- * handles standalone main-menu background animations.
- */
- @Inject(method = "renderMenuBackground(Lnet/minecraft/client/gui/GuiGraphics;)V", at = @At("HEAD"))
- private void easeGUI$preRenderMenuBackground(GuiGraphics guiGraphics, CallbackInfo ci) {
- if (this.easeGUI$containerScreenScope != null) {
- this.easeGUI$containerScreenScope.suspend();
- }
+ // Menu background
- if (this.easeGUI$menuBackgroundScope != null) {
- this.easeGUI$menuBackgroundScope.close();
- }
+ @WrapMethod(method = "renderMenuBackground(Lnet/minecraft/client/gui/GuiGraphics;)V")
+ private void easeGUI$wrapMenuBackground(GuiGraphics guiGraphics, Operation original) {
+ AnimationScope currentScope = AnimationContext.getCurrentScope();
+ if (currentScope != null) currentScope.suspend();
- if (!easeGUI$isWorldLoadingScreen() && BackgroundAnimator.shouldAnimate()) {
- this.easeGUI$menuBackgroundScope = BackgroundAnimator.beginRenderMenu(guiGraphics);
+ try (AnimationScope ignored = BackgroundAnimator.beginRenderMenu((Screen) (Object) this, guiGraphics)) {
+ original.call(guiGraphics);
+ } finally {
+ if (currentScope != null) currentScope.resume();
}
}
- /**
- * Cleans up menu background scope and restores the container animation transforms
- * for subsequent interface elements.
- */
- @Inject(method = "renderMenuBackground(Lnet/minecraft/client/gui/GuiGraphics;)V", at = @At("RETURN"))
- private void easeGUI$postRenderMenuBackground(GuiGraphics guiGraphics, CallbackInfo ci) {
- if (this.easeGUI$menuBackgroundScope != null) {
- this.easeGUI$menuBackgroundScope.close();
- this.easeGUI$menuBackgroundScope = null;
- }
-
- if (this.easeGUI$containerScreenScope != null) {
- this.easeGUI$containerScreenScope.resume();
- }
- }
+ // Gradient color
- // BACKGROUND GRADIENT COLOR MODIFICATIONS
-
- /**
- * Applies animated alpha to the top color of the Screen background gradient.
- */
- @ModifyArg(
+ @ModifyArgs(
method = "renderTransparentBackground(Lnet/minecraft/client/gui/GuiGraphics;)V",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;fillGradient(IIIIII)V"),
- index = 4
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;fillGradient(IIIIII)V")
)
- private int easeGUI$modifyTransparentBgTopColor(int originalColor) {
- if (easeGUI$isWorldLoadingScreen()) {
- return originalColor;
+ private void easeGUI$modifyTransparentBgColors(Args args) {
+ Screen currentScreen = (Screen) (Object) this;
+ if (!BackgroundAnimator.shouldAnimateBackground(currentScreen)) {
+ return;
}
- return BackgroundAnimator.getAnimatedColor(originalColor);
- }
- /**
- * Applies animated alpha to the bottom color of the Screen background gradient.
- */
- @ModifyArg(
- method = "renderTransparentBackground(Lnet/minecraft/client/gui/GuiGraphics;)V",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;fillGradient(IIIIII)V"),
- index = 5
- )
- private int easeGUI$modifyTransparentBgBottomColor(int originalColor) {
- if (easeGUI$isWorldLoadingScreen()) {
- return originalColor;
- }
- return BackgroundAnimator.getAnimatedColor(originalColor);
+ args.set(4, BackgroundAnimator.getAnimatedColor(currentScreen, args.get(4)));
+ args.set(5, BackgroundAnimator.getAnimatedColor(currentScreen, args.get(5)));
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/AbstractContainerScreenMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/AbstractContainerScreenMixin.java
index 2844c11..74ecd22 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/AbstractContainerScreenMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/AbstractContainerScreenMixin.java
@@ -3,12 +3,12 @@
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.network.chat.Component;
-import net.weyne1.easegui.client.accessor.ContainerScreenAccessor;
+import net.weyne1.easegui.client.extension.ContainerScreenExtension;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(AbstractContainerScreen.class)
-public abstract class AbstractContainerScreenMixin extends Screen implements ContainerScreenAccessor {
+public abstract class AbstractContainerScreenMixin extends Screen implements ContainerScreenExtension {
@Shadow protected int leftPos;
@Shadow protected int topPos;
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/AbstractRecipeBookScreenMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/AbstractRecipeBookScreenMixin.java
new file mode 100644
index 0000000..b58fcc0
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/AbstractRecipeBookScreenMixin.java
@@ -0,0 +1,20 @@
+package net.weyne1.easegui.client.mixin.gui.container;
+
+import net.minecraft.client.gui.screens.inventory.AbstractRecipeBookScreen;
+import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
+import net.weyne1.easegui.client.extension.RecipeBookScreenExtension;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+@Mixin(AbstractRecipeBookScreen.class)
+public abstract class AbstractRecipeBookScreenMixin implements RecipeBookScreenExtension {
+
+ @Final
+ @Shadow private RecipeBookComponent> recipeBookComponent;
+
+ @Override
+ public RecipeBookComponent> easeGUI$getRecipeBookComponent() {
+ return this.recipeBookComponent;
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/RecipeBookComponentMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/RecipeBookComponentMixin.java
index 66fe930..3090bfe 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/RecipeBookComponentMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/container/RecipeBookComponentMixin.java
@@ -1,29 +1,20 @@
package net.weyne1.easegui.client.mixin.gui.container;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
-import net.weyne1.easegui.client.accessor.RecipeBookAccessor;
+import net.weyne1.easegui.client.extension.RecipeBookComponentExtension;
import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Accessor;
+import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(RecipeBookComponent.class)
-public abstract class RecipeBookComponentMixin implements RecipeBookAccessor {
- @Shadow private boolean visible;
- @Shadow private int xOffset;
+public interface RecipeBookComponentMixin extends RecipeBookComponentExtension {
- @Accessor("IMAGE_WIDTH")
- public static int easeGUI$getVanillaWidth() {
- throw new AssertionError();
- }
+ @Accessor("visible")
+ boolean easeGUI$isVisible();
- @Accessor("IMAGE_HEIGHT")
- public static int easeGUI$getVanillaHeight() {
- throw new AssertionError();
- }
+ @Invoker("getXOrigin")
+ int easeGUI$getXOrigin();
- @Override public boolean easeGUI$isVisible() { return this.visible; }
- @Override public int easeGUI$getXOffset() { return this.xOffset; }
-
- @Override public int easeGUI$getBookWidth() { return easeGUI$getVanillaWidth(); }
- @Override public int easeGUI$getBookHeight() { return easeGUI$getVanillaHeight(); }
+ @Invoker("getYOrigin")
+ int easeGUI$getYOrigin();
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/SplashRendererMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/SplashRendererMixin.java
index 935cc09..a91ee6e 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/SplashRendererMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/SplashRendererMixin.java
@@ -2,10 +2,10 @@
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
-import net.minecraft.client.gui.Font;
-import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.ActiveTextCollector;
+import net.minecraft.client.gui.TextAlignment;
import net.minecraft.client.gui.components.SplashRenderer;
-import net.weyne1.easegui.client.animation.AnimationScope;
+import net.minecraft.network.chat.Component;
import net.weyne1.easegui.client.animator.SplashAnimator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -15,17 +15,24 @@ public class SplashRendererMixin {
@WrapOperation(
method = "render",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawCenteredString(Lnet/minecraft/client/gui/Font;Ljava/lang/String;III)V")
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/client/gui/ActiveTextCollector;accept(Lnet/minecraft/client/gui/TextAlignment;IILnet/minecraft/client/gui/ActiveTextCollector$Parameters;Lnet/minecraft/network/chat/Component;)V"
+ )
)
- private void easeGUI$wrapSplash(GuiGraphics gg, Font font, String text, int x, int y, int color, Operation original) {
- AnimationScope scope = SplashAnimator.beginRender(gg, color);
+ private void easeGUI$animateSplash(
+ ActiveTextCollector collector,
+ TextAlignment textAlignment,
+ int x,
+ int y,
+ ActiveTextCollector.Parameters parameters,
+ Component text,
+ Operation original
+ ) {
+ ActiveTextCollector.Parameters animatedParams = SplashAnimator.getAnimatedParameters(parameters);
- if (scope != null) {
- try (scope) {
- original.call(gg, font, text, x, y, color);
- }
- } else {
- original.call(gg, font, text, x, y, color);
+ if (animatedParams != null) {
+ original.call(collector, textAlignment, x, y, animatedParams, text);
}
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/TitleScreenMixin.java b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/TitleScreenMixin.java
index 15ab170..0e88ea2 100644
--- a/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/TitleScreenMixin.java
+++ b/common/src/main/java/net/weyne1/easegui/client/mixin/gui/title/TitleScreenMixin.java
@@ -1,11 +1,13 @@
package net.weyne1.easegui.client.mixin.gui.title;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.components.LogoRenderer;
import net.minecraft.client.gui.screens.TitleScreen;
import net.weyne1.easegui.client.config.ConfigManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class)
public class TitleScreenMixin {
@@ -15,14 +17,38 @@ public class TitleScreenMixin {
* This allows EaseGUI to fully control widget fade-in animation,
* while preserving vanilla transitions if the screen animation is disabled.
*/
- @Inject(method = "fadeWidgets", at = @At("HEAD"), cancellable = true)
- private void easeGUI$cancelFade(float alpha, CallbackInfo ci) {
+ @WrapOperation(
+ method = "render",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/client/gui/screens/TitleScreen;fadeWidgets(F)V"
+ )
+ )
+ private void easeGUI$conditionallyFadeWidgets(TitleScreen instance, float v, Operation original) {
var titleSettings = ConfigManager.getConfig().screens.get("title");
- if (titleSettings == null || !titleSettings.enabled) {
+ if (titleSettings != null && titleSettings.enabled) {
return;
}
- ci.cancel();
+ original.call(instance, v);
+ }
+
+ @WrapOperation(
+ method = "render",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/client/gui/components/LogoRenderer;renderLogo(Lnet/minecraft/client/gui/GuiGraphics;IF)V"
+ )
+ )
+ private void easeGUI$conditionallyFadeLogo(LogoRenderer instance, GuiGraphics guiGraphics, int screenWidth, float transparency, Operation original) {
+ var titleSettings = ConfigManager.getConfig().screens.get("title");
+
+ if (titleSettings != null && titleSettings.enabled) {
+ original.call(instance, guiGraphics, screenWidth, 1.0F);
+ return;
+ }
+
+ original.call(instance, guiGraphics, screenWidth, transparency);
}
}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/state/ScreenStateTracker.java b/common/src/main/java/net/weyne1/easegui/client/state/ScreenStateTracker.java
index 5e6f310..cf3c553 100644
--- a/common/src/main/java/net/weyne1/easegui/client/state/ScreenStateTracker.java
+++ b/common/src/main/java/net/weyne1/easegui/client/state/ScreenStateTracker.java
@@ -1,12 +1,14 @@
package net.weyne1.easegui.client.state;
-import net.minecraft.Util;
+import net.minecraft.util.Util;
import net.minecraft.client.gui.screens.Screen;
import java.lang.ref.WeakReference;
public class ScreenStateTracker {
private static long screenOpenTime = -1;
+ private static long lastTrackedSessionTime = -1L;
+ private static long titleActualStartTime = -1L;
private static int currentFrameId = 0;
private static int resizeGraceFrames = 0;
private static int lastWidth = -1;
@@ -51,6 +53,17 @@ public static void incrementFrame() {
}
}
+ public static long getTitleActualStartTime() {
+ long openTime = getScreenOpenTime();
+
+ if (lastTrackedSessionTime != openTime) {
+ lastTrackedSessionTime = openTime;
+ titleActualStartTime = Util.getMillis();
+ }
+
+ return titleActualStartTime;
+ }
+
public static long getScreenOpenTime() {
if (screenOpenTime == -1) {
screenOpenTime = Util.getMillis();
diff --git a/common/src/main/java/net/weyne1/easegui/client/util/ColorUtils.java b/common/src/main/java/net/weyne1/easegui/client/util/ColorUtils.java
new file mode 100644
index 0000000..7ebd546
--- /dev/null
+++ b/common/src/main/java/net/weyne1/easegui/client/util/ColorUtils.java
@@ -0,0 +1,21 @@
+package net.weyne1.easegui.client.util;
+
+import net.weyne1.easegui.client.animation.AnimationContext;
+
+public final class ColorUtils {
+
+ private ColorUtils() {}
+
+ public static int getAnimatedColor(int originalColor) {
+ int originalAlpha = (originalColor >> 24) & 0xFF;
+
+ if (originalAlpha == 0 && (originalColor & 0x00FFFFFF) != 0) {
+ originalAlpha = 255;
+ }
+
+ float animationAlpha = AnimationContext.getCurrentAlpha();
+ int finalAlpha = Math.round(originalAlpha * animationAlpha);
+
+ return (originalColor & 0x00FFFFFF) | (finalAlpha << 24);
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/net/weyne1/easegui/client/StringUtils.java b/common/src/main/java/net/weyne1/easegui/client/util/StringUtils.java
similarity index 94%
rename from common/src/main/java/net/weyne1/easegui/client/StringUtils.java
rename to common/src/main/java/net/weyne1/easegui/client/util/StringUtils.java
index 56d4c2b..70c46ef 100644
--- a/common/src/main/java/net/weyne1/easegui/client/StringUtils.java
+++ b/common/src/main/java/net/weyne1/easegui/client/util/StringUtils.java
@@ -1,4 +1,4 @@
-package net.weyne1.easegui.client;
+package net.weyne1.easegui.client.util;
public class StringUtils {
public static String toTitleCase(Enum> e) {
diff --git a/common/src/main/resources/easegui.mixins.json b/common/src/main/resources/easegui.mixins.json
index c0c4949..92ed8db 100644
--- a/common/src/main/resources/easegui.mixins.json
+++ b/common/src/main/resources/easegui.mixins.json
@@ -6,16 +6,20 @@
"client": [
"GameRendererMixin",
"MinecraftMixin",
+ "OptionsMixin",
"accessor.AdvancementTabAccessor",
"accessor.LogoRendererAccessor",
- "blaze3d.VertexBufferMixin",
"gui.AbstractSelectionListMixin",
"gui.AbstractWidgetMixin",
"gui.AdvancementsScreenMixin",
"gui.GuiGraphicsMixin",
+ "gui.GuiItemRenderStateMixin",
+ "gui.GuiRendererMixin",
+ "gui.GuiTextRenderStateMixin",
"gui.ScreenLifecycleMixin",
"gui.ScreenMixin",
"gui.container.AbstractContainerScreenMixin",
+ "gui.container.AbstractRecipeBookScreenMixin",
"gui.container.RecipeBookComponentMixin",
"gui.title.LogoRendererMixin",
"gui.title.SplashRendererMixin",
diff --git a/common/src/test/java/net/weyne1/easegui/client/animation/AnimationMathUtilsTest.java b/common/src/test/java/net/weyne1/easegui/client/animation/AnimationMathUtilsTest.java
index 755c262..4743827 100644
--- a/common/src/test/java/net/weyne1/easegui/client/animation/AnimationMathUtilsTest.java
+++ b/common/src/test/java/net/weyne1/easegui/client/animation/AnimationMathUtilsTest.java
@@ -1,6 +1,6 @@
package net.weyne1.easegui.client.animation;
-import net.weyne1.easegui.client.animation.AnimationProfile.PivotPoint;
+import net.weyne1.easegui.api.animation.EasingType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@@ -43,19 +43,19 @@ void testCalculateCurrentOffset() {
"500, 1000, 0.5f" // В середине
})
void testAnimationProgress(long timePassed, long duration, float expectedProgress) {
- float result = AnimationMath.calculateProgress(timePassed, duration, AnimationProfile.EasingType.LINEAR);
+ float result = AnimationMath.calculateProgress(timePassed, duration, EasingType.LINEAR);
assertEquals(expectedProgress, result, 0.0001f);
}
@ParameterizedTest
- @EnumSource(AnimationProfile.EasingType.class)
- void allEasingsReturnZeroAtStart(AnimationProfile.EasingType easing) {
+ @EnumSource(EasingType.class)
+ void allEasingsReturnZeroAtStart(EasingType easing) {
assertEquals(0.0f, easing.ease(0.0f), 0.0001f);
}
@ParameterizedTest
- @EnumSource(AnimationProfile.EasingType.class)
- void allEasingsReturnOneAtEnd(AnimationProfile.EasingType easing) {
+ @EnumSource(EasingType.class)
+ void allEasingsReturnOneAtEnd(EasingType easing) {
assertEquals(1.0f, easing.ease(1.0f), 0.0001f);
}
}
\ No newline at end of file
diff --git a/fabric/build.gradle b/fabric/build.gradle
index 06ad8cc..2fea682 100644
--- a/fabric/build.gradle
+++ b/fabric/build.gradle
@@ -29,8 +29,6 @@ dependencies {
modCompileOnly "com.terraformersmc:modmenu:${rootProject.mod_menu_version}"
modLocalRuntime "com.terraformersmc:modmenu:${rootProject.mod_menu_version}"
- modLocalRuntime "dev.emi:emi-fabric:${rootProject.emi_version}"
-
common(project(path: ':common', configuration: 'namedElements')) { transitive = false }
shadowBundle project(path: ':common', configuration: 'transformProductionFabric')
}
diff --git a/fabric/src/main/java/net/weyne1/easegui/neoforge/client/EaseGUIFabricClient.java b/fabric/src/main/java/net/weyne1/easegui/fabric/client/EaseGUIFabricClient.java
similarity index 84%
rename from fabric/src/main/java/net/weyne1/easegui/neoforge/client/EaseGUIFabricClient.java
rename to fabric/src/main/java/net/weyne1/easegui/fabric/client/EaseGUIFabricClient.java
index 66cd58b..5ba5b4a 100644
--- a/fabric/src/main/java/net/weyne1/easegui/neoforge/client/EaseGUIFabricClient.java
+++ b/fabric/src/main/java/net/weyne1/easegui/fabric/client/EaseGUIFabricClient.java
@@ -1,4 +1,4 @@
-package net.weyne1.easegui.neoforge.client;
+package net.weyne1.easegui.fabric.client;
import net.fabricmc.api.ClientModInitializer;
import net.weyne1.easegui.client.EaseGUIClient;
diff --git a/fabric/src/main/java/net/weyne1/easegui/neoforge/client/ModMenuIntegration.java b/fabric/src/main/java/net/weyne1/easegui/fabric/client/ModMenuIntegration.java
similarity index 88%
rename from fabric/src/main/java/net/weyne1/easegui/neoforge/client/ModMenuIntegration.java
rename to fabric/src/main/java/net/weyne1/easegui/fabric/client/ModMenuIntegration.java
index 1efaf69..93664e0 100644
--- a/fabric/src/main/java/net/weyne1/easegui/neoforge/client/ModMenuIntegration.java
+++ b/fabric/src/main/java/net/weyne1/easegui/fabric/client/ModMenuIntegration.java
@@ -1,4 +1,4 @@
-package net.weyne1.easegui.neoforge.client;
+package net.weyne1.easegui.fabric.client;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json
index 85427c1..09fb815 100644
--- a/fabric/src/main/resources/fabric.mod.json
+++ b/fabric/src/main/resources/fabric.mod.json
@@ -17,10 +17,10 @@
"environment": "client",
"entrypoints": {
"client": [
- "net.weyne1.easegui.neoforge.client.EaseGUIFabricClient"
+ "net.weyne1.easegui.fabric.client.EaseGUIFabricClient"
],
"modmenu": [
- "net.weyne1.easegui.neoforge.client.ModMenuIntegration"
+ "net.weyne1.easegui.fabric.client.ModMenuIntegration"
]
},
"mixins": [
diff --git a/gradle.properties b/gradle.properties
index 257d044..b64e679 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,21 +6,20 @@ org.gradle.parallel=true
org.gradle.configuration-cache=false
# Minecraft properties
-minecraft_version=1.21.1
+minecraft_version=1.21.11
# Mod Properties
-mod_version=0.3.0
+mod_version=0.4.0
maven_group=net.weyne1.easegui
archives_name=easegui
enabled_platforms=fabric,neoforge
# Mappings version. Find versions here: https://parchmentmc.org/docs/getting-started
-parchment_version=2024.11.17
+parchment_version=2025.12.20
# Dependencies
-neoforge_version=21.1.65
+neoforge_version=21.11.0-beta
fabric_loader_version=0.18.4
-fabric_api_version=0.105.0+1.21.1
-mod_menu_version=11.0.4
-emi_version=1.1.12+1.21
+fabric_api_version=0.139.4+1.21.11
+mod_menu_version=17.0.0-alpha.1
junit_version=5.13.4
\ No newline at end of file
diff --git a/neoforge/build.gradle b/neoforge/build.gradle
index 3430b6b..4f90a20 100644
--- a/neoforge/build.gradle
+++ b/neoforge/build.gradle
@@ -25,8 +25,6 @@ configurations {
dependencies {
neoForge "net.neoforged:neoforge:$rootProject.neoforge_version"
- localRuntime "dev.emi:emi-neoforge:${rootProject.emi_version}"
-
common(project(path: ':common', configuration: 'namedElements')) { transitive = false }
shadowBundle project(path: ':common', configuration: 'transformProductionNeoForge')
}