Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
49 changes: 48 additions & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,12 @@ jobs:
MAIN_BC: ${{ needs.main-roseau.outputs.has_bc }}
MAIN_N: ${{ needs.main-roseau.outputs.bc_count }}
steps:
- name: Download Roseau reports
uses: actions/download-artifact@v4
with:
pattern: roseau-*
path: roseau-reports

- name: Generate and post PR comment
run: |
row() {
Expand Down Expand Up @@ -398,9 +404,50 @@ jobs:
row "wheel" "$WHEEL_BC" "$WHEEL_N"
row "main" "$MAIN_BC" "$MAIN_N"
echo ""
echo "> Detailed reports: see the *Artifacts* section of [this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})."
} > /tmp/roseau-body.md

# Append breaking change details for each affected module
append_details() {
local mod=$1 bc=$2 count=$3
if [ "$bc" != "true" ]; then return; fi
local csv="roseau-reports/roseau-${mod}/report.csv"
if [ ! -f "$csv" ]; then return; fi
{
echo "### 🔴 ${mod} — ${count} breaking change(s)"
echo ""
while IFS=';' read -r type symbol kind nature location newSymbol binaryBreaking sourceBreaking; do
echo "#### \`${location}\`"
echo '```'
echo "${type}"
echo "${symbol}"
echo "${kind}"
[ "$binaryBreaking" = "true" ] && echo "✗ binary-breaking" || echo "✓ binary-compatible"
[ "$sourceBreaking" = "true" ] && echo "✗ source-breaking" || echo "✓ source-compatible"
echo '```'
echo ""
done < <(tail -n +2 "$csv")
} >> /tmp/roseau-body.md
}

append_details "codec" "$CODEC_BC" "$CODEC_N"
append_details "collision" "$COLLISION_BC" "$COLLISION_N"
append_details "config" "$CONFIG_BC" "$CONFIG_N"
append_details "font" "$FONT_BC" "$FONT_N"
append_details "integration" "$INTEGRATION_BC" "$INTEGRATION_N"
append_details "moveable-entity-block" "$MEB_BC" "$MEB_N"
append_details "multiblock" "$MULTIBLOCK_BC" "$MULTIBLOCK_N"
append_details "network" "$NETWORK_BC" "$NETWORK_N"
append_details "recipe" "$RECIPE_BC" "$RECIPE_N"
append_details "registrum" "$REGISTRUM_BC" "$REGISTRUM_N"
append_details "rendering" "$RENDERING_BC" "$RENDERING_N"
append_details "space-select" "$SPACESELECT_BC" "$SPACESELECT_N"
append_details "sync" "$SYNC_BC" "$SYNC_N"
append_details "util" "$UTIL_BC" "$UTIL_N"
append_details "wheel" "$WHEEL_BC" "$WHEEL_N"
append_details "main" "$MAIN_BC" "$MAIN_N"

echo "> Full CSVs: see the *Artifacts* section of [this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})." >> /tmp/roseau-body.md

- name: Find existing Roseau comment
id: find-comment
uses: peter-evans/find-comment@v3
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/roseau_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ jobs:
- name: Run roseauCheck
id: roseau
continue-on-error: true
run: ./gradlew :${{ inputs.module_id }}-neoforge-26.1:roseauCheck
run: |
chmod +x ./gradlew
./gradlew :${{ inputs.module_id }}-neoforge-26.1:roseauCheck

