From 5356427440819ba64c30c6a86f41d0e0810e0bb6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Fri, 17 Oct 2025 20:32:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Emerchant=5Ftrade=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/LegacyInventoryUtils.java | 6 + .../bukkit/plugin/BukkitPlatform.java | 23 +--- .../bukkit/plugin/gui/BukkitGuiManager.java | 52 ++++++++ .../src/main/resources/translations/en.yml | 3 + .../core/block/AbstractBlockManager.java | 36 ++++-- .../craftengine/core/plugin/Platform.java | 2 - .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 1 + .../context/function/DamageFunction.java | 2 +- .../function/MerchantTradeFunction.java | 122 ++++++++++++++++++ .../core/plugin/gui/GuiManager.java | 5 + .../plugin/locale/LocalizedException.java | 6 +- .../core/util/ResourceConfigUtils.java | 2 +- 13 files changed, 222 insertions(+), 39 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MerchantTradeFunction.java diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java index 7b8827dd0..5fa59cef1 100644 --- a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryEvent; @@ -74,6 +75,11 @@ public final class LegacyInventoryUtils { player.openMerchant(merchant, true); } + @SuppressWarnings("deprecation") + public static Merchant createMerchant() { + return Bukkit.createMerchant("Villager"); + } + public static Player getPlayerFromInventoryEvent(InventoryEvent event) { return (Player) event.getView().getPlayer(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java index e9195e591..becaa6d5c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java @@ -26,6 +26,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Merchant; import org.bukkit.inventory.MerchantRecipe; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -91,26 +92,4 @@ public class BukkitPlatform implements Platform { } return new BukkitParticleType(particle, name); } - - @Override - public void openMerchant(Player player, Component title, List> offers) { - Merchant merchant = Bukkit.createMerchant(); - List recipes = merchant.getRecipes(); - for (MerchantOffer offer : offers) { - MerchantRecipe merchantRecipe = new MerchantRecipe((ItemStack) offer.result().getItem(), 0, Integer.MAX_VALUE, offer.xp() > 0, offer.xp(), 0); - merchantRecipe.addIngredient((ItemStack) offer.cost1().getItem()); - offer.cost2().ifPresent(it -> merchantRecipe.addIngredient((ItemStack) it.getItem())); - recipes.add(merchantRecipe); - } - merchant.setRecipes(recipes); - if (title != null) { - try { - Object minecraftMerchant = CraftBukkitReflections.method$CraftMerchant$getMerchant.invoke(merchant); - CraftBukkitReflections.field$MinecraftMerchant$title.set(minecraftMerchant, ComponentUtils.adventureToMinecraft(title)); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to update merchant title", e); - } - } - LegacyInventoryUtils.openMerchant((org.bukkit.entity.Player) player.platformPlayer(), merchant); - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index 5dcdbc23b..a9470ed42 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -1,29 +1,44 @@ package net.momirealms.craftengine.bukkit.plugin.gui; +import io.papermc.paper.event.player.PlayerPurchaseEvent; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.block.entity.BlockEntityHolder; import net.momirealms.craftengine.bukkit.block.entity.SimpleStorageBlockEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.InventoryUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; +import net.momirealms.craftengine.core.item.trade.MerchantOffer; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.gui.*; +import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ExperienceOrb; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Merchant; +import org.bukkit.inventory.MerchantRecipe; + +import java.util.ArrayList; +import java.util.List; public class BukkitGuiManager implements GuiManager, Listener { + public static final int CRAFT_ENGINE_MAGIC_MERCHANT_NUMBER = 1821981731; private static BukkitGuiManager instance; private final BukkitCraftEngine plugin; @@ -135,6 +150,43 @@ public class BukkitGuiManager implements GuiManager, Listener { } } + // 为了修复没有经验的问题 + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onMerchantTrade(PlayerPurchaseEvent event) { + MerchantRecipe trade = event.getTrade(); + if (trade.getMaxUses() == CRAFT_ENGINE_MAGIC_MERCHANT_NUMBER) { + Player player = event.getPlayer(); + int exp = trade.getVillagerExperience(); + if (exp <= 0) return; + EntityUtils.spawnEntity(player.getWorld(), player.getLocation(), EntityType.EXPERIENCE_ORB, entity -> { + ExperienceOrb orb = (ExperienceOrb) entity; + orb.setExperience(exp); + }); + } + } + + @Override + public void openMerchant(net.momirealms.craftengine.core.entity.player.Player player, Component title, List> offers) { + Merchant merchant = VersionHelper.isOrAbove1_21_4() ? Bukkit.createMerchant() : LegacyInventoryUtils.createMerchant(); + List recipes = new ArrayList<>(); + for (MerchantOffer offer : offers) { + MerchantRecipe merchantRecipe = new MerchantRecipe((ItemStack) offer.result().getItem(), 0, CRAFT_ENGINE_MAGIC_MERCHANT_NUMBER, false, offer.xp(), 0); + merchantRecipe.addIngredient((ItemStack) offer.cost1().getItem()); + offer.cost2().ifPresent(it -> merchantRecipe.addIngredient((ItemStack) it.getItem())); + recipes.add(merchantRecipe); + } + merchant.setRecipes(recipes); + if (title != null) { + try { + Object minecraftMerchant = CraftBukkitReflections.method$CraftMerchant$getMerchant.invoke(merchant); + CraftBukkitReflections.field$MinecraftMerchant$title.set(minecraftMerchant, ComponentUtils.adventureToMinecraft(title)); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to update merchant title", e); + } + } + LegacyInventoryUtils.openMerchant((org.bukkit.entity.Player) player.platformPlayer(), merchant); + } + public static BukkitGuiManager instance() { return instance; } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index fe7dd065c..a93c66922 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -466,6 +466,9 @@ warning.config.function.set_variable.missing_value: "Issue found in file warning.config.function.toast.missing_toast: "Issue found in file - The config '' is missing the required 'toast' argument for 'toast' function." warning.config.function.toast.missing_icon: "Issue found in file - The config '' is missing the required 'icon' argument for 'toast' function." warning.config.function.toast.invalid_advancement_type: "Issue found in file - The config '' is using an invalid advancement type '' for 'toast' function. Allowed types: []." +warning.config.function.merchant_trade.missing_offers: "Issue found in file - The config '' is missing the required 'offers' argument for 'merchant_trade' function." +warning.config.function.merchant_trade.offer.missing_cost_1: "Issue found in file - The config '' is missing the required 'cost-1' argument for merchant trade offers." +warning.config.function.merchant_trade.offer.missing_result: "Issue found in file - The config '' is missing the required 'result' argument for merchant trade offers." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 870971aac..d835426df 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -491,13 +491,24 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } + ExceptionCollector eCollector1 = new ExceptionCollector<>(); + + Map>> events; + try { + events = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); + } catch (LocalizedResourceConfigException e) { + eCollector1.add(e); + events = Map.of(); + } + LootTable lootTable; + try { + lootTable = LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot")); + } catch (LocalizedResourceConfigException e) { + eCollector1.add(e); + lootTable = null; + } // 创建自定义方块 - AbstractCustomBlock customBlock = (AbstractCustomBlock) createCustomBlock( - holder, - variantProvider, - EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")), - LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot")) - ); + AbstractCustomBlock customBlock = (AbstractCustomBlock) createCustomBlock(holder, variantProvider, events, lootTable); BlockBehavior blockBehavior = createBlockBehavior(customBlock, MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))); Map> appearanceConfigs; @@ -592,7 +603,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 至少有一个外观吧 Objects.requireNonNull(anyAppearance, "any appearance should not be null"); - ExceptionCollector exceptionCollector = new ExceptionCollector<>(); + ExceptionCollector eCollector2 = new ExceptionCollector<>(); if (!singleState) { Map variantsSection = ResourceConfigUtils.getAsMapOrNull(stateSection.get("variants"), "variants"); if (variantsSection != null) { @@ -602,7 +613,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 先解析nbt,找到需要修改的方块状态 CompoundTag tag = BlockNbtParser.deserialize(variantProvider, variantNBT); if (tag == null) { - exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", variantNBT)); + eCollector2.add(new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", variantNBT)); continue; } List possibleStates = variantProvider.getPossibleStates(tag); @@ -612,11 +623,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem possibleState.setSettings(BlockSettings.ofFullCopy(possibleState.settings(), anotherSetting)); } } - String appearanceName = ResourceConfigUtils.getAsString(variantSection.get("appearance")); + String appearanceName = ResourceConfigUtils.getAsStringOrNull(variantSection.get("appearance")); if (appearanceName != null) { BlockStateAppearance appearance = appearances.get(appearanceName); if (appearance == null) { - exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearanceName)); + eCollector2.add(new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearanceName)); continue; } for (ImmutableBlockState possibleState : possibleStates) { @@ -675,8 +686,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem AbstractBlockManager.this.byId.put(customBlock.id(), customBlock); // 抛出次要警告 - exceptionCollector.throwIfPresent(); + eCollector2.throwIfPresent(); }, () -> GsonHelper.get().toJson(section))); + + // 抛出次要警告 + eCollector1.throwIfPresent(); }, () -> GsonHelper.get().toJson(section))); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java index 039146214..09f2f6e71 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java @@ -26,6 +26,4 @@ public interface Platform { World getWorld(String name); ParticleType getParticleType(Key name); - - void openMerchant(Player player, Component title, List> offers); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index e23bee3d9..bd3e5230c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -46,6 +46,7 @@ public class EventFunctions { register(CommonFunctions.SET_VARIABLE, new SetVariableFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.TOAST, new ToastFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.DAMAGE, new DamageFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.MERCHANT_TRADE, new MerchantTradeFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 56c9ab931..e54ece3ea 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -35,4 +35,5 @@ public final class CommonFunctions { public static final Key TOAST = Key.of("craftengine:toast"); public static final Key SET_VARIABLE = Key.of("craftengine:set_variable"); public static final Key DAMAGE = Key.of("craftengine:damage"); + public static final Key MERCHANT_TRADE = Key.of("craftengine:merchant_trade"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java index 6ebb22d35..8c75f6a53 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java @@ -43,7 +43,7 @@ public class DamageFunction extends AbstractConditionalFunc @Override public Function create(Map arguments) { PlayerSelector selector = PlayerSelectors.fromObject(arguments.getOrDefault("target", "self"), conditionFactory()); - Key damageType = Key.of(ResourceConfigUtils.getAsString(arguments.getOrDefault("damage-type", "generic"))); + Key damageType = Key.of(ResourceConfigUtils.getAsStringOrNull(arguments.getOrDefault("damage-type", "generic"))); NumberProvider amount = NumberProviders.fromObject(arguments.getOrDefault("amount", 1f)); return new DamageFunction<>(selector, damageType, amount, getPredicates(arguments)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MerchantTradeFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MerchantTradeFunction.java new file mode 100644 index 000000000..43ac9d0a6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MerchantTradeFunction.java @@ -0,0 +1,122 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.item.modifier.ComponentsModifier; +import net.momirealms.craftengine.core.item.modifier.TagsModifier; +import net.momirealms.craftengine.core.item.trade.MerchantOffer; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.util.*; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class MerchantTradeFunction extends AbstractConditionalFunction { + private final String title; + private final PlayerSelector selector; + private final LazyReference>> offers; + + public MerchantTradeFunction(List> predicates, @Nullable PlayerSelector selector, String title, LazyReference>> offers) { + super(predicates); + this.title = title; + this.selector = selector; + this.offers = offers; + } + + @Override + public void runInternal(CTX ctx) { + if (this.selector == null) { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { + CraftEngine.instance().guiManager().openMerchant(it, this.title == null ? null : AdventureHelper.miniMessage().deserialize(this.title, ctx.tagResolvers()), this.offers.get()); + }); + } else { + for (Player viewer : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer)); + CraftEngine.instance().guiManager().openMerchant(viewer, this.title == null ? null : AdventureHelper.miniMessage().deserialize(this.title, relationalContext.tagResolvers()), this.offers.get()); + } + } + } + + @Override + public Key type() { + return CommonFunctions.MESSAGE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Function create(Map arguments) { + String title = ResourceConfigUtils.getAsStringOrNull(arguments.get("title")); + List merchantOffers = ResourceConfigUtils.parseConfigAsList(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("offers"), "warning.config.function.merchant_trade.missing_offers"), map -> { + Object cost1 = ResourceConfigUtils.requireNonNullOrThrow(map.get("cost-1"), "warning.config.function.merchant_trade.offer.missing_cost_1"); + Object cost2 = map.get("cost-2"); + Object result = ResourceConfigUtils.requireNonNullOrThrow(map.get("result"), "warning.config.function.merchant_trade.offer.missing_result"); + int exp = ResourceConfigUtils.getAsInt(map.get("experience"), "experience"); + return new TempOffer(cost1, cost2, result, exp); + }); + return new MerchantTradeFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), title, + LazyReference.lazyReference(() -> { + List> offers = new ArrayList<>(merchantOffers.size()); + for (TempOffer offer : merchantOffers) { + Item cost1 = parseIngredient(offer.cost1); + Optional cost2 = Optional.ofNullable(parseIngredient(offer.cost2)); + Item result = parseIngredient(offer.result); + offers.add(new MerchantOffer<>(cost1, cost2, result, false, 0, Integer.MAX_VALUE, offer.exp, 0, 0, 0)); + } + return offers; + })); + } + + public record TempOffer(Object cost1, Object cost2, Object result, int exp) { + } + + private Item parseIngredient(Object arguments) { + if (arguments == null) return null; + if (arguments instanceof Map map) { + Map args = MiscUtils.castToMap(map, false); + String itemName = args.getOrDefault("item", "minecraft:stone").toString(); + Item item = createSafeItem(itemName); + if (args.containsKey("count")) { + item.count(ResourceConfigUtils.getAsInt(args.get("count"), "count")); + } + if (VersionHelper.isOrAbove1_20_5() && args.containsKey("components")) { + item = new ComponentsModifier<>(MiscUtils.castToMap(args.get("components"), false)).apply(item, ItemBuildContext.empty()); + } + if (!VersionHelper.isOrAbove1_20_5() && args.containsKey("nbt")) { + item = new TagsModifier<>(MiscUtils.castToMap(args.get("nbt"), false)).apply(item, ItemBuildContext.empty()); + } + return item; + } else { + String itemName = arguments.toString(); + return createSafeItem(itemName); + } + } + + private Item createSafeItem(String itemName) { + Key itemId = Key.of(itemName); + Item item = CraftEngine.instance().itemManager().createWrappedItem(itemId, null); + if (item == null) { + item = CraftEngine.instance().itemManager().createWrappedItem(ItemKeys.STONE, null); + assert item != null; + item.itemNameComponent(Component.text(itemName).color(NamedTextColor.RED)); + } + return item; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java index c23e6f7e8..fe38b4364 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java @@ -2,8 +2,11 @@ package net.momirealms.craftengine.core.plugin.gui; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.trade.MerchantOffer; import net.momirealms.craftengine.core.plugin.Manageable; +import java.util.List; + public interface GuiManager extends Manageable { void openInventory(Player player, GuiType guiType); @@ -11,4 +14,6 @@ public interface GuiManager extends Manageable { void updateInventoryTitle(Player player, Component component); Inventory createInventory(Gui gui, int size); + + void openMerchant(Player player, Component title, List> offers); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedException.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedException.java index d85532317..554e95341 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedException.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedException.java @@ -1,11 +1,13 @@ package net.momirealms.craftengine.core.plugin.locale; +import aQute.bnd.annotation.jpms.Open; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.ArrayUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.Optional; public class LocalizedException extends RuntimeException { private final String node; @@ -72,8 +74,8 @@ public class LocalizedException extends RuntimeException { private String generateLocalizedMessage() { try { - String rawMessage = TranslationManager.instance() - .miniMessageTranslation(this.node); + String rawMessage = Optional.ofNullable(TranslationManager.instance() + .miniMessageTranslation(this.node)).orElse(this.node); String cleanMessage = AdventureHelper.miniMessage() .stripTags(rawMessage); for (int i = 0; i < arguments.length; i++) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index ee688e805..3c21da4ce 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -23,7 +23,7 @@ public final class ResourceConfigUtils { return raw != null ? function.apply(raw) : defaultValue; } - public static String getAsString(@Nullable Object raw) { + public static String getAsStringOrNull(@Nullable Object raw) { if (raw == null) { return null; }