9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-28 19:39:11 +00:00

Merge pull request #44 from jhqwqmc/dev

feat(core): 添加查看物品配方和用法功能
This commit is contained in:
XiaoMoMi
2025-03-16 21:29:43 +08:00
committed by GitHub
21 changed files with 400 additions and 63 deletions

View File

@@ -38,6 +38,32 @@ item_browser:
- /ce item browser
- /ce
item_recipe_browser_player:
enable: true
permission: ce.command.player.item_recipe_browser
usage:
- /findrecipe by-result
item_usage_browser_player:
enable: true
permission: ce.command.player.item_usage_browser
usage:
- /findrecipe by-ingredient
item_recipe_browser_admin:
enable: true
permission: ce.command.admin.item_recipe_browser
usage:
- /craftengine recipe by-result
- /ce recipe by-result
item_usage_browser_admin:
enable: true
permission: ce.command.admin.item_usage_browser
usage:
- /craftengine recipe by-ingredient
- /ce recipe by-ingredient
# Debug commands
debug_set_block:
enable: true

View File

@@ -162,6 +162,7 @@ gui:
available: "internal:previous_page_0"
not-available: "internal:previous_page_1"
return: "internal:return"
exit: "internal:exit"
recipe:
get-item-icon: internal:get_item
cooking-information-icon: internal:cooking_info
@@ -173,6 +174,7 @@ gui:
available: "internal:previous_recipe_0"
not-available: "internal:previous_recipe_1"
return: "internal:return"
exit: "internal:exit"
none:
title: "<white><shift:-11><image:internal:no_recipe>"
blasting:

View File

@@ -158,4 +158,11 @@ items:
name: "<!i><#FF8C00><i18n:internal.cooking_info>"
lore:
- "<!i><gray><i18n:internal.cooking_info.0>"
- "<!i><gray><i18n:internal.cooking_info.1>"
- "<!i><gray><i18n:internal.cooking_info.1>"
internal:exit:
template: "internal:2d_icon"
arguments:
model_data: 1007
texture: exit
name: "<!i><#DAA520><i18n:internal.exit>"
lore: null

View File

@@ -3,6 +3,7 @@ i18n:
internal.next_page: "Next Page"
internal.previous_page: "Previous Page"
internal.return: "Return to Parent Page"
internal.exit: "Exit"
internal.next_recipe: "Next Recipe"
internal.previous_recipe: "Previous Recipe"
internal.get_item: "Get Item"
@@ -15,6 +16,7 @@ i18n:
internal.next_page: "下一页"
internal.previous_page: "上一页"
internal.return: "返回上一级"
internal.exit: "退出"
internal.next_recipe: "下一个配方"
internal.previous_recipe: "上一个配方"
internal.get_item: "获取物品"

View File

@@ -48,4 +48,6 @@ command.item.get.success: "<white>Got <arg:0> <arg:1></white>"
command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.recipe.browser.recipe.no_found: "<red>No recipe found for this item</red>"
command.item.usage.browser.recipe.no_found: "<red>No usage found for this item</red>"

View File

@@ -48,4 +48,4 @@ command.item.get.success: "<white>Obtener <arg:0> <arg:1></white>"
command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"

View File

@@ -49,3 +49,5 @@ command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.recipe.browser.recipe.no_found: "<red>找不到此物品的配方</red>"
command.item.usage.browser.recipe.no_found: "<red>找不到此物品的用法</red>"

View File

@@ -49,3 +49,5 @@ command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.recipe.browser.recipe.no_found: "<red>找不到此物品的配方</red>"
command.item.usage.browser.recipe.no_found: "<red>找不到此物品的用法</red>"

View File

@@ -32,6 +32,10 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new GetItemCommand(this, plugin),
new GiveItemCommand(this, plugin),
new ItemBrowserCommand(this, plugin),
new ItemRecipeBrowserPlayerCommand(this, plugin),
new ItemUsageBrowserPlayerCommand(this, plugin),
new ItemRecipeBrowserAdminCommand(this, plugin),
new ItemUsageBrowserAdminCommand(this, plugin),
new TestCommand(this, plugin),
new DebugGetBlockStateRegistryIdCommand(this, plugin),
new DebugGetBlockInternalIdCommand(this, plugin),

