Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
6ee3fea
init
RuiXuqi Aug 19, 2025
7d90fab
Lang keys
RuiXuqi Aug 19, 2025
b72cf62
Sync changes
RuiXuqi Aug 25, 2025
228df8f
Adapt cleanroom version check
RuiXuqi Aug 25, 2025
2f54366
Change search lang key
RuiXuqi Aug 26, 2025
4bb77d9
More metadata
RuiXuqi Aug 26, 2025
fc61b53
"/" is a problem
RuiXuqi Aug 26, 2025
a0504da
Minecraft should be a grass block
RuiXuqi Aug 26, 2025
b56b4fa
Logos
RuiXuqi Aug 26, 2025
1648a0b
Update forge and mcp logo, add logoBlur and iconBlur
RuiXuqi Aug 26, 2025
fe30282
Background
RuiXuqi Aug 26, 2025
5d64fe0
Add a dummy mod. TEST ONLY.
RuiXuqi Aug 26, 2025
595b361
Update CatalogueContainer.java
RuiXuqi Aug 26, 2025
965d082
The Great Rename
RuiXuqi Aug 26, 2025
4c5057d
Update CatalogueModListScreen.java
RuiXuqi Aug 26, 2025
fbc15c1
Cherry-pick new features back
RuiXuqi Aug 27, 2025
9c27fb9
Optimize
RuiXuqi Aug 27, 2025
d9592b2
Change root folder name, remove the old mod list
RuiXuqi Aug 27, 2025
b8aa362
Delete GuiSlotModList.java
RuiXuqi Aug 27, 2025
0ae99b9
📦 Cleaned up banner and icon drawing
RuiXuqi Aug 27, 2025
e28f8d8
✨ Added Ctrl + F to focus search textfield
RuiXuqi Aug 27, 2025
b989b98
Slight tweaks
RuiXuqi Aug 27, 2025
31142d9
Update CatalogueContainer.java
RuiXuqi Aug 27, 2025
4d74274
Update lang, remove mod options keys
RuiXuqi Aug 27, 2025
a4a9c1d
Fix typo
RuiXuqi Aug 27, 2025
9e95deb
Move path, load the dummy mod
RuiXuqi Aug 28, 2025
74e38dc
Fix crash with CoFH mods
RuiXuqi Aug 28, 2025
d938889
Change root package
RuiXuqi Aug 28, 2025
e14e608
Regen patches
RuiXuqi Aug 28, 2025
0b50e24
Minecraft Container
RuiXuqi Aug 28, 2025
19780b8
Remove banner.png
RuiXuqi Aug 28, 2025
c91e378
CatalogueConstants
RuiXuqi Aug 28, 2025
b964282
Call directly
RuiXuqi Aug 28, 2025
d8fd7c9
Configurable list of lib mods
RuiXuqi Aug 29, 2025
0683241
Update CatalogueConfig.java
RuiXuqi Aug 29, 2025
1a330b0
Make the structure clearer
RuiXuqi Aug 29, 2025
a57373b
Unnecessary to register scroll buttons
RuiXuqi Aug 29, 2025
3b55025
Update ClientHelper.java
RuiXuqi Aug 29, 2025
ad6ba81
Optimize Ctrl+F to focus
RuiXuqi Aug 30, 2025
4939ee0
Optimize search text field logic
RuiXuqi Aug 30, 2025
fea4d69
Optimize in-game background drawing
RuiXuqi Aug 30, 2025
6098091
Support ":"
RuiXuqi Aug 30, 2025
1995e09
Update CatalogueModListScreen.java
RuiXuqi Aug 30, 2025
563c7de
Update CatalogueIconButton.java
RuiXuqi Aug 30, 2025
88ba37d
Optimize imports
RuiXuqi Aug 30, 2025
3b2b735
Remove all the ":"
RuiXuqi Aug 30, 2025
f486cb9
Update CatalogueModListScreen.java
RuiXuqi Aug 31, 2025
61f96d2
Cleanroom page
RuiXuqi Oct 2, 2025
6d7f3a6
Sync changes
RuiXuqi Oct 3, 2025
05b4a10
Fix filter logic, add config to disable icon limit
RuiXuqi Oct 3, 2025
b516706
Fix scrolling logic, update translation
RuiXuqi Oct 12, 2025
2452473
Optimize
RuiXuqi Oct 19, 2025
2dc3890
Update DropdownMenu.java
RuiXuqi Oct 19, 2025
e3893a6
Sync changes, apply some IDE suggestions
RuiXuqi Nov 1, 2025
909b13c
Fix suggestion overload
RuiXuqi Nov 8, 2025
89a5c54
Add config to disable Catalogue mod
RuiXuqi Nov 21, 2025
66c1d3b
Fix update click
RuiXuqi Nov 22, 2025
431e418
Update CatalogueTextField.java
RuiXuqi Nov 23, 2025
38a57fe
Fix list mouse
RuiXuqi Nov 23, 2025
a6175c5
Fix responder call
RuiXuqi Nov 23, 2025
9107c70
Improve scissor
RuiXuqi Nov 23, 2025
51efc2b
Fix parent screen, use reflection
RuiXuqi Nov 28, 2025
cce5c91
Simplify list creation
RuiXuqi Nov 29, 2025
f5ffc1c
Update CatalogueModListScreen.java
RuiXuqi Dec 6, 2025
1421313
Update forge_at.cfg
RuiXuqi Dec 7, 2025
8c1eca9
Fix some render code
RuiXuqi Dec 12, 2025
d098ffb
Merge branch 'mod-list' into mod-list-sync
RuiXuqi Dec 19, 2025
9a2727e
Optimize item pick, remove item overlay layer
RuiXuqi Dec 19, 2025
20df0d0
Update build.gradle
RuiXuqi Dec 20, 2025
ec3880e
Update build.gradle
RuiXuqi Dec 20, 2025
72a0632
Merge pull request #1 from RuiXuqi/mod-list-sync
RuiXuqi Dec 20, 2025
38a86d7
Add update icon for in game menu
RuiXuqi Dec 20, 2025
1f64491
Fix some items not high enough
RuiXuqi Dec 20, 2025
8eab721
Fix window width and height
RuiXuqi Dec 21, 2025
2c7ced2
Rehandle child mods
RuiXuqi Dec 28, 2025
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
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
--- before/net/minecraft/client/gui/GuiIngameMenu.java
+++ after/net/minecraft/client/gui/GuiIngameMenu.java
@@ -30,9 +30,8 @@
@@ -13,6 +13,7 @@
{
private int saveStep;
private int visibleTime;
+ private net.minecraftforge.client.gui.NotificationModUpdateScreen modUpdateNotification;

@Override
public void initGui()
@@ -30,13 +31,13 @@

this.buttonList.add(new GuiButton(4, this.width / 2 - 100, this.height / 4 + 24 + -16, I18n.format("menu.returnToGame")));
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + -16, 98, 20, I18n.format("menu.options")));
- GuiButton guibutton = this.addButton(
- new GuiButton(7, this.width / 2 + 2, this.height / 4 + 96 + -16, 98, 20, I18n.format("menu.shareToLan"))
- );
+ this.buttonList.add(new GuiButton(12, this.width / 2 + 2, this.height / 4 + 96 + i, 98, 20, I18n.format("fml.menu.modoptions")));
+ GuiButton modButton = this.addButton(new GuiButton(12, this.width / 2 + 2, this.height / 4 + 96 + i, 98, 20, I18n.format("fml.menu.mods")));
+ GuiButton guibutton = this.addButton(new GuiButton(7, this.width / 2 - 100, this.height / 4 + 72 + -16, 200, 20, I18n.format("menu.shareToLan", new Object[0])));
guibutton.enabled = this.mc.isSingleplayer() && !this.mc.getIntegratedServer().getPublic();
this.buttonList
.add(new GuiButton(5, this.width / 2 - 100, this.height / 4 + 48 + -16, 98, 20, I18n.format("gui.advancements")));
@@ -77,13 +76,19 @@
- this.buttonList
- .add(new GuiButton(5, this.width / 2 - 100, this.height / 4 + 48 + -16, 98, 20, I18n.format("gui.advancements")));
+ this.buttonList.add(new GuiButton(5, this.width / 2 - 100, this.height / 4 + 48 + -16, 98, 20, I18n.format("gui.advancements")));
this.buttonList.add(new GuiButton(6, this.width / 2 + 2, this.height / 4 + 48 + -16, 98, 20, I18n.format("gui.stats")));
+
+ this.modUpdateNotification = net.minecraftforge.client.gui.NotificationModUpdateScreen.init(this, modButton);
}

