182 lines
6.8 KiB
Java
182 lines
6.8 KiB
Java
package net.minecraft.client.gui.screens.recipebook;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
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.narration.NarratedElementType;
|
|
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
|
import net.minecraft.client.gui.screens.Screen;
|
|
import net.minecraft.client.renderer.RenderType;
|
|
import net.minecraft.network.chat.CommonComponents;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.util.context.ContextMap;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.crafting.display.RecipeDisplayEntry;
|
|
import net.minecraft.world.item.crafting.display.RecipeDisplayId;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class RecipeButton extends AbstractWidget {
|
|
private static final ResourceLocation SLOT_MANY_CRAFTABLE_SPRITE = ResourceLocation.withDefaultNamespace("recipe_book/slot_many_craftable");
|
|
private static final ResourceLocation SLOT_CRAFTABLE_SPRITE = ResourceLocation.withDefaultNamespace("recipe_book/slot_craftable");
|
|
private static final ResourceLocation SLOT_MANY_UNCRAFTABLE_SPRITE = ResourceLocation.withDefaultNamespace("recipe_book/slot_many_uncraftable");
|
|
private static final ResourceLocation SLOT_UNCRAFTABLE_SPRITE = ResourceLocation.withDefaultNamespace("recipe_book/slot_uncraftable");
|
|
private static final float ANIMATION_TIME = 15.0F;
|
|
private static final int BACKGROUND_SIZE = 25;
|
|
private static final Component MORE_RECIPES_TOOLTIP = Component.translatable("gui.recipebook.moreRecipes");
|
|
private RecipeCollection collection = RecipeCollection.EMPTY;
|
|
private List<RecipeButton.ResolvedEntry> selectedEntries = List.of();
|
|
private boolean allRecipesHaveSameResultDisplay;
|
|
private final SlotSelectTime slotSelectTime;
|
|
private float animationTime;
|
|
|
|
public RecipeButton(SlotSelectTime slotSelectTime) {
|
|
super(0, 0, 25, 25, CommonComponents.EMPTY);
|
|
this.slotSelectTime = slotSelectTime;
|
|
}
|
|
|
|
public void init(RecipeCollection collection, boolean isFiltering, RecipeBookPage page, ContextMap contextMap) {
|
|
this.collection = collection;
|
|
List<RecipeDisplayEntry> list = collection.getSelectedRecipes(isFiltering ? RecipeCollection.CraftableStatus.CRAFTABLE : RecipeCollection.CraftableStatus.ANY);
|
|
this.selectedEntries = list.stream()
|
|
.map(recipeDisplayEntry -> new RecipeButton.ResolvedEntry(recipeDisplayEntry.id(), recipeDisplayEntry.resultItems(contextMap)))
|
|
.toList();
|
|
this.allRecipesHaveSameResultDisplay = allRecipesHaveSameResultDisplay(this.selectedEntries);
|
|
List<RecipeDisplayId> list2 = list.stream().map(RecipeDisplayEntry::id).filter(page.getRecipeBook()::willHighlight).toList();
|
|
if (!list2.isEmpty()) {
|
|
list2.forEach(page::recipeShown);
|
|
this.animationTime = 15.0F;
|
|
}
|
|
}
|
|
|
|
private static boolean allRecipesHaveSameResultDisplay(List<RecipeButton.ResolvedEntry> entries) {
|
|
Iterator<ItemStack> iterator = entries.stream().flatMap(resolvedEntry -> resolvedEntry.displayItems().stream()).iterator();
|
|
if (!iterator.hasNext()) {
|
|
return true;
|
|
} else {
|
|
ItemStack itemStack = (ItemStack)iterator.next();
|
|
|
|
while (iterator.hasNext()) {
|
|
ItemStack itemStack2 = (ItemStack)iterator.next();
|
|
if (!ItemStack.isSameItemSameComponents(itemStack, itemStack2)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public RecipeCollection getCollection() {
|
|
return this.collection;
|
|
}
|
|
|
|
@Override
|
|
public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
|
ResourceLocation resourceLocation;
|
|
if (this.collection.hasCraftable()) {
|
|
if (this.hasMultipleRecipes()) {
|
|
resourceLocation = SLOT_MANY_CRAFTABLE_SPRITE;
|
|
} else {
|
|
resourceLocation = SLOT_CRAFTABLE_SPRITE;
|
|
}
|
|
} else if (this.hasMultipleRecipes()) {
|
|
resourceLocation = SLOT_MANY_UNCRAFTABLE_SPRITE;
|
|
} else {
|
|
resourceLocation = SLOT_UNCRAFTABLE_SPRITE;
|
|
}
|
|
|
|
boolean bl = this.animationTime > 0.0F;
|
|
if (bl) {
|
|
float f = 1.0F + 0.1F * (float)Math.sin(this.animationTime / 15.0F * (float) Math.PI);
|
|
guiGraphics.pose().pushPose();
|
|
guiGraphics.pose().translate((float)(this.getX() + 8), (float)(this.getY() + 12), 0.0F);
|
|
guiGraphics.pose().scale(f, f, 1.0F);
|
|
guiGraphics.pose().translate((float)(-(this.getX() + 8)), (float)(-(this.getY() + 12)), 0.0F);
|
|
this.animationTime -= partialTick;
|
|
}
|
|
|
|
guiGraphics.blitSprite(RenderType::guiTextured, resourceLocation, this.getX(), this.getY(), this.width, this.height);
|
|
ItemStack itemStack = this.getDisplayStack();
|
|
int i = 4;
|
|
if (this.hasMultipleRecipes() && this.allRecipesHaveSameResultDisplay) {
|
|
guiGraphics.renderItem(itemStack, this.getX() + i + 1, this.getY() + i + 1, 0, 10);
|
|
i--;
|
|
}
|
|
|
|
guiGraphics.renderFakeItem(itemStack, this.getX() + i, this.getY() + i);
|
|
if (bl) {
|
|
guiGraphics.pose().popPose();
|
|
}
|
|
}
|
|
|
|
private boolean hasMultipleRecipes() {
|
|
return this.selectedEntries.size() > 1;
|
|
}
|
|
|
|
public boolean isOnlyOption() {
|
|
return this.selectedEntries.size() == 1;
|
|
}
|
|
|
|
public RecipeDisplayId getCurrentRecipe() {
|
|
int i = this.slotSelectTime.currentIndex() % this.selectedEntries.size();
|
|
return ((RecipeButton.ResolvedEntry)this.selectedEntries.get(i)).id;
|
|
}
|
|
|
|
public ItemStack getDisplayStack() {
|
|
int i = this.slotSelectTime.currentIndex();
|
|
int j = this.selectedEntries.size();
|
|
int k = i / j;
|
|
int l = i - j * k;
|
|
return ((RecipeButton.ResolvedEntry)this.selectedEntries.get(l)).selectItem(k);
|
|
}
|
|
|
|
public List<Component> getTooltipText(ItemStack stack) {
|
|
List<Component> list = new ArrayList(Screen.getTooltipFromItem(Minecraft.getInstance(), stack));
|
|
if (this.hasMultipleRecipes()) {
|
|
list.add(MORE_RECIPES_TOOLTIP);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
@Override
|
|
public void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {
|
|
narrationElementOutput.add(NarratedElementType.TITLE, Component.translatable("narration.recipe", this.getDisplayStack().getHoverName()));
|
|
if (this.hasMultipleRecipes()) {
|
|
narrationElementOutput.add(
|
|
NarratedElementType.USAGE, Component.translatable("narration.button.usage.hovered"), Component.translatable("narration.recipe.usage.more")
|
|
);
|
|
} else {
|
|
narrationElementOutput.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.hovered"));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getWidth() {
|
|
return 25;
|
|
}
|
|
|
|
@Override
|
|
protected boolean isValidClickButton(int button) {
|
|
return button == 0 || button == 1;
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
record ResolvedEntry(RecipeDisplayId id, List<ItemStack> displayItems) {
|
|
|
|
public ItemStack selectItem(int index) {
|
|
if (this.displayItems.isEmpty()) {
|
|
return ItemStack.EMPTY;
|
|
} else {
|
|
int i = index % this.displayItems.size();
|
|
return (ItemStack)this.displayItems.get(i);
|
|
}
|
|
}
|
|
}
|
|
}
|