From 8c3df594132650ffbed1c2c1f86439629df9bf6a Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 25 Jul 2024 21:05:16 +0200 Subject: [PATCH] fix: improve schematic format selection (#2838) - no longer allow selecting a format specifically because of the generic extension `.schem` --- .../worldedit/command/SchematicCommands.java | 12 ++--- .../clipboard/io/BuiltInClipboardFormat.java | 45 +++++++++++++++++++ .../extent/clipboard/io/ClipboardFormat.java | 7 +++ .../extent/clipboard/io/ClipboardFormats.java | 43 +++++++++++++++++- .../src/main/resources/lang/strings.json | 1 + 5 files changed, 101 insertions(+), 7 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 8a7751bd4..e6a369502 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -376,11 +376,13 @@ public class SchematicCommands { actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.load.other")); return; } - if (noExplicitFormat && filename.matches(".*\\.[\\w].*")) { - format = ClipboardFormats - .findByExtension(filename.substring(filename.lastIndexOf('.') + 1)); - } else { + if (!noExplicitFormat) { format = ClipboardFormats.findByAlias(formatName); + } else if (filename.matches(".*\\.[\\w].*")) { + format = ClipboardFormats + .findByExplicitExtension(filename.substring(filename.lastIndexOf('.') + 1)); + } else { + format = null; } file = MainUtil.resolve(dir, filename, format, false); } @@ -396,7 +398,7 @@ public class SchematicCommands { .isInSubDirectory(saveDir, file)) + ")")); return; } - if (format == null || noExplicitFormat) { + if (format == null) { format = ClipboardFormats.findByFile(file); if (format == null) { actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index bfd6b2029..a26e7c99a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -50,6 +50,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Collections; import java.util.Locale; import java.util.Set; import java.util.zip.GZIPInputStream; @@ -125,6 +126,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public String getPrimaryFileExtension() { return "schem"; } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("schem3", "sponge3", "fast3"); + } }, FAST_V2("fast.2", "fawe.2", "schem.2") { @Override @@ -168,6 +174,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } return super.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("schem2", "sponge2", "fast2"); + } }, //FAWE end @@ -217,6 +228,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } return rootEntry.value().value().containsKey("Materials"); } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("mcedit", "schem1", "sponge1", "fast1"); + } }, SPONGE_V1_SCHEMATIC("sponge.1") { @Override @@ -243,6 +259,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(File file) { return MCEDIT_SCHEMATIC.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, /** @@ -277,6 +298,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(File file) { return FAST_V2.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, SPONGE_V3_SCHEMATIC("sponge.3", "slow", "safe") { // FAWE - edit aliases for fast @@ -301,6 +327,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { return FAST_V3.isFormat(file); //FAWE end } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, //FAWE start - recover schematics with bad entity data & register other clipboard formats BROKENENTITY("brokenentity", "legacyentity", "le", "be", "brokenentities", "legacyentities") { @@ -341,6 +372,10 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { return false; } + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, /** @@ -401,6 +436,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(final File file) { return file.getName().toLowerCase(Locale.ROOT).endsWith(".nbt") && super.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("nbt"); + } }, /** @@ -427,6 +467,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public String getPrimaryFileExtension() { return "png"; } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("png"); + } }; //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java index 7b4b1bf3b..cb1b97e2a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -124,6 +124,13 @@ public interface ClipboardFormat { //FAWE start + /** + * Get the explicit file extensions (e.g. .schem2) this format is commonly known to use. + * + * @return The explicit file extensions this format might be known by + */ + Set getExplicitFileExtensions(); + /** * Sets the actor's clipboard. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index b69a7a0cc..786af54fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -66,6 +66,7 @@ public class ClipboardFormats { private static final Map aliasMap = new HashMap<>(); // FAWE start - keep order of ClipboardFormat entries -> prefer FAST over SPONGE_SCHEMATIC private static final Multimap fileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new); + private static final Multimap explicitFileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new); // FAWE end private static final List registeredFormats = new ArrayList<>(); @@ -86,6 +87,10 @@ public class ClipboardFormats { String lowExt = ext.toLowerCase(Locale.ROOT); fileExtensionMap.put(lowExt, format); } + for (String ext : format.getExplicitFileExtensions()) { + String lowExt = ext.toLowerCase(Locale.ROOT); + explicitFileExtensionMap.put(lowExt, format); + } registeredFormats.add(format); } @@ -147,6 +152,18 @@ public class ClipboardFormats { return fileExtensionMap.keySet().toArray(new String[fileExtensionMap.keySet().size()]); } + //FAWE start + + /** + * A mapping from explicit extensions (e.g. .schem2) to formats. + * + * @return a multimap from a file extension to the potential matching formats. + */ + public static Multimap getExplicitFileExtensionMap() { + return Multimaps.unmodifiableMultimap(explicitFileExtensionMap); + } + //FAWE end + private ClipboardFormats() { } @@ -157,8 +174,10 @@ public class ClipboardFormats { * * @param extension the extension * @return the format, otherwise null if one cannot be detected + * @deprecated DO NOT USE. Sponge formats 2 and 3 both use .schem by default. */ @Nullable + @Deprecated(forRemoval = true, since = "TODO") public static ClipboardFormat findByExtension(String extension) { checkNotNull(extension); @@ -172,6 +191,26 @@ public class ClipboardFormats { } + /** + * Detect the format given an explicit extension, e.g. ".schem2" + * + * @param extension the extension + * @return the format, otherwise null if one cannot be detected + */ + @Nullable + public static ClipboardFormat findByExplicitExtension(String extension) { + checkNotNull(extension); + + Collection> entries = getExplicitFileExtensionMap().entries(); + for (Map.Entry entry : entries) { + if (entry.getKey().equalsIgnoreCase(extension)) { + return entry.getValue(); + } + } + return null; + + } + public static MultiClipboardHolder loadAllFromInput( Actor player, String input, @@ -231,7 +270,7 @@ public class ClipboardFormats { } if (format == null && input.matches(".*\\.[\\w].*")) { String extension = input.substring(input.lastIndexOf('.') + 1); - format = findByExtension(extension); + format = findByExplicitExtension(extension); } f = MainUtil.resolve(dir, input, format, true); } @@ -302,7 +341,7 @@ public class ClipboardFormats { byte[] buffer = new byte[8192]; while ((entry = zip.getNextEntry()) != null) { String filename = entry.getName(); - ClipboardFormat format = findByExtension(filename); + ClipboardFormat format = findByExtension(filename); // FIXME if (format != null) { FastByteArrayOutputStream out = new FastByteArrayOutputStream(); int len; diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 16e10a00d..7d49114b5 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -68,6 +68,7 @@ "fawe.worldedit.schematic.schematic.loaded": "{0} loaded. Paste it with //paste", "fawe.worldedit.schematic.schematic.saved": "{0} saved.", "fawe.worldedit.schematic.schematic.none": "No files found.", + "fawe.worldedit.schematic.schematic.load-failure": "File could not be read or it does not exist: {0}. If you are specifying a format, you may not be specifying the correct one. Sponge schematic v2 and v3 both use the .schem file extension. To allow FAWE to select the format, do not specify one.", "fawe.worldedit.clipboard.clipboard.uri.not.found": "You do not have {0} loaded", "fawe.worldedit.clipboard.clipboard.cleared": "Clipboard cleared", "fawe.worldedit.clipboard.clipboard.invalid.format": "Unknown clipboard format: {0}",