AbstractGameRulesScreen.java

net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen

信息

  • 全限定名:net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen
  • 类型:public abstract class
  • 包:net.minecraft.client.gui.screens.worldselection
  • 源码路径:src/main/java/net/minecraft/client/gui/screens/worldselection/AbstractGameRulesScreen.java
  • 起始行号:L47
  • 继承:Screen
  • 职责:

    TODO

字段/常量

  • TITLE

    • 类型: Component
    • 修饰符: protected static final
    • 源码定位: L48
    • 说明:

      TODO

  • SEARCH_HINT

    • 类型: Component
    • 修饰符: private static final
    • 源码定位: L49
    • 说明:

      TODO

  • SEARCH_BOX_HEIGHT

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L50
    • 说明:

      TODO

  • invalidEntries

    • 类型: Set<AbstractGameRulesScreen.RuleEntry>
    • 修饰符: private final
    • 源码定位: L51
    • 说明:

      TODO

  • exitCallback

    • 类型: Consumer<Optional<GameRules>>
    • 修饰符: private final
    • 源码定位: L52
    • 说明:

      TODO

  • layout

    • 类型: HeaderAndFooterLayout
    • 修饰符: protected final
    • 源码定位: L53
    • 说明:

      TODO

  • gameRules

    • 类型: GameRules
    • 修饰符: protected final
    • 源码定位: L54
    • 说明:

      TODO

  • searchBox

    • 类型: EditBox
    • 修饰符: protected
    • 源码定位: L55
    • 说明:

      TODO

  • ruleList

    • 类型: AbstractGameRulesScreen.RuleList
    • 修饰符: protected
    • 源码定位: L56
    • 说明:

      TODO

  • doneButton

    • 类型: Button
    • 修饰符: protected
    • 源码定位: L57
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen.BooleanRuleEntry

    • 类型: class
    • 修饰符: public
    • 源码定位: L138
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen.CategoryRuleEntry

    • 类型: class
    • 修饰符: public
    • 源码定位: L161
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen.EntryFactory

    • 类型: interface
    • 修饰符: private
    • 源码定位: L202
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen.GameRuleEntry

    • 类型: class
    • 修饰符: public abstract
    • 源码定位: L207
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen.IntegerRuleEntry

    • 类型: class
    • 修饰符: public
    • 源码定位: L239
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen.RuleEntry

    • 类型: class
    • 修饰符: public abstract static
    • 源码定位: L271
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen.RuleList

    • 类型: class
    • 修饰符: public
    • 源码定位: L280
    • 说明:

      TODO

构造器

public AbstractGameRulesScreen(GameRules gameRules, Consumer<Optional<GameRules>> exitCallback) @ L59

  • 构造器名:AbstractGameRulesScreen
  • 源码定位:L59
  • 修饰符:public

参数:

  • gameRules: GameRules
  • exitCallback: Consumer<Optional>

说明:

TODO

方法

下面的方法块按源码顺序生成。

protected void createAndConfigureSearchBox(LinearLayout headerLayout) @ L66

  • 方法名:createAndConfigureSearchBox
  • 源码定位:L66
  • 返回类型:void
  • 修饰符:protected

参数:

  • headerLayout: LinearLayout

说明:

TODO

protected void init() @ L72

  • 方法名:init
  • 源码定位:L72
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

protected abstract void initContent() @ L86

  • 方法名:initContent
  • 源码定位:L86
  • 返回类型:void
  • 修饰符:protected abstract

参数:

说明:

TODO

protected abstract void onDone() @ L88

  • 方法名:onDone
  • 源码定位:L88
  • 返回类型:void
  • 修饰符:protected abstract

参数:

说明:

TODO

protected void repositionElements() @ L90

  • 方法名:repositionElements
  • 源码定位:L90
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

protected void setInitialFocus() @ L98

  • 方法名:setInitialFocus
  • 源码定位:L98
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

private void markInvalid(AbstractGameRulesScreen.RuleEntry invalidEntry) @ L105

  • 方法名:markInvalid
  • 源码定位:L105
  • 返回类型:void
  • 修饰符:private

参数:

  • invalidEntry: AbstractGameRulesScreen.RuleEntry

说明:

TODO

