211 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.server.packs;
 | |
| 
 | |
| import com.google.common.annotations.VisibleForTesting;
 | |
| import com.google.common.collect.Sets;
 | |
| import com.mojang.logging.LogUtils;
 | |
| import java.io.File;
 | |
| import java.io.IOException;
 | |
| import java.io.InputStream;
 | |
| import java.nio.file.Path;
 | |
| import java.util.ArrayList;
 | |
| import java.util.Enumeration;
 | |
| import java.util.List;
 | |
| import java.util.Locale;
 | |
| import java.util.Set;
 | |
| import java.util.zip.ZipEntry;
 | |
| import java.util.zip.ZipFile;
 | |
| import net.minecraft.resources.ResourceLocation;
 | |
| import net.minecraft.server.packs.repository.Pack;
 | |
| import net.minecraft.server.packs.resources.IoSupplier;
 | |
| import org.apache.commons.io.IOUtils;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| public class FilePackResources extends AbstractPackResources {
 | |
| 	static final Logger LOGGER = LogUtils.getLogger();
 | |
| 	private final FilePackResources.SharedZipFileAccess zipFileAccess;
 | |
| 	private final String prefix;
 | |
| 
 | |
| 	FilePackResources(PackLocationInfo location, FilePackResources.SharedZipFileAccess zipFileAccess, String prefix) {
 | |
| 		super(location);
 | |
| 		this.zipFileAccess = zipFileAccess;
 | |
| 		this.prefix = prefix;
 | |
| 	}
 | |
| 
 | |
| 	private static String getPathFromLocation(PackType packType, ResourceLocation location) {
 | |
| 		return String.format(Locale.ROOT, "%s/%s/%s", packType.getDirectory(), location.getNamespace(), location.getPath());
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	@Override
 | |
| 	public IoSupplier<InputStream> getRootResource(String... elements) {
 | |
| 		return this.getResource(String.join("/", elements));
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public IoSupplier<InputStream> getResource(PackType packType, ResourceLocation location) {
 | |
| 		return this.getResource(getPathFromLocation(packType, location));
 | |
| 	}
 | |
| 
 | |
| 	private String addPrefix(String resourcePath) {
 | |
| 		return this.prefix.isEmpty() ? resourcePath : this.prefix + "/" + resourcePath;
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	private IoSupplier<InputStream> getResource(String resourcePath) {
 | |
| 		ZipFile zipFile = this.zipFileAccess.getOrCreateZipFile();
 | |
| 		if (zipFile == null) {
 | |
| 			return null;
 | |
| 		} else {
 | |
| 			ZipEntry zipEntry = zipFile.getEntry(this.addPrefix(resourcePath));
 | |
| 			return zipEntry == null ? null : IoSupplier.create(zipFile, zipEntry);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public Set<String> getNamespaces(PackType type) {
 | |
| 		ZipFile zipFile = this.zipFileAccess.getOrCreateZipFile();
 | |
| 		if (zipFile == null) {
 | |
| 			return Set.of();
 | |
| 		} else {
 | |
| 			Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
 | |
| 			Set<String> set = Sets.<String>newHashSet();
 | |
| 			String string = this.addPrefix(type.getDirectory() + "/");
 | |
| 
 | |
| 			while (enumeration.hasMoreElements()) {
 | |
| 				ZipEntry zipEntry = (ZipEntry)enumeration.nextElement();
 | |
| 				String string2 = zipEntry.getName();
 | |
| 				String string3 = extractNamespace(string, string2);
 | |
| 				if (!string3.isEmpty()) {
 | |
| 					if (ResourceLocation.isValidNamespace(string3)) {
 | |
| 						set.add(string3);
 | |
| 					} else {
 | |
| 						LOGGER.warn("Non [a-z0-9_.-] character in namespace {} in pack {}, ignoring", string3, this.zipFileAccess.file);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return set;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@VisibleForTesting
 | |
| 	public static String extractNamespace(String directory, String name) {
 | |
| 		if (!name.startsWith(directory)) {
 | |
| 			return "";
 | |
| 		} else {
 | |
| 			int i = directory.length();
 | |
| 			int j = name.indexOf(47, i);
 | |
| 			return j == -1 ? name.substring(i) : name.substring(i, j);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void close() {
 | |
| 		this.zipFileAccess.close();
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void listResources(PackType packType, String namespace, String path, PackResources.ResourceOutput resourceOutput) {
 | |
| 		ZipFile zipFile = this.zipFileAccess.getOrCreateZipFile();
 | |
| 		if (zipFile != null) {
 | |
| 			Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
 | |
| 			String string = this.addPrefix(packType.getDirectory() + "/" + namespace + "/");
 | |
| 			String string2 = string + path + "/";
 | |
| 
 | |
| 			while (enumeration.hasMoreElements()) {
 | |
| 				ZipEntry zipEntry = (ZipEntry)enumeration.nextElement();
 | |
| 				if (!zipEntry.isDirectory()) {
 | |
| 					String string3 = zipEntry.getName();
 | |
| 					if (string3.startsWith(string2)) {
 | |
| 						String string4 = string3.substring(string.length());
 | |
| 						ResourceLocation resourceLocation = ResourceLocation.tryBuild(namespace, string4);
 | |
| 						if (resourceLocation != null) {
 | |
| 							resourceOutput.accept(resourceLocation, IoSupplier.create(zipFile, zipEntry));
 | |
| 						} else {
 | |
| 							LOGGER.warn("Invalid path in datapack: {}:{}, ignoring", namespace, string4);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static class FileResourcesSupplier implements Pack.ResourcesSupplier {
 | |
| 		private final File content;
 | |
| 
 | |
| 		public FileResourcesSupplier(Path content) {
 | |
| 			this(content.toFile());
 | |
| 		}
 | |
| 
 | |
| 		public FileResourcesSupplier(File content) {
 | |
| 			this.content = content;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public PackResources openPrimary(PackLocationInfo location) {
 | |
| 			FilePackResources.SharedZipFileAccess sharedZipFileAccess = new FilePackResources.SharedZipFileAccess(this.content);
 | |
| 			return new FilePackResources(location, sharedZipFileAccess, "");
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public PackResources openFull(PackLocationInfo location, Pack.Metadata metadata) {
 | |
| 			FilePackResources.SharedZipFileAccess sharedZipFileAccess = new FilePackResources.SharedZipFileAccess(this.content);
 | |
| 			PackResources packResources = new FilePackResources(location, sharedZipFileAccess, "");
 | |
| 			List<String> list = metadata.overlays();
 | |
| 			if (list.isEmpty()) {
 | |
| 				return packResources;
 | |
| 			} else {
 | |
| 				List<PackResources> list2 = new ArrayList(list.size());
 | |
| 
 | |
| 				for (String string : list) {
 | |
| 					list2.add(new FilePackResources(location, sharedZipFileAccess, string));
 | |
| 				}
 | |
| 
 | |
| 				return new CompositePackResources(packResources, list2);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	static class SharedZipFileAccess implements AutoCloseable {
 | |
| 		final File file;
 | |
| 		@Nullable
 | |
| 		private ZipFile zipFile;
 | |
| 		private boolean failedToLoad;
 | |
| 
 | |
| 		SharedZipFileAccess(File file) {
 | |
| 			this.file = file;
 | |
| 		}
 | |
| 
 | |
| 		@Nullable
 | |
| 		ZipFile getOrCreateZipFile() {
 | |
| 			if (this.failedToLoad) {
 | |
| 				return null;
 | |
| 			} else {
 | |
| 				if (this.zipFile == null) {
 | |
| 					try {
 | |
| 						this.zipFile = new ZipFile(this.file);
 | |
| 					} catch (IOException var2) {
 | |
| 						FilePackResources.LOGGER.error("Failed to open pack {}", this.file, var2);
 | |
| 						this.failedToLoad = true;
 | |
| 						return null;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				return this.zipFile;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public void close() {
 | |
| 			if (this.zipFile != null) {
 | |
| 				IOUtils.closeQuietly(this.zipFile);
 | |
| 				this.zipFile = null;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		protected void finalize() throws Throwable {
 | |
| 			this.close();
 | |
| 			super.finalize();
 | |
| 		}
 | |
| 	}
 | |
| }
 |