FallbackResourceManager.java

net.minecraft.server.packs.resources.FallbackResourceManager

信息

  • 全限定名:net.minecraft.server.packs.resources.FallbackResourceManager
  • 类型:public class
  • 包:net.minecraft.server.packs.resources
  • 源码路径:src/main/java/net/minecraft/server/packs/resources/FallbackResourceManager.java
  • 起始行号:L31
  • 实现:ResourceManager
  • 职责:

    TODO

字段/常量

  • LOGGER

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

      TODO

  • fallbacks

    • 类型: List<FallbackResourceManager.PackEntry>
    • 修饰符: protected final
    • 源码定位: L33
    • 说明:

      TODO

  • type

    • 类型: PackType
    • 修饰符: private final
    • 源码定位: L34
    • 说明:

      TODO

  • namespace

    • 类型: String
    • 修饰符: private final
    • 源码定位: L35
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.server.packs.resources.FallbackResourceManager.ResourceWithSourceAndIndex

    • 类型: record
    • 修饰符: package-private
    • 源码定位: L154
    • 说明:

      TODO

  • net.minecraft.server.packs.resources.FallbackResourceManager.EntryStack

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

      TODO

  • net.minecraft.server.packs.resources.FallbackResourceManager.LeakedResourceWarningInputStream

    • 类型: class
    • 修饰符: private static
    • 源码定位: L323
    • 说明:

      TODO

  • net.minecraft.server.packs.resources.FallbackResourceManager.PackEntry

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

      TODO

  • net.minecraft.server.packs.resources.FallbackResourceManager.ResourceWithSource

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

      TODO

构造器

public FallbackResourceManager(PackType type, String namespace) @ L37

  • 构造器名:FallbackResourceManager
  • 源码定位:L37
  • 修饰符:public

参数:

  • type: PackType
  • namespace: String

说明:

TODO

方法

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

public void push(PackResources pack) @ L42

  • 方法名:push
  • 源码定位:L42
  • 返回类型:void
  • 修饰符:public

参数:

  • pack: PackResources

说明:

TODO

public void push(PackResources pack, Predicate<Identifier> filter) @ L46

  • 方法名:push
  • 源码定位:L46
  • 返回类型:void
  • 修饰符:public

参数:

  • pack: PackResources
  • filter: Predicate

说明:

TODO

public void pushFilterOnly(String name, Predicate<Identifier> filter) @ L50

  • 方法名:pushFilterOnly
  • 源码定位:L50
  • 返回类型:void
  • 修饰符:public

参数:

  • name: String
  • filter: Predicate

说明:

TODO

private void pushInternal(String name, PackResources pack, Predicate<Identifier> contentFilter) @ L54

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

参数:

  • name: String
  • pack: PackResources
  • contentFilter: Predicate

说明:

TODO

public Set<String> getNamespaces() @ L58

  • 方法名:getNamespaces
  • 源码定位:L58
  • 返回类型:Set
  • 修饰符:public

参数:

说明:

TODO

public Optional<Resource> getResource(Identifier location) @ L63

  • 方法名:getResource
  • 源码定位:L63
  • 返回类型:Optional
  • 修饰符:public

参数:

  • location: Identifier

说明:

TODO

private static Resource createResource(PackResources source, Identifier location, IoSupplier<InputStream> resource, IoSupplier<ResourceMetadata> metadata) @ L85

  • 方法名:createResource
  • 源码定位:L85
  • 返回类型:Resource
  • 修饰符:private static

参数:

  • source: PackResources
  • location: Identifier
  • resource: IoSupplier
  • metadata: IoSupplier

说明:

TODO

private static IoSupplier<InputStream> wrapForDebug(Identifier location, PackResources source, IoSupplier<InputStream> resource) @ L89

  • 方法名:wrapForDebug
  • 源码定位:L89
  • 返回类型:IoSupplier
  • 修饰符:private static

参数:

  • location: Identifier
  • source: PackResources
  • resource: IoSupplier

说明:

TODO

