This commit is contained in:
Jake Potrebic 2024-04-23 23:05:14 -07:00
parent ebedfa4da7
commit 49787270cb
55 changed files with 46 additions and 90 deletions

View file

@ -8,7 +8,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java --- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S @@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public void inactiveTick() { } public void inactiveTick() { }
// Spigot end // Spigot end
protected int numCollisions = 0; // Paper - Cap entity collisions protected int numCollisions = 0; // Paper - Cap entity collisions
@ -16,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
// Paper start - Entity origin API // Paper start - Entity origin API
@javax.annotation.Nullable @javax.annotation.Nullable
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S @@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
if (spawnedViaMobSpawner) { if (spawnedViaMobSpawner) {
nbttagcompound.putBoolean("Paper.FromMobSpawner", true); nbttagcompound.putBoolean("Paper.FromMobSpawner", true);
} }
@ -26,7 +26,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Paper end // Paper end
return nbttagcompound; return nbttagcompound;
} catch (Throwable throwable) { } catch (Throwable throwable) {
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S @@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
} }
spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status

View file

@ -141,15 +141,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private KeyPair keyPair; private KeyPair keyPair;
@Nullable @Nullable
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.aggregatedTickTimesNanos += j;
this.tickTimesNanos[k] = j;
this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float) j / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F; this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float) j / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F;
long l = Util.getNanos();
+ // Paper start - Add tick times API and /mspt command + // Paper start - Add tick times API and /mspt command
+ tickTimes5s.add(this.tickCount, j); + this.tickTimes5s.add(this.tickCount, j);
+ tickTimes10s.add(this.tickCount, j); + this.tickTimes10s.add(this.tickCount, j);
+ tickTimes60s.add(this.tickCount, j); + this.tickTimes60s.add(this.tickCount, j);
+ // Paper end - Add tick times API and /mspt command + // Paper end - Add tick times API and /mspt command
this.logTickTime(l - i); this.logTickMethodTime(i);
this.profiler.pop(); this.profiler.pop();
org.spigotmc.WatchdogThread.tick(); // Spigot org.spigotmc.WatchdogThread.tick(); // Spigot
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View file

@ -30,5 +30,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.moveControl = new BeeFlyingMoveControl(this, 20, true); + this.moveControl = new BeeFlyingMoveControl(this, 20, true);
+ // Paper end - Fix MC-167279 + // Paper end - Fix MC-167279
this.lookControl = new Bee.BeeLookControl(this); this.lookControl = new Bee.BeeLookControl(this);
this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F); this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); this.setPathfindingMalus(PathType.WATER, -1.0F);

View file

@ -15,9 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public boolean killedEntity(ServerLevel world, LivingEntity other) { public boolean killedEntity(ServerLevel world, LivingEntity other) {
boolean flag = super.killedEntity(world, other); boolean flag = super.killedEntity(world, other);
- if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) { - if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager entityvillager) {
- Villager entityvillager = (Villager) other;
-
- if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { - if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
- return flag; - return flag;
- } - }

View file

@ -39,7 +39,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper - Do not allow bees to load chunks for beehives + if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper - Do not allow bees to load chunks for beehives
BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos); BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos);
if (tileentity instanceof BeehiveBlockEntity) { if (tileentity instanceof BeehiveBlockEntity tileentitybeehive) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Vex.java --- a/src/main/java/net/minecraft/world/entity/monster/Vex.java

View file

@ -17,14 +17,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player { @@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
this.server = server;
this.stats = server.getPlayerList().getPlayerStats(this); this.stats = server.getPlayerList().getPlayerStats(this);
this.advancements = server.getPlayerList().getPlayerAdvancements(this); this.advancements = server.getPlayerList().getPlayerAdvancements(this);
this.setMaxUpStep(1.0F);
- this.fudgeSpawnLocation(world); - this.fudgeSpawnLocation(world);
+ // this.fudgeSpawnLocation(world); // Paper - Don't move existing players to world spawn + // this.fudgeSpawnLocation(world); // Paper - Don't move existing players to world spawn
this.updateOptions(clientOptions); this.updateOptions(clientOptions);
this.object = null;
this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player { @@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
position = Vec3.atCenterOf(world.getSharedSpawnPos()); position = Vec3.atCenterOf(world.getSharedSpawnPos());
} }

View file

@ -87,6 +87,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return false; + return false;
+ } + }
+ // Paper end - duplicate uuid resolving + // Paper end - duplicate uuid resolving
public CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> prepareTickingChunk(ChunkHolder holder) { +
CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> { public CompletableFuture<ChunkResult<LevelChunk>> prepareTickingChunk(ChunkHolder holder) {
CompletableFuture<ChunkResult<List<ChunkAccess>>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> {
return ChunkStatus.FULL; return ChunkStatus.FULL;

View file

@ -66,7 +66,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ player.supressTrackerForLogin = true; + player.supressTrackerForLogin = true;
+ worldserver1.addNewPlayer(player); + worldserver1.addNewPlayer(player);
+ this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer); + this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer);
+ mountSavedVehicle(player, worldserver1, nbttagcompound); + this.mountSavedVehicle(player, worldserver1, optional);
+ // Paper end - Fire PlayerJoinEvent when Player is actually ready + // Paper end - Fire PlayerJoinEvent when Player is actually ready
// CraftBukkit start // CraftBukkit start
CraftPlayer bukkitPlayer = player.getBukkitEntity(); CraftPlayer bukkitPlayer = player.getBukkitEntity();
@ -79,19 +79,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now + ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now
// CraftBukkit end // CraftBukkit end
player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
@@ -0,0 +0,0 @@ public abstract class PlayerList { @@ -0,0 +0,0 @@ public abstract class PlayerList {
playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect));
}
playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect, false));
}
-
+ // Paper start - Fire PlayerJoinEvent when Player is actually ready; move vehicle into method so it can be called above - short circuit around that code + // Paper start - Fire PlayerJoinEvent when Player is actually ready; move vehicle into method so it can be called above - short circuit around that code
+ onPlayerJoinFinish(player, worldserver1, s1); + this.onPlayerJoinFinish(player, worldserver1, s1);
+ } + }
+ private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) { + private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, Optional<CompoundTag> optional) {
+ // Paper end - Fire PlayerJoinEvent when Player is actually ready + // Paper end - Fire PlayerJoinEvent when Player is actually ready
if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) { if (optional.isPresent() && ((CompoundTag) optional.get()).contains("RootVehicle", 10)) {
CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle"); CompoundTag nbttagcompound = ((CompoundTag) optional.get()).getCompound("RootVehicle");
// CraftBukkit start ServerLevel finalWorldServer = worldserver1; // CraftBukkit - decompile error
@@ -0,0 +0,0 @@ public abstract class PlayerList { @@ -0,0 +0,0 @@ public abstract class PlayerList {
} }
} }

