Skip to content

Commit

Permalink
Fix mods screen initialization being slow with many mods (#790)
Browse files Browse the repository at this point in the history
- Fix Mods screen being slow to open the first time
- Config screen errors no longer show until after a user has tried to open them
  • Loading branch information
LostLuma authored and Prospector committed Oct 14, 2024
1 parent db0cb4e commit 39f0fcf
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 49 deletions.
29 changes: 20 additions & 9 deletions src/main/java/com/terraformersmc/modmenu/ModMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -59,21 +60,31 @@ public class ModMenu implements ClientModInitializer {
public static final boolean DEV_ENVIRONMENT = FabricLoader.getInstance().isDevelopmentEnvironment();
public static final boolean TEXT_PLACEHOLDER_COMPAT = FabricLoader.getInstance().isModLoaded("placeholder-api");

public static Screen getConfigScreen(String modid, Screen menuScreen) {
public static boolean hasConfigScreen(String modId) {
return getConfigScreenFactory(modId) != null;
}

public static @Nullable Screen getConfigScreen(String modId, Screen parent) {
ConfigScreenFactory<?> factory = getConfigScreenFactory(modId);
if (factory != null) {
return factory.create(parent);
}
return null;
}

private static @Nullable ConfigScreenFactory<?> getConfigScreenFactory(String modId) {
if (ModMenuConfig.HIDDEN_CONFIGS.getValue().contains(modId)) {
return null;
}

for (ModMenuApi api : apiImplementations) {
var factoryProviders = api.getProvidedConfigScreenFactories();
if (!factoryProviders.isEmpty()) {
factoryProviders.forEach(configScreenFactories::putIfAbsent);
}
}
if (ModMenuConfig.HIDDEN_CONFIGS.getValue().contains(modid)) {
return null;
}
ConfigScreenFactory<?> factory = configScreenFactories.get(modid);
if (factory != null) {
return factory.create(menuScreen);
}
return null;

return configScreenFactories.get(modId);
}

@Override
Expand Down
55 changes: 28 additions & 27 deletions src/main/java/com/terraformersmc/modmenu/gui/ModsScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,6 @@ public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmou

@Override
protected void init() {
for (Mod mod : ModMenu.MODS.values()) {
String id = mod.getId();
if (!modHasConfigScreen.containsKey(id)) {
try {
Screen configScreen = ModMenu.getConfigScreen(id, this);
modHasConfigScreen.put(id, configScreen != null);
} catch (java.lang.NoClassDefFoundError e) {
LOGGER.warn(
"The '" + id + "' mod config screen is not available because " + e.getLocalizedMessage() +
" is missing.");
modScreenErrors.put(id, e);
modHasConfigScreen.put(id, false);
} catch (Throwable e) {
LOGGER.error("Error from mod '" + id + "'", e);
modScreenErrors.put(id, e);
modHasConfigScreen.put(id, false);
}
}
}

int paneY = ModMenuConfig.CONFIG_MODE.getValue() ? 48 : 48 + 19;
this.paneWidth = this.width / 2 - 8;
this.rightPaneX = this.width - this.paneWidth;
Expand Down Expand Up @@ -203,9 +183,8 @@ protected void init() {
if (!ModMenuConfig.HIDE_CONFIG_BUTTONS.getValue()) {
this.configureButton = LegacyTexturedButtonWidget.legacyTexturedBuilder(ScreenTexts.EMPTY, button -> {
final String id = Objects.requireNonNull(selected).getMod().getId();
if (modHasConfigScreen.get(id)) {
Screen configScreen = ModMenu.getConfigScreen(id, this);
client.setScreen(configScreen);
if (getModHasConfigScreen(id)) {
this.safelyOpenConfigScreen(id);
} else {
button.active = false;
}
Expand Down Expand Up @@ -540,9 +519,9 @@ public void updateSelectedEntry(ModListEntry entry) {

if (this.configureButton != null) {

this.configureButton.active = modHasConfigScreen.get(modId);
this.configureButton.active = getModHasConfigScreen(modId);
this.configureButton.visible =
selected != null && modHasConfigScreen.get(modId) || modScreenErrors.containsKey(modId);
selected != null && getModHasConfigScreen(modId) || modScreenErrors.containsKey(modId);

if (modScreenErrors.containsKey(modId)) {
Throwable e = modScreenErrors.get(modId);
Expand Down Expand Up @@ -652,7 +631,29 @@ private static boolean isValidMod(Path mod) {
}
}

public Map<String, Boolean> getModHasConfigScreen() {
return this.modHasConfigScreen;
public boolean getModHasConfigScreen(String modId) {
if (this.modScreenErrors.containsKey(modId)) {
return false;
} else {
return this.modHasConfigScreen.computeIfAbsent(modId, ModMenu::hasConfigScreen);
}
}

public void safelyOpenConfigScreen(String modId) {
try {
Screen screen = ModMenu.getConfigScreen(modId, this);

if (screen != null) {
this.client.setScreen(screen);
}
} catch (java.lang.NoClassDefFoundError e) {
LOGGER.warn(
"The '" + modId + "' mod config screen is not available because " + e.getLocalizedMessage() +
" is missing.");
modScreenErrors.put(modId, e);
} catch (Throwable e) {
LOGGER.error("Error from mod '" + modId + "'", e);
modScreenErrors.put(modId, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,7 @@ private void filter(String searchTerm, boolean refresh, boolean search) {
addedMods.clear();
Collection<Mod> mods = ModMenu.MODS.values().stream().filter(mod -> {
if (ModMenuConfig.CONFIG_MODE.getValue()) {
Map<String, Boolean> modHasConfigScreen = parent.getModHasConfigScreen();
var hasConfig = modHasConfigScreen.get(mod.getId());
if (!hasConfig) {
return false;
}
return !parent.getModHasConfigScreen(mod.getId());
}

return !mod.isHidden();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ public void render(
}

if (!(this instanceof ParentEntry) && ModMenuConfig.QUICK_CONFIGURE.getValue() && (this.list.getParent()
.getModHasConfigScreen()
.get(modId) || this.list.getParent().modScreenErrors.containsKey(modId))) {
.getModHasConfigScreen(modId) || this.list.getParent().modScreenErrors.containsKey(modId))) {
final int textureSize = ModMenuConfig.COMPACT_LIST.getValue() ?
(int) (256 / (FULL_ICON_SIZE / (double) COMPACT_ICON_SIZE)) :
256;
Expand Down Expand Up @@ -167,9 +166,7 @@ public void render(
@Override
public boolean mouseClicked(double mouseX, double mouseY, int delta) {
list.select(this);
if (ModMenuConfig.QUICK_CONFIGURE.getValue() && this.list.getParent()
.getModHasConfigScreen()
.get(this.mod.getId())) {
if (ModMenuConfig.QUICK_CONFIGURE.getValue() && this.list.getParent().getModHasConfigScreen(this.mod.getId())) {
int iconSize = ModMenuConfig.COMPACT_LIST.getValue() ? COMPACT_ICON_SIZE : FULL_ICON_SIZE;
if (mouseX - list.getRowLeft() <= iconSize) {
this.openConfig();
Expand All @@ -182,7 +179,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int delta) {
}

public void openConfig() {
MinecraftClient.getInstance().setScreen(ModMenu.getConfigScreen(mod.getId(), list.getParent()));
this.list.getParent().safelyOpenConfigScreen(mod.getId());
}

public Mod getMod() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ private static int passesFilters(ModsScreen screen, Mod mod, String query) {
|| deprecated.contains(query) && mod.getBadges()
.contains(Mod.Badge.DEPRECATED) // Search for deprecated mods
|| clientside.contains(query) && mod.getBadges().contains(Mod.Badge.CLIENT) // Search for clientside mods
|| configurable.contains(query) && screen.getModHasConfigScreen()
.get(modId) // Search for mods that can be configured
|| configurable.contains(query) && screen.getModHasConfigScreen(modId) // Search for mods that can be configured
|| hasUpdate.contains(query) && mod.hasUpdate() // Search for mods that have updates
) {
return 1;
Expand Down

0 comments on commit 39f0fcf

Please sign in to comment.