public List<Resource> getResourceStack(Identifier location) @ L95

  • 方法名:getResourceStack
  • 源码定位:L95
  • 返回类型:List
  • 修饰符:public

参数:

  • location: Identifier

说明:

TODO

private static boolean isMetadata(Identifier location) @ L139

  • 方法名:isMetadata
  • 源码定位:L139
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • location: Identifier

说明:

TODO

private static Identifier getIdentifierFromMetadata(Identifier identifier) @ L143

  • 方法名:getIdentifierFromMetadata
  • 源码定位:L143
  • 返回类型:Identifier
  • 修饰符:private static

参数:

  • identifier: Identifier

说明:

TODO

private static Identifier getMetadataLocation(Identifier identifier) @ L148

  • 方法名:getMetadataLocation
  • 源码定位:L148
  • 返回类型:Identifier
  • 修饰符:private static

参数:

  • identifier: Identifier

说明:

TODO

public Map<Identifier,Resource> listResources(String directory, Predicate<Identifier> filter) @ L152

  • 方法名:listResources
  • 源码定位:L152
  • 返回类型:Map<Identifier,Resource>
  • 修饰符:public

参数:

  • directory: String
  • filter: Predicate

说明:

TODO

private IoSupplier<ResourceMetadata> createStackMetadataFinder(Identifier location, int finalPackIndex) @ L196

  • 方法名:createStackMetadataFinder
  • 源码定位:L196
  • 返回类型:IoSupplier
  • 修饰符:private

参数:

  • location: Identifier
  • finalPackIndex: int

说明:

TODO

private static IoSupplier<ResourceMetadata> convertToMetadata(IoSupplier<InputStream> input) @ L219

  • 方法名:convertToMetadata
  • 源码定位:L219
  • 返回类型:IoSupplier
  • 修饰符:private static

参数:

  • input: IoSupplier

说明:

TODO

private static ResourceMetadata parseMetadata(IoSupplier<InputStream> input) @ L223

  • 方法名:parseMetadata
  • 源码定位:L223
  • 返回类型:ResourceMetadata
  • 修饰符:private static

参数:

  • input: IoSupplier

说明:

TODO

private static void applyPackFiltersToExistingResources(FallbackResourceManager.PackEntry entry, Map<Identifier,FallbackResourceManager.EntryStack> foundResources) @ L232

  • 方法名:applyPackFiltersToExistingResources
  • 源码定位:L232
  • 返回类型:void
  • 修饰符:private static

参数:

  • entry: FallbackResourceManager.PackEntry
  • foundResources: Map<Identifier,FallbackResourceManager.EntryStack>

说明:

TODO

private void listPackResources(FallbackResourceManager.PackEntry entry, String directory, Predicate<Identifier> filter, Map<Identifier,FallbackResourceManager.EntryStack> foundResources) @ L244

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

参数:

  • entry: FallbackResourceManager.PackEntry
  • directory: String
  • filter: Predicate
  • foundResources: Map<Identifier,FallbackResourceManager.EntryStack>

说明:

TODO

public Map<Identifier,List<Resource>> listResourceStacks(String directory, Predicate<Identifier> filter) @ L278

  • 方法名:listResourceStacks
  • 源码定位:L278
  • 返回类型:Map<Identifier,List>
  • 修饰符:public

参数:

  • directory: String
  • filter: Predicate

说明:

TODO

public Stream<PackResources> listPacks() @ L307

  • 方法名:listPacks
  • 源码定位:L307
  • 返回类型:Stream
  • 修饰符:public

参数:

说明:

TODO

代码

public class FallbackResourceManager implements ResourceManager {
    private static final Logger LOGGER = LogUtils.getLogger();
    protected final List<FallbackResourceManager.PackEntry> fallbacks = Lists.newArrayList();
    private final PackType type;
    private final String namespace;
 
    public FallbackResourceManager(PackType type, String namespace) {
        this.type = type;
        this.namespace = namespace;
    }
 
    public void push(PackResources pack) {
        this.pushInternal(pack.packId(), pack, null);
    }
 