View file

@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || (this.tickCount + this.getId()) % 4 == 0) { - if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || (this.tickCount + this.getId()) % 4 == 0) {
+ if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || (this.tickCount + this.getId()) % 4 == 0) { // Paper - Diff on change + if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || (this.tickCount + this.getId()) % 4 == 0) { // Paper - Diff on change
this.move(MoverType.SELF, this.getDeltaMovement()); this.move(MoverType.SELF, this.getDeltaMovement());
float f1 = 0.98F; float f = 0.98F;
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644

View file

@ -38,7 +38,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable { @@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
} }
public void write(ChunkPos chunkPos, CompoundTag nbt) { public CompletableFuture<Void> write(ChunkPos chunkPos, CompoundTag nbt) {
+ // Paper start - guard against serializing mismatching coordinates + // Paper start - guard against serializing mismatching coordinates
+ if (nbt != null && !chunkPos.equals(ChunkSerializer.getChunkCoordinate(nbt))) { + if (nbt != null && !chunkPos.equals(ChunkSerializer.getChunkCoordinate(nbt))) {
+ final String world = (this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap) this).level.getWorld().getName() : null; + final String world = (this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap) this).level.getWorld().getName() : null;
@ -46,6 +46,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ + " but compound says coordinate is " + ChunkSerializer.getChunkCoordinate(nbt) + (world == null ? " for an unknown world" : (" for world: " + world))); + + " but compound says coordinate is " + ChunkSerializer.getChunkCoordinate(nbt) + (world == null ? " for an unknown world" : (" for world: " + world)));
+ } + }
+ // Paper end - guard against serializing mismatching coordinates + // Paper end - guard against serializing mismatching coordinates
this.worker.store(chunkPos, nbt); this.handleLegacyStructureIndex(chunkPos);
if (this.legacyStructureHandler != null) { return this.worker.store(chunkPos, nbt);
this.legacyStructureHandler.removeIndex(chunkPos.toLong()); }

View file

@ -91,14 +91,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player { @@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
this.stats = server.getPlayerList().getPlayerStats(this);
this.advancements = server.getPlayerList().getPlayerAdvancements(this); this.advancements = server.getPlayerList().getPlayerAdvancements(this);
this.setMaxUpStep(1.0F);
// this.fudgeSpawnLocation(world); // Paper - Don't move existing players to world spawn // this.fudgeSpawnLocation(world); // Paper - Don't move existing players to world spawn
- this.updateOptions(clientOptions); - this.updateOptions(clientOptions);
+ this.updateOptionsNoEvents(clientOptions); // Paper - don't call options events on login + this.updateOptionsNoEvents(clientOptions); // Paper - don't call options events on login
this.object = null;
this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player { @@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
} }
} }

