-
Notifications
You must be signed in to change notification settings - Fork 158
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
, Closes #135, Closes #149, Closes #183 - Major internal refactors - Added links, contributors, and license information - Added an options screen for Mod Menu - Added a compact list mode option - Added an options to change Mods button style to: Below Realms (Default), Shrink Realms, Replace Realms, and Fabric Icon - Added an option to hide mod badges - Added an option to move where the mod count is displayed (on button, on title screen, both, neither) - Added options to specify whether or not to count libraries, children, and hidden mods in the mod count - Added options to hide mod links, credits, or license info - Added options to disable the modification of the title screen and/or game menu screen - Changed the hardcoded icon for "java" - Probably more that got forgotten about in this massive update
- Loading branch information
1 parent
253ec5b
commit 73bd4ad
Showing
83 changed files
with
2,590 additions
and
1,473 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package com.terraformersmc.modmenu; | ||
|
||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.collect.LinkedListMultimap; | ||
import com.google.gson.FieldNamingPolicy; | ||
import com.google.gson.Gson; | ||
import com.google.gson.GsonBuilder; | ||
import com.terraformersmc.modmenu.api.ConfigScreenFactory; | ||
import com.terraformersmc.modmenu.api.ModMenuApi; | ||
import com.terraformersmc.modmenu.config.ModMenuConfig; | ||
import com.terraformersmc.modmenu.config.ModMenuConfigManager; | ||
import com.terraformersmc.modmenu.event.ModMenuEventHandler; | ||
import com.terraformersmc.modmenu.util.ModMenuApiMarker; | ||
import com.terraformersmc.modmenu.util.mod.Mod; | ||
import com.terraformersmc.modmenu.util.mod.fabric.FabricDummyParentMod; | ||
import com.terraformersmc.modmenu.util.mod.fabric.FabricMod; | ||
import net.fabricmc.api.ClientModInitializer; | ||
import net.fabricmc.loader.api.FabricLoader; | ||
import net.fabricmc.loader.api.ModContainer; | ||
import net.minecraft.client.gui.screen.Screen; | ||
|
||
import java.text.NumberFormat; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class ModMenu implements ClientModInitializer { | ||
public static final String MOD_ID = "modmenu"; | ||
public static final Gson GSON = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create(); | ||
|
||
public static final Map<String, Mod> MODS = new HashMap<>(); | ||
public static final Map<String, Mod> ROOT_MODS = new HashMap<>(); | ||
public static final LinkedListMultimap<Mod, Mod> PARENT_MAP = LinkedListMultimap.create(); | ||
|
||
private static ImmutableMap<String, ConfigScreenFactory<?>> configScreenFactories = ImmutableMap.of(); | ||
|
||
private static int cachedDisplayedModCount = -1; | ||
|
||
public static Screen getConfigScreen(String modid, Screen menuScreen) { | ||
ConfigScreenFactory<?> factory = configScreenFactories.get(modid); | ||
return factory != null ? factory.create(menuScreen) : null; | ||
} | ||
|
||
@Override | ||
public void onInitializeClient() { | ||
ModMenuConfigManager.initializeConfig(); | ||
Map<String, ConfigScreenFactory<?>> factories = new HashMap<>(); | ||
FabricLoader.getInstance().getEntrypointContainers("modmenu", ModMenuApiMarker.class).forEach(entrypoint -> { | ||
ModMenuApiMarker marker = entrypoint.getEntrypoint(); | ||
if (marker instanceof ModMenuApi) { | ||
/* Current API */ | ||
ModMenuApi api = (ModMenuApi) marker; | ||
factories.put(entrypoint.getProvider().getMetadata().getId(), api.getModConfigScreenFactory()); | ||
api.getProvidedConfigScreenFactories().forEach(factories::putIfAbsent); | ||
} else if (marker instanceof io.github.prospector.modmenu.api.ModMenuApi) { | ||
/* Legacy API */ | ||
io.github.prospector.modmenu.api.ModMenuApi api = (io.github.prospector.modmenu.api.ModMenuApi) entrypoint.getEntrypoint(); | ||
factories.put(entrypoint.getProvider().getMetadata().getId(), screen -> api.getModConfigScreenFactory().create(screen)); | ||
api.getProvidedConfigScreenFactories().forEach((id, legacyFactory) -> factories.put(id, legacyFactory::create)); | ||
} else { | ||
throw new RuntimeException(entrypoint.getProvider().getMetadata().getId() + " is providing an invalid ModMenuApi implementation"); | ||
} | ||
}); | ||
configScreenFactories = new ImmutableMap.Builder<String, ConfigScreenFactory<?>>().putAll(factories).build(); | ||
|
||
|
||
// Fill mods map | ||
for (ModContainer modContainer : FabricLoader.getInstance().getAllMods()) { | ||
if (!ModMenuConfig.HIDDEN_MODS.getValue().contains(modContainer.getMetadata().getId())) { | ||
FabricMod mod = new FabricMod(modContainer); | ||
MODS.put(mod.getId(), mod); | ||
} | ||
} | ||
|
||
Map<String, Mod> dummyParents = new HashMap<>(); | ||
|
||
// Initialize parent map | ||
for (Mod mod : MODS.values()) { | ||
String parentId = mod.getParent(); | ||
if (parentId != null) { | ||
Mod parent = MODS.getOrDefault(parentId, dummyParents.get(parentId)); | ||
if (parent == null) { | ||
if (mod instanceof FabricMod) { | ||
parent = new FabricDummyParentMod((FabricMod) mod, parentId); | ||
dummyParents.put(parentId, parent); | ||
} | ||
} | ||
PARENT_MAP.put(parent, mod); | ||
} else { | ||
ROOT_MODS.put(mod.getId(), mod); | ||
} | ||
} | ||
MODS.putAll(dummyParents); | ||
ModMenuEventHandler.register(); | ||
} | ||
|
||
public static void clearModCountCache() { | ||
cachedDisplayedModCount = -1; | ||
} | ||
|
||
public static String getDisplayedModCount() { | ||
if (cachedDisplayedModCount == -1) { | ||
// listen, if you have >= 2^32 mods then that's on you | ||
cachedDisplayedModCount = Math.toIntExact(MODS.values().stream().filter(mod -> | ||
(ModMenuConfig.COUNT_CHILDREN.getValue() || mod.getParent() == null) && | ||
(ModMenuConfig.COUNT_LIBRARIES.getValue() || !mod.getBadges().contains(Mod.Badge.LIBRARY)) && | ||
(ModMenuConfig.COUNT_HIDDEN_MODS.getValue() || !ModMenuConfig.HIDDEN_MODS.getValue().contains(mod.getId())) | ||
).count()); | ||
} | ||
return NumberFormat.getInstance().format(cachedDisplayedModCount); | ||
} | ||
} |
15 changes: 11 additions & 4 deletions
15
...spector/modmenu/VanillaModMenuCompat.java → ...rmersmc/modmenu/ModMenuModMenuCompat.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
src/main/java/com/terraformersmc/modmenu/api/ConfigScreenFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.terraformersmc.modmenu.api; | ||
|
||
import net.minecraft.client.gui.screen.Screen; | ||
|
||
@FunctionalInterface | ||
public interface ConfigScreenFactory<S extends Screen> extends io.github.prospector.modmenu.api.ConfigScreenFactory<S> { | ||
S create(Screen parent); | ||
} |
48 changes: 48 additions & 0 deletions
48
src/main/java/com/terraformersmc/modmenu/api/ModMenuApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.terraformersmc.modmenu.api; | ||
|
||
import com.google.common.collect.ImmutableMap; | ||
import com.terraformersmc.modmenu.gui.ModsScreen; | ||
import com.terraformersmc.modmenu.util.ModMenuApiMarker; | ||
import net.minecraft.client.gui.screen.Screen; | ||
|
||
import java.util.Map; | ||
|
||
public interface ModMenuApi extends ModMenuApiMarker { | ||
/** | ||
* Used for creating a {@link Screen} instance of the Mod Menu | ||
* "Mods" screen | ||
* | ||
* @param previous The screen before opening | ||
* @return A "Mods" Screen | ||
*/ | ||
static Screen createModsScreen(Screen previous) { | ||
return new ModsScreen(previous); | ||
} | ||
|
||
/** | ||
* Used to construct a new config screen instance when your mod's | ||
* configuration button is selected on the mod menu screen. The | ||
* screen instance parameter is the active mod menu screen. | ||
* | ||
* @return A factory for constructing config screen instances. | ||
*/ | ||
default ConfigScreenFactory<?> getModConfigScreenFactory() { | ||
return screen -> null; | ||
} | ||
|
||
/** | ||
* Used to provide config screen factories for other mods. This takes second | ||
* priority to a mod's own config screen factory provider. For example, if | ||
* mod `xyz` supplies a config screen factory, mod `abc` providing a config | ||
* screen to `xyz` will be pointless, as the one provided by `xyz` will be | ||
* used. | ||
* <p> | ||
* This method is NOT meant to be used to add a config screen factory to | ||
* your own mod. | ||
* | ||
* @return a map of mod ids to screen factories. | ||
*/ | ||
default Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() { | ||
return ImmutableMap.of(); | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package com.terraformersmc.modmenu.config; | ||
|
||
import com.google.gson.annotations.SerializedName; | ||
import com.terraformersmc.modmenu.config.option.BooleanConfigOption; | ||
import com.terraformersmc.modmenu.config.option.EnumConfigOption; | ||
import com.terraformersmc.modmenu.config.option.StringSetConfigOption; | ||
import com.terraformersmc.modmenu.util.mod.Mod; | ||
import net.minecraft.client.options.Option; | ||
|
||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Modifier; | ||
import java.util.ArrayList; | ||
import java.util.Comparator; | ||
import java.util.HashSet; | ||
import java.util.Locale; | ||
|
||
public class ModMenuConfig { | ||
public static final EnumConfigOption<Sorting> SORTING = new EnumConfigOption<>("sorting", Sorting.ASCENDING); | ||
public static final BooleanConfigOption SHOW_LIBRARIES = new BooleanConfigOption("show_libraries", false); | ||
public static final BooleanConfigOption COMPACT_LIST = new BooleanConfigOption("compact_list", false); | ||
public static final BooleanConfigOption HIDE_BADGES = new BooleanConfigOption("hide_badges", false); | ||
public static final EnumConfigOption<ModsButtonStyle> MODS_BUTTON_STYLE = new EnumConfigOption<>("mods_button_style", ModsButtonStyle.CLASSIC); | ||
public static final EnumConfigOption<ModCountLocation> MOD_COUNT_LOCATION = new EnumConfigOption<>("mod_count_location", ModCountLocation.TITLE_SCREEN); | ||
public static final BooleanConfigOption COUNT_LIBRARIES = new BooleanConfigOption("count_libraries", true); | ||
public static final BooleanConfigOption COUNT_CHILDREN = new BooleanConfigOption("count_children", true); | ||
public static final BooleanConfigOption COUNT_HIDDEN_MODS = new BooleanConfigOption("count_hidden_mods", true); | ||
public static final BooleanConfigOption HIDE_CONFIG_BUTTONS = new BooleanConfigOption("hide_config_buttons", false); | ||
public static final BooleanConfigOption HIDE_MOD_LINKS = new BooleanConfigOption("hide_mod_links", false); | ||
public static final BooleanConfigOption HIDE_MOD_CREDITS = new BooleanConfigOption("hide_mod_credits", false); | ||
public static final BooleanConfigOption HIDE_MOD_LICENSE = new BooleanConfigOption("hide_mod_license", false); | ||
public static final BooleanConfigOption EASTER_EGGS = new BooleanConfigOption("easter_eggs", true); | ||
public static final BooleanConfigOption MODIFY_TITLE_SCREEN = new BooleanConfigOption("modify_title_screen", true); | ||
public static final BooleanConfigOption MODIFY_GAME_MENU = new BooleanConfigOption("modify_game_menu", true); | ||
public static final StringSetConfigOption HIDDEN_MODS = new StringSetConfigOption("hidden_mods", new HashSet<>()); | ||
|
||
public static Option[] asOptions() { | ||
ArrayList<Option> options = new ArrayList<>(); | ||
for (Field field : ModMenuConfig.class.getDeclaredFields()) { | ||
if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && Option.class.isAssignableFrom(field.getType()) && !field.getName().equals("HIDE_CONFIG_BUTTONS") && !field.getName().equals("MODIFY_TITLE_SCREEN") && !field.getName().equals("MODIFY_GAME_MENU")) { | ||
try { | ||
options.add((Option) field.get(null)); | ||
} catch (IllegalAccessException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
return options.stream().toArray(Option[]::new); | ||
} | ||
|
||
public enum Sorting { | ||
@SerializedName("ascending") | ||
ASCENDING(Comparator.comparing(mod -> mod.getName().toLowerCase(Locale.ROOT))), | ||
@SerializedName("descending") | ||
DESCENDING(ASCENDING.getComparator().reversed()); | ||
|
||
Comparator<Mod> comparator; | ||
|
||
Sorting(Comparator<Mod> comparator) { | ||
this.comparator = comparator; | ||
} | ||
|
||
public Comparator<Mod> getComparator() { | ||
return comparator; | ||
} | ||
} | ||
|
||
public enum ModCountLocation { | ||
@SerializedName("title_screen") | ||
TITLE_SCREEN(true, false), | ||
@SerializedName("mods_button") | ||
MODS_BUTTON(false, true), | ||
@SerializedName("title_screen_and_mods_button") | ||
TITLE_SCREEN_AND_MODS_BUTTON(true, true), | ||
@SerializedName("none") | ||
NONE(false, false); | ||
|
||
private final boolean titleScreen, modsButton; | ||
|
||
ModCountLocation(boolean titleScreen, boolean modsButton) { | ||
this.titleScreen = titleScreen; | ||
this.modsButton = modsButton; | ||
} | ||
|
||
public boolean isOnTitleScreen() { | ||
return titleScreen; | ||
} | ||
|
||
public boolean isOnModsButton() { | ||
return modsButton; | ||
} | ||
} | ||
|
||
public enum ModsButtonStyle { | ||
@SerializedName("classic") | ||
CLASSIC(false), | ||
@SerializedName("replace_realms") | ||
REPLACE_REALMS(true), | ||
@SerializedName("shrink") | ||
SHRINK(false), | ||
@SerializedName("fabric_icon") | ||
FABRIC_ICON(false); | ||
|
||
private final boolean titleScreenOnly; | ||
|
||
ModsButtonStyle(boolean titleScreenOnly) { | ||
this.titleScreenOnly = titleScreenOnly; | ||
} | ||
|
||
public ModsButtonStyle forGameMenu() { | ||
if (titleScreenOnly) { | ||
return CLASSIC; | ||
} | ||
return this; | ||
} | ||
} | ||
} |
Oops, something went wrong.