283 lines
13 KiB
Java
283 lines
13 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.google.common.collect.Lists
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.client.gui.screens.advancements;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import java.util.List;
|
|
import net.minecraft.advancements.AdvancementNode;
|
|
import net.minecraft.advancements.AdvancementProgress;
|
|
import net.minecraft.advancements.DisplayInfo;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.StringSplitter;
|
|
import net.minecraft.client.gui.Font;
|
|
import net.minecraft.client.gui.GuiGraphics;
|
|
import net.minecraft.client.gui.screens.advancements.AdvancementTab;
|
|
import net.minecraft.client.gui.screens.advancements.AdvancementWidgetType;
|
|
import net.minecraft.client.renderer.RenderPipelines;
|
|
import net.minecraft.locale.Language;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.chat.ComponentUtils;
|
|
import net.minecraft.network.chat.FormattedText;
|
|
import net.minecraft.network.chat.MutableComponent;
|
|
import net.minecraft.network.chat.Style;
|
|
import net.minecraft.resources.Identifier;
|
|
import net.minecraft.util.FormattedCharSequence;
|
|
import net.minecraft.util.Mth;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public class AdvancementWidget {
|
|
private static final Identifier TITLE_BOX_SPRITE = Identifier.withDefaultNamespace("advancements/title_box");
|
|
private static final int HEIGHT = 26;
|
|
private static final int BOX_X = 0;
|
|
private static final int BOX_WIDTH = 200;
|
|
private static final int FRAME_WIDTH = 26;
|
|
private static final int ICON_X = 8;
|
|
private static final int ICON_Y = 5;
|
|
private static final int ICON_WIDTH = 26;
|
|
private static final int TITLE_PADDING_LEFT = 3;
|
|
private static final int TITLE_PADDING_RIGHT = 5;
|
|
private static final int TITLE_X = 32;
|
|
private static final int TITLE_PADDING_TOP = 9;
|
|
private static final int TITLE_PADDING_BOTTOM = 8;
|
|
private static final int TITLE_MAX_WIDTH = 163;
|
|
private static final int TITLE_MIN_WIDTH = 80;
|
|
private static final int[] TEST_SPLIT_OFFSETS = new int[]{0, 10, -10, 25, -25};
|
|
private final AdvancementTab tab;
|
|
private final AdvancementNode advancementNode;
|
|
private final DisplayInfo display;
|
|
private final List<FormattedCharSequence> titleLines;
|
|
private final int width;
|
|
private final List<FormattedCharSequence> description;
|
|
private final Minecraft minecraft;
|
|
private @Nullable AdvancementWidget parent;
|
|
private final List<AdvancementWidget> children = Lists.newArrayList();
|
|
private @Nullable AdvancementProgress progress;
|
|
private final int x;
|
|
private final int y;
|
|
|
|
public AdvancementWidget(AdvancementTab tab, Minecraft minecraft, AdvancementNode advancementNode, DisplayInfo display) {
|
|
this.tab = tab;
|
|
this.advancementNode = advancementNode;
|
|
this.display = display;
|
|
this.minecraft = minecraft;
|
|
this.titleLines = minecraft.font.split(display.getTitle(), 163);
|
|
this.x = Mth.floor(display.getX() * 28.0f);
|
|
this.y = Mth.floor(display.getY() * 27.0f);
|
|
int titleWidth = Math.max(this.titleLines.stream().mapToInt(minecraft.font::width).max().orElse(0), 80);
|
|
int maxProgressWidth = this.getMaxProgressWidth();
|
|
int longestDescLine = 29 + titleWidth + maxProgressWidth;
|
|
this.description = Language.getInstance().getVisualOrder(this.findOptimalLines(ComponentUtils.mergeStyles(display.getDescription(), Style.EMPTY.withColor(display.getType().getChatColor())), longestDescLine));
|
|
for (FormattedCharSequence line : this.description) {
|
|
longestDescLine = Math.max(longestDescLine, minecraft.font.width(line));
|
|
}
|
|
this.width = longestDescLine + 3 + 5;
|
|
}
|
|
|
|
private int getMaxProgressWidth() {
|
|
int maxCriteraRequired = this.advancementNode.advancement().requirements().size();
|
|
if (maxCriteraRequired <= 1) {
|
|
return 0;
|
|
}
|
|
int spacing = 8;
|
|
MutableComponent fakeMaxProgress = Component.translatable("advancements.progress", maxCriteraRequired, maxCriteraRequired);
|
|
return this.minecraft.font.width(fakeMaxProgress) + 8;
|
|
}
|
|
|
|
private static float getMaxWidth(StringSplitter splitter, List<FormattedText> input) {
|
|
return (float)input.stream().mapToDouble(splitter::stringWidth).max().orElse(0.0);
|
|
}
|
|
|
|
private List<FormattedText> findOptimalLines(Component input, int preferredWidth) {
|
|
StringSplitter splitter = this.minecraft.font.getSplitter();
|
|
List<FormattedText> bestSplit = null;
|
|
float bestDistance = Float.MAX_VALUE;
|
|
for (int testMargin : TEST_SPLIT_OFFSETS) {
|
|
List<FormattedText> testSplit = splitter.splitLines(input, preferredWidth - testMargin, Style.EMPTY);
|
|
float distance = Math.abs(AdvancementWidget.getMaxWidth(splitter, testSplit) - (float)preferredWidth);
|
|
if (distance <= 10.0f) {
|
|
return testSplit;
|
|
}
|
|
if (!(distance < bestDistance)) continue;
|
|
bestDistance = distance;
|
|
bestSplit = testSplit;
|
|
}
|
|
return bestSplit;
|
|
}
|
|
|
|
private @Nullable AdvancementWidget getFirstVisibleParent(AdvancementNode node) {
|
|
while ((node = node.parent()) != null && node.advancement().display().isEmpty()) {
|
|
}
|
|
if (node == null || node.advancement().display().isEmpty()) {
|
|
return null;
|
|
}
|
|
return this.tab.getWidget(node.holder());
|
|
}
|
|
|
|
public void drawConnectivity(GuiGraphics graphics, int xo, int yo, boolean background) {
|
|
if (this.parent != null) {
|
|
int col;
|
|
int depX = xo + this.parent.x + 13;
|
|
int splitX = xo + this.parent.x + 26 + 4;
|
|
int depY = yo + this.parent.y + 13;
|
|
int myX = xo + this.x + 13;
|
|
int myY = yo + this.y + 13;
|
|
int n = col = background ? -16777216 : -1;
|
|
if (background) {
|
|
graphics.hLine(splitX, depX, depY - 1, col);
|
|
graphics.hLine(splitX + 1, depX, depY, col);
|
|
graphics.hLine(splitX, depX, depY + 1, col);
|
|
graphics.hLine(myX, splitX - 1, myY - 1, col);
|
|
graphics.hLine(myX, splitX - 1, myY, col);
|
|
graphics.hLine(myX, splitX - 1, myY + 1, col);
|
|
graphics.vLine(splitX - 1, myY, depY, col);
|
|
graphics.vLine(splitX + 1, myY, depY, col);
|
|
} else {
|
|
graphics.hLine(splitX, depX, depY, col);
|
|
graphics.hLine(myX, splitX, myY, col);
|
|
graphics.vLine(splitX, myY, depY, col);
|
|
}
|
|
}
|
|
for (AdvancementWidget child : this.children) {
|
|
child.drawConnectivity(graphics, xo, yo, background);
|
|
}
|
|
}
|
|
|
|
public void draw(GuiGraphics graphics, int xo, int yo) {
|
|
if (!this.display.isHidden() || this.progress != null && this.progress.isDone()) {
|
|
float amount = this.progress == null ? 0.0f : this.progress.getPercent();
|
|
AdvancementWidgetType iconFrame = amount >= 1.0f ? AdvancementWidgetType.OBTAINED : AdvancementWidgetType.UNOBTAINED;
|
|
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, iconFrame.frameSprite(this.display.getType()), xo + this.x + 3, yo + this.y, 26, 26);
|
|
graphics.renderFakeItem(this.display.getIcon(), xo + this.x + 8, yo + this.y + 5);
|
|
}
|
|
for (AdvancementWidget child : this.children) {
|
|
child.draw(graphics, xo, yo);
|
|
}
|
|
}
|
|
|
|
public int getWidth() {
|
|
return this.width;
|
|
}
|
|
|
|
public void setProgress(AdvancementProgress progress) {
|
|
this.progress = progress;
|
|
}
|
|
|
|
public void addChild(AdvancementWidget widget) {
|
|
this.children.add(widget);
|
|
}
|
|
|
|
public void drawHover(GuiGraphics graphics, int xo, int yo, float fade, int screenxo, int screenyo) {
|
|
AdvancementWidgetType iconFrame;
|
|
AdvancementWidgetType secondHalf;
|
|
AdvancementWidgetType firstHalf;
|
|
Font font = this.minecraft.font;
|
|
int titleBarHeight = font.lineHeight * this.titleLines.size() + 9 + 8;
|
|
int titleTop = yo + this.y + (26 - titleBarHeight) / 2;
|
|
int titleBarBottom = titleTop + titleBarHeight;
|
|
int descriptionTextHeight = this.description.size() * font.lineHeight;
|
|
int descriptionHeight = 6 + descriptionTextHeight;
|
|
boolean leftSide = screenxo + xo + this.x + this.width + 26 >= this.tab.getScreen().width;
|
|
Component progressText = this.progress == null ? null : this.progress.getProgressText();
|
|
int progressWidth = progressText == null ? 0 : font.width(progressText);
|
|
boolean topSide = titleBarBottom + descriptionHeight >= 113;
|
|
float amount = this.progress == null ? 0.0f : this.progress.getPercent();
|
|
int firstHalfWidth = Mth.floor(amount * (float)this.width);
|
|
if (amount >= 1.0f) {
|
|
firstHalfWidth = this.width / 2;
|
|
firstHalf = AdvancementWidgetType.OBTAINED;
|
|
secondHalf = AdvancementWidgetType.OBTAINED;
|
|
iconFrame = AdvancementWidgetType.OBTAINED;
|
|
} else if (firstHalfWidth < 2) {
|
|
firstHalfWidth = this.width / 2;
|
|
firstHalf = AdvancementWidgetType.UNOBTAINED;
|
|
secondHalf = AdvancementWidgetType.UNOBTAINED;
|
|
iconFrame = AdvancementWidgetType.UNOBTAINED;
|
|
} else if (firstHalfWidth > this.width - 2) {
|
|
firstHalfWidth = this.width / 2;
|
|
firstHalf = AdvancementWidgetType.OBTAINED;
|
|
secondHalf = AdvancementWidgetType.OBTAINED;
|
|
iconFrame = AdvancementWidgetType.UNOBTAINED;
|
|
} else {
|
|
firstHalf = AdvancementWidgetType.OBTAINED;
|
|
secondHalf = AdvancementWidgetType.UNOBTAINED;
|
|
iconFrame = AdvancementWidgetType.UNOBTAINED;
|
|
}
|
|
int secondBarWidth = this.width - firstHalfWidth;
|
|
int titleLeft = leftSide ? xo + this.x - this.width + 26 + 6 : xo + this.x;
|
|
int backgroundHeight = titleBarHeight + descriptionHeight;
|
|
if (!this.description.isEmpty()) {
|
|
if (topSide) {
|
|
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TITLE_BOX_SPRITE, titleLeft, titleBarBottom - backgroundHeight, this.width, backgroundHeight);
|
|
} else {
|
|
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TITLE_BOX_SPRITE, titleLeft, titleTop, this.width, backgroundHeight);
|
|
}
|
|
}
|
|
if (firstHalf != secondHalf) {
|
|
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, firstHalf.boxSprite(), 200, titleBarHeight, 0, 0, titleLeft, titleTop, firstHalfWidth, titleBarHeight);
|
|
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, secondHalf.boxSprite(), 200, titleBarHeight, 200 - secondBarWidth, 0, titleLeft + firstHalfWidth, titleTop, secondBarWidth, titleBarHeight);
|
|
} else {
|
|
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, firstHalf.boxSprite(), titleLeft, titleTop, this.width, titleBarHeight);
|
|
}
|
|
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, iconFrame.frameSprite(this.display.getType()), xo + this.x + 3, yo + this.y, 26, 26);
|
|
int descriptionLeft = titleLeft + 5;
|
|
if (leftSide) {
|
|
this.drawMultilineText(graphics, this.titleLines, descriptionLeft, titleTop + 9, -1);
|
|
if (progressText != null) {
|
|
graphics.drawString(font, progressText, xo + this.x - progressWidth, titleTop + 9, -1);
|
|
}
|
|
} else {
|
|
this.drawMultilineText(graphics, this.titleLines, xo + this.x + 32, titleTop + 9, -1);
|
|
if (progressText != null) {
|
|
graphics.drawString(font, progressText, xo + this.x + this.width - progressWidth - 5, titleTop + 9, -1);
|
|
}
|
|
}
|
|
if (topSide) {
|
|
this.drawMultilineText(graphics, this.description, descriptionLeft, titleTop - descriptionTextHeight + 1, -16711936);
|
|
} else {
|
|
this.drawMultilineText(graphics, this.description, descriptionLeft, titleBarBottom, -16711936);
|
|
}
|
|
graphics.renderFakeItem(this.display.getIcon(), xo + this.x + 8, yo + this.y + 5);
|
|
}
|
|
|
|
private void drawMultilineText(GuiGraphics graphics, List<FormattedCharSequence> lines, int x, int y, int color) {
|
|
Font font = this.minecraft.font;
|
|
for (int i = 0; i < lines.size(); ++i) {
|
|
graphics.drawString(font, lines.get(i), x, y + i * font.lineHeight, color);
|
|
}
|
|
}
|
|
|
|
public boolean isMouseOver(int xo, int yo, int mouseX, int mouseY) {
|
|
if (this.display.isHidden() && (this.progress == null || !this.progress.isDone())) {
|
|
return false;
|
|
}
|
|
int x0 = xo + this.x;
|
|
int x1 = x0 + 26;
|
|
int y0 = yo + this.y;
|
|
int y1 = y0 + 26;
|
|
return mouseX >= x0 && mouseX <= x1 && mouseY >= y0 && mouseY <= y1;
|
|
}
|
|
|
|
public void attachToParent() {
|
|
if (this.parent == null && this.advancementNode.parent() != null) {
|
|
this.parent = this.getFirstVisibleParent(this.advancementNode);
|
|
if (this.parent != null) {
|
|
this.parent.addChild(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
public int getY() {
|
|
return this.y;
|
|
}
|
|
|
|
public int getX() {
|
|
return this.x;
|
|
}
|
|
}
|
|
|