    public void push(PackResources pack, Predicate<Identifier> filter) {
        this.pushInternal(pack.packId(), pack, filter);
    }
 
    public void pushFilterOnly(String name, Predicate<Identifier> filter) {
        this.pushInternal(name, null, filter);
    }
 
    private void pushInternal(String name, @Nullable PackResources pack, @Nullable Predicate<Identifier> contentFilter) {
        this.fallbacks.add(new FallbackResourceManager.PackEntry(name, pack, contentFilter));
    }
 
    @Override
    public Set<String> getNamespaces() {
        return ImmutableSet.of(this.namespace);
    }
 
    @Override
    public Optional<Resource> getResource(Identifier location) {
        for (int i = this.fallbacks.size() - 1; i >= 0; i--) {
            FallbackResourceManager.PackEntry entry = this.fallbacks.get(i);
            PackResources fallback = entry.resources;
            if (fallback != null) {
                IoSupplier<InputStream> resource = fallback.getResource(this.type, location);
                if (resource != null) {
                    IoSupplier<ResourceMetadata> metadataGetter = this.createStackMetadataFinder(location, i);
                    return Optional.of(createResource(fallback, location, resource, metadataGetter));
                }
            }
 
            if (entry.isFiltered(location)) {
                LOGGER.warn("Resource {} not found, but was filtered by pack {}", location, entry.name);
                return Optional.empty();
            }
        }
 
        return Optional.empty();
    }
 
    private static Resource createResource(PackResources source, Identifier location, IoSupplier<InputStream> resource, IoSupplier<ResourceMetadata> metadata) {
        return new Resource(source, wrapForDebug(location, source, resource), metadata);
    }
 
    private static IoSupplier<InputStream> wrapForDebug(Identifier location, PackResources source, IoSupplier<InputStream> resource) {
        return LOGGER.isDebugEnabled()
            ? () -> new FallbackResourceManager.LeakedResourceWarningInputStream(resource.get(), location, source.packId())
            : resource;
    }
 
    @Override
    public List<Resource> getResourceStack(Identifier location) {
        Identifier metadataLocation = getMetadataLocation(location);
        List<Resource> result = new ArrayList<>();
        boolean filterMeta = false;
        String lastFilterName = null;
 
        for (int i = this.fallbacks.size() - 1; i >= 0; i--) {
            FallbackResourceManager.PackEntry entry = this.fallbacks.get(i);
            PackResources fileSource = entry.resources;
            if (fileSource != null) {
                IoSupplier<InputStream> resource = fileSource.getResource(this.type, location);
                if (resource != null) {
                    IoSupplier<ResourceMetadata> metadataGetter;
                    if (filterMeta) {
                        metadataGetter = ResourceMetadata.EMPTY_SUPPLIER;
                    } else {
                        metadataGetter = () -> {
                            IoSupplier<InputStream> metaResource = fileSource.getResource(this.type, metadataLocation);
                            return metaResource != null ? parseMetadata(metaResource) : ResourceMetadata.EMPTY;
                        };
                    }
 
                    result.add(new Resource(fileSource, resource, metadataGetter));
                }
            }
 
            if (entry.isFiltered(location)) {
                lastFilterName = entry.name;
                break;
            }
 
            if (entry.isFiltered(metadataLocation)) {
                filterMeta = true;
            }
        }
 
        if (result.isEmpty() && lastFilterName != null) {
            LOGGER.warn("Resource {} not found, but was filtered by pack {}", location, lastFilterName);
        }
 
        return Lists.reverse(result);
    }
 
    private static boolean isMetadata(Identifier location) {
        return location.getPath().endsWith(".mcmeta");
    }
 
    private static Identifier getIdentifierFromMetadata(Identifier identifier) {
        String newPath = identifier.getPath().substring(0, identifier.getPath().length() - ".mcmeta".length());
        return identifier.withPath(newPath);
    }
 
    private static Identifier getMetadataLocation(Identifier identifier) {
        return identifier.withPath(identifier.getPath() + ".mcmeta");
    }
 
