package com.hypixel.hytale.builtin.buildertools.prefablist;
import com.hypixel.hytale.common.util.StringCompareUtil;
import com.hypixel.hytale.server.core.prefab.PrefabStore;
import com.hypixel.hytale.server.core.ui.browser.FileListProvider;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetPrefabFileProvider implements FileListProvider {
private static final String PREFAB_EXTENSION = ".prefab.json";
private static final int MAX_SEARCH_RESULTS = 50;
public AssetPrefabFileProvider() {
}
@Nonnull
public List<FileListProvider.FileEntry> getFiles(@Nonnull Path currentDir, @Nonnull String searchQuery) {
String currentDirStr = currentDir.toString().replace('\\', '/');
if (!searchQuery.isEmpty()) {
return this.buildSearchResults(currentDirStr, searchQuery);
} else {
return currentDirStr.isEmpty() ? this.buildPackListings() : this.buildPackDirectoryListing(currentDirStr);
}
}
@Nonnull
private List<FileListProvider.FileEntry> buildPackListings() {
List<FileListProvider.FileEntry> entries = new ObjectArrayList<FileListProvider.FileEntry>();
for(PrefabStore.AssetPackPrefabPath packPath : PrefabStore.get().getAllAssetPrefabPaths()) {
String displayName = packPath.getDisplayName();
String packKey = this.getPackKey(packPath);
entries.add(new FileListProvider.FileEntry(packKey, displayName, true));
}
entries.sort(Comparator.comparing(FileListProvider.FileEntry::displayName, String.CASE_INSENSITIVE_ORDER));
return entries;
}
@Nonnull
private List<FileListProvider.FileEntry> buildPackDirectoryListing(@Nonnull String currentDirStr) {
List<FileListProvider.FileEntry> entries = new ObjectArrayList<FileListProvider.FileEntry>();
String[] parts = currentDirStr.split("/", 2);
String packKey = parts[0];
String subPath = parts.length > 1 ? parts[1] : "";
PrefabStore.AssetPackPrefabPath packPath = this.findPackByKey(packKey);
if (packPath == null) {
return entries;
} else {
Path targetPath = packPath.prefabsPath();
if (!subPath.isEmpty()) {
targetPath = targetPath.resolve(subPath);
}
if (!Files.isDirectory(targetPath, new LinkOption[0])) {
return entries;
} else {
try {
DirectoryStream<Path> stream = Files.newDirectoryStream(targetPath);
try {
for(Path file : stream) {
String fileName = file.getFileName().toString();
if (!fileName.startsWith(".")) {
boolean isDirectory = Files.isDirectory(file, new LinkOption[0]);
if (isDirectory || fileName.endsWith(".prefab.json")) {
String displayName = isDirectory ? fileName : this.removeExtension(fileName);
entries.add(new FileListProvider.FileEntry(fileName, displayName, isDirectory));
}
}
}
} catch (Throwable var15) {
if (stream != null) {
try {
stream.close();
} catch (Throwable var14) {
var15.addSuppressed(var14);
}
}
throw var15;
}
if (stream != null) {
stream.close();
}
} catch (IOException var16) {
}
entries.sort((a, b) -> {
if (a.isDirectory() == b.isDirectory()) {
return a.displayName().compareToIgnoreCase(b.displayName());
} else {
return a.isDirectory() ? -1 : 1;
}
});
return entries;
}
}
}
@Nonnull
private List<FileListProvider.FileEntry> buildSearchResults(@Nonnull String currentDirStr, @Nonnull String searchQuery) {
List<SearchResult> allResults = new ObjectArrayList<SearchResult>();
String lowerQuery = searchQuery.toLowerCase();
if (currentDirStr.isEmpty()) {
for(PrefabStore.AssetPackPrefabPath packPath : PrefabStore.get().getAllAssetPrefabPaths()) {
String packKey = this.getPackKey(packPath);
this.searchInDirectory(packPath.prefabsPath(), packKey, "", lowerQuery, allResults);
}
} else {
String[] parts = currentDirStr.split("/", 2);
String packKey = parts[0];
String subPath = parts.length > 1 ? parts[1] : "";
PrefabStore.AssetPackPrefabPath packPath = this.findPackByKey(packKey);
if (packPath != null) {
Path searchRoot = packPath.prefabsPath();
if (!subPath.isEmpty()) {
searchRoot = searchRoot.resolve(subPath);
}
this.searchInDirectory(searchRoot, packKey, subPath, lowerQuery, allResults);
}
}
allResults.sort(Comparator.comparingInt(SearchResult::score).reversed());
List<FileListProvider.FileEntry> entries = new ObjectArrayList<FileListProvider.FileEntry>();
for(int i = 0; i < Math.min(allResults.size(), 50); ++i) {
SearchResult result = (SearchResult)allResults.get(i);
entries.add(new FileListProvider.FileEntry(result.relativePath(), result.displayName(), false, result.score()));
}
return entries;
}
private void searchInDirectory(@Nonnull final Path root, @Nonnull final String packKey, @Nonnull final String basePath, @Nonnull final String searchQuery, @Nonnull final List<SearchResult> results) {
if (Files.isDirectory(root, new LinkOption[0])) {
try {
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Nonnull
public FileVisitResult visitFile(@Nonnull Path file, @Nonnull BasicFileAttributes attrs) {
String fileName = file.getFileName().toString();
if (fileName.endsWith(".prefab.json")) {
String baseName = AssetPrefabFileProvider.this.removeExtension(fileName);
int score = StringCompareUtil.getFuzzyDistance(baseName.toLowerCase(), searchQuery, Locale.ENGLISH);
if (score > 0) {
Path relativePath = root.relativize(file);
String fullRelativePath = basePath.isEmpty() ? packKey + "/" + relativePath.toString().replace('\\', '/') : packKey + "/" + basePath + "/" + relativePath.toString().replace('\\', '/');
results.add(new SearchResult(fullRelativePath, baseName, score));
}
}
return FileVisitResult.CONTINUE;
}
});
} catch (IOException var7) {
}
}
}
@Nonnull
private String getPackKey(@Nonnull PrefabStore.AssetPackPrefabPath packPath) {
return packPath.getDisplayName();
}
@Nullable
private PrefabStore.AssetPackPrefabPath findPackByKey(@Nonnull String packKey) {
for(PrefabStore.AssetPackPrefabPath packPath : PrefabStore.get().getAllAssetPrefabPaths()) {
if (this.getPackKey(packPath).equals(packKey)) {
return packPath;
}
}
return null;
}
@Nonnull
private String removeExtension(@Nonnull String fileName) {
return fileName.endsWith(".prefab.json") ? fileName.substring(0, fileName.length() - ".prefab.json".length()) : fileName;
}
@Nullable
public Path resolveVirtualPath(@Nonnull String virtualPath) {
if (virtualPath.isEmpty()) {
return null;
} else {
String[] parts = virtualPath.split("/", 2);
String packKey = parts[0];
String subPath = parts.length > 1 ? parts[1] : "";
PrefabStore.AssetPackPrefabPath packPath = this.findPackByKey(packKey);
if (packPath == null) {
return null;
} else {
return subPath.isEmpty() ? packPath.prefabsPath() : packPath.prefabsPath().resolve(subPath);
}
}
}
@Nonnull
public String getPackDisplayName(@Nonnull String packKey) {
PrefabStore.AssetPackPrefabPath packPath = this.findPackByKey(packKey);
return packPath != null ? packPath.getDisplayName() : packKey;
}
private static record SearchResult(@Nonnull String relativePath, @Nonnull String displayName, int score) {
}
}