更新版本号0.1.0 -> 0.1.1

添加交易构建器
This commit is contained in:
叁玖领域 2026-01-03 17:01:27 +08:00
parent f3daa2ed24
commit 87bffc5fc9
2 changed files with 637 additions and 1 deletions

View File

@ -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

View File

@ -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<Structure> 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<VillagerType, Item> 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<VillagerType, Item> 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<Potion> 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<Enchantment> 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<Structure> 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<Structure> 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<DyeItem> 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)));
}
}
}