This commit is contained in:
Bjarne Koll 2024-10-23 19:46:06 +02:00
parent f5177aa121
commit 2810f50ca2
No known key found for this signature in database
GPG key ID: 27F6CCCF55D2EE62
40 changed files with 200 additions and 197 deletions

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sat, 9 Jan 2021 14:17:07 +0100
Subject: [PATCH] Remove stale POIs
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index fdcc744cd210535067a69362411305e23f0e4273..85c83c900c33d139072d17e1850e95d86da324a7 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1743,6 +1743,11 @@ public class ServerLevel extends Level implements WorldGenLevel {
});
optional1.ifPresent((holder) -> {
this.getServer().execute(() -> {
+ // Paper start - Remove stale POIs
+ if (optional.isEmpty() && this.getPoiManager().exists(blockposition1, poiType -> true)) {
+ this.getPoiManager().remove(blockposition1);
+ }
+ // Paper end - Remove stale POIs
this.getPoiManager().add(blockposition1, holder);
DebugPackets.sendPoiAddedPacket(this, blockposition1);
});

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Mon, 11 Jan 2021 12:43:51 -0800
Subject: [PATCH] Fix villager boat exploit
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 98eb00a8ee23543714d424d3ff5ca19887d6db19..9436a9614dea81d14c4f77cc21ca91f85ca87152 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -595,6 +595,14 @@ public abstract class PlayerList {
PlayerList.LOGGER.debug("Removing player mount");
entityplayer.stopRiding();
entity.getPassengersAndSelf().forEach((entity1) -> {
+ // Paper start - Fix villager boat exploit
+ if (entity1 instanceof net.minecraft.world.entity.npc.AbstractVillager villager) {
+ final net.minecraft.world.entity.player.Player human = villager.getTradingPlayer();
+ if (human != null) {
+ villager.setTradingPlayer(null);
+ }
+ }
+ // Paper end - Fix villager boat exploit
entity1.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause
});
}

View file

@ -1,53 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mariell Hoversholm <proximyst@proximyst.com>
Date: Tue, 29 Dec 2020 15:03:03 +0100
Subject: [PATCH] Add sendOpLevel API
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 9436a9614dea81d14c4f77cc21ca91f85ca87152..9b94ca912f99a3a465f30130b24347fc9aca72ff 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -1066,6 +1066,11 @@ public abstract class PlayerList {
}
private void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel) {
+ // Paper start - Add sendOpLevel API
+ this.sendPlayerPermissionLevel(player, permissionLevel, true);
+ }
+ public void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel, boolean recalculatePermissions) {
+ // Paper end - Add sendOpLevel API
if (player.connection != null) {
byte b0;
@@ -1080,8 +1085,10 @@ public abstract class PlayerList {
player.connection.send(new ClientboundEntityEventPacket(player, b0));
}
+ if (recalculatePermissions) { // Paper - Add sendOpLevel API
player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
this.server.getCommands().sendCommands(player);
+ } // Paper - Add sendOpLevel API
}
public boolean isWhiteListed(GameProfile profile) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 73fde8be0098238582fb3661ae67d4139be417dc..7de53f6750d478a052bc8ade6edac056565fe068 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -677,6 +677,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
// Paper end
+ // Paper start - Add sendOpLevel API
+ @Override
+ public void sendOpLevel(byte level) {
+ Preconditions.checkArgument(level >= 0 && level <= 4, "Level must be within [0, 4]");
+
+ this.getHandle().getServer().getPlayerList().sendPlayerPermissionLevel(this.getHandle(), level, false);
+ }
+ // Paper end - Add sendOpLevel API
+
@Override
public void setCompassTarget(Location loc) {
Preconditions.checkArgument(loc != null, "Location cannot be null");

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: dfsek <dfsek@protonmail.com>
Date: Wed, 16 Sep 2020 01:12:29 -0700
Subject: [PATCH] Add StructuresLocateEvent
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
index 0a779632c9d11496fcfc147870fba2699d9cc274..5adc1952504b26772116b55a5144b7704136edfa 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -126,6 +126,24 @@ public abstract class ChunkGenerator {
@Nullable
public Pair<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel world, HolderSet<Structure> structures, BlockPos center, int radius, boolean skipReferencedStructures) {
+ // Paper start - StructuresLocateEvent
+ final org.bukkit.World bukkitWorld = world.getWorld();
+ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(world, center);
+ final List<org.bukkit.generator.structure.Structure> apiStructures = structures.stream().map(Holder::value).map(nms -> org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(nms)).toList();
+ if (!apiStructures.isEmpty()) {
+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, radius, skipReferencedStructures);
+ if (!event.callEvent()) {
+ return null;
+ }
+ if (event.getResult() != null) {
+ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), world.registryAccess().registryOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(event.getResult().structure())));
+ }
+ center = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin());
+ radius = event.getRadius();
+ skipReferencedStructures = event.shouldFindUnexplored();
+ structures = HolderSet.direct(api -> world.registryAccess().registryOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(api)), event.getStructures());
+ }
+ // Paper end
ChunkGeneratorStructureState chunkgeneratorstructurestate = world.getChunkSource().getGeneratorState();
Map<StructurePlacement, Set<Holder<Structure>>> map = new Object2ObjectArrayMap();
Iterator iterator = structures.iterator();

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mariell Hoversholm <proximyst@proximyst.com>
Date: Sat, 14 Nov 2020 16:48:37 +0100
Subject: [PATCH] Collision option for requiring a player participant
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index bed376337035545e7ec677f2f7fe3372a3c9ea25..7d131f3b3f5739468aa3115e97ed28b6bfeca33d 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1936,6 +1936,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public void push(Entity entity) {
if (!this.isPassengerOfSameVehicle(entity)) {
if (!entity.noPhysics && !this.noPhysics) {
+ if (this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof ServerPlayer || this instanceof ServerPlayer)) return; // Paper - Collision option for requiring a player participant
double d0 = entity.getX() - this.getX();
double d1 = entity.getZ() - this.getZ();
double d2 = Mth.absMax(d0, d1);
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
index 4d8c14d3a42f3e4b963cf5f8fa764df79813912b..93634fb01962ca7a35026e3c365f2a7f6b258a39 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
@@ -799,6 +799,7 @@ public abstract class AbstractMinecart extends VehicleEntity {
public void push(Entity entity) {
if (!this.level().isClientSide) {
if (!entity.noPhysics && !this.noPhysics) {
+ if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant
if (!this.hasPassenger(entity)) {
// CraftBukkit start
VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), entity.getBukkitEntity());
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
index 2cb535639bff0e867c1b1e845fee6e34bb237044..907f751c859855484151fb5d607acee2f2a35076 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
@@ -204,6 +204,7 @@ public class Boat extends VehicleEntity implements Leashable, VariantHolder<Boat
@Override
public void push(Entity entity) {
+ if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant
if (entity instanceof Boat) {
if (entity.getBoundingBox().minY < this.getBoundingBox().maxY) {
// CraftBukkit start

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: CDFN <codefun@protonmail.com>
Date: Tue, 7 Jul 2020 17:53:23 +0200
Subject: [PATCH] Return chat component with empty text instead of throwing
exception
diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
index fe8d66893aa2c2ca6fc57ea96479ce4d646d8619..b8d8aad81f54f7f43c01da075e63ec9173750bec 100644
--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -89,7 +89,12 @@ public abstract class AbstractContainerMenu {
}
private Component title;
public final Component getTitle() {
- Preconditions.checkState(this.title != null, "Title not set");
+ // Paper start - return chat component with empty text instead of throwing error
+ // Preconditions.checkState(this.title != null, "Title not set");
+ if (this.title == null){
+ return Component.literal("");
+ }
+ // Paper end - return chat component with empty text instead of throwing error
return this.title;
}
public final void setTitle(Component title) {

View file

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 4 Jan 2021 19:52:44 -0800
Subject: [PATCH] Make schedule command per-world
diff --git a/src/main/java/net/minecraft/server/commands/ScheduleCommand.java b/src/main/java/net/minecraft/server/commands/ScheduleCommand.java
index f2d1430d714debc9e9b53eef0cbcda0d8cdcd459..d090f94a9a8a314df01e83a031dd18d5c6f1caf9 100644
--- a/src/main/java/net/minecraft/server/commands/ScheduleCommand.java
+++ b/src/main/java/net/minecraft/server/commands/ScheduleCommand.java
@@ -30,7 +30,7 @@ public class ScheduleCommand {
return Component.translatableEscape("commands.schedule.cleared.failure", object);
});
private static final SuggestionProvider<CommandSourceStack> SUGGEST_SCHEDULE = (commandcontext, suggestionsbuilder) -> {
- return SharedSuggestionProvider.suggest((Iterable) ((CommandSourceStack) commandcontext.getSource()).getServer().getWorldData().overworldData().getScheduledEvents().getEventsIds(), suggestionsbuilder);
+ return SharedSuggestionProvider.suggest((Iterable) ((net.minecraft.commands.CommandSourceStack) commandcontext.getSource()).getLevel().serverLevelData.getScheduledEvents().getEventsIds(), suggestionsbuilder); // Paper - Make schedule command per-world
};
public ScheduleCommand() {}
@@ -85,7 +85,7 @@ public class ScheduleCommand {
}
private static int remove(CommandSourceStack source, String eventName) throws CommandSyntaxException {
- int i = source.getServer().getWorldData().overworldData().getScheduledEvents().remove(eventName);
+ int i = source.getLevel().serverLevelData.getScheduledEvents().remove(eventName); // Paper - Make schedule command per-world
if (i == 0) {
throw ScheduleCommand.ERROR_CANT_REMOVE.create(eventName);

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 3 Jan 2021 21:04:03 -0800
Subject: [PATCH] Configurable max leash distance
diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java
index 1f2d04a456c383815b0c5ef331471593556fd128..5c51dd5229689cba459655d488aee59bd159a414 100644
--- a/src/main/java/net/minecraft/world/entity/Leashable.java
+++ b/src/main/java/net/minecraft/world/entity/Leashable.java
@@ -179,7 +179,7 @@ public interface Leashable {
return;
}
- if ((double) f > 10.0D) {
+ if ((double) f > entity.level().paperConfig().misc.maxLeashDistance.or(LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance
((Leashable) entity).leashTooFarBehaviour();
} else if ((double) f > 6.0D) {
((Leashable) entity).elasticRangeLeashBehaviour(entity1, f);
diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java
index f2d311a5450eb684603580bbf7e9e7fc73fc2f5c..bf2c9134c7d9d5926add36b55e3cfea79e8c8243 100644
--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java
+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java
@@ -97,7 +97,7 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity {
@Override
public boolean handleLeashAtDistance(Entity leashHolder, float distance) {
if (this.isInSittingPose()) {
- if (distance > 10.0F) {
+ if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance
this.dropLeash(true, true);
}

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Madeline Miller <mnmiller1@me.com>
Date: Sun, 17 Jan 2021 13:16:09 +1000
Subject: [PATCH] Add BlockPreDispenseEvent
diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
index 94bcbaf7daf7dfe566f508d1170a433930d9d49a..f6edfea463b3725d3a79aca38825e86dbf82175c 100644
--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
@@ -110,6 +110,7 @@ public class DispenserBlock extends BaseEntityBlock {
DispenseItemBehavior idispensebehavior = this.getDispenseMethod(world, itemstack);
if (idispensebehavior != DispenseItemBehavior.NOOP) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent
DispenserBlock.eventFired = false; // CraftBukkit - reset event status
tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack));
}
diff --git a/src/main/java/net/minecraft/world/level/block/DropperBlock.java b/src/main/java/net/minecraft/world/level/block/DropperBlock.java
index 91b514967405115f22edf4255775361a672e5c2f..ddecf443df3679e3098eb54edd19585a0512e342 100644
--- a/src/main/java/net/minecraft/world/level/block/DropperBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DropperBlock.java
@@ -71,6 +71,7 @@ public class DropperBlock extends DispenserBlock {
ItemStack itemstack1;
if (iinventory == null) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent
itemstack1 = DropperBlock.DISPENSE_BEHAVIOUR.dispense(sourceblock, itemstack);
} else {
// CraftBukkit start - Fire event when pushing items into other inventories
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 9e67dc35ea12149265517b951a96828460b2ca67..251b605396b77b0c449972c1da75978f57587e1a 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -2134,5 +2134,11 @@ public class CraftEventFactory {
io.papermc.paper.event.block.BlockFailedDispenseEvent event = new io.papermc.paper.event.block.BlockFailedDispenseEvent(block);
return event.callEvent();
}
+
+ public static boolean handleBlockPreDispenseEvent(ServerLevel serverLevel, BlockPos pos, ItemStack itemStack, int slot) {
+ org.bukkit.block.Block block = CraftBlock.at(serverLevel, pos);
+ io.papermc.paper.event.block.BlockPreDispenseEvent event = new io.papermc.paper.event.block.BlockPreDispenseEvent(block, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), slot);
+ return event.callEvent();
+ }
// Paper end
}

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 24 Jun 2020 15:14:51 -0600
Subject: [PATCH] Add PlayerChangeBeaconEffectEvent
diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
index 7c4d2c184d9a1e4a1856e6771d39db384381e300..396559c281eee9e8c677cb222721414e8d9e12a2 100644
--- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
@@ -171,12 +171,25 @@ public class BeaconMenu extends AbstractContainerMenu {
return BeaconMenu.decodeEffect(this.beaconData.get(2));
}
+ // Paper start - Add PlayerChangeBeaconEffectEvent
+ private static @Nullable org.bukkit.potion.PotionEffectType convert(Optional<Holder<MobEffect>> optionalEffect) {
+ return optionalEffect.map(org.bukkit.craftbukkit.potion.CraftPotionEffectType::minecraftHolderToBukkit).orElse(null);
+ }
+ // Paper end - Add PlayerChangeBeaconEffectEvent
+
public void updateEffects(Optional<Holder<MobEffect>> primary, Optional<Holder<MobEffect>> secondary) {
if (this.paymentSlot.hasItem()) {
- this.beaconData.set(1, BeaconMenu.encodeEffect((Holder) primary.orElse(null)));// CraftBukkit - decompile error
- this.beaconData.set(2, BeaconMenu.encodeEffect((Holder) secondary.orElse(null)));// CraftBukkit - decompile error
+ // Paper start - Add PlayerChangeBeaconEffectEvent
+ io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent event = new io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent((org.bukkit.entity.Player) this.player.player.getBukkitEntity(), convert(primary), convert(secondary), this.access.getLocation().getBlock());
+ if (event.callEvent()) {
+ // Paper end - Add PlayerChangeBeaconEffectEvent
+ this.beaconData.set(1, BeaconMenu.encodeEffect(event.getPrimary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getPrimary())));// CraftBukkit - decompile error
+ this.beaconData.set(2, BeaconMenu.encodeEffect(event.getSecondary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getSecondary())));// CraftBukkit - decompile error
+ if (event.willConsumeItem()) { // Paper
this.paymentSlot.remove(1);
+ } // Paper
this.access.execute(Level::blockEntityChanged);
+ } // Paper end - Add PlayerChangeBeaconEffectEvent
}
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Thu, 26 Nov 2020 11:47:24 +0000
Subject: [PATCH] Add toggle for always placing the dragon egg
diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
index d6deedb96583c19eeb27e671289c4edc8a9245b4..4f3fdc6ea0cafd61f778edb6a967bd0eb00abdb9 100644
--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -409,7 +409,7 @@ public class EndDragonFight {
this.dragonEvent.setVisible(false);
this.spawnExitPortal(true);
this.spawnNewGateway();
- if (!this.previouslyKilled) {
+ if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - Add toggle for always placing the dragon egg
this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState());
}

View file

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 27 Nov 2020 17:14:27 -0800
Subject: [PATCH] Add PlayerStonecutterRecipeSelectEvent
Co-Authored-By: MiniDigger <admin@benndorf.dev>
diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
index 5b4f03128499b0c1a4b8c5f5ccd17e4bdb391e81..37e75c02c374314372630f4bda0b92519809f2a4 100644
--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
@@ -64,7 +64,7 @@ public class StonecutterMenu extends AbstractContainerMenu {
public StonecutterMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) {
super(MenuType.STONECUTTER, syncId);
- this.selectedRecipeIndex = DataSlot.standalone();
+ this.selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent
this.recipes = Lists.newArrayList();
this.input = ItemStack.EMPTY;
this.slotUpdateListener = () -> {
@@ -162,7 +162,30 @@ public class StonecutterMenu extends AbstractContainerMenu {
@Override
public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) {
if (this.isValidRecipeIndex(id)) {
- this.selectedRecipeIndex.set(id);
+ // Paper start - Add PlayerStonecutterRecipeSelectEvent
+ int recipeIndex = id;
+ this.selectedRecipeIndex.set(recipeIndex);
+ this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed
+ if (this.isValidRecipeIndex(id)) {
+ io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((Player) player.getBukkitEntity(), (org.bukkit.inventory.StonecutterInventory) getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) this.getRecipes().get(id).toBukkitRecipe());
+ if (!event.callEvent()) {
+ player.containerMenu.sendAllDataToRemote();
+ return false;
+ }
+
+ net.minecraft.resources.ResourceLocation key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey());
+ if (!this.getRecipes().get(recipeIndex).id().equals(key)) { // If the recipe did NOT stay the same
+ for (int newRecipeIndex = 0; newRecipeIndex < this.getRecipes().size(); newRecipeIndex++) {
+ if (this.getRecipes().get(newRecipeIndex).id().equals(key)) {
+ recipeIndex = newRecipeIndex;
+ break;
+ }
+ }
+ }
+ }
+ player.containerMenu.sendAllDataToRemote();
+ this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it
+ // Paper end - Add PlayerStonecutterRecipeSelectEvent
this.setupResultSlot();
}

View file

@ -1,158 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Fri, 29 Jan 2021 15:13:11 +0100
Subject: [PATCH] Expand EntityUnleashEvent
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 7d131f3b3f5739468aa3115e97ed28b6bfeca33d..da184893d617311a43f9ce176a965f8417a2876d 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2574,12 +2574,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
if (leashable.getLeashHolder() == player) {
if (!this.level().isClientSide()) {
// CraftBukkit start - fire PlayerUnleashEntityEvent
- if (CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand).isCancelled()) {
+ // Paper start - Expand EntityUnleashEvent
+ org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials());
+ if (event.isCancelled()) {
+ // Paper end - Expand EntityUnleashEvent
((ServerPlayer) player).connection.send(new ClientboundSetEntityLinkPacket(this, leashable.getLeashHolder()));
return InteractionResult.PASS;
}
// CraftBukkit end
- leashable.dropLeash(true, !player.hasInfiniteMaterials());
+ leashable.dropLeash(true, event.isDropLeash()); // Paper - Expand EntityUnleashEvent
this.gameEvent(GameEvent.ENTITY_INTERACT, player);
}
@@ -3449,9 +3452,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
protected void removeAfterChangingDimensions() {
this.setRemoved(Entity.RemovalReason.CHANGED_DIMENSION, null); // CraftBukkit - add Bukkit remove cause
- if (this instanceof Leashable leashable) {
- this.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit
- leashable.dropLeash(true, false);
+ if (this instanceof Leashable leashable && leashable.isLeashed()) { // Paper - only call if it is leashed
+ // Paper start - Expand EntityUnleashEvent
+ final EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN, false); // CraftBukkit
+ event.callEvent();
+ leashable.dropLeash(true, event.isDropLeash());
+ // Paper end - Expand EntityUnleashEvent
}
}
diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java
index 5c51dd5229689cba459655d488aee59bd159a414..e7535f15be3cc1537aafee53779ccfb4f21d1f38 100644
--- a/src/main/java/net/minecraft/world/entity/Leashable.java
+++ b/src/main/java/net/minecraft/world/entity/Leashable.java
@@ -166,8 +166,11 @@ public interface Leashable {
if (leashable_a != null && leashable_a.leashHolder != null) {
if (!entity.isAlive() || !leashable_a.leashHolder.isAlive()) {
- entity.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(entity.getBukkitEntity(), (!entity.isAlive()) ? UnleashReason.PLAYER_UNLEASH : UnleashReason.HOLDER_GONE)); // CraftBukkit
- Leashable.dropLeash(entity, true, !entity.pluginRemoved); // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin
+ // Paper start - Expand EntityUnleashEvent
+ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), (!entity.isAlive()) ? UnleashReason.PLAYER_UNLEASH : UnleashReason.HOLDER_GONE, !entity.pluginRemoved);
+ event.callEvent();
+ Leashable.dropLeash(entity, true, event.isDropLeash()); // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin
+ // Paper end - Expand EntityUnleashEvent
}
Entity entity1 = ((Leashable) entity).getLeashHolder();
@@ -198,11 +201,16 @@ public interface Leashable {
default void leashTooFarBehaviour() {
// CraftBukkit start
+ boolean dropLeash = true; // Paper
if (this instanceof Entity entity) {
- entity.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(entity.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE));
+ // Paper start - Expand EntityUnleashEvent
+ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true);
+ if (!event.callEvent()) return;
+ dropLeash = event.isDropLeash();
+ // Paper end - Expand EntityUnleashEvent
}
// CraftBukkit end
- this.dropLeash(true, true);
+ this.dropLeash(true, dropLeash); // Paper
}
default void closeRangeLeashBehaviour(Entity entity) {}
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index b46572f6e3b52f498b395d3b8c5def2aa799ff03..e87360e21e6eb7b0161c34a3ac6cb83d18bcd1e8 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -1621,8 +1621,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
boolean flag1 = super.startRiding(entity, force);
if (flag1 && this.isLeashed()) {
- this.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit
- this.dropLeash(true, true);
+ // Paper start - Expand EntityUnleashEvent
+ EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.UNKNOWN, true);
+ if (!event.callEvent()) { return flag1; }
+ this.dropLeash(true, event.isDropLeash());
+ // Paper end - Expand EntityUnleashEvent
}
return flag1;
diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java
index bf2c9134c7d9d5926add36b55e3cfea79e8c8243..7b7bc1a205dfacbe5709011b6b6799e75af9e4cc 100644
--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java
+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java
@@ -98,7 +98,11 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity {
public boolean handleLeashAtDistance(Entity leashHolder, float distance) {
if (this.isInSittingPose()) {
if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance
- this.dropLeash(true, true);
+ // Paper start - Expand EntityUnleashEvent
+ org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(this.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true);
+ if (!event.callEvent()) return false;
+ this.dropLeash(true, event.isDropLeash());
+ // Paper end - Expand EntityUnleashEvent
}
return false;
diff --git a/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java b/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java
index 3c0af74ed65610b1d5e3b72fdcf28c5a3423f0da..01173fc7177d78588978e087e63efda0b0527c2f 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java
@@ -118,13 +118,18 @@ public class LeashFenceKnotEntity extends BlockAttachedEntity {
if (leashable1.isLeashed() && leashable1.getLeashHolder() == this) {
// CraftBukkit start
+ boolean dropLeash = !player.hasInfiniteMaterials();
if (leashable1 instanceof Entity leashed) {
- if (CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand).isCancelled()) {
+ // Paper start - Expand EntityUnleashEvent
+ org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand, dropLeash);
+ dropLeash = event.isDropLeash();
+ if (event.isCancelled()) {
+ // Paper end - Expand EntityUnleashEvent
die = false;
continue;
}
}
- leashable1.dropLeash(true, !player.getAbilities().instabuild); // false -> survival mode boolean
+ leashable1.dropLeash(true, dropLeash); // false -> survival mode boolean // Paper - Expand EntityUnleashEvent
// CraftBukkit end
flag1 = true;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 251b605396b77b0c449972c1da75978f57587e1a..c48a9026c4db2005b67c5f70e9e1fa95b7820bc0 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1598,8 +1598,10 @@ public class CraftEventFactory {
Bukkit.getPluginManager().callEvent(new PlayerRecipeBookSettingsChangeEvent(player.getBukkitEntity(), bukkitType, open, filter));
}
- public static PlayerUnleashEntityEvent callPlayerUnleashEntityEvent(Entity entity, net.minecraft.world.entity.player.Player player, InteractionHand enumhand) {
- PlayerUnleashEntityEvent event = new PlayerUnleashEntityEvent(entity.getBukkitEntity(), (Player) player.getBukkitEntity(), CraftEquipmentSlot.getHand(enumhand));
+ // Paper start - Expand EntityUnleashEvent
+ public static PlayerUnleashEntityEvent callPlayerUnleashEntityEvent(Entity entity, net.minecraft.world.entity.player.Player player, InteractionHand enumhand, boolean dropLeash) {
+ PlayerUnleashEntityEvent event = new PlayerUnleashEntityEvent(entity.getBukkitEntity(), (Player) player.getBukkitEntity(), CraftEquipmentSlot.getHand(enumhand), dropLeash);
+ // Paper end - Expand EntityUnleashEvent
entity.level().getCraftServer().getPluginManager().callEvent(event);
return event;
}

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yive <admin@yive.me>
Date: Sun, 24 Jan 2021 08:55:19 -0800
Subject: [PATCH] Reset shield blocking on dimension change
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 2ea613f818403f8e8ece4b36891738139345cf89..fffd3ae6c4fc0b86057cd915bb4f0987f41a64d0 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1349,6 +1349,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld());
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
// CraftBukkit end
+ // Paper start - Reset shield blocking on dimension change
+ if (this.isBlocking()) {
+ this.stopUsingItem();
+ }
+ // Paper end - Reset shield blocking on dimension change
return this;
}
}

View file

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Trigary <trigary0@gmail.com>
Date: Mon, 25 Jan 2021 14:53:57 +0100
Subject: [PATCH] Add DragonEggFormEvent
diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
index 4f3fdc6ea0cafd61f778edb6a967bd0eb00abdb9..460744ec3a1abe9a2d9d16c2ec521c52c7f8db95 100644
--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -409,8 +409,22 @@ public class EndDragonFight {
this.dragonEvent.setVisible(false);
this.spawnExitPortal(true);
this.spawnNewGateway();
+ // Paper start - Add DragonEggFormEvent
+ BlockPos eggPosition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin));
+ org.bukkit.craftbukkit.block.CraftBlockState eggState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.level, eggPosition);
+ eggState.setData(Blocks.DRAGON_EGG.defaultBlockState());
+ io.papermc.paper.event.block.DragonEggFormEvent eggEvent = new io.papermc.paper.event.block.DragonEggFormEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this.level, eggPosition), eggState,
+ new org.bukkit.craftbukkit.boss.CraftDragonBattle(this));
+ // Paper end - Add DragonEggFormEvent
if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - Add toggle for always placing the dragon egg
- this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState());
+ // Paper start - Add DragonEggFormEvent
+ // this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState());
+ } else {
+ eggEvent.setCancelled(true);
+ }
+ if (eggEvent.callEvent()) {
+ eggEvent.getNewState().update(true);
+ // Paper end - Add DragonEggFormEvent
}
this.previouslyKilled = true;

View file

@ -1,55 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Tue, 11 Feb 2020 21:56:48 -0600
Subject: [PATCH] Add EntityMoveEvent
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 39ce74bc3fbb282f56028273d53f980171bdb464..43b28b56c7949f95af5b7e99b04b93ed711d8880 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1605,6 +1605,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
+ worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
this.profiler.push(() -> {
String s = String.valueOf(worldserver);
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 373560fc82e491e6c8b755fecfe78d49a2fc3e2f..644341b8bc3079c6f092226acd11667f64bd55a1 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -228,6 +228,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final LevelStorageSource.LevelStorageAccess convertable;
public final UUID uuid;
public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
+ public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunk(x, z, false);
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index d94c3e86885c5a8ba636988d29f98b496e13b627..a89c6ba4140f15e7f68f0df5cf64a176d350123b 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3510,6 +3510,20 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.pushEntities();
this.level().getProfiler().pop();
+ // Paper start - Add EntityMoveEvent
+ if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) {
+ if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) {
+ Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO);
+ Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+ io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone());
+ if (!event.callEvent()) {
+ this.absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch());
+ } else if (!to.equals(event.getTo())) {
+ this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
+ }
+ }
+ }
+ // Paper end - Add EntityMoveEvent
if (!this.level().isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
this.hurt(this.damageSources().drown(), 1.0F);
}

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lukas81298 <lukas81298@gommehd.net>
Date: Mon, 25 Jan 2021 14:37:57 +0100
Subject: [PATCH] added option to disable pathfinding updates on block changes
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 644341b8bc3079c6f092226acd11667f64bd55a1..1fe013b94cf1b5332f1e4645dd35df01e11fe0d9 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1374,6 +1374,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.getChunkSource().blockChanged(pos);
this.pathTypesByPosCache.invalidate(pos);
+ if (this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates
VoxelShape voxelshape = oldState.getCollisionShape(this, pos);
VoxelShape voxelshape1 = newState.getCollisionShape(this, pos);
@@ -1415,6 +1416,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
}
+ } // Paper - option to disable pathfinding updates
}
@Override