@Override
@@ -77,13 +78,19 @@
this.mc.setIngameFocus();
break;
case 5:
Expand All @@ -32,3 +47,10 @@
}
}

@@ -100,5 +107,6 @@
this.drawDefaultBackground();
this.drawCenteredString(this.fontRenderer, I18n.format("menu.game"), this.width / 2, 40, 16777215);
super.drawScreen(mouseX, mouseY, partialTicks);
+ this.modUpdateNotification.drawScreen(mouseX, mouseY, partialTicks);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@
- this.realmsNotification.setGuiSize(this.width, this.height);
- this.realmsNotification.initGui();
- }
+ modUpdateNotification = net.minecraftforge.client.gui.NotificationModUpdateScreen.init(this, modButton);
+ this.modUpdateNotification = net.minecraftforge.client.gui.NotificationModUpdateScreen.init(this, this.modButton);
}

private void addSingleplayerMultiplayerButtons(int p_73969_1_, int p_73969_2_)
{
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, p_73969_1_, I18n.format("menu.singleplayer")));
this.buttonList.add(new GuiButton(2, this.width / 2 - 100, p_73969_1_ + p_73969_2_ * 1, I18n.format("menu.multiplayer")));
- this.realmsButton = this.addButton(new GuiButton(14, this.width / 2 - 100, p_73969_1_ + p_73969_2_ * 2, I18n.format("menu.online")));
+ this.buttonList.add(modButton = new GuiButton(6, this.width / 2 - 100, p_73969_1_ + p_73969_2_ * 2, I18n.format("fml.menu.mods")));
+ this.buttonList.add(this.modButton = new GuiButton(6, this.width / 2 - 100, p_73969_1_ + p_73969_2_ * 2, I18n.format("fml.menu.mods")));
}

