388 lines
14 KiB
Java
388 lines
14 KiB
Java
package net.minecraft.client.gui.screens.achievement;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Sets;
|
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.gui.GuiGraphics;
|
|
import net.minecraft.client.gui.components.AbstractWidget;
|
|
import net.minecraft.client.gui.components.Button;
|
|
import net.minecraft.client.gui.components.LoadingDotsWidget;
|
|
import net.minecraft.client.gui.components.ObjectSelectionList;
|
|
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
|
import net.minecraft.client.gui.layouts.LinearLayout;
|
|
import net.minecraft.client.gui.screens.Screen;
|
|
import net.minecraft.client.gui.screens.achievement.StatsScreen.ItemStatisticsList.ItemRow;
|
|
import net.minecraft.client.gui.screens.achievement.StatsScreen.ItemStatisticsList.ItemRowComparator;
|
|
import net.minecraft.client.gui.screens.achievement.StatsScreen.MobsStatisticsList.MobRow;
|
|
import net.minecraft.client.renderer.RenderType;
|
|
import net.minecraft.client.resources.language.I18n;
|
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
|
import net.minecraft.core.component.DataComponents;
|
|
import net.minecraft.core.registries.BuiltInRegistries;
|
|
import net.minecraft.network.chat.CommonComponents;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.protocol.game.ServerboundClientCommandPacket;
|
|
import net.minecraft.network.protocol.game.ServerboundClientCommandPacket.Action;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.stats.Stat;
|
|
import net.minecraft.stats.StatType;
|
|
import net.minecraft.stats.Stats;
|
|
import net.minecraft.stats.StatsCounter;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.level.block.Block;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class StatsScreen extends Screen {
|
|
private static final Component TITLE = Component.translatable("gui.stats");
|
|
static final ResourceLocation SLOT_SPRITE = ResourceLocation.withDefaultNamespace("container/slot");
|
|
static final ResourceLocation HEADER_SPRITE = ResourceLocation.withDefaultNamespace("statistics/header");
|
|
static final ResourceLocation SORT_UP_SPRITE = ResourceLocation.withDefaultNamespace("statistics/sort_up");
|
|
static final ResourceLocation SORT_DOWN_SPRITE = ResourceLocation.withDefaultNamespace("statistics/sort_down");
|
|
private static final Component PENDING_TEXT = Component.translatable("multiplayer.downloadingStats");
|
|
static final Component NO_VALUE_DISPLAY = Component.translatable("stats.none");
|
|
private static final Component GENERAL_BUTTON = Component.translatable("stat.generalButton");
|
|
private static final Component ITEMS_BUTTON = Component.translatable("stat.itemsButton");
|
|
private static final Component MOBS_BUTTON = Component.translatable("stat.mobsButton");
|
|
protected final Screen lastScreen;
|
|
private static final int LIST_WIDTH = 280;
|
|
private static final int PADDING = 5;
|
|
private static final int FOOTER_HEIGHT = 58;
|
|
private HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this, 33, 58);
|
|
@Nullable
|
|
private StatsScreen.GeneralStatisticsList statsList;
|
|
@Nullable
|
|
StatsScreen.ItemStatisticsList itemStatsList;
|
|
@Nullable
|
|
private StatsScreen.MobsStatisticsList mobsStatsList;
|
|
final StatsCounter stats;
|
|
@Nullable
|
|
private ObjectSelectionList<?> activeList;
|
|
/**
|
|
* When true, the game will be paused when the gui is shown
|
|
*/
|
|
private boolean isLoading = true;
|
|
|
|
public StatsScreen(Screen lastScreen, StatsCounter stats) {
|
|
super(TITLE);
|
|
this.lastScreen = lastScreen;
|
|
this.stats = stats;
|
|
}
|
|
|
|
@Override
|
|
protected void init() {
|
|
this.layout.addToContents(new LoadingDotsWidget(this.font, PENDING_TEXT));
|
|
this.minecraft.getConnection().send(new ServerboundClientCommandPacket(Action.REQUEST_STATS));
|
|
}
|
|
|
|
public void initLists() {
|
|
this.statsList = new StatsScreen.GeneralStatisticsList(this.minecraft);
|
|
this.itemStatsList = new StatsScreen.ItemStatisticsList(this.minecraft);
|
|
this.mobsStatsList = new StatsScreen.MobsStatisticsList(this.minecraft);
|
|
}
|
|
|
|
public void initButtons() {
|
|
HeaderAndFooterLayout headerAndFooterLayout = new HeaderAndFooterLayout(this, 33, 58);
|
|
headerAndFooterLayout.addTitleHeader(TITLE, this.font);
|
|
LinearLayout linearLayout = headerAndFooterLayout.addToFooter(LinearLayout.vertical()).spacing(5);
|
|
linearLayout.defaultCellSetting().alignHorizontallyCenter();
|
|
LinearLayout linearLayout2 = linearLayout.addChild(LinearLayout.horizontal()).spacing(5);
|
|
linearLayout2.addChild(Button.builder(GENERAL_BUTTON, buttonx -> this.setActiveList(this.statsList)).width(120).build());
|
|
Button button = linearLayout2.addChild(Button.builder(ITEMS_BUTTON, buttonx -> this.setActiveList(this.itemStatsList)).width(120).build());
|
|
Button button2 = linearLayout2.addChild(Button.builder(MOBS_BUTTON, buttonx -> this.setActiveList(this.mobsStatsList)).width(120).build());
|
|
linearLayout.addChild(Button.builder(CommonComponents.GUI_DONE, buttonx -> this.onClose()).width(200).build());
|
|
if (this.itemStatsList != null && this.itemStatsList.children().isEmpty()) {
|
|
button.active = false;
|
|
}
|
|
|
|
if (this.mobsStatsList != null && this.mobsStatsList.children().isEmpty()) {
|
|
button2.active = false;
|
|
}
|
|
|
|
this.layout = headerAndFooterLayout;
|
|
this.layout.visitWidgets(guiEventListener -> {
|
|
AbstractWidget var10000 = this.addRenderableWidget(guiEventListener);
|
|
});
|
|
this.repositionElements();
|
|
}
|
|
|
|
@Override
|
|
protected void repositionElements() {
|
|
this.layout.arrangeElements();
|
|
if (this.activeList != null) {
|
|
this.activeList.updateSize(this.width, this.layout);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onClose() {
|
|
this.minecraft.setScreen(this.lastScreen);
|
|
}
|
|
|
|
public void onStatsUpdated() {
|
|
if (this.isLoading) {
|
|
this.initLists();
|
|
this.setActiveList(this.statsList);
|
|
this.initButtons();
|
|
this.setInitialFocus();
|
|
this.isLoading = false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isPauseScreen() {
|
|
return !this.isLoading;
|
|
}
|
|
|
|
public void setActiveList(@Nullable ObjectSelectionList<?> activeList) {
|
|
if (this.activeList != null) {
|
|
this.removeWidget(this.activeList);
|
|
}
|
|
|
|
if (activeList != null) {
|
|
this.addRenderableWidget(activeList);
|
|
this.activeList = activeList;
|
|
this.repositionElements();
|
|
}
|
|
}
|
|
|
|
static String getTranslationKey(Stat<ResourceLocation> stat) {
|
|
return "stat." + stat.getValue().toString().replace(':', '.');
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
class GeneralStatisticsList extends ObjectSelectionList<net.minecraft.client.gui.screens.achievement.StatsScreen.GeneralStatisticsList.Entry> {
|
|
public GeneralStatisticsList(final Minecraft minecraft) {
|
|
super(minecraft, StatsScreen.this.width, StatsScreen.this.height - 33 - 58, 33, 14);
|
|
ObjectArrayList<Stat<ResourceLocation>> objectArrayList = new ObjectArrayList<>(Stats.CUSTOM.iterator());
|
|
objectArrayList.sort(Comparator.comparing(statx -> I18n.get(StatsScreen.getTranslationKey(statx))));
|
|
|
|
for (Stat<ResourceLocation> stat : objectArrayList) {
|
|
this.addEntry(new net.minecraft.client.gui.screens.achievement.StatsScreen.GeneralStatisticsList.Entry(this, stat));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getRowWidth() {
|
|
return 280;
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
class ItemStatisticsList extends ObjectSelectionList<ItemRow> {
|
|
private static final int SLOT_BG_SIZE = 18;
|
|
private static final int SLOT_STAT_HEIGHT = 22;
|
|
private static final int SLOT_BG_Y = 1;
|
|
private static final int SORT_NONE = 0;
|
|
private static final int SORT_DOWN = -1;
|
|
private static final int SORT_UP = 1;
|
|
private final ResourceLocation[] iconSprites = new ResourceLocation[]{
|
|
ResourceLocation.withDefaultNamespace("statistics/block_mined"),
|
|
ResourceLocation.withDefaultNamespace("statistics/item_broken"),
|
|
ResourceLocation.withDefaultNamespace("statistics/item_crafted"),
|
|
ResourceLocation.withDefaultNamespace("statistics/item_used"),
|
|
ResourceLocation.withDefaultNamespace("statistics/item_picked_up"),
|
|
ResourceLocation.withDefaultNamespace("statistics/item_dropped")
|
|
};
|
|
protected final List<StatType<Block>> blockColumns;
|
|
protected final List<StatType<Item>> itemColumns;
|
|
protected final Comparator<ItemRow> itemStatSorter = new ItemRowComparator(this);
|
|
@Nullable
|
|
protected StatType<?> sortColumn;
|
|
protected int headerPressed = -1;
|
|
protected int sortOrder;
|
|
|
|
public ItemStatisticsList(final Minecraft minecraft) {
|
|
super(minecraft, StatsScreen.this.width, StatsScreen.this.height - 33 - 58, 33, 22, 22);
|
|
this.blockColumns = Lists.<StatType<Block>>newArrayList();
|
|
this.blockColumns.add(Stats.BLOCK_MINED);
|
|
this.itemColumns = Lists.<StatType<Item>>newArrayList(Stats.ITEM_BROKEN, Stats.ITEM_CRAFTED, Stats.ITEM_USED, Stats.ITEM_PICKED_UP, Stats.ITEM_DROPPED);
|
|
Set<Item> set = Sets.newIdentityHashSet();
|
|
|
|
for (Item item : BuiltInRegistries.ITEM) {
|
|
boolean bl = false;
|
|
|
|
for (StatType<Item> statType : this.itemColumns) {
|
|
if (statType.contains(item) && StatsScreen.this.stats.getValue(statType.get(item)) > 0) {
|
|
bl = true;
|
|
}
|
|
}
|
|
|
|
if (bl) {
|
|
set.add(item);
|
|
}
|
|
}
|
|
|
|
for (Block block : BuiltInRegistries.BLOCK) {
|
|
boolean bl = false;
|
|
|
|
for (StatType<Block> statTypex : this.blockColumns) {
|
|
if (statTypex.contains(block) && StatsScreen.this.stats.getValue(statTypex.get(block)) > 0) {
|
|
bl = true;
|
|
}
|
|
}
|
|
|
|
if (bl) {
|
|
set.add(block.asItem());
|
|
}
|
|
}
|
|
|
|
set.remove(Items.AIR);
|
|
|
|
for (Item item : set) {
|
|
this.addEntry(new ItemRow(this, item));
|
|
}
|
|
}
|
|
|
|
int getColumnX(int index) {
|
|
return 75 + 40 * index;
|
|
}
|
|
|
|
@Override
|
|
protected void renderHeader(GuiGraphics guiGraphics, int x, int y) {
|
|
if (!this.minecraft.mouseHandler.isLeftPressed()) {
|
|
this.headerPressed = -1;
|
|
}
|
|
|
|
for (int i = 0; i < this.iconSprites.length; i++) {
|
|
ResourceLocation resourceLocation = this.headerPressed == i ? StatsScreen.SLOT_SPRITE : StatsScreen.HEADER_SPRITE;
|
|
guiGraphics.blitSprite(RenderType::guiTextured, resourceLocation, x + this.getColumnX(i) - 18, y + 1, 18, 18);
|
|
}
|
|
|
|
if (this.sortColumn != null) {
|
|
int i = this.getColumnX(this.getColumnIndex(this.sortColumn)) - 36;
|
|
ResourceLocation resourceLocation = this.sortOrder == 1 ? StatsScreen.SORT_UP_SPRITE : StatsScreen.SORT_DOWN_SPRITE;
|
|
guiGraphics.blitSprite(RenderType::guiTextured, resourceLocation, x + i, y + 1, 18, 18);
|
|
}
|
|
|
|
for (int i = 0; i < this.iconSprites.length; i++) {
|
|
int j = this.headerPressed == i ? 1 : 0;
|
|
guiGraphics.blitSprite(RenderType::guiTextured, this.iconSprites[i], x + this.getColumnX(i) - 18 + j, y + 1 + j, 18, 18);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
|
boolean bl = super.mouseClicked(mouseX, mouseY, button);
|
|
return !bl
|
|
&& this.clickedHeader(
|
|
(int)(mouseX - (this.getX() + this.width / 2.0 - this.getRowWidth() / 2.0)), (int)(mouseY - this.getY()) + (int)this.scrollAmount() - 4
|
|
)
|
|
? true
|
|
: bl;
|
|
}
|
|
|
|
protected boolean clickedHeader(int x, int y) {
|
|
this.headerPressed = -1;
|
|
|
|
for (int i = 0; i < this.iconSprites.length; i++) {
|
|
int j = x - this.getColumnX(i);
|
|
if (j >= -36 && j <= 0) {
|
|
this.headerPressed = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (this.headerPressed >= 0) {
|
|
this.sortByColumn(this.getColumn(this.headerPressed));
|
|
this.minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getRowWidth() {
|
|
return 280;
|
|
}
|
|
|
|
private StatType<?> getColumn(int index) {
|
|
return index < this.blockColumns.size() ? (StatType)this.blockColumns.get(index) : (StatType)this.itemColumns.get(index - this.blockColumns.size());
|
|
}
|
|
|
|
private int getColumnIndex(StatType<?> statType) {
|
|
int i = this.blockColumns.indexOf(statType);
|
|
if (i >= 0) {
|
|
return i;
|
|
} else {
|
|
int j = this.itemColumns.indexOf(statType);
|
|
return j >= 0 ? j + this.blockColumns.size() : -1;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void renderDecorations(GuiGraphics guiGraphics, int mouseX, int mouseY) {
|
|
if (mouseY >= this.getY() && mouseY <= this.getBottom()) {
|
|
ItemRow itemRow = this.getHovered();
|
|
int i = this.getRowLeft();
|
|
if (itemRow != null) {
|
|
if (mouseX < i || mouseX > i + 18) {
|
|
return;
|
|
}
|
|
|
|
Item item = itemRow.getItem();
|
|
guiGraphics.renderTooltip(StatsScreen.this.font, item.getName(), mouseX, mouseY, item.components().get(DataComponents.TOOLTIP_STYLE));
|
|
} else {
|
|
Component component = null;
|
|
int j = mouseX - i;
|
|
|
|
for (int k = 0; k < this.iconSprites.length; k++) {
|
|
int l = this.getColumnX(k);
|
|
if (j >= l - 18 && j <= l) {
|
|
component = this.getColumn(k).getDisplayName();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (component != null) {
|
|
guiGraphics.renderTooltip(StatsScreen.this.font, component, mouseX, mouseY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void sortByColumn(StatType<?> statType) {
|
|
if (statType != this.sortColumn) {
|
|
this.sortColumn = statType;
|
|
this.sortOrder = -1;
|
|
} else if (this.sortOrder == -1) {
|
|
this.sortOrder = 1;
|
|
} else {
|
|
this.sortColumn = null;
|
|
this.sortOrder = 0;
|
|
}
|
|
|
|
this.children().sort(this.itemStatSorter);
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
class MobsStatisticsList extends ObjectSelectionList<MobRow> {
|
|
public MobsStatisticsList(final Minecraft minecraft) {
|
|
super(minecraft, StatsScreen.this.width, StatsScreen.this.height - 33 - 58, 33, 9 * 4);
|
|
|
|
for (EntityType<?> entityType : BuiltInRegistries.ENTITY_TYPE) {
|
|
if (StatsScreen.this.stats.getValue(Stats.ENTITY_KILLED.get(entityType)) > 0 || StatsScreen.this.stats.getValue(Stats.ENTITY_KILLED_BY.get(entityType)) > 0
|
|
)
|
|
{
|
|
this.addEntry(new MobRow(this, entityType));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getRowWidth() {
|
|
return 280;
|
|
}
|
|
}
|
|
}
|