Skip to content
Merged
210 changes: 195 additions & 15 deletions canvas-server/minecraft-patches/base/0004-Region-Threading.patch
Original file line number Diff line number Diff line change
Expand Up @@ -24121,7 +24121,7 @@ index bb5f66c62c9541bb76a9faad9e9ee91c1466fc6a..66d7bb9418832638c220a08d06c01ef0
return blockToFallLocation(blockState);
} else {
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227590fea87 100644
index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..472b82ad0416786766c0ffb43007e5eac11de673 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -170,7 +170,7 @@ public abstract class Entity
Expand Down Expand Up @@ -24397,7 +24397,28 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
}

public int getDimensionChangingDelay() {
@@ -4038,7 +4108,1138 @@ public abstract class Entity
@@ -4021,12 +4091,20 @@ public abstract class Entity
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
}

public void restoreFrom(final Entity oldEntity) {
+ // Canvas start - copy entity data without forwarding the Bukkit handle
+ this.restoreFrom(oldEntity, true);
+ }
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+
+ public void restoreFrom(final Entity oldEntity, final boolean forwardBukkitEntity) {
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+ // Canvas end - copy entity data without forwarding the Bukkit handle
// Paper start - Forward CraftEntity in teleport command
+ if (forwardBukkitEntity) { // Canvas - copy entity data without forwarding the Bukkit handle
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity = oldEntity.bukkitEntity;
if (bukkitEntity != null) {
bukkitEntity.setHandle(this);
this.bukkitEntity = bukkitEntity;
}
+ } // Canvas - copy entity data without forwarding the Bukkit handle
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
// Paper end - Forward CraftEntity in teleport command
try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) {
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
TagValueOutput entityData = TagValueOutput.createWithContext(reporter, oldEntity.registryAccess());
@@ -4038,7 +4116,1162 @@ public abstract class Entity
this.portalProcess = oldEntity.portalProcess;
}

Expand Down Expand Up @@ -25308,6 +25329,16 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
+
+ }
+
+ // Canvas start - safely continue falling block ticks after starting an End portal transfer
Comment thread
BaconCat1 marked this conversation as resolved.
+ protected @Nullable Runnable canvas$preparePortalTransferContinuation(
+ final ServerLevel origin,
+ final ServerLevel destination,
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+ final PortalType type
+ ) {
+ return null;
+ }
+ // Canvas end - safely continue falling block ticks after starting an End portal transfer
+
+ // note: destination param is mutable because we mutate this
+ // later in event handling
+ // note: teleportComplete param is nullable
Expand Down Expand Up @@ -25347,6 +25378,10 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
+ canvas$ensureCanPortalAsync(destination, takePassengers);
+ }
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+ final ServerLevel finalDestination = destination;
+
+ // set the portal transfer continuation for falling block ticks for portal transfers
+ final java.lang.Runnable portalTransferContinuation =
+ this.canvas$preparePortalTransferContinuation(originWorld, finalDestination, type);
+ // Canvas end - region threading
+
+ Vec3 initialPosition = this.position();
Expand Down Expand Up @@ -25381,6 +25416,16 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
+ // Canvas end - region threading
+ }
+
+ // Canvas start - safely continue falling block ticks after starting an End portal transfer
+ if (portalTransferContinuation != null) {
+ try {
+ portalTransferContinuation.run();
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+ } catch (final Throwable thrown) {
+ LOGGER.error("Failed to run a source-side portal transfer continuation", thrown);
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+ }
+ }
+
+ // Canvas end - safely continue falling block ticks after starting an End portal transfer
+ // ensure the region is always ticking in case of a shutdown
+ // otherwise, the shutdown will not be able to complete the shutdown as it requires a ticking region
+ Long teleportHoldId = Long.valueOf(TELEPORT_HOLD_TICKET_GEN.getAndIncrement());
Expand Down Expand Up @@ -25536,7 +25581,7 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
// Paper start - Fix item duplication and teleport issues
if ((!this.isAlive() || !this.valid) && (transition.newLevel() != this.level)) {
LOGGER.warn("Illegal Entity Teleport {} to {}:{}", this, transition.newLevel(), transition.position(), new Throwable());
@@ -4240,6 +5441,12 @@ public abstract class Entity
@@ -4240,6 +5473,12 @@ public abstract class Entity
}
}

Expand All @@ -25549,7 +25594,7 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
protected void removeAfterChangingDimensions() {
this.setRemoved(Entity.RemovalReason.CHANGED_DIMENSION, null); // CraftBukkit - add Bukkit remove cause
if (this instanceof Leashable leashable && leashable.isLeashed()) { // Paper - only call if it is leashed
@@ -4573,6 +5780,12 @@ public abstract class Entity
@@ -4573,6 +5812,12 @@ public abstract class Entity
}

public void startSeenByPlayer(final ServerPlayer player) {
Expand All @@ -25562,7 +25607,7 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
}

public void stopSeenByPlayer(final ServerPlayer player) {
@@ -4582,6 +5795,12 @@ public abstract class Entity
@@ -4582,6 +5827,12 @@ public abstract class Entity
new io.papermc.paper.event.player.PlayerUntrackEntityEvent(player.getBukkitEntity(), this.getBukkitEntity()).callEvent();
}
// Paper end - entity tracking events
Expand All @@ -25575,7 +25620,7 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
}

