ProblemReporter.java

net.minecraft.util.ProblemReporter

信息

  • 全限定名:net.minecraft.util.ProblemReporter
  • 类型:public interface
  • 包:net.minecraft.util
  • 源码路径:src/main/java/net/minecraft/util/ProblemReporter.java
  • 起始行号:L17
  • 职责:

    TODO

字段/常量

  • DISCARDING
    • 类型: ProblemReporter
    • 修饰符: public public
    • 源码定位: L18
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.util.ProblemReporter.Collector

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

      TODO

  • net.minecraft.util.ProblemReporter.Collector.Entry

    • 类型: record
    • 修饰符: private
    • 源码定位: L125
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.Collector.ProblemTreeNode

    • 类型: record
    • 修饰符: private
    • 源码定位: L128
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.ElementReferencePathElement

    • 类型: record
    • 修饰符: public
    • 源码定位: L169
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.FieldPathElement

    • 类型: record
    • 修饰符: public
    • 源码定位: L176
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.IndexedFieldPathElement

    • 类型: record
    • 修饰符: public
    • 源码定位: L183
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.IndexedPathElement

    • 类型: record
    • 修饰符: public
    • 源码定位: L190
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.MapEntryPathElement

    • 类型: record
    • 修饰符: public
    • 源码定位: L197
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.PathElement

    • 类型: interface
    • 修饰符: public
    • 源码定位: L205
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.Problem

    • 类型: interface
    • 修饰符: public
    • 源码定位: L209
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.RootElementPathElement

    • 类型: record
    • 修饰符: public
    • 源码定位: L213
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.RootFieldPathElement

    • 类型: record
    • 修饰符: public
    • 源码定位: L220
    • 说明:

      TODO

  • net.minecraft.util.ProblemReporter.ScopedCollector

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

      TODO

构造器

方法

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

ProblemReporter forChild(ProblemReporter.PathElement path) @ L29

  • 方法名:forChild
  • 源码定位:L29
  • 返回类型:ProblemReporter
  • 修饰符:package-private

参数:

  • path: ProblemReporter.PathElement

说明:

TODO

void report(ProblemReporter.Problem problem) @ L31

  • 方法名:report
  • 源码定位:L31
  • 返回类型:void
  • 修饰符:package-private

参数:

  • problem: ProblemReporter.Problem

说明:

TODO

代码

public interface ProblemReporter {
    ProblemReporter DISCARDING = new ProblemReporter() {
        @Override
        public ProblemReporter forChild(ProblemReporter.PathElement path) {
            return this;
        }
 
        @Override
        public void report(ProblemReporter.Problem problem) {
        }
    };
 
    ProblemReporter forChild(ProblemReporter.PathElement path);
 
    void report(ProblemReporter.Problem problem);
 
    public static class Collector implements ProblemReporter {
        public static final ProblemReporter.PathElement EMPTY_ROOT = () -> "";
        private final ProblemReporter.@Nullable Collector parent;
        private final ProblemReporter.PathElement element;
        private final Set<ProblemReporter.Collector.Entry> problems;
 
        public Collector() {
            this(EMPTY_ROOT);
        }
 
        public Collector(ProblemReporter.PathElement root) {
            this.parent = null;
            this.problems = new LinkedHashSet<>();
            this.element = root;
        }
 
        private Collector(ProblemReporter.Collector parent, ProblemReporter.PathElement path) {
            this.problems = parent.problems;
            this.parent = parent;
            this.element = path;
        }
 
        @Override
        public ProblemReporter forChild(ProblemReporter.PathElement path) {
            return new ProblemReporter.Collector(this, path);
        }
 
        @Override
        public void report(ProblemReporter.Problem problem) {
            this.problems.add(new ProblemReporter.Collector.Entry(this, problem));
        }
 
        public boolean isEmpty() {
            return this.problems.isEmpty();
        }
 
        public void forEach(BiConsumer<String, ProblemReporter.Problem> output) {
            List<ProblemReporter.PathElement> pathElements = new ArrayList<>();
            StringBuilder pathString = new StringBuilder();
 
            for (ProblemReporter.Collector.Entry entry : this.problems) {
                for (ProblemReporter.Collector current = entry.source; current != null; current = current.parent) {
                    pathElements.add(current.element);
                }
 
                for (int i = pathElements.size() - 1; i >= 0; i--) {
                    pathString.append(pathElements.get(i).get());
                }
 
                output.accept(pathString.toString(), entry.problem());
                pathString.setLength(0);
                pathElements.clear();
            }
        }
 
