Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -3,6 +3,7 @@
import de.hysky.skyblocker.skyblock.dwarven.CorpseType;
import de.hysky.skyblocker.skyblock.itemlist.ItemRepository;
import de.hysky.skyblocker.utils.FlexibleItemStack;
import de.hysky.skyblocker.utils.Formatters;
import de.hysky.skyblocker.utils.render.GuiHelper;
import org.apache.commons.text.WordUtils;
import org.jspecify.annotations.Nullable;
Expand All @@ -12,39 +13,35 @@
import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;

import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.StringWidget;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.network.chat.Component;

public class CorpseList extends ContainerObjectSelectionList<CorpseList.AbstractEntry> {
public class CorpseList extends ContainerObjectSelectionList<RewardList.AbstractEntry> {
private static final Logger LOGGER = LoggerFactory.getLogger(CorpseList.class);
private static final int BORDER_COLOR = 0xFF6C7086;
private static final int INNER_MARGIN = 2;

public CorpseList(Minecraft client, int width, int height, int y, int entryHeight, List<CorpseLoot> lootList) {
super(client, width, height, y, entryHeight);
public CorpseList(Minecraft client, int width, int height, int entryHeight, List<CorpseLoot> lootList) {
super(client, width, height, 0, entryHeight);
if (lootList.isEmpty()) {
addEmptyEntry();
addEmptyEntry();
addEmptyEntry();
addEntry(new CorpseList.SingleEntry(Component.literal("Your corpse history list is empty :(").withStyle(ChatFormatting.RED), false));
addEntry(new RewardList.SingleEntry(Component.literal("Your corpse history list is empty :(").withStyle(ChatFormatting.RED), false));
return;
}

for (int i = 0; i < lootList.size(); i++) {
CorpseLoot loot = lootList.get(i);
CorpseType type = loot.corpseType();
addEntry(new CorpseList.SingleEntry(Component.literal(WordUtils.capitalizeFully(type.name()) + " Corpse").withStyle(type.color)));
//TODO: Make this use the Formatters class instead when it's added
addEntry(new CorpseList.SingleEntry(Component.literal(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.ofInstant(loot.timestamp(), ZoneId.systemDefault()))).withStyle(ChatFormatting.LIGHT_PURPLE)));
addEntry(new RewardList.SingleEntry(Component.literal(WordUtils.capitalizeFully(type.name()) + " Corpse").withStyle(type.color)));
addEntry(new RewardList.SingleEntry(Component.literal(Formatters.DATE_FORMATTER.format(LocalDateTime.ofInstant(loot.timestamp(), ZoneId.systemDefault()))).withStyle(ChatFormatting.LIGHT_PURPLE)));

List<Reward> entries = loot.rewards();
for (Reward reward : entries) {
Expand All @@ -60,7 +57,7 @@ public CorpseList(Minecraft client, int width, int height, int y, int entryHeigh
}

if (loot.isPriceDataComplete()) addEntry(new CorpseList.MultiEntry(loot.profit()));
else addEntry(new CorpseList.SingleEntry(Component.literal("Price data incomplete, can't calculate profit").withStyle(ChatFormatting.RED)));
else addEntry(new RewardList.SingleEntry(Component.literal("Price data incomplete, can't calculate profit").withStyle(ChatFormatting.RED)));

if (i < lootList.size() - 1) {
addEmptyEntry();
Expand Down Expand Up @@ -92,65 +89,24 @@ public static Component getItemName(String itemId) {
}

private void addEmptyEntry() {
addEntry(new EmptyEntry());
addEntry(new RewardList.EmptyEntry());
}

@Override
public int getRowWidth() {
return 500;
}

public abstract static class AbstractEntry extends ContainerObjectSelectionList.Entry<AbstractEntry> {
protected List<AbstractWidget> children;

@Override
public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {}

@Override
public List<? extends NarratableEntry> narratables() {
return children;
}

@Override
public List<? extends GuiEventListener> children() {
return children;
}
}

// As a separator between entries
public static class EmptyEntry extends AbstractEntry {
public EmptyEntry() {
children = List.of();
}
return Math.min(500, getWidth() - 24);
}

// For a single line of text, allows for a border to be drawn or not
public static class SingleEntry extends AbstractEntry {
private boolean drawBorder = true;

public SingleEntry(Component text) {
children = List.of(new StringWidget(text, Minecraft.getInstance().font));
}

public SingleEntry(Component text, boolean drawBorder) {
this(text);
this.drawBorder = drawBorder;
}

@Override
public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
if (drawBorder) GuiHelper.border(graphics, this.getX(), this.getY(), this.getWidth(), this.getHeight() + 1, BORDER_COLOR);
for (var child : children) {
child.setX(this.getX() + INNER_MARGIN);
child.setY(this.getY() + INNER_MARGIN);
child.setWidth(this.getWidth() - 2 * INNER_MARGIN);
child.extractRenderState(graphics, mouseX, mouseY, a);
}
@Override
public void refreshScrollAmount() {
super.refreshScrollAmount();
for (var entry : this.children()) {
entry.repositionElements(entry.getX(), entry.getY(), this.width, this.height);
}
}

// The main grid structure
public static class MultiEntry extends AbstractEntry {
public static class MultiEntry extends RewardList.AbstractEntry {
protected @Nullable StringWidget itemName;
protected @Nullable StringWidget amount = null;
protected @Nullable StringWidget totalPrice;
Expand All @@ -159,7 +115,7 @@ public static class MultiEntry extends AbstractEntry {
// For the items
public MultiEntry(Component itemName, int amount, double pricePerUnit) {
this.itemName = new StringWidget(itemName, Minecraft.getInstance().font);
this.amount = new StringWidget(Component.literal("x" + amount).withStyle(ChatFormatting.AQUA), Minecraft.getInstance().font);
this.amount = new StringWidget(Component.literal("x" + Formatters.INTEGER_NUMBERS.format(amount)).withStyle(ChatFormatting.AQUA), Minecraft.getInstance().font);
this.totalPrice = new StringWidget(Component.literal(NumberFormat.getInstance().format(amount * pricePerUnit) + " Coins").withStyle(ChatFormatting.GOLD), Minecraft.getInstance().font);
this.pricePerUnit = new StringWidget(Component.literal(NumberFormat.getInstance().format(pricePerUnit) + " each").withStyle(ChatFormatting.GRAY), Minecraft.getInstance().font);
children = List.of(this.itemName, this.amount, this.totalPrice, this.pricePerUnit);
Expand All @@ -168,7 +124,7 @@ public MultiEntry(Component itemName, int amount, double pricePerUnit) {
// For the items
public MultiEntry(Component itemName, int amount) {
this.itemName = new StringWidget(itemName, Minecraft.getInstance().font);
this.amount = new StringWidget(Component.literal("x" + amount).withStyle(ChatFormatting.AQUA), Minecraft.getInstance().font);
this.amount = new StringWidget(Component.literal("x" + Formatters.INTEGER_NUMBERS.format(amount)).withStyle(ChatFormatting.AQUA), Minecraft.getInstance().font);
children = List.of(this.itemName, this.amount);
}

Expand Down Expand Up @@ -204,28 +160,36 @@ public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY

int entryY = y + INNER_MARGIN;
if (itemName != null) {
itemName.setX(x + INNER_MARGIN);
itemName.setY(entryY);
itemName.setMaxWidth(entryWidth / 3 - 2 * INNER_MARGIN, StringWidget.TextOverflow.SCROLLING);
itemName.extractRenderState(graphics, mouseX, mouseY, a);
}

if (amount != null) {
position(amount, x + entryWidth / 3 + INNER_MARGIN, entryWidth / 6 - 2 * INNER_MARGIN, entryY);
amount.setY(entryY);
amount.extractRenderState(graphics, mouseX, mouseY, a);
}

if (totalPrice != null) {
position(totalPrice, x + entryWidth / 2 + INNER_MARGIN, entryWidth / 4 - 2 * INNER_MARGIN, entryY);
totalPrice.setY(entryY);
totalPrice.extractRenderState(graphics, mouseX, mouseY, a);
}

if (pricePerUnit != null) {
position(pricePerUnit, x + 3 * entryWidth / 4 + INNER_MARGIN, entryWidth / 4 - 2 * INNER_MARGIN, entryY);
pricePerUnit.setY(entryY);
pricePerUnit.extractRenderState(graphics, mouseX, mouseY, a);
}
}

@Override
public void repositionElements(int x, int y, int width, int entryHeight) {
if (itemName != null) itemName.setX(x + INNER_MARGIN);
int entryWidth = getWidth();
if (amount != null) position(amount, x + entryWidth / 3 + INNER_MARGIN, entryWidth / 6 - 2 * INNER_MARGIN, y);
if (totalPrice != null) position(totalPrice, x + entryWidth / 2 + INNER_MARGIN, entryWidth / 4 - 2 * INNER_MARGIN, y);
if (pricePerUnit != null) position(pricePerUnit, x + 3 * entryWidth / 4 + INNER_MARGIN, entryWidth / 4 - 2 * INNER_MARGIN, y);
}

private static void position(StringWidget widget, int start, int width, int y) {
widget.setMaxWidth(width, StringWidget.TextOverflow.SCROLLING);
widget.setX(start + (width - widget.getWidth()) / 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@

import it.unimi.dsi.fastutil.doubles.DoubleBooleanImmutablePair;
import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair;

import java.text.NumberFormat;
import java.util.List;

import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.StringWidget;
import net.minecraft.client.gui.layouts.FrameLayout;
import net.minecraft.client.gui.layouts.GridLayout;
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.util.CommonColors;
import org.jspecify.annotations.Nullable;

public class CorpseProfitScreen extends Screen {
Expand All @@ -26,6 +28,9 @@ public class CorpseProfitScreen extends Screen {
private final DoubleBooleanPair totalProfit = calculateTotalProfit(rewardsList);
private boolean summaryView;

private @Nullable HeaderAndFooterLayout layout;
private @Nullable ContainerObjectSelectionList<?> selectionList;

public CorpseProfitScreen(Screen parent) {
this(parent, true);
}
Expand All @@ -37,13 +42,20 @@ public CorpseProfitScreen(Screen parent, boolean summaryView) {
}

@Override
protected void init() {
addRenderableOnly((context, _, _, _) -> {
context.centeredText(minecraft.font, Component.translatable("skyblocker.corpseTracker.screenTitle").withStyle(ChatFormatting.BOLD), width / 2, (32 - minecraft.font.lineHeight) / 2, CommonColors.WHITE);
});
protected void repositionElements() {
if (layout == null || selectionList == null) return;
layout.arrangeElements();
selectionList.setSize(layout.getWidth(), layout.getContentHeight());
selectionList.setPosition(layout.getX(), layout.getHeaderHeight());
selectionList.refreshScrollAmount();
}

if (summaryView) addRenderableWidget(getRewardList());
else addRenderableWidget(getCorpseList());
@Override
protected void init() {
layout = new HeaderAndFooterLayout(this, 25, 45);
layout.addTitleHeader(Component.translatable("skyblocker.corpseTracker.screenTitle").withStyle(ChatFormatting.BOLD), this.minecraft.font);
selectionList = summaryView ? getRewardList() : getCorpseList();
layout.addToContents(selectionList);

GridLayout gridWidget = new GridLayout();
gridWidget.defaultCellSetting().paddingHorizontal(5).paddingVertical(2);
Expand All @@ -59,9 +71,10 @@ protected void init() {
Component buttonText = summaryView ? Component.translatable("skyblocker.corpseTracker.historyView") : Component.translatable("skyblocker.corpseTracker.summaryView");
adder.addChild(Button.builder(buttonText, this::changeView).build());
adder.addChild(Button.builder(CommonComponents.GUI_DONE, _ -> onClose()).build());
gridWidget.arrangeElements();
FrameLayout.centerInRectangle(gridWidget, 0, this.height - 64, this.width, 64);
gridWidget.visitWidgets(this::addRenderableWidget);

layout.addToFooter(gridWidget);
repositionElements();
layout.visitWidgets(this::addRenderableWidget);
}

// Rebuilds the screen with the new view, the main difference being which list is displayed
Expand All @@ -72,12 +85,12 @@ private void changeView(Button button) {

// Lazy init
private CorpseList getCorpseList() {
return corpseList == null ? corpseList = new CorpseList(Minecraft.getInstance(), width, height - 96, 32, ENTRY_HEIGHT, rewardsList) : corpseList;
return corpseList == null ? corpseList = new CorpseList(Minecraft.getInstance(), width, height - 96, ENTRY_HEIGHT, rewardsList) : corpseList;
}

// Lazy init
private RewardList getRewardList() {
return rewardList == null ? rewardList = new RewardList(Minecraft.getInstance(), width, height - 96, 32, ENTRY_HEIGHT, rewardsList) : rewardList;
return rewardList == null ? rewardList = new RewardList(Minecraft.getInstance(), width, height - 96, 0, ENTRY_HEIGHT, rewardsList) : rewardList;
}

private static DoubleBooleanPair calculateTotalProfit(List<CorpseLoot> list) {
Expand Down
Loading
Loading