diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/CheckItemExpansion.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/CheckItemExpansion.java index 5404038b0..a208e2901 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/CheckItemExpansion.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/CheckItemExpansion.java @@ -13,7 +13,6 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Locale; import java.util.function.Predicate; public class CheckItemExpansion extends PlaceholderExpansion { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 9fee10396..08f477aaa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -115,7 +115,7 @@ public class BukkitItemManager extends AbstractItemManager { } @Override - public Optional> s2c(Item item, Player player) { + public Optional> s2c(Item item, @Nullable Player player) { if (item.isEmpty()) return Optional.empty(); return this.networkItemHandler.s2c(item, player); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index eb3c19461..264f0c49e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -22,6 +22,7 @@ import net.momirealms.sparrow.nbt.ListTag; import net.momirealms.sparrow.nbt.StringTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -119,7 +120,7 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler> s2c(Item wrapped, Player player) { + public Optional> s2c(Item wrapped, @Nullable Player player) { boolean forceReturn = false; // 处理收纳袋 diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index e92092a98..532a84788 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -19,6 +19,7 @@ import net.momirealms.sparrow.nbt.ListTag; import net.momirealms.sparrow.nbt.StringTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -110,7 +111,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler> s2c(Item wrapped, Player player) { + public Optional> s2c(Item wrapped, @Nullable Player player) { boolean forceReturn = false; // 处理收纳袋 diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index 82f859183..6ce68c38d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -64,8 +64,9 @@ public class BukkitCommandManager extends AbstractCommandManager new SendResourcePackCommand(this, plugin), new DebugSaveDefaultResourcesCommand(this, plugin), new DebugCleanCacheCommand(this, plugin), - new DebugGenerateInternalAssetsCommand(this, plugin) -// new OverrideGiveCommand(this, plugin) + new DebugGenerateInternalAssetsCommand(this, plugin), + new DebugCustomModelDataCommand(this, plugin), + new DebugImageCommand(this, plugin) )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCustomModelDataCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCustomModelDataCommand.java new file mode 100644 index 000000000..21d08f6f6 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCustomModelDataCommand.java @@ -0,0 +1,88 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; +import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.CompletableFuture; + +public class DebugCustomModelDataCommand extends BukkitCommandFeature { + + public DebugCustomModelDataCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .optional("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(plugin().itemManager().cachedCustomItemSuggestions()); + } + })) + .handler(this::handleCommand); + } + + @Override + public String getFeatureID() { + return "debug_custom_model_data"; + } + + private void handleCommand(CommandContext context) { + NamespacedKey namespacedKey = context.getOrDefault("id", null); + @Nullable BukkitServerPlayer player = context.sender() instanceof Player p ? BukkitAdaptors.adapt(p) : null; + + if (namespacedKey != null) { + Key itemId = KeyUtils.namespacedKey2Key(namespacedKey); + CustomItem customItem = CraftEngineItems.byId(itemId); + if (customItem == null) return; + Item item = customItem.buildItem(player); + sendMessage(context, getCustomModelData(item, player)); + return; + } + + if (player != null) { + Item item = player.getItemInHand(InteractionHand.MAIN_HAND).copyWithCount(1); + sendMessage(context, getCustomModelData(item, player)); + } + } + + private int getCustomModelData(Item itemStack, BukkitServerPlayer player) { + return plugin().itemManager().s2c(itemStack, player) + .map(Item::customModelData) + .orElse(itemStack.customModelData()) + .orElse(0); + } + + private void sendMessage(CommandContext context, int customModelData) { + Component message = Component.text(customModelData) + .hoverEvent(Component.text("Copy", NamedTextColor.YELLOW)) + .clickEvent(ClickEvent.suggestCommand(String.valueOf(customModelData))); + plugin().senderFactory().wrap(context.sender()).sendMessage(message); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugImageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugImageCommand.java new file mode 100644 index 000000000..3ced3f48d --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugImageCommand.java @@ -0,0 +1,88 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.font.BitmapImage; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.FormatUtils; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.command.CommandSender; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.IntegerParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.concurrent.CompletableFuture; + +public class DebugImageCommand extends BukkitCommandFeature { + + public DebugImageCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(plugin().fontManager().cachedImagesSuggestions()); + } + })) + .optional("row", IntegerParser.integerParser(0)) + .optional("column", IntegerParser.integerParser(0)) + .handler(context -> { + Key imageId = KeyUtils.namespacedKey2Key(context.get("id")); + plugin().fontManager().bitmapImageByImageId(imageId).ifPresent(image -> { + int row = context.getOrDefault("row", 0); + int column = context.getOrDefault("column", 0); + String string = image.isValidCoordinate(row, column) + ? imageId.asString() + ((row != 0 || column != 0) ? ":" + row + ":" + column : "") // 自动最小化 + : imageId.asString() + ":" + (row = 0) + ":" + (column = 0); // 因为是无效的所以说要强调告诉获取的是00 + Component component = Component.text() + .append(Component.text(string) + .hoverEvent(image.componentAt(row, column).color(NamedTextColor.WHITE)) + .clickEvent(ClickEvent.suggestCommand(string))) + .append(getHelperInfo(image, row, column)) + .build(); + plugin().senderFactory().wrap(context.sender()).sendMessage(component); + }); + }); + } + + @Override + public String getFeatureID() { + return "debug_image"; + } + + private static TextComponent.Builder getHelperInfo(BitmapImage image, int row, int column) { + String raw = new String(Character.toChars(image.codepointAt(row, column))); + String font = image.font().toString(); + return Component.text() + .append(Component.text(" ")) + .append(Component.text("[MM]") + .color(NamedTextColor.YELLOW) + .hoverEvent(Component.text("Copy", NamedTextColor.YELLOW)) + .clickEvent(ClickEvent.suggestCommand(FormatUtils.miniMessageFont(raw, font)))) + .append(Component.text(" ")) + .append(Component.text("[MD]") + .color(NamedTextColor.YELLOW) + .hoverEvent(Component.text("Copy", NamedTextColor.YELLOW)) + .clickEvent(ClickEvent.suggestCommand(FormatUtils.mineDownFont(raw, font)))) + .append(Component.text(" ")) + .append(Component.text("[RAW]") + .color(NamedTextColor.YELLOW) + .hoverEvent(Component.text("Copy", NamedTextColor.YELLOW)) + .clickEvent(ClickEvent.suggestCommand(raw))); + } +} diff --git a/common-files/src/main/resources/commands.yml b/common-files/src/main/resources/commands.yml index cd3ca9688..a2bfdbeef 100644 --- a/common-files/src/main/resources/commands.yml +++ b/common-files/src/main/resources/commands.yml @@ -237,6 +237,20 @@ debug_clean_cache: - /craftengine debug clean-cache - /ce debug clean-cache +debug_custom_model_data: + enable: true + permission: ce.command.debug.custom_model_data + usage: + - /craftengine debug custom-model-data + - /ce debug custom-model-data + +debug_image: + enable: true + permission: ce.command.debug.image + usage: + - /craftengine debug image + - /ce debug image + debug_generate_internal_assets: enable: false permission: ce.command.debug.generate_internal_assets diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 640e66d9a..df9e4fdff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.util.*; import org.ahocorasick.trie.Token; import org.ahocorasick.trie.Trie; +import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import javax.imageio.ImageIO; @@ -52,6 +53,8 @@ public abstract class AbstractFontManager implements FontManager { protected Map emojiMapper; protected List emojiList; protected List allEmojiSuggestions; + // Cached command suggestions + protected final List cachedImagesSuggestions = new ArrayList<>(); public AbstractFontManager(CraftEngine plugin) { this.plugin = plugin; @@ -95,6 +98,7 @@ public abstract class AbstractFontManager implements FontManager { public void unload() { this.fonts.clear(); this.images.clear(); + this.cachedImagesSuggestions.clear(); this.illegalChars.clear(); this.emojis.clear(); this.networkTagTrie = null; @@ -415,6 +419,12 @@ public abstract class AbstractFontManager implements FontManager { return Optional.ofNullable(this.fonts.get(id)); } + + @Override + public Collection cachedImagesSuggestions() { + return Collections.unmodifiableCollection(this.cachedImagesSuggestions); + } + private Font getOrCreateFont(Key key) { return this.fonts.computeIfAbsent(key, Font::new); } @@ -712,6 +722,7 @@ public abstract class AbstractFontManager implements FontManager { } AbstractFontManager.this.images.put(id, bitmapImage); + AbstractFontManager.this.cachedImagesSuggestions.add(Suggestion.suggestion(id.asString())); }, () -> GsonHelper.get().toJson(section))); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java index 0c9e46730..1aad2075b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.util.*; import net.momirealms.sparrow.nbt.Tag; +import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -80,6 +81,8 @@ public interface FontManager extends Manageable { Optional fontById(Key font); + Collection cachedImagesSuggestions(); + int codepointByImageId(Key imageId, int x, int y); default int codepointByImageId(Key imageId) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 3b017a27a..ba87486ee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -113,7 +113,7 @@ public interface ItemManager extends Manageable, ModelGenerator { Optional> c2s(Item item); - Optional> s2c(Item item, Player player); + Optional> s2c(Item item, @Nullable Player player); UniqueIdItem uniqueEmptyItem(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java index 529bd293e..1ee213ea7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java @@ -18,7 +18,7 @@ public interface NetworkItemHandler { String NETWORK_OPERATION = "type"; String NETWORK_VALUE = "value"; - Optional> s2c(Item itemStack, Player player); + Optional> s2c(Item itemStack, @Nullable Player player); Optional> c2s(Item itemStack); diff --git a/gradle.properties b/gradle.properties index 4d5cc6e4e..5ec8f0c20 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings project_version=0.0.65.11 -config_version=56 +config_version=57 lang_version=39 project_group=net.momirealms latest_supported_version=1.21.10