private void addDemoButtons(int p_73972_1_, int p_73972_2_)
Expand Down
1 change: 1 addition & 0 deletions projects/cleanroom/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ configurations {

dependencies {
compileOnly "com.cleanroommc:lwjglx:1.0.0"
compileOnly "org.jetbrains:annotations:26.0.2-1"
installer "com.cleanroommc:lwjglxx:1.1.17"
lwjglLibraries[0].each {
installer "org.lwjgl:$it:$props.lwjgl_version"
Expand Down
94 changes: 94 additions & 0 deletions src/main/java/com/cleanroommc/catalogue/CatalogueConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.cleanroommc.catalogue;

import net.minecraftforge.common.config.Config;
import net.minecraftforge.common.config.ConfigManager;
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.jetbrains.annotations.NotNull;

@Config(modid = CatalogueConstants.MOD_ID)
public class CatalogueConfig {

@Config.Comment({
"Whether enable Catalogue mod.",
"Setting it false will stop Catalogue redirecting Forge's mod list calls."
})
@Config.LangKey("catalogue.config.enable_mod")
public static boolean enableMod = true;

@Config.RequiresMcRestart
@Config.Comment({
"The list of library mods' mod ids.",
"They will have grey names in the mod list."
})
@Config.LangKey("catalogue.config.library_list")
public static String[] libraryList = new String[]{
"forge",
"FML",
"mcp",
"cleanroom",
"configanytime",
"mixinbooter",
"fugue",
"scalar"
};

@Config.RequiresMcRestart
@Config.Comment({
"The list of ignored dependencies' mod ids.",
"They will not be displayed when searching for dependencies/dependants."
})
@Config.LangKey("catalogue.config.ignored_dependencies_list")
public static String[] ignoredDependenciesList = new String[]{
"minecraft",
"forge",
"FML",
"mcp",
"cleanroom"
};

@Config.RequiresMcRestart
@Config.Comment({
"Whether limit the size of mods' banners."
})
@Config.LangKey("catalogue.config.enable_banner_limit")
public static boolean enableBannerLimit = false;

@Config.RequiresMcRestart
@Config.Comment({
"The maximum of banner's width. Will not work if Enable Banner Limit is set false."
})
@Config.LangKey("catalogue.config.banner_max_width")
@Config.RangeInt(min = 0)
public static int bannerMaxWidth = 1280;

@Config.RequiresMcRestart
@Config.Comment({
"The maximum of banner's height. Will not work if Enable Banner Limit is set false."
})
@Config.LangKey("catalogue.config.banner_max_height")
@Config.RangeInt(min = 0)
public static int bannerMaxHeight = 256;

@Config.RequiresMcRestart
@Config.Comment({
"Whether limit the size of mods' icons."
})
@Config.LangKey("catalogue.config.enable_icon_limit")
public static boolean enableIconLimit = false;

@Config.RequiresMcRestart
@Config.Comment({
"The maximum of icon's width and height. Will not work if Enable Icon Limit is set false."
})
@Config.LangKey("catalogue.config.icon_max_width_height")
@Config.RangeInt(min = 0)
public static int iconMaxWidthHeight = 256;

@SubscribeEvent
public static void onConfigChanged(@NotNull ConfigChangedEvent.OnConfigChangedEvent event) {
if (event.getModID().equals(CatalogueConstants.MOD_ID)) {
ConfigManager.sync(CatalogueConstants.MOD_ID, Config.Type.INSTANCE);
}
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/cleanroommc/catalogue/CatalogueConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.cleanroommc.catalogue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CatalogueConstants {
public static final String MOD_ID = "catalogue";
public static final String MOD_NAME = "Catalogue";
public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME);
}
39 changes: 39 additions & 0 deletions src/main/java/com/cleanroommc/catalogue/Utils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.cleanroommc.catalogue;

import net.minecraft.util.ResourceLocation;

import java.util.function.Consumer;

/**
* Author: MrCrayfish
*/
public class Utils {
public static ResourceLocation resource(String name) {
return new ResourceLocation(CatalogueConstants.MOD_ID, name);
}

public static ResourceLocation withDefaultNamespace(String name) {
return resource("textures/gui/sprites/" + name + ".png");
}

public static <T> T make(T object, Consumer<? super T> consumer) {
consumer.accept(object);
return object;
}

public static float lerp(float delta, float start, float end) {
return start + delta * (end - start);
}

public static double lerp(double delta, double start, double end) {
return start + delta * (end - start);
}

public static int roundToward(int value, int factor) {
return positiveCeilDiv(value, factor) * factor;
}

public static int positiveCeilDiv(int x, int y) {
return -Math.floorDiv(-x, y);
}
}
64 changes: 64 additions & 0 deletions src/main/java/com/cleanroommc/catalogue/client/Branding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.cleanroommc.catalogue.client;

import com.cleanroommc.catalogue.CatalogueConstants;
import com.cleanroommc.catalogue.Utils;
import com.cleanroommc.catalogue.exception.InvalidBrandingImageException;
import com.cleanroommc.catalogue.exception.ModResourceNotFoundException;
import com.cleanroommc.catalogue.platform.ClientServices;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.util.ResourceLocation;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.function.Function;

/**
* Author: MrCrayfish
*/
public record Branding(String prefix, int imageWidth, int imageHeight,
BiPredicate<BufferedImage, Branding> predicate,
Function<IModData, String> locator, boolean override) {
public static final Branding ICON = new Branding("icon", ClientServices.PLATFORM.getIconLimit(), ClientServices.PLATFORM.getIconLimit(), ImagePredicate.SQUARE.and(ClientServices.PLATFORM.getEnableIconLimit() ? ImagePredicate.LESS_THAN_OR_EQUAL : ImagePredicate.ANY), IModData::getImageIcon, false);
public static final Branding BANNER = new Branding("banner", ClientServices.PLATFORM.getBannerLimit().maxWidth(), ClientServices.PLATFORM.getBannerLimit().maxHeight(), ClientServices.PLATFORM.getEnableBannerLimit() ? ImagePredicate.LESS_THAN_OR_EQUAL : ImagePredicate.ANY, IModData::getBanner, false);
public static final Branding BACKGROUND = new Branding("background", 512, 256, ImagePredicate.EQUAL, IModData::getBackground, true);

public Optional<ImageInfo> loadResource(IModData data) {
String resource = this.locator.apply(data);
if (resource == null || resource.isBlank()) return Optional.empty();

String modId = data.getModId();
BufferedImage image;
try {
IResourcePack resourcePack = data.getResourcePack();
if (this.equals(Branding.BANNER) && resourcePack != null && !resource.startsWith("/")) {
image = resourcePack.getPackImage();
} else {
resource = resource.startsWith("/") ? resource : "/" + resource;
image = ClientServices.PLATFORM.loadImageFromModResource(modId, resource);
}
this.predicate.test(image, this); // An InvalidBrandingImageException will be thrown if anything is wrong
DynamicTexture texture = new DynamicTexture(image);
ResourceLocation id = this.override ? Utils.resource(this.prefix) :
Utils.resource("%s/%s".formatted(this.prefix, data.getModId()));
Minecraft.getMinecraft().getTextureManager().loadTexture(id, texture);
return Optional.of(new ImageInfo(id, image.getWidth(), image.getHeight(), () -> {
Minecraft.getMinecraft().getTextureManager().deleteTexture(id);
}));
} catch (InvalidBrandingImageException e) {
CatalogueConstants.LOG.error("Invalid {} branding resource '{}' for mod '{}'", this.prefix, resource, modId, e);
} catch (ModResourceNotFoundException e) {
CatalogueConstants.LOG.error("Unable to locate the {} branding resource '{}' for mod '{}'", this.prefix, resource, modId, e);
} catch (IOException e) {
CatalogueConstants.LOG.error("An error occurred when loading the {} branding resource '{}' for mod '{}'", this.prefix, resource, modId, e);
}

return Optional.empty();
}

public record BannerLimit(int maxWidth, int maxHeight) {
}
}
Loading