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;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Locale;
@@ -14,32 +14,44 @@ public class BELocale {
public final String couldNotFindWandById, selectArea, copiedSelectionToClipboard, selectionReset, firstPositionSet,
secondPositionSet, pastingClipboard, clipboardRotated, settingBlocks, replacingBlocks, schematicLoaded,
startedLoadingSchematic, noProviderForSchematicFileExtension, schematicLoadError, schematicNotFound;
startedLoadingSchematic, noProviderForSchematicFileExtension, schematicLoadError, schematicNotFound,
providerNotFound;
protected BELocale(JsonObject json) {
couldNotFindWandById = json.get("could_not_find_wand_by_id").getAsString();
selectArea = json.get("select_area").getAsString();
copiedSelectionToClipboard = json.get("copied_selection_to_clipboard").getAsString();
selectionReset = json.get("selection_reset").getAsString();
firstPositionSet = json.get("first_position_set").getAsString();
secondPositionSet = json.get("second_position_set").getAsString();
pastingClipboard = json.get("pasting_clipboard").getAsString();
clipboardRotated = json.get("clipboard_rotated").getAsString();
settingBlocks = json.get("setting_blocks").getAsString();
replacingBlocks = json.get("replacing_blocks").getAsString();
startedLoadingSchematic = json.get("started_loading_schematic").getAsString();
schematicLoaded = json.get("schematic_loaded").getAsString();
noProviderForSchematicFileExtension = json.get("no_provider_for_schematic_file_extension").getAsString();
schematicLoadError = json.get("schematic_load_error").getAsString();
schematicNotFound = json.get("schematic_not_found").getAsString();
couldNotFindWandById = getString(json, "could_not_find_wand_by_id");
selectArea = getString(json, "select_area");
copiedSelectionToClipboard = getString(json, "copied_selection_to_clipboard");
selectionReset = getString(json, "selection_reset");
firstPositionSet = getString(json, "first_position_set");
secondPositionSet = getString(json, "second_position_set");
pastingClipboard = getString(json, "pasting_clipboard");
clipboardRotated = getString(json, "clipboard_rotated");
settingBlocks = getString(json, "setting_blocks");
replacingBlocks = getString(json, "replacing_blocks");
startedLoadingSchematic = getString(json, "started_loading_schematic");
schematicLoaded = getString(json, "schematic_loaded");
noProviderForSchematicFileExtension = getString(json, "no_provider_for_schematic_file_extension");
schematicLoadError = getString(json, "schematic_load_error");
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) {
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);
if (beLocale == null) beLocale = locales.get(defaultLocale);
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.types.LifecycleEvents;
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.operations.PasteOperation;
import me.youhavetrouble.blockedit.operations.ReplaceOperation;
import me.youhavetrouble.blockedit.operations.SetOperation;
import me.youhavetrouble.blockedit.schematic.Schematic;
import me.youhavetrouble.blockedit.schematic.SchematicProvider;
import me.youhavetrouble.blockedit.util.Selection;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
@@ -28,6 +29,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
@@ -85,6 +87,11 @@ public class BlockEditCommands {
"Replaces the specified block with another block"
);
commands.register(
schematicCommand(),
"Loads a schematic"
);
});
}
@@ -389,37 +396,33 @@ public class BlockEditCommands {
.requires(commandSourceStack -> {
if (!(commandSourceStack.getSender() instanceof Player player))
return false;
return player.hasPermission("blockedit.command.schematic.load.file");
return player.hasPermission("blockedit.command.schematic.load");
})
.executes(context -> {
CompletableFuture.runAsync(() -> {
Player player = (Player) context.getSource().getSender();
String schematicName = context.getArgument("schematic_name", String.class);
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).startedLoadingSchematic.formatted(schematicName), NamedTextColor.GRAY));
Schematic schematic;
try {
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) {
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) {
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicNotFound.formatted(schematicName), NamedTextColor.RED));
return;
}
BEPlayer bePlayer = BEPlayer.getByPlayer(player);
bePlayer.setClipboard(schematic.asClipboard());
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicLoaded.formatted(schematicName), NamedTextColor.GRAY));
});
Player player = (Player) context.getSource().getSender();
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;
})
)
@@ -428,4 +431,38 @@ public class BlockEditCommands {
.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));
Schematic schematic;
if (provider == null) {
try {
schematic = BlockEditAPI.getSchematicHandler().loadSchematic(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;
}
} 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) {
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicNotFound.formatted(schematicName), NamedTextColor.RED));
return;
}
BEPlayer bePlayer = BEPlayer.getByPlayer(player);
bePlayer.setClipboard(schematic.asClipboard());
player.sendMessage(Component.text(BELocale.getLocale(player.locale()).schematicLoaded.formatted(schematicName), NamedTextColor.GRAY));
});
}
}
@@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.Collection;
import java.util.HashMap;
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(
@NotNull SchematicProvider<S> schematicProvider
) 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...",
"started_loading_schematic": "Started loading 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",
"schematic_load_error": "Error loading schematic %s: %s",
"schematic_not_found": "Schematic %s not found"
+7 -1
View File
@@ -8,5 +8,11 @@
"pasting_clipboard": "Wklejanie ze schowka...",
"clipboard_rotated": "Schowek obrócony o %s stopni",
"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"
}