- name: Collect result
id: result
Expand Down
3 changes: 3 additions & 0 deletions gradle/scripts/roseau.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ def roseauBaselineVersion = project.findProperty('roseauBaselineVersion') ?: {
def roseauMvnCoord = "${roseauGroup}:${roseauArtifact}:${roseauBaselineVersion}"
def roseauBaselineDep = dependencies.create(group: roseauGroup, name: roseauArtifact, version: roseauBaselineVersion)
def roseauBaselineConfig = configurations.detachedConfiguration(roseauBaselineDep)
roseauBaselineConfig.transitive = false
def roseauBaselineJarProvider = provider { roseauBaselineConfig.singleFile }
def roseauConfig = rootProject.file("roseau.yaml").absolutePath

tasks.register('roseauCheck', JavaExec) {
group = 'verification'
Expand Down Expand Up @@ -71,6 +73,7 @@ tasks.register('roseauCheck', JavaExec) {
'--fail-on-bc',
'--report', "HTML=${new File(reportsDir, 'report.html').absolutePath}",
'--report', "CSV=${new File(reportsDir, 'report.csv').absolutePath}",
'--config', roseauConfig
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexFormatElement;
import lombok.extern.slf4j.Slf4j;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.RegisterRenderPipelinesEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jetbrains.annotations.ApiStatus;

/**
* Font module render pipeline registration.
*
* <p>The pipeline is ready for SDF text quad rendering and will be consumed by the
* runtime text render state in a follow-up step.</p>
*/
@ApiStatus.Internal
@Slf4j
@EventBusSubscriber(modid = AnvilLibFont.MOD_ID, value = Dist.CLIENT)
public final class ALFPipelines {
private static final Logger LOGGER = LoggerFactory.getLogger(ALFPipelines.class);

public static final VertexFormat SDF_TEXT_FORMAT = VertexFormat.builder()
.add("Position", VertexFormatElement.POSITION)
.add("Color", VertexFormatElement.COLOR)
Expand All @@ -47,7 +47,7 @@ private ALFPipelines() {
@SubscribeEvent
public static void on(RegisterRenderPipelinesEvent event) {
event.registerPipeline(SDF_TEXT);
LOGGER.info("Registered SDF_TEXT pipeline: {}", SDF_TEXT);
log.info("Registered SDF_TEXT pipeline: {}", SDF_TEXT);
}
}

Expand Down
15 changes: 5 additions & 10 deletions module.font/src/main/java/dev/anvilcraft/lib/v2/font/ALFont.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.anvilcraft.lib.v2.font;

import com.google.common.annotations.Beta;
import dev.anvilcraft.lib.v2.font.sdf.SdfGlyphAtlas;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.FormattedText;
Expand All @@ -10,12 +11,12 @@
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import org.jspecify.annotations.Nullable;

/**
* Wraps {@link Font} with text measurement and layout utilities that
* delegate to {@link SdfGlyphAtlas} for glyph metrics.
*/
@Beta
public class ALFont {
public final int lineHeight = Minecraft.getInstance().font.lineHeight;
private final Font font;
Expand All @@ -26,19 +27,16 @@ public ALFont(Font font) {

public Font awtFont() { return this.font; }

private @Nullable SdfGlyphAtlas atlas() { return SdfGlyphAtlas.getIfReady(this.font); }
private SdfGlyphAtlas atlasBlocking() { return SdfGlyphAtlas.getOrCreate(this.font).join(); }
private SdfGlyphAtlas atlas() { return SdfGlyphAtlas.getOrCreate(this.font).join(); }

private float scale() {
SdfGlyphAtlas a = atlas();
return a == null ? 1f : (float) lineHeight / a.awtHeight();
return (float) lineHeight / atlas().awtHeight();
}

// ── Width measurement ───────────────────────────────────────

public int width(String str) {
SdfGlyphAtlas a = atlas();
return a == null ? 0 : Mth.ceil(a.measureText(str) * scale());
return Mth.ceil(atlas().measureText(str) * scale());
}

public int width(FormattedText text) { return width(text.getString()); }
Expand All @@ -58,7 +56,6 @@ public String plainSubstrByWidth(String str, int maxWidth) {

private String plainHeadByWidth(String str, int maxWidth) {
SdfGlyphAtlas a = atlas();
if (a == null) return str;
float s = scale();
if (a.measureText(str) * s <= maxWidth) return str;
int lo = 0, hi = str.length();
Expand All @@ -72,7 +69,6 @@ private String plainHeadByWidth(String str, int maxWidth) {

private String plainTailByWidth(String str, int maxWidth) {
SdfGlyphAtlas a = atlas();
if (a == null) return str;
float s = scale();
if (a.measureText(str) * s <= maxWidth) return str;
int lo = 0, hi = str.length();
Expand All @@ -92,7 +88,6 @@ public FormattedText substrByWidth(FormattedText text, int maxWidth) {

public List<FormattedCharSequence> split(FormattedText input, int maxWidth) {
SdfGlyphAtlas a = atlas();
if (a == null) return List.of(FormattedCharSequence.forward(input.getString(), Style.EMPTY));
float s = scale();
List<String> lines = wrapLines(a, input.getString(), maxWidth, s);
List<FormattedCharSequence> result = new ArrayList<>(lines.size());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.anvilcraft.lib.v2.font;

import dev.anvilcraft.lib.v2.font.screen.FontConfigScreen;
import dev.anvilcraft.lib.v2.font.sdf.SdfGlyphAtlas;
import net.minecraft.resources.Identifier;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.ModContainer;
Expand All @@ -9,6 +10,7 @@
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;

import java.awt.Font;
import java.util.List;

@EventBusSubscriber
@Mod(value = AnvilLibFont.MOD_ID, dist = Dist.CLIENT)
Expand All @@ -20,10 +22,22 @@ public class AnvilLibFont {
public AnvilLibFont(ModContainer container) {
AnvilLibFontConfig.AnvilLibFontConfigManager.readConfig(AnvilLibFont.CONFIG);
container.registerExtensionPoint(IConfigScreenFactory.class, FontConfigScreen::new);
// Start building the SDF atlas for the base font and all common style
// variants on background threads at mod init time. This avoids render-
// thread blocking (visible lag) when bold/italic text is first drawn.
Font base = getSelectFont();
SdfGlyphAtlas.getOrCreate(base);
for (int style : List.of(Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC)) {
SdfGlyphAtlas.getOrCreate(base.deriveFont(style));
}
}

public static Font getSelectFont() {
return FontManager.INSTANCE.getFont(AnvilLibFont.CONFIG.getFont());
Font font = FontManager.INSTANCE.getFont(AnvilLibFont.CONFIG.getFont());
// Eagerly start building the SDF atlas on a background thread so it is
// ready (or nearly ready) by the time the first text is rendered.
SdfGlyphAtlas.getOrCreate(font);
return font;
}

public static Identifier of(String path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.neoforged.fml.loading.FMLLoader;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;

import java.io.File;
Expand Down Expand Up @@ -41,6 +42,7 @@ public void setFont(String font) {
AnvilLibFontConfigManager.saveConfig(this);
}

@ApiStatus.Internal
@Slf4j
public static class AnvilLibFontConfigManager {
public static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.anvilcraft.lib.v2.font;

import com.google.common.annotations.Beta;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import lombok.Getter;
Expand All @@ -19,6 +20,7 @@
import java.util.TreeSet;
import javax.swing.UIManager;

@Beta
@Slf4j
@Getter
public class FontManager {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.common.data.LanguageProvider;
import net.neoforged.neoforge.data.event.GatherDataEvent;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
@EventBusSubscriber(modid = AnvilLibFont.MOD_ID)
public class AnvilLibFontData {
@SubscribeEvent
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.anvilcraft.lib.v2.font.extension;

import com.google.common.annotations.Beta;
import dev.anvilcraft.lib.v2.font.sdf.SdfTextRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
Expand All @@ -11,6 +12,7 @@

import java.awt.Font;

@Beta
public interface GuiGraphicsExtractorExtension {
default GuiGraphicsExtractor self() {
return (GuiGraphicsExtractor) this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import dev.anvilcraft.lib.v2.font.extension.GuiGraphicsExtractorExtension;
import dev.anvilcraft.lib.v2.font.sdf.SdfTextRenderer;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import org.jetbrains.annotations.ApiStatus;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;

@ApiStatus.Internal
@Mixin(GuiGraphicsExtractor.class)
public abstract class GuiGraphicsExtractorMixin implements GuiGraphicsExtractorExtension {
@Unique
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.neoforged.fml.ModContainer;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

@ApiStatus.Internal
public class FontConfigScreen extends Screen {
protected final Screen lastScreen;
private Dropdown.@Nullable Shielding shielding;
Expand Down Expand Up @@ -96,7 +98,7 @@ protected void init() {

this.refreshFontOptions(this.familyDropdown.getValueId(), AnvilLibFont.CONFIG.getFont(), false);

this.familyDropdown.setValue(AnvilLibFont.CONFIG.getFont());
this.fontDropdown.setValue(AnvilLibFont.CONFIG.getFont());

this.addRenderableWidget(this.testBtn);
this.addRenderableWidget(this.fontDropdown);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import org.joml.Matrix3x2fStack;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
public class FontTestScreen extends Screen {
protected final Screen lastScreen;

Expand All @@ -30,7 +31,7 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo
);
graphics.anvillib$centeredText(
AnvilLibFont.getSelectFont(),
Component.literal("请不要关闭你的计算机").withStyle(ChatFormatting.GREEN),
Component.literal("请不要关闭你的计算机").withStyle(Style.EMPTY.withColor(ChatFormatting.GREEN).withStrikethrough(true)),
offsetX,
offsetY + this.font.lineHeight,
0xFFFFFFFF
Expand Down Expand Up @@ -60,7 +61,7 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo
graphics.anvillib$centeredText(
AnvilLibFont.getSelectFont(),
Component.literal("The quick brown fox jumped over the lazy dog.")
.withStyle(Style.EMPTY.withItalic(true).withColor(ChatFormatting.DARK_PURPLE)),
.withStyle(Style.EMPTY.withItalic(true).withColor(ChatFormatting.DARK_PURPLE).withUnderlined(true)),
offsetX,
offsetY + this.font.lineHeight * 5,
0xFFFFFFFF
Expand All @@ -87,6 +88,14 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo
offsetY + this.font.lineHeight * 8,
0xFFFFFFFF
);
graphics.anvillib$centeredText(
AnvilLibFont.getSelectFont(),
Component.literal("混淆文字测试")
.withStyle(Style.EMPTY.withItalic(true).withBold(true).withObfuscated(true)),
offsetX,
offsetY + this.font.lineHeight * 9,
0xFFFFFFFF
);
}

@Override
Expand Down
Loading
Loading