View File

@@ -0,0 +1,65 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.plugin.locale.MessageConstants;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.data.MultiplePlayerSelector;
import org.incendo.cloud.bukkit.parser.NamespacedKeyParser;
import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser;
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 java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class ItemRecipeBrowserAdminCommand extends BukkitCommandFeature<CommandSender> {
public ItemRecipeBrowserAdminCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.required("player", MultiplePlayerSelectorParser.multiplePlayerSelectorParser(true))
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions());
}
}))
.handler(context -> {
MultiplePlayerSelector selector = context.get("player");
Collection<Player> players = selector.values();
for (Player player : players) {
BukkitServerPlayer serverPlayer = plugin().adapt(player);
NamespacedKey namespacedKey = context.get("id");
Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value());
List<Recipe<Object>> inRecipes = plugin().recipeManager().getRecipeByResult(itemId);
if (!inRecipes.isEmpty()) {
plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false);
} else {
handleFeedback(context, MessageConstants.COMMAND_ITEM_RECIPE_BROWSER_RECIPE_NOT_FOUND);
}
}
});
}
@Override
public String getFeatureID() {
return "item_recipe_browser_admin";
}
}

View File

@@ -0,0 +1,59 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.plugin.locale.MessageConstants;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
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 java.util.List;
import java.util.concurrent.CompletableFuture;
public class ItemRecipeBrowserPlayerCommand extends BukkitCommandFeature<CommandSender> {
public ItemRecipeBrowserPlayerCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions());
}
}))
.handler(context -> {
Player player = context.sender();
BukkitServerPlayer serverPlayer = plugin().adapt(player);
NamespacedKey namespacedKey = context.get("id");
Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value());
List<Recipe<Object>> inRecipes = plugin().recipeManager().getRecipeByResult(itemId);
if (!inRecipes.isEmpty()) {
plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false);
} else {
handleFeedback(context, MessageConstants.COMMAND_ITEM_RECIPE_BROWSER_RECIPE_NOT_FOUND);
}
});
}
@Override
public String getFeatureID() {
return "item_recipe_browser_player";
}
}

View File

@@ -0,0 +1,65 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.plugin.locale.MessageConstants;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.data.MultiplePlayerSelector;
import org.incendo.cloud.bukkit.parser.NamespacedKeyParser;
import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser;
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 java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class ItemUsageBrowserAdminCommand extends BukkitCommandFeature<CommandSender> {
public ItemUsageBrowserAdminCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.required("player", MultiplePlayerSelectorParser.multiplePlayerSelectorParser(true))
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions());
}
}))
.handler(context -> {
MultiplePlayerSelector selector = context.get("player");
Collection<Player> players = selector.values();
for (Player player : players) {
BukkitServerPlayer serverPlayer = plugin().adapt(player);
NamespacedKey namespacedKey = context.get("id");
Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value());
List<Recipe<Object>> inRecipes = plugin().recipeManager().getRecipeByIngredient(itemId);
if (!inRecipes.isEmpty()) {
plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false);
} else {
handleFeedback(context, MessageConstants.COMMAND_ITEM_USAGE_BROWSER_RECIPE_NOT_FOUND);
}
}
});
}
@Override
public String getFeatureID() {
return "item_usage_browser_admin";
}
}

View File

@@ -0,0 +1,59 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.plugin.locale.MessageConstants;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
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 java.util.List;
import java.util.concurrent.CompletableFuture;
public class ItemUsageBrowserPlayerCommand extends BukkitCommandFeature<CommandSender> {
public ItemUsageBrowserPlayerCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions());
}
}))
.handler(context -> {
Player player = context.sender();
BukkitServerPlayer serverPlayer = plugin().adapt(player);
NamespacedKey namespacedKey = context.get("id");
Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value());
List<Recipe<Object>> inRecipes = plugin().recipeManager().getRecipeByIngredient(itemId);
if (!inRecipes.isEmpty()) {
plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false);
} else {
handleFeedback(context, MessageConstants.COMMAND_ITEM_USAGE_BROWSER_RECIPE_NOT_FOUND);
}
});
}
@Override
public String getFeatureID() {
return "item_usage_browser_player";
}
}

