font: load bundled .ttf/.otf fonts from fontfiles/ and config/angelia/fonts/ (#1904)

This commit is contained in:
GribanovIvan authored and GitHub committed 2026-07-04 12:16:48 -07:00
1 parent 610209605f
commit ecbf8fea2f
1 file changed
+50 -5
@@ -11,9 +11,13 @@ import net.minecraft.client.resources.DefaultResourcePack;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import cpw.mods.fml.common.Loader;
import java.awt.Font; import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment; import java.awt.GraphicsEnvironment;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@@ -27,13 +31,13 @@ public class FontStrategist {
public static final Logger LOGGER = LogManager.getLogger("Angelica"); public static final Logger LOGGER = LogManager.getLogger("Angelica");
static { static {
HashMap<String, Font> fontSet = new HashMap<>();
if (GraphicsEnvironment.isHeadless()) { if (GraphicsEnvironment.isHeadless()) {
LOGGER.warn("GraphicsEnvironment.isHeadless() returned true! Custom fonts will be unavailable. This is likely a MacOS issue."); LOGGER.warn("GraphicsEnvironment.isHeadless() returned true! Only bundled fonts will be available. This is likely a MacOS issue.");
availableFonts = new Font[0];
} else { } else {
// get available fonts without duplicates (250 copies of dialog.plain need not apply) // get available fonts without duplicates (250 copies of dialog.plain need not apply)
Font[] availableFontsDirty = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); Font[] availableFontsDirty = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
HashMap<String, Font> fontSet = new HashMap<>();
HashMultiset<String> duplicates = HashMultiset.create(); // for debugging HashMultiset<String> duplicates = HashMultiset.create(); // for debugging
for (Font font : availableFontsDirty) { for (Font font : availableFontsDirty) {
@@ -57,11 +61,14 @@ public class FontStrategist {
sb.append(". Some fonts may be missing from the font selection menu."); sb.append(". Some fonts may be missing from the font selection menu.");
LOGGER.warn(sb.toString()); LOGGER.warn(sb.toString());
} }
availableFonts = fontSet.values().stream().sorted(Comparator.comparing(Font::getFontName)).toArray(Font[]::new);
LOGGER.info("Got {} fonts from GraphicsEnvironment ({} after deduplication)", availableFontsDirty.length, availableFonts.length); LOGGER.info("Got {} fonts from GraphicsEnvironment ({} after deduplication)", availableFontsDirty.length, fontSet.size());
} }
loadBundledFonts(fontSet);
availableFonts = fontSet.values().stream().sorted(Comparator.comparing(Font::getFontName)).toArray(Font[]::new);
// create and add the resource pack that provides fonts // create and add the resource pack that provides fonts
HashMap<String, File> packMap = new HashMap<>(); HashMap<String, File> packMap = new HashMap<>();
for (int i = 0; i < FontProviderCustom.ATLAS_COUNT; i++) { for (int i = 0; i < FontProviderCustom.ATLAS_COUNT; i++) {
@@ -74,6 +81,44 @@ public class FontStrategist {
defaultResourcePacks.add(fontResourcePack); defaultResourcePacks.add(fontResourcePack);
} }
// Load .ttf/.otf shipped with the pack so customFontName* can point at a font that isn't installed
// on the system. fontfiles/ is SmoothFont's folder, kept so packs built for it work unchanged.
private static void loadBundledFonts(HashMap<String, Font> fontSet) {
File configDir = Loader.instance().getConfigDir();
if (configDir == null) {
LOGGER.warn("Loader.instance().getConfigDir() returned null. Bundled fonts will not be loaded.");
return;
}
File parent = configDir.getParentFile();
File[] fontDirs = { new File(parent, "fontfiles"), new File(configDir, "angelica/fonts") };
GraphicsEnvironment ge = GraphicsEnvironment.isHeadless() ? null : GraphicsEnvironment.getLocalGraphicsEnvironment();
int loaded = 0;
for (File dir : fontDirs) {
File[] files = dir.listFiles((d, name) -> name.toLowerCase().endsWith(".ttf") || name.toLowerCase().endsWith(".otf"));
if (files == null) continue;
for (File file : files) {
try {
Font font = Font.createFont(Font.TRUETYPE_FONT, file);
String name = font.getFontName();
if (fontSet.containsKey(name)) {
String deduped = name;
int n = 1;
while (fontSet.containsKey(deduped)) deduped = name + "_" + n++;
LOGGER.warn("Font name {} (from {}) is already registered; registering this one as {}", name, file.getName(), deduped);
name = deduped;
}
if (ge != null) ge.registerFont(font);
fontSet.put(name, font);
loaded++;
LOGGER.info("Loaded font {} from {}/{}", name, dir.getName(), file.getName());
} catch (FontFormatException | IOException e) {
LOGGER.error("Couldn't load font {}", file.getPath(), e);
}
}
}
if (loaded > 0) LOGGER.info("Loaded {} bundled font(s) from the pack", loaded);
}
/** /**
Lets you get a FontProvider per char while respecting font priority and fallbacks, the unicode flag, whether Lets you get a FontProvider per char while respecting font priority and fallbacks, the unicode flag, whether
SGA is on, if we're in a splash screen, if a font can even display a character in the first place, etc. SGA is on, if we're in a splash screen, if a font can even display a character in the first place, etc.