public float rotate(final Rotation rotation) {
@@ -4989,7 +6208,10 @@ public abstract class Entity
@@ -4989,7 +6240,10 @@ public abstract class Entity
return;
}
// Paper end - Block invalid positions and bounding box
Expand All @@ -25587,7 +25632,7 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
this.position = new Vec3(x, y, z);
int fx = Mth.floor(x);
int fy = Mth.floor(y);
@@ -5020,7 +6242,7 @@ public abstract class Entity
@@ -5020,7 +6274,7 @@ public abstract class Entity
}
// Paper start - Block invalid positions and bounding box; don't allow desync of pos and AABB
// hanging has its own special logic
Expand All @@ -25596,23 +25641,23 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
this.setBoundingBox(this.makeBoundingBox());
}
// Paper end - Block invalid positions and bounding box
@@ -5095,6 +6317,7 @@ public abstract class Entity
@@ -5095,6 +6349,7 @@ public abstract class Entity
Util.logAndPauseIfInIde("Invalid entity rotation: " + yRot + ", discarding.");
} else {
this.yRot = yRot;
+ this.canvas$threadSafeYRot = yRot; // Canvas - region threading
}
}

@@ -5107,6 +6330,7 @@ public abstract class Entity
@@ -5107,6 +6362,7 @@ public abstract class Entity
Util.logAndPauseIfInIde("Invalid entity rotation: " + xRot + ", discarding.");
} else {
this.xRot = Math.clamp(xRot % 360.0F, -90.0F, 90.0F);
+ this.canvas$threadSafeXRot = this.xRot; // Canvas - region threading
}
}

@@ -5126,6 +6350,12 @@ public abstract class Entity
@@ -5126,6 +6382,12 @@ public abstract class Entity
return this.removalReason != null;
}

Expand All @@ -25625,15 +25670,15 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
public Entity.@Nullable RemovalReason getRemovalReason() {
return this.removalReason;
}
@@ -5140,6 +6370,7 @@ public abstract class Entity
@@ -5140,6 +6402,7 @@ public abstract class Entity
// Paper end - rewrite chunk system
org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit
final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers
+ this.preRemove(removalReason); // Folia - region threading
if (this.removalReason == null) {
this.removalReason = reason;
}
@@ -5163,6 +6394,10 @@ public abstract class Entity
@@ -5163,6 +6426,10 @@ public abstract class Entity
this.removalReason = null;
}