View File

@@ -196,6 +196,11 @@ public class BukkitServerPlayer extends Player {
PlayerUtils.giveItem(platformPlayer(), (ItemStack) item.getItem(), item.count());
}
@Override
public void closeInventory() {
platformPlayer().closeInventory();
}
@Override
public void sendPacket(Object packet, boolean immediately) {
this.plugin.networkManager().sendPacket(this, packet, immediately);

View File

@@ -66,4 +66,6 @@ public abstract class Player extends Entity implements NetWorkUser {
public abstract void playSound(Key sound, float volume, float pitch);
public abstract void giveItem(Item<?> item);
public abstract void closeInventory();
}

View File

@@ -258,6 +258,7 @@ public abstract class AbstractPackManager implements PackManager {
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/item/custom/gui/previous_page_0.png");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/item/custom/gui/previous_page_1.png");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/item/custom/gui/return.png");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/item/custom/gui/exit.png");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/item/custom/gui/cooking_info.png");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/item/custom/gui/cooking_info.png.mcmeta");
// default pack

View File

@@ -2,10 +2,12 @@ package net.momirealms.craftengine.core.plugin.gui.category;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.plugin.Reloadable;
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import net.momirealms.craftengine.core.plugin.gui.Gui;
import net.momirealms.craftengine.core.util.Key;
import java.util.List;
@@ -33,6 +35,10 @@ public interface ItemBrowserManager extends Reloadable, ConfigSectionParser {
void open(Player player);
void openRecipePage(Player player, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth, boolean canOpenNoRecipePage);
void openNoRecipePage(Player player, Key result, Gui parentGui, int depth);
TreeSet<Category> categories();
Optional<Category> byId(Key key);
@@ -46,6 +52,7 @@ public interface ItemBrowserManager extends Reloadable, ConfigSectionParser {
public static String CATEGORY_TITLE;
public static Key CATEGORY_BACK;
public static Key CATEGORY_EXIT;
public static Key CATEGORY_NEXT_PAGE_AVAILABLE;
public static Key CATEGORY_NEXT_PAGE_BLOCK;
public static Key CATEGORY_PREVIOUS_PAGE_AVAILABLE;
@@ -59,6 +66,7 @@ public interface ItemBrowserManager extends Reloadable, ConfigSectionParser {
public static String RECIPE_CRAFTING_TITLE;
public static String RECIPE_STONECUTTING_TITLE;
public static Key RECIPE_BACK;
public static Key RECIPE_EXIT;
public static Key RECIPE_NEXT_PAGE_AVAILABLE;
public static Key RECIPE_NEXT_PAGE_BLOCK;
public static Key RECIPE_PREVIOUS_PAGE_AVAILABLE;
@@ -82,6 +90,7 @@ public interface ItemBrowserManager extends Reloadable, ConfigSectionParser {
CATEGORY_TITLE = getOrThrow(section, "category.title");
CATEGORY_BACK = Key.of(getOrThrow(section, "category.page-navigation.return"));
CATEGORY_EXIT = Key.of(getOrThrow(section, "category.page-navigation.exit"));
CATEGORY_NEXT_PAGE_AVAILABLE = Key.of(getOrThrow(section, "category.page-navigation.next.available"));
CATEGORY_NEXT_PAGE_BLOCK = Key.of(getOrThrow(section, "category.page-navigation.next.not-available"));
CATEGORY_PREVIOUS_PAGE_AVAILABLE = Key.of(getOrThrow(section, "category.page-navigation.previous.available"));
@@ -95,6 +104,7 @@ public interface ItemBrowserManager extends Reloadable, ConfigSectionParser {
RECIPE_CRAFTING_TITLE = getOrThrow(section, "recipe.crafting.title");
RECIPE_STONECUTTING_TITLE = getOrThrow(section, "recipe.stonecutting.title");
RECIPE_BACK = Key.of(getOrThrow(section, "recipe.page-navigation.return"));
RECIPE_EXIT = Key.of(getOrThrow(section, "recipe.page-navigation.exit"));
RECIPE_NEXT_PAGE_AVAILABLE = Key.of(getOrThrow(section, "recipe.page-navigation.next.available"));
RECIPE_NEXT_PAGE_BLOCK = Key.of(getOrThrow(section, "recipe.page-navigation.next.not-available"));
RECIPE_PREVIOUS_PAGE_AVAILABLE = Key.of(getOrThrow(section, "recipe.page-navigation.previous.available"));

View File

@@ -7,8 +7,8 @@ import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.recipe.*;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.gui.Ingredient;
import net.momirealms.craftengine.core.plugin.gui.*;
import net.momirealms.craftengine.core.plugin.gui.Ingredient;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.Key;
@@ -141,7 +141,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
return new ItemWithAction(item, (element, click) -> {
click.cancel();
player.playSound(Constants.SOUND_CLICK_BUTTON);
openCategoryPage(click.clicker(), it.id(), element.gui());
openCategoryPage(click.clicker(), it.id(), element.gui(), true);
});
}).filter(Objects::nonNull).toList();
@@ -159,7 +159,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
.open(player);
}
public void openCategoryPage(Player player, Key categoryId, Gui parentGui) {
public void openCategoryPage(Player player, Key categoryId, Gui parentGui, boolean canOpenNoRecipePage) {
GuiLayout layout = new GuiLayout(
"AAAAAAAAA",
"AAAAAAAAA",
@@ -169,13 +169,17 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
" < = > "
)
.addIngredient('A', Ingredient.paged())
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(Constants.CATEGORY_BACK)
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.CATEGORY_BACK : Constants.CATEGORY_EXIT)
.map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY)))
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + Constants.CATEGORY_BACK)),
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.CATEGORY_BACK : Constants.CATEGORY_EXIT))),
((element, click) -> {
click.cancel();
player.playSound(Constants.SOUND_RETURN_PAGE, 0.25f, 1);
parentGui.open(player);
if (parentGui != null) {
parentGui.open(player);
} else {
player.closeInventory();
}
}))
)
.addIngredient('>', GuiElement.paged((element) -> {
@@ -223,7 +227,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
return new ItemWithAction(item, (element, click) -> {
click.cancel();
player.playSound(Constants.SOUND_CLICK_BUTTON);
openCategoryPage(click.clicker(), subCategory.id(), element.gui());
openCategoryPage(click.clicker(), subCategory.id(), element.gui(), canOpenNoRecipePage);
});
} else {
Key itemId = Key.of(it);
@@ -241,15 +245,15 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
List<Recipe<Object>> inRecipes = this.plugin.recipeManager().getRecipeByResult(itemId);
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, itemId, e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
List<Recipe<Object>> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(itemId);
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
});
@@ -270,6 +274,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
.open(player);
}
@Override
public void openNoRecipePage(Player player, Key result, Gui parentGui, int depth) {
GuiLayout layout = new GuiLayout(
" ",
@@ -289,7 +294,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
List<Recipe<Object>> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result);
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, true);
}
}
}))
@@ -303,13 +308,17 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
player.giveItem(item.count(item.maxStackSize()));
}
}) : GuiElement.EMPTY)
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(Constants.RECIPE_BACK)
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT)
.map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY)))
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + Constants.RECIPE_BACK)),
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))),
((element, click) -> {
click.cancel();
player.playSound(Constants.SOUND_RETURN_PAGE, 0.25f, 1);
parentGui.open(player);
if (parentGui != null) {
parentGui.open(player);
} else {
player.closeInventory();
}
}))
);
@@ -326,26 +335,27 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
.open(player);
}
public void openRecipePage(Player player, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth) {
@Override
public void openRecipePage(Player player, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth, boolean canOpenNoRecipePage) {
if (index >= recipes.size()) return;
if (depth > MAX_RECIPE_DEPTH) return;
Recipe<Object> recipe = recipes.get(index);
Key recipeType = recipe.type();
if (recipeType == RecipeTypes.SHAPELESS || recipeType == RecipeTypes.SHAPED) {
openCraftingRecipePage(player, (CustomCraftingTableRecipe<Object>) recipe, parentGui, recipes, index, depth);
openCraftingRecipePage(player, (CustomCraftingTableRecipe<Object>) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage);
return;
}
if (recipeType == RecipeTypes.BLASTING || recipeType == RecipeTypes.CAMPFIRE_COOKING || recipeType == RecipeTypes.SMOKING || recipeType == RecipeTypes.SMELTING) {
openCookingRecipePage(player, (CustomCookingRecipe<Object>) recipe, parentGui, recipes, index, depth);
openCookingRecipePage(player, (CustomCookingRecipe<Object>) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage);
return;
}
if (recipeType == RecipeTypes.STONE_CUTTING) {
openStoneCuttingRecipePage(player, (CustomStoneCuttingRecipe<Object>) recipe, parentGui, recipes, index, depth);
openStoneCuttingRecipePage(player, (CustomStoneCuttingRecipe<Object>) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage);
return;
}
}
public void openStoneCuttingRecipePage(Player player, CustomStoneCuttingRecipe<Object> recipe, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth) {
public void openStoneCuttingRecipePage(Player player, CustomStoneCuttingRecipe<Object> recipe, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth, boolean canOpenNoRecipePage) {
Key previous = index > 0 ? Constants.RECIPE_PREVIOUS_PAGE_AVAILABLE : Constants.RECIPE_PREVIOUS_PAGE_BLOCK;
Key next = index + 1 < recipes.size() ? Constants.RECIPE_NEXT_PAGE_AVAILABLE : Constants.RECIPE_NEXT_PAGE_BLOCK;
Key result = recipe.result().item().id();
@@ -376,8 +386,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, result, e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
@@ -385,7 +395,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
}))
@@ -412,8 +422,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
@@ -421,17 +431,21 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
}))
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(Constants.RECIPE_BACK)
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT)
.map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY)))
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + Constants.RECIPE_BACK)),
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))),
((element, click) -> {
click.cancel();
player.playSound(Constants.SOUND_RETURN_PAGE, 0.25f, 1);
parentGui.open(player);
if (parentGui != null) {
parentGui.open(player);
} else {
player.closeInventory();
}
}))
)
.addIngredient('>', GuiElement.constant(this.plugin.itemManager()
@@ -444,7 +458,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
c.cancel();
if (index + 1 < recipes.size()) {
player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1);
openRecipePage(player, parentGui, recipes, index + 1, depth);
openRecipePage(player, parentGui, recipes, index + 1, depth, canOpenNoRecipePage);
}
}))
.addIngredient('<', GuiElement.constant(this.plugin.itemManager()
@@ -457,7 +471,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
c.cancel();
if (index > 0) {
player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1);
openRecipePage(player, parentGui, recipes, index - 1, depth);
openRecipePage(player, parentGui, recipes, index - 1, depth, canOpenNoRecipePage);
}
}));
@@ -474,7 +488,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
.open(player);
}
public void openCookingRecipePage(Player player, CustomCookingRecipe<Object> recipe, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth) {
public void openCookingRecipePage(Player player, CustomCookingRecipe<Object> recipe, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth, boolean canOpenNoRecipePage) {
Key previous = index > 0 ? Constants.RECIPE_PREVIOUS_PAGE_AVAILABLE : Constants.RECIPE_PREVIOUS_PAGE_BLOCK;
Key next = index + 1 < recipes.size() ? Constants.RECIPE_NEXT_PAGE_AVAILABLE : Constants.RECIPE_NEXT_PAGE_BLOCK;
Key result = recipe.result().item().id();
@@ -505,8 +519,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, result, e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
@@ -514,7 +528,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
}))
@@ -547,8 +561,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
@@ -556,17 +570,21 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
}))
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(Constants.RECIPE_BACK)
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT)
.map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY)))
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + Constants.RECIPE_BACK)),
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))),
((element, click) -> {
click.cancel();
player.playSound(Constants.SOUND_RETURN_PAGE, 0.25f, 1);
parentGui.open(player);
if (parentGui != null) {
parentGui.open(player);
} else {
player.closeInventory();
}
}))
)
.addIngredient('>', GuiElement.constant(this.plugin.itemManager()
@@ -579,7 +597,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
c.cancel();
if (index + 1 < recipes.size()) {
player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1);
openRecipePage(player, parentGui, recipes, index + 1, depth);
openRecipePage(player, parentGui, recipes, index + 1, depth, canOpenNoRecipePage);
}
}))
.addIngredient('<', GuiElement.constant(this.plugin.itemManager()
@@ -592,7 +610,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
c.cancel();
if (index > 0) {
player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1);
openRecipePage(player, parentGui, recipes, index - 1, depth);
openRecipePage(player, parentGui, recipes, index - 1, depth, canOpenNoRecipePage);
}
}));
@@ -620,7 +638,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
.open(player);
}
public void openCraftingRecipePage(Player player, CustomCraftingTableRecipe<Object> recipe, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth) {
public void openCraftingRecipePage(Player player, CustomCraftingTableRecipe<Object> recipe, Gui parentGui, List<Recipe<Object>> recipes, int index, int depth, boolean canOpenNoRecipePage) {
Key previous = index > 0 ? Constants.RECIPE_PREVIOUS_PAGE_AVAILABLE : Constants.RECIPE_PREVIOUS_PAGE_BLOCK;
Key next = index + 1 < recipes.size() ? Constants.RECIPE_NEXT_PAGE_AVAILABLE : Constants.RECIPE_NEXT_PAGE_BLOCK;
Key result = recipe.result().item().id();
@@ -646,8 +664,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, result, e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
@@ -655,7 +673,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
}))
@@ -669,13 +687,17 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
player.giveItem(item.count(item.maxStackSize()));
}
}) : GuiElement.EMPTY)
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(Constants.RECIPE_BACK)
.addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT)
.map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY)))
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + Constants.RECIPE_BACK)),
.orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))),
((element, click) -> {
click.cancel();
player.playSound(Constants.SOUND_RETURN_PAGE, 0.25f, 1);
parentGui.open(player);
if (parentGui != null) {
parentGui.open(player);
} else {
player.closeInventory();
}
}))
)
.addIngredient('>', GuiElement.constant(this.plugin.itemManager()
@@ -688,7 +710,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
c.cancel();
if (index + 1 < recipes.size()) {
player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1);
openRecipePage(player, parentGui, recipes, index + 1, depth);
openRecipePage(player, parentGui, recipes, index + 1, depth, canOpenNoRecipePage);
}
}))
.addIngredient('<', GuiElement.constant(this.plugin.itemManager()
@@ -701,7 +723,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
c.cancel();
if (index > 0) {
player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1);
openRecipePage(player, parentGui, recipes, index - 1, depth);
openRecipePage(player, parentGui, recipes, index - 1, depth, canOpenNoRecipePage);
}
}));
@@ -734,8 +756,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
@@ -743,7 +765,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
}));
@@ -777,8 +799,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
} else {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
} else if (RIGHT_CLICK.contains(c.type())) {
@@ -786,7 +808,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
}
}
}));

View File

@@ -16,4 +16,6 @@ public interface MessageConstants {
TranslatableComponent.Builder COMMAND_ITEM_GIVE_SUCCESS_SINGLE = Component.translatable().key("command.item.give.success.single");
TranslatableComponent.Builder COMMAND_ITEM_GIVE_SUCCESS_MULTIPLE = Component.translatable().key("command.item.give.success.multiple");
TranslatableComponent.Builder COMMAND_ITEM_GIVE_FAILURE_NOT_EXIST = Component.translatable().key("command.item.give.failure.not_exist");
TranslatableComponent.Builder COMMAND_ITEM_RECIPE_BROWSER_RECIPE_NOT_FOUND = Component.translatable().key("command.item.recipe.browser.recipe.no_found");
TranslatableComponent.Builder COMMAND_ITEM_USAGE_BROWSER_RECIPE_NOT_FOUND = Component.translatable().key("command.item.usage.browser.recipe.no_found");
}

View File

@@ -1,8 +1,8 @@
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.33
config_version=13
lang_version=2
project_version=0.0.34
config_version=14
lang_version=3
project_group=net.momirealms
latest_minecraft_version=1.21.4