        public String getReport() {
            Multimap<String, ProblemReporter.Problem> groupedProblems = HashMultimap.create();
            this.forEach(groupedProblems::put);
            return groupedProblems.asMap()
                .entrySet()
                .stream()
                .map(
                    entry -> " at "
                        + entry.getKey()
                        + ": "
                        + entry.getValue().stream().map(ProblemReporter.Problem::description).collect(Collectors.joining("; "))
                )
                .collect(Collectors.joining("\n"));
        }
 
        public String getTreeReport() {
            List<ProblemReporter.PathElement> pathElements = new ArrayList<>();
            ProblemReporter.Collector.ProblemTreeNode root = new ProblemReporter.Collector.ProblemTreeNode(this.element);
 
            for (ProblemReporter.Collector.Entry entry : this.problems) {
                for (ProblemReporter.Collector current = entry.source; current != this; current = current.parent) {
                    pathElements.add(current.element);
                }
 
                ProblemReporter.Collector.ProblemTreeNode node = root;
 
                for (int i = pathElements.size() - 1; i >= 0; i--) {
                    node = node.child(pathElements.get(i));
                }
 
                pathElements.clear();
                node.problems.add(entry.problem);
            }
 
            return String.join("\n", root.getLines());
        }
 
        private record Entry(ProblemReporter.Collector source, ProblemReporter.Problem problem) {
        }
 
        private record ProblemTreeNode(
            ProblemReporter.PathElement element,
            List<ProblemReporter.Problem> problems,
            Map<ProblemReporter.PathElement, ProblemReporter.Collector.ProblemTreeNode> children
        ) {
            public ProblemTreeNode(ProblemReporter.PathElement pathElement) {
                this(pathElement, new ArrayList<>(), new LinkedHashMap<>());
            }
 
            public ProblemReporter.Collector.ProblemTreeNode child(ProblemReporter.PathElement id) {
                return this.children.computeIfAbsent(id, ProblemReporter.Collector.ProblemTreeNode::new);
            }
 
            public List<String> getLines() {
                int problemCount = this.problems.size();
                int childrenCount = this.children.size();
                if (problemCount == 0 && childrenCount == 0) {
                    return List.of();
                } else if (problemCount == 0 && childrenCount == 1) {
                    List<String> lines = new ArrayList<>();
                    this.children.forEach((element, child) -> lines.addAll(child.getLines()));
                    lines.set(0, this.element.get() + lines.get(0));
                    return lines;
                } else if (problemCount == 1 && childrenCount == 0) {
                    return List.of(this.element.get() + ": " + this.problems.getFirst().description());
                } else {
                    List<String> lines = new ArrayList<>();
                    this.children.forEach((element, child) -> lines.addAll(child.getLines()));
                    lines.replaceAll(s -> "  " + s);
 
                    for (ProblemReporter.Problem problem : this.problems) {
                        lines.add("  " + problem.description());
                    }
 
                    lines.addFirst(this.element.get() + ":");
                    return lines;
                }
            }
        }
    }
 
    public record ElementReferencePathElement(ResourceKey<?> id) implements ProblemReporter.PathElement {
        @Override
        public String get() {
            return "->{" + this.id.identifier() + "@" + this.id.registry() + "}";
        }
    }
 
    public record FieldPathElement(String name) implements ProblemReporter.PathElement {
        @Override
        public String get() {
            return "." + this.name;
        }
    }
 
    public record IndexedFieldPathElement(String name, int index) implements ProblemReporter.PathElement {
        @Override
        public String get() {
            return "." + this.name + "[" + this.index + "]";
        }
    }
 
    public record IndexedPathElement(int index) implements ProblemReporter.PathElement {
        @Override
        public String get() {
            return "[" + this.index + "]";
        }
    }
 
    public record MapEntryPathElement(String name, String key) implements ProblemReporter.PathElement {
        @Override
        public String get() {
            return "." + this.name + "[" + this.key + "]";
        }
    }
 
    @FunctionalInterface
    public interface PathElement {
        String get();
    }
 
    public interface Problem {
        String description();
    }
 
    public record RootElementPathElement(ResourceKey<?> id) implements ProblemReporter.PathElement {
        @Override
        public String get() {
            return "{" + this.id.identifier() + "@" + this.id.registry() + "}";
        }
    }
 
    public record RootFieldPathElement(String name) implements ProblemReporter.PathElement {
        @Override
        public String get() {
            return this.name;
        }
    }
 
    public static class ScopedCollector extends ProblemReporter.Collector implements AutoCloseable {
        private final Logger logger;
 
        public ScopedCollector(Logger logger) {
            this.logger = logger;
        }
 
        public ScopedCollector(ProblemReporter.PathElement root, Logger logger) {
            super(root);
            this.logger = logger;
        }
 
        @Override
        public void close() {
            if (!this.isEmpty()) {
                this.logger.warn("[{}] Serialization errors:\n{}", this.logger.getName(), this.getTreeReport());
            }
        }
    }
}

引用的其他类