View file

@ -43,12 +43,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- if (playerchunk == null) { - if (playerchunk == null) {
- return null; - return null;
- } else { - } else {
- Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = (Either) playerchunk.getFutureIfPresent(ChunkStatus.FULL).getNow(null); // CraftBukkit - decompile error - ChunkResult<ChunkAccess> chunkresult = (ChunkResult) playerchunk.getFutureIfPresent(ChunkStatus.FULL).getNow(null); // CraftBukkit - decompile error
- -
- if (either == null) { - if (chunkresult == null) {
- return null; - return null;
- } else { - } else {
- ChunkAccess ichunkaccess1 = (ChunkAccess) either.left().orElse(null); // CraftBukkit - decompile error - ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error
- -
- if (ichunkaccess1 != null) { - if (ichunkaccess1 != null) {
- this.storeInCache(k, ichunkaccess1, ChunkStatus.FULL); - this.storeInCache(k, ichunkaccess1, ChunkStatus.FULL);

View file

@ -19,6 +19,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ private int pathfindFailures = 0; + private int pathfindFailures = 0;
+ // Paper end - Perf: Optimise pathfinding + // Paper end - Perf: Optimise pathfinding
+ +
public boolean moveTo(double x, double y, double z, int distance, double speed) {
return this.moveTo(this.createPath(x, y, z, distance), speed);
}
public boolean moveTo(Entity entity, double speed) { public boolean moveTo(Entity entity, double speed) {
+ // Paper start - Perf: Optimise pathfinding + // Paper start - Perf: Optimise pathfinding
+ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) { + if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) {

View file

@ -34,9 +34,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
- ServerLevel.this.getChunkSource().addEntity(entity); - ServerLevel.this.getChunkSource().addEntity(entity);
+ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true + // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true
if (entity instanceof ServerPlayer) { if (entity instanceof ServerPlayer entityplayer) {
ServerPlayer entityplayer = (ServerPlayer) entity; ServerLevel.this.players.add(entityplayer);
ServerLevel.this.updateSleepingPlayerList();
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
entity.updateDynamicGameEventListener(DynamicGameEventListener::add); entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
entity.inWorld = true; // CraftBukkit - Mark entity as in world entity.inWorld = true; // CraftBukkit - Mark entity as in world

View file

@ -30,4 +30,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - Show blockstate location if we failed to read it + // Paper end - Show blockstate location if we failed to read it
} }
protected CraftBlockEntityState(CraftBlockEntityState<T> state) { protected CraftBlockEntityState(CraftBlockEntityState<T> state, Location location) {

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AJMFactsheets <AJMFactsheets@gmail.com>
Date: Wed, 22 Jan 2020 19:52:28 -0600
Subject: [PATCH] Fix items vanishing through end portal
If the Paper configuration option "keep-spawn-loaded" is set to false,
items entering the overworld from the end will spawn at Y = 0.
This is due to logic in the getHighestBlockYAt method in World.java
only searching the heightmap if the chunk is loaded.
Quickly loading the exact world spawn chunk before searching the
heightmap resolves the issue without having to load all spawn chunks.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
if (flag1) {
blockposition1 = ServerLevel.END_SPAWN_POINT;
} else {
+ destination.getChunkAt(destination.getSharedSpawnPos()); // Paper - Ensure spawn chunk is always loaded before calculating Y coordinate
blockposition1 = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, destination.getSharedSpawnPos());
}
// CraftBukkit start

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 17 Jan 2020 18:44:55 -0800
Subject: [PATCH] Fix last firework in stack not having effects when dispensed
CB used the resulting item in the dispenser rather than the item
dispensed. The resulting item would have size == 0 and therefore
be convertered to air, hence why the effects disappeared.
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -0,0 +0,0 @@ public interface DispenseItemBehavior {
itemstack1 = CraftItemStack.asNMSCopy(event.getItem());
Vec3 vec3d = DispenseItemBehavior.getEntityPokingOutOfBlockPos(pointer, EntityType.FIREWORK_ROCKET, enumdirection);
- FireworkRocketEntity entityfireworks = new FireworkRocketEntity(pointer.level(), stack, vec3d.x(), vec3d.y(), vec3d.z(), true);
+ FireworkRocketEntity entityfireworks = new FireworkRocketEntity(pointer.level(), itemstack1, vec3d.x(), vec3d.y(), vec3d.z(), true); // Paper - GH-2871 - fix last firework in stack having no effects when dispensed
entityfireworks.shoot((double) enumdirection.getStepX(), (double) enumdirection.getStepY(), (double) enumdirection.getStepZ(), 0.5F, 1.0F);
pointer.level().addFreshEntity(entityfireworks);