Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
edeb881
chore: update dependencies
Weyne1 Jul 5, 2026
3b62ec3
ref: imports
Weyne1 Jul 5, 2026
76065eb
ref: animation system
Weyne1 Jul 5, 2026
f53b5a1
ref: EaseGUI screens
Weyne1 Jul 5, 2026
2b6af36
ref: recipe book
Weyne1 Jul 5, 2026
708e794
ref: Screen mixins
Weyne1 Jul 5, 2026
02db85d
ref: adapt blur animation to new shader system
Weyne1 Jul 5, 2026
ec9bb83
ref: AdvancementsScreenMixin
Weyne1 Jul 5, 2026
94c14ea
ref: AbstractSelectionListMixin
Weyne1 Jul 5, 2026
cf10368
ref: TitleScreenMixin
Weyne1 Jul 5, 2026
2e4cdfa
ref: move splash interception logic to TitleScreenMixin
Weyne1 Jul 5, 2026
a14471a
chore: add @Dynamic to EmiCompatMixin
Weyne1 Jul 5, 2026
0017750
ref: remove redundant GuiGraphicsMixin
Weyne1 Jul 5, 2026
33b6660
feat: remove redundant VertexBufferMixin
Weyne1 Jul 6, 2026
a4f4002
fix: AbstractRecipeBookScreenMixin naming
Weyne1 Jul 6, 2026
5b0f100
feat: add GuiGraphicsMixin to control GUI alpha
Weyne1 Jul 6, 2026
f9c18f0
feat: add GuiTextRenderStateMixin to control text alpha
Weyne1 Jul 6, 2026
c5c93ca
ref: add ColorUtils
Weyne1 Jul 6, 2026
b70779e
fix: disable the default logo fade-in effect
Weyne1 Jul 6, 2026
753d741
fix: correct splash animation
Weyne1 Jul 8, 2026
be43362
ref: ScreenMixin lifecycle
Weyne1 Jul 8, 2026
f8c0849
fix(AbstractSelectionListMixin): safe push/pop for parent animation
Weyne1 Jul 8, 2026
82888fd
ref: improve text widget category detection
Weyne1 Jul 8, 2026
9027e68
ref: delegate widget category resolution to UIElementCategory
Weyne1 Jul 8, 2026
9ca3766
ref: extract AnimationState into a top-level class
Weyne1 Jul 8, 2026
57a313b
ref(anim): migrate AnimationContext to object scope tracking
Weyne1 Jul 11, 2026
aa33280
ref(anim): migrate ScreenMixin to updated AnimationContext
Weyne1 Jul 11, 2026
ffa5937
ref(anim): migrate AbstractWidgetMixin to updated AnimationContext
Weyne1 Jul 11, 2026
6758a33
ref(anim): migrate AdvancementsScreen animation to updated AnimationC…
Weyne1 Jul 11, 2026
f06856e
ref(anim): migrate ListItem Animation to updated AnimationContext
Weyne1 Jul 11, 2026
2f9ae5e
ref(anim): migrate Splash Animation to updated AnimationContext
Weyne1 Jul 11, 2026
212fdca
feat: add animation for 3D layers within GuiGraphics
Weyne1 Jul 13, 2026
0bf5a2e
ref: split AnimationProfile into separate classes
Weyne1 Jul 13, 2026
4b6dbf2
ref: move duck-interfaces to extension package
Weyne1 Jul 13, 2026
bca52f3
ref: move FieldValidator into components package
Weyne1 Jul 13, 2026
a75fc7f
ref: centralize timing and progress calculation in AnimationSystem
Weyne1 Jul 13, 2026
b6f3e57
ref: delegate title screen session tracking to ScreenStateTracker
Weyne1 Jul 13, 2026
5bf0ed1
ref: make bg animation bypass extensible via registry
Weyne1 Jul 13, 2026
efa78b3
ref(config): split EaseGUIConfig data structure from initialization a…
Weyne1 Jul 13, 2026
d1f34e4
feat(config): implement dev API for registering custom screen animati…
Weyne1 Jul 13, 2026
538cc3d
ref: moving API classes to a separate package
Weyne1 Jul 13, 2026
c07cfbb
ref: oops the fabric package was named neoforge
Weyne1 Jul 14, 2026
ea6f79e
chore: bump version to 0.4.0
Weyne1 Jul 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -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
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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"),
Expand All @@ -9,7 +9,7 @@ public enum ScreenGroup {

private final String translationKey;

ScreenGroup(String translationKey) {
EaseGUIScreenGroup(String translationKey) {
this.translationKey = translationKey;
}

Expand Down
243 changes: 243 additions & 0 deletions common/src/main/java/net/weyne1/easegui/api/EaseGUIScreenRegistry.java
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>This is used by EaseGUI to decide how different screens should be categorized
* and animated. Matching works in two steps:
* <ul>
* <li>Fast exact class lookup (cache)</li>
* <li>Fallback hierarchy scan using isAssignableFrom</li>
* </ul>
*
* <p>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<Class<? extends Screen>, EaseGUIScreenType> EXACT_MATCH_CACHE = new ConcurrentHashMap<>();
private static final Map<String, Consumer<EaseGUIConfig.ScreenSettings>> DEFAULT_CONFIGURATORS = new ConcurrentHashMap<>();
private static final List<EaseGUIScreenType> 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<EaseGUIConfig.ScreenSettings> 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<EaseGUIConfig.ScreenSettings> 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<EaseGUIConfig.ScreenSettings> 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<WidgetCategory, AnimationProfile> 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.
*
* <p>Resolution order:
* <ol>
* <li>Exact class match (fast path)</li>
* <li>Assignable-from hierarchy scan</li>
* <li>Fallback to OTHER</li>
* </ol>
*/
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<EaseGUIScreenType> getRegisteredTypes() {
return Collections.unmodifiableList(HIERARCHY_LIST);
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -17,13 +17,13 @@
* <li>UI grouping</li>
* </ul>
*/
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;

/**
Expand All @@ -35,11 +35,11 @@ public final class ScreenType {
* <li>"modid:screen" → "modid.screen_type.screen"</li>
* </ul>
*/
public ScreenType(
public EaseGUIScreenType(
String id,
Class<? extends Screen> screenClass,
int priority,
ScreenGroup group,
EaseGUIScreenGroup group,
boolean enabledByDefault
) {
this.id = id;
Expand All @@ -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);
}
Expand All @@ -80,7 +81,7 @@ public int getPriority() {
return priority;
}

public ScreenGroup getGroup() {
public EaseGUIScreenGroup getGroup() {
return group;
}

Expand Down
Loading