    @Override
    public Map<Identifier, Resource> listResources(String directory, Predicate<Identifier> filter) {
        record ResourceWithSourceAndIndex(PackResources packResources, IoSupplier<InputStream> resource, int packIndex) {
        }
 
        Map<Identifier, ResourceWithSourceAndIndex> topResourceForFileLocation = new HashMap<>();
        Map<Identifier, ResourceWithSourceAndIndex> topResourceForMetaLocation = new HashMap<>();
        int packCount = this.fallbacks.size();
 
        for (int i = 0; i < packCount; i++) {
            FallbackResourceManager.PackEntry entry = this.fallbacks.get(i);
            entry.filterAll(topResourceForFileLocation.keySet());
            entry.filterAll(topResourceForMetaLocation.keySet());
            PackResources packResources = entry.resources;
            if (packResources != null) {
                int packIndex = i;
                packResources.listResources(this.type, this.namespace, directory, (resource, streamSupplier) -> {
                    if (isMetadata(resource)) {
                        if (filter.test(getIdentifierFromMetadata(resource))) {
                            topResourceForMetaLocation.put(resource, new ResourceWithSourceAndIndex(packResources, streamSupplier, packIndex));
                        }
                    } else if (filter.test(resource)) {
                        topResourceForFileLocation.put(resource, new ResourceWithSourceAndIndex(packResources, streamSupplier, packIndex));
                    }
                });
            }
        }
 
        Map<Identifier, Resource> result = Maps.newTreeMap();
        topResourceForFileLocation.forEach((location, resource) -> {
            Identifier metadataLocation = getMetadataLocation(location);
            ResourceWithSourceAndIndex metaResource = topResourceForMetaLocation.get(metadataLocation);
            IoSupplier<ResourceMetadata> metaGetter;
            if (metaResource != null && metaResource.packIndex >= resource.packIndex) {
                metaGetter = convertToMetadata(metaResource.resource);
            } else {
                metaGetter = ResourceMetadata.EMPTY_SUPPLIER;
            }
 
            result.put(location, createResource(resource.packResources, location, resource.resource, metaGetter));
        });
        return result;
    }
 
    private IoSupplier<ResourceMetadata> createStackMetadataFinder(Identifier location, int finalPackIndex) {
        return () -> {
            Identifier metadataLocation = getMetadataLocation(location);
 
            for (int i = this.fallbacks.size() - 1; i >= finalPackIndex; i--) {
                FallbackResourceManager.PackEntry entry = this.fallbacks.get(i);
                PackResources metadataPackCandidate = entry.resources;
                if (metadataPackCandidate != null) {
                    IoSupplier<InputStream> resource = metadataPackCandidate.getResource(this.type, metadataLocation);
                    if (resource != null) {
                        return parseMetadata(resource);
                    }
                }
 
                if (entry.isFiltered(metadataLocation)) {
                    break;
                }
            }
 
            return ResourceMetadata.EMPTY;
        };
    }
 
    private static IoSupplier<ResourceMetadata> convertToMetadata(IoSupplier<InputStream> input) {
        return () -> parseMetadata(input);
    }
 
    private static ResourceMetadata parseMetadata(IoSupplier<InputStream> input) throws IOException {
        ResourceMetadata var2;
        try (InputStream metadata = input.get()) {
            var2 = ResourceMetadata.fromJsonStream(metadata);
        }
 
        return var2;
    }
 
    private static void applyPackFiltersToExistingResources(
        FallbackResourceManager.PackEntry entry, Map<Identifier, FallbackResourceManager.EntryStack> foundResources
    ) {
        for (FallbackResourceManager.EntryStack e : foundResources.values()) {
            if (entry.isFiltered(e.fileLocation)) {
                e.fileSources.clear();
            } else if (entry.isFiltered(e.metadataLocation())) {
                e.metaSources.clear();
            }
        }
    }
 