Expand All @@ -25644,7 +25689,7 @@ index bd935ae0cafc8fa2f53ed756a9acedab9db54b30..e87539cdd9813e68fe105d5311221227
// Paper start - Folia schedulers
/**
* Invoked only when the entity is truly removed from the server, never to be added to any world.
@@ -5174,7 +6409,7 @@ public abstract class Entity
@@ -5174,7 +6441,7 @@ public abstract class Entity
// Paper end - Folia schedulers
// Paper start - optimise Folia entity scheduler
public final void registerScheduler() {
Expand Down Expand Up @@ -26771,10 +26816,32 @@ index 4d0d58d5cbfa88fdd0f5ea3b9d96b21a88f2f988..154e4de3262ee9f56c121eb42cb54495
}
}
diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java
index 899f4ac76ae1397146bf15c4e5b9f5996451c2b5..0917beab5437f6a7a64b0f1f327dbfbaf6cb76a8 100644
index 899f4ac76ae1397146bf15c4e5b9f5996451c2b5..e9c6016fe2eed7f8f72c0a88aefe8ac2295c22e7 100644
--- a/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -165,7 +165,7 @@ public class FallingBlockEntity extends Entity {
@@ -71,6 +71,7 @@ public class FallingBlockEntity extends Entity {
public float fallDamagePerDistance = 0.0F;
public @Nullable CompoundTag blockData;
public boolean forceTickAfterTeleportToDuplicate;
+ private boolean canvas$finishTickOnly; // Canvas - safely continue falling block ticks after End portal transfers
protected static final EntityDataAccessor<BlockPos> DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS);
public boolean autoExpire = true; // Paper - Expand FallingBlock API

@@ -152,20 +153,11 @@ public class FallingBlockEntity extends Entity {
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
} else {
Block block = this.blockState.getBlock();
- this.time++;
- this.applyGravity();
- this.move(MoverType.SELF, this.getDeltaMovement());
- this.applyEffectsFromBlocks();
- // Paper start - Configurable falling blocks height nerf
- if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) {
- if (this.dropItem && this.level() instanceof final ServerLevel serverLevel && serverLevel.getGameRules().get(GameRules.ENTITY_DROPS)) {
- this.spawnAtLocation(serverLevel, block);
- }
- this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.OUT_OF_WORLD);
+ if (this.canvas$runFallingBlockTickPrefix(block)) { // Canvas - safely continue falling block ticks after End portal transfers
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
return;
}
// Paper end - Configurable falling blocks height nerf
Expand All @@ -26783,6 +26850,119 @@ index 899f4ac76ae1397146bf15c4e5b9f5996451c2b5..0917beab5437f6a7a64b0f1f327dbfba
if (this.level() instanceof ServerLevel serverLevel && (this.isAlive() || this.forceTickAfterTeleportToDuplicate)) {
BlockPos pos = this.blockPosition();
boolean isConcrete = this.blockState.getBlock() instanceof ConcretePowderBlock;
@@ -265,6 +257,112 @@ public class FallingBlockEntity extends Entity {
}
}

+ // Canvas start - handle End portal transfer before falling block tick tail
+ private boolean canvas$runFallingBlockTickPrefix(final net.minecraft.world.level.block.Block block) {
+ if (this.canvas$finishTickOnly) {
+ this.canvas$finishTickOnly = false;
+ return false;
+ }
+
+ this.time++;
+ this.applyGravity();
+ this.move(net.minecraft.world.entity.MoverType.SELF, this.getDeltaMovement());
+ this.applyEffectsFromBlocks();
+ // Paper start - Configurable falling blocks height nerf
+ if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(value -> this.getY() > value)) {
+ if (
+ this.dropItem
+ && this.level() instanceof final net.minecraft.server.level.ServerLevel serverLevel
+ && serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.ENTITY_DROPS)
+ ) {
+ this.spawnAtLocation(serverLevel, block);
+ }
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.OUT_OF_WORLD);
+ return true;
+ }
+ // Paper end - Configurable falling blocks height nerf
+ if (
+ io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation
+ && this.portalProcess != null
+ && this.portalProcess.isSamePortal((net.minecraft.world.level.block.Portal) net.minecraft.world.level.block.Blocks.END_PORTAL)
+ && this.handlePortal()
+ ) {
+ return true;
+ }
+
+ return false;
Comment thread
BaconCat1 marked this conversation as resolved.
+ }
+
+ @Override
+ protected @Nullable Runnable canvas$preparePortalTransferContinuation(
+ final ServerLevel origin,
+ final ServerLevel destination,
+ final Entity.PortalType type
+ ) {
+ final boolean fromOrToEnd =
+ (
+ origin.dimension() == net.minecraft.world.level.Level.END
+ || destination.dimension() == net.minecraft.world.level.Level.END
+ ) && origin.dimension() != destination.dimension();
+ if (
+ type != net.minecraft.world.entity.Entity.PortalType.END
+ || !fromOrToEnd
+ || !io.papermc.paper.configuration.GlobalConfiguration.get()
+ .unsupportedSettings
+ .allowUnsafeEndPortalTeleportation
+ ) {
+ return null;
+ }
+
+ final net.minecraft.world.entity.Entity created = this.getType()
+ .create(origin, net.minecraft.world.entity.EntitySpawnReason.DIMENSION_TRAVEL);
+ if (!(created instanceof net.minecraft.world.entity.item.FallingBlockEntity continuation)) {
+ LOGGER.error("Unable to create a falling block continuation for End portal duplication");
+ return null;
+ }
+
Comment thread
Dueris marked this conversation as resolved.
+ continuation.restoreFrom(this, false);
+ continuation.setUUID(java.util.UUID.randomUUID());
+ continuation.portalProcess = null;
+ continuation.forceTickAfterTeleportToDuplicate = false;
+ continuation.setStartPos(this.getStartPos());
+ continuation.setDeltaMovement(this.getDeltaMovement());
+ continuation.xo = this.xo;
+ continuation.yo = this.yo;
+ continuation.zo = this.zo;
+ continuation.xOld = this.xOld;
+ continuation.yOld = this.yOld;
+ continuation.zOld = this.zOld;
+ continuation.yRotO = this.yRotO;
+ continuation.xRotO = this.xRotO;
+ continuation.onGround = this.onGround;
+ continuation.horizontalCollision = this.horizontalCollision;
+ continuation.verticalCollision = this.verticalCollision;
+ continuation.verticalCollisionBelow = this.verticalCollisionBelow;
+ continuation.minorHorizontalCollision = this.minorHorizontalCollision;
+
+ return () -> {
+ origin.addDuringTeleport(continuation);
+ if (continuation.hasNullCallback() || continuation.isRemoved()) {
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+ LOGGER.error(
+ "Unable to add a falling block continuation for End portal duplication because it {}",
+ continuation.hasNullCallback() ? "has a null callback" : "was removed"
+ );
+ return;
+ }
+
+ try {
+ continuation.canvas$finishTickOnly = true;
+ continuation.tick();
+ } finally {
+ if (!continuation.isRemoved()) {
+ continuation.discard();
+ }
Comment thread
BaconCat1 marked this conversation as resolved.
Outdated
+ }
+ };
+ }
+
+ // Canvas end - safely continue falling block ticks after End portal transfers
public void callOnBrokenAfterFall(final Block block, final BlockPos pos) {
if (block instanceof Fallable fallable) {
fallable.onBrokenAfterFall(this.level(), pos, this);
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index c800c894a921ae77ed1757794ddf8d737b05681e..76467ded9c4eaf368cd256d53761d87bcb489864 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
Expand Down