Move patches to unapplied
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
--- a/net/minecraft/world/item/ArmorStandItem.java
|
||||
+++ b/net/minecraft/world/item/ArmorStandItem.java
|
||||
@@ -53,6 +53,12 @@
|
||||
float f = (float) Mth.floor((Mth.wrapDegrees(context.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F;
|
||||
|
||||
entityarmorstand.moveTo(entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), f, 0.0F);
|
||||
+ // CraftBukkit start
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityarmorstand).isCancelled()) {
|
||||
+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
worldserver.addFreshEntityWithPassengers(entityarmorstand);
|
||||
world.playSound((Player) null, entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F);
|
||||
entityarmorstand.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer());
|
||||
@@ -0,0 +1,14 @@
|
||||
--- a/net/minecraft/world/item/AxeItem.java
|
||||
+++ b/net/minecraft/world/item/AxeItem.java
|
||||
@@ -67,6 +67,11 @@
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
ItemStack itemStack = context.getItemInHand();
|
||||
+ // Paper start - EntityChangeBlockEvent
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, optional.get())) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (player instanceof ServerPlayer) {
|
||||
CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
--- a/net/minecraft/world/item/BlockItem.java
|
||||
+++ b/net/minecraft/world/item/BlockItem.java
|
||||
@@ -10,9 +10,9 @@
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
-import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -31,6 +31,10 @@
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
||||
+import org.bukkit.event.block.BlockCanBuildEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class BlockItem extends Item {
|
||||
|
||||
@@ -62,6 +66,13 @@
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
BlockState iblockdata = this.getPlacementState(blockactioncontext1);
|
||||
+ // CraftBukkit start - special case for handling block placement with water lilies and snow buckets
|
||||
+ org.bukkit.block.BlockState blockstate = null;
|
||||
+ if (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem) {
|
||||
+ blockstate = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos());
|
||||
+ }
|
||||
+ final org.bukkit.block.BlockState oldBlockstate = blockstate != null ? blockstate : org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos()); // Paper - Reset placed block on exception
|
||||
+ // CraftBukkit end
|
||||
|
||||
if (iblockdata == null) {
|
||||
return InteractionResult.FAIL;
|
||||
@@ -76,9 +87,34 @@
|
||||
|
||||
if (iblockdata1.is(iblockdata.getBlock())) {
|
||||
iblockdata1 = this.updateBlockStateFromTag(blockposition, world, itemstack, iblockdata1);
|
||||
+ // Paper start - Reset placed block on exception
|
||||
+ try {
|
||||
this.updateCustomBlockEntityTag(blockposition, world, entityhuman, itemstack, iblockdata1);
|
||||
BlockItem.updateBlockEntityComponents(world, blockposition, itemstack);
|
||||
+ } catch (Exception e) {
|
||||
+ oldBlockstate.update(true, false);
|
||||
+ if (entityhuman instanceof ServerPlayer player) {
|
||||
+ org.apache.logging.log4j.LogManager.getLogger().error("Player {} tried placing invalid block", player.getScoreboardName(), e);
|
||||
+ player.getBukkitEntity().kickPlayer("Packet processing error");
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ throw e; // Rethrow exception if not placed by a player
|
||||
+ }
|
||||
+ // Paper end - Reset placed block on exception
|
||||
iblockdata1.getBlock().setPlacedBy(world, blockposition, iblockdata1, entityhuman, itemstack);
|
||||
+ // CraftBukkit start
|
||||
+ if (blockstate != null) {
|
||||
+ org.bukkit.event.block.BlockPlaceEvent placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent((ServerLevel) world, entityhuman, blockactioncontext1.getHand(), blockstate, blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
|
||||
+ blockstate.update(true, false);
|
||||
+
|
||||
+ if (true) { // Paper - if the event is called here, the inventory should be updated
|
||||
+ ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541
|
||||
+ }
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
if (entityhuman instanceof ServerPlayer) {
|
||||
CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) entityhuman, blockposition, itemstack);
|
||||
}
|
||||
@@ -86,7 +122,7 @@
|
||||
|
||||
SoundType soundeffecttype = iblockdata1.getSoundType();
|
||||
|
||||
- world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F);
|
||||
+ if (entityhuman == null) world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), net.minecraft.sounds.SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); // Paper - Fix block place logic; reintroduce this for the dispenser (i.e the shulker)
|
||||
world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(entityhuman, iblockdata1));
|
||||
itemstack.consume(1, entityhuman);
|
||||
return InteractionResult.SUCCESS;
|
||||
@@ -144,8 +180,16 @@
|
||||
protected boolean canPlace(BlockPlaceContext context, BlockState state) {
|
||||
Player entityhuman = context.getPlayer();
|
||||
CollisionContext voxelshapecollision = entityhuman == null ? CollisionContext.empty() : CollisionContext.of(entityhuman);
|
||||
+ // CraftBukkit start - store default return
|
||||
+ Level world = context.getLevel(); // Paper - Cancel hit for vanished players
|
||||
+ boolean defaultReturn = (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && world.checkEntityCollision(state, entityhuman, voxelshapecollision, context.getClickedPos(), true); // Paper - Cancel hit for vanished players
|
||||
+ org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null;
|
||||
|
||||
- return (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && context.getLevel().isUnobstructed(state, context.getClickedPos(), voxelshapecollision);
|
||||
+ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent
|
||||
+ context.getLevel().getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ return event.isBuildable();
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
protected boolean mustSurvive() {
|
||||
@@ -178,7 +222,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (tileentitytypes1.onlyOpCanSetNbt() && (player == null || !player.canUseGameMasterBlocks())) {
|
||||
+ if (tileentitytypes1.onlyOpCanSetNbt() && (player == null || !(player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place"))))) { // Spigot - add permission
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
--- a/net/minecraft/world/item/BoatItem.java
|
||||
+++ b/net/minecraft/world/item/BoatItem.java
|
||||
@@ -58,6 +58,13 @@
|
||||
}
|
||||
|
||||
if (movingobjectpositionblock.getType() == HitResult.Type.BLOCK) {
|
||||
+ // CraftBukkit start - Boat placement
|
||||
+ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(user, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, movingobjectpositionblock.getBlockPos(), movingobjectpositionblock.getDirection(), itemstack, false, hand, movingobjectpositionblock.getLocation());
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
AbstractBoat abstractboat = this.getBoat(world, movingobjectpositionblock, itemstack, user);
|
||||
|
||||
if (abstractboat == null) {
|
||||
@@ -68,7 +75,15 @@
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
if (!world.isClientSide) {
|
||||
- world.addFreshEntity(abstractboat);
|
||||
+ // CraftBukkit start
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(world, movingobjectpositionblock.getBlockPos(), movingobjectpositionblock.getDirection(), user, abstractboat, hand).isCancelled()) {
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+
|
||||
+ if (!world.addFreshEntity(abstractboat)) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
world.gameEvent((Entity) user, (Holder) GameEvent.ENTITY_PLACE, movingobjectpositionblock.getLocation());
|
||||
itemstack.consume(1, user);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
--- a/net/minecraft/world/item/BoneMealItem.java
|
||||
+++ b/net/minecraft/world/item/BoneMealItem.java
|
||||
@@ -35,24 +35,30 @@
|
||||
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
- Level world = context.getLevel();
|
||||
- BlockPos blockposition = context.getClickedPos();
|
||||
- BlockPos blockposition1 = blockposition.relative(context.getClickedFace());
|
||||
+ // CraftBukkit start - extract bonemeal application logic to separate, static method
|
||||
+ return BoneMealItem.applyBonemeal(context);
|
||||
+ }
|
||||
|
||||
- if (BoneMealItem.growCrop(context.getItemInHand(), world, blockposition)) {
|
||||
+ public static InteractionResult applyBonemeal(UseOnContext itemactioncontext) {
|
||||
+ // CraftBukkit end
|
||||
+ Level world = itemactioncontext.getLevel();
|
||||
+ BlockPos blockposition = itemactioncontext.getClickedPos();
|
||||
+ BlockPos blockposition1 = blockposition.relative(itemactioncontext.getClickedFace());
|
||||
+
|
||||
+ if (BoneMealItem.growCrop(itemactioncontext.getItemInHand(), world, blockposition)) {
|
||||
if (!world.isClientSide) {
|
||||
- context.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
|
||||
+ if (itemactioncontext.getPlayer() != null) itemactioncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518
|
||||
world.levelEvent(1505, blockposition, 15);
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
} else {
|
||||
BlockState iblockdata = world.getBlockState(blockposition);
|
||||
- boolean flag = iblockdata.isFaceSturdy(world, blockposition, context.getClickedFace());
|
||||
+ boolean flag = iblockdata.isFaceSturdy(world, blockposition, itemactioncontext.getClickedFace());
|
||||
|
||||
- if (flag && BoneMealItem.growWaterPlant(context.getItemInHand(), world, blockposition1, context.getClickedFace())) {
|
||||
+ if (flag && BoneMealItem.growWaterPlant(itemactioncontext.getItemInHand(), world, blockposition1, itemactioncontext.getClickedFace())) {
|
||||
if (!world.isClientSide) {
|
||||
- context.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
|
||||
+ if (itemactioncontext.getPlayer() != null) itemactioncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518
|
||||
world.levelEvent(1505, blockposition1, 15);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
--- a/net/minecraft/world/item/BucketItem.java
|
||||
+++ b/net/minecraft/world/item/BucketItem.java
|
||||
@@ -6,6 +6,8 @@
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
+import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
@@ -29,9 +31,17 @@
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.util.DummyGeneratorAccess;
|
||||
+import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
+import org.bukkit.event.player.PlayerBucketFillEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class BucketItem extends Item implements DispensibleContainerItem {
|
||||
|
||||
+ private static @Nullable ItemStack itemLeftInHandAfterPlayerBucketEmptyEvent = null; // Paper - Fix PlayerBucketEmptyEvent result itemstack
|
||||
+
|
||||
public final Fluid content;
|
||||
|
||||
public BucketItem(Fluid fluid, Item.Properties settings) {
|
||||
@@ -63,7 +73,18 @@
|
||||
|
||||
if (block instanceof BucketPickup) {
|
||||
BucketPickup ifluidsource = (BucketPickup) block;
|
||||
+ // CraftBukkit start
|
||||
+ ItemStack dummyFluid = ifluidsource.pickupBlock(user, DummyGeneratorAccess.INSTANCE, blockposition, iblockdata);
|
||||
+ if (dummyFluid.isEmpty()) return InteractionResult.FAIL; // Don't fire event if the bucket won't be filled.
|
||||
+ PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) world, user, blockposition, blockposition, movingobjectpositionblock.getDirection(), itemstack, dummyFluid.getItem(), hand);
|
||||
|
||||
+ if (event.isCancelled()) {
|
||||
+ // ((ServerPlayer) user).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-5163 (see PlayerInteractManager) // Paper - Don't resend blocks
|
||||
+ ((ServerPlayer) user).getBukkitEntity().updateInventory(); // SPIGOT-4541
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
itemstack1 = ifluidsource.pickupBlock(user, world, blockposition, iblockdata);
|
||||
if (!itemstack1.isEmpty()) {
|
||||
user.awardStat(Stats.ITEM_USED.get(this));
|
||||
@@ -71,7 +92,7 @@
|
||||
user.playSound(soundeffect, 1.0F, 1.0F);
|
||||
});
|
||||
world.gameEvent((Entity) user, (Holder) GameEvent.FLUID_PICKUP, blockposition);
|
||||
- ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, user, itemstack1);
|
||||
+ ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, user, CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit
|
||||
|
||||
if (!world.isClientSide) {
|
||||
CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer) user, itemstack1);
|
||||
@@ -86,7 +107,7 @@
|
||||
iblockdata = world.getBlockState(blockposition);
|
||||
BlockPos blockposition2 = iblockdata.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? blockposition : blockposition1;
|
||||
|
||||
- if (this.emptyContents(user, world, blockposition2, movingobjectpositionblock)) {
|
||||
+ if (this.emptyContents(user, world, blockposition2, movingobjectpositionblock, movingobjectpositionblock.getDirection(), blockposition, itemstack, hand)) { // CraftBukkit
|
||||
this.checkExtraContent(user, world, itemstack, blockposition2);
|
||||
if (user instanceof ServerPlayer) {
|
||||
CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) user, blockposition2, itemstack);
|
||||
@@ -106,6 +127,13 @@
|
||||
}
|
||||
|
||||
public static ItemStack getEmptySuccessItem(ItemStack stack, Player player) {
|
||||
+ // Paper start - Fix PlayerBucketEmptyEvent result itemstack
|
||||
+ if (itemLeftInHandAfterPlayerBucketEmptyEvent != null) {
|
||||
+ ItemStack itemInHand = itemLeftInHandAfterPlayerBucketEmptyEvent;
|
||||
+ itemLeftInHandAfterPlayerBucketEmptyEvent = null;
|
||||
+ return itemInHand;
|
||||
+ }
|
||||
+ // Paper end - Fix PlayerBucketEmptyEvent result itemstack
|
||||
return !player.hasInfiniteMaterials() ? new ItemStack(Items.BUCKET) : stack;
|
||||
}
|
||||
|
||||
@@ -114,6 +142,12 @@
|
||||
|
||||
@Override
|
||||
public boolean emptyContents(@Nullable Player player, Level world, BlockPos pos, @Nullable BlockHitResult hitResult) {
|
||||
+ // CraftBukkit start
|
||||
+ return this.emptyContents(player, world, pos, hitResult, null, null, null, InteractionHand.MAIN_HAND);
|
||||
+ }
|
||||
+
|
||||
+ public boolean emptyContents(Player entityhuman, Level world, BlockPos blockposition, @Nullable BlockHitResult movingobjectpositionblock, Direction enumdirection, BlockPos clicked, ItemStack itemstack, InteractionHand enumhand) {
|
||||
+ // CraftBukkit end
|
||||
Fluid fluidtype = this.content;
|
||||
|
||||
if (!(fluidtype instanceof FlowingFluid fluidtypeflowing)) {
|
||||
@@ -126,7 +160,7 @@
|
||||
boolean flag1;
|
||||
label70:
|
||||
{
|
||||
- iblockdata = world.getBlockState(pos);
|
||||
+ iblockdata = world.getBlockState(blockposition);
|
||||
block = iblockdata.getBlock();
|
||||
flag = iblockdata.canBeReplaced(this.content);
|
||||
if (!iblockdata.isAir() && !flag) {
|
||||
@@ -134,7 +168,7 @@
|
||||
{
|
||||
if (block instanceof LiquidBlockContainer) {
|
||||
ifluidcontainer = (LiquidBlockContainer) block;
|
||||
- if (ifluidcontainer.canPlaceLiquid(player, world, pos, iblockdata, this.content)) {
|
||||
+ if (ifluidcontainer.canPlaceLiquid(entityhuman, world, blockposition, iblockdata, this.content)) {
|
||||
break label67;
|
||||
}
|
||||
}
|
||||
@@ -149,14 +183,25 @@
|
||||
|
||||
boolean flag2 = flag1;
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ if (flag2 && entityhuman != null) {
|
||||
+ PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent((ServerLevel) world, entityhuman, blockposition, clicked, enumdirection, itemstack, enumhand);
|
||||
+ if (event.isCancelled()) {
|
||||
+ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity // Paper - Don't resend blocks
|
||||
+ ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541
|
||||
+ return false;
|
||||
+ }
|
||||
+ itemLeftInHandAfterPlayerBucketEmptyEvent = event.getItemStack() != null ? event.getItemStack().equals(CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.BUCKET)) ? null : CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; // Paper - Fix PlayerBucketEmptyEvent result itemstack
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
if (!flag2) {
|
||||
- return hitResult != null && this.emptyContents(player, world, hitResult.getBlockPos().relative(hitResult.getDirection()), (BlockHitResult) null);
|
||||
+ return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit
|
||||
} else if (world.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) {
|
||||
- int i = pos.getX();
|
||||
- int j = pos.getY();
|
||||
- int k = pos.getZ();
|
||||
+ int i = blockposition.getX();
|
||||
+ int j = blockposition.getY();
|
||||
+ int k = blockposition.getZ();
|
||||
|
||||
- world.playSound(player, pos, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F);
|
||||
+ world.playSound(entityhuman, blockposition, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F);
|
||||
|
||||
for (int l = 0; l < 8; ++l) {
|
||||
world.addParticle(ParticleTypes.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D);
|
||||
@@ -167,20 +212,20 @@
|
||||
if (block instanceof LiquidBlockContainer) {
|
||||
ifluidcontainer = (LiquidBlockContainer) block;
|
||||
if (this.content == Fluids.WATER) {
|
||||
- ifluidcontainer.placeLiquid(world, pos, iblockdata, fluidtypeflowing.getSource(false));
|
||||
- this.playEmptySound(player, world, pos);
|
||||
+ ifluidcontainer.placeLiquid(world, blockposition, iblockdata, fluidtypeflowing.getSource(false));
|
||||
+ this.playEmptySound(entityhuman, world, blockposition);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!world.isClientSide && flag && !iblockdata.liquid()) {
|
||||
- world.destroyBlock(pos, true);
|
||||
+ world.destroyBlock(blockposition, true);
|
||||
}
|
||||
|
||||
- if (!world.setBlock(pos, this.content.defaultFluidState().createLegacyBlock(), 11) && !iblockdata.getFluidState().isSource()) {
|
||||
+ if (!world.setBlock(blockposition, this.content.defaultFluidState().createLegacyBlock(), 11) && !iblockdata.getFluidState().isSource()) {
|
||||
return false;
|
||||
} else {
|
||||
- this.playEmptySound(player, world, pos);
|
||||
+ this.playEmptySound(entityhuman, world, blockposition);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
--- a/net/minecraft/world/item/CrossbowItem.java
|
||||
+++ b/net/minecraft/world/item/CrossbowItem.java
|
||||
@@ -90,7 +90,14 @@
|
||||
public boolean releaseUsing(ItemStack stack, Level world, LivingEntity user, int remainingUseTicks) {
|
||||
int i = this.getUseDuration(stack, user) - remainingUseTicks;
|
||||
float f = getPowerForTime(i, stack, user);
|
||||
- if (f >= 1.0F && !isCharged(stack) && tryLoadProjectiles(user, stack)) {
|
||||
+ // Paper start - Add EntityLoadCrossbowEvent
|
||||
+ if (f >= 1.0F && !isCharged(stack)) {
|
||||
+ final io.papermc.paper.event.entity.EntityLoadCrossbowEvent event = new io.papermc.paper.event.entity.EntityLoadCrossbowEvent(user.getBukkitLivingEntity(), stack.asBukkitMirror(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(user.getUsedItemHand()));
|
||||
+ if (!event.callEvent() || !tryLoadProjectiles(user, stack, event.shouldConsumeItem()) || !event.shouldConsumeItem()) {
|
||||
+ if (user instanceof ServerPlayer player) player.containerMenu.sendAllDataToRemote();
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - Add EntityLoadCrossbowEvent
|
||||
CrossbowItem.ChargingSounds chargingSounds = this.getChargingSounds(stack);
|
||||
chargingSounds.end()
|
||||
.ifPresent(
|
||||
@@ -111,8 +118,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
- private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow) {
|
||||
- List<ItemStack> list = draw(crossbow, shooter.getProjectile(crossbow), shooter);
|
||||
+ @io.papermc.paper.annotation.DoNotUse // Paper - Add EntityLoadCrossbowEvent
|
||||
+ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow) {
|
||||
+ // Paper start - Add EntityLoadCrossbowEvent
|
||||
+ return CrossbowItem.tryLoadProjectiles(shooter, crossbow, true);
|
||||
+ }
|
||||
+ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow, boolean consume) {
|
||||
+ List<ItemStack> list = draw(crossbow, shooter.getProjectile(crossbow), shooter, consume);
|
||||
+ // Paper end - Add EntityLoadCrossbowEvent
|
||||
if (!list.isEmpty()) {
|
||||
crossbow.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list));
|
||||
return true;
|
||||
@@ -164,7 +177,11 @@
|
||||
@Override
|
||||
protected Projectile createProjectile(Level world, LivingEntity shooter, ItemStack weaponStack, ItemStack projectileStack, boolean critical) {
|
||||
if (projectileStack.is(Items.FIREWORK_ROCKET)) {
|
||||
- return new FireworkRocketEntity(world, projectileStack, shooter, shooter.getX(), shooter.getEyeY() - 0.15F, shooter.getZ(), true);
|
||||
+ // Paper start
|
||||
+ FireworkRocketEntity entity = new FireworkRocketEntity(world, projectileStack, shooter, shooter.getX(), shooter.getEyeY() - 0.15F, shooter.getZ(), true);
|
||||
+ entity.spawningEntity = shooter.getUUID(); // Paper
|
||||
+ return entity;
|
||||
+ // Paper end
|
||||
} else {
|
||||
Projectile projectile = super.createProjectile(world, shooter, weaponStack, projectileStack, critical);
|
||||
if (projectile instanceof AbstractArrow abstractArrow) {
|
||||
@@ -0,0 +1,25 @@
|
||||
--- a/net/minecraft/world/item/DebugStickItem.java
|
||||
+++ b/net/minecraft/world/item/DebugStickItem.java
|
||||
@@ -1,3 +1,4 @@
|
||||
+// mc-dev import
|
||||
package net.minecraft.world.item;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -52,7 +53,7 @@
|
||||
}
|
||||
|
||||
public boolean handleInteraction(Player player, BlockState state, LevelAccessor world, BlockPos pos, boolean update, ItemStack stack) {
|
||||
- if (!player.canUseGameMasterBlocks()) {
|
||||
+ if (!player.canUseGameMasterBlocks() && !(player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.debugstick")) && !player.getBukkitEntity().hasPermission("minecraft.debugstick.always")) { // Spigot
|
||||
return false;
|
||||
} else {
|
||||
Holder<Block> holder = state.getBlockHolder();
|
||||
@@ -92,7 +93,7 @@
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> BlockState cycleState(BlockState state, Property<T> property, boolean inverse) {
|
||||
- return (BlockState) state.setValue(property, (Comparable) DebugStickItem.getRelative(property.getPossibleValues(), state.getValue(property), inverse));
|
||||
+ return (BlockState) state.setValue(property, DebugStickItem.getRelative(property.getPossibleValues(), state.getValue(property), inverse)); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
private static <T> T getRelative(Iterable<T> elements, @Nullable T current, boolean inverse) {
|
||||
@@ -0,0 +1,29 @@
|
||||
--- a/net/minecraft/world/item/DyeItem.java
|
||||
+++ b/net/minecraft/world/item/DyeItem.java
|
||||
@@ -12,6 +12,7 @@
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||
+import org.bukkit.event.entity.SheepDyeWoolEvent; // CraftBukkit
|
||||
|
||||
public class DyeItem extends Item implements SignApplicator {
|
||||
|
||||
@@ -30,7 +31,17 @@
|
||||
if (entitysheep.isAlive() && !entitysheep.isSheared() && entitysheep.getColor() != this.dyeColor) {
|
||||
entitysheep.level().playSound(user, (Entity) entitysheep, SoundEvents.DYE_USE, SoundSource.PLAYERS, 1.0F, 1.0F);
|
||||
if (!user.level().isClientSide) {
|
||||
- entitysheep.setColor(this.dyeColor);
|
||||
+ // CraftBukkit start
|
||||
+ byte bColor = (byte) this.dyeColor.getId();
|
||||
+ SheepDyeWoolEvent event = new SheepDyeWoolEvent((org.bukkit.entity.Sheep) entitysheep.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData(bColor), (org.bukkit.entity.Player) user.getBukkitEntity());
|
||||
+ entitysheep.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+
|
||||
+ entitysheep.setColor(DyeColor.byId((byte) event.getColor().getWoolData()));
|
||||
+ // CraftBukkit end
|
||||
stack.shrink(1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
--- a/net/minecraft/world/item/EggItem.java
|
||||
+++ b/net/minecraft/world/item/EggItem.java
|
||||
@@ -25,13 +25,32 @@
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
ItemStack itemstack = user.getItemInHand(hand);
|
||||
|
||||
- world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.EGG_THROW, SoundSource.PLAYERS, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ // world.playSound((EntityHuman) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEffects.EGG_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F)); // CraftBukkit - moved down
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
- Projectile.spawnProjectileFromRotation(ThrownEgg::new, worldserver, itemstack, user, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
- }
|
||||
+ // CraftBukkit start
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ final Projectile.Delayed<ThrownEgg> thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, worldserver, itemstack, user, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) thrownEgg.projectile().getBukkitEntity());
|
||||
+ if (event.callEvent() && thrownEgg.attemptSpawn()) {
|
||||
+ if (event.shouldConsume()) {
|
||||
+ itemstack.consume(1, user);
|
||||
+ } else if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
|
||||
- user.awardStat(Stats.ITEM_USED.get(this));
|
||||
- itemstack.consume(1, user);
|
||||
+ world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.EGG_THROW, SoundSource.PLAYERS, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ user.awardStat(Stats.ITEM_USED.get(this));
|
||||
+ } else {
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
+ if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+ world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.EGG_THROW, SoundSource.PLAYERS, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ // Paper - PlayerLaunchProjectileEvent - moved up
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
--- a/net/minecraft/world/item/EndCrystalItem.java
|
||||
+++ b/net/minecraft/world/item/EndCrystalItem.java
|
||||
@@ -30,7 +30,7 @@
|
||||
if (!iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) {
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
- BlockPos blockposition1 = blockposition.above();
|
||||
+ BlockPos blockposition1 = blockposition.above(); final BlockPos aboveBlockPosition = blockposition1; // Paper - OBFHELPER
|
||||
|
||||
if (!world.isEmptyBlock(blockposition1)) {
|
||||
return InteractionResult.FAIL;
|
||||
@@ -47,12 +47,18 @@
|
||||
EndCrystal entityendercrystal = new EndCrystal(world, d0 + 0.5D, d1, d2 + 0.5D);
|
||||
|
||||
entityendercrystal.setShowBottom(false);
|
||||
+ // CraftBukkit start
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityendercrystal).isCancelled()) {
|
||||
+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
world.addFreshEntity(entityendercrystal);
|
||||
world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.ENTITY_PLACE, blockposition1);
|
||||
EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight();
|
||||
|
||||
if (enderdragonbattle != null) {
|
||||
- enderdragonbattle.tryRespawn();
|
||||
+ enderdragonbattle.tryRespawn(aboveBlockPosition); // Paper - Perf: Do crystal-portal proximity check before entity lookup
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
--- a/net/minecraft/world/item/EnderEyeItem.java
|
||||
+++ b/net/minecraft/world/item/EnderEyeItem.java
|
||||
@@ -45,6 +45,11 @@
|
||||
return InteractionResult.SUCCESS;
|
||||
} else {
|
||||
BlockState iblockdata1 = (BlockState) iblockdata.setValue(EndPortalFrameBlock.HAS_EYE, true);
|
||||
+ // Paper start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockposition, iblockdata1)) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
Block.pushEntitiesUp(iblockdata, iblockdata1, world, blockposition);
|
||||
world.setBlock(blockposition, iblockdata1, 2);
|
||||
@@ -62,7 +67,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
- world.globalLevelEvent(1038, blockposition1.offset(1, 0, 1), 0);
|
||||
+ // CraftBukkit start - Use relative location for far away sounds
|
||||
+ // world.globalLevelEvent(1038, blockposition1.offset(1, 0, 1), 0);
|
||||
+ int viewDistance = world.getCraftServer().getViewDistance() * 16;
|
||||
+ BlockPos soundPos = blockposition1.offset(1, 0, 1);
|
||||
+ final net.minecraft.server.level.ServerLevel serverLevel = (net.minecraft.server.level.ServerLevel) world; // Paper - respect global sound events gamerule - ensured by isClientSide check above
|
||||
+ for (ServerPlayer player : serverLevel.getPlayersForGlobalSoundGamerule()) { // Paper - respect global sound events gamerule
|
||||
+ double deltaX = soundPos.getX() - player.getX();
|
||||
+ double deltaZ = soundPos.getZ() - player.getZ();
|
||||
+ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
|
||||
+ final double soundRadiusSquared = serverLevel.getGlobalSoundRangeSquared(config -> config.endPortalSoundRadius); // Paper - respect global sound events gamerule
|
||||
+ if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared) continue; // Spigot // Paper - respect global sound events gamerule
|
||||
+ if (distanceSquared > viewDistance * viewDistance) {
|
||||
+ double deltaLength = Math.sqrt(distanceSquared);
|
||||
+ double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance;
|
||||
+ double relativeZ = player.getZ() + (deltaZ / deltaLength) * viewDistance;
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(1038, new BlockPos((int) relativeX, (int) soundPos.getY(), (int) relativeZ), 0, true));
|
||||
+ } else {
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(1038, soundPos, 0, true));
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
@@ -99,7 +124,11 @@
|
||||
entityendersignal.setItem(itemstack);
|
||||
entityendersignal.signalTo(blockposition);
|
||||
world.gameEvent((Holder) GameEvent.PROJECTILE_SHOOT, entityendersignal.position(), GameEvent.Context.of((Entity) user));
|
||||
- world.addFreshEntity(entityendersignal);
|
||||
+ // CraftBukkit start
|
||||
+ if (!world.addFreshEntity(entityendersignal)) {
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
if (user instanceof ServerPlayer) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) user;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
--- a/net/minecraft/world/item/EnderpearlItem.java
|
||||
+++ b/net/minecraft/world/item/EnderpearlItem.java
|
||||
@@ -23,13 +23,32 @@
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
ItemStack itemstack = user.getItemInHand(hand);
|
||||
|
||||
- world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.ENDER_PEARL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
- Projectile.spawnProjectileFromRotation(ThrownEnderpearl::new, worldserver, itemstack, user, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ // CraftBukkit start
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, worldserver, itemstack, user, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity());
|
||||
+ if (event.callEvent() && thrownEnderpearl.attemptSpawn()) {
|
||||
+ if (event.shouldConsume()) {
|
||||
+ itemstack.consume(1, user);
|
||||
+ } else if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+
|
||||
+ world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.ENDER_PEARL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ user.awardStat(Stats.ITEM_USED.get(this));
|
||||
+ } else {
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
+ if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
}
|
||||
+ world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.ENDER_PEARL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ // CraftBukkit end
|
||||
|
||||
- user.awardStat(Stats.ITEM_USED.get(this));
|
||||
- itemstack.consume(1, user);
|
||||
+ // Paper - PlayerLaunchProjectileEvent - moved up
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
--- a/net/minecraft/world/item/ExperienceBottleItem.java
|
||||
+++ b/net/minecraft/world/item/ExperienceBottleItem.java
|
||||
@@ -21,22 +21,38 @@
|
||||
@Override
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
ItemStack itemStack = user.getItemInHand(hand);
|
||||
- world.playSound(
|
||||
- null,
|
||||
- user.getX(),
|
||||
- user.getY(),
|
||||
- user.getZ(),
|
||||
- SoundEvents.EXPERIENCE_BOTTLE_THROW,
|
||||
- SoundSource.NEUTRAL,
|
||||
- 0.5F,
|
||||
- 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F)
|
||||
- );
|
||||
+ // Paper - PlayerLaunchProjectileEvent - moved down
|
||||
if (world instanceof ServerLevel serverLevel) {
|
||||
- Projectile.spawnProjectileFromRotation(ThrownExperienceBottle::new, serverLevel, itemStack, user, -20.0F, 0.7F, 1.0F);
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ final Projectile.Delayed<ThrownExperienceBottle> thrownExperienceBottle = Projectile.spawnProjectileFromRotationDelayed(ThrownExperienceBottle::new, serverLevel, itemStack, user, -20.0F, 0.7F, 1.0F);
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownExperienceBottle.projectile().getBukkitEntity());
|
||||
+ if (event.callEvent() && thrownExperienceBottle.attemptSpawn()) {
|
||||
+ if (event.shouldConsume()) {
|
||||
+ itemStack.consume(1, user);
|
||||
+ } else if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+
|
||||
+ world.playSound(
|
||||
+ null,
|
||||
+ user.getX(),
|
||||
+ user.getY(),
|
||||
+ user.getZ(),
|
||||
+ SoundEvents.EXPERIENCE_BOTTLE_THROW,
|
||||
+ SoundSource.NEUTRAL,
|
||||
+ 0.5F,
|
||||
+ 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F)
|
||||
+ );
|
||||
+ } else {
|
||||
+ if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
}
|
||||
|
||||
- user.awardStat(Stats.ITEM_USED.get(this));
|
||||
- itemStack.consume(1, user);
|
||||
+ // Paper - PlayerLaunchProjectileEvent - moved up
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
--- a/net/minecraft/world/item/FireChargeItem.java
|
||||
+++ b/net/minecraft/world/item/FireChargeItem.java
|
||||
@@ -40,12 +40,28 @@
|
||||
if (!CampfireBlock.canLight(iblockdata) && !CandleBlock.canLight(iblockdata) && !CandleCakeBlock.canLight(iblockdata)) {
|
||||
blockposition = blockposition.relative(context.getClickedFace());
|
||||
if (BaseFireBlock.canBePlacedAt(world, blockposition, context.getHorizontalDirection())) {
|
||||
+ // CraftBukkit start - fire BlockIgniteEvent
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) {
|
||||
+ if (!context.getPlayer().getAbilities().instabuild) {
|
||||
+ context.getItemInHand().shrink(1);
|
||||
+ }
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
this.playSound(world, blockposition);
|
||||
world.setBlockAndUpdate(blockposition, BaseFireBlock.getState(world, blockposition));
|
||||
world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.BLOCK_PLACE, blockposition);
|
||||
flag = true;
|
||||
}
|
||||
} else {
|
||||
+ // CraftBukkit start - fire BlockIgniteEvent
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) {
|
||||
+ if (!context.getPlayer().getAbilities().instabuild) {
|
||||
+ context.getItemInHand().shrink(1);
|
||||
+ }
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
this.playSound(world, blockposition);
|
||||
world.setBlockAndUpdate(blockposition, (BlockState) iblockdata.setValue(BlockStateProperties.LIT, true));
|
||||
world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.BLOCK_CHANGE, blockposition);
|
||||
@@ -0,0 +1,51 @@
|
||||
--- a/net/minecraft/world/item/FireworkRocketItem.java
|
||||
+++ b/net/minecraft/world/item/FireworkRocketItem.java
|
||||
@@ -33,7 +33,7 @@
|
||||
ItemStack itemStack = context.getItemInHand();
|
||||
Vec3 vec3 = context.getClickLocation();
|
||||
Direction direction = context.getClickedFace();
|
||||
- Projectile.spawnProjectile(
|
||||
+ final Projectile.Delayed<FireworkRocketEntity> fireworkRocketEntity = Projectile.spawnProjectileDelayed( // Paper - PlayerLaunchProjectileEvent
|
||||
new FireworkRocketEntity(
|
||||
level,
|
||||
context.getPlayer(),
|
||||
@@ -43,9 +43,14 @@
|
||||
itemStack
|
||||
),
|
||||
serverLevel,
|
||||
- itemStack
|
||||
+ itemStack, f -> f.spawningEntity = context.getPlayer() == null ? null : context.getPlayer().getUUID() // Paper - firework api - assign spawning entity uuid
|
||||
);
|
||||
- itemStack.shrink(1);
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) fireworkRocketEntity.projectile().getBukkitEntity());
|
||||
+ if (!event.callEvent() || !fireworkRocketEntity.attemptSpawn()) return InteractionResult.PASS;
|
||||
+ if (event.shouldConsume() && !context.getPlayer().hasInfiniteMaterials()) itemStack.shrink(1);
|
||||
+ else if (context.getPlayer() instanceof net.minecraft.server.level.ServerPlayer) ((net.minecraft.server.level.ServerPlayer) context.getPlayer()).getBukkitEntity().updateInventory();
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
@@ -56,9 +61,19 @@
|
||||
if (user.isFallFlying()) {
|
||||
ItemStack itemStack = user.getItemInHand(hand);
|
||||
if (world instanceof ServerLevel serverLevel) {
|
||||
- Projectile.spawnProjectile(new FireworkRocketEntity(world, itemStack, user), serverLevel, itemStack);
|
||||
- itemStack.consume(1, user);
|
||||
- user.awardStat(Stats.ITEM_USED.get(this));
|
||||
+ // Paper start - PlayerElytraBoostEvent
|
||||
+ final Projectile.Delayed<FireworkRocketEntity> delayed = Projectile.spawnProjectileDelayed(new FireworkRocketEntity(world, itemStack, user), serverLevel, itemStack, f -> f.spawningEntity = user.getUUID()); // Paper - firework api - assign spawning entity uuid
|
||||
+ com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) delayed.projectile().getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand));
|
||||
+ if (event.callEvent() && delayed.attemptSpawn()) {
|
||||
+ user.awardStat(Stats.ITEM_USED.get(this)); // Moved up from below
|
||||
+ if (event.shouldConsume() && !user.hasInfiniteMaterials()) {
|
||||
+ itemStack.shrink(1); // Moved up from below
|
||||
+ } else ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ } else {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ // Moved up consume/stat
|
||||
+ // Paper end - PlayerElytraBoostEvent
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
@@ -0,0 +1,50 @@
|
||||
--- a/net/minecraft/world/item/FishingRodItem.java
|
||||
+++ b/net/minecraft/world/item/FishingRodItem.java
|
||||
@@ -14,6 +14,11 @@
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.player.PlayerFishEvent;
|
||||
+import org.bukkit.craftbukkit.CraftEquipmentSlot;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class FishingRodItem extends Item {
|
||||
|
||||
public FishingRodItem(Item.Properties settings) {
|
||||
@@ -26,7 +31,7 @@
|
||||
|
||||
if (user.fishing != null) {
|
||||
if (!world.isClientSide) {
|
||||
- int i = user.fishing.retrieve(itemstack);
|
||||
+ int i = user.fishing.retrieve(hand, itemstack); // Paper - Add hand parameter to PlayerFishEvent
|
||||
|
||||
itemstack.hurtAndBreak(i, user, LivingEntity.getSlotForHand(hand));
|
||||
}
|
||||
@@ -34,13 +39,24 @@
|
||||
world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.FISHING_BOBBER_RETRIEVE, SoundSource.NEUTRAL, 1.0F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
user.gameEvent(GameEvent.ITEM_INTERACT_FINISH);
|
||||
} else {
|
||||
- world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.FISHING_BOBBER_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ // world.playSound((EntityHuman) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEffects.FISHING_BOBBER_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
if (world instanceof ServerLevel) {
|
||||
ServerLevel worldserver = (ServerLevel) world;
|
||||
int j = (int) (EnchantmentHelper.getFishingTimeReduction(worldserver, itemstack, user) * 20.0F);
|
||||
int k = EnchantmentHelper.getFishingLuckBonus(worldserver, itemstack, user);
|
||||
|
||||
- Projectile.spawnProjectile(new FishingHook(user, world, k, j), worldserver, itemstack);
|
||||
+ // CraftBukkit start
|
||||
+ FishingHook entityfishinghook = new FishingHook(user, world, k, j);
|
||||
+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) user.getBukkitEntity(), null, (org.bukkit.entity.FishHook) entityfishinghook.getBukkitEntity(), CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.FISHING);
|
||||
+ world.getCraftServer().getPluginManager().callEvent(playerFishEvent);
|
||||
+
|
||||
+ if (playerFishEvent.isCancelled()) {
|
||||
+ user.fishing = null;
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.FISHING_BOBBER_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ Projectile.spawnProjectile(entityfishinghook, worldserver, itemstack);
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
user.awardStat(Stats.ITEM_USED.get(this));
|
||||
@@ -0,0 +1,28 @@
|
||||
--- a/net/minecraft/world/item/FlintAndSteelItem.java
|
||||
+++ b/net/minecraft/world/item/FlintAndSteelItem.java
|
||||
@@ -37,6 +37,12 @@
|
||||
BlockPos blockposition1 = blockposition.relative(context.getClickedFace());
|
||||
|
||||
if (BaseFireBlock.canBePlacedAt(world, blockposition1, context.getHorizontalDirection())) {
|
||||
+ // CraftBukkit start - Store the clicked block
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition1, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, entityhuman).isCancelled()) {
|
||||
+ context.getItemInHand().hurtAndBreak(1, entityhuman, LivingEntity.getSlotForHand(context.getHand()));
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
world.playSound(entityhuman, blockposition1, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.4F + 0.8F);
|
||||
BlockState iblockdata1 = BaseFireBlock.getState(world, blockposition1);
|
||||
|
||||
@@ -54,6 +60,12 @@
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
} else {
|
||||
+ // CraftBukkit start - Store the clicked block
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, entityhuman).isCancelled()) {
|
||||
+ context.getItemInHand().hurtAndBreak(1, entityhuman, LivingEntity.getSlotForHand(context.getHand()));
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
world.playSound(entityhuman, blockposition, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.4F + 0.8F);
|
||||
world.setBlock(blockposition, (BlockState) iblockdata.setValue(BlockStateProperties.LIT, true), 11);
|
||||
world.gameEvent((Entity) entityhuman, (Holder) GameEvent.BLOCK_CHANGE, blockposition);
|
||||
@@ -0,0 +1,67 @@
|
||||
--- a/net/minecraft/world/item/HangingEntityItem.java
|
||||
+++ b/net/minecraft/world/item/HangingEntityItem.java
|
||||
@@ -19,12 +19,16 @@
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.entity.decoration.Painting;
|
||||
import net.minecraft.world.entity.decoration.PaintingVariant;
|
||||
-import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.bukkit.event.hanging.HangingPlaceEvent;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class HangingEntityItem extends Item {
|
||||
|
||||
private static final Component TOOLTIP_RANDOM_VARIANT = Component.translatable("painting.random").withStyle(ChatFormatting.GRAY);
|
||||
@@ -40,7 +44,7 @@
|
||||
BlockPos blockposition = context.getClickedPos();
|
||||
Direction enumdirection = context.getClickedFace();
|
||||
BlockPos blockposition1 = blockposition.relative(enumdirection);
|
||||
- Player entityhuman = context.getPlayer();
|
||||
+ net.minecraft.world.entity.player.Player entityhuman = context.getPlayer();
|
||||
ItemStack itemstack = context.getItemInHand();
|
||||
|
||||
if (entityhuman != null && !this.mayPlace(entityhuman, enumdirection, itemstack, blockposition1)) {
|
||||
@@ -75,6 +79,19 @@
|
||||
|
||||
if (((HangingEntity) object).survives()) {
|
||||
if (!world.isClientSide) {
|
||||
+ // CraftBukkit start - fire HangingPlaceEvent
|
||||
+ Player who = (context.getPlayer() == null) ? null : (Player) context.getPlayer().getBukkitEntity();
|
||||
+ org.bukkit.block.Block blockClicked = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
+ org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection);
|
||||
+ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand());
|
||||
+
|
||||
+ HangingPlaceEvent event = new HangingPlaceEvent((org.bukkit.entity.Hanging) ((HangingEntity) object).getBukkitEntity(), who, blockClicked, blockFace, hand, org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack));
|
||||
+ world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
((HangingEntity) object).playPlacementSound();
|
||||
world.gameEvent((Entity) entityhuman, (Holder) GameEvent.ENTITY_PLACE, ((HangingEntity) object).position());
|
||||
world.addFreshEntity((Entity) object);
|
||||
@@ -88,7 +105,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- protected boolean mayPlace(Player player, Direction side, ItemStack stack, BlockPos pos) {
|
||||
+ protected boolean mayPlace(net.minecraft.world.entity.player.Player player, Direction side, ItemStack stack, BlockPos pos) {
|
||||
return !side.getAxis().isVertical() && player.mayUseItemAt(pos, side, stack);
|
||||
}
|
||||
|
||||
@@ -102,7 +119,7 @@
|
||||
|
||||
if (!customdata.isEmpty()) {
|
||||
customdata.read(holderlookup_a.createSerializationContext(NbtOps.INSTANCE), Painting.VARIANT_MAP_CODEC).result().ifPresentOrElse((holder) -> {
|
||||
- Optional optional = ((PaintingVariant) holder.value()).title();
|
||||
+ Optional<Component> optional = ((PaintingVariant) holder.value()).title(); // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(tooltip);
|
||||
optional.ifPresent(tooltip::add);
|
||||
@@ -0,0 +1,17 @@
|
||||
--- a/net/minecraft/world/item/HoneycombItem.java
|
||||
+++ b/net/minecraft/world/item/HoneycombItem.java
|
||||
@@ -74,6 +74,14 @@
|
||||
return getWaxed(blockState).map(state -> {
|
||||
Player player = context.getPlayer();
|
||||
ItemStack itemStack = context.getItemInHand();
|
||||
+ // Paper start - EntityChangeBlockEvent
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, state)) {
|
||||
+ if (!player.isCreative()) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ }
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(serverPlayer, blockPos, itemStack);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
--- a/net/minecraft/world/item/ItemCooldowns.java
|
||||
+++ b/net/minecraft/world/item/ItemCooldowns.java
|
||||
@@ -56,6 +56,13 @@
|
||||
}
|
||||
|
||||
public void addCooldown(ResourceLocation groupId, int duration) {
|
||||
+ // Paper start - Item cooldown events
|
||||
+ this.addCooldown(groupId, duration, true);
|
||||
+ }
|
||||
+
|
||||
+ public void addCooldown(ResourceLocation groupId, int duration, boolean callEvent) {
|
||||
+ // Event called in server override
|
||||
+ // Paper end - Item cooldown events
|
||||
this.cooldowns.put(groupId, new ItemCooldowns.CooldownInstance(this.tickCount, this.tickCount + duration));
|
||||
this.onCooldownStarted(groupId, duration);
|
||||
}
|
||||
@@ -0,0 +1,630 @@
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -23,6 +23,7 @@
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.advancements.CriteriaTriggers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.HolderSet;
|
||||
@@ -46,10 +47,12 @@
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
+import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
+import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.stats.Stats;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
@@ -70,7 +73,6 @@
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
-import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.world.inventory.ClickAction;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
@@ -88,26 +90,53 @@
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.item.enchantment.ItemEnchantments;
|
||||
import net.minecraft.world.item.enchantment.Repairable;
|
||||
-import net.minecraft.world.level.ItemLike;
|
||||
-import net.minecraft.world.level.Level;
|
||||
-import net.minecraft.world.level.block.state.BlockState;
|
||||
-import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
||||
import net.minecraft.world.level.saveddata.maps.MapId;
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import java.util.Map;
|
||||
+import java.util.Objects;
|
||||
+import net.minecraft.world.level.ItemLike;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.level.block.BaseEntityBlock;
|
||||
+import net.minecraft.world.level.block.BedBlock;
|
||||
+import net.minecraft.world.level.block.Blocks;
|
||||
+import net.minecraft.world.level.block.SaplingBlock;
|
||||
+import net.minecraft.world.level.block.SignBlock;
|
||||
+import net.minecraft.world.level.block.SoundType;
|
||||
+import net.minecraft.world.level.block.WitherSkullBlock;
|
||||
+import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
+import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||
+import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
||||
+import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
||||
+import net.minecraft.world.level.gameevent.GameEvent;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.TreeType;
|
||||
+import org.bukkit.block.BlockState;
|
||||
+import org.bukkit.craftbukkit.block.CapturedBlockState;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlockState;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.bukkit.event.block.BlockFertilizeEvent;
|
||||
+import org.bukkit.event.player.PlayerItemDamageEvent;
|
||||
+import org.bukkit.event.world.StructureGrowEvent;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public final class ItemStack implements DataComponentHolder {
|
||||
|
||||
private static final List<Component> OP_NBT_WARNING = List.of(Component.translatable("item.op_warning.line1").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), Component.translatable("item.op_warning.line2").withStyle(ChatFormatting.RED), Component.translatable("item.op_warning.line3").withStyle(ChatFormatting.RED));
|
||||
public static final Codec<ItemStack> CODEC = Codec.lazyInitialized(() -> {
|
||||
- return RecordCodecBuilder.create((instance) -> {
|
||||
+ return RecordCodecBuilder.<ItemStack>create((instance) -> { // CraftBukkit - decompile error
|
||||
return instance.group(Item.CODEC.fieldOf("id").forGetter(ItemStack::getItemHolder), ExtraCodecs.intRange(1, 99).fieldOf("count").orElse(1).forGetter(ItemStack::getCount), DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter((itemstack) -> {
|
||||
return itemstack.components.asPatch();
|
||||
})).apply(instance, ItemStack::new);
|
||||
});
|
||||
});
|
||||
public static final Codec<ItemStack> SINGLE_ITEM_CODEC = Codec.lazyInitialized(() -> {
|
||||
- return RecordCodecBuilder.create((instance) -> {
|
||||
+ return RecordCodecBuilder.<ItemStack>create((instance) -> { // CraftBukkit - decompile error
|
||||
return instance.group(Item.CODEC.fieldOf("id").forGetter(ItemStack::getItemHolder), DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter((itemstack) -> {
|
||||
return itemstack.components.asPatch();
|
||||
})).apply(instance, (holder, datacomponentpatch) -> {
|
||||
@@ -132,20 +161,38 @@
|
||||
if (i <= 0) {
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
- Holder<Item> holder = (Holder) null.ITEM_STREAM_CODEC.decode(registryfriendlybytebuf);
|
||||
+ Holder<Item> holder = (Holder) ITEM_STREAM_CODEC.decode(registryfriendlybytebuf); // CraftBukkit - decompile error
|
||||
DataComponentPatch datacomponentpatch = (DataComponentPatch) DataComponentPatch.STREAM_CODEC.decode(registryfriendlybytebuf);
|
||||
|
||||
- return new ItemStack(holder, i, datacomponentpatch);
|
||||
+ // CraftBukkit start
|
||||
+ ItemStack itemstack = new ItemStack(holder, i, datacomponentpatch);
|
||||
+ if (false && !datacomponentpatch.isEmpty()) { // Paper - This is no longer needed with raw NBT being handled in metadata
|
||||
+ CraftItemStack.setItemMeta(itemstack, CraftItemStack.getItemMeta(itemstack));
|
||||
+ }
|
||||
+ return itemstack;
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
|
||||
public void encode(RegistryFriendlyByteBuf registryfriendlybytebuf, ItemStack itemstack) {
|
||||
- if (itemstack.isEmpty()) {
|
||||
+ if (itemstack.isEmpty() || itemstack.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem()
|
||||
registryfriendlybytebuf.writeVarInt(0);
|
||||
} else {
|
||||
registryfriendlybytebuf.writeVarInt(itemstack.getCount());
|
||||
- null.ITEM_STREAM_CODEC.encode(registryfriendlybytebuf, itemstack.getItemHolder());
|
||||
+ // Spigot start - filter
|
||||
+ // itemstack = itemstack.copy();
|
||||
+ // CraftItemStack.setItemMeta(itemstack, CraftItemStack.getItemMeta(itemstack)); // Paper - This is no longer with raw NBT being handled in metadata
|
||||
+ // Spigot end
|
||||
+ ITEM_STREAM_CODEC.encode(registryfriendlybytebuf, itemstack.getItemHolder()); // CraftBukkit - decompile error
|
||||
+ // Paper start - adventure; conditionally render translatable components
|
||||
+ boolean prev = net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.get();
|
||||
+ try {
|
||||
+ net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(true);
|
||||
DataComponentPatch.STREAM_CODEC.encode(registryfriendlybytebuf, itemstack.components.asPatch());
|
||||
+ } finally {
|
||||
+ net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(prev);
|
||||
+ }
|
||||
+ // Paper end - adventure; conditionally render translatable components
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -187,7 +234,7 @@
|
||||
|
||||
return dataresult.isError() ? dataresult.map((unit) -> {
|
||||
return stack;
|
||||
- }) : (stack.getCount() > stack.getMaxStackSize() ? DataResult.error(() -> {
|
||||
+ }) : (stack.getCount() > stack.getMaxStackSize() ? DataResult.<ItemStack>error(() -> { // CraftBukkit - decompile error
|
||||
int i = stack.getCount();
|
||||
|
||||
return "Item stack with stack size of " + i + " was larger than maximum: " + stack.getMaxStackSize();
|
||||
@@ -294,8 +341,9 @@
|
||||
j = itemstack.getMaxStackSize();
|
||||
} while (i <= j);
|
||||
|
||||
+ int finalI = i, finalJ = j; // CraftBukkit - decompile error
|
||||
return DataResult.error(() -> {
|
||||
- return "Item stack with count of " + i + " was larger than maximum: " + j;
|
||||
+ return "Item stack with count of " + finalI + " was larger than maximum: " + finalJ; // CraftBukkit - decompile error
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -370,32 +418,200 @@
|
||||
}
|
||||
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
- Player entityhuman = context.getPlayer();
|
||||
+ net.minecraft.world.entity.player.Player entityhuman = context.getPlayer();
|
||||
BlockPos blockposition = context.getClickedPos();
|
||||
|
||||
if (entityhuman != null && !entityhuman.getAbilities().mayBuild && !this.canPlaceOnBlockInAdventureMode(new BlockInWorld(context.getLevel(), blockposition, false))) {
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
Item item = this.getItem();
|
||||
- InteractionResult enuminteractionresult = item.useOn(context);
|
||||
+ // CraftBukkit start - handle all block place event logic here
|
||||
+ DataComponentPatch oldData = this.components.asPatch();
|
||||
+ int oldCount = this.getCount();
|
||||
+ ServerLevel world = (ServerLevel) context.getLevel();
|
||||
|
||||
+ if (!(item instanceof BucketItem/* || item instanceof SolidBucketItem*/)) { // if not bucket // Paper - Fix cancelled powdered snow bucket placement
|
||||
+ world.captureBlockStates = true;
|
||||
+ // special case bonemeal
|
||||
+ if (item == Items.BONE_MEAL) {
|
||||
+ world.captureTreeGeneration = true;
|
||||
+ }
|
||||
+ }
|
||||
+ InteractionResult enuminteractionresult;
|
||||
+ try {
|
||||
+ enuminteractionresult = item.useOn(context);
|
||||
+ } finally {
|
||||
+ world.captureBlockStates = false;
|
||||
+ }
|
||||
+ DataComponentPatch newData = this.components.asPatch();
|
||||
+ int newCount = this.getCount();
|
||||
+ this.setCount(oldCount);
|
||||
+ this.restorePatch(oldData);
|
||||
+ if (enuminteractionresult.consumesAction() && world.captureTreeGeneration && world.capturedBlockStates.size() > 0) {
|
||||
+ world.captureTreeGeneration = false;
|
||||
+ Location location = CraftLocation.toBukkit(blockposition, world.getWorld());
|
||||
+ TreeType treeType = SaplingBlock.treeType;
|
||||
+ SaplingBlock.treeType = null;
|
||||
+ List<CraftBlockState> blocks = new java.util.ArrayList<>(world.capturedBlockStates.values());
|
||||
+ world.capturedBlockStates.clear();
|
||||
+ StructureGrowEvent structureEvent = null;
|
||||
+ if (treeType != null) {
|
||||
+ boolean isBonemeal = this.getItem() == Items.BONE_MEAL;
|
||||
+ structureEvent = new StructureGrowEvent(location, treeType, isBonemeal, (Player) entityhuman.getBukkitEntity(), (List< BlockState>) (List<? extends BlockState>) blocks);
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent);
|
||||
+ }
|
||||
+
|
||||
+ BlockFertilizeEvent fertilizeEvent = new BlockFertilizeEvent(CraftBlock.at(world, blockposition), (Player) entityhuman.getBukkitEntity(), (List< BlockState>) (List<? extends BlockState>) blocks);
|
||||
+ fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled());
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent);
|
||||
+
|
||||
+ if (!fertilizeEvent.isCancelled()) {
|
||||
+ // Change the stack to its new contents if it hasn't been tampered with.
|
||||
+ if (this.getCount() == oldCount && Objects.equals(this.components.asPatch(), oldData)) {
|
||||
+ this.restorePatch(newData);
|
||||
+ this.setCount(newCount);
|
||||
+ }
|
||||
+ for (CraftBlockState blockstate : blocks) {
|
||||
+ // SPIGOT-7572 - Move fix for SPIGOT-7248 to CapturedBlockState, to allow bees in bee nest
|
||||
+ CapturedBlockState.setBlockState(blockstate);
|
||||
+ world.checkCapturedTreeStateForObserverNotify(blockposition, blockstate); // Paper - notify observers even if grow failed
|
||||
+ }
|
||||
+ entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat
|
||||
+ }
|
||||
+
|
||||
+ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return
|
||||
+ return enuminteractionresult;
|
||||
+ }
|
||||
+ world.captureTreeGeneration = false;
|
||||
+
|
||||
if (entityhuman != null && enuminteractionresult instanceof InteractionResult.Success) {
|
||||
InteractionResult.Success enuminteractionresult_d = (InteractionResult.Success) enuminteractionresult;
|
||||
|
||||
if (enuminteractionresult_d.wasItemInteraction()) {
|
||||
- entityhuman.awardStat(Stats.ITEM_USED.get(item));
|
||||
+ InteractionHand enumhand = context.getHand();
|
||||
+ org.bukkit.event.block.BlockPlaceEvent placeEvent = null;
|
||||
+ List<BlockState> blocks = new java.util.ArrayList<>(world.capturedBlockStates.values());
|
||||
+ world.capturedBlockStates.clear();
|
||||
+ if (blocks.size() > 1) {
|
||||
+ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, enumhand, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
+ } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement
|
||||
+ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, enumhand, blocks.get(0), blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
+ }
|
||||
+
|
||||
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
|
||||
+ enuminteractionresult = InteractionResult.FAIL; // cancel placement
|
||||
+ // PAIL: Remove this when MC-99075 fixed
|
||||
+ placeEvent.getPlayer().updateInventory();
|
||||
+ world.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot
|
||||
+ // revert back all captured blocks
|
||||
+ world.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710
|
||||
+ world.isBlockPlaceCancelled = true; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
||||
+ for (BlockState blockstate : blocks) {
|
||||
+ blockstate.update(true, false);
|
||||
+ }
|
||||
+ world.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
||||
+ world.preventPoiUpdated = false;
|
||||
+
|
||||
+ // Brute force all possible updates
|
||||
+ // Paper start - Don't resync blocks
|
||||
+ // BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition();
|
||||
+ // for (Direction dir : Direction.values()) {
|
||||
+ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir)));
|
||||
+ // }
|
||||
+ // Paper end - Don't resync blocks
|
||||
+ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return
|
||||
+ } else {
|
||||
+ // Change the stack to its new contents if it hasn't been tampered with.
|
||||
+ if (this.getCount() == oldCount && Objects.equals(this.components.asPatch(), oldData)) {
|
||||
+ this.restorePatch(newData);
|
||||
+ this.setCount(newCount);
|
||||
+ }
|
||||
+
|
||||
+ for (Map.Entry<BlockPos, BlockEntity> e : world.capturedTileEntities.entrySet()) {
|
||||
+ world.setBlockEntity(e.getValue());
|
||||
+ }
|
||||
+
|
||||
+ for (BlockState blockstate : blocks) {
|
||||
+ int updateFlag = ((CraftBlockState) blockstate).getFlag();
|
||||
+ net.minecraft.world.level.block.state.BlockState oldBlock = ((CraftBlockState) blockstate).getHandle();
|
||||
+ BlockPos newblockposition = ((CraftBlockState) blockstate).getPosition();
|
||||
+ net.minecraft.world.level.block.state.BlockState block = world.getBlockState(newblockposition);
|
||||
+
|
||||
+ if (!(block.getBlock() instanceof BaseEntityBlock)) { // Containers get placed automatically
|
||||
+ block.onPlace(world, newblockposition, oldBlock, true, context);
|
||||
+ }
|
||||
+
|
||||
+ world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block, world.getBlockState(newblockposition), updateFlag, 512); // send null chunk as chunk.k() returns false by this point
|
||||
+ }
|
||||
+
|
||||
+ if (this.item == Items.WITHER_SKELETON_SKULL) { // Special case skulls to allow wither spawns to be cancelled
|
||||
+ BlockPos bp = blockposition;
|
||||
+ if (!world.getBlockState(blockposition).canBeReplaced()) {
|
||||
+ if (!world.getBlockState(blockposition).isSolid()) {
|
||||
+ bp = null;
|
||||
+ } else {
|
||||
+ bp = bp.relative(context.getClickedFace());
|
||||
+ }
|
||||
+ }
|
||||
+ if (bp != null) {
|
||||
+ BlockEntity te = world.getBlockEntity(bp);
|
||||
+ if (te instanceof SkullBlockEntity) {
|
||||
+ WitherSkullBlock.checkSpawn(world, bp, (SkullBlockEntity) te);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // SPIGOT-4678
|
||||
+ if (this.item instanceof SignItem && SignItem.openSign != null) {
|
||||
+ try {
|
||||
+ if (world.getBlockEntity(SignItem.openSign) instanceof SignBlockEntity tileentitysign) {
|
||||
+ if (world.getBlockState(SignItem.openSign).getBlock() instanceof SignBlock blocksign) {
|
||||
+ blocksign.openTextEdit(entityhuman, tileentitysign, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // Craftbukkit // Paper - Add PlayerOpenSignEvent
|
||||
+ }
|
||||
+ }
|
||||
+ } finally {
|
||||
+ SignItem.openSign = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // SPIGOT-7315: Moved from BlockBed#setPlacedBy
|
||||
+ if (placeEvent != null && this.item instanceof BedItem) {
|
||||
+ BlockPos position = ((CraftBlock) placeEvent.getBlock()).getPosition();
|
||||
+ net.minecraft.world.level.block.state.BlockState blockData = world.getBlockState(position);
|
||||
+
|
||||
+ if (blockData.getBlock() instanceof BedBlock) {
|
||||
+ world.blockUpdated(position, Blocks.AIR);
|
||||
+ blockData.updateNeighbourShapes(world, position, 3);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // SPIGOT-1288 - play sound stripped from ItemBlock
|
||||
+ if (this.item instanceof BlockItem) {
|
||||
+ // Paper start - Fix spigot sound playing for BlockItem ItemStacks
|
||||
+ BlockPos position = new net.minecraft.world.item.context.BlockPlaceContext(context).getClickedPos();
|
||||
+ net.minecraft.world.level.block.state.BlockState blockData = world.getBlockState(position);
|
||||
+ SoundType soundeffecttype = blockData.getSoundType();
|
||||
+ // Paper end - Fix spigot sound playing for BlockItem ItemStacks
|
||||
+ world.playSound(entityhuman, blockposition, soundeffecttype.getPlaceSound(), SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F);
|
||||
+ }
|
||||
+
|
||||
+ entityhuman.awardStat(Stats.ITEM_USED.get(item));
|
||||
+ }
|
||||
}
|
||||
}
|
||||
+ world.capturedTileEntities.clear();
|
||||
+ world.capturedBlockStates.clear();
|
||||
+ // CraftBukkit end
|
||||
|
||||
return enuminteractionresult;
|
||||
}
|
||||
}
|
||||
|
||||
- public float getDestroySpeed(BlockState state) {
|
||||
+ public float getDestroySpeed(net.minecraft.world.level.block.state.BlockState state) {
|
||||
return this.getItem().getDestroySpeed(this, state);
|
||||
}
|
||||
|
||||
- public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
+ public InteractionResult use(Level world, net.minecraft.world.entity.player.Player user, InteractionHand hand) {
|
||||
ItemStack itemstack = this.copy();
|
||||
boolean flag = this.getUseDuration(user) <= 0;
|
||||
InteractionResult enuminteractionresult = this.getItem().use(world, user, hand);
|
||||
@@ -490,27 +706,66 @@
|
||||
return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage() - 1;
|
||||
}
|
||||
|
||||
- public void hurtAndBreak(int amount, ServerLevel world, @Nullable ServerPlayer player, Consumer<Item> breakCallback) {
|
||||
- int j = this.processDurabilityChange(amount, world, player);
|
||||
+ public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer<Item> breakCallback) { // Paper - Add EntityDamageItemEvent
|
||||
+ // Paper start - add force boolean overload
|
||||
+ this.hurtAndBreak(amount, world, player, breakCallback, false);
|
||||
+ }
|
||||
+ public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer<Item> breakCallback, boolean force) { // Paper - Add EntityDamageItemEvent
|
||||
+ // Paper end
|
||||
+ int originalDamage = amount; // Paper - Expand PlayerItemDamageEvent
|
||||
+ int j = this.processDurabilityChange(amount, world, player, force); // Paper
|
||||
+ // CraftBukkit start
|
||||
+ if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent
|
||||
+ PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j, originalDamage); // Paper - Add EntityDamageItemEvent
|
||||
+ event.getPlayer().getServer().getPluginManager().callEvent(event);
|
||||
|
||||
+ if (j != event.getDamage() || event.isCancelled()) {
|
||||
+ event.getPlayer().updateInventory();
|
||||
+ }
|
||||
+ if (event.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ j = event.getDamage();
|
||||
+ // Paper start - Add EntityDamageItemEvent
|
||||
+ } else if (player != null) {
|
||||
+ io.papermc.paper.event.entity.EntityDamageItemEvent event = new io.papermc.paper.event.entity.EntityDamageItemEvent(player.getBukkitLivingEntity(), CraftItemStack.asCraftMirror(this), amount);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ j = event.getDamage();
|
||||
+ // Paper end - Add EntityDamageItemEvent
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
if (j != 0) {
|
||||
this.applyDamage(this.getDamageValue() + j, player, breakCallback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable ServerPlayer player) {
|
||||
- return !this.isDamageableItem() ? 0 : (player != null && player.hasInfiniteMaterials() ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage));
|
||||
+ private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable LivingEntity player) { // Paper - Add EntityDamageItemEvent
|
||||
+ // Paper start - itemstack damage api
|
||||
+ return processDurabilityChange(baseDamage, world, player, false);
|
||||
}
|
||||
+ private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable LivingEntity player, boolean force) {
|
||||
+ return !this.isDamageableItem() ? 0 : (player instanceof ServerPlayer && player.hasInfiniteMaterials() && !force ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage)); // Paper - Add EntityDamageItemEvent
|
||||
+ // Paper end - itemstack damage api
|
||||
+ }
|
||||
|
||||
- private void applyDamage(int damage, @Nullable ServerPlayer player, Consumer<Item> breakCallback) {
|
||||
- if (player != null) {
|
||||
- CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(player, this, damage);
|
||||
+ private void applyDamage(int damage, @Nullable LivingEntity player, Consumer<Item> breakCallback) { // Paper - Add EntityDamageItemEvent
|
||||
+ if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent
|
||||
+ CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(serverPlayer, this, damage); // Paper - Add EntityDamageItemEvent
|
||||
}
|
||||
|
||||
this.setDamageValue(damage);
|
||||
if (this.isBroken()) {
|
||||
Item item = this.getItem();
|
||||
+ // CraftBukkit start - Check for item breaking
|
||||
+ if (this.count == 1 && player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(serverPlayer, this); // Paper - Add EntityDamageItemEvent
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
|
||||
this.shrink(1);
|
||||
breakCallback.accept(item);
|
||||
@@ -518,7 +773,7 @@
|
||||
|
||||
}
|
||||
|
||||
- public void hurtWithoutBreaking(int amount, Player player) {
|
||||
+ public void hurtWithoutBreaking(int amount, net.minecraft.world.entity.player.Player player) {
|
||||
if (player instanceof ServerPlayer entityplayer) {
|
||||
int j = this.processDurabilityChange(amount, entityplayer.serverLevel(), entityplayer);
|
||||
|
||||
@@ -535,6 +790,11 @@
|
||||
}
|
||||
|
||||
public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot) {
|
||||
+ // Paper start - add param to skip infinite mats check
|
||||
+ this.hurtAndBreak(amount, entity, slot, false);
|
||||
+ }
|
||||
+ public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot, boolean force) {
|
||||
+ // Paper end - add param to skip infinite mats check
|
||||
Level world = entity.level();
|
||||
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
@@ -546,9 +806,9 @@
|
||||
entityplayer = null;
|
||||
}
|
||||
|
||||
- this.hurtAndBreak(amount, worldserver, entityplayer, (item) -> {
|
||||
- entity.onEquippedItemBroken(item, slot);
|
||||
- });
|
||||
+ this.hurtAndBreak(amount, worldserver, entity, (item) -> { // Paper - Add EntityDamageItemEvent
|
||||
+ if (slot != null) entity.onEquippedItemBroken(item, slot); // Paper - itemstack damage API - do not process entity related callbacks when damaging from API
|
||||
+ }, force); // Paper - itemstack damage API
|
||||
}
|
||||
|
||||
}
|
||||
@@ -580,11 +840,11 @@
|
||||
return this.getItem().getBarColor(this);
|
||||
}
|
||||
|
||||
- public boolean overrideStackedOnOther(Slot slot, ClickAction clickType, Player player) {
|
||||
+ public boolean overrideStackedOnOther(Slot slot, ClickAction clickType, net.minecraft.world.entity.player.Player player) {
|
||||
return this.getItem().overrideStackedOnOther(this, slot, clickType, player);
|
||||
}
|
||||
|
||||
- public boolean overrideOtherStackedOnMe(ItemStack stack, Slot slot, ClickAction clickType, Player player, SlotAccess cursorStackReference) {
|
||||
+ public boolean overrideOtherStackedOnMe(ItemStack stack, Slot slot, ClickAction clickType, net.minecraft.world.entity.player.Player player, SlotAccess cursorStackReference) {
|
||||
return this.getItem().overrideOtherStackedOnMe(this, stack, slot, clickType, player, cursorStackReference);
|
||||
}
|
||||
|
||||
@@ -592,8 +852,8 @@
|
||||
Item item = this.getItem();
|
||||
|
||||
if (item.hurtEnemy(this, target, user)) {
|
||||
- if (user instanceof Player) {
|
||||
- Player entityhuman = (Player) user;
|
||||
+ if (user instanceof net.minecraft.world.entity.player.Player) {
|
||||
+ net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) user;
|
||||
|
||||
entityhuman.awardStat(Stats.ITEM_USED.get(item));
|
||||
}
|
||||
@@ -608,7 +868,7 @@
|
||||
this.getItem().postHurtEnemy(this, target, user);
|
||||
}
|
||||
|
||||
- public void mineBlock(Level world, BlockState state, BlockPos pos, Player miner) {
|
||||
+ public void mineBlock(Level world, net.minecraft.world.level.block.state.BlockState state, BlockPos pos, net.minecraft.world.entity.player.Player miner) {
|
||||
Item item = this.getItem();
|
||||
|
||||
if (item.mineBlock(this, world, state, pos, miner)) {
|
||||
@@ -617,11 +877,11 @@
|
||||
|
||||
}
|
||||
|
||||
- public boolean isCorrectToolForDrops(BlockState state) {
|
||||
+ public boolean isCorrectToolForDrops(net.minecraft.world.level.block.state.BlockState state) {
|
||||
return this.getItem().isCorrectToolForDrops(this, state);
|
||||
}
|
||||
|
||||
- public InteractionResult interactLivingEntity(Player user, LivingEntity entity, InteractionHand hand) {
|
||||
+ public InteractionResult interactLivingEntity(net.minecraft.world.entity.player.Player user, LivingEntity entity, InteractionHand hand) {
|
||||
return this.getItem().interactLivingEntity(this, user, entity, hand);
|
||||
}
|
||||
|
||||
@@ -736,7 +996,7 @@
|
||||
|
||||
}
|
||||
|
||||
- public void onCraftedBy(Level world, Player player, int amount) {
|
||||
+ public void onCraftedBy(Level world, net.minecraft.world.entity.player.Player player, int amount) {
|
||||
player.awardStat(Stats.ITEM_CRAFTED.get(this.getItem()), amount);
|
||||
this.getItem().onCraftedBy(this, world, player);
|
||||
}
|
||||
@@ -768,7 +1028,13 @@
|
||||
|
||||
public boolean useOnRelease() {
|
||||
return this.getItem().useOnRelease(this);
|
||||
+ }
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ public void restorePatch(DataComponentPatch datacomponentpatch) {
|
||||
+ this.components.restorePatch(datacomponentpatch);
|
||||
}
|
||||
+ // CraftBukkit end
|
||||
|
||||
@Nullable
|
||||
public <T> T set(DataComponentType<? super T> type, @Nullable T value) {
|
||||
@@ -805,6 +1071,25 @@
|
||||
this.getItem().verifyComponentsAfterLoad(this);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start - (this is just a good no conflict location)
|
||||
+ public org.bukkit.inventory.ItemStack asBukkitMirror() {
|
||||
+ return CraftItemStack.asCraftMirror(this);
|
||||
+ }
|
||||
+ public org.bukkit.inventory.ItemStack asBukkitCopy() {
|
||||
+ return CraftItemStack.asCraftMirror(this.copy());
|
||||
+ }
|
||||
+ public static ItemStack fromBukkitCopy(org.bukkit.inventory.ItemStack itemstack) {
|
||||
+ return CraftItemStack.asNMSCopy(itemstack);
|
||||
+ }
|
||||
+ private org.bukkit.craftbukkit.inventory.CraftItemStack bukkitStack;
|
||||
+ public org.bukkit.inventory.ItemStack getBukkitStack() {
|
||||
+ if (bukkitStack == null || bukkitStack.handle != this) {
|
||||
+ bukkitStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this);
|
||||
+ }
|
||||
+ return bukkitStack;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public void applyComponents(DataComponentPatch changes) {
|
||||
this.components.applyPatch(changes);
|
||||
@@ -858,7 +1143,7 @@
|
||||
}
|
||||
|
||||
private <T extends TooltipProvider> void addToTooltip(DataComponentType<T> componentType, Item.TooltipContext context, Consumer<Component> textConsumer, TooltipFlag type) {
|
||||
- T t0 = (TooltipProvider) this.get(componentType);
|
||||
+ T t0 = (T) this.get(componentType); // CraftBukkit - decompile error
|
||||
|
||||
if (t0 != null) {
|
||||
t0.addToTooltip(context, textConsumer, type);
|
||||
@@ -866,7 +1151,7 @@
|
||||
|
||||
}
|
||||
|
||||
- public List<Component> getTooltipLines(Item.TooltipContext context, @Nullable Player player, TooltipFlag type) {
|
||||
+ public List<Component> getTooltipLines(Item.TooltipContext context, @Nullable net.minecraft.world.entity.player.Player player, TooltipFlag type) {
|
||||
boolean flag = this.getItem().shouldPrintOpWarning(this, player);
|
||||
|
||||
if (!type.isCreative() && this.has(DataComponents.HIDE_TOOLTIP)) {
|
||||
@@ -941,7 +1226,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- private void addAttributeTooltips(Consumer<Component> textConsumer, @Nullable Player player) {
|
||||
+ private void addAttributeTooltips(Consumer<Component> textConsumer, @Nullable net.minecraft.world.entity.player.Player player) {
|
||||
ItemAttributeModifiers itemattributemodifiers = (ItemAttributeModifiers) this.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY);
|
||||
|
||||
if (itemattributemodifiers.showInTooltip()) {
|
||||
@@ -966,7 +1251,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- private void addModifierTooltip(Consumer<Component> textConsumer, @Nullable Player player, Holder<Attribute> attribute, AttributeModifier modifier) {
|
||||
+ private void addModifierTooltip(Consumer<Component> textConsumer, @Nullable net.minecraft.world.entity.player.Player player, Holder<Attribute> attribute, AttributeModifier modifier) {
|
||||
double d0 = modifier.amount();
|
||||
boolean flag = false;
|
||||
|
||||
@@ -1091,6 +1376,19 @@
|
||||
EnchantmentHelper.forEachModifier(this, slot, attributeModifierConsumer);
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ @Deprecated
|
||||
+ public void setItem(Item item) {
|
||||
+ this.bukkitStack = null; // Paper
|
||||
+ this.item = item;
|
||||
+ // Paper start - change base component prototype
|
||||
+ final DataComponentPatch patch = this.getComponentsPatch();
|
||||
+ this.components = new PatchedDataComponentMap(this.item.components());
|
||||
+ this.applyComponents(patch);
|
||||
+ // Paper end - change base component prototype
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public Component getDisplayName() {
|
||||
MutableComponent ichatmutablecomponent = Component.empty().append(this.getHoverName());
|
||||
|
||||
@@ -1153,7 +1451,7 @@
|
||||
}
|
||||
|
||||
public void consume(int amount, @Nullable LivingEntity entity) {
|
||||
- if (entity == null || !entity.hasInfiniteMaterials()) {
|
||||
+ if ((entity == null || !entity.hasInfiniteMaterials()) && this != ItemStack.EMPTY) { // CraftBukkit
|
||||
this.shrink(amount);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
--- a/net/minecraft/world/item/ItemUtils.java
|
||||
+++ b/net/minecraft/world/item/ItemUtils.java
|
||||
@@ -41,7 +41,15 @@
|
||||
public static void onContainerDestroyed(ItemEntity itemEntity, Iterable<ItemStack> contents) {
|
||||
Level level = itemEntity.level();
|
||||
if (!level.isClientSide) {
|
||||
- contents.forEach(stack -> level.addFreshEntity(new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack)));
|
||||
+ // Paper start - call EntityDropItemEvent
|
||||
+ contents.forEach(stack -> {
|
||||
+ ItemEntity droppedItem = new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack);
|
||||
+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(itemEntity.getBukkitEntity(), (org.bukkit.entity.Item) droppedItem.getBukkitEntity());
|
||||
+ if (event.callEvent()) {
|
||||
+ level.addFreshEntity(droppedItem);
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - call EntityDropItemEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
--- a/net/minecraft/world/item/LeadItem.java
|
||||
+++ b/net/minecraft/world/item/LeadItem.java
|
||||
@@ -18,6 +18,11 @@
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.CraftEquipmentSlot;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.event.hanging.HangingPlaceEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class LeadItem extends Item {
|
||||
|
||||
@@ -35,37 +40,70 @@
|
||||
Player entityhuman = context.getPlayer();
|
||||
|
||||
if (!world.isClientSide && entityhuman != null) {
|
||||
- return LeadItem.bindPlayerMobs(entityhuman, world, blockposition);
|
||||
+ return LeadItem.bindPlayerMobs(entityhuman, world, blockposition, context.getHand()); // CraftBukkit - Pass hand
|
||||
}
|
||||
}
|
||||
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
- public static InteractionResult bindPlayerMobs(Player player, Level world, BlockPos pos) {
|
||||
+ public static InteractionResult bindPlayerMobs(Player entityhuman, Level world, BlockPos blockposition, net.minecraft.world.InteractionHand enumhand) { // CraftBukkit - Add EnumHand
|
||||
LeashFenceKnotEntity entityleash = null;
|
||||
- List<Leashable> list = LeadItem.leashableInArea(world, pos, (leashable) -> {
|
||||
- return leashable.getLeashHolder() == player;
|
||||
+ List<Leashable> list = LeadItem.leashableInArea(world, blockposition, (leashable) -> {
|
||||
+ return leashable.getLeashHolder() == entityhuman;
|
||||
});
|
||||
|
||||
Leashable leashable;
|
||||
|
||||
- for (Iterator iterator = list.iterator(); iterator.hasNext(); leashable.setLeashedTo(entityleash, true)) {
|
||||
+ for (Iterator iterator = list.iterator(); iterator.hasNext();) { // CraftBukkit - handle setLeashedTo at end of loop
|
||||
leashable = (Leashable) iterator.next();
|
||||
if (entityleash == null) {
|
||||
- entityleash = LeashFenceKnotEntity.getOrCreateKnot(world, pos);
|
||||
+ entityleash = LeashFenceKnotEntity.getOrCreateKnot(world, blockposition);
|
||||
+
|
||||
+ // CraftBukkit start - fire HangingPlaceEvent
|
||||
+ org.bukkit.inventory.EquipmentSlot hand = CraftEquipmentSlot.getHand(enumhand);
|
||||
+ HangingPlaceEvent event = new HangingPlaceEvent((org.bukkit.entity.Hanging) entityleash.getBukkitEntity(), entityhuman != null ? (org.bukkit.entity.Player) entityhuman.getBukkitEntity() : null, CraftBlock.at(world, blockposition), org.bukkit.block.BlockFace.SELF, hand);
|
||||
+ world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ entityleash.discard(null); // CraftBukkit - add Bukkit remove cause
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
entityleash.playPlacementSound();
|
||||
}
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ if (leashable instanceof Entity leashed) {
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(leashed, entityleash, entityhuman, enumhand).isCancelled()) {
|
||||
+ iterator.remove();
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ leashable.setLeashedTo(entityleash, true);
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
- world.gameEvent((Holder) GameEvent.BLOCK_ATTACH, pos, GameEvent.Context.of((Entity) player));
|
||||
+ world.gameEvent((Holder) GameEvent.BLOCK_ATTACH, blockposition, GameEvent.Context.of((Entity) entityhuman));
|
||||
return InteractionResult.SUCCESS_SERVER;
|
||||
} else {
|
||||
+ // CraftBukkit start- remove leash if we do not leash any entity because of the cancelled event
|
||||
+ if (entityleash != null) {
|
||||
+ entityleash.discard(null);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ public static InteractionResult bindPlayerMobs(Player player, Level world, BlockPos pos) {
|
||||
+ return LeadItem.bindPlayerMobs(player, world, pos, net.minecraft.world.InteractionHand.MAIN_HAND);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static List<Leashable> leashableInArea(Level world, BlockPos pos, Predicate<Leashable> predicate) {
|
||||
double d0 = 7.0D;
|
||||
int i = pos.getX();
|
||||
@@ -0,0 +1,21 @@
|
||||
--- a/net/minecraft/world/item/LingeringPotionItem.java
|
||||
+++ b/net/minecraft/world/item/LingeringPotionItem.java
|
||||
@@ -24,6 +24,10 @@
|
||||
|
||||
@Override
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ final InteractionResult wrapper = super.use(world, user, hand);
|
||||
+ if (wrapper instanceof InteractionResult.Fail) return wrapper;
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
world.playSound(
|
||||
null,
|
||||
user.getX(),
|
||||
@@ -34,6 +38,6 @@
|
||||
0.5F,
|
||||
0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F)
|
||||
);
|
||||
- return super.use(world, user, hand);
|
||||
+ return wrapper; // Paper - PlayerLaunchProjectileEvent
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
--- a/net/minecraft/world/item/MapItem.java
|
||||
+++ b/net/minecraft/world/item/MapItem.java
|
||||
@@ -97,8 +97,8 @@
|
||||
int r = (j / i + o - 64) * i;
|
||||
int s = (k / i + p - 64) * i;
|
||||
Multiset<MapColor> multiset = LinkedHashMultiset.create();
|
||||
- LevelChunk levelChunk = world.getChunk(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s));
|
||||
- if (!levelChunk.isEmpty()) {
|
||||
+ LevelChunk levelChunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); // Paper - Maps shouldn't load chunks
|
||||
+ if (levelChunk != null && !levelChunk.isEmpty()) { // Paper - Maps shouldn't load chunks
|
||||
int t = 0;
|
||||
double e = 0.0;
|
||||
if (world.dimensionType().hasCeiling()) {
|
||||
@@ -205,7 +205,7 @@
|
||||
|
||||
for (int n = 0; n < 128; n++) {
|
||||
for (int o = 0; o < 128; o++) {
|
||||
- Holder<Biome> holder = world.getBiome(mutableBlockPos.set((l + o) * i, 0, (m + n) * i));
|
||||
+ Holder<Biome> holder = world.getUncachedNoiseBiome((l + o) * i, 0, (m + n) * i); // Paper - Perf: Use seed based lookup for treasure maps
|
||||
bls[n * 128 + o] = holder.is(BiomeTags.WATER_ON_MAP_OUTLINES);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
--- a/net/minecraft/world/item/MinecartItem.java
|
||||
+++ b/net/minecraft/world/item/MinecartItem.java
|
||||
@@ -67,7 +67,13 @@
|
||||
if (world instanceof ServerLevel) {
|
||||
ServerLevel worldserver = (ServerLevel) world;
|
||||
|
||||
- worldserver.addFreshEntity(entityminecartabstract);
|
||||
+ // CraftBukkit start
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityminecartabstract).isCancelled()) {
|
||||
+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ if (!worldserver.addFreshEntity(entityminecartabstract)) return InteractionResult.PASS; // CraftBukkit
|
||||
worldserver.gameEvent((Holder) GameEvent.ENTITY_PLACE, blockposition, GameEvent.Context.of(context.getPlayer(), worldserver.getBlockState(blockposition.below())));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
--- a/net/minecraft/world/item/NameTagItem.java
|
||||
+++ b/net/minecraft/world/item/NameTagItem.java
|
||||
@@ -18,8 +18,13 @@
|
||||
Component component = stack.get(DataComponents.CUSTOM_NAME);
|
||||
if (component != null && entity.getType().canSerialize() && entity.canBeNameTagged()) {
|
||||
if (!user.level().isClientSide && entity.isAlive()) {
|
||||
- entity.setCustomName(component);
|
||||
- if (entity instanceof Mob mob) {
|
||||
+ // Paper start - Add PlayerNameEntityEvent
|
||||
+ io.papermc.paper.event.player.PlayerNameEntityEvent event = new io.papermc.paper.event.player.PlayerNameEntityEvent(((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity(), entity.getBukkitLivingEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(stack.getHoverName()), true);
|
||||
+ if (!event.callEvent()) return InteractionResult.PASS;
|
||||
+ 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 (event.isPersistent() && newEntity instanceof Mob mob) {
|
||||
+ // Paper end - Add PlayerNameEntityEvent
|
||||
mob.setPersistenceRequired();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
--- a/net/minecraft/world/item/PotionItem.java
|
||||
+++ b/net/minecraft/world/item/PotionItem.java
|
||||
@@ -42,6 +42,12 @@
|
||||
PotionContents potionContents = itemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
|
||||
BlockState blockState = level.getBlockState(blockPos);
|
||||
if (context.getClickedFace() != Direction.DOWN && blockState.is(BlockTags.CONVERTABLE_TO_MUD) && potionContents.is(Potions.WATER)) {
|
||||
+ // Paper start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, Blocks.MUD.defaultBlockState())) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // Paper end
|
||||
level.playSound(null, blockPos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
player.setItemInHand(context.getHand(), ItemUtils.createFilledResult(itemStack, player, new ItemStack(Items.GLASS_BOTTLE)));
|
||||
player.awardStat(Stats.ITEM_USED.get(itemStack.getItem()));
|
||||
@@ -0,0 +1,52 @@
|
||||
--- a/net/minecraft/world/item/ProjectileWeaponItem.java
|
||||
+++ b/net/minecraft/world/item/ProjectileWeaponItem.java
|
||||
@@ -54,9 +54,25 @@
|
||||
float f6 = f4 + f5 * (float) ((i + 1) / 2) * f3;
|
||||
|
||||
f5 = -f5;
|
||||
- Projectile.spawnProjectile(this.createProjectile(world, shooter, stack, itemstack1, critical), world, itemstack1, (iprojectile) -> {
|
||||
- this.shootProjectile(shooter, iprojectile, i, speed, divergence, f6, target);
|
||||
- });
|
||||
+ // CraftBukkit start
|
||||
+ Projectile iprojectile = this.createProjectile(world, shooter, stack, itemstack1, critical);
|
||||
+ this.shootProjectile(shooter, iprojectile, i, speed, divergence, f6, target);
|
||||
+
|
||||
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, stack, itemstack1, iprojectile, hand, speed, true);
|
||||
+ if (event.isCancelled()) {
|
||||
+ event.getProjectile().remove();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (event.getProjectile() == iprojectile.getBukkitEntity()) {
|
||||
+ if (Projectile.spawnProjectile(iprojectile, world, itemstack1).isRemoved()) {
|
||||
+ if (shooter instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) shooter).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
stack.hurtAndBreak(this.getDurabilityUse(itemstack1), shooter, LivingEntity.getSlotForHand(hand));
|
||||
if (stack.isEmpty()) {
|
||||
break;
|
||||
@@ -93,6 +109,11 @@
|
||||
}
|
||||
|
||||
protected static List<ItemStack> draw(ItemStack stack, ItemStack projectileStack, LivingEntity shooter) {
|
||||
+ // Paper start
|
||||
+ return draw(stack, projectileStack, shooter, true);
|
||||
+ }
|
||||
+ protected static List<ItemStack> draw(ItemStack stack, ItemStack projectileStack, LivingEntity shooter, boolean consume) {
|
||||
+ // Paper end
|
||||
if (projectileStack.isEmpty()) {
|
||||
return List.of();
|
||||
} else {
|
||||
@@ -112,7 +133,7 @@
|
||||
ItemStack itemstack2 = projectileStack.copy();
|
||||
|
||||
for (int k = 0; k < j; ++k) {
|
||||
- ItemStack itemstack3 = ProjectileWeaponItem.useAmmo(stack, k == 0 ? projectileStack : itemstack2, shooter, k > 0);
|
||||
+ ItemStack itemstack3 = ProjectileWeaponItem.useAmmo(stack, k == 0 ? projectileStack : itemstack2, shooter, k > 0 || !consume); // Paper
|
||||
|
||||
if (!itemstack3.isEmpty()) {
|
||||
list.add(itemstack3);
|
||||
@@ -0,0 +1,43 @@
|
||||
--- a/net/minecraft/world/item/ServerItemCooldowns.java
|
||||
+++ b/net/minecraft/world/item/ServerItemCooldowns.java
|
||||
@@ -11,7 +11,40 @@
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
+ // Paper start - Add PlayerItemCooldownEvent
|
||||
@Override
|
||||
+ public void addCooldown(ItemStack item, int duration) {
|
||||
+ final ResourceLocation cooldownGroup = this.getCooldownGroup(item);
|
||||
+ final io.papermc.paper.event.player.PlayerItemCooldownEvent event = new io.papermc.paper.event.player.PlayerItemCooldownEvent(
|
||||
+ this.player.getBukkitEntity(),
|
||||
+ org.bukkit.craftbukkit.inventory.CraftItemType.minecraftToBukkit(item.getItem()),
|
||||
+ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(cooldownGroup),
|
||||
+ duration
|
||||
+ );
|
||||
+ if (event.callEvent()) {
|
||||
+ super.addCooldown(cooldownGroup, event.getCooldown(), false);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void addCooldown(ResourceLocation groupId, int duration, boolean callEvent) {
|
||||
+ if (callEvent) {
|
||||
+ final io.papermc.paper.event.player.PlayerItemGroupCooldownEvent event = new io.papermc.paper.event.player.PlayerItemGroupCooldownEvent(
|
||||
+ this.player.getBukkitEntity(),
|
||||
+ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(groupId),
|
||||
+ duration
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ duration = event.getCooldown();
|
||||
+ }
|
||||
+ super.addCooldown(groupId, duration, false);
|
||||
+ }
|
||||
+ // Paper end - Add PlayerItemCooldownEvent
|
||||
+
|
||||
+ @Override
|
||||
protected void onCooldownStarted(ResourceLocation groupId, int duration) {
|
||||
super.onCooldownStarted(groupId, duration);
|
||||
this.player.connection.send(new ClientboundCooldownPacket(groupId, duration));
|
||||
@@ -0,0 +1,33 @@
|
||||
--- a/net/minecraft/world/item/ShovelItem.java
|
||||
+++ b/net/minecraft/world/item/ShovelItem.java
|
||||
@@ -46,20 +46,29 @@
|
||||
Player player = context.getPlayer();
|
||||
BlockState blockState2 = FLATTENABLES.get(blockState.getBlock());
|
||||
BlockState blockState3 = null;
|
||||
+ Runnable afterAction = null; // Paper
|
||||
if (blockState2 != null && level.getBlockState(blockPos.above()).isAir()) {
|
||||
- level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
+ afterAction = () -> level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper
|
||||
blockState3 = blockState2;
|
||||
} else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) {
|
||||
+ afterAction = () -> { // Paper
|
||||
if (!level.isClientSide()) {
|
||||
level.levelEvent(null, 1009, blockPos, 0);
|
||||
}
|
||||
|
||||
CampfireBlock.dowse(context.getPlayer(), level, blockPos, blockState);
|
||||
+ }; // Paper
|
||||
blockState3 = blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false));
|
||||
}
|
||||
|
||||
if (blockState3 != null) {
|
||||
if (!level.isClientSide) {
|
||||
+ // Paper start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockPos, blockState3)) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ afterAction.run();
|
||||
+ // Paper end
|
||||
level.setBlock(blockPos, blockState3, 11);
|
||||
level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, blockState3));
|
||||
if (player != null) {
|
||||
@@ -0,0 +1,23 @@
|
||||
--- a/net/minecraft/world/item/SignItem.java
|
||||
+++ b/net/minecraft/world/item/SignItem.java
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
public class SignItem extends StandingAndWallBlockItem {
|
||||
|
||||
+ public static BlockPos openSign; // CraftBukkit
|
||||
+
|
||||
public SignItem(Block standingBlock, Block wallBlock, Item.Properties settings) {
|
||||
super(standingBlock, wallBlock, Direction.DOWN, settings);
|
||||
}
|
||||
@@ -35,7 +37,10 @@
|
||||
if (block instanceof SignBlock) {
|
||||
SignBlock blocksign = (SignBlock) block;
|
||||
|
||||
- blocksign.openTextEdit(player, tileentitysign, true);
|
||||
+ // CraftBukkit start - SPIGOT-4678
|
||||
+ // blocksign.openTextEdit(entityhuman, tileentitysign, true);
|
||||
+ SignItem.openSign = pos;
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
--- a/net/minecraft/world/item/SnowballItem.java
|
||||
+++ b/net/minecraft/world/item/SnowballItem.java
|
||||
@@ -25,13 +25,30 @@
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
ItemStack itemstack = user.getItemInHand(hand);
|
||||
|
||||
- world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.SNOWBALL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ // CraftBukkit start - moved down
|
||||
+ // world.playSound((EntityHuman) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEffects.SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
- Projectile.spawnProjectileFromRotation(Snowball::new, worldserver, itemstack, user, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ final Projectile.Delayed<Snowball> snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, worldserver, itemstack, user, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) snowball.projectile().getBukkitEntity());
|
||||
+ if (event.callEvent() && snowball.attemptSpawn()) {
|
||||
+ user.awardStat(Stats.ITEM_USED.get(this));
|
||||
+ if (event.shouldConsume()) {
|
||||
+ itemstack.consume(1, user);
|
||||
+ } else if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
+
|
||||
+ world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.SNOWBALL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
||||
+ } else { if (user instanceof net.minecraft.server.level.ServerPlayer) { // Paper - PlayerLaunchProjectileEvent - return fail
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ } return InteractionResult.FAIL; } // Paper - PlayerLaunchProjectileEvent - return fail
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
- user.awardStat(Stats.ITEM_USED.get(this));
|
||||
- itemstack.consume(1, user);
|
||||
+ // Paper - PlayerLaunchProjectileEvent - moved up
|
||||
+ // itemstack.consume(1, entityhuman); // CraftBukkit - moved up
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
--- a/net/minecraft/world/item/SpawnEggItem.java
|
||||
+++ b/net/minecraft/world/item/SpawnEggItem.java
|
||||
@@ -63,6 +63,8 @@
|
||||
EntityType entitytypes;
|
||||
|
||||
if (tileentity instanceof Spawner) {
|
||||
+ if (world.paperConfig().entities.spawning.disableMobSpawnerSpawnEggTransformation) return InteractionResult.FAIL; // Paper - Allow disabling mob spawner spawn egg transformation
|
||||
+
|
||||
Spawner spawner = (Spawner) tileentity;
|
||||
|
||||
entitytypes = this.getType(world.registryAccess(), itemstack);
|
||||
@@ -176,10 +178,10 @@
|
||||
return Optional.empty();
|
||||
} else {
|
||||
((Mob) object).moveTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F);
|
||||
- world.addFreshEntityWithPassengers((Entity) object);
|
||||
+ world.addFreshEntityWithPassengers((Entity) object, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // CraftBukkit
|
||||
((Mob) object).setCustomName((Component) stack.get(DataComponents.CUSTOM_NAME));
|
||||
stack.consume(1, user);
|
||||
- return Optional.of(object);
|
||||
+ return Optional.of((Mob) object); // CraftBukkit - decompile error
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
--- a/net/minecraft/world/item/SplashPotionItem.java
|
||||
+++ b/net/minecraft/world/item/SplashPotionItem.java
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
@Override
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ final InteractionResult wrapper = super.use(world, user, hand);
|
||||
+ if (wrapper instanceof InteractionResult.Fail) return wrapper;
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
world.playSound(
|
||||
null,
|
||||
user.getX(),
|
||||
@@ -24,6 +28,6 @@
|
||||
0.5F,
|
||||
0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F)
|
||||
);
|
||||
- return super.use(world, user, hand);
|
||||
+ return wrapper; // Paper - PlayerLaunchProjectileEvent
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
--- a/net/minecraft/world/item/StandingAndWallBlockItem.java
|
||||
+++ b/net/minecraft/world/item/StandingAndWallBlockItem.java
|
||||
@@ -4,12 +4,17 @@
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
||||
+import org.bukkit.event.block.BlockCanBuildEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class StandingAndWallBlockItem extends BlockItem {
|
||||
|
||||
@@ -49,7 +54,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
- return iblockdata1 != null && world.isUnobstructed(iblockdata1, blockposition, CollisionContext.empty()) ? iblockdata1 : null;
|
||||
+ // CraftBukkit start
|
||||
+ if (iblockdata1 != null) {
|
||||
+ boolean defaultReturn = world.isUnobstructed(iblockdata1, blockposition, CollisionContext.empty());
|
||||
+ org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null;
|
||||
+
|
||||
+ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(world, blockposition), player, CraftBlockData.fromData(iblockdata1), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent
|
||||
+ context.getLevel().getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ return (event.isBuildable()) ? iblockdata1 : null;
|
||||
+ } else {
|
||||
+ return null;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,34 @@
|
||||
--- a/net/minecraft/world/item/ThrowablePotionItem.java
|
||||
+++ b/net/minecraft/world/item/ThrowablePotionItem.java
|
||||
@@ -22,11 +22,28 @@
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
ItemStack itemStack = user.getItemInHand(hand);
|
||||
if (world instanceof ServerLevel serverLevel) {
|
||||
- Projectile.spawnProjectileFromRotation(ThrownPotion::new, serverLevel, itemStack, user, -20.0F, PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ final Projectile.Delayed<ThrownPotion> thrownPotion = Projectile.spawnProjectileFromRotationDelayed(ThrownPotion::new, serverLevel, itemStack, user, -20.0F, PROJECTILE_SHOOT_POWER, 1.0F);
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownPotion.projectile().getBukkitEntity());
|
||||
+ if (event.callEvent() && thrownPotion.attemptSpawn()) {
|
||||
+ if (event.shouldConsume()) {
|
||||
+ itemStack.consume(1, user);
|
||||
+ } else if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+
|
||||
+ user.awardStat(Stats.ITEM_USED.get(this));
|
||||
+ } else {
|
||||
+ if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
}
|
||||
|
||||
- user.awardStat(Stats.ITEM_USED.get(this));
|
||||
- itemStack.consume(1, user);
|
||||
+ // Paper - PlayerLaunchProjectileEvent - move up
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
--- a/net/minecraft/world/item/TridentItem.java
|
||||
+++ b/net/minecraft/world/item/TridentItem.java
|
||||
@@ -86,18 +86,37 @@
|
||||
if (world instanceof ServerLevel) {
|
||||
ServerLevel worldserver = (ServerLevel) world;
|
||||
|
||||
- stack.hurtWithoutBreaking(1, entityhuman);
|
||||
+ // itemstack.hurtWithoutBreaking(1, entityhuman); // CraftBukkit - moved down
|
||||
if (f == 0.0F) {
|
||||
- ThrownTrident entitythrowntrident = (ThrownTrident) Projectile.spawnProjectileFromRotation(ThrownTrident::new, worldserver, stack, entityhuman, 0.0F, 2.5F, 1.0F);
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ Projectile.Delayed<ThrownTrident> tridentDelayed = Projectile.spawnProjectileFromRotationDelayed(ThrownTrident::new, worldserver, stack, entityhuman, 0.0F, 2.5F, 1.0F);
|
||||
+ // Paper start - PlayerLaunchProjectileEvent
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity());
|
||||
+ if (!event.callEvent() || !tridentDelayed.attemptSpawn()) {
|
||||
+ // CraftBukkit start
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
+ if (entityhuman instanceof net.minecraft.server.level.ServerPlayer) {
|
||||
+ ((net.minecraft.server.level.ServerPlayer) entityhuman).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ ThrownTrident entitythrowntrident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent
|
||||
+ if (event.shouldConsume()) stack.hurtWithoutBreaking(1, entityhuman); // Paper - PlayerLaunchProjectileEvent
|
||||
+ entitythrowntrident.pickupItemStack = stack.copy(); // SPIGOT-4511 update since damage call moved
|
||||
+ // CraftBukkit end
|
||||
|
||||
if (entityhuman.hasInfiniteMaterials()) {
|
||||
entitythrowntrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
|
||||
- } else {
|
||||
+ } else if (event.shouldConsume()) { // Paper - PlayerLaunchProjectileEvent
|
||||
entityhuman.getInventory().removeItem(stack);
|
||||
}
|
||||
|
||||
world.playSound((Player) null, (Entity) entitythrowntrident, (SoundEvent) holder.value(), SoundSource.PLAYERS, 1.0F, 1.0F);
|
||||
return true;
|
||||
+ // CraftBukkit start - SPIGOT-5458 also need in this branch :(
|
||||
+ } else {
|
||||
+ stack.hurtWithoutBreaking(1, entityhuman);
|
||||
+ // CraftBukkkit end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +131,7 @@
|
||||
f3 *= f / f6;
|
||||
f4 *= f / f6;
|
||||
f5 *= f / f6;
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(entityhuman, stack, f3, f4, f5); // CraftBukkit
|
||||
entityhuman.push((double) f3, (double) f4, (double) f5);
|
||||
entityhuman.startAutoSpinAttack(20, 8.0F, stack);
|
||||
if (entityhuman.onGround()) {
|
||||
@@ -0,0 +1,42 @@
|
||||
--- a/net/minecraft/world/item/WindChargeItem.java
|
||||
+++ b/net/minecraft/world/item/WindChargeItem.java
|
||||
@@ -27,7 +27,7 @@
|
||||
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
||||
ItemStack itemStack = user.getItemInHand(hand);
|
||||
if (world instanceof ServerLevel serverLevel) {
|
||||
- Projectile.spawnProjectileFromRotation(
|
||||
+ final Projectile.Delayed<WindCharge> windCharge = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent
|
||||
(world2, shooter, stack) -> new WindCharge(user, world, user.position().x(), user.getEyePosition().y(), user.position().z()),
|
||||
serverLevel,
|
||||
itemStack,
|
||||
@@ -36,6 +36,21 @@
|
||||
PROJECTILE_SHOOT_POWER,
|
||||
1.0F
|
||||
);
|
||||
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) windCharge.projectile().getBukkitEntity());
|
||||
+ if (!event.callEvent() || !windCharge.attemptSpawn()) {
|
||||
+ user.containerMenu.sendAllDataToRemote();
|
||||
+ if (user instanceof net.minecraft.server.level.ServerPlayer player) {
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(user.getCooldowns().getCooldownGroup(itemStack), 0)); // prevent visual desync of cooldown on the slot
|
||||
+ }
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+
|
||||
+ user.awardStat(Stats.ITEM_USED.get(this));
|
||||
+ if (event.shouldConsume()) itemStack.consume(1, user);
|
||||
+ else if (!user.hasInfiniteMaterials()) {
|
||||
+ user.containerMenu.sendAllDataToRemote();
|
||||
+ }
|
||||
+ // Paper end - PlayerLaunchProjectileEvent
|
||||
}
|
||||
|
||||
world.playSound(
|
||||
@@ -48,8 +63,6 @@
|
||||
0.5F,
|
||||
0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F)
|
||||
);
|
||||
- user.awardStat(Stats.ITEM_USED.get(this));
|
||||
- itemStack.consume(1, user);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/item/WrittenBookItem.java
|
||||
+++ b/net/minecraft/world/item/WrittenBookItem.java
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
public static boolean resolveBookComponents(ItemStack book, CommandSourceStack commandSource, @Nullable Player player) {
|
||||
WrittenBookContent writtenBookContent = book.get(DataComponents.WRITTEN_BOOK_CONTENT);
|
||||
- if (writtenBookContent != null && !writtenBookContent.resolved()) {
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && writtenBookContent != null && !writtenBookContent.resolved()) { // Paper - Disable component selector resolving in books by default
|
||||
WrittenBookContent writtenBookContent2 = writtenBookContent.resolve(commandSource, player);
|
||||
if (writtenBookContent2 != null) {
|
||||
book.set(DataComponents.WRITTEN_BOOK_CONTENT, writtenBookContent2);
|
||||
@@ -0,0 +1,96 @@
|
||||
--- a/net/minecraft/world/item/alchemy/PotionBrewing.java
|
||||
+++ b/net/minecraft/world/item/alchemy/PotionBrewing.java
|
||||
@@ -19,6 +19,7 @@
|
||||
private final List<Ingredient> containers;
|
||||
private final List<PotionBrewing.Mix<Potion>> potionMixes;
|
||||
private final List<PotionBrewing.Mix<Item>> containerMixes;
|
||||
+ private final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<org.bukkit.NamespacedKey, io.papermc.paper.potion.PaperPotionMix> customMixes = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper - Custom Potion Mixes
|
||||
|
||||
PotionBrewing(List<Ingredient> potionTypes, List<PotionBrewing.Mix<Potion>> potionRecipes, List<PotionBrewing.Mix<Item>> itemRecipes) {
|
||||
this.containers = potionTypes;
|
||||
@@ -27,7 +28,7 @@
|
||||
}
|
||||
|
||||
public boolean isIngredient(ItemStack stack) {
|
||||
- return this.isContainerIngredient(stack) || this.isPotionIngredient(stack);
|
||||
+ return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || this.isCustomIngredient(stack); // Paper - Custom Potion Mixes
|
||||
}
|
||||
|
||||
private boolean isContainer(ItemStack stack) {
|
||||
@@ -71,6 +72,11 @@
|
||||
}
|
||||
|
||||
public boolean hasMix(ItemStack input, ItemStack ingredient) {
|
||||
+ // Paper start - Custom Potion Mixes
|
||||
+ if (this.hasCustomMix(input, ingredient)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - Custom Potion Mixes
|
||||
return this.isContainer(input) && (this.hasContainerMix(input, ingredient) || this.hasPotionMix(input, ingredient));
|
||||
}
|
||||
|
||||
@@ -103,6 +109,13 @@
|
||||
if (input.isEmpty()) {
|
||||
return input;
|
||||
} else {
|
||||
+ // Paper start - Custom Potion Mixes
|
||||
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
|
||||
+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) {
|
||||
+ return mix.result().copy();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Custom Potion Mixes
|
||||
Optional<Holder<Potion>> optional = input.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion();
|
||||
if (optional.isEmpty()) {
|
||||
return input;
|
||||
@@ -190,6 +203,50 @@
|
||||
builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING);
|
||||
}
|
||||
|
||||
+ // Paper start - Custom Potion Mixes
|
||||
+ public boolean isCustomIngredient(ItemStack stack) {
|
||||
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
|
||||
+ if (mix.ingredient().test(stack)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ public boolean isCustomInput(ItemStack stack) {
|
||||
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
|
||||
+ if (mix.input().test(stack)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private boolean hasCustomMix(ItemStack input, ItemStack ingredient) {
|
||||
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
|
||||
+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ public void addPotionMix(io.papermc.paper.potion.PotionMix mix) {
|
||||
+ if (this.customMixes.containsKey(mix.getKey())) {
|
||||
+ throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey());
|
||||
+ }
|
||||
+ this.customMixes.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix));
|
||||
+ }
|
||||
+
|
||||
+ public boolean removePotionMix(org.bukkit.NamespacedKey key) {
|
||||
+ return this.customMixes.remove(key) != null;
|
||||
+ }
|
||||
+
|
||||
+ public PotionBrewing reload(FeatureFlagSet flags) {
|
||||
+ return bootstrap(flags);
|
||||
+ }
|
||||
+ // Paper end - Custom Potion Mixes
|
||||
+
|
||||
public static class Builder {
|
||||
private final List<Ingredient> containers = new ArrayList<>();
|
||||
private final List<PotionBrewing.Mix<Potion>> potionMixes = new ArrayList<>();
|
||||
@@ -0,0 +1,20 @@
|
||||
--- a/net/minecraft/world/item/alchemy/PotionContents.java
|
||||
+++ b/net/minecraft/world/item/alchemy/PotionContents.java
|
||||
@@ -93,7 +93,7 @@
|
||||
}
|
||||
|
||||
public PotionContents withEffectAdded(MobEffectInstance customEffect) {
|
||||
- return new PotionContents(this.potion, this.customColor, Util.copyAndAdd(this.customEffects, (Object) customEffect), this.customName);
|
||||
+ return new PotionContents(this.potion, this.customColor, Util.copyAndAdd(this.customEffects, customEffect), this.customName); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
@@ -172,7 +172,7 @@
|
||||
if (((MobEffect) mobeffect.getEffect().value()).isInstantenous()) {
|
||||
((MobEffect) mobeffect.getEffect().value()).applyInstantenousEffect(worldserver, entityhuman2, entityhuman2, user, mobeffect.getAmplifier(), 1.0D);
|
||||
} else {
|
||||
- user.addEffect(mobeffect);
|
||||
+ user.addEffect(mobeffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_DRINK); // CraftBukkit
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
--- a/net/minecraft/world/item/component/Consumable.java
|
||||
+++ b/net/minecraft/world/item/component/Consumable.java
|
||||
@@ -29,6 +29,11 @@
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import net.minecraft.world.item.Items;
|
||||
+import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public record Consumable(float consumeSeconds, ItemUseAnimation animation, Holder<SoundEvent> sound, boolean hasConsumeParticles, List<ConsumeEffect> onConsumeEffects) {
|
||||
|
||||
public static final float DEFAULT_CONSUME_SECONDS = 1.6F;
|
||||
@@ -69,8 +74,19 @@
|
||||
consumablelistener.onConsume(world, user, stack, this);
|
||||
});
|
||||
if (!world.isClientSide) {
|
||||
+ // CraftBukkit start
|
||||
+ EntityPotionEffectEvent.Cause cause;
|
||||
+ if (stack.is(Items.MILK_BUCKET)) {
|
||||
+ cause = EntityPotionEffectEvent.Cause.MILK;
|
||||
+ } else if (stack.is(Items.POTION)) {
|
||||
+ cause = EntityPotionEffectEvent.Cause.POTION_DRINK;
|
||||
+ } else {
|
||||
+ cause = EntityPotionEffectEvent.Cause.FOOD;
|
||||
+ }
|
||||
+
|
||||
this.onConsumeEffects.forEach((consumeeffect) -> {
|
||||
- consumeeffect.apply(world, stack, user);
|
||||
+ consumeeffect.apply(world, stack, user, cause);
|
||||
+ // CraftBukkit end
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,6 +95,17 @@
|
||||
return stack;
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {
|
||||
+ final java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packets = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // Paper - properly resend entities - collect packets for bundle
|
||||
+ itemstack.getAllOfType(ConsumableListener.class).forEach((consumablelistener) -> {
|
||||
+ consumablelistener.cancelUsingItem(entityplayer, itemstack, packets); // Paper - properly resend entities - collect packets for bundle
|
||||
+ });
|
||||
+ entityplayer.server.getPlayerList().sendActiveEffects(entityplayer, packets::add); // Paper - properly resend entities - collect packets for bundle
|
||||
+ entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(packets));
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public boolean canConsume(LivingEntity user, ItemStack stack) {
|
||||
FoodProperties foodinfo = (FoodProperties) stack.get(DataComponents.FOOD);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
--- a/net/minecraft/world/item/component/ConsumableListener.java
|
||||
+++ b/net/minecraft/world/item/component/ConsumableListener.java
|
||||
@@ -7,4 +7,6 @@
|
||||
public interface ConsumableListener {
|
||||
|
||||
void onConsume(Level world, LivingEntity user, ItemStack stack, Consumable consumable);
|
||||
+
|
||||
+ default void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) {} // CraftBukkit // Paper - properly resend entities - collect packets for bundle
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
--- a/net/minecraft/world/item/component/CustomData.java
|
||||
+++ b/net/minecraft/world/item/component/CustomData.java
|
||||
@@ -34,7 +34,17 @@
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final CustomData EMPTY = new CustomData(new CompoundTag());
|
||||
private static final String TYPE_TAG = "id";
|
||||
- public static final Codec<CustomData> CODEC = Codec.withAlternative(CompoundTag.CODEC, TagParser.AS_CODEC)
|
||||
+ // Paper start - Item serialization as json
|
||||
+ public static ThreadLocal<Boolean> SERIALIZE_CUSTOM_AS_SNBT = ThreadLocal.withInitial(() -> false);
|
||||
+ public static final Codec<CustomData> CODEC = Codec.either(CompoundTag.CODEC, TagParser.AS_CODEC)
|
||||
+ .xmap(com.mojang.datafixers.util.Either::unwrap, data -> { // Both will be used for deserialization, but we decide which one to use for serialization
|
||||
+ if (!SERIALIZE_CUSTOM_AS_SNBT.get()) {
|
||||
+ return com.mojang.datafixers.util.Either.left(data); // First codec
|
||||
+ } else {
|
||||
+ return com.mojang.datafixers.util.Either.right(data); // Second codec
|
||||
+ }
|
||||
+ })
|
||||
+ // Paper end - Item serialization as json
|
||||
.xmap(CustomData::new, component -> component.tag);
|
||||
public static final Codec<CustomData> CODEC_WITH_ID = CODEC.validate(
|
||||
component -> component.getUnsafe().contains("id", 8) ? DataResult.success(component) : DataResult.error(() -> "Missing id for entity in: " + component)
|
||||
@@ -0,0 +1,22 @@
|
||||
--- a/net/minecraft/world/item/component/DeathProtection.java
|
||||
+++ b/net/minecraft/world/item/component/DeathProtection.java
|
||||
@@ -15,6 +15,10 @@
|
||||
import net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect;
|
||||
import net.minecraft.world.item.consume_effects.ConsumeEffect;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public record DeathProtection(List<ConsumeEffect> deathEffects) {
|
||||
|
||||
public static final Codec<DeathProtection> CODEC = RecordCodecBuilder.create((instance) -> {
|
||||
@@ -29,7 +33,7 @@
|
||||
while (iterator.hasNext()) {
|
||||
ConsumeEffect consumeeffect = (ConsumeEffect) iterator.next();
|
||||
|
||||
- consumeeffect.apply(entity.level(), stack, entity);
|
||||
+ consumeeffect.apply(entity.level(), stack, entity, EntityPotionEffectEvent.Cause.TOTEM); // CraftBukkit
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/item/component/LodestoneTracker.java
|
||||
+++ b/net/minecraft/world/item/component/LodestoneTracker.java
|
||||
@@ -29,7 +29,7 @@
|
||||
return this;
|
||||
} else {
|
||||
BlockPos blockPos = this.target.get().pos();
|
||||
- return world.isInWorldBounds(blockPos) && world.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos)
|
||||
+ return world.isInWorldBounds(blockPos) && (!world.hasChunkAt(blockPos) || world.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos)) // Paper - Prevent compass from loading chunks
|
||||
? this
|
||||
: new LodestoneTracker(Optional.empty(), true);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
--- a/net/minecraft/world/item/component/OminousBottleAmplifier.java
|
||||
+++ b/net/minecraft/world/item/component/OminousBottleAmplifier.java
|
||||
@@ -28,8 +28,14 @@
|
||||
|
||||
@Override
|
||||
public void onConsume(Level world, LivingEntity user, ItemStack stack, Consumable consumable) {
|
||||
- user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true));
|
||||
+ user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below
|
||||
}
|
||||
+ // Paper start - properly resend entities - collect packets for bundle
|
||||
+ @Override
|
||||
+ public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) {
|
||||
+ collectedPackets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), MobEffects.BAD_OMEN));
|
||||
+ }
|
||||
+ // Paper end - properly resend entities - collect packets for bundle
|
||||
|
||||
@Override
|
||||
public void addToTooltip(Item.TooltipContext context, Consumer<Component> tooltip, TooltipFlag type) {
|
||||
@@ -0,0 +1,23 @@
|
||||
--- a/net/minecraft/world/item/component/ResolvableProfile.java
|
||||
+++ b/net/minecraft/world/item/component/ResolvableProfile.java
|
||||
@@ -20,9 +20,10 @@
|
||||
instance -> instance.group(
|
||||
ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile::name),
|
||||
UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile::id),
|
||||
+ UUIDUtil.STRING_CODEC.lenientOptionalFieldOf("Id").forGetter($ -> Optional.empty()), // Paper
|
||||
ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", new PropertyMap()).forGetter(ResolvableProfile::properties)
|
||||
)
|
||||
- .apply(instance, ResolvableProfile::new)
|
||||
+ .apply(instance, (s, uuid, uuid2, propertyMap) -> new ResolvableProfile(s, uuid2.or(() -> uuid), propertyMap)) // Paper
|
||||
);
|
||||
public static final Codec<ResolvableProfile> CODEC = Codec.withAlternative(
|
||||
FULL_CODEC, ExtraCodecs.PLAYER_NAME, name -> new ResolvableProfile(Optional.of(name), Optional.empty(), new PropertyMap())
|
||||
@@ -49,7 +50,7 @@
|
||||
if (this.isResolved()) {
|
||||
return CompletableFuture.completedFuture(this);
|
||||
} else {
|
||||
- return this.id.isPresent() ? SkullBlockEntity.fetchGameProfile(this.id.get()).thenApply(optional -> {
|
||||
+ return this.id.isPresent() ? SkullBlockEntity.fetchGameProfile(this.id.get(), this.name.orElse(null)).thenApply(optional -> { // Paper - player profile events
|
||||
GameProfile gameProfile = optional.orElseGet(() -> new GameProfile(this.id.get(), this.name.orElse("")));
|
||||
return new ResolvableProfile(gameProfile);
|
||||
}) : SkullBlockEntity.fetchGameProfile(this.name.orElseThrow()).thenApply(profile -> {
|
||||
@@ -0,0 +1,28 @@
|
||||
--- a/net/minecraft/world/item/component/SuspiciousStewEffects.java
|
||||
+++ b/net/minecraft/world/item/component/SuspiciousStewEffects.java
|
||||
@@ -29,7 +29,7 @@
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, SuspiciousStewEffects> STREAM_CODEC = SuspiciousStewEffects.Entry.STREAM_CODEC.apply(ByteBufCodecs.list()).map(SuspiciousStewEffects::new, SuspiciousStewEffects::effects);
|
||||
|
||||
public SuspiciousStewEffects withEffectAdded(SuspiciousStewEffects.Entry stewEffect) {
|
||||
- return new SuspiciousStewEffects(Util.copyAndAdd(this.effects, (Object) stewEffect));
|
||||
+ return new SuspiciousStewEffects(Util.copyAndAdd(this.effects, stewEffect)); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,7 +44,16 @@
|
||||
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
@Override
|
||||
+ public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) { // Paper - properly resend entities - collect packets for bundle
|
||||
+ for (SuspiciousStewEffects.Entry suspicioussteweffects_a : this.effects) {
|
||||
+ collectedPackets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect())); // Paper - bundlize packets
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ @Override
|
||||
public void addToTooltip(Item.TooltipContext context, Consumer<Component> tooltip, TooltipFlag type) {
|
||||
if (type.isCreative()) {
|
||||
List<MobEffectInstance> list = new ArrayList();
|
||||
@@ -0,0 +1,32 @@
|
||||
--- a/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java
|
||||
+++ b/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java
|
||||
@@ -12,6 +12,9 @@
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public record ApplyStatusEffectsConsumeEffect(List<MobEffectInstance> effects, float probability) implements ConsumeEffect {
|
||||
|
||||
@@ -38,8 +41,8 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public boolean apply(Level world, ItemStack stack, LivingEntity user) {
|
||||
- if (user.getRandom().nextFloat() >= this.probability) {
|
||||
+ public boolean apply(Level world, ItemStack itemstack, LivingEntity entityliving, EntityPotionEffectEvent.Cause cause) { // CraftBukkit
|
||||
+ if (entityliving.getRandom().nextFloat() >= this.probability) {
|
||||
return false;
|
||||
} else {
|
||||
boolean flag = false;
|
||||
@@ -48,7 +51,7 @@
|
||||
while (iterator.hasNext()) {
|
||||
MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
|
||||
|
||||
- if (user.addEffect(new MobEffectInstance(mobeffect))) {
|
||||
+ if (entityliving.addEffect(new MobEffectInstance(mobeffect), cause)) { // CraftBukkit
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
--- a/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java
|
||||
+++ b/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java
|
||||
@@ -6,6 +6,9 @@
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public record ClearAllStatusEffectsConsumeEffect() implements ConsumeEffect {
|
||||
|
||||
@@ -19,7 +22,9 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public boolean apply(Level world, ItemStack stack, LivingEntity user) {
|
||||
- return user.removeAllEffects();
|
||||
+ // CraftBukkit start
|
||||
+ public boolean apply(Level world, ItemStack itemstack, LivingEntity entityliving, EntityPotionEffectEvent.Cause cause) {
|
||||
+ return entityliving.removeAllEffects(cause);
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
--- a/net/minecraft/world/item/consume_effects/ConsumeEffect.java
|
||||
+++ b/net/minecraft/world/item/consume_effects/ConsumeEffect.java
|
||||
@@ -11,6 +11,9 @@
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public interface ConsumeEffect {
|
||||
|
||||
@@ -19,8 +22,16 @@
|
||||
|
||||
ConsumeEffect.Type<? extends ConsumeEffect> getType();
|
||||
|
||||
- boolean apply(Level world, ItemStack stack, LivingEntity user);
|
||||
+ // CraftBukkit start
|
||||
+ default boolean apply(Level world, ItemStack stack, LivingEntity user) {
|
||||
+ return this.apply(world, stack, user, EntityPotionEffectEvent.Cause.UNKNOWN);
|
||||
+ }
|
||||
|
||||
+ default boolean apply(Level world, ItemStack itemstack, LivingEntity entityliving, EntityPotionEffectEvent.Cause cause) {
|
||||
+ return this.apply(world, itemstack, entityliving);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static record Type<T extends ConsumeEffect>(MapCodec<T> codec, StreamCodec<RegistryFriendlyByteBuf, T> streamCodec) {
|
||||
|
||||
public static final ConsumeEffect.Type<ApplyStatusEffectsConsumeEffect> APPLY_EFFECTS = register("apply_effects", ApplyStatusEffectsConsumeEffect.CODEC, ApplyStatusEffectsConsumeEffect.STREAM_CODEC);
|
||||
@@ -0,0 +1,29 @@
|
||||
--- a/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java
|
||||
+++ b/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java
|
||||
@@ -14,6 +14,9 @@
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public record RemoveStatusEffectsConsumeEffect(HolderSet<MobEffect> effects) implements ConsumeEffect {
|
||||
|
||||
@@ -32,14 +35,14 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public boolean apply(Level world, ItemStack stack, LivingEntity user) {
|
||||
+ public boolean apply(Level world, ItemStack itemstack, LivingEntity entityliving, EntityPotionEffectEvent.Cause cause) { // CraftBukkit
|
||||
boolean flag = false;
|
||||
Iterator iterator = this.effects.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Holder<MobEffect> holder = (Holder) iterator.next();
|
||||
|
||||
- if (user.removeEffect(holder)) {
|
||||
+ if (entityliving.removeEffect(holder, cause)) { // CraftBukkit
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
--- a/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java
|
||||
+++ b/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java
|
||||
@@ -53,7 +53,16 @@
|
||||
|
||||
Vec3 vec3d = user.position();
|
||||
|
||||
- if (user.randomTeleport(d0, d1, d2, true)) {
|
||||
+ // CraftBukkit start - handle canceled status of teleport event
|
||||
+ java.util.Optional<Boolean> status = user.randomTeleport(d0, d1, d2, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT);
|
||||
+
|
||||
+ if (!status.isPresent()) {
|
||||
+ // teleport event was canceled, no more tries
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (status.get()) {
|
||||
+ // CraftBukkit end
|
||||
world.gameEvent((Holder) GameEvent.TELEPORT, vec3d, GameEvent.Context.of((Entity) user));
|
||||
SoundEvent soundeffect;
|
||||
SoundSource soundcategory;
|
||||
@@ -0,0 +1,35 @@
|
||||
--- a/net/minecraft/world/item/crafting/BlastingRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/BlastingRecipe.java
|
||||
@@ -4,6 +4,14 @@
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftBlastingRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class BlastingRecipe extends AbstractCookingRecipe {
|
||||
|
||||
public BlastingRecipe(String group, CookingBookCategory category, Ingredient ingredient, ItemStack result, float experience, int cookingTime) {
|
||||
@@ -43,4 +51,17 @@
|
||||
|
||||
return recipebookcategory;
|
||||
}
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result());
|
||||
+
|
||||
+ CraftBlastingRecipe recipe = new CraftBlastingRecipe(id, result, CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime());
|
||||
+ recipe.setGroup(this.group());
|
||||
+ recipe.setCategory(CraftRecipe.getCategory(this.category()));
|
||||
+
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
--- a/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
|
||||
@@ -4,6 +4,14 @@
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftCampfireRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class CampfireCookingRecipe extends AbstractCookingRecipe {
|
||||
|
||||
public CampfireCookingRecipe(String group, CookingBookCategory category, Ingredient ingredient, ItemStack result, float experience, int cookingTime) {
|
||||
@@ -29,4 +37,17 @@
|
||||
public RecipeBookCategory recipeBookCategory() {
|
||||
return RecipeBookCategories.CAMPFIRE;
|
||||
}
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result());
|
||||
+
|
||||
+ CraftCampfireRecipe recipe = new CraftCampfireRecipe(id, result, CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime());
|
||||
+ recipe.setGroup(this.group());
|
||||
+ recipe.setCategory(CraftRecipe.getCategory(this.category()));
|
||||
+
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
--- a/net/minecraft/world/item/crafting/CustomRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/CustomRecipe.java
|
||||
@@ -8,6 +8,15 @@
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftComplexRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public abstract class CustomRecipe implements CraftingRecipe {
|
||||
|
||||
private final CraftingBookCategory category;
|
||||
@@ -34,6 +43,19 @@
|
||||
@Override
|
||||
public abstract RecipeSerializer<? extends CustomRecipe> getSerializer();
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(ItemStack.EMPTY);
|
||||
+
|
||||
+ CraftComplexRecipe recipe = new CraftComplexRecipe(id, result, this);
|
||||
+ recipe.setGroup(this.group());
|
||||
+ recipe.setCategory(CraftRecipe.getCategory(this.category()));
|
||||
+
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static class Serializer<T extends CraftingRecipe> implements RecipeSerializer<T> {
|
||||
|
||||
private final MapCodec<T> codec;
|
||||
@@ -41,13 +63,13 @@
|
||||
|
||||
public Serializer(CustomRecipe.Serializer.Factory<T> factory) {
|
||||
this.codec = RecordCodecBuilder.mapCodec((instance) -> {
|
||||
- P1 p1 = instance.group(CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter(CraftingRecipe::category));
|
||||
+ P1<RecordCodecBuilder.Mu<T>, CraftingBookCategory> p1 = instance.group(CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter(CraftingRecipe::category)); // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(factory);
|
||||
return p1.apply(instance, factory::create);
|
||||
});
|
||||
StreamCodec streamcodec = CraftingBookCategory.STREAM_CODEC;
|
||||
- Function function = CraftingRecipe::category;
|
||||
+ Function<CraftingRecipe, CraftingBookCategory> function = CraftingRecipe::category; // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(factory);
|
||||
this.streamCodec = StreamCodec.composite(streamcodec, function, factory::create);
|
||||
@@ -0,0 +1,66 @@
|
||||
--- a/net/minecraft/world/item/crafting/Ingredient.java
|
||||
+++ b/net/minecraft/world/item/crafting/Ingredient.java
|
||||
@@ -20,6 +20,10 @@
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.display.SlotDisplay;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
+// CraftBukkit start
|
||||
+import java.util.List;
|
||||
+import javax.annotation.Nullable;
|
||||
+// CraftBukkit end
|
||||
|
||||
public final class Ingredient implements StackedContents.IngredientInfo<Holder<Item>>, Predicate<ItemStack> {
|
||||
|
||||
@@ -38,7 +42,25 @@
|
||||
return recipeitemstack.values;
|
||||
});
|
||||
private final HolderSet<Item> values;
|
||||
+ // CraftBukkit start
|
||||
+ @Nullable
|
||||
+ private List<ItemStack> itemStacks;
|
||||
|
||||
+ public boolean isExact() {
|
||||
+ return this.itemStacks != null;
|
||||
+ }
|
||||
+
|
||||
+ public List<ItemStack> itemStacks() {
|
||||
+ return this.itemStacks;
|
||||
+ }
|
||||
+
|
||||
+ public static Ingredient ofStacks(List<ItemStack> stacks) {
|
||||
+ Ingredient recipe = Ingredient.of(stacks.stream().map(ItemStack::getItem));
|
||||
+ recipe.itemStacks = stacks;
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
private Ingredient(HolderSet<Item> entries) {
|
||||
entries.unwrap().ifRight((list) -> {
|
||||
if (list.isEmpty()) {
|
||||
@@ -70,6 +92,17 @@
|
||||
}
|
||||
|
||||
public boolean test(ItemStack itemstack) {
|
||||
+ // CraftBukkit start
|
||||
+ if (this.isExact()) {
|
||||
+ for (ItemStack itemstack1 : this.itemStacks()) {
|
||||
+ if (itemstack1.getItem() == itemstack.getItem() && ItemStack.isSameItemSameComponents(itemstack, itemstack1)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
return itemstack.is(this.values);
|
||||
}
|
||||
|
||||
@@ -79,7 +112,7 @@
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if (object instanceof Ingredient recipeitemstack) {
|
||||
- return Objects.equals(this.values, recipeitemstack.values);
|
||||
+ return Objects.equals(this.values, recipeitemstack.values) && Objects.equals(this.itemStacks, recipeitemstack.itemStacks); // CraftBukkit
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
--- a/net/minecraft/world/item/crafting/Recipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/Recipe.java
|
||||
@@ -44,4 +44,6 @@
|
||||
}
|
||||
|
||||
RecipeBookCategory recipeBookCategory();
|
||||
+
|
||||
+ org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
--- a/net/minecraft/world/item/crafting/RecipeHolder.java
|
||||
+++ b/net/minecraft/world/item/crafting/RecipeHolder.java
|
||||
@@ -5,10 +5,21 @@
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
||||
-public record RecipeHolder<T extends Recipe<?>>(ResourceKey<Recipe<?>> id, T value) {
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
|
||||
- public static final StreamCodec<RegistryFriendlyByteBuf, RecipeHolder<?>> STREAM_CODEC = StreamCodec.composite(ResourceKey.streamCodec(Registries.RECIPE), RecipeHolder::id, Recipe.STREAM_CODEC, RecipeHolder::value, RecipeHolder::new);
|
||||
+public record RecipeHolder<T extends net.minecraft.world.item.crafting.Recipe<?>>(ResourceKey<net.minecraft.world.item.crafting.Recipe<?>> id, T value) {
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ public final Recipe toBukkitRecipe() {
|
||||
+ return this.value.toBukkitRecipe(CraftNamespacedKey.fromMinecraft(this.id.location()));
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ public static final StreamCodec<RegistryFriendlyByteBuf, RecipeHolder<?>> STREAM_CODEC = StreamCodec.composite(ResourceKey.streamCodec(Registries.RECIPE), RecipeHolder::id, net.minecraft.world.item.crafting.Recipe.STREAM_CODEC, RecipeHolder::value, RecipeHolder::new);
|
||||
+
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
@@ -0,0 +1,111 @@
|
||||
--- a/net/minecraft/world/item/crafting/RecipeManager.java
|
||||
+++ b/net/minecraft/world/item/crafting/RecipeManager.java
|
||||
@@ -26,11 +26,6 @@
|
||||
import net.minecraft.resources.FileToIdConverter;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
-import net.minecraft.server.level.ServerLevel;
|
||||
-import net.minecraft.server.packs.resources.ResourceManager;
|
||||
-import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
|
||||
-import net.minecraft.server.packs.resources.SimplePreparableReloadListener;
|
||||
-import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.crafting.display.RecipeDisplay;
|
||||
@@ -39,6 +34,16 @@
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import java.util.Collections;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+// CraftBukkit end
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.packs.resources.ResourceManager;
|
||||
+import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
|
||||
+import net.minecraft.server.packs.resources.SimplePreparableReloadListener;
|
||||
+import net.minecraft.util.profiling.ProfilerFiller;
|
||||
+
|
||||
public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> implements RecipeAccess {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -111,7 +116,26 @@
|
||||
RecipeManager.LOGGER.info("Loaded {} recipes", prepared.values().size());
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ public void addRecipe(RecipeHolder<?> irecipe) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Recipe Add"); // Spigot
|
||||
+ this.recipes.addRecipe(irecipe);
|
||||
+ this.finalizeRecipeLoading();
|
||||
+ }
|
||||
+
|
||||
+ private FeatureFlagSet featureflagset;
|
||||
+
|
||||
+ public void finalizeRecipeLoading() {
|
||||
+ if (this.featureflagset != null) {
|
||||
+ this.finalizeRecipeLoading(this.featureflagset);
|
||||
+
|
||||
+ MinecraftServer.getServer().getPlayerList().reloadRecipes();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
public void finalizeRecipeLoading(FeatureFlagSet features) {
|
||||
+ this.featureflagset = features;
|
||||
+ // CraftBukkit end
|
||||
List<SelectableRecipe.SingleInputEntry<StonecutterRecipe>> list = new ArrayList();
|
||||
List<RecipeManager.IngredientCollector> list1 = RecipeManager.RECIPE_PROPERTY_SETS.entrySet().stream().map((entry) -> {
|
||||
return new RecipeManager.IngredientCollector((ResourceKey) entry.getKey(), (RecipeManager.IngredientExtractor) entry.getValue());
|
||||
@@ -130,7 +154,7 @@
|
||||
StonecutterRecipe recipestonecutting = (StonecutterRecipe) irecipe;
|
||||
|
||||
if (RecipeManager.isIngredientEnabled(features, recipestonecutting.input()) && recipestonecutting.resultDisplay().isEnabled(features)) {
|
||||
- list.add(new SelectableRecipe.SingleInputEntry<>(recipestonecutting.input(), new SelectableRecipe<>(recipestonecutting.resultDisplay(), Optional.of(recipeholder))));
|
||||
+ list.add(new SelectableRecipe.SingleInputEntry<StonecutterRecipe>(recipestonecutting.input(), new SelectableRecipe<>(recipestonecutting.resultDisplay(), Optional.of((RecipeHolder<StonecutterRecipe>) recipeholder)))); // CraftBukkit - decompile error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +196,10 @@
|
||||
}
|
||||
|
||||
public <I extends RecipeInput, T extends Recipe<I>> Optional<RecipeHolder<T>> getRecipeFor(RecipeType<T> type, I input, Level world) {
|
||||
- return this.recipes.getRecipesFor(type, input, world).findFirst();
|
||||
+ // CraftBukkit start
|
||||
+ List<RecipeHolder<T>> list = this.recipes.getRecipesFor(type, input, world).toList();
|
||||
+ return (list.isEmpty()) ? Optional.empty() : Optional.of(list.getLast()); // CraftBukkit - SPIGOT-4638: last recipe gets priority
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
public Optional<RecipeHolder<?>> byKey(ResourceKey<Recipe<?>> key) {
|
||||
@@ -183,7 +210,7 @@
|
||||
private <T extends Recipe<?>> RecipeHolder<T> byKeyTyped(RecipeType<T> type, ResourceKey<Recipe<?>> key) {
|
||||
RecipeHolder<?> recipeholder = this.recipes.byKey(key);
|
||||
|
||||
- return recipeholder != null && recipeholder.value().getType().equals(type) ? recipeholder : null;
|
||||
+ return recipeholder != null && recipeholder.value().getType().equals(type) ? (RecipeHolder) recipeholder : null; // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
public Map<ResourceKey<RecipePropertySet>, RecipePropertySet> getSynchronizedItemProperties() {
|
||||
@@ -231,6 +258,22 @@
|
||||
return new RecipeHolder<>(key, irecipe);
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ public boolean removeRecipe(ResourceKey<Recipe<?>> mcKey) {
|
||||
+ boolean removed = this.recipes.removeRecipe((ResourceKey<Recipe<RecipeInput>>) (ResourceKey) mcKey); // Paper - generic fix
|
||||
+ if (removed) {
|
||||
+ this.finalizeRecipeLoading();
|
||||
+ }
|
||||
+
|
||||
+ return removed;
|
||||
+ }
|
||||
+
|
||||
+ public void clearRecipes() {
|
||||
+ this.recipes = RecipeMap.create(Collections.emptyList());
|
||||
+ this.finalizeRecipeLoading();
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static <I extends RecipeInput, T extends Recipe<I>> RecipeManager.CachedCheck<I, T> createCheck(final RecipeType<T> type) {
|
||||
return new RecipeManager.CachedCheck<I, T>() {
|
||||
@Nullable
|
||||
@@ -0,0 +1,72 @@
|
||||
--- a/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
+++ b/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
@@ -11,6 +11,10 @@
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import com.google.common.collect.LinkedHashMultimap;
|
||||
+import com.google.common.collect.Maps;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class RecipeMap {
|
||||
|
||||
@@ -35,11 +39,56 @@
|
||||
com_google_common_collect_immutablemap_builder.put(recipeholder.id(), recipeholder);
|
||||
}
|
||||
|
||||
- return new RecipeMap(builder.build(), com_google_common_collect_immutablemap_builder.build());
|
||||
+ // CraftBukkit start - mutable
|
||||
+ return new RecipeMap(LinkedHashMultimap.create(builder.build()), Maps.newHashMap(com_google_common_collect_immutablemap_builder.build()));
|
||||
}
|
||||
|
||||
+ public void addRecipe(RecipeHolder<?> irecipe) {
|
||||
+ Collection<RecipeHolder<?>> map = this.byType.get(irecipe.value().getType());
|
||||
+
|
||||
+ if (this.byKey.containsKey(irecipe.id())) {
|
||||
+ throw new IllegalStateException("Duplicate recipe ignored with ID " + irecipe.id());
|
||||
+ } else {
|
||||
+ map.add(irecipe);
|
||||
+ this.byKey.put(irecipe.id(), irecipe);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // public boolean removeRecipe(ResourceKey<Recipe<?>> mcKey) {
|
||||
+ // boolean removed = false;
|
||||
+ // Iterator<RecipeHolder<?>> iter = this.byType.values().iterator();
|
||||
+ // while (iter.hasNext()) {
|
||||
+ // RecipeHolder<?> recipe = iter.next();
|
||||
+ // if (recipe.id().equals(mcKey)) {
|
||||
+ // iter.remove();
|
||||
+ // removed = true;
|
||||
+ // }
|
||||
+ // }
|
||||
+ // removed |= this.byKey.remove(mcKey) != null;
|
||||
+ //
|
||||
+ // return removed;
|
||||
+ // }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+
|
||||
+ // Paper start - replace removeRecipe implementation
|
||||
+ public <T extends RecipeInput> boolean removeRecipe(ResourceKey<Recipe<T>> mcKey) {
|
||||
+ //noinspection unchecked
|
||||
+ final RecipeHolder<Recipe<T>> remove = (RecipeHolder<Recipe<T>>) this.byKey.remove(mcKey);
|
||||
+ if (remove == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ final Collection<? extends RecipeHolder<? extends Recipe<T>>> recipes = this.byType(remove.value().getType());
|
||||
+ if (recipes.remove(remove)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ // Paper end - why are you using a loop???
|
||||
+ }
|
||||
+ // Paper end - replace removeRecipe implementation
|
||||
+
|
||||
public <I extends RecipeInput, T extends Recipe<I>> Collection<RecipeHolder<T>> byType(RecipeType<T> type) {
|
||||
- return this.byType.get(type);
|
||||
+ return (Collection) this.byType.get(type); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
public Collection<RecipeHolder<?>> values() {
|
||||
@@ -0,0 +1,86 @@
|
||||
--- a/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
@@ -16,6 +16,13 @@
|
||||
import net.minecraft.world.item.crafting.display.ShapedCraftingRecipeDisplay;
|
||||
import net.minecraft.world.item.crafting.display.SlotDisplay;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
|
||||
+import org.bukkit.inventory.RecipeChoice;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class ShapedRecipe implements CraftingRecipe {
|
||||
|
||||
@@ -39,7 +46,69 @@
|
||||
this(group, category, raw, result, true);
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
@Override
|
||||
+ public org.bukkit.inventory.ShapedRecipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
|
||||
+ CraftShapedRecipe recipe = new CraftShapedRecipe(id, result, this);
|
||||
+ recipe.setGroup(this.group);
|
||||
+ recipe.setCategory(CraftRecipe.getCategory(this.category()));
|
||||
+
|
||||
+ switch (this.pattern.height()) {
|
||||
+ case 1:
|
||||
+ switch (this.pattern.width()) {
|
||||
+ case 1:
|
||||
+ recipe.shape("a");
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ recipe.shape("ab");
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ recipe.shape("abc");
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ switch (this.pattern.width()) {
|
||||
+ case 1:
|
||||
+ recipe.shape("a","b");
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ recipe.shape("ab","cd");
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ recipe.shape("abc","def");
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ switch (this.pattern.width()) {
|
||||
+ case 1:
|
||||
+ recipe.shape("a","b","c");
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ recipe.shape("ab","cd","ef");
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ recipe.shape("abc","def","ghi");
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ char c = 'a';
|
||||
+ for (Optional<Ingredient> list : this.pattern.ingredients()) {
|
||||
+ RecipeChoice choice = CraftRecipe.toBukkit(list);
|
||||
+ if (choice != RecipeChoice.empty()) { // Paper
|
||||
+ recipe.setIngredient(c, choice);
|
||||
+ }
|
||||
+
|
||||
+ c++;
|
||||
+ }
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ @Override
|
||||
public RecipeSerializer<? extends ShapedRecipe> getSerializer() {
|
||||
return RecipeSerializer.SHAPED_RECIPE;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
@@ -16,6 +16,12 @@
|
||||
import net.minecraft.world.item.crafting.display.ShapelessCraftingRecipeDisplay;
|
||||
import net.minecraft.world.item.crafting.display.SlotDisplay;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class ShapelessRecipe implements CraftingRecipe {
|
||||
|
||||
@@ -33,7 +39,23 @@
|
||||
this.ingredients = ingredients;
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ @SuppressWarnings("unchecked")
|
||||
@Override
|
||||
+ public org.bukkit.inventory.ShapelessRecipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
|
||||
+ CraftShapelessRecipe recipe = new CraftShapelessRecipe(id, result, this);
|
||||
+ recipe.setGroup(this.group);
|
||||
+ recipe.setCategory(CraftRecipe.getCategory(this.category()));
|
||||
+
|
||||
+ for (Ingredient list : this.ingredients) {
|
||||
+ recipe.addIngredient(CraftRecipe.toBukkit(list));
|
||||
+ }
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ @Override
|
||||
public RecipeSerializer<ShapelessRecipe> getSerializer() {
|
||||
return RecipeSerializer.SHAPELESS_RECIPE;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
--- a/net/minecraft/world/item/crafting/SmeltingRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/SmeltingRecipe.java
|
||||
@@ -4,6 +4,14 @@
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class SmeltingRecipe extends AbstractCookingRecipe {
|
||||
|
||||
public SmeltingRecipe(String group, CookingBookCategory category, Ingredient ingredient, ItemStack result, float experience, int cookingTime) {
|
||||
@@ -45,4 +53,17 @@
|
||||
|
||||
return recipebookcategory;
|
||||
}
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result());
|
||||
+
|
||||
+ CraftFurnaceRecipe recipe = new CraftFurnaceRecipe(id, result, CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime());
|
||||
+ recipe.setGroup(this.group());
|
||||
+ recipe.setCategory(CraftRecipe.getCategory(this.category()));
|
||||
+
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
--- a/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
|
||||
@@ -14,6 +14,14 @@
|
||||
import net.minecraft.world.item.crafting.display.SlotDisplay;
|
||||
import net.minecraft.world.item.crafting.display.SmithingRecipeDisplay;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftSmithingTransformRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class SmithingTransformRecipe implements SmithingRecipe {
|
||||
|
||||
final Optional<Ingredient> template;
|
||||
@@ -22,8 +30,15 @@
|
||||
final ItemStack result;
|
||||
@Nullable
|
||||
private PlacementInfo placementInfo;
|
||||
+ final boolean copyDataComponents; // Paper - Option to prevent data components copy
|
||||
|
||||
public SmithingTransformRecipe(Optional<Ingredient> template, Optional<Ingredient> base, Optional<Ingredient> addition, ItemStack result) {
|
||||
+ // Paper start - Option to prevent data components copy
|
||||
+ this(template, base, addition, result, true);
|
||||
+ }
|
||||
+ public SmithingTransformRecipe(Optional<Ingredient> template, Optional<Ingredient> base, Optional<Ingredient> addition, ItemStack result, boolean copyDataComponents) {
|
||||
+ this.copyDataComponents = copyDataComponents;
|
||||
+ // Paper end - Option to prevent data components copy
|
||||
this.template = template;
|
||||
this.base = base;
|
||||
this.addition = addition;
|
||||
@@ -33,7 +48,9 @@
|
||||
public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) {
|
||||
ItemStack itemstack = input.base().transmuteCopy(this.result.getItem(), this.result.getCount());
|
||||
|
||||
+ if (this.copyDataComponents) { // Paper - Option to prevent data components copy
|
||||
itemstack.applyComponents(this.result.getComponentsPatch());
|
||||
+ } // Paper - Option to prevent data components copy
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
@@ -71,6 +88,17 @@
|
||||
return List.of(new SmithingRecipeDisplay(Ingredient.optionalIngredientToDisplay(this.template), Ingredient.optionalIngredientToDisplay(this.base), Ingredient.optionalIngredientToDisplay(this.addition), new SlotDisplay.ItemStackSlotDisplay(this.result), new SlotDisplay.ItemSlotDisplay(Items.SMITHING_TABLE)));
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
|
||||
+
|
||||
+ CraftSmithingTransformRecipe recipe = new CraftSmithingTransformRecipe(id, result, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition), this.copyDataComponents); // Paper - Option to prevent data components copy
|
||||
+
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static class Serializer implements RecipeSerializer<SmithingTransformRecipe> {
|
||||
|
||||
private static final MapCodec<SmithingTransformRecipe> CODEC = RecordCodecBuilder.mapCodec((instance) -> {
|
||||
@@ -0,0 +1,69 @@
|
||||
--- a/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
|
||||
@@ -21,6 +21,13 @@
|
||||
import net.minecraft.world.item.equipment.trim.TrimPattern;
|
||||
import net.minecraft.world.item.equipment.trim.TrimPatterns;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftSmithingTrimRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class SmithingTrimRecipe implements SmithingRecipe {
|
||||
|
||||
final Optional<Ingredient> template;
|
||||
@@ -28,18 +35,28 @@
|
||||
final Optional<Ingredient> addition;
|
||||
@Nullable
|
||||
private PlacementInfo placementInfo;
|
||||
+ final boolean copyDataComponents; // Paper - Option to prevent data components copy
|
||||
|
||||
public SmithingTrimRecipe(Optional<Ingredient> template, Optional<Ingredient> base, Optional<Ingredient> addition) {
|
||||
+ // Paper start - Option to prevent data components copy
|
||||
+ this(template, base, addition, true);
|
||||
+ }
|
||||
+ public SmithingTrimRecipe(Optional<Ingredient> template, Optional<Ingredient> base, Optional<Ingredient> addition, boolean copyDataComponents) {
|
||||
+ this.copyDataComponents = copyDataComponents;
|
||||
+ // Paper end - Option to prevent data components copy
|
||||
this.template = template;
|
||||
this.base = base;
|
||||
this.addition = addition;
|
||||
}
|
||||
|
||||
public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) {
|
||||
- return SmithingTrimRecipe.applyTrim(registries, input.base(), input.addition(), input.template());
|
||||
+ return SmithingTrimRecipe.applyTrim(registries, input.base(), input.addition(), input.template(), this.copyDataComponents);
|
||||
}
|
||||
|
||||
public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, ItemStack template) {
|
||||
+ return applyTrim(registries, base, addition, template, true);
|
||||
+ }
|
||||
+ public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, ItemStack template, boolean copyDataComponents) {
|
||||
Optional<Holder.Reference<TrimMaterial>> optional = TrimMaterials.getFromIngredient(registries, addition);
|
||||
Optional<Holder.Reference<TrimPattern>> optional1 = TrimPatterns.getFromTemplate(registries, template);
|
||||
|
||||
@@ -49,7 +66,7 @@
|
||||
if (armortrim != null && armortrim.hasPatternAndMaterial((Holder) optional1.get(), (Holder) optional.get())) {
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
- ItemStack itemstack3 = base.copyWithCount(1);
|
||||
+ ItemStack itemstack3 = copyDataComponents ? base.copyWithCount(1) : new ItemStack(base.getItem(), 1); // Paper - Option to prevent data components copy
|
||||
|
||||
itemstack3.set(DataComponents.TRIM, new ArmorTrim((Holder) optional.get(), (Holder) optional1.get()));
|
||||
return itemstack3;
|
||||
@@ -97,6 +114,13 @@
|
||||
return List.of(new SmithingRecipeDisplay(slotdisplay2, slotdisplay, slotdisplay1, new SlotDisplay.SmithingTrimDemoSlotDisplay(slotdisplay, slotdisplay1, slotdisplay2), new SlotDisplay.ItemSlotDisplay(Items.SMITHING_TABLE)));
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ return new CraftSmithingTrimRecipe(id, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition), this.copyDataComponents); // Paper - Option to prevent data components copy
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static class Serializer implements RecipeSerializer<SmithingTrimRecipe> {
|
||||
|
||||
private static final MapCodec<SmithingTrimRecipe> CODEC = RecordCodecBuilder.mapCodec((instance) -> {
|
||||
@@ -0,0 +1,35 @@
|
||||
--- a/net/minecraft/world/item/crafting/SmokingRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/SmokingRecipe.java
|
||||
@@ -4,6 +4,14 @@
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftSmokingRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class SmokingRecipe extends AbstractCookingRecipe {
|
||||
|
||||
public SmokingRecipe(String group, CookingBookCategory category, Ingredient ingredient, ItemStack result, float experience, int cookingTime) {
|
||||
@@ -29,4 +37,17 @@
|
||||
public RecipeBookCategory recipeBookCategory() {
|
||||
return RecipeBookCategories.SMOKER_FOOD;
|
||||
}
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result());
|
||||
+
|
||||
+ CraftSmokingRecipe recipe = new CraftSmokingRecipe(id, result, CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime());
|
||||
+ recipe.setGroup(this.group());
|
||||
+ recipe.setCategory(CraftRecipe.getCategory(this.category()));
|
||||
+
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
--- a/net/minecraft/world/item/crafting/StonecutterRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/StonecutterRecipe.java
|
||||
@@ -7,6 +7,14 @@
|
||||
import net.minecraft.world.item.crafting.display.SlotDisplay;
|
||||
import net.minecraft.world.item.crafting.display.StonecutterRecipeDisplay;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftStonecuttingRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class StonecutterRecipe extends SingleItemRecipe {
|
||||
|
||||
public StonecutterRecipe(String group, Ingredient ingredient, ItemStack result) {
|
||||
@@ -36,4 +44,16 @@
|
||||
public RecipeBookCategory recipeBookCategory() {
|
||||
return RecipeBookCategories.STONECUTTER;
|
||||
}
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ @Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ CraftItemStack result = CraftItemStack.asCraftMirror(this.result());
|
||||
+
|
||||
+ CraftStonecuttingRecipe recipe = new CraftStonecuttingRecipe(id, result, CraftRecipe.toBukkit(this.input()));
|
||||
+ recipe.setGroup(this.group());
|
||||
+
|
||||
+ return recipe;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
--- a/net/minecraft/world/item/crafting/TransmuteRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/TransmuteRecipe.java
|
||||
@@ -19,6 +19,13 @@
|
||||
import net.minecraft.world.item.crafting.display.SlotDisplay;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.Level;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemType;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftTransmuteRecipe;
|
||||
+import org.bukkit.inventory.Recipe;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class TransmuteRecipe implements CraftingRecipe {
|
||||
|
||||
@@ -84,7 +91,14 @@
|
||||
return List.of(new ShapelessCraftingRecipeDisplay(List.of(this.input.display(), this.material.display()), new SlotDisplay.ItemSlotDisplay(this.result), new SlotDisplay.ItemSlotDisplay(Items.CRAFTING_TABLE)));
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
@Override
|
||||
+ public Recipe toBukkitRecipe(NamespacedKey id) {
|
||||
+ return new CraftTransmuteRecipe(id, CraftItemType.minecraftToBukkit(this.result.value()), CraftRecipe.toBukkit(this.input), CraftRecipe.toBukkit(this.material));
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ @Override
|
||||
public RecipeSerializer<TransmuteRecipe> getSerializer() {
|
||||
return RecipeSerializer.TRANSMUTE;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
--- a/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
||||
+++ b/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
||||
@@ -26,12 +26,25 @@
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.TooltipProvider;
|
||||
+// Paper start
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap;
|
||||
+// Paper end
|
||||
|
||||
public class ItemEnchantments implements TooltipProvider {
|
||||
- public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntOpenHashMap<>(), true);
|
||||
+ // Paper start
|
||||
+ private static final java.util.Comparator<Holder<Enchantment>> ENCHANTMENT_ORDER = java.util.Comparator.comparing(Holder::getRegisteredName);
|
||||
+ public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true);
|
||||
+ // Paper end
|
||||
private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(1, 255);
|
||||
- private static final Codec<Object2IntOpenHashMap<Holder<Enchantment>>> LEVELS_CODEC = Codec.unboundedMap(Enchantment.CODEC, LEVEL_CODEC)
|
||||
- .xmap(Object2IntOpenHashMap::new, Function.identity());
|
||||
+ private static final Codec<Object2IntAVLTreeMap<Holder<Enchantment>>> LEVELS_CODEC = Codec.unboundedMap(
|
||||
+ Enchantment.CODEC, LEVEL_CODEC
|
||||
+ )// Paper start - sort enchantments
|
||||
+ .xmap(m -> {
|
||||
+ final Object2IntAVLTreeMap<Holder<Enchantment>> map = new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER);
|
||||
+ map.putAll(m);
|
||||
+ return map;
|
||||
+ }, Function.identity());
|
||||
+ // Paper end - sort enchantments
|
||||
private static final Codec<ItemEnchantments> FULL_CODEC = RecordCodecBuilder.create(
|
||||
instance -> instance.group(
|
||||
LEVELS_CODEC.fieldOf("levels").forGetter(component -> component.enchantments),
|
||||
@@ -41,16 +54,16 @@
|
||||
);
|
||||
public static final Codec<ItemEnchantments> CODEC = Codec.withAlternative(FULL_CODEC, LEVELS_CODEC, map -> new ItemEnchantments(map, true));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, ItemEnchantments> STREAM_CODEC = StreamCodec.composite(
|
||||
- ByteBufCodecs.map(Object2IntOpenHashMap::new, Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT),
|
||||
+ ByteBufCodecs.map((v) -> new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT),
|
||||
component -> component.enchantments,
|
||||
ByteBufCodecs.BOOL,
|
||||
component -> component.showInTooltip,
|
||||
ItemEnchantments::new
|
||||
);
|
||||
- final Object2IntOpenHashMap<Holder<Enchantment>> enchantments;
|
||||
+ final Object2IntAVLTreeMap<Holder<Enchantment>> enchantments; // Paper
|
||||
public final boolean showInTooltip;
|
||||
|
||||
- ItemEnchantments(Object2IntOpenHashMap<Holder<Enchantment>> enchantments, boolean showInTooltip) {
|
||||
+ ItemEnchantments(Object2IntAVLTreeMap<Holder<Enchantment>> enchantments, boolean showInTooltip) { // Paper
|
||||
this.enchantments = enchantments;
|
||||
this.showInTooltip = showInTooltip;
|
||||
|
||||
@@ -139,7 +152,7 @@
|
||||
}
|
||||
|
||||
public static class Mutable {
|
||||
- private final Object2IntOpenHashMap<Holder<Enchantment>> enchantments = new Object2IntOpenHashMap<>();
|
||||
+ private final Object2IntAVLTreeMap<Holder<Enchantment>> enchantments = new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER); // Paper
|
||||
public boolean showInTooltip;
|
||||
|
||||
public Mutable(ItemEnchantments enchantmentsComponent) {
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java
|
||||
+++ b/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java
|
||||
@@ -34,7 +34,7 @@
|
||||
int j = Math.round(Mth.randomBetween(randomsource, this.minDuration.calculate(level), this.maxDuration.calculate(level)) * 20.0F);
|
||||
int k = Math.max(0, Math.round(Mth.randomBetween(randomsource, this.minAmplifier.calculate(level), this.maxAmplifier.calculate(level))));
|
||||
|
||||
- entityliving.addEffect(new MobEffectInstance((Holder) optional.get(), j, k));
|
||||
+ entityliving.addEffect(new MobEffectInstance((Holder) optional.get(), j, k), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
--- a/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java
|
||||
+++ b/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java
|
||||
@@ -21,9 +21,9 @@
|
||||
public void apply(ServerLevel world, int level, EnchantedItemInUse context, Entity user, Vec3 pos) {
|
||||
ItemStack itemStack = context.itemStack();
|
||||
if (itemStack.has(DataComponents.MAX_DAMAGE) && itemStack.has(DataComponents.DAMAGE)) {
|
||||
- ServerPlayer serverPlayer2 = context.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null;
|
||||
+ // ServerPlayer serverPlayer2 = context.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null; // Paper - EntityDamageItemEvent - always pass in entity
|
||||
int i = (int)this.amount.calculate(level);
|
||||
- itemStack.hurtAndBreak(i, world, serverPlayer2, context.onBreak());
|
||||
+ itemStack.hurtAndBreak(i, world, context.owner(), context.onBreak()); // Paper - EntityDamageItemEvent - always pass in entity
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
--- a/net/minecraft/world/item/enchantment/effects/Ignite.java
|
||||
+++ b/net/minecraft/world/item/enchantment/effects/Ignite.java
|
||||
@@ -7,6 +7,10 @@
|
||||
import net.minecraft.world.item.enchantment.EnchantedItemInUse;
|
||||
import net.minecraft.world.item.enchantment.LevelBasedValue;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityCombustByEntityEvent;
|
||||
+import org.bukkit.event.entity.EntityCombustEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public record Ignite(LevelBasedValue duration) implements EnchantmentEntityEffect {
|
||||
|
||||
@@ -18,7 +22,21 @@
|
||||
|
||||
@Override
|
||||
public void apply(ServerLevel world, int level, EnchantedItemInUse context, Entity user, Vec3 pos) {
|
||||
- user.igniteForSeconds(this.duration.calculate(level));
|
||||
+ // CraftBukkit start - Call a combust event when somebody hits with a fire enchanted item
|
||||
+ EntityCombustEvent entityCombustEvent;
|
||||
+ if (context.owner() != null) {
|
||||
+ entityCombustEvent = new EntityCombustByEntityEvent(context.owner().getBukkitEntity(), user.getBukkitEntity(), this.duration.calculate(level));
|
||||
+ } else {
|
||||
+ entityCombustEvent = new EntityCombustEvent(user.getBukkitEntity(), this.duration.calculate(level));
|
||||
+ }
|
||||
+
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(entityCombustEvent);
|
||||
+ if (entityCombustEvent.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ user.igniteForSeconds(entityCombustEvent.getDuration(), false);
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java
|
||||
+++ b/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
if ((Boolean) this.predicate.map((blockpredicate) -> {
|
||||
return blockpredicate.test(world, blockposition);
|
||||
- }).orElse(true) && world.setBlockAndUpdate(blockposition, this.blockState.getState(user.getRandom(), blockposition))) {
|
||||
+ }).orElse(true) && org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(world, blockposition, this.blockState.getState(user.getRandom(), blockposition), user)) { // CraftBukkit - Call EntityBlockFormEvent
|
||||
this.triggerGameEvent.ifPresent((holder) -> {
|
||||
world.gameEvent(user, holder, blockposition);
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java
|
||||
+++ b/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
if (blockposition1.distToCenterSqr(pos.x(), (double) blockposition1.getY() + 0.5D, pos.z()) < (double) Mth.square(j) && (Boolean) this.predicate.map((blockpredicate) -> {
|
||||
return blockpredicate.test(world, blockposition1);
|
||||
- }).orElse(true) && world.setBlockAndUpdate(blockposition1, this.blockState.getState(randomsource, blockposition1))) {
|
||||
+ }).orElse(true) && org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(world, blockposition1, this.blockState.getState(randomsource, blockposition1), user)) { // CraftBukkit - Call EntityBlockFormEvent for Frost Walker
|
||||
this.triggerGameEvent.ifPresent((holder) -> {
|
||||
world.gameEvent(user, holder, blockposition1);
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
--- a/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java
|
||||
+++ b/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java
|
||||
@@ -19,6 +19,11 @@
|
||||
import net.minecraft.world.item.enchantment.EnchantedItemInUse;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
+// CraftBukkit start
|
||||
+import net.minecraft.world.item.Items;
|
||||
+import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
+import org.bukkit.event.weather.LightningStrikeEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public record SummonEntityEffect(HolderSet<EntityType<?>> entityTypes, boolean joinTeam) implements EnchantmentEntityEffect {
|
||||
|
||||
@@ -34,7 +39,7 @@
|
||||
Optional<Holder<EntityType<?>>> optional = this.entityTypes().getRandomElement(world.getRandom());
|
||||
|
||||
if (!optional.isEmpty()) {
|
||||
- Entity entity1 = ((EntityType) ((Holder) optional.get()).value()).spawn(world, blockposition, EntitySpawnReason.TRIGGERED);
|
||||
+ Entity entity1 = ((EntityType) ((Holder) optional.get()).value()).create(world, null, blockposition, EntitySpawnReason.TRIGGERED, false, false); // CraftBukkit
|
||||
|
||||
if (entity1 != null) {
|
||||
if (entity1 instanceof LightningBolt) {
|
||||
@@ -46,6 +51,11 @@
|
||||
|
||||
entitylightning.setCause(entityplayer);
|
||||
}
|
||||
+ // CraftBukkit start
|
||||
+ world.strikeLightning(entity1, (context.itemStack().getItem() == Items.TRIDENT) ? LightningStrikeEvent.Cause.TRIDENT : LightningStrikeEvent.Cause.ENCHANTMENT);
|
||||
+ } else {
|
||||
+ world.addFreshEntityWithPassengers(entity1, CreatureSpawnEvent.SpawnReason.ENCHANTMENT);
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
if (this.joinTeam && user.getTeam() != null) {
|
||||
@@ -0,0 +1,17 @@
|
||||
--- a/net/minecraft/world/item/trading/Merchant.java
|
||||
+++ b/net/minecraft/world/item/trading/Merchant.java
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
void overrideOffers(MerchantOffers offers);
|
||||
|
||||
+ default void processTrade(MerchantOffer merchantRecipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { this.notifyTrade(merchantRecipe); } // Paper
|
||||
void notifyTrade(MerchantOffer offer);
|
||||
|
||||
void notifyTradeUpdated(ItemStack stack);
|
||||
@@ -54,4 +55,6 @@
|
||||
boolean isClientSide();
|
||||
|
||||
boolean stillValid(Player player);
|
||||
+
|
||||
+ org.bukkit.craftbukkit.inventory.CraftMerchant getCraftMerchant(); // CraftBukkit
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
--- a/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
+++ b/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
@@ -8,6 +8,8 @@
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
+import org.bukkit.craftbukkit.inventory.CraftMerchantRecipe; // CraftBukkit
|
||||
+
|
||||
public class MerchantOffer {
|
||||
|
||||
public static final Codec<MerchantOffer> CODEC = RecordCodecBuilder.create((instance) -> {
|
||||
@@ -31,6 +33,10 @@
|
||||
return merchantrecipe.priceMultiplier;
|
||||
}), Codec.INT.lenientOptionalFieldOf("xp", 1).forGetter((merchantrecipe) -> {
|
||||
return merchantrecipe.xp;
|
||||
+ // Paper start
|
||||
+ }), Codec.BOOL.lenientOptionalFieldOf("Paper.IgnoreDiscounts", false).forGetter((merchantrecipe) -> {
|
||||
+ return merchantrecipe.ignoreDiscounts;
|
||||
+ // Paper end
|
||||
})).apply(instance, MerchantOffer::new);
|
||||
});
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, MerchantOffer> STREAM_CODEC = StreamCodec.of(MerchantOffer::writeToStream, MerchantOffer::createFromStream);
|
||||
@@ -44,8 +50,22 @@
|
||||
public int demand;
|
||||
public float priceMultiplier;
|
||||
public int xp;
|
||||
+ public boolean ignoreDiscounts; // Paper - Add ignore discounts API
|
||||
+ // CraftBukkit start
|
||||
+ private CraftMerchantRecipe bukkitHandle;
|
||||
|
||||
- private MerchantOffer(ItemCost firstBuyItem, Optional<ItemCost> secondBuyItem, ItemStack sellItem, int uses, int maxUses, boolean rewardingPlayerExperience, int specialPrice, int demandBonus, float priceMultiplier, int merchantExperience) {
|
||||
+ public CraftMerchantRecipe asBukkit() {
|
||||
+ return (this.bukkitHandle == null) ? this.bukkitHandle = new CraftMerchantRecipe(this) : this.bukkitHandle;
|
||||
+ }
|
||||
+
|
||||
+ public MerchantOffer(ItemCost baseCostA, Optional<ItemCost> costB, ItemStack result, int uses, int maxUses, int experience, float priceMultiplier, int demand, final boolean ignoreDiscounts, CraftMerchantRecipe bukkit) { // Paper
|
||||
+ this(baseCostA, costB, result, uses, maxUses, experience, priceMultiplier, demand);
|
||||
+ this.ignoreDiscounts = ignoreDiscounts; // Paper
|
||||
+ this.bukkitHandle = bukkit;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ private MerchantOffer(ItemCost firstBuyItem, Optional<ItemCost> secondBuyItem, ItemStack sellItem, int uses, int maxUses, boolean rewardingPlayerExperience, int specialPrice, int demandBonus, float priceMultiplier, int merchantExperience, final boolean ignoreDiscounts) { // Paper
|
||||
this.baseCostA = firstBuyItem;
|
||||
this.costB = secondBuyItem;
|
||||
this.result = sellItem;
|
||||
@@ -56,6 +76,7 @@
|
||||
this.demand = demandBonus;
|
||||
this.priceMultiplier = priceMultiplier;
|
||||
this.xp = merchantExperience;
|
||||
+ this.ignoreDiscounts = ignoreDiscounts; // Paper
|
||||
}
|
||||
|
||||
public MerchantOffer(ItemCost buyItem, ItemStack sellItem, int maxUses, int merchantExperience, float priceMultiplier) {
|
||||
@@ -71,11 +92,11 @@
|
||||
}
|
||||
|
||||
public MerchantOffer(ItemCost firstBuyItem, Optional<ItemCost> secondBuyItem, ItemStack sellItem, int uses, int maxUses, int merchantExperience, float priceMultiplier, int demandBonus) {
|
||||
- this(firstBuyItem, secondBuyItem, sellItem, uses, maxUses, true, 0, demandBonus, priceMultiplier, merchantExperience);
|
||||
+ this(firstBuyItem, secondBuyItem, sellItem, uses, maxUses, true, 0, demandBonus, priceMultiplier, merchantExperience, false); // Paper
|
||||
}
|
||||
|
||||
private MerchantOffer(MerchantOffer offer) {
|
||||
- this(offer.baseCostA, offer.costB, offer.result.copy(), offer.uses, offer.maxUses, offer.rewardExp, offer.specialPriceDiff, offer.demand, offer.priceMultiplier, offer.xp);
|
||||
+ this(offer.baseCostA, offer.costB, offer.result.copy(), offer.uses, offer.maxUses, offer.rewardExp, offer.specialPriceDiff, offer.demand, offer.priceMultiplier, offer.xp, offer.ignoreDiscounts); // Paper
|
||||
}
|
||||
|
||||
public ItemStack getBaseCostA() {
|
||||
@@ -110,7 +131,7 @@
|
||||
}
|
||||
|
||||
public void updateDemand() {
|
||||
- this.demand = this.demand + this.uses - (this.maxUses - this.uses);
|
||||
+ this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
|
||||
}
|
||||
|
||||
public ItemStack assemble() {
|
||||
@@ -185,7 +206,11 @@
|
||||
if (!this.satisfiedBy(firstBuyStack, secondBuyStack)) {
|
||||
return false;
|
||||
} else {
|
||||
- firstBuyStack.shrink(this.getCostA().getCount());
|
||||
+ // CraftBukkit start
|
||||
+ if (!this.getCostA().isEmpty()) {
|
||||
+ firstBuyStack.shrink(this.getCostA().getCount());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
if (!this.getCostB().isEmpty()) {
|
||||
secondBuyStack.shrink(this.getCostB().getCount());
|
||||
}
|
||||
Reference in New Issue
Block a user