From 7383c74fcc78a94fad40ba63cb3cef22457a68a2 Mon Sep 17 00:00:00 2001 From: YouHaveTrouble Date: Mon, 19 May 2025 20:52:02 +0200 Subject: [PATCH] expanded the schematic api draft --- .../blockedit/SchematicHandler.java | 92 ++++++++++++++----- .../exception/SchematicException.java | 25 +++++ ...SchematicHandlerRegistrationException.java | 24 +++++ .../exception/SchematicLoadException.java | 13 ++- .../exception/SchematicSaveException.java | 14 +++ .../schematic/FileSchematicProvider.java | 12 +++ .../schematic/SchematicProvider.java | 5 +- .../blockedit/util/NameFilenameFilter.java | 25 +++++ 8 files changed, 179 insertions(+), 31 deletions(-) create mode 100644 src/main/java/me/youhavetrouble/blockedit/exception/SchematicException.java create mode 100644 src/main/java/me/youhavetrouble/blockedit/exception/SchematicHandlerRegistrationException.java create mode 100644 src/main/java/me/youhavetrouble/blockedit/exception/SchematicSaveException.java create mode 100644 src/main/java/me/youhavetrouble/blockedit/schematic/FileSchematicProvider.java create mode 100644 src/main/java/me/youhavetrouble/blockedit/util/NameFilenameFilter.java diff --git a/src/main/java/me/youhavetrouble/blockedit/SchematicHandler.java b/src/main/java/me/youhavetrouble/blockedit/SchematicHandler.java index 9243866..f1fd44e 100644 --- a/src/main/java/me/youhavetrouble/blockedit/SchematicHandler.java +++ b/src/main/java/me/youhavetrouble/blockedit/SchematicHandler.java @@ -1,8 +1,13 @@ package me.youhavetrouble.blockedit; +import me.youhavetrouble.blockedit.exception.SchematicHandlerRegistrationException; +import me.youhavetrouble.blockedit.exception.SchematicLoadException; +import me.youhavetrouble.blockedit.exception.SchematicSaveException; +import me.youhavetrouble.blockedit.schematic.FileSchematicProvider; import me.youhavetrouble.blockedit.schematic.Schematic; import me.youhavetrouble.blockedit.schematic.SchematicProvider; import me.youhavetrouble.blockedit.util.Clipboard; +import me.youhavetrouble.blockedit.util.NameFilenameFilter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,7 +22,7 @@ public class SchematicHandler { private final Map> schematicProvidersByExtension = new HashMap<>(); private final Map> schematicProvidersByName = new HashMap<>(); - private final File schematicsDirectory; + public final File schematicsDirectory; protected SchematicHandler(BlockEdit plugin) { this.plugin = plugin; @@ -35,40 +40,53 @@ public class SchematicHandler { public void registerSchematicProvider( @NotNull SchematicProvider schematicProvider - ) throws IllegalArgumentException { - if (!schematicProvider.name().matches("^[a-z0-9]+$")) { - throw new IllegalArgumentException("Schematic provider name can only contain lowercase letters and numbers"); + ) throws SchematicHandlerRegistrationException { + + String schematicProviderName = schematicProvider.name().trim(); + + if (!schematicProviderName.matches("^[a-z0-9]+$")) { + throw new SchematicHandlerRegistrationException("Schematic provider name can only contain lowercase letters and numbers", schematicProvider); } - if (schematicProvidersByName.containsKey(schematicProvider.name())) { - throw new IllegalArgumentException("Schematic provider " + schematicProvider.name() + " is already registered"); + if (schematicProvidersByName.containsKey(schematicProviderName)) { + throw new SchematicHandlerRegistrationException("Schematic provider with name " + schematicProvider.name() + " is already registered", schematicProvider); } - // Loop extensions to verify if they're valid and not already registered - for (String extension : schematicProvider.fileExtensions()) { - String trimmedExtension = extension.trim(); - if (trimmedExtension.isEmpty()) throw new IllegalArgumentException("File extension cannot be empty"); - if (!trimmedExtension.matches("^[a-z0-9]+$")) throw new IllegalArgumentException("File extension can only contain lowercase letters and numbers"); - if (schematicProvidersByExtension.containsKey(trimmedExtension)) { - throw new IllegalArgumentException("File extension " + trimmedExtension + " is already registered to " + schematicProvidersByExtension.get(trimmedExtension).name()); + // Register the provider as a file provider that associates the provider with file extensions + if (schematicProvider instanceof FileSchematicProvider fileSchematicProvider) { + // Loop extensions to verify if they're valid and not already registered + for (String extension : fileSchematicProvider.fileExtensions()) { + String trimmedExtension = extension.trim(); + if (trimmedExtension.isEmpty()) throw new SchematicHandlerRegistrationException("File extension cannot be empty", fileSchematicProvider); + if (!trimmedExtension.matches("^[a-z0-9]+$")) throw new SchematicHandlerRegistrationException("File extension can only contain lowercase letters and numbers", fileSchematicProvider); + if (schematicProvidersByExtension.containsKey(trimmedExtension)) { + throw new SchematicHandlerRegistrationException("File extension " + trimmedExtension + " is already registered to " + schematicProvidersByExtension.get(trimmedExtension).name(), fileSchematicProvider); + } } + // Loop again to actually register the extensions + for (String extension : fileSchematicProvider.fileExtensions()) { + String trimmedExtension = extension.trim(); + schematicProvidersByExtension.put(trimmedExtension, schematicProvider); + } + return; } - // Loop again to actually register the extensions - for (String extension : schematicProvider.fileExtensions()) { - String trimmedExtension = extension.trim(); - schematicProvidersByExtension.put(trimmedExtension, schematicProvider); - } schematicProvidersByName.put(schematicProvider.name(), schematicProvider); } /** - * Loads a schematic from the schematics directory + * Loads a schematic from the schematic provider * @param providerName Schematic provider to use * @param schematicName Name of the schematic * @return Clipboard object containing the schematic. Null if schematic does not exist or could not be loaded. */ - public @Nullable Schematic loadSchematic(String providerName, @NotNull String schematicName) { + public @Nullable Schematic loadSchematic(@NotNull String providerName, @NotNull String schematicName) { + + // file provider is a special case here + if (providerName.equals("file")) { + return loadSchematic(schematicName); + } + SchematicProvider schematicProvider = schematicProvidersByName.get(providerName); if (schematicProvider == null) { throw new IllegalArgumentException("Schematic provider " + providerName + " is not registered"); @@ -76,6 +94,34 @@ public class SchematicHandler { return schematicProvider.load(schematicName); } + /** + * Loads a schematic from the schematic directory. File schematic provider will be matched by the file extenstion + * @param schematicName File name without extension + * @return Schematic object + */ + public @Nullable Schematic loadSchematic(@NotNull String schematicName) throws SchematicLoadException { + File[] files; + try { + files = this.schematicsDirectory.listFiles(new NameFilenameFilter(schematicName)); + if (files == null || files.length == 0) return null; + } catch (SecurityException e) { + throw new SchematicLoadException("Could not list schematics directory", schematicName, e); + } + + File schematicFile = files[0]; + String fileName = schematicFile.getName(); + String fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1); + SchematicProvider schematicProvider = schematicProvidersByExtension.get(fileExtension); + if (schematicProvider == null) { + throw new SchematicLoadException("No schematic provider found for file extension " + fileExtension, schematicName); + } + Schematic schematic = schematicProvider.load(schematicName); + if (schematic == null) { + throw new SchematicLoadException("Schematic could not be loaded", schematicName); + } + return schematic; + } + /** * Saves a schematic to the schematics directory * @param schematicName Name of the schematic @@ -85,15 +131,13 @@ public class SchematicHandler { @NotNull String schematicName, @NotNull String providerName, @NotNull Clipboard clipboard - ) { + ) throws SchematicSaveException { SchematicProvider schematicProvider = schematicProvidersByName.get(providerName); if (schematicProvider == null) { - throw new IllegalArgumentException("Schematic provider " + providerName + " is not registered"); + throw new SchematicSaveException("Schematic provider " + providerName + " is not registered", schematicName); } S schematic = schematicProvider.fromClipboard(schematicName, clipboard); - schematicProvider.save(schematic); - } } diff --git a/src/main/java/me/youhavetrouble/blockedit/exception/SchematicException.java b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicException.java new file mode 100644 index 0000000..bd14614 --- /dev/null +++ b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicException.java @@ -0,0 +1,25 @@ +package me.youhavetrouble.blockedit.exception; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SchematicException extends RuntimeException { + + private final String schematicName; + + public SchematicException(@NotNull String message, @Nullable String schematicName, Throwable cause) { + super(message); + this.schematicName = schematicName; + initCause(cause); + } + + public SchematicException(@NotNull String message, @Nullable String schematicName) { + super(message); + this.schematicName = schematicName; + } + + public String getSchematicName() { + return schematicName; + } + +} diff --git a/src/main/java/me/youhavetrouble/blockedit/exception/SchematicHandlerRegistrationException.java b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicHandlerRegistrationException.java new file mode 100644 index 0000000..bbadb0d --- /dev/null +++ b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicHandlerRegistrationException.java @@ -0,0 +1,24 @@ +package me.youhavetrouble.blockedit.exception; + +import me.youhavetrouble.blockedit.schematic.SchematicProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SchematicHandlerRegistrationException extends IllegalArgumentException { + + private final SchematicProvider schematicProvider; + + public SchematicHandlerRegistrationException( + @NotNull String message, + @Nullable SchematicProvider schematicProvider + ) { + super(message); + this.schematicProvider = schematicProvider; + } + + @Nullable + public SchematicProvider getSchematicProvider() { + return schematicProvider; + } + +} diff --git a/src/main/java/me/youhavetrouble/blockedit/exception/SchematicLoadException.java b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicLoadException.java index a837c2a..26aeb4d 100644 --- a/src/main/java/me/youhavetrouble/blockedit/exception/SchematicLoadException.java +++ b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicLoadException.java @@ -1,9 +1,16 @@ package me.youhavetrouble.blockedit.exception; -public class SchematicLoadException extends RuntimeException { +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; - public SchematicLoadException(String message) { - super(message); +public class SchematicLoadException extends SchematicException { + + public SchematicLoadException(@NotNull String message, @NotNull String schematicName, @Nullable Throwable cause) { + super(message, schematicName, cause); + } + + public SchematicLoadException(@NotNull String message, @NotNull String schematicName) { + super(message, schematicName); } } diff --git a/src/main/java/me/youhavetrouble/blockedit/exception/SchematicSaveException.java b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicSaveException.java new file mode 100644 index 0000000..d618851 --- /dev/null +++ b/src/main/java/me/youhavetrouble/blockedit/exception/SchematicSaveException.java @@ -0,0 +1,14 @@ +package me.youhavetrouble.blockedit.exception; + +import org.jetbrains.annotations.NotNull; + +public class SchematicSaveException extends SchematicException { + + public SchematicSaveException(@NotNull String message, @NotNull String schematicName, Throwable cause) { + super(message, schematicName, cause); + } + + public SchematicSaveException(@NotNull String message, @NotNull String schematicName) { + super(message, schematicName); + } +} diff --git a/src/main/java/me/youhavetrouble/blockedit/schematic/FileSchematicProvider.java b/src/main/java/me/youhavetrouble/blockedit/schematic/FileSchematicProvider.java new file mode 100644 index 0000000..7b18606 --- /dev/null +++ b/src/main/java/me/youhavetrouble/blockedit/schematic/FileSchematicProvider.java @@ -0,0 +1,12 @@ +package me.youhavetrouble.blockedit.schematic; + +import org.jetbrains.annotations.NotNull; + +public interface FileSchematicProvider extends SchematicProvider { + + /** + * Get the file extensions of the schematic provider. + */ + @NotNull String[] fileExtensions(); + +} diff --git a/src/main/java/me/youhavetrouble/blockedit/schematic/SchematicProvider.java b/src/main/java/me/youhavetrouble/blockedit/schematic/SchematicProvider.java index d25ab2b..ee1b1f6 100644 --- a/src/main/java/me/youhavetrouble/blockedit/schematic/SchematicProvider.java +++ b/src/main/java/me/youhavetrouble/blockedit/schematic/SchematicProvider.java @@ -15,10 +15,7 @@ public interface SchematicProvider { */ @NotNull String name(); - /** - * Get the file extensions of the schematic provider. - */ - @NotNull String[] fileExtensions(); + /** * Save the schematic diff --git a/src/main/java/me/youhavetrouble/blockedit/util/NameFilenameFilter.java b/src/main/java/me/youhavetrouble/blockedit/util/NameFilenameFilter.java new file mode 100644 index 0000000..d2b2367 --- /dev/null +++ b/src/main/java/me/youhavetrouble/blockedit/util/NameFilenameFilter.java @@ -0,0 +1,25 @@ +package me.youhavetrouble.blockedit.util; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.List; + +public class NameFilenameFilter implements FilenameFilter { + + private final String filterName; + + public NameFilenameFilter(@NotNull String name) { + this.filterName = name; + } + + @Override + public boolean accept(File dir, String name) { + + String[] parts = name.split("\\."); + if (parts.length < 2) return filterName.equals(name); + String joined = String.join(".", List.of(parts).subList(0, parts.length - 1)); + return joined.equals(filterName); + } +}