diff --git a/gradle.properties b/gradle.properties index da9f5ea..bf89df6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -33,7 +33,7 @@ mod_name=3944Realms 's Lib Mod # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=0.1.0 +mod_version=0.1.1 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/top/r3944realms/lib39/util/villager/TradeBuilder.java b/src/main/java/top/r3944realms/lib39/util/villager/TradeBuilder.java new file mode 100644 index 0000000..ff1168d --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/util/villager/TradeBuilder.java @@ -0,0 +1,636 @@ +package top.r3944realms.lib39.util.villager; + +import com.google.common.collect.Lists; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.VillagerDataHolder; +import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.world.entity.npc.VillagerType; +import net.minecraft.world.item.*; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.PotionBrewing; +import net.minecraft.world.item.alchemy.PotionUtils; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.saveddata.maps.MapDecoration; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.Map; + +/** + * 村民交易构建器 + * 用于创建自定义的交易项目 + */ +public class TradeBuilder { + /** + * 创建物品换绿宝石的交易 + * + * @param item 物品 + * @param cost 需要的数量 + * @param maxUses 最大使用次数 + * @param villagerXp 村民获得的经验 + * @return 交易实例 emerald for items + */ + @Contract("_, _, _, _ -> new") + public static @NotNull EmeraldForItems createSellItemTrade(ItemLike item, int cost, int maxUses, int villagerXp) { + return new EmeraldForItems(item, cost, maxUses, villagerXp); + } + + /** + * 创建绿宝石换物品的交易 + * + * @param item 物品 + * @param emeraldCost 需要的绿宝石数量 + * @param numberOfItems 获得的物品数量 + * @param maxUses 最大使用次数 + * @param villagerXp 村民获得的经验 + * @return 交易实例 items for emeralds + */ + @Contract("_, _, _, _, _ -> new") + public static @NotNull ItemsForEmeralds createBuyItemTrade(ItemLike item, int emeraldCost, int numberOfItems, int maxUses, int villagerXp) { + return new ItemsForEmeralds(item, emeraldCost, numberOfItems, maxUses, villagerXp); + } + + /** + * 创建物品和绿宝石换物品的交易 + * + * @param fromItem 提供的物品 + * @param fromCount 提供的物品数量 + * @param emeraldCost 需要的绿宝石数量 + * @param toItem 获得的物品 + * @param toCount 获得的物品数量 + * @param maxUses 最大使用次数 + * @param villagerXp 村民获得的经验 + * @return 交易实例 items and emeralds to items + */ + @Contract("_, _, _, _, _, _, _ -> new") + public static @NotNull ItemsAndEmeraldsToItems createItemExchangeTrade( + ItemLike fromItem, int fromCount, int emeraldCost, + @NotNull ItemLike toItem, int toCount, int maxUses, int villagerXp) { + return new ItemsAndEmeraldsToItems(fromItem, fromCount, emeraldCost, + toItem.asItem(), toCount, maxUses, villagerXp); + } + + /** + * 创建附魔物品交易 + * + * @param item 物品 + * @param baseEmeraldCost 基础绿宝石价格 + * @param maxUses 最大使用次数 + * @param villagerXp 村民获得的经验 + * @return 交易实例 enchanted item for emeralds + */ + @Contract("_, _, _, _ -> new") + public static @NotNull EnchantedItemForEmeralds createEnchantedItemTrade( + Item item, int baseEmeraldCost, int maxUses, int villagerXp) { + return new EnchantedItemForEmeralds(item, baseEmeraldCost, maxUses, villagerXp); + } + + /** + * 创建附魔书交易 + * + * @param villagerXp 村民获得的经验 + * @return 交易实例 enchant book for emeralds + */ + @Contract(value = "_ -> new", pure = true) + public static @NotNull EnchantBookForEmeralds createEnchantedBookTrade(int villagerXp) { + return new EnchantBookForEmeralds(villagerXp); + } + + /** + * 创建宝藏地图交易 + * + * @param emeraldCost 绿宝石价格 + * @param destination the destination + * @param displayName 显示名称 + * @param destinationTyp the destination typ + * @param maxUses 最大使用次数 + * @param villagerXp 村民获得的经验 + * @return 交易实例 treasure map for emeralds + */ + @Contract(pure = true) + public static @NotNull TreasureMapForEmeralds createTreasureMapTrade( + int emeraldCost, TagKey destination, String displayName, MapDecoration.Type destinationTyp, int maxUses, int villagerXp) { + + return new TreasureMapForEmeralds(emeraldCost, destination, displayName, destinationTyp, maxUses, villagerXp); + } + + /** + * 创建染色盔甲交易 + * + * @param item 盔甲物品 + * @param value 绿宝石价格 + * @param maxUses 最大使用次数 + * @param villagerXp 村民获得的经验 + * @return 交易实例 dyed armor for emeralds + */ + @Contract(value = "_, _, _, _ -> new", pure = true) + public static @NotNull DyedArmorForEmeralds createDyedArmorTrade( + Item item, int value, int maxUses, int villagerXp) { + return new DyedArmorForEmeralds(item, value, maxUses, villagerXp); + } + + /** + * The type Emerald for items. + */ + public static class EmeraldForItems implements VillagerTrades.ItemListing { + private final Item item; + private final int cost; + private final int maxUses; + private final int villagerXp; + private final float priceMultiplier; + + /** + * Instantiates a new Emerald for items. + * + * @param item the item + * @param cost the cost + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public EmeraldForItems(@NotNull ItemLike item, int cost, int maxUses, int villagerXp) { + this.item = item.asItem(); + this.cost = cost; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + this.priceMultiplier = 0.05F; + } + + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + ItemStack itemstack = new ItemStack(this.item, this.cost); + return new MerchantOffer(itemstack, new ItemStack(Items.EMERALD), this.maxUses, this.villagerXp, this.priceMultiplier); + } + } + + /** + * The type Items for emeralds. + */ + public static class ItemsForEmeralds implements VillagerTrades.ItemListing { + private final ItemStack itemStack; + private final int emeraldCost; + private final int numberOfItems; + private final int maxUses; + private final int villagerXp; + private final float priceMultiplier; + + /** + * Instantiates a new Items for emeralds. + * + * @param block the block + * @param emeraldCost the emerald cost + * @param numberOfItems the number of items + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public ItemsForEmeralds(Block block, int emeraldCost, int numberOfItems, int maxUses, int villagerXp) { + this(new ItemStack(block), emeraldCost, numberOfItems, maxUses, villagerXp); + } + + /** + * Instantiates a new Items for emeralds. + * + * @param item the item + * @param emeraldCost the emerald cost + * @param numberOfItems the number of items + * @param villagerXp the villager xp + */ + public ItemsForEmeralds(ItemLike item, int emeraldCost, int numberOfItems, int villagerXp) { + this(new ItemStack(item), emeraldCost, numberOfItems, 12, villagerXp); + } + + /** + * Instantiates a new Items for emeralds. + * + * @param item the item + * @param emeraldCost the emerald cost + * @param numberOfItems the number of items + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public ItemsForEmeralds(ItemLike item, int emeraldCost, int numberOfItems, int maxUses, int villagerXp) { + this(new ItemStack(item), emeraldCost, numberOfItems, maxUses, villagerXp); + } + + /** + * Instantiates a new Items for emeralds. + * + * @param itemStack the item stack + * @param emeraldCost the emerald cost + * @param numberOfItems the number of items + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public ItemsForEmeralds(ItemStack itemStack, int emeraldCost, int numberOfItems, int maxUses, int villagerXp) { + this(itemStack, emeraldCost, numberOfItems, maxUses, villagerXp, 0.05F); + } + + /** + * Instantiates a new Items for emeralds. + * + * @param itemStack the item stack + * @param emeraldCost the emerald cost + * @param numberOfItems the number of items + * @param maxUses the max uses + * @param villagerXp the villager xp + * @param priceMultiplier the price multiplier + */ + public ItemsForEmeralds(ItemStack itemStack, int emeraldCost, int numberOfItems, int maxUses, int villagerXp, float priceMultiplier) { + this.itemStack = itemStack; + this.emeraldCost = emeraldCost; + this.numberOfItems = numberOfItems; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + this.priceMultiplier = priceMultiplier; + } + + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + return new MerchantOffer(new ItemStack(Items.EMERALD, this.emeraldCost), new ItemStack(this.itemStack.getItem(), this.numberOfItems), this.maxUses, this.villagerXp, this.priceMultiplier); + } + } + + /** + * The type Suspicious stew for emerald. + */ + public static class SuspiciousStewForEmerald implements VillagerTrades.ItemListing { + /** + * The Effect. + */ + final MobEffect effect; + /** + * The Duration. + */ + final int duration; + /** + * The Xp. + */ + final int xp; + private final float priceMultiplier; + + /** + * Instantiates a new Suspicious stew for emerald. + * + * @param effect the effect + * @param duration the duration + * @param xp the xp + */ + public SuspiciousStewForEmerald(MobEffect effect, int duration, int xp) { + this.effect = effect; + this.duration = duration; + this.xp = xp; + this.priceMultiplier = 0.05F; + } + + @Nullable + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + ItemStack itemstack = new ItemStack(Items.SUSPICIOUS_STEW, 1); + SuspiciousStewItem.saveMobEffect(itemstack, this.effect, this.duration); + return new MerchantOffer(new ItemStack(Items.EMERALD, 1), itemstack, 12, this.xp, this.priceMultiplier); + } + } + + /** + * The type Items and emeralds to items. + */ + public static class ItemsAndEmeraldsToItems implements VillagerTrades.ItemListing { + private final ItemStack fromItem; + private final int fromCount; + private final int emeraldCost; + private final ItemStack toItem; + private final int toCount; + private final int maxUses; + private final int villagerXp; + private final float priceMultiplier; + + /** + * Instantiates a new Items and emeralds to items. + * + * @param fromItem the from item + * @param fromCount the from count + * @param toItem the to item + * @param toCount the to count + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public ItemsAndEmeraldsToItems(ItemLike fromItem, int fromCount, Item toItem, int toCount, int maxUses, int villagerXp) { + this(fromItem, fromCount, 1, toItem, toCount, maxUses, villagerXp); + } + + /** + * Instantiates a new Items and emeralds to items. + * + * @param fromItem the from item + * @param fromCount the from count + * @param emeraldCost the emerald cost + * @param toItem the to item + * @param toCount the to count + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public ItemsAndEmeraldsToItems(ItemLike fromItem, int fromCount, int emeraldCost, Item toItem, int toCount, int maxUses, int villagerXp) { + this.fromItem = new ItemStack(fromItem); + this.fromCount = fromCount; + this.emeraldCost = emeraldCost; + this.toItem = new ItemStack(toItem); + this.toCount = toCount; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + this.priceMultiplier = 0.05F; + } + + @Nullable + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + return new MerchantOffer(new ItemStack(Items.EMERALD, this.emeraldCost), new ItemStack(this.fromItem.getItem(), this.fromCount), new ItemStack(this.toItem.getItem(), this.toCount), this.maxUses, this.villagerXp, this.priceMultiplier); + } + } + + /** + * The type Enchanted item for emeralds. + */ + public static class EnchantedItemForEmeralds implements VillagerTrades.ItemListing { + private final ItemStack itemStack; + private final int baseEmeraldCost; + private final int maxUses; + private final int villagerXp; + private final float priceMultiplier; + + /** + * Instantiates a new Enchanted item for emeralds. + * + * @param item the item + * @param baseEmeraldCost the base emerald cost + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public EnchantedItemForEmeralds(Item item, int baseEmeraldCost, int maxUses, int villagerXp) { + this(item, baseEmeraldCost, maxUses, villagerXp, 0.05F); + } + + /** + * Instantiates a new Enchanted item for emeralds. + * + * @param item the item + * @param baseEmeraldCost the base emerald cost + * @param maxUses the max uses + * @param villagerXp the villager xp + * @param priceMultiplier the price multiplier + */ + public EnchantedItemForEmeralds(Item item, int baseEmeraldCost, int maxUses, int villagerXp, float priceMultiplier) { + this.itemStack = new ItemStack(item); + this.baseEmeraldCost = baseEmeraldCost; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + this.priceMultiplier = priceMultiplier; + } + + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + int i = 5 + random.nextInt(15); + ItemStack itemstack = EnchantmentHelper.enchantItem(random, new ItemStack(this.itemStack.getItem()), i, false); + int j = Math.min(this.baseEmeraldCost + i, 64); + ItemStack itemstack1 = new ItemStack(Items.EMERALD, j); + return new MerchantOffer(itemstack1, itemstack, this.maxUses, this.villagerXp, this.priceMultiplier); + } + } + + /** + * The type Emeralds for villager type item. + */ + public static class EmeraldsForVillagerTypeItem implements VillagerTrades.ItemListing { + private final Map trades; + private final int cost; + private final int maxUses; + private final int villagerXp; + + /** + * Instantiates a new Emeralds for villager type item. + * + * @param cost the cost + * @param maxUses the max uses + * @param villagerXp the villager xp + * @param trades the trades + */ + public EmeraldsForVillagerTypeItem(int cost, int maxUses, int villagerXp, Map trades) { + BuiltInRegistries.VILLAGER_TYPE.stream().filter((villagerType) -> { + return !trades.containsKey(villagerType); + }).findAny().ifPresent((p_258962_) -> { + throw new IllegalStateException("Missing trade for villager type: " + BuiltInRegistries.VILLAGER_TYPE.getKey(p_258962_)); + }); + this.trades = trades; + this.cost = cost; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + } + + @Nullable + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + if (trader instanceof VillagerDataHolder) { + ItemStack itemstack = new ItemStack(this.trades.get(((VillagerDataHolder)trader).getVillagerData().getType()), this.cost); + return new MerchantOffer(itemstack, new ItemStack(Items.EMERALD), this.maxUses, this.villagerXp, 0.05F); + } else { + return null; + } + } + } + + /** + * The type Tipped arrow for items and emeralds. + */ + @SuppressWarnings("deprecation") + public static class TippedArrowForItemsAndEmeralds implements VillagerTrades.ItemListing { + private final ItemStack toItem; + private final int toCount; + private final int emeraldCost; + private final int maxUses; + private final int villagerXp; + private final Item fromItem; + private final int fromCount; + private final float priceMultiplier; + + /** + * Instantiates a new Tipped arrow for items and emeralds. + * + * @param fromItem the from item + * @param fromCount the from count + * @param toItem the to item + * @param toCount the to count + * @param emeraldCost the emerald cost + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public TippedArrowForItemsAndEmeralds(Item fromItem, int fromCount, Item toItem, int toCount, int emeraldCost, int maxUses, int villagerXp) { + this.toItem = new ItemStack(toItem); + this.emeraldCost = emeraldCost; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + this.fromItem = fromItem; + this.fromCount = fromCount; + this.toCount = toCount; + this.priceMultiplier = 0.05F; + } + + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + ItemStack itemstack = new ItemStack(Items.EMERALD, this.emeraldCost); + List list = BuiltInRegistries.POTION.stream().filter((effects) -> !effects.getEffects().isEmpty() && PotionBrewing.isBrewablePotion(effects)).toList(); + Potion potion = list.get(random.nextInt(list.size())); + ItemStack itemstack1 = PotionUtils.setPotion(new ItemStack(this.toItem.getItem(), this.toCount), potion); + return new MerchantOffer(itemstack, new ItemStack(this.fromItem, this.fromCount), itemstack1, this.maxUses, this.villagerXp, this.priceMultiplier); + } + } + + /** + * The type Enchant book for emeralds. + */ + @SuppressWarnings("deprecation") + public static class EnchantBookForEmeralds implements VillagerTrades.ItemListing { + private final int villagerXp; + + /** + * Instantiates a new Enchant book for emeralds. + * + * @param villagerXp the villager xp + */ + public EnchantBookForEmeralds(int villagerXp) { + this.villagerXp = villagerXp; + } + + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + List list = BuiltInRegistries.ENCHANTMENT.stream().filter(Enchantment::isTradeable).toList(); + Enchantment enchantment = list.get(random.nextInt(list.size())); + int i = Mth.nextInt(random, enchantment.getMinLevel(), enchantment.getMaxLevel()); + ItemStack itemstack = EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, i)); + int j = 2 + random.nextInt(5 + i * 10) + 3 * i; + if (enchantment.isTreasureOnly()) { + j *= 2; + } + + if (j > 64) { + j = 64; + } + + return new MerchantOffer(new ItemStack(Items.EMERALD, j), new ItemStack(Items.BOOK), itemstack, 12, this.villagerXp, 0.2F); + } + } + + /** + * The type Treasure map for emeralds. + */ + public static class TreasureMapForEmeralds implements VillagerTrades.ItemListing { + private final int emeraldCost; + private final TagKey destination; + private final String displayName; + private final MapDecoration.Type destinationType; + private final int maxUses; + private final int villagerXp; + + /** + * Instantiates a new Treasure map for emeralds. + * + * @param emeraldCost the emerald cost + * @param destination the destination + * @param displayName the display name + * @param destinationType the destination type + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public TreasureMapForEmeralds(int emeraldCost, TagKey destination, String displayName, MapDecoration.Type destinationType, int maxUses, int villagerXp) { + this.emeraldCost = emeraldCost; + this.destination = destination; + this.displayName = displayName; + this.destinationType = destinationType; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + } + + @Nullable + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + if (!(trader.level() instanceof ServerLevel serverlevel)) { + return null; + } else { + BlockPos blockpos = serverlevel.findNearestMapStructure(this.destination, trader.blockPosition(), 100, true); + if (blockpos != null) { + ItemStack itemstack = MapItem.create(serverlevel, blockpos.getX(), blockpos.getZ(), (byte)2, true, true); + MapItem.renderBiomePreviewMap(serverlevel, itemstack); + MapItemSavedData.addTargetDecoration(itemstack, blockpos, "+", this.destinationType); + itemstack.setHoverName(Component.translatable(this.displayName)); + return new MerchantOffer(new ItemStack(Items.EMERALD, this.emeraldCost), new ItemStack(Items.COMPASS), itemstack, this.maxUses, this.villagerXp, 0.2F); + } else { + return null; + } + } + } + } + + /** + * The type Dyed armor for emeralds. + */ + public static class DyedArmorForEmeralds implements VillagerTrades.ItemListing { + private final Item item; + private final int value; + private final int maxUses; + private final int villagerXp; + + /** + * Instantiates a new Dyed armor for emeralds. + * + * @param item the item + * @param value the value + */ + public DyedArmorForEmeralds(Item item, int value) { + this(item, value, 12, 1); + } + + /** + * Instantiates a new Dyed armor for emeralds. + * + * @param item the item + * @param value the value + * @param maxUses the max uses + * @param villagerXp the villager xp + */ + public DyedArmorForEmeralds(Item item, int value, int maxUses, int villagerXp) { + this.item = item; + this.value = value; + this.maxUses = maxUses; + this.villagerXp = villagerXp; + } + + public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) { + ItemStack itemstack = new ItemStack(Items.EMERALD, this.value); + ItemStack itemstack1 = new ItemStack(this.item); + if (this.item instanceof DyeableArmorItem) { + List list = Lists.newArrayList(); + list.add(getRandomDye(random)); + if (random.nextFloat() > 0.7F) { + list.add(getRandomDye(random)); + } + + if (random.nextFloat() > 0.8F) { + list.add(getRandomDye(random)); + } + + itemstack1 = DyeableLeatherItem.dyeArmor(itemstack1, list); + } + + return new MerchantOffer(itemstack, itemstack1, this.maxUses, this.villagerXp, 0.2F); + } + + private static @NotNull DyeItem getRandomDye(@NotNull RandomSource random) { + return DyeItem.byColor(DyeColor.byId(random.nextInt(16))); + } + } +}