211 lines
8.3 KiB
Java
211 lines
8.3 KiB
Java
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.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;
|
|
|
|
@Nonnull
|
|
@Override
|
|
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();
|
|
|
|
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();
|
|
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)) {
|
|
return entries;
|
|
} else {
|
|
try (DirectoryStream<Path> stream = Files.newDirectoryStream(targetPath)) {
|
|
for (Path file : stream) {
|
|
String fileName = file.getFileName().toString();
|
|
if (!fileName.startsWith(".")) {
|
|
boolean isDirectory = Files.isDirectory(file);
|
|
if (isDirectory || fileName.endsWith(".prefab.json")) {
|
|
String displayName = isDirectory ? fileName : this.removeExtension(fileName);
|
|
entries.add(new FileListProvider.FileEntry(fileName, displayName, isDirectory));
|
|
}
|
|
}
|
|
}
|
|
} 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<AssetPrefabFileProvider.SearchResult> allResults = new ObjectArrayList();
|
|
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(AssetPrefabFileProvider.SearchResult::score).reversed());
|
|
List<FileListProvider.FileEntry> entries = new ObjectArrayList();
|
|
|
|
for (int i = 0; i < Math.min(allResults.size(), 50); i++) {
|
|
AssetPrefabFileProvider.SearchResult result = 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<AssetPrefabFileProvider.SearchResult> results
|
|
) {
|
|
if (Files.isDirectory(root)) {
|
|
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 AssetPrefabFileProvider.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 record SearchResult(@Nonnull String relativePath, @Nonnull String displayName, int score) {
|
|
}
|
|
}
|