mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-22 19:07:44 +01:00
update nms file patches
This commit is contained in:
@@ -1,71 +0,0 @@
|
||||
--- a/net/minecraft/world/item/AxeItem.java
|
||||
+++ b/net/minecraft/world/item/AxeItem.java
|
||||
@@ -62,13 +_,15 @@
|
||||
if (playerHasShieldUseIntent(context)) {
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
- Optional<BlockState> optional = this.evaluateNewBlockState(level, clickedPos, player, level.getBlockState(clickedPos));
|
||||
+ Optional<org.purpurmc.purpur.tool.Actionable> optional = this.evaluateActionable(level, clickedPos, player, level.getBlockState(clickedPos)); // Purpur - Tool actionable options
|
||||
if (optional.isEmpty()) {
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
+ org.purpurmc.purpur.tool.Actionable actionable = optional.get(); // Purpur - Tool actionable options
|
||||
+ BlockState state = actionable.into().withPropertiesOf(level.getBlockState(clickedPos)); // Purpur - Tool actionable options
|
||||
ItemStack itemInHand = context.getItemInHand();
|
||||
// Paper start - EntityChangeBlockEvent
|
||||
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, optional.get())) {
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, state)) { // Purpur - Tool actionable options
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
// Paper end
|
||||
@@ -76,8 +_,15 @@
|
||||
CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, clickedPos, itemInHand);
|
||||
}
|
||||
|
||||
- level.setBlock(clickedPos, optional.get(), 11);
|
||||
- level.gameEvent(GameEvent.BLOCK_CHANGE, clickedPos, GameEvent.Context.of(player, optional.get()));
|
||||
+ // Purpur start - Tool actionable options
|
||||
+ level.setBlock(clickedPos, state, 11);
|
||||
+ actionable.drops().forEach((drop, chance) -> {
|
||||
+ if (level.random.nextDouble() < chance) {
|
||||
+ Block.popResourceFromFace(level, clickedPos, context.getClickedFace(), new ItemStack(drop));
|
||||
+ }
|
||||
+ });
|
||||
+ level.gameEvent(GameEvent.BLOCK_CHANGE, clickedPos, GameEvent.Context.of(player, state));
|
||||
+ // Purpur end - Tool actionable options
|
||||
if (player != null) {
|
||||
itemInHand.hurtAndBreak(1, player, LivingEntity.getSlotForHand(context.getHand()));
|
||||
}
|
||||
@@ -92,22 +_,24 @@
|
||||
return context.getHand().equals(InteractionHand.MAIN_HAND) && player.getOffhandItem().is(Items.SHIELD) && !player.isSecondaryUseActive();
|
||||
}
|
||||
|
||||
- private Optional<BlockState> evaluateNewBlockState(Level level, BlockPos pos, @Nullable Player player, BlockState state) {
|
||||
- Optional<BlockState> stripped = this.getStripped(state);
|
||||
+ private Optional<org.purpurmc.purpur.tool.Actionable> evaluateActionable(Level level, BlockPos pos, @Nullable Player player, BlockState state) { // Purpur - Tool actionable options
|
||||
+ Optional<org.purpurmc.purpur.tool.Actionable> stripped = Optional.ofNullable(level.purpurConfig.axeStrippables.get(state.getBlock())); // Purpur - Tool actionable options
|
||||
if (stripped.isPresent()) {
|
||||
- level.playSound(player, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
+ level.playSound(STRIPPABLES.containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound
|
||||
return stripped;
|
||||
} else {
|
||||
- Optional<BlockState> previous = WeatheringCopper.getPrevious(state);
|
||||
+ Optional<org.purpurmc.purpur.tool.Actionable> previous = Optional.ofNullable(level.purpurConfig.axeWeatherables.get(state.getBlock())); // Purpur - Tool actionable options
|
||||
if (previous.isPresent()) {
|
||||
- level.playSound(player, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
+ level.playSound(WeatheringCopper.getPrevious(state).isPresent() ? player : null, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - Tool actionable options - force sound
|
||||
level.levelEvent(player, 3005, pos, 0);
|
||||
return previous;
|
||||
} else {
|
||||
- Optional<BlockState> optional = Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(state.getBlock()))
|
||||
- .map(block -> block.withPropertiesOf(state));
|
||||
+ // Purpur start - Tool actionable options
|
||||
+ Optional<org.purpurmc.purpur.tool.Actionable> optional = Optional.ofNullable(level.purpurConfig.axeWaxables.get(state.getBlock()));
|
||||
+ // .map(block -> block.withPropertiesOf(state));
|
||||
+ // Purpur end - Tool actionable options
|
||||
if (optional.isPresent()) {
|
||||
- level.playSound(player, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
+ level.playSound(HoneycombItem.WAX_OFF_BY_BLOCK.get().containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - Tool actionable options - force sound
|
||||
level.levelEvent(player, 3004, pos, 0);
|
||||
return optional;
|
||||
} else {
|
||||
@@ -1,36 +0,0 @@
|
||||
--- a/net/minecraft/world/item/BlockItem.java
|
||||
+++ b/net/minecraft/world/item/BlockItem.java
|
||||
@@ -152,7 +_,16 @@
|
||||
}
|
||||
|
||||
protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, @Nullable Player player, ItemStack stack, BlockState state) {
|
||||
- return updateCustomBlockEntityTag(level, player, pos, stack);
|
||||
+ // Purpur start - Persistent BlockEntity Lore and DisplayName
|
||||
+ boolean handled = updateCustomBlockEntityTag(level, player, pos, stack);
|
||||
+ if (level.purpurConfig.persistentTileEntityLore) {
|
||||
+ BlockEntity blockEntity1 = level.getBlockEntity(pos);
|
||||
+ if (blockEntity1 != null) {
|
||||
+ blockEntity1.setPersistentLore(stack.getOrDefault(DataComponents.LORE, net.minecraft.world.item.component.ItemLore.EMPTY));
|
||||
+ }
|
||||
+ }
|
||||
+ return handled;
|
||||
+ // Purpur end - Persistent BlockEntity Lore and DisplayName
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -217,6 +_,7 @@
|
||||
}
|
||||
|
||||
if (!type.onlyOpCanSetNbt() || player != null && (player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place")))) { // Spigot - add permission
|
||||
+ if (!(level.purpurConfig.silkTouchEnabled && blockEntity instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity && player.getBukkitEntity().hasPermission("purpur.drop.spawners"))) // Purpur - Silk touch spawners
|
||||
return customData.loadInto(blockEntity, level.registryAccess());
|
||||
}
|
||||
|
||||
@@ -264,6 +_,7 @@
|
||||
public void onDestroyed(ItemEntity itemEntity) {
|
||||
ItemContainerContents itemContainerContents = itemEntity.getItem().set(DataComponents.CONTAINER, ItemContainerContents.EMPTY);
|
||||
if (itemContainerContents != null) {
|
||||
+ if (itemEntity.level().purpurConfig.shulkerBoxItemDropContentsWhenDestroyed && this.getBlock() instanceof ShulkerBoxBlock) // Purpur - option to disable shulker box items from dropping contents when destroyed
|
||||
ItemUtils.onContainerDestroyed(itemEntity, itemContainerContents.nonEmptyItemsCopy());
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
--- a/net/minecraft/world/item/BowItem.java
|
||||
+++ b/net/minecraft/world/item/BowItem.java
|
||||
@@ -28,6 +_,11 @@
|
||||
return false;
|
||||
} else {
|
||||
ItemStack projectile = player.getProjectile(stack);
|
||||
+ // Purpur start - Infinity bow settings
|
||||
+ if (level.purpurConfig.infinityWorksWithoutArrows && projectile.isEmpty() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, stack) > 0) {
|
||||
+ projectile = new ItemStack(Items.ARROW);
|
||||
+ }
|
||||
+ // Purpur end - Infinity bow settings
|
||||
if (projectile.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -38,7 +_,7 @@
|
||||
} else {
|
||||
List<ItemStack> list = draw(stack, projectile, player);
|
||||
if (level instanceof ServerLevel serverLevel && !list.isEmpty()) {
|
||||
- this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null);
|
||||
+ this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, (float) serverLevel.purpurConfig.bowProjectileOffset, powerForTime == 1.0F, null); // Purpur - Projectile offset config
|
||||
}
|
||||
|
||||
level.playSound(
|
||||
@@ -89,7 +_,7 @@
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
ItemStack itemInHand = player.getItemInHand(hand);
|
||||
boolean flag = !player.getProjectile(itemInHand).isEmpty();
|
||||
- if (!player.hasInfiniteMaterials() && !flag) {
|
||||
+ if (!player.hasInfiniteMaterials() && !flag && !(level.purpurConfig.infinityWorksWithoutArrows && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, itemInHand) > 0)) { // Purpur - Infinity bow settings
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
player.startUsingItem(hand);
|
||||
@@ -1,20 +0,0 @@
|
||||
--- a/net/minecraft/world/item/BucketItem.java
|
||||
+++ b/net/minecraft/world/item/BucketItem.java
|
||||
@@ -147,7 +_,7 @@
|
||||
// CraftBukkit end
|
||||
if (!flag) {
|
||||
return result != null && this.emptyContents(player, level, result.getBlockPos().relative(result.getDirection()), null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit
|
||||
- } else if (level.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) {
|
||||
+ } else if ((level.dimensionType().ultraWarm() || (level.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) && this.content.is(FluidTags.WATER)) { // Purpur - Add allow water in end world option
|
||||
int x = pos.getX();
|
||||
int y = pos.getY();
|
||||
int z = pos.getZ();
|
||||
@@ -156,7 +_,7 @@
|
||||
);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
- level.addParticle(ParticleTypes.LARGE_SMOKE, x + Math.random(), y + Math.random(), z + Math.random(), 0.0, 0.0, 0.0);
|
||||
+ ((net.minecraft.server.level.ServerLevel) level).sendParticlesSource(null, ParticleTypes.LARGE_SMOKE, true, false, x + Math.random(), y + Math.random(), z + Math.random(), 1, 0.0D, 0.0D, 0.0D, 0.0D); // Purpur - Add allow water in end world option
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/item/CrossbowItem.java
|
||||
+++ b/net/minecraft/world/item/CrossbowItem.java
|
||||
@@ -70,7 +_,7 @@
|
||||
ItemStack itemInHand = player.getItemInHand(hand);
|
||||
ChargedProjectiles chargedProjectiles = itemInHand.get(DataComponents.CHARGED_PROJECTILES);
|
||||
if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) {
|
||||
- this.performShooting(level, player, hand, itemInHand, getShootingPower(chargedProjectiles), 1.0F, null);
|
||||
+ this.performShooting(level, player, hand, itemInHand, getShootingPower(chargedProjectiles), (float) level.purpurConfig.crossbowProjectileOffset, null); // Purpur - Projectile offset config
|
||||
return InteractionResult.CONSUME;
|
||||
} else if (!player.getProjectile(itemInHand).isEmpty()) {
|
||||
this.startSoundPlayed = false;
|
||||
@@ -1,13 +0,0 @@
|
||||
--- a/net/minecraft/world/item/DyeColor.java
|
||||
+++ b/net/minecraft/world/item/DyeColor.java
|
||||
@@ -123,4 +_,10 @@
|
||||
private static CraftingInput makeCraftColorInput(DyeColor first, DyeColor second) {
|
||||
return CraftingInput.of(2, 1, List.of(new ItemStack(DyeItem.byColor(first)), new ItemStack(DyeItem.byColor(second))));
|
||||
}
|
||||
+
|
||||
+ // Purpur start - Shulker spawn from bullet options
|
||||
+ public static DyeColor random(net.minecraft.util.RandomSource random) {
|
||||
+ return values()[random.nextInt(values().length)];
|
||||
+ }
|
||||
+ // Purpur end - Shulker spawn from bullet options
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/item/EggItem.java
|
||||
+++ b/net/minecraft/world/item/EggItem.java
|
||||
@@ -26,7 +_,7 @@
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
// CraftBukkit start
|
||||
// Paper start - PlayerLaunchProjectileEvent
|
||||
- final Projectile.Delayed<ThrownEgg> thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, serverLevel, itemInHand, player, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ final Projectile.Delayed<ThrownEgg> thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, serverLevel, itemInHand, player, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.eggProjectileOffset); // Purpur - Projectile offset config
|
||||
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownEgg.projectile().getBukkitEntity());
|
||||
if (event.callEvent() && thrownEgg.attemptSpawn()) {
|
||||
if (event.shouldConsume()) {
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/item/EndCrystalItem.java
|
||||
+++ b/net/minecraft/world/item/EndCrystalItem.java
|
||||
@@ -24,7 +_,7 @@
|
||||
Level level = context.getLevel();
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
BlockState blockState = level.getBlockState(clickedPos);
|
||||
- if (!blockState.is(Blocks.OBSIDIAN) && !blockState.is(Blocks.BEDROCK)) {
|
||||
+ if (!level.purpurConfig.endCrystalPlaceAnywhere && !blockState.is(Blocks.OBSIDIAN) && !blockState.is(Blocks.BEDROCK)) { // Purpur - place end crystal on any block
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
BlockPos blockPos = clickedPos.above(); final BlockPos aboveBlockPosition = blockPos; // Paper - OBFHELPER
|
||||
@@ -1,19 +0,0 @@
|
||||
--- a/net/minecraft/world/item/EnderpearlItem.java
|
||||
+++ b/net/minecraft/world/item/EnderpearlItem.java
|
||||
@@ -24,7 +_,7 @@
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
// CraftBukkit start
|
||||
// Paper start - PlayerLaunchProjectileEvent
|
||||
- final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemInHand, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemInHand, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.enderPearlProjectileOffset); // Purpur - Projectile offset config
|
||||
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity());
|
||||
if (event.callEvent() && thrownEnderpearl.attemptSpawn()) {
|
||||
if (event.shouldConsume()) {
|
||||
@@ -44,6 +_,7 @@
|
||||
0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F)
|
||||
);
|
||||
player.awardStat(Stats.ITEM_USED.get(this));
|
||||
+ player.getCooldowns().addCooldown(itemInHand, player.getAbilities().instabuild ? level.purpurConfig.enderPearlCooldownCreative : level.purpurConfig.enderPearlCooldown); // Purpur - Configurable Ender Pearl cooldown
|
||||
} else {
|
||||
if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
|
||||
serverPlayer.deregisterEnderPearl(thrownEnderpearl.projectile());
|
||||
@@ -1,33 +0,0 @@
|
||||
--- a/net/minecraft/world/item/HoeItem.java
|
||||
+++ b/net/minecraft/world/item/HoeItem.java
|
||||
@@ -46,15 +_,25 @@
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
Level level = context.getLevel();
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
- Pair<Predicate<UseOnContext>, Consumer<UseOnContext>> pair = TILLABLES.get(level.getBlockState(clickedPos).getBlock());
|
||||
- if (pair == null) {
|
||||
+ // Purpur start - Tool actionable options
|
||||
+ Block clickedBlock = level.getBlockState(clickedPos).getBlock();
|
||||
+ org.purpurmc.purpur.tool.Tillable tillable = level.purpurConfig.hoeTillables.get(clickedBlock);
|
||||
+ if (tillable == null) {
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
- Predicate<UseOnContext> predicate = pair.getFirst();
|
||||
- Consumer<UseOnContext> consumer = pair.getSecond();
|
||||
+ Predicate<UseOnContext> predicate = tillable.condition().predicate();
|
||||
+ Consumer<UseOnContext> consumer = (ctx) -> {
|
||||
+ level.setBlock(clickedPos, tillable.into().defaultBlockState(), 11);
|
||||
+ tillable.drops().forEach((drop, chance) -> {
|
||||
+ if (level.random.nextDouble() < chance) {
|
||||
+ Block.popResourceFromFace(level, clickedPos, ctx.getClickedFace(), new ItemStack(drop));
|
||||
+ }
|
||||
+ });
|
||||
+ };
|
||||
+ // Purpur end - Tool actionable options
|
||||
if (predicate.test(context)) {
|
||||
Player player = context.getPlayer();
|
||||
- level.playSound(player, clickedPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
+ if (!TILLABLES.containsKey(clickedBlock)) level.playSound(null, clickedPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - Tool actionable options - force sound
|
||||
if (!level.isClientSide) {
|
||||
consumer.accept(context);
|
||||
if (player != null) {
|
||||
@@ -1,58 +0,0 @@
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -461,6 +_,7 @@
|
||||
serverLevel.isBlockPlaceCancelled = true; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
||||
for (org.bukkit.block.BlockState blockstate : blocks) {
|
||||
blockstate.update(true, false);
|
||||
+ ((org.bukkit.craftbukkit.block.CraftBlock) blockstate.getBlock()).getNMS().getBlock().forgetPlacer(); // Purpur - Store placer on Block when placed
|
||||
}
|
||||
serverLevel.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
||||
serverLevel.preventPoiUpdated = false;
|
||||
@@ -486,6 +_,7 @@
|
||||
if (!(block.getBlock() instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Containers get placed automatically
|
||||
block.onPlace(serverLevel, newPos, oldBlock, true, context);
|
||||
}
|
||||
+ block.getBlock().forgetPlacer(); // Purpur - Store placer on Block when placed
|
||||
|
||||
serverLevel.notifyAndUpdatePhysics(newPos, null, oldBlock, block, serverLevel.getBlockState(newPos), updateFlag, net.minecraft.world.level.block.Block.UPDATE_LIMIT); // send null chunk as chunk.k() returns false by this point
|
||||
}
|
||||
@@ -627,6 +_,26 @@
|
||||
return this.isDamageableItem() && this.getDamageValue() > 0;
|
||||
}
|
||||
|
||||
+ // Purpur start - Add option to mend the most damaged equipment first
|
||||
+ public float getDamagePercent() {
|
||||
+ if (this.has(DataComponents.UNBREAKABLE)) {
|
||||
+ return 0.0F;
|
||||
+ }
|
||||
+
|
||||
+ final int maxDamage = this.getOrDefault(DataComponents.MAX_DAMAGE, 0);
|
||||
+ if (maxDamage == 0) {
|
||||
+ return 0.0F;
|
||||
+ }
|
||||
+
|
||||
+ final int damage = this.getOrDefault(DataComponents.DAMAGE, 0);
|
||||
+ if (damage == 0) {
|
||||
+ return 0.0F;
|
||||
+ }
|
||||
+
|
||||
+ return (float) damage / maxDamage;
|
||||
+ }
|
||||
+ // Purpur end - Add option to mend the most damaged equipment first
|
||||
+
|
||||
public int getDamageValue() {
|
||||
return Mth.clamp(this.getOrDefault(DataComponents.DAMAGE, Integer.valueOf(0)), 0, this.getMaxDamage());
|
||||
}
|
||||
@@ -1251,6 +_,12 @@
|
||||
public boolean isEnchanted() {
|
||||
return !this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).isEmpty();
|
||||
}
|
||||
+
|
||||
+ // Purpur start - Config to allow unsafe enchants
|
||||
+ public boolean hasEnchantment(Holder<Enchantment> enchantment) {
|
||||
+ return this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).getLevel(enchantment) > 0;
|
||||
+ }
|
||||
+ // Purpur end - Config to allow unsafe enchants
|
||||
|
||||
public ItemEnchantments getEnchantments() {
|
||||
return this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
@@ -1,20 +0,0 @@
|
||||
--- a/net/minecraft/world/item/Items.java
|
||||
+++ b/net/minecraft/world/item/Items.java
|
||||
@@ -367,7 +_,7 @@
|
||||
public static final Item PURPUR_BLOCK = registerBlock(Blocks.PURPUR_BLOCK);
|
||||
public static final Item PURPUR_PILLAR = registerBlock(Blocks.PURPUR_PILLAR);
|
||||
public static final Item PURPUR_STAIRS = registerBlock(Blocks.PURPUR_STAIRS);
|
||||
- public static final Item SPAWNER = registerBlock(Blocks.SPAWNER);
|
||||
+ public static final Item SPAWNER = registerBlock(Blocks.SPAWNER, org.purpurmc.purpur.item.SpawnerItem::new, new Item.Properties().rarity(Rarity.EPIC)); // Purpur - Silk touch spawners
|
||||
public static final Item CREAKING_HEART = registerBlock(Blocks.CREAKING_HEART);
|
||||
public static final Item CHEST = registerBlock(Blocks.CHEST, properties -> properties.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY));
|
||||
public static final Item CRAFTING_TABLE = registerBlock(Blocks.CRAFTING_TABLE);
|
||||
@@ -2010,7 +_,7 @@
|
||||
"sweet_berries", createBlockItemWithCustomItemName(Blocks.SWEET_BERRY_BUSH), new Item.Properties().food(Foods.SWEET_BERRIES)
|
||||
);
|
||||
public static final Item GLOW_BERRIES = registerItem(
|
||||
- "glow_berries", createBlockItemWithCustomItemName(Blocks.CAVE_VINES), new Item.Properties().food(Foods.GLOW_BERRIES)
|
||||
+ "glow_berries", settings -> new org.purpurmc.purpur.item.GlowBerryItem(Blocks.CAVE_VINES, settings.useItemDescriptionPrefix()), new Item.Properties().food(Foods.GLOW_BERRIES) // Purpur - Eating glow berries adds glow effect
|
||||
);
|
||||
public static final Item CAMPFIRE = registerBlock(
|
||||
Blocks.CAMPFIRE, properties -> properties.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY)
|
||||
@@ -1,10 +0,0 @@
|
||||
--- a/net/minecraft/world/item/MapItem.java
|
||||
+++ b/net/minecraft/world/item/MapItem.java
|
||||
@@ -196,6 +_,7 @@
|
||||
public static void renderBiomePreviewMap(ServerLevel serverLevel, ItemStack stack) {
|
||||
MapItemSavedData savedData = getSavedData(stack, serverLevel);
|
||||
if (savedData != null) {
|
||||
+ savedData.isExplorerMap = true; // Purpur - Explorer Map API
|
||||
if (serverLevel.dimension() == savedData.dimension) {
|
||||
int i = 1 << savedData.scale;
|
||||
int i1 = savedData.centerX;
|
||||
@@ -1,10 +0,0 @@
|
||||
--- a/net/minecraft/world/item/NameTagItem.java
|
||||
+++ b/net/minecraft/world/item/NameTagItem.java
|
||||
@@ -24,6 +_,7 @@
|
||||
|
||||
LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle();
|
||||
newEntity.setCustomName(event.getName() != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getName()) : null);
|
||||
+ if (player.level().purpurConfig.armorstandFixNametags && target instanceof net.minecraft.world.entity.decoration.ArmorStand) target.setCustomNameVisible(true); // Purpur - Set name visible when using a Name Tag on an Armor Stand
|
||||
if (event.isPersistent() && newEntity instanceof Mob mob) {
|
||||
// Paper end - Add PlayerNameEntityEvent
|
||||
mob.setPersistenceRequired();
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/item/ProjectileWeaponItem.java
|
||||
+++ b/net/minecraft/world/item/ProjectileWeaponItem.java
|
||||
@@ -108,6 +_,8 @@
|
||||
abstractArrow.setCritArrow(true);
|
||||
}
|
||||
|
||||
+ abstractArrow.setActualEnchantments(weapon.getEnchantments()); // Purpur - Add an option to fix MC-3304 projectile looting
|
||||
+
|
||||
return abstractArrow;
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
--- a/net/minecraft/world/item/ShovelItem.java
|
||||
+++ b/net/minecraft/world/item/ShovelItem.java
|
||||
@@ -47,9 +_,12 @@
|
||||
BlockState blockState1 = FLATTENABLES.get(blockState.getBlock());
|
||||
BlockState blockState2 = null;
|
||||
Runnable afterAction = null; // Paper
|
||||
+ org.purpurmc.purpur.tool.Flattenable flattenable = level.purpurConfig.shovelFlattenables.get(blockState.getBlock()); // Purpur - Tool actionable options
|
||||
if (blockState1 != null && level.getBlockState(clickedPos.above()).isAir()) {
|
||||
- afterAction = () -> level.playSound(player, clickedPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper
|
||||
- blockState2 = blockState1;
|
||||
+ // Purpur start - Tool actionable options
|
||||
+ afterAction = () -> {if (!FLATTENABLES.containsKey(blockState.getBlock())) level.playSound(player, clickedPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F);}; // Paper
|
||||
+ blockState2 = flattenable.into().defaultBlockState();
|
||||
+ // Purpur end - Tool actionable options
|
||||
} else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) {
|
||||
afterAction = () -> { // Paper
|
||||
if (!level.isClientSide()) {
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/item/SnowballItem.java
|
||||
+++ b/net/minecraft/world/item/SnowballItem.java
|
||||
@@ -26,7 +_,7 @@
|
||||
// CraftBukkit start - moved down
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
// Paper start - PlayerLaunchProjectileEvent
|
||||
- final Projectile.Delayed<Snowball> snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, serverLevel, itemInHand, player, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ final Projectile.Delayed<Snowball> snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, serverLevel, itemInHand, player, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.snowballProjectileOffset); // Purpur - Projectile offset config
|
||||
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) snowball.projectile().getBukkitEntity());
|
||||
if (event.callEvent() && snowball.attemptSpawn()) {
|
||||
player.awardStat(Stats.ITEM_USED.get(this));
|
||||
@@ -1,26 +0,0 @@
|
||||
--- a/net/minecraft/world/item/SpawnEggItem.java
|
||||
+++ b/net/minecraft/world/item/SpawnEggItem.java
|
||||
@@ -57,6 +_,23 @@
|
||||
if (level.getBlockEntity(clickedPos) instanceof Spawner spawner) {
|
||||
if (level.paperConfig().entities.spawning.disableMobSpawnerSpawnEggTransformation) return InteractionResult.FAIL; // Paper - Allow disabling mob spawner spawn egg transformation
|
||||
EntityType<?> type = this.getType(level.registryAccess(), itemInHand);
|
||||
+ // Purpur start - PlayerSetSpawnerTypeWithEggEvent
|
||||
+ if (spawner instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity) {
|
||||
+ org.bukkit.block.Block bukkitBlock = level.getWorld().getBlockAt(clickedPos.getX(), clickedPos.getY(), clickedPos.getZ());
|
||||
+ org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent event = new org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.CreatureSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(type.getName()));
|
||||
+ if (!event.callEvent()) {
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ type = EntityType.getFromBukkitType(event.getEntityType());
|
||||
+ } else if (spawner instanceof net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity) {
|
||||
+ org.bukkit.block.Block bukkitBlock = level.getWorld().getBlockAt(clickedPos.getX(), clickedPos.getY(), clickedPos.getZ());
|
||||
+ org.purpurmc.purpur.event.PlayerSetTrialSpawnerTypeWithEggEvent event = new org.purpurmc.purpur.event.PlayerSetTrialSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.TrialSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(type.getName()));
|
||||
+ if (!event.callEvent()) {
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ type = EntityType.getFromBukkitType(event.getEntityType());
|
||||
+ }
|
||||
+ // Purpur end - PlayerSetSpawnerTypeWithEggEvent
|
||||
spawner.setEntityId(type, level.getRandom());
|
||||
level.sendBlockUpdated(clickedPos, blockState, blockState, 3);
|
||||
level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, clickedPos);
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/item/ThrowablePotionItem.java
|
||||
+++ b/net/minecraft/world/item/ThrowablePotionItem.java
|
||||
@@ -23,7 +_,7 @@
|
||||
ItemStack itemInHand = player.getItemInHand(hand);
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
// Paper start - PlayerLaunchProjectileEvent
|
||||
- final Projectile.Delayed<ThrownPotion> thrownPotion = Projectile.spawnProjectileFromRotationDelayed(ThrownPotion::new, serverLevel, itemInHand, player, -20.0F, PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ final Projectile.Delayed<ThrownPotion> thrownPotion = Projectile.spawnProjectileFromRotationDelayed(ThrownPotion::new, serverLevel, itemInHand, player, -20.0F, PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.throwablePotionProjectileOffset); // Purpur - Projectile offset config
|
||||
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownPotion.projectile().getBukkitEntity());
|
||||
if (event.callEvent() && thrownPotion.attemptSpawn()) {
|
||||
if (event.shouldConsume()) {
|
||||
@@ -1,21 +0,0 @@
|
||||
--- a/net/minecraft/world/item/TridentItem.java
|
||||
+++ b/net/minecraft/world/item/TridentItem.java
|
||||
@@ -90,7 +_,7 @@
|
||||
// stack.hurtWithoutBreaking(1, player); // CraftBukkit - moved down
|
||||
if (tridentSpinAttackStrength == 0.0F) {
|
||||
Projectile.Delayed<ThrownTrident> tridentDelayed = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent
|
||||
- ThrownTrident::new, serverLevel, stack, player, 0.0F, 2.5F, 1.0F
|
||||
+ ThrownTrident::new, serverLevel, stack, player, 0.0F, 2.5F, (float) serverLevel.purpurConfig.tridentProjectileOffset // Purpur - Projectile offset config
|
||||
);
|
||||
// Paper start - PlayerLaunchProjectileEvent
|
||||
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity());
|
||||
@@ -101,6 +_,9 @@
|
||||
return false;
|
||||
}
|
||||
ThrownTrident thrownTrident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent
|
||||
+
|
||||
+ thrownTrident.setActualEnchantments(stack.getEnchantments()); // Purpur - Add an option to fix MC-3304 projectile looting
|
||||
+
|
||||
if (event.shouldConsume()) stack.hurtWithoutBreaking(1, player); // Paper - PlayerLaunchProjectileEvent
|
||||
thrownTrident.pickupItemStack = stack.copy(); // SPIGOT-4511 update since damage call moved
|
||||
// CraftBukkit end
|
||||
@@ -1,15 +0,0 @@
|
||||
--- a/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java
|
||||
+++ b/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java
|
||||
@@ -20,6 +_,12 @@
|
||||
@Override
|
||||
// CraftBukkit start
|
||||
public boolean apply(Level level, ItemStack stack, LivingEntity entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) {
|
||||
+ // Purpur start - Option to toggle milk curing bad omen
|
||||
+ net.minecraft.world.effect.MobEffectInstance badOmen = entity.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN);
|
||||
+ if (!level.purpurConfig.milkCuresBadOmen && stack.is(net.minecraft.world.item.Items.MILK_BUCKET) && badOmen != null) {
|
||||
+ return entity.removeAllEffects(cause) && entity.addEffect(badOmen);
|
||||
+ }
|
||||
+ // Purpur end - Option to toggle milk curing bad omen
|
||||
return entity.removeAllEffects(cause);
|
||||
// CraftBukkit end
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
--- a/net/minecraft/world/item/crafting/Ingredient.java
|
||||
+++ b/net/minecraft/world/item/crafting/Ingredient.java
|
||||
@@ -36,6 +_,7 @@
|
||||
// CraftBukkit start
|
||||
@javax.annotation.Nullable
|
||||
private java.util.Set<ItemStack> itemStacks; // Paper - Improve exact choice recipe ingredients
|
||||
+ public Predicate<org.bukkit.inventory.ItemStack> predicate; // Purpur - Add predicate to recipe's ExactChoice ingredient
|
||||
|
||||
public boolean isExact() {
|
||||
return this.itemStacks != null;
|
||||
@@ -87,6 +_,11 @@
|
||||
if (this.isExact()) {
|
||||
return this.itemStacks.contains(stack); // Paper - Improve exact choice recipe ingredients (hashing FTW!)
|
||||
}
|
||||
+ // Purpur start - Add predicate to recipe's ExactChoice ingredient
|
||||
+ if (predicate != null) {
|
||||
+ return predicate.test(stack.asBukkitCopy());
|
||||
+ }
|
||||
+ // Purpur end - Add predicate to recipe's ExactChoice ingredient
|
||||
// CraftBukkit end
|
||||
return stack.is(this.values);
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
--- a/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
||||
+++ b/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
||||
@@ -602,4 +_,58 @@
|
||||
interface EnchantmentVisitor {
|
||||
void accept(Holder<Enchantment> enchantment, int level);
|
||||
}
|
||||
+
|
||||
+ // Purpur start - Enchantment convenience methods
|
||||
+ public static Holder.Reference<Enchantment> getEnchantmentHolder(ResourceKey<Enchantment> enchantment) {
|
||||
+ return net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(enchantment);
|
||||
+ }
|
||||
+
|
||||
+ public static int getItemEnchantmentLevel(ResourceKey<Enchantment> enchantment, ItemStack stack) {
|
||||
+ return getItemEnchantmentLevel(getEnchantmentHolder(enchantment), stack);
|
||||
+ }
|
||||
+ // Purpur end - Enchantment convenience methods
|
||||
+
|
||||
+ // Purpur start - Add option to mend the most damaged equipment first
|
||||
+ public static Optional<EnchantedItemInUse> getMostDamagedItemWith(DataComponentType<?> componentType, LivingEntity entity) {
|
||||
+ ItemStack maxStack = null;
|
||||
+ EquipmentSlot maxSlot = null;
|
||||
+ float maxPercent = 0.0F;
|
||||
+
|
||||
+ equipmentSlotLoop:
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.values()) {
|
||||
+ ItemStack stack = entity.getItemBySlot(equipmentSlot);
|
||||
+
|
||||
+ // do not even check enchantments for item with lower or equal damage percent
|
||||
+ float percent = stack.getDamagePercent();
|
||||
+ if (percent <= maxPercent) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ItemEnchantments itemEnchantments = stack.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
+
|
||||
+ for (Entry<Holder<Enchantment>> entry : itemEnchantments.entrySet()) {
|
||||
+ Enchantment enchantment = entry.getKey().value();
|
||||
+
|
||||
+ net.minecraft.core.component.DataComponentMap effects = enchantment.effects();
|
||||
+ if (!effects.has(componentType)) {
|
||||
+ // try with another enchantment
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (enchantment.matchingSlot(equipmentSlot)) {
|
||||
+ maxStack = stack;
|
||||
+ maxSlot = equipmentSlot;
|
||||
+ maxPercent = percent;
|
||||
+
|
||||
+ // check another slot now
|
||||
+ continue equipmentSlotLoop;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return maxStack != null
|
||||
+ ? Optional.of(new EnchantedItemInUse(maxStack, maxSlot, entity))
|
||||
+ : Optional.empty();
|
||||
+ }
|
||||
+ // Purpur end - Add option to mend the most damaged equipment first
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
--- a/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
||||
+++ b/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
||||
@@ -32,7 +_,7 @@
|
||||
private static final java.util.Comparator<Holder<Enchantment>> ENCHANTMENT_ORDER = java.util.Comparator.comparing(Holder::getRegisteredName);
|
||||
public static final ItemEnchantments EMPTY = new ItemEnchantments(new it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true);
|
||||
// Paper end
|
||||
- private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(1, 255);
|
||||
+ private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(1, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)); // Purpur - Add toggle for enchant level clamping
|
||||
// Paper start - sort enchantments
|
||||
private static final Codec<it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap<Holder<Enchantment>>> LEVELS_CODEC = Codec.unboundedMap(Enchantment.CODEC, LEVEL_CODEC)
|
||||
.xmap(m -> {
|
||||
@@ -65,7 +_,7 @@
|
||||
|
||||
for (Entry<Holder<Enchantment>> entry : enchantments.object2IntEntrySet()) {
|
||||
int intValue = entry.getIntValue();
|
||||
- if (intValue < 0 || intValue > 255) {
|
||||
+ if (intValue < 0 || intValue > (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)) { // Purpur - Add toggle for enchant level clamping
|
||||
throw new IllegalArgumentException("Enchantment " + entry.getKey() + " has invalid level " + intValue);
|
||||
}
|
||||
}
|
||||
@@ -160,13 +_,13 @@
|
||||
if (level <= 0) {
|
||||
this.enchantments.removeInt(enchantment);
|
||||
} else {
|
||||
- this.enchantments.put(enchantment, Math.min(level, 255));
|
||||
+ this.enchantments.put(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767))); // Purpur - Add toggle for enchant level clamping
|
||||
}
|
||||
}
|
||||
|
||||
public void upgrade(Holder<Enchantment> enchantment, int level) {
|
||||
if (level > 0) {
|
||||
- this.enchantments.merge(enchantment, Math.min(level, 255), Integer::max);
|
||||
+ this.enchantments.merge(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)), Integer::max); // Purpur - Add toggle for enchant level clamping
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
--- a/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
+++ b/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
@@ -143,7 +_,12 @@
|
||||
}
|
||||
|
||||
public void updateDemand() {
|
||||
- this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
|
||||
+ // Purpur start - Configurable minimum demand for trades
|
||||
+ this.updateDemand(0);
|
||||
+ }
|
||||
+ public void updateDemand(int minimumDemand) {
|
||||
+ this.demand = Math.max(minimumDemand, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
|
||||
+ // Purpur end - Configurable minimum demand for trades
|
||||
}
|
||||
|
||||
public ItemStack assemble() {
|
||||
Reference in New Issue
Block a user