    private void listPackResources(
        FallbackResourceManager.PackEntry entry,
        String directory,
        Predicate<Identifier> filter,
        Map<Identifier, FallbackResourceManager.EntryStack> foundResources
    ) {
        PackResources pack = entry.resources;
        if (pack != null) {
            pack.listResources(
                this.type,
                this.namespace,
                directory,
                (id, resource) -> {
                    if (isMetadata(id)) {
                        Identifier actualId = getIdentifierFromMetadata(id);
                        if (!filter.test(actualId)) {
                            return;
                        }
 
                        foundResources.computeIfAbsent(actualId, FallbackResourceManager.EntryStack::new).metaSources.put(pack, resource);
                    } else {
                        if (!filter.test(id)) {
                            return;
                        }
 
                        foundResources.computeIfAbsent(id, FallbackResourceManager.EntryStack::new)
                            .fileSources
                            .add(new FallbackResourceManager.ResourceWithSource(pack, resource));
                    }
                }
            );
        }
    }
 
    @Override
    public Map<Identifier, List<Resource>> listResourceStacks(String directory, Predicate<Identifier> filter) {
        Map<Identifier, FallbackResourceManager.EntryStack> foundResources = Maps.newHashMap();
 
        for (FallbackResourceManager.PackEntry entry : this.fallbacks) {
            applyPackFiltersToExistingResources(entry, foundResources);
            this.listPackResources(entry, directory, filter, foundResources);
        }
 
        TreeMap<Identifier, List<Resource>> result = Maps.newTreeMap();
 
        for (FallbackResourceManager.EntryStack entry : foundResources.values()) {
            if (!entry.fileSources.isEmpty()) {
                List<Resource> resources = new ArrayList<>();
 
                for (FallbackResourceManager.ResourceWithSource stackEntry : entry.fileSources) {
                    PackResources source = stackEntry.source;
                    IoSupplier<InputStream> metaSource = entry.metaSources.get(source);
                    IoSupplier<ResourceMetadata> metaGetter = metaSource != null ? convertToMetadata(metaSource) : ResourceMetadata.EMPTY_SUPPLIER;
                    resources.add(createResource(source, entry.fileLocation, stackEntry.resource, metaGetter));
                }
 
                result.put(entry.fileLocation, resources);
            }
        }
 
        return result;
    }
 
    @Override
    public Stream<PackResources> listPacks() {
        return this.fallbacks.stream().map(p -> p.resources).filter(Objects::nonNull);
    }
 
    private record EntryStack(
        Identifier fileLocation,
        Identifier metadataLocation,
        List<FallbackResourceManager.ResourceWithSource> fileSources,
        Map<PackResources, IoSupplier<InputStream>> metaSources
    ) {
        EntryStack(Identifier fileLocation) {
            this(fileLocation, FallbackResourceManager.getMetadataLocation(fileLocation), new ArrayList<>(), new Object2ObjectArrayMap<>());
        }
    }
 
    private static class LeakedResourceWarningInputStream extends FilterInputStream {
        private final Supplier<String> message;
        private boolean closed;
 
        public LeakedResourceWarningInputStream(InputStream wrapped, Identifier location, String name) {
            super(wrapped);
            Exception exception = new Exception("Stacktrace");
            this.message = () -> {
                StringWriter data = new StringWriter();
                exception.printStackTrace(new PrintWriter(data));
                return "Leaked resource: '" + location + "' loaded from pack: '" + name + "'\n" + data;
            };
        }
 
        @Override
        public void close() throws IOException {
            super.close();
            this.closed = true;
        }
 
        @Override
        protected void finalize() throws Throwable {
            if (!this.closed) {
                FallbackResourceManager.LOGGER.warn("{}", this.message.get());
            }
 
            super.finalize();
        }
    }
 
    private record PackEntry(String name, @Nullable PackResources resources, @Nullable Predicate<Identifier> filter) {
        public void filterAll(Collection<Identifier> collection) {
            if (this.filter != null) {
                collection.removeIf(this.filter);
            }
        }
 
        public boolean isFiltered(Identifier location) {
            return this.filter != null && this.filter.test(location);
        }
    }
 
    private record ResourceWithSource(PackResources source, IoSupplier<InputStream> resource) {
    }
}

引用的其他类