Code/net/minecraft/server/packs/resources/FallbackResourceManager.java

374 lines
16 KiB
Java
Raw Permalink Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.server.packs.resources;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.PackType;
import org.slf4j.Logger;
public class FallbackResourceManager implements ResourceManager {
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 p_10605_, String p_10606_) {
this.type = p_10605_;
this.namespace = p_10606_;
}
public void push(PackResources p_215378_) {
this.pushInternal(p_215378_.packId(), p_215378_, null);
}
public void push(PackResources p_215383_, Predicate<ResourceLocation> p_215384_) {
this.pushInternal(p_215383_.packId(), p_215383_, p_215384_);
}
public void pushFilterOnly(String p_215400_, Predicate<ResourceLocation> p_215401_) {
this.pushInternal(p_215400_, null, p_215401_);
}
private void pushInternal(String p_215396_, @Nullable PackResources p_215397_, @Nullable Predicate<ResourceLocation> p_215398_) {
this.fallbacks.add(new FallbackResourceManager.PackEntry(p_215396_, p_215397_, p_215398_));
}
@Override
public Set<String> getNamespaces() {
return ImmutableSet.of(this.namespace);
}
@Override
public Optional<Resource> getResource(ResourceLocation p_215419_) {
for (int i = this.fallbacks.size() - 1; i >= 0; i--) {
FallbackResourceManager.PackEntry fallbackresourcemanager$packentry = this.fallbacks.get(i);
PackResources packresources = fallbackresourcemanager$packentry.resources;
if (packresources != null) {
IoSupplier<InputStream> iosupplier = packresources.getResource(this.type, p_215419_);
if (iosupplier != null) {
IoSupplier<ResourceMetadata> iosupplier1 = this.createStackMetadataFinder(p_215419_, i);
return Optional.of(createResource(packresources, p_215419_, iosupplier, iosupplier1));
}
}
if (fallbackresourcemanager$packentry.isFiltered(p_215419_)) {
LOGGER.warn("Resource {} not found, but was filtered by pack {}", p_215419_, fallbackresourcemanager$packentry.name);
return Optional.empty();
}
}
return Optional.empty();
}
private static Resource createResource(
PackResources p_249946_, ResourceLocation p_250632_, IoSupplier<InputStream> p_250514_, IoSupplier<ResourceMetadata> p_251676_
) {
return new Resource(p_249946_, wrapForDebug(p_250632_, p_249946_, p_250514_), p_251676_);
}
private static IoSupplier<InputStream> wrapForDebug(ResourceLocation p_248639_, PackResources p_251740_, IoSupplier<InputStream> p_249116_) {
return LOGGER.isDebugEnabled()
? () -> new FallbackResourceManager.LeakedResourceWarningInputStream(p_249116_.get(), p_248639_, p_251740_.packId())
: p_249116_;
}
@Override
public List<Resource> getResourceStack(ResourceLocation p_215367_) {
ResourceLocation resourcelocation = getMetadataLocation(p_215367_);
List<Resource> list = new ArrayList<>();
boolean flag = false;
String s = null;
for (int i = this.fallbacks.size() - 1; i >= 0; i--) {
FallbackResourceManager.PackEntry fallbackresourcemanager$packentry = this.fallbacks.get(i);
PackResources packresources = fallbackresourcemanager$packentry.resources;
if (packresources != null) {
IoSupplier<InputStream> iosupplier = packresources.getResource(this.type, p_215367_);
if (iosupplier != null) {
IoSupplier<ResourceMetadata> iosupplier1;
if (flag) {
iosupplier1 = ResourceMetadata.EMPTY_SUPPLIER;
} else {
iosupplier1 = () -> {
IoSupplier<InputStream> iosupplier2 = packresources.getResource(this.type, resourcelocation);
return iosupplier2 != null ? parseMetadata(iosupplier2) : ResourceMetadata.EMPTY;
};
}
list.add(new Resource(packresources, iosupplier, iosupplier1));
}
}
if (fallbackresourcemanager$packentry.isFiltered(p_215367_)) {
s = fallbackresourcemanager$packentry.name;
break;
}
if (fallbackresourcemanager$packentry.isFiltered(resourcelocation)) {
flag = true;
}
}
if (list.isEmpty() && s != null) {
LOGGER.warn("Resource {} not found, but was filtered by pack {}", p_215367_, s);
}
return Lists.reverse(list);
}
private static boolean isMetadata(ResourceLocation p_249381_) {
return p_249381_.getPath().endsWith(".mcmeta");
}
private static ResourceLocation getResourceLocationFromMetadata(ResourceLocation p_249669_) {
String s = p_249669_.getPath().substring(0, p_249669_.getPath().length() - ".mcmeta".length());
return p_249669_.withPath(s);
}
static ResourceLocation getMetadataLocation(ResourceLocation p_10625_) {
return p_10625_.withPath(p_10625_.getPath() + ".mcmeta");
}
@Override
public Map<ResourceLocation, Resource> listResources(String p_215413_, Predicate<ResourceLocation> p_215414_) {
record ResourceWithSourceAndIndex(PackResources packResources, IoSupplier<InputStream> resource, int packIndex) {
}
Map<ResourceLocation, ResourceWithSourceAndIndex> map = new HashMap<>();
Map<ResourceLocation, ResourceWithSourceAndIndex> map1 = new HashMap<>();
int i = this.fallbacks.size();
for (int j = 0; j < i; j++) {
FallbackResourceManager.PackEntry fallbackresourcemanager$packentry = this.fallbacks.get(j);
fallbackresourcemanager$packentry.filterAll(map.keySet());
fallbackresourcemanager$packentry.filterAll(map1.keySet());
PackResources packresources = fallbackresourcemanager$packentry.resources;
if (packresources != null) {
int k = j;
packresources.listResources(this.type, this.namespace, p_215413_, (p_248254_, p_248255_) -> {
if (isMetadata(p_248254_)) {
if (p_215414_.test(getResourceLocationFromMetadata(p_248254_))) {
map1.put(p_248254_, new ResourceWithSourceAndIndex(packresources, p_248255_, k));
}
} else if (p_215414_.test(p_248254_)) {
map.put(p_248254_, new ResourceWithSourceAndIndex(packresources, p_248255_, k));
}
});
}
}
Map<ResourceLocation, Resource> map2 = Maps.newTreeMap();
map.forEach(
(p_248258_, p_248259_) -> {
ResourceLocation resourcelocation = getMetadataLocation(p_248258_);
ResourceWithSourceAndIndex fallbackresourcemanager$1resourcewithsourceandindex = map1.get(resourcelocation);
IoSupplier<ResourceMetadata> iosupplier;
if (fallbackresourcemanager$1resourcewithsourceandindex != null
&& fallbackresourcemanager$1resourcewithsourceandindex.packIndex >= p_248259_.packIndex) {
iosupplier = convertToMetadata(fallbackresourcemanager$1resourcewithsourceandindex.resource);
} else {
iosupplier = ResourceMetadata.EMPTY_SUPPLIER;
}
map2.put(p_248258_, createResource(p_248259_.packResources, p_248258_, p_248259_.resource, iosupplier));
}
);
return map2;
}
private IoSupplier<ResourceMetadata> createStackMetadataFinder(ResourceLocation p_215369_, int p_215370_) {
return () -> {
ResourceLocation resourcelocation = getMetadataLocation(p_215369_);
for (int i = this.fallbacks.size() - 1; i >= p_215370_; i--) {
FallbackResourceManager.PackEntry fallbackresourcemanager$packentry = this.fallbacks.get(i);
PackResources packresources = fallbackresourcemanager$packentry.resources;
if (packresources != null) {
IoSupplier<InputStream> iosupplier = packresources.getResource(this.type, resourcelocation);
if (iosupplier != null) {
return parseMetadata(iosupplier);
}
}
if (fallbackresourcemanager$packentry.isFiltered(resourcelocation)) {
break;
}
}
return ResourceMetadata.EMPTY;
};
}
private static IoSupplier<ResourceMetadata> convertToMetadata(IoSupplier<InputStream> p_250827_) {
return () -> parseMetadata(p_250827_);
}
private static ResourceMetadata parseMetadata(IoSupplier<InputStream> p_250103_) throws IOException {
ResourceMetadata resourcemetadata;
try (InputStream inputstream = p_250103_.get()) {
resourcemetadata = ResourceMetadata.fromJsonStream(inputstream);
}
return resourcemetadata;
}
private static void applyPackFiltersToExistingResources(FallbackResourceManager.PackEntry p_215393_, Map<ResourceLocation, FallbackResourceManager.EntryStack> p_215394_) {
for (FallbackResourceManager.EntryStack fallbackresourcemanager$entrystack : p_215394_.values()) {
if (p_215393_.isFiltered(fallbackresourcemanager$entrystack.fileLocation)) {
fallbackresourcemanager$entrystack.fileSources.clear();
} else if (p_215393_.isFiltered(fallbackresourcemanager$entrystack.metadataLocation())) {
fallbackresourcemanager$entrystack.metaSources.clear();
}
}
}
private void listPackResources(
FallbackResourceManager.PackEntry p_215388_,
String p_215389_,
Predicate<ResourceLocation> p_215390_,
Map<ResourceLocation, FallbackResourceManager.EntryStack> p_215391_
) {
PackResources packresources = p_215388_.resources;
if (packresources != null) {
packresources.listResources(
this.type,
this.namespace,
p_215389_,
(p_248266_, p_248267_) -> {
if (isMetadata(p_248266_)) {
ResourceLocation resourcelocation = getResourceLocationFromMetadata(p_248266_);
if (!p_215390_.test(resourcelocation)) {
return;
}
p_215391_.computeIfAbsent(resourcelocation, FallbackResourceManager.EntryStack::new).metaSources.put(packresources, p_248267_);
} else {
if (!p_215390_.test(p_248266_)) {
return;
}
p_215391_.computeIfAbsent(p_248266_, FallbackResourceManager.EntryStack::new)
.fileSources
.add(new FallbackResourceManager.ResourceWithSource(packresources, p_248267_));
}
}
);
}
}
@Override
public Map<ResourceLocation, List<Resource>> listResourceStacks(String p_215416_, Predicate<ResourceLocation> p_215417_) {
Map<ResourceLocation, FallbackResourceManager.EntryStack> map = Maps.newHashMap();
for (FallbackResourceManager.PackEntry fallbackresourcemanager$packentry : this.fallbacks) {
applyPackFiltersToExistingResources(fallbackresourcemanager$packentry, map);
this.listPackResources(fallbackresourcemanager$packentry, p_215416_, p_215417_, map);
}
TreeMap<ResourceLocation, List<Resource>> treemap = Maps.newTreeMap();
for (FallbackResourceManager.EntryStack fallbackresourcemanager$entrystack : map.values()) {
if (!fallbackresourcemanager$entrystack.fileSources.isEmpty()) {
List<Resource> list = new ArrayList<>();
for (FallbackResourceManager.ResourceWithSource fallbackresourcemanager$resourcewithsource : fallbackresourcemanager$entrystack.fileSources) {
PackResources packresources = fallbackresourcemanager$resourcewithsource.source;
IoSupplier<InputStream> iosupplier = fallbackresourcemanager$entrystack.metaSources.get(packresources);
IoSupplier<ResourceMetadata> iosupplier1 = iosupplier != null ? convertToMetadata(iosupplier) : ResourceMetadata.EMPTY_SUPPLIER;
list.add(
createResource(
packresources, fallbackresourcemanager$entrystack.fileLocation, fallbackresourcemanager$resourcewithsource.resource, iosupplier1
)
);
}
treemap.put(fallbackresourcemanager$entrystack.fileLocation, list);
}
}
return treemap;
}
@Override
public Stream<PackResources> listPacks() {
return this.fallbacks.stream().map(p_215386_ -> p_215386_.resources).filter(Objects::nonNull);
}
record EntryStack(
ResourceLocation fileLocation,
ResourceLocation metadataLocation,
List<FallbackResourceManager.ResourceWithSource> fileSources,
Map<PackResources, IoSupplier<InputStream>> metaSources
) {
EntryStack(ResourceLocation p_251350_) {
this(p_251350_, FallbackResourceManager.getMetadataLocation(p_251350_), new ArrayList<>(), new Object2ObjectArrayMap<>());
}
}
static class LeakedResourceWarningInputStream extends FilterInputStream {
private final Supplier<String> message;
private boolean closed;
public LeakedResourceWarningInputStream(InputStream p_10633_, ResourceLocation p_10634_, String p_10635_) {
super(p_10633_);
Exception exception = new Exception("Stacktrace");
this.message = () -> {
StringWriter stringwriter = new StringWriter();
exception.printStackTrace(new PrintWriter(stringwriter));
return "Leaked resource: '" + p_10634_ + "' loaded from pack: '" + p_10635_ + "'\n" + stringwriter;
};
}
@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();
}
}
record PackEntry(String name, @Nullable PackResources resources, @Nullable Predicate<ResourceLocation> filter) {
public void filterAll(Collection<ResourceLocation> p_215443_) {
if (this.filter != null) {
p_215443_.removeIf(this.filter);
}
}
public boolean isFiltered(ResourceLocation p_215441_) {
return this.filter != null && this.filter.test(p_215441_);
}
}
record ResourceWithSource(PackResources source, IoSupplier<InputStream> resource) {
}
}