265 lines
7.6 KiB
Java
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;
|
|
}
|
|
}
|