private void clearInvalid(AbstractGameRulesScreen.RuleEntry invalidEntry) @ L110

  • 方法名:clearInvalid
  • 源码定位:L110
  • 返回类型:void
  • 修饰符:private

参数:

  • invalidEntry: AbstractGameRulesScreen.RuleEntry

说明:

TODO

private void updateDoneButton() @ L115

  • 方法名:updateDoneButton
  • 源码定位:L115
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

protected void closeAndDiscardChanges() @ L121

  • 方法名:closeAndDiscardChanges
  • 源码定位:L121
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

protected void closeAndApplyChanges() @ L125

  • 方法名:closeAndApplyChanges
  • 源码定位:L125
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

protected void filterGameRules(String filter) @ L129

  • 方法名:filterGameRules
  • 源码定位:L129
  • 返回类型:void
  • 修饰符:protected

参数:

  • filter: String

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public abstract class AbstractGameRulesScreen extends Screen {
    protected static final Component TITLE = Component.translatable("editGamerule.title");
    private static final Component SEARCH_HINT = Component.translatable("gui.game_rule.search").withStyle(EditBox.SEARCH_HINT_STYLE);
    private static final int SEARCH_BOX_HEIGHT = 15;
    private final Set<AbstractGameRulesScreen.RuleEntry> invalidEntries = Sets.newHashSet();
    private final Consumer<Optional<GameRules>> exitCallback;
    protected final HeaderAndFooterLayout layout;
    protected final GameRules gameRules;
    protected @Nullable EditBox searchBox;
    protected AbstractGameRulesScreen.@Nullable RuleList ruleList;
    protected @Nullable Button doneButton;
 
    public AbstractGameRulesScreen(GameRules gameRules, Consumer<Optional<GameRules>> exitCallback) {
        super(TITLE);
        this.gameRules = gameRules;
        this.exitCallback = exitCallback;
        this.layout = new HeaderAndFooterLayout(this, (int)(12.0 + 9.0 + 15.0), 33);
    }
 
    protected void createAndConfigureSearchBox(LinearLayout headerLayout) {
        this.searchBox = headerLayout.addChild(new EditBox(this.font, 200, 15, Component.empty()));
        this.searchBox.setHint(SEARCH_HINT);
        this.searchBox.setResponder(this::filterGameRules);
    }
 
    @Override
    protected void init() {
        LinearLayout header = this.layout.addToHeader(LinearLayout.vertical().spacing(4));
        header.defaultCellSetting().alignHorizontallyCenter();
        header.addChild(new StringWidget(TITLE, this.font));
        this.createAndConfigureSearchBox(header);
        this.initContent();
        LinearLayout footer = this.layout.addToFooter(LinearLayout.horizontal().spacing(8));
        this.doneButton = footer.addChild(Button.builder(CommonComponents.GUI_DONE, button -> this.onDone()).build());
        footer.addChild(Button.builder(CommonComponents.GUI_CANCEL, button -> this.onClose()).build());
        this.layout.visitWidgets(x$0 -> this.addRenderableWidget(x$0));
        this.repositionElements();
    }
 
    protected abstract void initContent();
 
    protected abstract void onDone();
 
    @Override
    protected void repositionElements() {
        this.layout.arrangeElements();
        if (this.ruleList != null) {
            this.ruleList.updateSize(this.width, this.layout);
        }
    }
 
    @Override
    protected void setInitialFocus() {
        if (this.searchBox != null) {
            this.setInitialFocus(this.searchBox);
        }
    }
 
    private void markInvalid(AbstractGameRulesScreen.RuleEntry invalidEntry) {
        this.invalidEntries.add(invalidEntry);
        this.updateDoneButton();
    }
 
    private void clearInvalid(AbstractGameRulesScreen.RuleEntry invalidEntry) {
        this.invalidEntries.remove(invalidEntry);
        this.updateDoneButton();
    }
 
    private void updateDoneButton() {
        if (this.doneButton != null) {
            this.doneButton.active = this.invalidEntries.isEmpty();
        }
    }
 
    protected void closeAndDiscardChanges() {
        this.exitCallback.accept(Optional.empty());
    }
 
    protected void closeAndApplyChanges() {
        this.exitCallback.accept(Optional.of(this.gameRules));
    }
 
    protected void filterGameRules(String filter) {
        if (this.ruleList != null) {
            this.ruleList.populateChildren(filter);
            this.ruleList.setScrollAmount(0.0);
            this.repositionElements();
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public class BooleanRuleEntry extends AbstractGameRulesScreen.GameRuleEntry {
        private final CycleButton<Boolean> checkbox;
 
        public BooleanRuleEntry(Component name, List<FormattedCharSequence> tooltip, String narration, GameRule<Boolean> gameRule) {
            Objects.requireNonNull(AbstractGameRulesScreen.this);
            super(tooltip, name);
            this.checkbox = CycleButton.onOffBuilder(AbstractGameRulesScreen.this.gameRules.get(gameRule))
                .displayOnlyValue()
                .withCustomNarration(button -> button.createDefaultNarrationMessage().append("\n").append(narration))
                .create(10, 5, 44, 20, name, (button, newValue) -> AbstractGameRulesScreen.this.gameRules.set(gameRule, newValue, null));
            this.children.add(this.checkbox);
        }
 
        @Override
        public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
            this.extractLabel(graphics, this.getContentY(), this.getContentX());
            this.checkbox.setX(this.getContentRight() - 45);
            this.checkbox.setY(this.getContentY());
            this.checkbox.extractRenderState(graphics, mouseX, mouseY, a);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public class CategoryRuleEntry extends AbstractGameRulesScreen.RuleEntry {
        private final Component label;
 
        public CategoryRuleEntry(Component label) {
            Objects.requireNonNull(AbstractGameRulesScreen.this);
            super(null);
            this.label = label;
        }
 
        @Override
        public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
            graphics.centeredText(AbstractGameRulesScreen.this.minecraft.font, this.label, this.getContentXMiddle(), this.getContentY() + 5, -1);
        }
 
        @Override
        public List<? extends GuiEventListener> children() {
            return ImmutableList.of();
        }
 
        @Override
        public List<? extends NarratableEntry> narratables() {
            return ImmutableList.of(new NarratableEntry() {
                {
                    Objects.requireNonNull(CategoryRuleEntry.this);
                }
 
                @Override
                public NarratableEntry.NarrationPriority narrationPriority() {
                    return NarratableEntry.NarrationPriority.HOVERED;
                }
 
                @Override
                public void updateNarration(NarrationElementOutput output) {
                    output.add(NarratedElementType.TITLE, CategoryRuleEntry.this.label);
                }
            });
        }
    }
 
    @FunctionalInterface
    @OnlyIn(Dist.CLIENT)
    private interface EntryFactory<T> {
        AbstractGameRulesScreen.RuleEntry create(Component name, List<FormattedCharSequence> tooltip, String narration, GameRule<T> gameRule);
    }
 
    @OnlyIn(Dist.CLIENT)
    public abstract class GameRuleEntry extends AbstractGameRulesScreen.RuleEntry {
        private final List<FormattedCharSequence> label;
        protected final List<AbstractWidget> children;
 
        public GameRuleEntry(List<FormattedCharSequence> tooltip, Component label) {
            Objects.requireNonNull(AbstractGameRulesScreen.this);
            super(tooltip);
            this.children = Lists.newArrayList();
            this.label = AbstractGameRulesScreen.this.minecraft.font.split(label, 170);
        }
 
        @Override
        public List<? extends GuiEventListener> children() {
            return this.children;
        }
 
        @Override
        public List<? extends NarratableEntry> narratables() {
            return this.children;
        }
 
        protected void extractLabel(GuiGraphicsExtractor graphics, int rowTop, int rowLeft) {
            if (this.label.size() == 1) {
                graphics.text(AbstractGameRulesScreen.this.minecraft.font, this.label.get(0), rowLeft, rowTop + 5, -1);
            } else if (this.label.size() >= 2) {
                graphics.text(AbstractGameRulesScreen.this.minecraft.font, this.label.get(0), rowLeft, rowTop, -1);
                graphics.text(AbstractGameRulesScreen.this.minecraft.font, this.label.get(1), rowLeft, rowTop + 10, -1);
            }
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public class IntegerRuleEntry extends AbstractGameRulesScreen.GameRuleEntry {
        private final EditBox input;
 
        public IntegerRuleEntry(Component label, List<FormattedCharSequence> tooltip, String narration, GameRule<Integer> gameRule) {
            Objects.requireNonNull(AbstractGameRulesScreen.this);
            super(tooltip, label);
            this.input = new EditBox(AbstractGameRulesScreen.this.minecraft.font, 10, 5, 44, 20, label.copy().append("\n").append(narration).append("\n"));
            this.input.setValue(AbstractGameRulesScreen.this.gameRules.getAsString(gameRule));
            this.input.setResponder(v -> {
                DataResult<Integer> value = gameRule.deserialize(v);
                if (value.isSuccess()) {
                    this.input.setTextColor(-2039584);
                    AbstractGameRulesScreen.this.clearInvalid(this);
                    AbstractGameRulesScreen.this.gameRules.set(gameRule, value.getOrThrow(), null);
                } else {
                    this.input.setTextColor(-65536);
                    AbstractGameRulesScreen.this.markInvalid(this);
                }
            });
            this.children.add(this.input);
        }
 
        @Override
        public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
            this.extractLabel(graphics, this.getContentY(), this.getContentX());
            this.input.setX(this.getContentRight() - 45);
            this.input.setY(this.getContentY());
            this.input.extractRenderState(graphics, mouseX, mouseY, a);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public abstract static class RuleEntry extends ContainerObjectSelectionList.Entry<AbstractGameRulesScreen.RuleEntry> {
        private final @Nullable List<FormattedCharSequence> tooltip;
 
        public RuleEntry(@Nullable List<FormattedCharSequence> tooltip) {
            this.tooltip = tooltip;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public class RuleList extends ContainerObjectSelectionList<AbstractGameRulesScreen.RuleEntry> {
        private static final int ITEM_HEIGHT = 24;
        private final GameRules gameRules;
 
        public RuleList(GameRules gameRules) {
            Objects.requireNonNull(AbstractGameRulesScreen.this);
            super(
                Minecraft.getInstance(),
                AbstractGameRulesScreen.this.width,
                AbstractGameRulesScreen.this.layout.getContentHeight(),
                AbstractGameRulesScreen.this.layout.getHeaderHeight(),
                24
            );
            this.gameRules = gameRules;
            this.populateChildren("");
        }
 
        private void populateChildren(String filter) {
            this.clearEntries();
            final Map<GameRuleCategory, Map<GameRule<?>, AbstractGameRulesScreen.RuleEntry>> entries = Maps.newHashMap();
            final String lowerCaseFilter = filter.toLowerCase(Locale.ROOT);
            this.gameRules
                .visitGameRuleTypes(
                    new GameRuleTypeVisitor() {
                        {
                            Objects.requireNonNull(RuleList.this);
                        }
 
                        @Override
                        public void visitBoolean(GameRule<Boolean> gameRule) {
                            this.addEntry(gameRule, (x$0, x$1, x$2, x$3) -> AbstractGameRulesScreen.this.new BooleanRuleEntry(x$0, x$1, x$2, x$3));
                        }
 
                        @Override
                        public void visitInteger(GameRule<Integer> gameRule) {
                            this.addEntry(gameRule, (x$0, x$1, x$2, x$3) -> AbstractGameRulesScreen.this.new IntegerRuleEntry(x$0, x$1, x$2, x$3));
                        }
 
                        private <T> void addEntry(GameRule<T> gameRule, AbstractGameRulesScreen.EntryFactory<T> factory) {
                            Component readableName = Component.translatable(gameRule.getDescriptionId());
                            String descriptionKey = gameRule.getDescriptionId() + ".description";
                            Optional<MutableComponent> optionalDescription = Optional.of(Component.translatable(descriptionKey))
                                .filter(ComponentUtils::isTranslationResolvable);
                            if (AbstractGameRulesScreen.RuleList.matchesFilter(
                                gameRule.id(), readableName.getString(), gameRule.category().label().getString(), optionalDescription, lowerCaseFilter
                            )) {
                                Component actualName = Component.literal(gameRule.id()).withStyle(ChatFormatting.YELLOW);
                                Component defaultValue = Component.translatable(
                                        "editGamerule.default", Component.literal(gameRule.serialize(gameRule.defaultValue()))
                                    )
                                    .withStyle(ChatFormatting.GRAY);
                                List<FormattedCharSequence> tooltip;
                                String narration;
                                if (optionalDescription.isPresent()) {
                                    Builder<FormattedCharSequence> result = ImmutableList.<FormattedCharSequence>builder().add(actualName.getVisualOrderText());
                                    AbstractGameRulesScreen.this.font.split(optionalDescription.get(), 150).forEach(result::add);
                                    tooltip = result.add(defaultValue.getVisualOrderText()).build();
                                    narration = optionalDescription.get().getString() + "\n" + defaultValue.getString();
                                } else {
                                    tooltip = ImmutableList.of(actualName.getVisualOrderText(), defaultValue.getVisualOrderText());
                                    narration = defaultValue.getString();
                                }
 
                                entries.computeIfAbsent(gameRule.category(), k -> Maps.newHashMap())
                                    .put(gameRule, factory.create(readableName, tooltip, narration, gameRule));
                            }
                        }
                    }
                );
            entries.entrySet()
                .stream()
                .sorted(Map.Entry.comparingByKey(Comparator.comparing(GameRuleCategory::getDescriptionId)))
                .forEach(
                    e -> {
                        this.addEntry(
                            AbstractGameRulesScreen.this.new CategoryRuleEntry(e.getKey().label().withStyle(ChatFormatting.BOLD, ChatFormatting.YELLOW))
                        );
                        e.getValue()
                            .entrySet()
                            .stream()
                            .sorted(Map.Entry.comparingByKey(Comparator.comparing(GameRule::getDescriptionId)))
                            .forEach(v -> this.addEntry(v.getValue()));
                    }
                );
        }
 
        private static boolean matchesFilter(
            String gameRuleId, String readableName, String categoryName, Optional<MutableComponent> optionalDescription, String lowerCaseFilter
        ) {
            return toLowerCaseMatchesFilter(gameRuleId, lowerCaseFilter)
                || toLowerCaseMatchesFilter(readableName, lowerCaseFilter)
                || toLowerCaseMatchesFilter(categoryName, lowerCaseFilter)
                || optionalDescription.<Boolean>map(description -> toLowerCaseMatchesFilter(description.getString(), lowerCaseFilter)).orElse(false);
        }
 
        private static boolean toLowerCaseMatchesFilter(String gameRuleId, String lowerCaseFilter) {
            return gameRuleId.toLowerCase(Locale.ROOT).contains(lowerCaseFilter);
        }
 
        @Override
        public void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
            super.extractWidgetRenderState(graphics, mouseX, mouseY, a);
            AbstractGameRulesScreen.RuleEntry hovered = this.getHovered();
            if (hovered != null && hovered.tooltip != null) {
                graphics.setTooltipForNextFrame(hovered.tooltip, mouseX, mouseY);
            }
        }
    }
}

引用的其他类

  • Minecraft

    • 引用位置: 方法调用
    • 关联成员: Minecraft.getInstance()
  • Button

    • 引用位置: 字段/方法调用
    • 关联成员: Button.builder()
  • CycleButton

    • 引用位置: 方法调用
    • 关联成员: CycleButton.onOffBuilder()
  • EditBox

    • 引用位置: 字段/构造调用
    • 关联成员: EditBox()
  • StringWidget

    • 引用位置: 构造调用
    • 关联成员: StringWidget()
  • HeaderAndFooterLayout

    • 引用位置: 字段/构造调用
    • 关联成员: HeaderAndFooterLayout()
  • LinearLayout

    • 引用位置: 参数/方法调用
    • 关联成员: LinearLayout.horizontal(), LinearLayout.vertical()
  • NarratableEntry

    • 引用位置: 构造调用
    • 关联成员: NarratableEntry()
  • Screen

    • 引用位置: 继承
  • Component

    • 引用位置: 字段/方法调用
    • 关联成员: Component.empty(), Component.literal(), Component.translatable()
  • GameRuleTypeVisitor

    • 引用位置: 构造调用
    • 关联成员: GameRuleTypeVisitor()
  • GameRules

    • 引用位置: 参数/字段