proper argument aprsing and completion for registered providers

This commit is contained in:
2025-05-22 19:49:48 +02:00
parent 9408b3cb56
commit 7aee826e64
7 changed files with 180 additions and 49 deletions
@@ -1,7 +1,7 @@
package me.youhavetrouble.blockedit; package me.youhavetrouble.blockedit;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
@@ -14,32 +14,44 @@ public class BELocale {
public final String couldNotFindWandById, selectArea, copiedSelectionToClipboard, selectionReset, firstPositionSet, public final String couldNotFindWandById, selectArea, copiedSelectionToClipboard, selectionReset, firstPositionSet,
secondPositionSet, pastingClipboard, clipboardRotated, settingBlocks, replacingBlocks, schematicLoaded, secondPositionSet, pastingClipboard, clipboardRotated, settingBlocks, replacingBlocks, schematicLoaded,
startedLoadingSchematic, noProviderForSchematicFileExtension, schematicLoadError, schematicNotFound; startedLoadingSchematic, noProviderForSchematicFileExtension, schematicLoadError, schematicNotFound,
providerNotFound;
protected BELocale(JsonObject json) { protected BELocale(JsonObject json) {
couldNotFindWandById = json.get("could_not_find_wand_by_id").getAsString(); couldNotFindWandById = getString(json, "could_not_find_wand_by_id");
selectArea = json.get("select_area").getAsString(); selectArea = getString(json, "select_area");
copiedSelectionToClipboard = json.get("copied_selection_to_clipboard").getAsString(); copiedSelectionToClipboard = getString(json, "copied_selection_to_clipboard");
selectionReset = json.get("selection_reset").getAsString(); selectionReset = getString(json, "selection_reset");
firstPositionSet = json.get("first_position_set").getAsString(); firstPositionSet = getString(json, "first_position_set");
secondPositionSet = json.get("second_position_set").getAsString(); secondPositionSet = getString(json, "second_position_set");
pastingClipboard = json.get("pasting_clipboard").getAsString(); pastingClipboard = getString(json, "pasting_clipboard");
clipboardRotated = json.get("clipboard_rotated").getAsString(); clipboardRotated = getString(json, "clipboard_rotated");
settingBlocks = json.get("setting_blocks").getAsString(); settingBlocks = getString(json, "setting_blocks");
replacingBlocks = json.get("replacing_blocks").getAsString(); replacingBlocks = getString(json, "replacing_blocks");
startedLoadingSchematic = json.get("started_loading_schematic").getAsString(); startedLoadingSchematic = getString(json, "started_loading_schematic");
schematicLoaded = json.get("schematic_loaded").getAsString(); schematicLoaded = getString(json, "schematic_loaded");
noProviderForSchematicFileExtension = json.get("no_provider_for_schematic_file_extension").getAsString(); noProviderForSchematicFileExtension = getString(json, "no_provider_for_schematic_file_extension");
schematicLoadError = json.get("schematic_load_error").getAsString(); schematicLoadError = getString(json, "schematic_load_error");
schematicNotFound = json.get("schematic_not_found").getAsString(); schematicNotFound = getString(json, "schematic_not_found");
providerNotFound = getString(json, "provider_not_found");
}
@Nullable
private String getString(JsonObject jsonObject, String key) {
if (jsonObject.has(key)) {
return jsonObject.get(key).getAsString();
} else {
return null;
}
} }
protected static void registerLocale(Locale locale, BELocale blockEditLocale) { protected static void registerLocale(Locale locale, BELocale blockEditLocale) {
locales.put(locale, blockEditLocale); locales.put(locale, blockEditLocale);
} }
public static BELocale getLocale(@NotNull Locale locale) { public static BELocale getLocale(@Nullable Locale locale) {
if (locale == null) return locales.get(defaultLocale);
BELocale beLocale = locales.get(locale); BELocale beLocale = locales.get(locale);
if (beLocale == null) beLocale = locales.get(defaultLocale); if (beLocale == null) beLocale = locales.get(defaultLocale);
return beLocale; return beLocale;
@@ -12,12 +12,13 @@ import io.papermc.paper.command.brigadier.argument.resolvers.BlockPositionResolv
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import me.youhavetrouble.blockedit.api.BlockEditAPI; import me.youhavetrouble.blockedit.api.BlockEditAPI;
import me.youhavetrouble.blockedit.exception.NoProviderForSchematicFileExtensionException; import me.youhavetrouble.blockedit.commands.arguments.SchematicProviderArgument;
import me.youhavetrouble.blockedit.exception.SchematicLoadException; import me.youhavetrouble.blockedit.exception.SchematicLoadException;
import me.youhavetrouble.blockedit.operations.PasteOperation; import me.youhavetrouble.blockedit.operations.PasteOperation;
import me.youhavetrouble.blockedit.operations.ReplaceOperation; import me.youhavetrouble.blockedit.operations.ReplaceOperation;
import me.youhavetrouble.blockedit.operations.SetOperation; import me.youhavetrouble.blockedit.operations.SetOperation;
import me.youhavetrouble.blockedit.schematic.Schematic; import me.youhavetrouble.blockedit.schematic.Schematic;
import me.youhavetrouble.blockedit.schematic.SchematicProvider;
import me.youhavetrouble.blockedit.util.Selection; import me.youhavetrouble.blockedit.util.Selection;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@@ -28,6 +29,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -85,6 +87,11 @@ public class BlockEditCommands {
"Replaces the specified block with another block" "Replaces the specified block with another block"
); );
commands.register(
schematicCommand(),
"Loads a schematic"
);
}); });
} }
@@ -389,26 +396,63 @@ public class BlockEditCommands {
.requires(commandSourceStack -> { .requires(commandSourceStack -> {
if (!(commandSourceStack.getSender() instanceof Player player)) if (!(commandSourceStack.getSender() instanceof Player player))
return false; return false;
return player.hasPermission("blockedit.command.schematic.load.file"); return player.hasPermission("blockedit.command.schematic.load");
}) })
.executes(context -> { .executes(context -> {
CompletableFuture.runAsync(() -> {
Player player = (Player) context.getSource().getSender(); Player player = (Player) context.getSource().getSender();
String schematicName = context.getArgument("schematic_name", String.class); loadSchematic(
player,
null, // file provider
context.getArgument("schematic_name", String.class)
);
return Command.SINGLE_SUCCESS;
})
)
)
.then(Commands.argument("provider_name", new SchematicProviderArgument(BlockEdit.getSchematicHandler()))
.then(Commands.argument("schematic_name", StringArgumentType.word())
.requires(commandSourceStack -> {
if (!(commandSourceStack.getSender() instanceof Player player))
return false;
return player.hasPermission("blockedit.command.schematic.load");
})
.executes(context -> {
Player player = (Player) context.getSource().getSender();
loadSchematic(
player,
context.getArgument("provider_name", SchematicProvider.class),
context.getArgument("schematic_name", String.class)
);
return Command.SINGLE_SUCCESS;
})
)
)
)
.build();
}
private static void loadSchematic(@NotNull Player player, @Nullable SchematicProvider<?> provider, @NotNull String schematicName) {
CompletableFuture.runAsync(() -> {
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).startedLoadingSchematic.formatted(schematicName), NamedTextColor.GRAY)); player.sendMessage(Component.text(BELocale.getLocale(player.locale()).startedLoadingSchematic.formatted(schematicName), NamedTextColor.GRAY));
Schematic schematic; Schematic schematic;
if (provider == null) {
try { try {
schematic = BlockEditAPI.getSchematicHandler().loadSchematic(schematicName); schematic = BlockEditAPI.getSchematicHandler().loadSchematic(schematicName);
} catch (NoProviderForSchematicFileExtensionException e) {
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).noProviderForSchematicFileExtension.formatted(e.getExtension()), NamedTextColor.RED));
return;
} catch (SchematicLoadException e) { } catch (SchematicLoadException e) {
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicLoadError.formatted(schematicName), NamedTextColor.RED)); player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicLoadError.formatted(schematicName), NamedTextColor.RED));
BlockEdit.getPlugin().getSLF4JLogger().error("Could not load schematic {} due to provider error ", schematicName, e); BlockEdit.getPlugin().getSLF4JLogger().error("Could not load schematic {} due to provider error ", schematicName, e);
return; return;
} }
} else {
try {
schematic = provider.load(schematicName);
} catch (SchematicLoadException e) {
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicLoadError.formatted(schematicName), NamedTextColor.RED));
BlockEdit.getPlugin().getSLF4JLogger().error("Could not load schematic {} due to provider error ", schematicName, e);
return;
}
}
if (schematic == null) { if (schematic == null) {
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicNotFound.formatted(schematicName), NamedTextColor.RED)); player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicNotFound.formatted(schematicName), NamedTextColor.RED));
@@ -419,13 +463,6 @@ public class BlockEditCommands {
bePlayer.setClipboard(schematic.asClipboard()); bePlayer.setClipboard(schematic.asClipboard());
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicLoaded.formatted(schematicName), NamedTextColor.GRAY)); player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicLoaded.formatted(schematicName), NamedTextColor.GRAY));
}); });
return Command.SINGLE_SUCCESS;
})
)
)
)
.build();
} }
} }
@@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.*; import java.io.*;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -39,6 +40,14 @@ public class SchematicHandler<S extends Schematic> {
} }
} }
public Collection<String> getSchematicProvidersList() {
return schematicProvidersByName.keySet();
}
public SchematicProvider<? extends Schematic> getSchematicProviderByName(String name) {
return schematicProvidersByName.get(name);
}
public void registerSchematicProvider( public void registerSchematicProvider(
@NotNull SchematicProvider<S> schematicProvider @NotNull SchematicProvider<S> schematicProvider
) throws SchematicHandlerRegistrationException { ) throws SchematicHandlerRegistrationException {
@@ -0,0 +1,60 @@
package me.youhavetrouble.blockedit.commands.arguments;
import com.mojang.brigadier.LiteralMessage;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import io.papermc.paper.command.brigadier.argument.CustomArgumentType;
import me.youhavetrouble.blockedit.SchematicHandler;
import me.youhavetrouble.blockedit.commands.exceptiontype.UnknownProviderExceptionType;
import me.youhavetrouble.blockedit.schematic.Schematic;
import me.youhavetrouble.blockedit.schematic.SchematicProvider;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("UnstableApiUsage")
public class SchematicProviderArgument implements CustomArgumentType<SchematicProvider<? extends Schematic>, String> {
private final SchematicHandler<?> schematicHandler;
public SchematicProviderArgument(@NotNull SchematicHandler<?> schematicHandler) {
this.schematicHandler = schematicHandler;
}
@Override
public @NotNull SchematicProvider<? extends Schematic> parse(StringReader reader) throws CommandSyntaxException {
int cursor = reader.getCursor();
String arg = reader.getString().toLowerCase(Locale.ENGLISH);
if (!this.schematicHandler.getSchematicProvidersList().contains(arg)) {
throw new CommandSyntaxException(
new UnknownProviderExceptionType(),
new LiteralMessage("Provider not found"),
arg,
cursor
);
}
return schematicHandler.getSchematicProviderByName(arg);
}
@Override
public @NotNull ArgumentType<String> getNativeType() {
return StringArgumentType.word();
}
@Override
public <S> @NotNull CompletableFuture<Suggestions> listSuggestions(@NotNull CommandContext<S> context, @NotNull SuggestionsBuilder builder) {
for (String providerName : schematicHandler.getSchematicProvidersList()) {
if (!providerName.startsWith(builder.getRemaining())) continue;
builder.suggest(providerName);
}
return builder.buildFuture();
}
}
@@ -0,0 +1,6 @@
package me.youhavetrouble.blockedit.commands.exceptiontype;
import com.mojang.brigadier.exceptions.CommandExceptionType;
public class UnknownProviderExceptionType implements CommandExceptionType {
}
+1
View File
@@ -11,6 +11,7 @@
"replacing_blocks": "Replacing blocks...", "replacing_blocks": "Replacing blocks...",
"started_loading_schematic": "Started loading schematic %s", "started_loading_schematic": "Started loading schematic %s",
"schematic_loaded": "Loaded schematic %s", "schematic_loaded": "Loaded schematic %s",
"provider_not_found": "Provider not found",
"no_provider_for_schematic_file": "No provider for schematic file type %s", "no_provider_for_schematic_file": "No provider for schematic file type %s",
"schematic_load_error": "Error loading schematic %s: %s", "schematic_load_error": "Error loading schematic %s: %s",
"schematic_not_found": "Schematic %s not found" "schematic_not_found": "Schematic %s not found"
+7 -1
View File
@@ -8,5 +8,11 @@
"pasting_clipboard": "Wklejanie ze schowka...", "pasting_clipboard": "Wklejanie ze schowka...",
"clipboard_rotated": "Schowek obrócony o %s stopni", "clipboard_rotated": "Schowek obrócony o %s stopni",
"setting_blocks": "Ustawianie bloków...", "setting_blocks": "Ustawianie bloków...",
"replacing_blocks": "Zastępowanie bloków..." "replacing_blocks": "Zastępowanie bloków...",
"started_loading_schematic": "Rozpoczęto ładowanie schematu %s",
"schematic_loaded": "Załadowano schemat %s",
"provider_not_found": "Nie znaleziono dostawcy",
"no_provider_for_schematic_file": "Nie znaleziono dostawcy dla typu pliku %s",
"schematic_load_error": "Błąd podczas ładowania schematu %s: %s",
"schematic_not_found": "Nie znaleziono schematu %s"
} }