View file

@ -1,56 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn <git@steinborn.me>
Date: Mon, 18 Jan 2021 20:45:25 -0500
Subject: [PATCH] Inline shift direction fields
Removes a layer of indirection for EnumDirection.getAdjacent(X|Y|Z)(), which is in the
critical section for much of the server, including the lighting engine.
diff --git a/src/main/java/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java
index c47e6acbd36737aa7af13b452f51b3f017d324f4..03c45ee77276462818a6f774b5945b25924aa3f0 100644
--- a/src/main/java/net/minecraft/core/Direction.java
+++ b/src/main/java/net/minecraft/core/Direction.java
@@ -55,6 +55,12 @@ public enum Direction implements StringRepresentable {
.sorted(Comparator.comparingInt(direction -> direction.data2d))
.toArray(Direction[]::new);
+ // Paper start - Perf: Inline shift direction fields
+ private final int adjX;
+ private final int adjY;
+ private final int adjZ;
+ // Paper end - Perf: Inline shift direction fields
+
private Direction(
final int id,
final int idOpposite,
@@ -71,6 +77,11 @@ public enum Direction implements StringRepresentable {
this.axis = axis;
this.axisDirection = direction;
this.normal = vector;
+ // Paper start - Perf: Inline shift direction fields
+ this.adjX = vector.getX();
+ this.adjY = vector.getY();
+ this.adjZ = vector.getZ();
+ // Paper end - Perf: Inline shift direction fields
}
public static Direction[] orderedByNearest(Entity entity) {
@@ -234,15 +245,15 @@ public enum Direction implements StringRepresentable {
}
public int getStepX() {
- return this.normal.getX();
+ return this.adjX; // Paper - Perf: Inline shift direction fields
}
public int getStepY() {
- return this.normal.getY();
+ return this.adjY; // Paper - Perf: Inline shift direction fields
}
public int getStepZ() {
- return this.normal.getZ();
+ return this.adjZ; // Paper - Perf: Inline shift direction fields
}
public Vector3f step() {

View file

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Wed, 20 Jan 2021 14:23:37 -0600
Subject: [PATCH] Allow adding items to BlockDropItemEvent
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index c48a9026c4db2005b67c5f70e9e1fa95b7820bc0..36adcab02e97cae2d087bae74cc4ceaf3052a9f8 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -462,13 +462,30 @@ public class CraftEventFactory {
}
public static void handleBlockDropItemEvent(Block block, BlockState state, ServerPlayer player, List<ItemEntity> items) {
- BlockDropItemEvent event = new BlockDropItemEvent(block, state, player.getBukkitEntity(), Lists.transform(items, (item) -> (org.bukkit.entity.Item) item.getBukkitEntity()));
+ // Paper start - Allow adding items to BlockDropItemEvent
+ List<Item> list = new ArrayList<>();
+ for (ItemEntity item : items) {
+ list.add((Item) item.getBukkitEntity());
+ }
+ BlockDropItemEvent event = new BlockDropItemEvent(block, state, player.getBukkitEntity(), list);
+ // Paper end - Allow adding items to BlockDropItemEvent
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
- for (ItemEntity item : items) {
- item.level().addFreshEntity(item);
+ // Paper start - Allow adding items to BlockDropItemEvent
+ for (Item bukkit : list) {
+ if (!bukkit.isValid()) {
+ Entity item = ((org.bukkit.craftbukkit.entity.CraftItem) bukkit).getHandle();
+ item.level().addFreshEntity(item);
+ }
+ }
+ } else {
+ for (Item bukkit : list) {
+ if (bukkit.isValid()) {
+ bukkit.remove();
+ }
}
+ // Paper end - Allow adding items to BlockDropItemEvent
}
}

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aleksander Jagiello <themolkapl@gmail.com>
Date: Sun, 24 Jan 2021 22:17:54 +0100
Subject: [PATCH] Add getMainThreadExecutor to BukkitScheduler
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index d7c2d8993a172e343669228cf24a58d8992a1c10..2f4d6b56301195f8d39ed50dffe842464065bfe1 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -642,4 +642,15 @@ public class CraftScheduler implements BukkitScheduler {
public BukkitTask runTaskTimerAsynchronously(Plugin plugin, BukkitRunnable task, long delay, long period) throws IllegalArgumentException {
throw new UnsupportedOperationException("Use BukkitRunnable#runTaskTimerAsynchronously(Plugin, long, long)");
}
+
+ // Paper start - add getMainThreadExecutor
+ @Override
+ public Executor getMainThreadExecutor(Plugin plugin) {
+ Preconditions.checkArgument(plugin != null, "Plugin cannot be null");
+ return command -> {
+ Preconditions.checkArgument(command != null, "Command cannot be null");
+ this.runTask(plugin, command);
+ };
+ }
+ // Paper end
}

View file

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ysl3000 <yannicklamprecht@live.de>
Date: Sat, 24 Oct 2020 16:37:44 +0200
Subject: [PATCH] living entity allow attribute registration
diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
index cd03d705337a0ea34c7c06a581294112433afb50..69992ebc999ea3ff9e47e4e049bcc514c01150ca 100644
--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
@@ -140,4 +140,12 @@ public class AttributeMap {
}
}
}
+
+ // Paper - start - living entity allow attribute registration
+ public void registerAttribute(Holder<Attribute> attributeBase) {
+ AttributeInstance attributeModifiable = new AttributeInstance(attributeBase, AttributeInstance::getAttribute);
+ attributes.put(attributeBase, attributeModifiable);
+ }
+ // Paper - end - living entity allow attribute registration
+
}
diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
index 5678d2007d5adf45dec0638c5dd848b601801814..0a7ed5a4f1644a70d8f98ad7a6962b814ad6daf4 100644
--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
@@ -35,4 +35,11 @@ public class CraftAttributeMap implements Attributable {
return (nms == null) ? null : new CraftAttributeInstance(nms, attribute);
}
+ // Paper start - living entity allow attribute registration
+ @Override
+ public void registerAttribute(Attribute attribute) {
+ Preconditions.checkArgument(attribute != null, "attribute");
+ handle.registerAttribute(CraftAttribute.bukkitToMinecraftHolder(attribute));
+ }
+ // Paper end - living entity allow attribute registration
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 10f3defa8f4b57fb45cf7de06d415b72102e47d5..e56a0d8928e3c0e27b1acd171162e4a53b70d925 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -768,6 +768,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
return this.getHandle().craftAttributes.getAttribute(attribute);
}
+ // Paper start - living entity allow attribute registration
+ @Override
+ public void registerAttribute(Attribute attribute) {
+ getHandle().craftAttributes.registerAttribute(attribute);
+ }
+ // Paper end - living entity allow attribute registration
+
@Override
public void setAI(boolean ai) {
if (this.getHandle() instanceof Mob) {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Trigary <trigary0@gmail.com>
Date: Fri, 5 Feb 2021 22:12:13 +0100
Subject: [PATCH] fix dead slime setSize invincibility
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java
index 3d9b7c0e128ea05bec5600c774e9685998b71cac..e48f7d1cbec4a2319745ba48a5d44ab9925214e2 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java
@@ -16,7 +16,7 @@ public class CraftSlime extends CraftMob implements Slime, CraftEnemy {
@Override
public void setSize(int size) {
- this.getHandle().setSize(size, true);
+ this.getHandle().setSize(size, /* true */ getHandle().isAlive()); // Paper - fix dead slime setSize invincibility
}
@Override

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Wed, 10 Feb 2021 14:53:36 -0800
Subject: [PATCH] Merchant#getRecipes should return an immutable list
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java
index 770686757a87d923ecb0361ba0939b4f7d184d76..72b5f6724278ec78605d7f435ef7ca340f195f5b 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java
@@ -16,7 +16,7 @@ public interface CraftMerchant extends Merchant {
@Override
default List<MerchantRecipe> getRecipes() {
- return Collections.unmodifiableList(Lists.transform(this.getMerchant().getOffers(), new Function<net.minecraft.world.item.trading.MerchantOffer, MerchantRecipe>() {
+ return List.copyOf(Lists.transform(this.getMerchant().getOffers(), new Function<net.minecraft.world.item.trading.MerchantOffer, MerchantRecipe>() { // Paper - javadoc says 'an immutable list of trades' - not 'an unmodifiable view of a list of trades'. fixes issue with setRecipes(getRecipes())
@Override
public MerchantRecipe apply(net.minecraft.world.item.trading.MerchantOffer recipe) {
return recipe.asBukkit();

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tom <cryptite@gmail.com>
Date: Fri, 26 Feb 2021 16:24:25 -0600
Subject: [PATCH] Expose Tracked Players
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 98e8ad81b8c9c0636abe59f70ce891fe926a37fe..96201ea45f8b53dcadb1a8732b1d49b1e8d1d7df 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1069,4 +1069,21 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return getHandle().isTicking();
}
// Paper end - isTicking API
+
+ // Paper start - tracked players API
+ @Override
+ public Set<org.bukkit.entity.Player> getTrackedPlayers() {
+ ServerLevel world = (net.minecraft.server.level.ServerLevel)this.entity.level();
+ ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.entity.getId());
+ if (tracker == null) {
+ return java.util.Collections.emptySet();
+ }
+
+ Set<org.bukkit.entity.Player> set = new java.util.HashSet<>(tracker.seenBy.size());
+ for (net.minecraft.server.network.ServerPlayerConnection connection : tracker.seenBy) {
+ set.add(connection.getPlayer().getBukkitEntity().getPlayer());
+ }
+ return set;
+ }
+ // Paper end - tracked players API
}

View file

@ -1,431 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlexProgrammerDE <40795980+AlexProgrammerDE@users.noreply.github.com>
Date: Sat, 3 Oct 2020 08:27:40 +0200
Subject: [PATCH] Improve ServerGUI
- Added logo to server frame
- Show tps in the server stats
diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
index f93373d28d741e1f8a53e07b4e328ce9c4e1657f..12b327eea95e0de9e9c39b7d039badee8ec46508 100644
--- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
@@ -58,9 +58,22 @@ public class RAMDetails extends JList<String> {
public void update() {
GraphData data = RAMGraph.DATA.peekLast();
Vector<String> vector = new Vector<>();
+
+ // Follows CraftServer#getTPS
+ double[] tps = new double[] {
+ server.tps1.getAverage(),
+ server.tps5.getAverage(),
+ server.tps15.getAverage()
+ };
+ String[] tpsAvg = new String[tps.length];
+
+ for ( int g = 0; g < tps.length; g++) {
+ tpsAvg[g] = format( tps[g] );
+ }
vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)");
vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb");
vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms");
+ vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg));
setListData(vector);
}
@@ -71,4 +84,8 @@ public class RAMDetails extends JList<String> {
}
return ((double) total / (double) tickTimes.length) * 1.0E-6D;
}
+
+ private static String format(double tps) {
+ return ( ( tps > 21.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 );
+ }
}
diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
index 8b570b0c3967a22c085f390110cb29cbd9c8feff..4d3fe4f56e0b264fa030409919caf52d5f421d46 100644
--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
@@ -59,6 +59,15 @@ public class MinecraftServerGui extends JComponent {
jframe.pack();
jframe.setLocationRelativeTo((Component) null);
jframe.setVisible(true);
+ jframe.setName("Minecraft server"); // Paper - Improve ServerGUI
+
+ // Paper start - Improve ServerGUI
+ try {
+ jframe.setIconImage(javax.imageio.ImageIO.read(Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png"))));
+ } catch (java.io.IOException ignore) {
+ }
+ // Paper end - Improve ServerGUI
+
jframe.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowevent) {
if (!servergui.isClosing.getAndSet(true)) {
diff --git a/src/main/java/net/minecraft/server/gui/StatsComponent.java b/src/main/java/net/minecraft/server/gui/StatsComponent.java
index 6e9c6d556ed55325e36d191fc9d1508c00879671..096c89bd01cec2abd151bf6fffc4847d1bcd548f 100644
--- a/src/main/java/net/minecraft/server/gui/StatsComponent.java
+++ b/src/main/java/net/minecraft/server/gui/StatsComponent.java
@@ -34,10 +34,19 @@ public class StatsComponent extends JComponent {
private void tick() {
long l = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+ // Paper start - Improve ServerGUI
+ double[] tps = org.bukkit.Bukkit.getTPS();
+ String[] tpsAvg = new String[tps.length];
+
+ for ( int g = 0; g < tps.length; g++) {
+ tpsAvg[g] = format( tps[g] );
+ }
this.msgs[0] = "Memory use: " + l / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)";
this.msgs[1] = "Avg tick: "
+ DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double)TimeUtil.NANOSECONDS_PER_MILLISECOND)
+ " ms";
+ this.msgs[2] = "TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg);
+ // Paper end - Improve ServerGUI
this.values[this.vp++ & 0xFF] = (int)(l * 100L / Runtime.getRuntime().maxMemory());
this.repaint();
}
@@ -66,4 +75,10 @@ public class StatsComponent extends JComponent {
public void close() {
this.timer.stop();
}
+
+ // Paper start - Improve ServerGUI
+ private static String format(double tps) {
+ return (( tps > 21.0 ) ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0); // only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise
+ }
+ // Paper end - Improve ServerGUI
}
diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b924977b7886df9ab8790b1e4ff9b1c04a2af45
GIT binary patch
literal 16900
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
LFIp>X81%mY^Bg|U
literal 0
HcmV?d00001

View file

@ -1,61 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 4 Jan 2021 19:49:15 -0800
Subject: [PATCH] fix converting txt to json file
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
index 929f59bce01c8e6ed4b0b551744d42e131b8fc80..22c4f8dea99f92a1eb3da2baf0a15bf9d2ca0462 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
@@ -18,6 +18,11 @@ public class DedicatedPlayerList extends PlayerList {
this.setViewDistance(dedicatedServerProperties.viewDistance);
this.setSimulationDistance(dedicatedServerProperties.simulationDistance);
super.setUsingWhiteList(dedicatedServerProperties.whiteList.get());
+ // Paper start - fix converting txt to json file; moved from constructor
+ }
+ @Override
+ public void loadAndSaveFiles() {
+ // Paper end - fix converting txt to json file
this.loadUserBanList();
this.saveUserBanList();
this.loadIpBanList();
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 2b1d7a2360a9ee7bca9d93a2dc8c61d1648a8348..d5153f804cfcfd1a70c46975e3fb1e50c8a82999 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -216,6 +216,12 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
// Paper end - initialize global and world-defaults configuration
+ // Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save
+ if (this.convertOldUsers()) {
+ this.getProfileCache().save(false); // Paper
+ }
+ this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames
+ // Paper end - fix converting txt to json file
org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
@@ -270,9 +276,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
DedicatedServer.LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file.");
}
- if (this.convertOldUsers()) {
- this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving
- }
if (!OldUsersConverter.serverReadyAfterUserconversion(this)) {
return false;
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 9b94ca912f99a3a465f30130b24347fc9aca72ff..123fe4f5b98a7483af86695ec82987abd45eafb2 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -179,6 +179,7 @@ public abstract class PlayerList {
this.maxPlayers = maxPlayers;
this.playerIo = saveHandler;
}
+ abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) {
player.isRealPlayer = true; // Paper

View file

@ -1,72 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 4 Jan 2021 22:40:34 -0800
Subject: [PATCH] Add worldborder events
diff --git a/src/main/java/net/minecraft/world/level/border/WorldBorder.java b/src/main/java/net/minecraft/world/level/border/WorldBorder.java
index 3442e33a1146318228c4727a2a5afde685f69bf7..04e62c54f224f7949fde9ceded208e700db55aa1 100644
--- a/src/main/java/net/minecraft/world/level/border/WorldBorder.java
+++ b/src/main/java/net/minecraft/world/level/border/WorldBorder.java
@@ -140,6 +140,14 @@ public class WorldBorder {
}
public void setCenter(double x, double z) {
+ // Paper start - Add worldborder events
+ if (this.world != null) {
+ io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), new org.bukkit.Location(world.getWorld(), this.getCenterX(), 0, this.getCenterZ()), new org.bukkit.Location(world.getWorld(), x, 0, z));
+ if (!event.callEvent()) return;
+ x = event.getNewCenter().getX();
+ z = event.getNewCenter().getZ();
+ }
+ // Paper end - Add worldborder events
this.centerX = x;
this.centerZ = z;
this.extent.onCenterChange();
@@ -166,6 +174,17 @@ public class WorldBorder {
}
public void setSize(double size) {
+ // Paper start - Add worldborder events
+ if (this.world != null) {
+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE, getSize(), size, 0);
+ if (!event.callEvent()) return;
+ if (event.getType() == io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE && event.getDuration() > 0) { // If changed to a timed transition
+ lerpSizeBetween(event.getOldSize(), event.getNewSize(), event.getDuration());
+ return;
+ }
+ size = event.getNewSize();
+ }
+ // Paper end - Add worldborder events
this.extent = new WorldBorder.StaticBorderExtent(size);
Iterator iterator = this.getListeners().iterator();
@@ -178,6 +197,20 @@ public class WorldBorder {
}
public void lerpSizeBetween(double fromSize, double toSize, long time) {
+ // Paper start - Add worldborder events
+ if (this.world != null) {
+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type type;
+ if (fromSize == toSize) { // new size = old size
+ type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE; // Use INSTANT_MOVE because below it creates a Static border if they are equal.
+ } else {
+ type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE;
+ }
+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), type, fromSize, toSize, time);
+ if (!event.callEvent()) return;
+ toSize = event.getNewSize();
+ time = event.getDuration();
+ }
+ // Paper end - Add worldborder events
this.extent = (WorldBorder.BorderExtent) (fromSize == toSize ? new WorldBorder.StaticBorderExtent(toSize) : new WorldBorder.MovingBorderExtent(fromSize, toSize, time));
Iterator iterator = this.getListeners().iterator();
@@ -489,6 +522,7 @@ public class WorldBorder {
@Override
public WorldBorder.BorderExtent update() {
+ if (world != null && this.getLerpRemainingTime() <= 0L) new io.papermc.paper.event.world.border.WorldBorderBoundsChangeFinishEvent(world.getWorld(), world.getWorld().getWorldBorder(), this.from, this.to, this.lerpDuration).callEvent(); // Paper - Add worldborder events
return (WorldBorder.BorderExtent) (this.getLerpRemainingTime() <= 0L ? WorldBorder.this.new StaticBorderExtent(this.to) : this);
}

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 5 Jul 2020 00:33:54 -0700
Subject: [PATCH] Add PlayerNameEntityEvent
diff --git a/src/main/java/net/minecraft/world/item/NameTagItem.java b/src/main/java/net/minecraft/world/item/NameTagItem.java
index 3ce8c725270510dbaaf2c1edc895d37ea9ca424c..774c982f28b4f127fc3f036c19dfb47fb9ae3264 100644
--- a/src/main/java/net/minecraft/world/item/NameTagItem.java
+++ b/src/main/java/net/minecraft/world/item/NameTagItem.java
@@ -18,8 +18,13 @@ public class NameTagItem extends Item {
Component component = stack.get(DataComponents.CUSTOM_NAME);
if (component != null && !(entity instanceof Player)) {
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();
}

View file

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com>
Date: Wed, 6 Jan 2021 12:04:03 -0800
Subject: [PATCH] Add recipe to cook events
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index 5ea2b05961590732a43bb5a1abf00bf8a00c72c2..84a3130a31f7a0fd5a8ae1b293dd3f2ca07c86d3 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -444,7 +444,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
CraftItemStack source = CraftItemStack.asCraftMirror(itemstack);
org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1);
- FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result);
+ FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result, (org.bukkit.inventory.CookingRecipe<?>) recipeholder.toBukkitRecipe()); // Paper - Add recipe to cook events
world.getCraftServer().getPluginManager().callEvent(furnaceSmeltEvent);
if (furnaceSmeltEvent.isCancelled()) {
diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
index 80f911692c97585a696a19ebbe616d6aa312b2d9..0c20a334be4b1c4cf7999826f8d9bff5e36bc2b8 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
@@ -67,7 +67,10 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) {
SingleRecipeInput singlerecipeinput = new SingleRecipeInput(itemstack);
- ItemStack itemstack1 = (ItemStack) campfire.quickCheck.getRecipeFor(singlerecipeinput, world).map((recipeholder) -> {
+ // Paper start - add recipe to cook events
+ Optional<RecipeHolder<CampfireCookingRecipe>> recipeHolderOptional = campfire.quickCheck.getRecipeFor(singlerecipeinput, world);
+ ItemStack itemstack1 = recipeHolderOptional.map((recipeholder) -> {
+ // Paper end - Add recipe to cook events
return ((CampfireCookingRecipe) recipeholder.value()).assemble(singlerecipeinput, world.registryAccess());
}).orElse(itemstack);
@@ -76,7 +79,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
CraftItemStack source = CraftItemStack.asCraftMirror(itemstack);
org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1);
- BlockCookEvent blockCookEvent = new BlockCookEvent(CraftBlock.at(world, pos), source, result);
+ BlockCookEvent blockCookEvent = new BlockCookEvent(CraftBlock.at(world, pos), source, result, (org.bukkit.inventory.CookingRecipe<?>) recipeHolderOptional.map(RecipeHolder::toBukkitRecipe).orElse(null)); // Paper - Add recipe to cook events
world.getCraftServer().getPluginManager().callEvent(blockCookEvent);
if (blockCookEvent.isCancelled()) {

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 6 Jul 2020 12:44:31 -0700
Subject: [PATCH] Add Block#isValidTool
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 98e87dc15e2ed23f6897ba6359846ff5bc32b655..2034858a53c4c887da334cdc7713997daa01124f 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -693,5 +693,9 @@ public class CraftBlock implements Block {
public String translationKey() {
return this.getNMS().getBlock().getDescriptionId();
}
+
+ public boolean isValidTool(ItemStack itemStack) {
+ return getDrops(itemStack).size() != 0;
+ }
// Paper end
}

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Anton Lindroth <ntoonio@gmail.com>
Date: Wed, 15 Apr 2020 01:54:02 +0200
Subject: [PATCH] Allow using signs inside spawn protection
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index d7d36b5148f2e7280816cc70b300b9b10720f751..25d060e8d77b1e8ea2ac951d2b25d60a984398cd 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1758,8 +1758,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
int i = this.player.level().getMaxBuildHeight();
if (blockposition.getY() < i) {
- if (this.awaitingPositionFromClient == null && worldserver.mayInteract(this.player, blockposition)) {
- this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706
+ if (this.awaitingPositionFromClient == null && (worldserver.mayInteract(this.player, blockposition) || (worldserver.paperConfig().spawn.allowUsingSignsInsideSpawnProtection && worldserver.getBlockState(blockposition).getBlock() instanceof net.minecraft.world.level.block.SignBlock))) { // Paper - Allow using signs inside spawn protection
InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock);
if (enuminteractionresult.consumesAction()) {

View file

@ -1,84 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 6 Jan 2021 00:34:04 -0800
Subject: [PATCH] Expand world key API
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index 1963e826548c5a8859c50f57654784c3aef50e44..04a39cb6c13c26e2cb1d73a9da98df5d04df69bc 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -515,5 +515,10 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
public io.papermc.paper.world.MoonPhase getMoonPhase() {
return io.papermc.paper.world.MoonPhase.getPhase(this.getHandle().dayTime() / 24000L);
}
+
+ @Override
+ public org.bukkit.NamespacedKey getKey() {
+ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.getHandle().getLevel().dimension().location());
+ }
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index f402ef662779e096ee354b9edd66cca785b85f33..a9c6f53c7e828a4b7d0cefbaa98e50ff1db9354a 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1183,9 +1183,15 @@ public final class CraftServer implements Server {
File folder = new File(this.getWorldContainer(), name);
World world = this.getWorld(name);
- if (world != null) {
- return world;
+ // Paper start
+ World worldByKey = this.getWorld(creator.key());
+ if (world != null || worldByKey != null) {
+ if (world == worldByKey) {
+ return world;
+ }
+ throw new IllegalArgumentException("Cannot create a world with key " + creator.key() + " and name " + name + " one (or both) already match a world that exists");
}
+ // Paper end
if (folder.exists()) {
Preconditions.checkArgument(folder.isDirectory(), "File (%s) exists and isn't a folder", name);
@@ -1311,7 +1317,7 @@ public final class CraftServer implements Server {
} else if (name.equals(levelName + "_the_end")) {
worldKey = net.minecraft.world.level.Level.END;
} else {
- worldKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace(name.toLowerCase(Locale.ROOT)));
+ worldKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.fromNamespaceAndPath(creator.key().namespace(), creator.key().value()));
}
// If set to not keep spawn in memory (changed from default) then adjust rule accordingly
@@ -1407,6 +1413,15 @@ public final class CraftServer implements Server {
return null;
}
+ // Paper start
+ @Override
+ public World getWorld(net.kyori.adventure.key.Key worldKey) {
+ ServerLevel worldServer = console.getLevel(ResourceKey.create(net.minecraft.core.registries.Registries.DIMENSION, io.papermc.paper.adventure.PaperAdventure.asVanilla(worldKey)));
+ if (worldServer == null) return null;
+ return worldServer.getWorld();
+ }
+ // Paper end
+
public void addWorld(World world) {
// Check if a World already exists with the UID.
if (this.getWorld(world.getUID()) != null) {
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index 66249c5caefb0879e13c02d5553b09b4122418b9..79915a93b36ddf2925444369a5df4e8f4fd5610e 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -522,6 +522,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
public int nextEntityId() {
return net.minecraft.world.entity.Entity.nextEntityId();
}
+
+ @Override
+ public String getMainLevelName() {
+ return ((net.minecraft.server.dedicated.DedicatedServer) net.minecraft.server.MinecraftServer.getServer()).getProperties().levelName;
+ }
// Paper end
@Override

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Irmo van den Berge <irmo.vandenberge@ziggo.nl>
Date: Wed, 10 Mar 2021 21:26:31 +0100
Subject: [PATCH] Add fast alternative constructor for Rotations
diff --git a/src/main/java/net/minecraft/core/Rotations.java b/src/main/java/net/minecraft/core/Rotations.java
index e6c97efb3aa89646149d11bb0ae4420b3977d214..27007280dba9e6d19a50dc2a4b160e96b20c67f7 100644
--- a/src/main/java/net/minecraft/core/Rotations.java
+++ b/src/main/java/net/minecraft/core/Rotations.java
@@ -34,6 +34,18 @@ public class Rotations {
this(serialized.getFloat(0), serialized.getFloat(1), serialized.getFloat(2));
}
+ // Paper start - faster alternative constructor
+ private Rotations(float x, float y, float z, Void dummy_var) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public static Rotations createWithoutValidityChecks(float x, float y, float z) {
+ return new Rotations(x, y, z, null);
+ }
+ // Paper end - faster alternative constructor
+
public ListTag save() {
ListTag listTag = new ListTag();
listTag.add(FloatTag.valueOf(this.x));

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <jonmagon@gmail.com>
Date: Thu, 4 Feb 2021 20:32:01 +0300
Subject: [PATCH] Drop carried item when player has disconnected
Fixes disappearance of held items, when a player gets disconnected and PlayerDropItemEvent is cancelled.
Closes #5036
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 123fe4f5b98a7483af86695ec82987abd45eafb2..bbc6f64a3b2c0702a0a752acd48145cdcafd742e 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -588,6 +588,14 @@ public abstract class PlayerList {
}
// Paper end - Configurable player collision
+ // Paper - Drop carried item when player has disconnected
+ if (!entityplayer.containerMenu.getCarried().isEmpty()) {
+ net.minecraft.world.item.ItemStack carried = entityplayer.containerMenu.getCarried();
+ entityplayer.containerMenu.setCarried(net.minecraft.world.item.ItemStack.EMPTY);
+ entityplayer.drop(carried, false);
+ }
+ // Paper end - Drop carried item when player has disconnected
+
this.save(entityplayer);
if (entityplayer.isPassenger()) {
Entity entity = entityplayer.getRootVehicle();

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Trigary <trigary0@gmail.com>
Date: Sat, 27 Mar 2021 09:24:23 +0100
Subject: [PATCH] forced whitelist: use configurable kick message
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 43b28b56c7949f95af5b7e99b04b93ed711d8880..6651afa50cfaf53959f89108904d4bf65a0fc495 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -2286,7 +2286,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
if (!whitelist.isWhiteListed(entityplayer.getGameProfile()) && !this.getPlayerList().isOp(entityplayer.getGameProfile())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420)
- entityplayer.connection.disconnect((Component) Component.translatable("multiplayer.disconnect.not_whitelisted"));
+ entityplayer.connection.disconnect(net.kyori.adventure.text.Component.text(org.spigotmc.SpigotConfig.whitelistMessage));
}
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Mon, 5 Apr 2021 18:35:15 -0700
Subject: [PATCH] Don't ignore result of PlayerEditBookEvent
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 25d060e8d77b1e8ea2ac951d2b25d60a984398cd..403b2499374906daa0ca2bb774522f92e186e6d5 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1154,7 +1154,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
List<Filterable<String>> list1 = pages.stream().map(this::filterableFromOutgoing).toList();
itemstack.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(list1));
- CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack); // CraftBukkit
+ this.player.getInventory().setItem(slotId, CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent)
}
}

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Fri, 26 Mar 2021 11:23:17 +0100
Subject: [PATCH] Expose protocol version
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index 79915a93b36ddf2925444369a5df4e8f4fd5610e..09fa524fa1155d53d988c15c1af551f73c96ede5 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -527,6 +527,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
public String getMainLevelName() {
return ((net.minecraft.server.dedicated.DedicatedServer) net.minecraft.server.MinecraftServer.getServer()).getProperties().levelName;
}
+
+ @Override
+ public int getProtocolVersion() {
+ return net.minecraft.SharedConstants.getCurrentVersion().getProtocolVersion();
+ }
// Paper end
@Override

View file

@ -1,445 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Tue, 30 Mar 2021 16:06:08 -0700
Subject: [PATCH] Enhance console tab completions for brigadier commands
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
index a4070b59e261f0f1ac4beec47b11492f4724bf27..6ee39b534b8d992655bc0cef3c299d12cbae0034 100644
--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
@@ -1,5 +1,8 @@
package com.destroystokyo.paper.console;
+import io.papermc.paper.configuration.GlobalConfiguration;
+import io.papermc.paper.console.BrigadierCompletionMatcher;
+import io.papermc.paper.console.BrigadierConsoleParser;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecrell.terminalconsole.SimpleTerminalConsole;
import org.bukkit.craftbukkit.command.ConsoleCommandCompleter;
@@ -16,11 +19,20 @@ public final class PaperConsole extends SimpleTerminalConsole {
@Override
protected LineReader buildReader(LineReaderBuilder builder) {
- return super.buildReader(builder
+ builder
.appName("Paper")
.variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history"))
.completer(new ConsoleCommandCompleter(this.server))
- );
+ .option(LineReader.Option.COMPLETE_IN_WORD, true);
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierHighlighting) {
+ builder.highlighter(new io.papermc.paper.console.BrigadierCommandHighlighter(this.server));
+ }
+ if (GlobalConfiguration.get().console.enableBrigadierCompletions) {
+ System.setProperty("org.jline.reader.support.parsedline", "true"); // to hide a warning message about the parser not supporting
+ builder.parser(new BrigadierConsoleParser(this.server));
+ builder.completionMatcher(new BrigadierCompletionMatcher());
+ }
+ return super.buildReader(builder);
}
@Override
diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf7b9518c05ff8a6d4b7d7cd36187ca22257e3dc
--- /dev/null
+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java
@@ -0,0 +1,119 @@
+package io.papermc.paper.console;
+
+import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent;
+import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion;
+import com.google.common.base.Suppliers;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.suggestion.Suggestion;
+import io.papermc.paper.adventure.PaperAdventure;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Supplier;
+import net.kyori.adventure.text.Component;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.network.chat.ComponentUtils;
+import net.minecraft.server.dedicated.DedicatedServer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jline.reader.Candidate;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
+
+import static com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion.completion;
+
+public final class BrigadierCommandCompleter {
+ private final Supplier<CommandSourceStack> commandSourceStack;
+ private final DedicatedServer server;
+
+ public BrigadierCommandCompleter(final @NonNull DedicatedServer server) {
+ this.server = server;
+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack);
+ }
+
+ public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List<Candidate> candidates, final @NonNull List<Completion> existing) {
+ //noinspection ConstantConditions
+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet
+ return;
+ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierCompletions) {
+ this.addCandidates(candidates, Collections.emptyList(), existing, new ParseContext(line.line(), 0));
+ return;
+ }
+ final CommandDispatcher<CommandSourceStack> dispatcher = this.server.getCommands().getDispatcher();
+ final ParseResults<CommandSourceStack> results = dispatcher.parse(new StringReader(line.line()), this.commandSourceStack.get());
+ this.addCandidates(
+ candidates,
+ dispatcher.getCompletionSuggestions(results, line.cursor()).join().getList(),
+ existing,
+ new ParseContext(line.line(), results.getContext().findSuggestionContext(line.cursor()).startPos)
+ );
+ }
+
+ private void addCandidates(
+ final @NonNull List<Candidate> candidates,
+ final @NonNull List<Suggestion> brigSuggestions,
+ final @NonNull List<Completion> existing,
+ final @NonNull ParseContext context
+ ) {
+ brigSuggestions.forEach(it -> {
+ if (it.getText().isEmpty()) return;
+ candidates.add(toCandidate(it, context));
+ });
+ for (final AsyncTabCompleteEvent.Completion completion : existing) {
+ if (completion.suggestion().isEmpty() || brigSuggestions.stream().anyMatch(it -> it.getText().equals(completion.suggestion()))) {
+ continue;
+ }
+ candidates.add(toCandidate(completion));
+ }
+ }
+
+ private static Candidate toCandidate(final Suggestion suggestion, final @NonNull ParseContext context) {
+ Component tooltip = null;
+ if (suggestion.getTooltip() != null) {
+ tooltip = PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip()));
+ }
+ return toCandidate(context.line.substring(context.suggestionStart, suggestion.getRange().getStart()) + suggestion.getText(), tooltip);
+ }
+
+ private static @NonNull Candidate toCandidate(final @NonNull Completion completion) {
+ return toCandidate(completion.suggestion(), completion.tooltip());
+ }
+
+ private static @NonNull Candidate toCandidate(final @NonNull String suggestionText, final @Nullable Component tooltip) {
+ final String suggestionTooltip = PaperAdventure.ANSI_SERIALIZER.serializeOr(tooltip, null);
+ //noinspection SpellCheckingInspection
+ return new PaperCandidate(
+ suggestionText,
+ suggestionText,
+ null,
+ suggestionTooltip,
+ null,
+ null,
+ /*
+ in an ideal world, this would sometimes be true if the suggestion represented the final possible value for a word.
+ Like for `/execute alig`, pressing enter on align would add a trailing space if this value was true. But not all
+ suggestions should add spaces after, like `/execute as @`, accepting any suggestion here would be valid, but its also
+ valid to have a `[` following the selector
+ */
+ false
+ );
+ }
+
+ private static @NonNull Completion toCompletion(final @NonNull Suggestion suggestion) {
+ if (suggestion.getTooltip() == null) {
+ return completion(suggestion.getText());
+ }
+ return completion(suggestion.getText(), PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip())));
+ }
+
+ private record ParseContext(String line, int suggestionStart) {
+ }
+
+ public static final class PaperCandidate extends Candidate {
+ public PaperCandidate(final String value, final String display, final String group, final String descr, final String suffix, final String key, final boolean complete) {
+ super(value, display, group, descr, suffix, key, complete);
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b21dac4473e3ea8022ef5c17f5f7d4d49d3ac0a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java
@@ -0,0 +1,67 @@
+package io.papermc.paper.console;
+
+import com.google.common.base.Suppliers;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.context.ParsedCommandNode;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import java.util.function.Supplier;
+import java.util.regex.Pattern;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.server.dedicated.DedicatedServer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jline.reader.Highlighter;
+import org.jline.reader.LineReader;
+import org.jline.utils.AttributedString;
+import org.jline.utils.AttributedStringBuilder;
+import org.jline.utils.AttributedStyle;
+
+public final class BrigadierCommandHighlighter implements Highlighter {
+ private static final int[] COLORS = {AttributedStyle.CYAN, AttributedStyle.YELLOW, AttributedStyle.GREEN, AttributedStyle.MAGENTA, /* Client uses GOLD here, not BLUE, however there is no GOLD AttributedStyle. */ AttributedStyle.BLUE};
+ private final Supplier<CommandSourceStack> commandSourceStack;
+ private final DedicatedServer server;
+
+ public BrigadierCommandHighlighter(final @NonNull DedicatedServer server) {
+ this.server = server;
+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack);
+ }
+
+ @Override
+ public AttributedString highlight(final @NonNull LineReader reader, final @NonNull String buffer) {
+ //noinspection ConstantConditions
+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet
+ return new AttributedString(buffer, AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
+ }
+ final AttributedStringBuilder builder = new AttributedStringBuilder();
+ final ParseResults<CommandSourceStack> results = this.server.getCommands().getDispatcher().parse(new StringReader(buffer), this.commandSourceStack.get());
+ int pos = 0;
+ int component = -1;
+ for (final ParsedCommandNode<CommandSourceStack> node : results.getContext().getLastChild().getNodes()) {
+ if (node.getRange().getStart() >= buffer.length()) {
+ break;
+ }
+ final int start = node.getRange().getStart();
+ final int end = Math.min(node.getRange().getEnd(), buffer.length());
+ builder.append(buffer.substring(pos, start), AttributedStyle.DEFAULT);
+ if (node.getNode() instanceof LiteralCommandNode) {
+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT);
+ } else {
+ if (++component >= COLORS.length) {
+ component = 0;
+ }
+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT.foreground(COLORS[component]));
+ }
+ pos = end;
+ }
+ if (pos < buffer.length()) {
+ builder.append((buffer.substring(pos)), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
+ }
+ return builder.toAttributedString();
+ }
+
+ @Override
+ public void setErrorPattern(final Pattern errorPattern) {}
+
+ @Override
+ public void setErrorIndex(final int errorIndex) {}
+}
diff --git a/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java b/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e8028a43db0ff1d5b22d06ef12c1c32d992c09c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java
@@ -0,0 +1,27 @@
+package io.papermc.paper.console;
+
+import com.google.common.collect.Iterables;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.jline.reader.Candidate;
+import org.jline.reader.CompletingParsedLine;
+import org.jline.reader.LineReader;
+import org.jline.reader.impl.CompletionMatcherImpl;
+
+public class BrigadierCompletionMatcher extends CompletionMatcherImpl {
+
+ @Override
+ protected void defaultMatchers(final Map<LineReader.Option, Boolean> options, final boolean prefix, final CompletingParsedLine line, final boolean caseInsensitive, final int errors, final String originalGroupName) {
+ super.defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName);
+ this.matchers.addFirst(m -> {
+ final Map<String, List<Candidate>> candidates = new HashMap<>();
+ for (final Map.Entry<String, List<Candidate>> entry : m.entrySet()) {
+ if (Iterables.all(entry.getValue(), BrigadierCommandCompleter.PaperCandidate.class::isInstance)) {
+ candidates.put(entry.getKey(), entry.getValue());
+ }
+ }
+ return candidates;
+ });
+ }
+}
diff --git a/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java b/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..8239a8ba57f856cbbee237a601b3cabfce20ba26
--- /dev/null
+++ b/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java
@@ -0,0 +1,79 @@
+package io.papermc.paper.console;
+
+import com.mojang.brigadier.ImmutableStringReader;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.context.CommandContextBuilder;
+import com.mojang.brigadier.context.ParsedCommandNode;
+import com.mojang.brigadier.context.StringRange;
+import java.util.ArrayList;
+import java.util.List;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.server.dedicated.DedicatedServer;
+import org.jline.reader.ParsedLine;
+import org.jline.reader.Parser;
+import org.jline.reader.SyntaxError;
+
+public class BrigadierConsoleParser implements Parser {
+
+ private final DedicatedServer server;
+
+ public BrigadierConsoleParser(DedicatedServer server) {
+ this.server = server;
+ }
+
+ @Override
+ public ParsedLine parse(final String line, final int cursor, final ParseContext context) throws SyntaxError {
+ final ParseResults<CommandSourceStack> results = this.server.getCommands().getDispatcher().parse(new StringReader(line), this.server.createCommandSourceStack());
+ final ImmutableStringReader reader = results.getReader();
+ final List<String> words = new ArrayList<>();
+ CommandContextBuilder<CommandSourceStack> currentContext = results.getContext();
+ int currentWordIdx = -1;
+ int wordIdx = -1;
+ int inWordCursor = -1;
+ if (currentContext.getRange().getLength() > 0) {
+ do {
+ for (final ParsedCommandNode<CommandSourceStack> node : currentContext.getNodes()) {
+ final StringRange nodeRange = node.getRange();
+ String current = nodeRange.get(reader);
+ words.add(current);
+ currentWordIdx++;
+ if (wordIdx == -1 && nodeRange.getStart() <= cursor && nodeRange.getEnd() >= cursor) {
+ // if cursor is in the middle of a parsed word/node
+ wordIdx = currentWordIdx;
+ inWordCursor = cursor - nodeRange.getStart();
+ }
+ }
+ currentContext = currentContext.getChild();
+ } while (currentContext != null);
+ }
+ final String leftovers = reader.getRemaining();
+ if (!leftovers.isEmpty() && leftovers.isBlank()) {
+ // if brig didn't consume the whole line, and everything else is blank, add a new empty word
+ currentWordIdx++;
+ words.add("");
+ if (wordIdx == -1) {
+ wordIdx = currentWordIdx;
+ inWordCursor = 0;
+ }
+ } else if (!leftovers.isEmpty()) {
+ // if there are unparsed leftovers, add a new word with the remaining input
+ currentWordIdx++;
+ words.add(leftovers);
+ if (wordIdx == -1) {
+ wordIdx = currentWordIdx;
+ inWordCursor = cursor - reader.getCursor();
+ }
+ }
+ if (wordIdx == -1) {
+ currentWordIdx++;
+ words.add("");
+ wordIdx = currentWordIdx;
+ inWordCursor = 0;
+ }
+ return new BrigadierParsedLine(words.get(wordIdx), inWordCursor, wordIdx, words, line, cursor);
+ }
+
+ record BrigadierParsedLine(String word, int wordCursor, int wordIndex, List<String> words, String line, int cursor) implements ParsedLine {
+ }
+}
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index d5153f804cfcfd1a70c46975e3fb1e50c8a82999..764395fe8e49d811294ca82887fee91ca6cd01fc 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -190,7 +190,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
thread.setDaemon(true);
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER));
- thread.start();
+ // thread.start(); // Paper - Enhance console tab completions for brigadier commands; moved down
DedicatedServer.LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().getName());
if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) {
DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
@@ -223,6 +223,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames
// Paper end - fix converting txt to json file
org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread
+ thread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
index 15bc85f4799a4b23edd2f1e93f1794de5ca3e8e3..a45e658996e483e9a21cfd8178153ddb7b87ae69 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
@@ -18,9 +18,11 @@ import org.bukkit.event.server.TabCompleteEvent;
public class ConsoleCommandCompleter implements Completer {
private final DedicatedServer server; // Paper - CraftServer -> DedicatedServer
+ private final io.papermc.paper.console.BrigadierCommandCompleter brigadierCompleter; // Paper - Enhance console tab completions for brigadier commands
public ConsoleCommandCompleter(DedicatedServer server) { // Paper - CraftServer -> DedicatedServer
this.server = server;
+ this.brigadierCompleter = new io.papermc.paper.console.BrigadierCommandCompleter(this.server); // Paper - Enhance console tab completions for brigadier commands
}
// Paper start - Change method signature for JLine update
@@ -64,7 +66,7 @@ public class ConsoleCommandCompleter implements Completer {
}
}
- if (!completions.isEmpty()) {
+ if (false && !completions.isEmpty()) {
for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) {
if (completion.suggestion().isEmpty()) {
continue;
@@ -80,6 +82,7 @@ public class ConsoleCommandCompleter implements Completer {
));
}
}
+ this.addCompletions(reader, line, candidates, completions);
return;
}
@@ -99,10 +102,12 @@ public class ConsoleCommandCompleter implements Completer {
try {
List<String> offers = waitable.get();
if (offers == null) {
+ this.addCompletions(reader, line, candidates, Collections.emptyList()); // Paper - Enhance console tab completions for brigadier commands
return; // Paper - Method returns void
}
// Paper start - JLine update
+ /*
for (String completion : offers) {
if (completion.isEmpty()) {
continue;
@@ -110,6 +115,8 @@ public class ConsoleCommandCompleter implements Completer {
candidates.add(new Candidate(completion));
}
+ */
+ this.addCompletions(reader, line, candidates, offers.stream().map(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion::completion).collect(java.util.stream.Collectors.toList()));
// Paper end
// Paper start - JLine handles cursor now
@@ -138,5 +145,9 @@ public class ConsoleCommandCompleter implements Completer {
}
return false;
}
+
+ private void addCompletions(final LineReader reader, final ParsedLine line, final List<Candidate> candidates, final List<com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion> existing) {
+ this.brigadierCompleter.complete(reader, line, candidates, existing);
+ }
// Paper end
}

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: chickeneer <emcchickeneer@gmail.com>
Date: Fri, 19 Mar 2021 00:33:15 -0500
Subject: [PATCH] Fix PlayerItemConsumeEvent cancelling properly
When the active item is not cleared, the item is still readied
for use and will repeatedly trigger the PlayerItemConsumeEvent
till their item is switched.
This patch clears the active item when the event is cancelled
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index a89c6ba4140f15e7f68f0df5cf64a176d350123b..afa2d3f5199fcac5c83639bb87e31425da4c5310 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -4011,6 +4011,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.level().getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
+ this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use
// Update client
if (this.useItem.getItem() instanceof net.minecraft.world.item.SuspiciousStewItem itemSuspiciousStew) {
itemSuspiciousStew.cancelUsingItem(entityPlayer, this.useItem);