package net.minecraft.client.gui.screens.worldselection; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.collect.ImmutableList.Builder; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import javax.annotation.Nullable; import net.minecraft.ChatFormatting; 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.ContainerObjectSelectionList; import net.minecraft.client.gui.components.CycleButton; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.narration.NarratableEntry; 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.resources.language.I18n; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.level.GameRules; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class EditGameRulesScreen extends Screen { private static final Component TITLE = Component.translatable("editGamerule.title"); private static final int SPACING = 8; final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); private final Consumer> exitCallback; private final Set invalidEntries = Sets.newHashSet(); private final GameRules gameRules; @Nullable private EditGameRulesScreen.RuleList ruleList; @Nullable private Button doneButton; public EditGameRulesScreen(GameRules p_101051_, Consumer> p_101052_) { super(TITLE); this.gameRules = p_101051_; this.exitCallback = p_101052_; } @Override protected void init() { this.layout.addTitleHeader(TITLE, this.font); this.ruleList = this.layout.addToContents(new EditGameRulesScreen.RuleList(this.gameRules)); LinearLayout linearlayout = this.layout.addToFooter(LinearLayout.horizontal().spacing(8)); this.doneButton = linearlayout.addChild( Button.builder(CommonComponents.GUI_DONE, p_101059_ -> this.exitCallback.accept(Optional.of(this.gameRules))).build() ); linearlayout.addChild(Button.builder(CommonComponents.GUI_CANCEL, p_325430_ -> this.onClose()).build()); this.layout.visitWidgets(p_325432_ -> { AbstractWidget abstractwidget = this.addRenderableWidget(p_325432_); }); this.repositionElements(); } @Override protected void repositionElements() { this.layout.arrangeElements(); if (this.ruleList != null) { this.ruleList.updateSize(this.width, this.layout); } } @Override public void onClose() { this.exitCallback.accept(Optional.empty()); } private void updateDoneButton() { if (this.doneButton != null) { this.doneButton.active = this.invalidEntries.isEmpty(); } } void markInvalid(EditGameRulesScreen.RuleEntry p_101061_) { this.invalidEntries.add(p_101061_); this.updateDoneButton(); } void clearInvalid(EditGameRulesScreen.RuleEntry p_101075_) { this.invalidEntries.remove(p_101075_); this.updateDoneButton(); } @OnlyIn(Dist.CLIENT) public class BooleanRuleEntry extends EditGameRulesScreen.GameRuleEntry { private final CycleButton checkbox; public BooleanRuleEntry( final Component p_101101_, final List p_101102_, final String p_101103_, final GameRules.BooleanValue p_101104_ ) { super(p_101102_, p_101101_); this.checkbox = CycleButton.onOffBuilder(p_101104_.get()) .displayOnlyValue() .withCustomNarration(p_170219_ -> p_170219_.createDefaultNarrationMessage().append("\n").append(p_101103_)) .create(10, 5, 44, 20, p_101101_, (p_170215_, p_170216_) -> p_101104_.set(p_170216_, null)); this.children.add(this.checkbox); } @Override public void render( GuiGraphics p_281587_, int p_281471_, int p_281257_, int p_282541_, int p_282993_, int p_283543_, int p_281322_, int p_282930_, boolean p_283227_, float p_283364_ ) { this.renderLabel(p_281587_, p_281257_, p_282541_); this.checkbox.setX(p_282541_ + p_282993_ - 45); this.checkbox.setY(p_281257_); this.checkbox.render(p_281587_, p_281322_, p_282930_, p_283364_); } } @OnlyIn(Dist.CLIENT) public class CategoryRuleEntry extends EditGameRulesScreen.RuleEntry { final Component label; public CategoryRuleEntry(final Component p_101141_) { super(null); this.label = p_101141_; } @Override public void render( GuiGraphics p_283335_, int p_283214_, int p_283476_, int p_281365_, int p_281817_, int p_283006_, int p_282893_, int p_282500_, boolean p_283421_, float p_282445_ ) { p_283335_.drawCenteredString(EditGameRulesScreen.this.minecraft.font, this.label, p_281365_ + p_281817_ / 2, p_283476_ + 5, -1); } @Override public List children() { return ImmutableList.of(); } @Override public List narratables() { return ImmutableList.of(new NarratableEntry() { @Override public NarratableEntry.NarrationPriority narrationPriority() { return NarratableEntry.NarrationPriority.HOVERED; } @Override public void updateNarration(NarrationElementOutput p_170225_) { p_170225_.add(NarratedElementType.TITLE, CategoryRuleEntry.this.label); } }); } } @FunctionalInterface @OnlyIn(Dist.CLIENT) interface EntryFactory> { EditGameRulesScreen.RuleEntry create(Component p_101155_, List p_101156_, String p_101157_, T p_101158_); } @OnlyIn(Dist.CLIENT) public abstract class GameRuleEntry extends EditGameRulesScreen.RuleEntry { private final List label; protected final List children = Lists.newArrayList(); public GameRuleEntry(@Nullable final List p_101164_, final Component p_101165_) { super(p_101164_); this.label = EditGameRulesScreen.this.minecraft.font.split(p_101165_, 175); } @Override public List children() { return this.children; } @Override public List narratables() { return this.children; } protected void renderLabel(GuiGraphics p_282711_, int p_281539_, int p_281414_) { if (this.label.size() == 1) { p_282711_.drawString(EditGameRulesScreen.this.minecraft.font, this.label.get(0), p_281414_, p_281539_ + 5, -1); } else if (this.label.size() >= 2) { p_282711_.drawString(EditGameRulesScreen.this.minecraft.font, this.label.get(0), p_281414_, p_281539_, -1); p_282711_.drawString(EditGameRulesScreen.this.minecraft.font, this.label.get(1), p_281414_, p_281539_ + 10, -1); } } } @OnlyIn(Dist.CLIENT) public class IntegerRuleEntry extends EditGameRulesScreen.GameRuleEntry { private final EditBox input; public IntegerRuleEntry( final Component p_101175_, final List p_101176_, final String p_101177_, final GameRules.IntegerValue p_101178_ ) { super(p_101176_, p_101175_); this.input = new EditBox( EditGameRulesScreen.this.minecraft.font, 10, 5, 44, 20, p_101175_.copy().append("\n").append(p_101177_).append("\n") ); this.input.setValue(Integer.toString(p_101178_.get())); this.input.setResponder(p_101181_ -> { if (p_101178_.tryDeserialize(p_101181_)) { this.input.setTextColor(14737632); EditGameRulesScreen.this.clearInvalid(this); } else { this.input.setTextColor(-65536); EditGameRulesScreen.this.markInvalid(this); } }); this.children.add(this.input); } @Override public void render( GuiGraphics p_281756_, int p_281882_, int p_281876_, int p_283136_, int p_283044_, int p_282526_, int p_282433_, int p_281816_, boolean p_282227_, float p_281751_ ) { this.renderLabel(p_281756_, p_281876_, p_283136_); this.input.setX(p_283136_ + p_283044_ - 45); this.input.setY(p_281876_); this.input.render(p_281756_, p_282433_, p_281816_, p_281751_); } } @OnlyIn(Dist.CLIENT) public abstract static class RuleEntry extends ContainerObjectSelectionList.Entry { @Nullable final List tooltip; public RuleEntry(@Nullable List p_194062_) { this.tooltip = p_194062_; } } @OnlyIn(Dist.CLIENT) public class RuleList extends ContainerObjectSelectionList { private static final int ITEM_HEIGHT = 24; public RuleList(final GameRules p_101203_) { super( Minecraft.getInstance(), EditGameRulesScreen.this.width, EditGameRulesScreen.this.layout.getContentHeight(), EditGameRulesScreen.this.layout.getHeaderHeight(), 24 ); final Map, EditGameRulesScreen.RuleEntry>> map = Maps.newHashMap(); p_101203_.visitGameRuleTypes( new GameRules.GameRuleTypeVisitor() { @Override public void visitBoolean(GameRules.Key p_101238_, GameRules.Type p_101239_) { this.addEntry( p_101238_, (p_101228_, p_101229_, p_101230_, p_101231_) -> EditGameRulesScreen.this.new BooleanRuleEntry( p_101228_, p_101229_, p_101230_, p_101231_ ) ); } @Override public void visitInteger(GameRules.Key p_101241_, GameRules.Type p_101242_) { this.addEntry( p_101241_, (p_101233_, p_101234_, p_101235_, p_101236_) -> EditGameRulesScreen.this.new IntegerRuleEntry( p_101233_, p_101234_, p_101235_, p_101236_ ) ); } private > void addEntry(GameRules.Key p_101225_, EditGameRulesScreen.EntryFactory p_101226_) { Component component = Component.translatable(p_101225_.getDescriptionId()); Component component1 = Component.literal(p_101225_.getId()).withStyle(ChatFormatting.YELLOW); T t = p_101203_.getRule(p_101225_); String s = t.serialize(); Component component2 = Component.translatable("editGamerule.default", Component.literal(s)).withStyle(ChatFormatting.GRAY); String s1 = p_101225_.getDescriptionId() + ".description"; List list; String s2; if (I18n.exists(s1)) { Builder builder = ImmutableList.builder().add(component1.getVisualOrderText()); Component component3 = Component.translatable(s1); EditGameRulesScreen.this.font.split(component3, 150).forEach(builder::add); list = builder.add(component2.getVisualOrderText()).build(); s2 = component3.getString() + "\n" + component2.getString(); } else { list = ImmutableList.of(component1.getVisualOrderText(), component2.getVisualOrderText()); s2 = component2.getString(); } map.computeIfAbsent(p_101225_.getCategory(), p_101223_ -> Maps.newHashMap()).put(p_101225_, p_101226_.create(component, list, s2, t)); } } ); map.entrySet() .stream() .sorted(Map.Entry.comparingByKey()) .forEach( p_101210_ -> { this.addEntry( EditGameRulesScreen.this.new CategoryRuleEntry( Component.translatable(p_101210_.getKey().getDescriptionId()).withStyle(ChatFormatting.BOLD, ChatFormatting.YELLOW) ) ); p_101210_.getValue() .entrySet() .stream() .sorted(Map.Entry.comparingByKey(Comparator.comparing(GameRules.Key::getId))) .forEach(p_170229_ -> this.addEntry(p_170229_.getValue())); } ); } @Override public void renderWidget(GuiGraphics p_309387_, int p_311816_, int p_311348_, float p_311962_) { super.renderWidget(p_309387_, p_311816_, p_311348_, p_311962_); EditGameRulesScreen.RuleEntry editgamerulesscreen$ruleentry = this.getHovered(); if (editgamerulesscreen$ruleentry != null && editgamerulesscreen$ruleentry.tooltip != null) { EditGameRulesScreen.this.setTooltipForNextRenderPass(editgamerulesscreen$ruleentry.tooltip); } } } }