minecraft-src/net/minecraft/world/item/trading/MerchantOffer.java
2025-07-04 01:41:11 +03:00

265 lines
7.6 KiB
Java

package net.minecraft.world.item.trading;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Optional;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
public class MerchantOffer {
public static final Codec<MerchantOffer> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
ItemCost.CODEC.fieldOf("buy").forGetter(merchantOffer -> merchantOffer.baseCostA),
ItemCost.CODEC.lenientOptionalFieldOf("buyB").forGetter(merchantOffer -> merchantOffer.costB),
ItemStack.CODEC.fieldOf("sell").forGetter(merchantOffer -> merchantOffer.result),
Codec.INT.lenientOptionalFieldOf("uses", 0).forGetter(merchantOffer -> merchantOffer.uses),
Codec.INT.lenientOptionalFieldOf("maxUses", 4).forGetter(merchantOffer -> merchantOffer.maxUses),
Codec.BOOL.lenientOptionalFieldOf("rewardExp", true).forGetter(merchantOffer -> merchantOffer.rewardExp),
Codec.INT.lenientOptionalFieldOf("specialPrice", 0).forGetter(merchantOffer -> merchantOffer.specialPriceDiff),
Codec.INT.lenientOptionalFieldOf("demand", 0).forGetter(merchantOffer -> merchantOffer.demand),
Codec.FLOAT.lenientOptionalFieldOf("priceMultiplier", 0.0F).forGetter(merchantOffer -> merchantOffer.priceMultiplier),
Codec.INT.lenientOptionalFieldOf("xp", 1).forGetter(merchantOffer -> merchantOffer.xp)
)
.apply(instance, MerchantOffer::new)
);
public static final StreamCodec<RegistryFriendlyByteBuf, MerchantOffer> STREAM_CODEC = StreamCodec.of(
MerchantOffer::writeToStream, MerchantOffer::createFromStream
);
/**
* The first input for this offer.
*/
private final ItemCost baseCostA;
/**
* The second input for this offer.
*/
private final Optional<ItemCost> costB;
/**
* The output of this offer.
*/
private final ItemStack result;
private int uses;
private final int maxUses;
private final boolean rewardExp;
private int specialPriceDiff;
private int demand;
private final float priceMultiplier;
private final int xp;
private MerchantOffer(
ItemCost baseCostA,
Optional<ItemCost> costB,
ItemStack result,
int uses,
int maxUses,
boolean rewardExp,
int specialPriceDiff,
int demand,
float priceMultiplier,
int xp
) {
this.baseCostA = baseCostA;
this.costB = costB;
this.result = result;
this.uses = uses;
this.maxUses = maxUses;
this.rewardExp = rewardExp;
this.specialPriceDiff = specialPriceDiff;
this.demand = demand;
this.priceMultiplier = priceMultiplier;
this.xp = xp;
}
public MerchantOffer(ItemCost baseCostA, ItemStack result, int maxUses, int xp, float priceMultiplier) {
this(baseCostA, Optional.empty(), result, maxUses, xp, priceMultiplier);
}
public MerchantOffer(ItemCost baseCostA, Optional<ItemCost> costB, ItemStack result, int maxUses, int xp, float priceMultiplier) {
this(baseCostA, costB, result, 0, maxUses, xp, priceMultiplier);
}
public MerchantOffer(ItemCost baseCostA, Optional<ItemCost> costB, ItemStack result, int uses, int maxUses, int xp, float priceMultiplier) {
this(baseCostA, costB, result, uses, maxUses, xp, priceMultiplier, 0);
}
public MerchantOffer(ItemCost baseCostA, Optional<ItemCost> costB, ItemStack result, int uses, int maxUses, int xp, float priceMultiplier, int demand) {
this(baseCostA, costB, result, uses, maxUses, true, 0, demand, priceMultiplier, xp);
}
private MerchantOffer(MerchantOffer other) {
this(
other.baseCostA,
other.costB,
other.result.copy(),
other.uses,
other.maxUses,
other.rewardExp,
other.specialPriceDiff,
other.demand,
other.priceMultiplier,
other.xp
);
}
public ItemStack getBaseCostA() {
return this.baseCostA.itemStack();
}
public ItemStack getCostA() {
return this.baseCostA.itemStack().copyWithCount(this.getModifiedCostCount(this.baseCostA));
}
private int getModifiedCostCount(ItemCost itemCost) {
int i = itemCost.count();
int j = Math.max(0, Mth.floor(i * this.demand * this.priceMultiplier));
return Mth.clamp(i + j + this.specialPriceDiff, 1, itemCost.itemStack().getMaxStackSize());
}
public ItemStack getCostB() {
return (ItemStack)this.costB.map(ItemCost::itemStack).orElse(ItemStack.EMPTY);
}
public ItemCost getItemCostA() {
return this.baseCostA;
}
public Optional<ItemCost> getItemCostB() {
return this.costB;
}
public ItemStack getResult() {
return this.result;
}
/**
* Calculates the demand with following formula: demand = demand + uses - maxUses - uses
*/
public void updateDemand() {
this.demand = this.demand + this.uses - (this.maxUses - this.uses);
}
public ItemStack assemble() {
return this.result.copy();
}
public int getUses() {
return this.uses;
}
public void resetUses() {
this.uses = 0;
}
public int getMaxUses() {
return this.maxUses;
}
public void increaseUses() {
this.uses++;
}
public int getDemand() {
return this.demand;
}
public void addToSpecialPriceDiff(int add) {
this.specialPriceDiff += add;
}
public void resetSpecialPriceDiff() {
this.specialPriceDiff = 0;
}
public int getSpecialPriceDiff() {
return this.specialPriceDiff;
}
public void setSpecialPriceDiff(int price) {
this.specialPriceDiff = price;
}
public float getPriceMultiplier() {
return this.priceMultiplier;
}
public int getXp() {
return this.xp;
}
public boolean isOutOfStock() {
return this.uses >= this.maxUses;
}
public void setToOutOfStock() {
this.uses = this.maxUses;
}
public boolean needsRestock() {
return this.uses > 0;
}
public boolean shouldRewardExp() {
return this.rewardExp;
}
public boolean satisfiedBy(ItemStack playerOfferA, ItemStack playerOfferB) {
if (!this.baseCostA.test(playerOfferA) || playerOfferA.getCount() < this.getModifiedCostCount(this.baseCostA)) {
return false;
} else {
return !this.costB.isPresent()
? playerOfferB.isEmpty()
: ((ItemCost)this.costB.get()).test(playerOfferB) && playerOfferB.getCount() >= ((ItemCost)this.costB.get()).count();
}
}
public boolean take(ItemStack playerOfferA, ItemStack playerOfferB) {
if (!this.satisfiedBy(playerOfferA, playerOfferB)) {
return false;
} else {
playerOfferA.shrink(this.getCostA().getCount());
if (!this.getCostB().isEmpty()) {
playerOfferB.shrink(this.getCostB().getCount());
}
return true;
}
}
public MerchantOffer copy() {
return new MerchantOffer(this);
}
private static void writeToStream(RegistryFriendlyByteBuf buffer, MerchantOffer offer) {
ItemCost.STREAM_CODEC.encode(buffer, offer.getItemCostA());
ItemStack.STREAM_CODEC.encode(buffer, offer.getResult());
ItemCost.OPTIONAL_STREAM_CODEC.encode(buffer, offer.getItemCostB());
buffer.writeBoolean(offer.isOutOfStock());
buffer.writeInt(offer.getUses());
buffer.writeInt(offer.getMaxUses());
buffer.writeInt(offer.getXp());
buffer.writeInt(offer.getSpecialPriceDiff());
buffer.writeFloat(offer.getPriceMultiplier());
buffer.writeInt(offer.getDemand());
}
public static MerchantOffer createFromStream(RegistryFriendlyByteBuf buffer) {
ItemCost itemCost = ItemCost.STREAM_CODEC.decode(buffer);
ItemStack itemStack = ItemStack.STREAM_CODEC.decode(buffer);
Optional<ItemCost> optional = ItemCost.OPTIONAL_STREAM_CODEC.decode(buffer);
boolean bl = buffer.readBoolean();
int i = buffer.readInt();
int j = buffer.readInt();
int k = buffer.readInt();
int l = buffer.readInt();
float f = buffer.readFloat();
int m = buffer.readInt();
MerchantOffer merchantOffer = new MerchantOffer(itemCost, optional, itemStack, i, j, k, f, m);
if (bl) {
merchantOffer.setToOutOfStock();
}
merchantOffer.setSpecialPriceDiff(l);
return merchantOffer;
}
}