MOAR PATCHES

This commit is contained in:
Jake Potrebic 2021-06-13 15:05:18 -07:00
parent 7dd2ea0897
commit 3ee043dc0c
33 changed files with 384 additions and 843 deletions

View file

@ -1,55 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sun, 26 Jan 2020 16:30:19 -0600
Subject: [PATCH] Bees get gravity in void. Fixes MC-167279
diff --git a/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java
+++ b/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java
@@ -0,0 +0,0 @@ public class FlyingMoveControl extends MoveControl {
}
@Override
- public void tick() {
+ public void tick() { tick(); } public void tick() { // Paper - OBFHELPER
if (this.operation == MoveControl.Operation.MOVE_TO) {
this.operation = MoveControl.Operation.WAIT;
this.mob.setNoGravity(true);
diff --git a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
+++ b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
@@ -0,0 +0,0 @@ import net.minecraft.world.phys.shapes.VoxelShape;
public class MoveControl {
- protected final Mob mob;
+ protected final Mob mob; public final Mob getEntity() { return mob; } // Paper - OBFHELPER
protected double wantedX;
protected double wantedY;
protected double wantedZ;
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
@@ -0,0 +0,0 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
public Bee(EntityType<? extends Bee> type, Level world) {
super(type, world);
- this.moveControl = new FlyingMoveControl(this, 20, true);
+ // Paper start - apply gravity to bees when they get stuck in the void, fixes MC-167279
+ this.moveControl = new FlyingMoveControl(this, 20, true) {
+ @Override
+ public void tick() {
+ if (getEntity().getY() <= 0) {
+ getEntity().setNoGravity(false);
+ }
+ super.tick();
+ }
+ };
+ // Paper end
this.lookControl = new Bee.BeeLookControl(this);
this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F);
this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F);

View file

@ -1,79 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 29 Mar 2020 18:26:14 -0400
Subject: [PATCH] Ensure Entity is never double registered
If something calls register twice, and the world is ticking, it could be
enqueued to add twice.
Vs behavior of non ticking of just overwriting state.
We will now simply log a warning when this happens instead of crashing the server.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
Entity entity2;
while ((entity2 = (Entity) this.toAddAfterTick.poll()) != null) {
+ if (!entity2.isQueuedForRegister) continue; // Paper - ignore cancelled registers
this.add(entity2);
}
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
public void onEntityRemoved(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot
+ // Paper start - fix entity registration issues
+ if (entity instanceof EnderDragonPart) {
+ // Usually this is a no-op for complex parts, and ID's should be removed, but go ahead and remove it anyways
+ // Dragon parts are handled special in register. they don't receive a valid = true or register by UUID etc.
+ this.entitiesById.remove(entity.getId(), entity);
+ return;
+ }
+ if (!entity.valid) {
+ // Someone called remove before we ever got added, cancel the add.
+ entity.isQueuedForRegister = false;
+ return;
+ }
+ // Paper end
// Spigot start
if ( entity instanceof Player )
{
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
private void add(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
+ // Paper start - don't double enqueue entity registration
+ //noinspection ObjectEquality
+ if (this.entitiesById.get(entity.getId()) == entity) {
+ LOGGER.error(entity + " was already registered!");
+ new Throwable().printStackTrace();
+ return;
+ }
+ // Paper end
if (this.tickingEntities) {
- this.toAddAfterTick.add(entity);
+ if (!entity.isQueuedForRegister) { // Paper
+ this.toAddAfterTick.add(entity);
+ entity.isQueuedForRegister = true; // Paper
+ }
} else {
+ entity.isQueuedForRegister = false; // Paper
this.entitiesById.put(entity.getId(), entity);
if (entity instanceof EnderDragon) {
EnderDragonPart[] aentitycomplexpart = ((EnderDragon) entity).getSubEntities();
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, CommandSource, net.minecraft.s
}
// Paper start
+ public boolean isQueuedForRegister = false;
public static Random SHARED_RANDOM = new Random() {
private boolean locked = false;
@Override

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 31 Mar 2020 03:01:45 -0400
Subject: [PATCH] Fix unregistering entities from unloading chunks
CraftBukkit caused a regression here by making unloading chunks not
have a ticket added and returning unloaded future.
This caused entities who were killed in same tick their chunk is unloading
to not be able to be removed from the chunk.
This then results in dead entities lingering in the Chunk.
Combine that with a buggy detail of the previous implementation of
the Dupe UUID patch, then this was the likely source of the "Ghost entities"
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
private void removeFromChunk(Entity entity) {
- ChunkAccess ichunkaccess = chunkSource.getChunkUnchecked(entity.xChunk, entity.zChunk); // CraftBukkit - SPIGOT-5228: getChunkAt won't find the entity's chunk if it has already been unloaded (i.e. if it switched to state INACCESSIBLE).
+ LevelChunk ichunkaccess = entity.getCurrentChunk(); // Paper - getChunkAt(x,z,full,false) is broken by CraftBukkit as it won't return an unloading chunk. Use our current chunk reference as this points to what chunk they need to be removed from anyways
- if (ichunkaccess instanceof LevelChunk) {
+ if (ichunkaccess != null) { // Paper
((LevelChunk) ichunkaccess).removeEntity(entity);
}

View file

@ -22,8 +22,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ hatching = event.isHatching();
+ hatchingType = event.getHatchingType();
+ // Paper end
+
+
if (hatching) {
for (int i = 0; i < b0; ++i) {
Entity entity = level.getWorld().createEntity(new org.bukkit.Location(level.getWorld(), this.getX(), this.getY(), this.getZ(), this.yRot, 0.0F), hatchingType.getEntityClass());
Entity entity = level.getWorld().createEntity(new org.bukkit.Location(level.getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass());

View file

@ -9,20 +9,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -0,0 +0,0 @@ public class PaperWorldConfig {
disableHopperMoveEvents = getBoolean("hopper.disable-move-event", disableHopperMoveEvents);
log("Hopper Move Item Events: " + (disableHopperMoveEvents ? "disabled" : "enabled"));
}
+
+ public boolean nerfNetherPortalPigmen = false;
+ private void nerfNetherPortalPigmen() {
+ nerfNetherPortalPigmen = getBoolean("game-mechanics.nerf-pigmen-from-nether-portals", nerfNetherPortalPigmen);
+ }
}
+
public int lightQueueSize = 20;
private void lightQueueSize() {
lightQueueSize = getInt("light-queue-size", lightQueueSize);
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, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public long activatedTick = Integer.MIN_VALUE;
public boolean isTemporarilyActive = false; // Paper
public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
@ -30,42 +32,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
protected int numCollisions = 0; // Paper
public void inactiveTick() { }
// Spigot end
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
if (spawnedViaMobSpawner) {
tag.putBoolean("Paper.FromMobSpawner", true);
nbt.putBoolean("Paper.FromMobSpawner", true);
}
+ if (fromNetherPortal) {
+ tag.putBoolean("Paper.FromNetherPortal", true);
+ nbt.putBoolean("Paper.FromNetherPortal", true);
+ }
// Paper end
return tag;
return nbt;
} catch (Throwable throwable) {
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
spawnedViaMobSpawner = tag.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
+ fromNetherPortal = tag.getBoolean("Paper.FromNetherPortal");
if (tag.contains("Paper.SpawnReason")) {
String spawnReasonName = tag.getString("Paper.SpawnReason");
spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
+ fromNetherPortal = nbt.getBoolean("Paper.FromNetherPortal");
if (nbt.contains("Paper.SpawnReason")) {
String spawnReasonName = nbt.getString("Paper.SpawnReason");
try {
diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
@@ -0,0 +0,0 @@ import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
@@ -0,0 +0,0 @@ public class NetherPortalBlock extends Block {
if (entity != null) {
entity.setPortalCooldown();
+ entity.fromNetherPortal = true; // Paper
+ if (world.paperConfig.nerfNetherPortalPigmen) ((Mob) entity).aware = false; // Paper
+ if (world.paperConfig.nerfNetherPortalPigmen) ((net.minecraft.world.entity.Mob) entity).aware = false; // Paper
}
}
}

View file

@ -10,7 +10,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -0,0 +0,0 @@ public class Main {
float javaVersion = Float.parseFloat(System.getProperty("java.class.version"));
}
if (javaVersion > 60.0) {
System.err.println("Unsupported Java detected (" + javaVersion + "). Only up to Java 16 is supported.");
- return;

View file

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sun, 26 Jan 2020 16:30:19 -0600
Subject: [PATCH] Bees get gravity in void. Fixes MC-167279
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
@@ -0,0 +0,0 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
public Bee(EntityType<? extends Bee> type, Level world) {
super(type, world);
this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
- this.moveControl = new FlyingMoveControl(this, 20, true);
+ // Paper start - apply gravity to bees when they get stuck in the void, fixes MC-167279
+ this.moveControl = new FlyingMoveControl(this, 20, true) {
+ @Override
+ public void tick() {
+ if (this.mob.getY() <= 0) {
+ this.mob.setNoGravity(false);
+ }
+ super.tick();
+ }
+ };
+ // Paper end
this.lookControl = new Bee.BeeLookControl(this);
this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F);
this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F);

View file

@ -12,33 +12,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -0,0 +0,0 @@ public class PaperWorldConfig {
private void nerfNetherPortalPigmen() {
nerfNetherPortalPigmen = getBoolean("game-mechanics.nerf-pigmen-from-nether-portals", nerfNetherPortalPigmen);
}
+
+ public double zombieVillagerInfectionChance = -1.0;
+ private void zombieVillagerInfectionChance() {
+ zombieVillagerInfectionChance = getDouble("zombie-villager-infection-chance", zombieVillagerInfectionChance);
+ }
}
+
public int lightQueueSize = 20;
private void lightQueueSize() {
lightQueueSize = getInt("light-queue-size", lightQueueSize);
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
@@ -0,0 +0,0 @@ public class Zombie extends Monster {
@Override
public void killed(ServerLevel worldserver, LivingEntity entityliving) {
super.killed(worldserver, entityliving);
- if ((worldserver.getDifficulty() == Difficulty.NORMAL || worldserver.getDifficulty() == Difficulty.HARD) && entityliving instanceof Villager) {
- if (worldserver.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
+ // Paper start
+ if (level.paperConfig.zombieVillagerInfectionChance != 0.0 && (level.paperConfig.zombieVillagerInfectionChance != -1.0 || worldserver.getDifficulty() == Difficulty.NORMAL || worldserver.getDifficulty() == Difficulty.HARD) && entityliving instanceof Villager) {
+ if (level.paperConfig.zombieVillagerInfectionChance == -1.0 && worldserver.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
public void killed(ServerLevel world, LivingEntity other) {
super.killed(world, other);
- if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) {
- if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
+ if (level.paperConfig.zombieVillagerInfectionChance != 0.0 && (level.paperConfig.zombieVillagerInfectionChance != -1.0 || world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) {
+ if (level.paperConfig.zombieVillagerInfectionChance == -1.0 && world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
return;
}
+ if (level.paperConfig.zombieVillagerInfectionChance != -1.0 && (this.random.nextDouble() * 100.0) > level.paperConfig.zombieVillagerInfectionChance) {
+ return;
+ } // Paper end
Villager entityvillager = (Villager) entityliving;
Villager entityvillager = (Villager) other;
// CraftBukkit start

View file

@ -15,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@Override
protected boolean isImmobile() {
- return super.isImmobile() || this.isSleeping();
+ return super.isImmobile() || this.isSleeping() || removed || !valid; // Paper - player's who are dead or not in a world shouldn't move...
+ return super.isImmobile() || this.isSleeping() || this.isRemoved() || !valid; // Paper - player's who are dead or not in a world shouldn't move...
}
@Override

View file

@ -13,25 +13,26 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/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 implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
this.stats = server.getPlayerList().getStatisticManager(this);
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
this.maxUpStep = 1.0F;
- this.fudgeSpawnLocation(world);
+ //this.c(worldserver); // Paper - don't move to spawn on login, only first join
this.textFilter = server.createTextFilterForPlayer(this);
this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
}
// CraftBukkit end
+ public final void moveToSpawn(ServerLevel worldserver) { fudgeSpawnLocation(worldserver); } // Paper - OBFHELPER
private void fudgeSpawnLocation(ServerLevel world) {
BlockPos blockposition = world.getSpawn();
- private void fudgeSpawnLocation(ServerLevel world) {
+ public void fudgeSpawnLocation(ServerLevel world) { // Paper - private -> public
BlockPos blockposition = world.getSharedSpawnPos();
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
position = Vec3.atCenterOf(((ServerLevel) world).getSpawn());
if (world.dimensionType().hasSkyLight() && world.serverLevelData.getGameType() != GameType.ADVENTURE) { // CraftBukkit
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
position = Vec3.atCenterOf(((ServerLevel) world).getSharedSpawnPos());
}
this.level = world;
- this.setPos(position.x(), position.y(), position.z());
@ -47,8 +48,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
worldserver1 = worldserver;
}
+ if (nbttagcompound == null) player.moveToSpawn(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are....
+ if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are....
+
player.setLevel(worldserver1);
player.gameMode.setLevel((ServerLevel) player.level);
String s1 = "local";

View file

@ -10,12 +10,12 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/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 implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
public void doTick() {
try {
- if (!this.isSpectator() || this.level.hasChunkAt(this.blockPosition())) {
+ if (valid && !this.isSpectator() || this.level.hasChunkAt(this.blockPosition())) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
- if (!this.isSpectator() || !this.touchingUnloadedChunk()) {
+ if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
super.tick();
}

View file

@ -16,13 +16,13 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav
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, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
BlockPos blockposition1;
if (flag1) {
+ // Paper start - Ensure spawn chunk is always loaded before calculating Y coordinate
+ this.level.getChunkAt(this.level.getSpawn());
+ this.level.getChunkAt(this.level.getSharedSpawnPos());
+ // Paper end
blockposition1 = ServerLevel.END_SPAWN_POINT;
} else {
blockposition1 = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, destination.getSpawn());
blockposition1 = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, destination.getSharedSpawnPos());

View file

@ -149,7 +149,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return new Dimension(350, 200);
+ }
+
+ public void stop() { a(); } public void a() {
+ public void close() {
+ timer.stop();
+ ramGraph.stop();
+ }
@ -176,7 +176,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.util.Vector;
+
+public class RAMDetails extends JList<String> {
+ public static final DecimalFormat DECIMAL_FORMAT = Util.peek(new DecimalFormat("########0.000"), (format)
+ public static final DecimalFormat DECIMAL_FORMAT = Util.make(new DecimalFormat("########0.000"), (format)
+ -> format.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)));
+
+ private final MinecraftServer server;
@ -221,7 +221,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ Vector<String> vector = new Vector<>();
+ 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(getAverage(server.getTickTimes())) + " ms");
+ vector.add("Avg tick: " + DECIMAL_FORMAT.format(getAverage(server.tickTimes)) + " ms");
+ setListData(vector);
+ }
+
@ -383,31 +383,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ timer.stop();
+ }
+}
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -0,0 +0,0 @@ public class Util {
return factory.get();
}
+ public static <T> T peek(T t0, Consumer<T> consumer) { return make(t0, consumer); } // Paper - OBFHELPER
public static <T> T make(T object, Consumer<T> initializer) {
initializer.accept(object);
return object;
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private String motd;
private int maxBuildHeight;
private int playerIdleTimeout;
- public final long[] tickTimes;
+ public final long[] tickTimes; public long[] getTickTimes() { return tickTimes; } // Paper - OBFHELPER
@Nullable
private KeyPair keyPair;
@Nullable
diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
@ -418,22 +393,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
JPanel jpanel = new JPanel(new BorderLayout());
- StatsComponent guistatscomponent = new StatsComponent(this.server);
+ com.destroystokyo.paper.gui.GuiStatsComponent guistatscomponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper
Collection<Runnable> collection = this.finalizers; // CraftBukkit - decompile error
- this.finalizers.add(guistatscomponent::close);
+ this.finalizers.add(guistatscomponent::a);
jpanel.add(guistatscomponent, "North");
jpanel.add(this.buildPlayerPanel(), "Center");
jpanel.setBorder(new TitledBorder(new EtchedBorder(), "Stats"));
diff --git a/src/main/java/net/minecraft/server/gui/StatsComponent.java b/src/main/java/net/minecraft/server/gui/StatsComponent.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/gui/StatsComponent.java
+++ b/src/main/java/net/minecraft/server/gui/StatsComponent.java
@@ -0,0 +0,0 @@ import net.minecraft.server.MinecraftServer;
public class StatsComponent extends JComponent {
- private static final DecimalFormat DECIMAL_FORMAT = (DecimalFormat) Util.make((Object) (new DecimalFormat("########0.000")), (decimalformat) -> {
+ private static final DecimalFormat DECIMAL_FORMAT = (DecimalFormat) Util.make(new DecimalFormat("########0.000"), (decimalformat) -> { // Paper - decompile error
decimalformat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT));
});
private final int[] values = new int[256];
Objects.requireNonNull(guistatscomponent);

View file

@ -66,7 +66,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ midTickChunksTasksRan = 0; // Paper
// Spigot end
//MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time
if (this.debugCommandProfilerDelayStart) {
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
@ -111,7 +111,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
protected void tickChildren(BooleanSupplier shouldKeepTicking) {
public void tickChildren(BooleanSupplier shouldKeepTicking) {
+ midTickLoadChunks(); // Paper
MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper
this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit
@ -126,7 +126,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
Iterator iterator = this.getAllLevels().iterator();
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
processQueue.remove().run();
this.processQueue.remove().run();
}
MinecraftTimings.processQueueTimer.stopTiming(); // Spigot
-
@ -150,14 +150,6 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/sr
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -0,0 +0,0 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.server.MCUtil;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.Mth;
import net.minecraft.util.profiling.ProfilerFiller;
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
this.level.getProfiler().push("purge");
this.level.timings.doChunkMap.startTiming(); // Spigot
@ -169,7 +161,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
this.level.timings.doChunkUnload.startTiming(); // Spigot
this.level.getProfiler().popPush("unload");
this.chunkMap.tick(shouldKeepTicking);
this.chunkMap.tick(booleansupplier);
+ this.level.getServer().midTickLoadChunks(); // Paper
this.level.timings.doChunkUnload.stopTiming(); // Spigot
this.level.getProfiler().pop();
@ -184,13 +176,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
if (optional.isPresent()) {
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
//this.world.timings.chunkTicks.startTiming(); // Spigot // Paper
this.level.tickChunk(chunk, k);
//this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper
chunk.setInhabitedTime(chunk.getInhabitedTime() + j);
if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot
NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag2);
+ if (chunksTicked[0]++ % 10 == 0) this.level.getServer().midTickLoadChunks(); // Paper
}
}
}
// this.level.timings.doTickTiles.startTiming(); // Spigot // Paper
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
super.doRunTask(task);
}
@ -210,7 +202,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return false;
+ }
+ public void midTickLoadChunks() {
+ MinecraftServer server = ServerChunkCache.this.level.getServer();
+ net.minecraft.server.MinecraftServer server = ServerChunkCache.this.level.getServer();
+ // always try to load chunks, restrain generation/other updates only. don't count these towards tick count
+ //noinspection StatementWithEmptyBody
+ while (pollChunkLoadTasks()) {}
@ -231,8 +223,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end
+
@Override
protected boolean pollTask() {
// CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task
public boolean pollTask() {
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
@ -251,21 +243,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
timings.doSounds.stopTiming(); // Spigot
+ this.getServer().midTickLoadChunks(); // Paper
this.handlingTick = false;
gameprofilerfiller.popPush("entities");
gameprofilerfiller.pop();
boolean flag3 = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
timings.entityTick.stopTiming(); // Spigot
this.tickingEntities = false;
+ this.getServer().midTickLoadChunks(); // Paper
Entity entity2;
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
timings.tickEntities.stopTiming(); // Spigot
gameprofilerfiller.pop();
+ this.getServer().midTickLoadChunks(); // Paper
this.tickBlockEntities();
}
gameprofilerfiller.push("entityManagement");
+ this.getServer().midTickLoadChunks(); // Paper
this.entityManager.tick();
gameprofilerfiller.pop();
}

View file

@ -16,14 +16,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public FluidState getFluidState(int x, int y, int z) {
- try {
- if (y >= 0 && y >> 4 < this.sections.length) {
- LevelChunkSection chunksection = this.sections[y >> 4];
- int l = this.getSectionIndex(y);
-
- if (l >= 0 && l < this.sections.length) {
- LevelChunkSection chunksection = this.sections[l];
-
- if (!LevelChunkSection.isEmpty(chunksection)) {
- return chunksection.getFluidState(x & 15, y & 15, z & 15);
+ //try { // Paper - remove try catch
+ // try { // Paper - remove try catch
+ // Paper start - reduce the number of ops in this call
+ int index = y >> 4;
+ int index = this.getSectionIndex(y);
+ if (index >= 0 && index < this.sections.length) {
+ LevelChunkSection chunksection = this.sections[index];
+
@ -34,17 +36,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
return Fluids.EMPTY.defaultFluidState();
- } catch (Throwable throwable) {
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state");
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got");
+ /*} catch (Throwable throwable) { // Paper - remove try catch
+ CrashReport crashreport = CrashReport.a(throwable, "Getting fluid state");
+ CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Block being got");
- crashreportsystemdetails.setDetail("Location", () -> {
- return CrashReportCategory.formatLocation(x, y, z);
+ crashreportsystemdetails.a("Location", () -> {
+ return CrashReportSystemDetails.a(i, j, k);
+ /* // Paper - remove try catch
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got");
@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
});
throw new ReportedException(crashreport);
}
@ -60,8 +56,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
public FluidState getFluidState(int x, int y, int z) {
- return ((BlockState) this.states.get(x, y, z)).getFluidState();
+ return ((BlockState) this.states.get(x, y, z)).getFluidState(); // Paper - diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
- return this.states.get(x, y, z).getFluidState();
+ return this.states.get(x, y, z).getFluidState(); // Paper - diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
}
public void acquire() {

View file

@ -168,7 +168,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ private void queueEntryForTick(final TickNextTickData<T> entry, final ServerChunkCache chunkProvider) {
+ if (entry.tickState == STATE_SCHEDULED) {
+ if (chunkProvider.isTickingReadyMainThread(entry.getPosition())) {
+ if (chunkProvider.isTickingReadyMainThread(entry.pos)) {
+ this.toTickThisTick.add(entry);
+ entry.tickState = STATE_PENDING_TICK;
+ } else {
@ -179,13 +179,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ private void addToNotTickingReady(final TickNextTickData<T> entry) {
+ this.pendingChunkTickLoad.computeIfAbsent(MCUtil.getCoordinateKey(entry.getPosition()), (long keyInMap) -> {
+ this.pendingChunkTickLoad.computeIfAbsent(MCUtil.getCoordinateKey(entry.pos), (long keyInMap) -> {
+ return new ArrayList<>();
+ }).add(entry);
+ }
+
+ private void addToSchedule(final TickNextTickData<T> entry) {
+ long delay = entry.getTargetTick() - (this.currentTick + 1);
+ long delay = entry.triggerTick - (this.currentTick + 1);
+ if (delay < SHORT_SCHEDULE_TICK_THRESHOLD) {
+ if (delay < 0) {
+ // longScheduled orders by tick time, short scheduled does not
@ -202,7 +202,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ entry.tickState = STATE_CANCELLED_TICK;
+ // short/long scheduled will skip the entry
+
+ final BlockPos pos = entry.getPosition();
+ final BlockPos pos = entry.pos;
+ final long blockKey = MCUtil.getBlockKey(pos);
+
+ final ArrayList<TickNextTickData<T>> currentEntries = this.entriesByBlock.get(blockKey);
@ -221,7 +221,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ }
+
+ final long chunkKey = MCUtil.getCoordinateKey(entry.getPosition());
+ final long chunkKey = MCUtil.getCoordinateKey(entry.pos);
+
+ ObjectRBTreeSet<TickNextTickData<T>> set = this.entriesByChunk.get(chunkKey);
+
@ -246,7 +246,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ }
+
+ long delay = entry.getTargetTick() - (this.currentTick + 1);
+ long delay = entry.triggerTick - (this.currentTick + 1);
+ if (delay >= SHORT_SCHEDULE_TICK_THRESHOLD) {
+ this.longScheduled.remove(entry);
+ }
@ -274,7 +274,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ // we don't remove items from shortScheduled (but do from longScheduled) because they're cleared at the end of
+ // this tick
+ if (this.longScheduled.isEmpty() || this.longScheduled.first().getTargetTick() > currentTick) {
+ if (this.longScheduled.isEmpty() || this.longScheduled.first().triggerTick > currentTick) {
+ // nothing in longScheduled to worry about
+ final TickListServerInterval<T> interval = this.shortScheduled[this.shortScheduledIndex];
+ for (int i = 0, len = interval.byPriority.length; i < len; ++i) {
@ -300,7 +300,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ longScheduledIterator.remove();
+ if (longScheduledIterator.hasNext()) {
+ longCurrent = longScheduledIterator.next();
+ if (longCurrent.getTargetTick() > currentTick) {
+ if (longCurrent.triggerTick > currentTick) {
+ longCurrent = null;
+ break;
+ }
@ -316,7 +316,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ // add remaining from long scheduled
+ for (;;) {
+ if (longCurrent == null || longCurrent.getTargetTick() > currentTick) {
+ if (longCurrent == null || longCurrent.triggerTick > currentTick) {
+ break;
+ }
+ longScheduledIterator.remove();
@ -368,7 +368,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ continue;
+ }
+ try {
+ if (chunkProvider.isTickingReadyMainThread(toTick.getPosition())) {
+ if (chunkProvider.isTickingReadyMainThread(toTick.pos)) {
+ toTick.tickState = STATE_TICKING;
+ this.tickFunction.accept(toTick);
+ if (toTick.tickState == STATE_TICKING) {
@ -384,7 +384,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ CrashReport crashreport = CrashReport.forThrowable(thr, "Exception while ticking");
+ CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being ticked");
+
+ CrashReportCategory.populateBlockDetails(crashreportsystemdetails, toTick.getPosition(), (BlockState) null);
+ CrashReportCategory.populateBlockDetails(crashreportsystemdetails, this.world, toTick.pos, (BlockState) null);
+ throw new ReportedException(crashreport);
+ // end copy from TickListServer
+ }
@ -413,7 +413,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ entry.tickState = STATE_UNSCHEDULED;
+
+ final BlockPos pos = entry.getPosition();
+ final BlockPos pos = entry.pos;
+ final long blockKey = MCUtil.getBlockKey(pos);
+
+ final ArrayList<TickNextTickData<T>> currentEntries = this.entriesByBlock.get(blockKey);
@ -432,7 +432,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ }
+
+ final long chunkKey = MCUtil.getCoordinateKey(entry.getPosition());
+ final long chunkKey = MCUtil.getCoordinateKey(entry.pos);
+
+ ObjectRBTreeSet<TickNextTickData<T>> set = this.entriesByChunk.get(chunkKey);
+
@ -446,7 +446,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ @Override
+ public boolean isPendingTickThisTick(final BlockPos blockposition, final T data) {
+ public boolean willTickThisTick(final BlockPos blockposition, final T data) {
+ final ArrayList<TickNextTickData<T>> entries = this.entriesByBlock.get(MCUtil.getBlockKey(blockposition));
+
+ if (entries == null) {
@ -455,7 +455,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ for (int i = 0, size = entries.size(); i < size; ++i) {
+ final TickNextTickData<T> entry = entries.get(i);
+ if (entry.getData() == data && entry.tickState == STATE_PENDING_TICK) {
+ if (entry.getType() == data && entry.tickState == STATE_PENDING_TICK) {
+ return true;
+ }
+ }
@ -464,7 +464,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ @Override
+ public boolean isScheduledForTick(final BlockPos blockposition, final T data) {
+ public boolean hasScheduledTick(final BlockPos blockposition, final T data) {
+ final ArrayList<TickNextTickData<T>> entries = this.entriesByBlock.get(MCUtil.getBlockKey(blockposition));
+
+ if (entries == null) {
@ -473,7 +473,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ for (int i = 0, size = entries.size(); i < size; ++i) {
+ final TickNextTickData<T> entry = entries.get(i);
+ if (entry.getData() == data && entry.tickState == STATE_SCHEDULED) {
+ if (entry.getType() == data && entry.tickState == STATE_SCHEDULED) {
+ return true;
+ }
+ }
@ -482,22 +482,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ @Override
+ public void schedule(BlockPos blockPosition, T t, int i, TickPriority tickListPriority) {
+ public void scheduleTick(BlockPos blockPosition, T t, int i, TickPriority tickListPriority) {
+ this.schedule(blockPosition, t, i + this.currentTick, tickListPriority);
+ }
+
+ public void schedule(final TickNextTickData<T> entry) {
+ this.schedule(entry.getPosition(), entry.getData(), entry.getTargetTick(), entry.getPriority());
+ this.schedule(entry.pos, entry.getType(), entry.triggerTick, entry.priority);
+ }
+
+ public void schedule(final BlockPos pos, final T data, final long targetTick, final TickPriority priority) {
+ final TickNextTickData<T> entry = new TickNextTickData<>(pos, data, targetTick, priority);
+ if (this.excludeFromScheduling.test(entry.getData())) {
+ if (this.excludeFromScheduling.test(entry.getType())) {
+ return;
+ }
+
+ if (WARN_ON_EXCESSIVE_DELAY) {
+ final long delay = entry.getTargetTick() - this.currentTick;
+ final long delay = entry.triggerTick - this.currentTick;
+ if (delay >= EXCESSIVE_DELAY_THRESHOLD) {
+ MinecraftServer.LOGGER.warn("Entry " + entry.toString() + " has been scheduled with an excessive delay of: " + delay, new Throwable());
+ }
@ -514,7 +514,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final TickNextTickData<T> currentEntry = currentEntries.get(i);
+
+ // entries are only blocked from scheduling if currentEntry.equals(toSchedule) && currentEntry is scheduled to tick (NOT including pending)
+ if (currentEntry.getData() == entry.getData() && currentEntry.tickState == STATE_SCHEDULED) {
+ if (currentEntry.getType() == entry.getType() && currentEntry.tickState == STATE_SCHEDULED) {
+ // can't add
+ return;
+ }
@ -524,7 +524,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ entry.tickState = STATE_SCHEDULED;
+
+ this.entriesByChunk.computeIfAbsent(MCUtil.getCoordinateKey(entry.getPosition()), (final long keyInMap) -> {
+ this.entriesByChunk.computeIfAbsent(MCUtil.getCoordinateKey(entry.pos), (final long keyInMap) -> {
+ return new ObjectRBTreeSet<>(TickListServerInterval.ENTRY_COMPARATOR);
+ }).add(entry);
+
@ -541,19 +541,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // i.e the y value is ignored? the x, z calc isn't correct?
+ // however for the copy op they use the correct intersection, after using this one of course...
+ private static boolean isBlockInSortof(final BoundingBox boundingBox, final BlockPos pos) {
+ return pos.getX() >= boundingBox.getMinX() && pos.getX() < boundingBox.getMaxX() && pos.getZ() >= boundingBox.getMinZ() && pos.getZ() < boundingBox.getMaxZ();
+ return pos.getX() >= boundingBox.minX() && pos.getX() < boundingBox.maxX() && pos.getZ() >= boundingBox.minZ() && pos.getZ() < boundingBox.maxZ();
+ }
+
+ @Override
+ public List<TickNextTickData<T>> getEntriesInBoundingBox(final BoundingBox structureboundingbox, final boolean removeReturned, final boolean excludeTicked) {
+ if (structureboundingbox.getMinX() == structureboundingbox.getMaxX() || structureboundingbox.getMinZ() == structureboundingbox.getMaxZ()) {
+ public List<TickNextTickData<T>> fetchTicksInArea(final BoundingBox structureboundingbox, final boolean removeReturned, final boolean excludeTicked) {
+ if (structureboundingbox.minX() == structureboundingbox.maxX() || structureboundingbox.minZ() == structureboundingbox.maxZ()) {
+ return Collections.emptyList(); // vanilla behaviour, check isBlockInSortof above
+ }
+
+ final int lowerChunkX = structureboundingbox.getMinX() >> 4;
+ final int upperChunkX = (structureboundingbox.getMaxX() - 1) >> 4; // subtract 1 since maxX is exclusive
+ final int lowerChunkZ = structureboundingbox.getMinZ() >> 4;
+ final int upperChunkZ = (structureboundingbox.getMaxZ() - 1) >> 4; // subtract 1 since maxZ is exclusive
+ final int lowerChunkX = structureboundingbox.minX() >> 4;
+ final int upperChunkX = (structureboundingbox.maxX() - 1) >> 4; // subtract 1 since maxX is exclusive
+ final int lowerChunkZ = structureboundingbox.minZ() >> 4;
+ final int upperChunkZ = (structureboundingbox.maxZ() - 1) >> 4; // subtract 1 since maxZ is exclusive
+
+ final int xChunksLength = (upperChunkX - lowerChunkX + 1);
+ final int zChunksLength = (upperChunkZ - lowerChunkZ + 1);
@ -579,7 +579,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final int matchOne = (STATE_SCHEDULED | STATE_PENDING_TICK) | (excludeTicked ? 0 : (STATE_TICKING | STATE_TICKED));
+
+ MCUtil.mergeSortedSets((TickNextTickData<T> entry) -> {
+ if (!isBlockInSortof(structureboundingbox, entry.getPosition())) {
+ if (!isBlockInSortof(structureboundingbox, entry.pos)) {
+ return;
+ }
+ final int tickState = entry.tickState;
@ -603,24 +603,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ @Override
+ public void copy(BoundingBox structureboundingbox, BlockPos blockposition) {
+ // start copy from TickListServer // TODO check on update
+ List<TickNextTickData<T>> list = this.getEntriesInBoundingBox(structureboundingbox, false, false);
+ List<TickNextTickData<T>> list = this.fetchTicksInArea(structureboundingbox, false, false);
+ Iterator<TickNextTickData<T>> iterator = list.iterator();
+
+ while (iterator.hasNext()) {
+ TickNextTickData<T> nextticklistentry = iterator.next();
+
+ if (structureboundingbox.hasPoint( nextticklistentry.getPosition())) {
+ BlockPos blockposition1 = nextticklistentry.getPosition().add(blockposition);
+ T t0 = nextticklistentry.getData();
+ if (structureboundingbox.isInside( nextticklistentry.pos)) {
+ BlockPos blockposition1 = nextticklistentry.pos.offset(blockposition);
+ T t0 = nextticklistentry.getType();
+
+ this.schedule(new TickNextTickData<>(blockposition1, t0, nextticklistentry.getTargetTick(), nextticklistentry.getPriority()));
+ this.schedule(new TickNextTickData<>(blockposition1, t0, nextticklistentry.triggerTick, nextticklistentry.priority));
+ }
+ }
+ // end copy from TickListServer
+ }
+
+ @Override
+ public List<TickNextTickData<T>> getEntriesInChunk(ChunkPos chunkPos, boolean removeReturned, boolean excludeTicked) {
+ public List<TickNextTickData<T>> fetchTicksInChunk(ChunkPos chunkPos, boolean removeReturned, boolean excludeTicked) {
+ // Vanilla DOES get the entries 2 blocks out of the chunk too, but that doesn't matter since we ignore chunks
+ // not at ticking status, and ticking status requires neighbours loaded
+ // so with this method we will reduce scheduler churning
@ -651,16 +651,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ @Override
+ public ListTag serialize(ChunkPos chunkcoordintpair) {
+ public ListTag save(ChunkPos chunkcoordintpair) {
+ // start copy from TickListServer // TODO check on update
+ List<TickNextTickData<T>> list = this.getEntriesInChunk(chunkcoordintpair, false, true);
+ List<TickNextTickData<T>> list = this.fetchTicksInChunk(chunkcoordintpair, false, true);
+
+ return ServerTickList.serialize(this.getMinecraftKeyFrom, list, this.currentTick);
+ return ServerTickList.saveTickList(this.getMinecraftKeyFrom, list, this.currentTick);
+ // end copy from TickListServer
+ }
+
+ @Override
+ public int getTotalScheduledEntries() {
+ public int size() {
+ // good thing this is only used in debug reports // TODO check on update
+ int ret = 0;
+
@ -713,7 +713,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ public static final Comparator<TickNextTickData<?>> ENTRY_COMPARATOR_BY_ID = (entry1, entry2) -> {
+ return Long.compare(entry1.getId(), entry2.getId());
+ };
+ public static final Comparator<TickNextTickData<?>> ENTRY_COMPARATOR = (Comparator)TickNextTickData.comparator();
+ public static final Comparator<TickNextTickData<?>> ENTRY_COMPARATOR = (Comparator)TickNextTickData.createTimeComparator();
+
+ // we do not record the interval, this class is meant to be used on a ring buffer
+
@ -727,11 +727,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ public void addEntryLast(final TickNextTickData<T> entry) {
+ this.byPriority[entry.getPriority().ordinal()].addLast(entry);
+ this.byPriority[entry.priority.ordinal()].addLast(entry);
+ }
+
+ public void addEntryFirst(final TickNextTickData<T> entry) {
+ this.byPriority[entry.getPriority().ordinal()].addFirst(entry);
+ this.byPriority[entry.priority.ordinal()].addFirst(entry);
+ }
+
+ public void clear() {
@ -888,59 +888,58 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.getX() + x, this.getY() + y, this.getZ() + z);
}
+ public final BlockPos add(Vec3i baseblockposition) { return this.offset(baseblockposition); } // Paper - OBFHELPER
public BlockPos offset(Vec3i pos) {
return this.offset(pos.getX(), pos.getY(), pos.getZ());
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -0,0 +0,0 @@ public class ChunkHolder {
return null;
}
// Paper end - no-tick view distance
+ // Paper start
+ public final boolean isEntityTickingReady() {
+ return this.isEntityTickingReady;
+ }
+
+ public final boolean isTickingReady() {
+ return this.isTickingReady;
+ }
+
+ public final boolean isFullChunkReady() {
+ return this.isFullChunkReady;
+ }
+ // Paper end
public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
@@ -0,0 +0,0 @@ public class ChunkHolder {
either.ifLeft(chunk -> {
// note: Here is a very good place to add callbacks to logic waiting on this.
ChunkHolder.this.isTickingReady = true;
-
+
+ // Paper start - rewrite ticklistserver
+ ChunkHolder.this.chunkMap.level.onChunkSetTicking(ChunkHolder.this.pos.x, ChunkHolder.this.pos.z);
+ // Paper end - rewrite ticklistserver
}
});
});
// Paper end
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -0,0 +0,0 @@ import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
+import net.minecraft.server.MCUtil;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.Mth;
import net.minecraft.util.profiling.ProfilerFiller;
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
}, this.mainThreadProcessor);
}
// Paper end
+ // Paper start - rewrite ticklistserver
+ public final boolean isTickingReadyMainThread(BlockPos pos) {
+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(pos));
+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(net.minecraft.server.MCUtil.getCoordinateKey(pos));
+ return chunk != null && chunk.isTickingReady();
+ }
+ // Paper end - rewrite ticklistserver
+
public ServerChunkCache(ServerLevel worldserver, LevelStorageSource.LevelStorageAccess convertable_conversionsession, DataFixer dataFixer, StructureManager structureManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, boolean flag, ChunkProgressListener worldloadlistener, Supplier<DimensionDataStorage> supplier) {
this.level = worldserver;
this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(worldserver);
public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, boolean flag, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkstatusupdatelistener, Supplier<DimensionDataStorage> supplier) {
this.level = world;
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
@ -960,80 +959,73 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
// Add env and gen to constructor, WorldData -> WorldDataServer
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, ServerLevelData iworlddataserver, ResourceKey<net.minecraft.world.level.Level> resourcekey, DimensionType dimensionmanager, ChunkProgressListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<CustomSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getProfiler, false, flag, i, gen, env, executor); // Paper pass executor
// Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
convertable = convertable_conversionsession;
uuid = WorldUUID.getUUID(convertable_conversionsession.levelPath.toFile());
// CraftBukkit end
- this.blockTicks = new ServerTickList<>(this, (block) -> {
- return block == null || block.defaultBlockState().isAir();
- }, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
- this.liquidTicks = new ServerTickList<>(this, (fluidtype) -> {
- return fluidtype == null || fluidtype == Fluids.EMPTY;
- }, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper - Timings
DefaultedRegistry registryblocks = Registry.BLOCK;
Objects.requireNonNull(registryblocks);
- this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // CraftBukkit - decompile error // Paper - Timings
+ // this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // CraftBukkit - decompile error // Paper - Timings // Paper - copied down
Predicate<Fluid> predicate2 = (fluidtype) -> { // CraftBukkit - decompile error
return fluidtype == null || fluidtype == Fluids.EMPTY;
};
registryblocks = Registry.FLUID;
Objects.requireNonNull(registryblocks);
+ if (com.destroystokyo.paper.PaperConfig.useOptimizedTickList) {
+ this.blockTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (block) -> {
+ return block == null || block.defaultBlockState().isAir();
+ }, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
+ this.liquidTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (fluidtype) -> {
+ return fluidtype == null || fluidtype == Fluids.EMPTY;
+ }, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper - Timings
+ this.blockTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
+ this.liquidTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, predicate2, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper timings
+ } else {
+ this.blockTicks = new ServerTickList<>(this, (block) -> {
+ return block == null || block.defaultBlockState().isAir();
+ }, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
+ this.liquidTicks = new ServerTickList<>(this, (fluidtype) -> {
+ return fluidtype == null || fluidtype == Fluids.EMPTY;
+ }, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper - Timings
+ this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // CraftBukkit - decompile error // Paper - Timings & copied from above
this.liquidTicks = new ServerTickList<>(this, predicate2, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // CraftBukkit - decompile error // Paper - Timings
+ }
this.navigations = Sets.newHashSet();
this.navigatingMobs = new ObjectOpenHashSet();
this.blockEvents = new ObjectLinkedOpenHashSet();
this.tickTime = flag1;
this.dragonParts = new Int2ObjectOpenHashMap();
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
if (this.tickTime) {
long i = this.levelData.getGameTime() + 1L;
- this.worldDataServer.setGameTime(i);
+ this.worldDataServer.setGameTime(i); // Paper - diff on change, we want the below to be ran right after this
- this.serverLevelData.setGameTime(i);
+ this.serverLevelData.setGameTime(i); ; // Paper - diff on change, we want the below to be ran right after this
+ this.blockTicks.nextTick(); // Paper
+ this.liquidTicks.nextTick(); // Paper
this.worldDataServer.getScheduledEvents().tick(this.server, i);
this.serverLevelData.getScheduledEvents().tick(this.server, i);
if (this.levelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
this.setDayTime(this.levelData.getDayTime() + 1L);
diff --git a/src/main/java/net/minecraft/world/level/ChunkTickList.java b/src/main/java/net/minecraft/world/level/ChunkTickList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/ChunkTickList.java
+++ b/src/main/java/net/minecraft/world/level/ChunkTickList.java
@@ -0,0 +0,0 @@ import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MinecraftServer;
@@ -0,0 +0,0 @@ public class ChunkTickList<T> implements TickList<T> {
public class ChunkTickList<T> implements TickList<T> {
public ChunkTickList(Function<T, ResourceLocation> identifierProvider, List<TickNextTickData<T>> scheduledTicks, long startTime) {
this(identifierProvider, scheduledTicks.stream().map((tickNextTickData) -> {
- return new ChunkTickList.ScheduledTick(tickNextTickData.getType(), tickNextTickData.pos, (int)(tickNextTickData.triggerTick - startTime), tickNextTickData.priority);
+ return new ChunkTickList.ScheduledTick<>(tickNextTickData.getType(), tickNextTickData.pos, (int)(tickNextTickData.triggerTick - startTime), tickNextTickData.priority); // Paper - decompile error
}).collect(Collectors.toList()));
}
@@ -0,0 +0,0 @@ public class ChunkTickList<T> implements TickList<T> {
return nbttaglist;
return listTag;
}
+ private static final int MAX_TICK_DELAY = Integer.getInteger("paper.ticklist-max-tick-delay", -1).intValue(); // Paper - clean up broken entries
+
public static <T> ChunkTickList<T> create(ListTag ticks, Function<T, ResourceLocation> function, Function<ResourceLocation, T> function1) {
public static <T> ChunkTickList<T> create(ListTag ticks, Function<T, ResourceLocation> function, Function<ResourceLocation, T> function2) {
List<ChunkTickList.ScheduledTick<T>> list = Lists.newArrayList();
@@ -0,0 +0,0 @@ public class ChunkTickList<T> implements TickList<T> {
if (t0 != null) {
BlockPos blockposition = new BlockPos(nbttagcompound.getInt("x"), nbttagcompound.getInt("y"), nbttagcompound.getInt("z"));
- list.add(new ChunkTickList.ScheduledTick<>(t0, blockposition, nbttagcompound.getInt("t"), TickPriority.byValue(nbttagcompound.getInt("p"))));
T object = function2.apply(new ResourceLocation(compoundTag.getString("i")));
if (object != null) {
BlockPos blockPos = new BlockPos(compoundTag.getInt("x"), compoundTag.getInt("y"), compoundTag.getInt("z"));
- list.add(new ChunkTickList.ScheduledTick<>(object, blockPos, compoundTag.getInt("t"), TickPriority.byValue(compoundTag.getInt("p"))));
+ // Paper start - clean up broken entries
+ int delay = nbttagcompound.getInt("t");
+ int delay = compoundTag.getInt("t");
+ if (MAX_TICK_DELAY > 0 && delay > MAX_TICK_DELAY) {
+ MinecraftServer.LOGGER.warn("Dropping tick for pos " + blockposition + ", tick delay " + delay);
+ net.minecraft.server.MinecraftServer.LOGGER.warn("Dropping tick for pos " + blockPos + ", tick delay " + delay);
+ continue;
+ }
+ list.add(new ChunkTickList.ScheduledTick<>(t0, blockposition, delay, TickPriority.byValue(nbttagcompound.getInt("p"))));
+ // Paper end - clean up broken entries
+ list.add(new ChunkTickList.ScheduledTick<>(object, blockPos, delay, TickPriority.byValue(compoundTag.getInt("p"))));
}
}
@ -1048,164 +1040,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper start
+ public void nextTick() {}
+ // Paper end
+
+ public void tick() {
+ // Paper start - allow overriding
+ this.tick();
+ }
public void tick() {
+ // Paper end
int i = this.tickNextTickList.size();
if (false) { // CraftBukkit
@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
@Override
public boolean willTickThisTick(BlockPos pos, T object) {
- return this.currentlyTicking.contains(new TickNextTickData<>(pos, object));
+ // Paper start - allow overriding
+ return this.isPendingTickThisTick(pos, object);
+ }
+ public boolean isPendingTickThisTick(BlockPos blockposition, T t0) {
+ // Paper end
+ return this.currentlyTicking.contains(new TickNextTickData<>(blockposition, t0));
return ServerTickList.saveTickList(this.toId, list, this.level.getGameTime());
}
public List<TickNextTickData<T>> fetchTicksInChunk(ChunkPos chunkcoordintpair, boolean updateState, boolean getStaleTicks) {
+ // Paper start - allow overriding
+ return this.getEntriesInChunk(chunkcoordintpair, updateState, getStaleTicks);
+ }
+ public List<TickNextTickData<T>> getEntriesInChunk(ChunkPos chunkcoordintpair, boolean flag, boolean flag1) {
+ // Paper end
int i = (chunkcoordintpair.x << 4) - 2;
int j = i + 16 + 2;
int k = (chunkcoordintpair.z << 4) - 2;
int l = k + 16 + 2;
- return this.fetchTicksInArea(new BoundingBox(i, 0, k, j, 256, l), updateState, getStaleTicks);
+ return this.fetchTicksInArea(new BoundingBox(i, 0, k, j, 256, l), flag, flag1);
}
public List<TickNextTickData<T>> fetchTicksInArea(BoundingBox bounds, boolean updateState, boolean getStaleTicks) {
- List<TickNextTickData<T>> list = this.fetchTicksInArea((List) null, this.tickNextTickList, bounds, updateState);
+ // Paper start - allow overriding
+ return this.getEntriesInBoundingBox(bounds, updateState, getStaleTicks);
+ }
+ public List<TickNextTickData<T>> getEntriesInBoundingBox(BoundingBox structureboundingbox, boolean flag, boolean flag1) {
+ // Paper end
+ List<TickNextTickData<T>> list = this.fetchTicksInArea((List) null, this.tickNextTickList, structureboundingbox, flag);
- if (updateState && list != null) {
+ if (flag && list != null) {
this.tickNextTickSet.removeAll(list);
}
- list = this.fetchTicksInArea(list, this.currentlyTicking, bounds, updateState);
- if (!getStaleTicks) {
- list = this.fetchTicksInArea(list, this.alreadyTicked, bounds, updateState);
+ list = this.fetchTicksInArea(list, this.currentlyTicking, structureboundingbox, flag);
+ if (!flag1) {
+ list = this.fetchTicksInArea(list, this.alreadyTicked, structureboundingbox, flag);
}
return list == null ? Collections.emptyList() : list;
@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
}
public void copy(BoundingBox box, BlockPos offset) {
- List<TickNextTickData<T>> list = this.fetchTicksInArea(box, false, false);
+ // Paper start - allow overriding
+ this.copy(box, offset);
+ }
+ public void copy(BoundingBox structureboundingbox, BlockPos blockposition) {
+ // Paper end
+ List<TickNextTickData<T>> list = this.fetchTicksInArea(structureboundingbox, false, false);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
TickNextTickData<T> nextticklistentry = (TickNextTickData) iterator.next();
- if (box.isInside((Vec3i) nextticklistentry.pos)) {
- BlockPos blockposition1 = nextticklistentry.pos.offset((Vec3i) offset);
+ if (structureboundingbox.isInside((Vec3i) nextticklistentry.pos)) {
+ BlockPos blockposition1 = nextticklistentry.pos.offset((Vec3i) blockposition);
T t0 = nextticklistentry.getType();
this.addTickData(new TickNextTickData<>(blockposition1, t0, nextticklistentry.triggerTick, nextticklistentry.priority));
@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
}
public ListTag save(ChunkPos chunkcoordintpair) {
+ // Paper start - allow overriding
+ return this.serialize(chunkcoordintpair);
+ }
+ public ListTag serialize(ChunkPos chunkcoordintpair) {
+ // Paper end
List<TickNextTickData<T>> list = this.fetchTicksInChunk(chunkcoordintpair, false, true);
return saveTickList(this.toId, list, this.level.getGameTime());
}
+ public static <T> ListTag serialize(Function<T, ResourceLocation> function, Iterable<TickNextTickData<T>> iterable, long i) { return ServerTickList.saveTickList(function, iterable, i); } // Paper - OBFHELPER
private static <T> ListTag saveTickList(Function<T, ResourceLocation> identifierProvider, Iterable<TickNextTickData<T>> scheduledTicks, long time) {
- private static <T> ListTag saveTickList(Function<T, ResourceLocation> identifierProvider, Iterable<TickNextTickData<T>> scheduledTicks, long time) {
+ public static <T> ListTag saveTickList(Function<T, ResourceLocation> identifierProvider, Iterable<TickNextTickData<T>> scheduledTicks, long time) { // Paper - private -> public
ListTag nbttaglist = new ListTag();
Iterator iterator = scheduledTicks.iterator();
@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
@Override
public boolean hasScheduledTick(BlockPos pos, T object) {
- return this.tickNextTickSet.contains(new TickNextTickData<>(pos, object));
+ // Paper start - allow overriding
+ return this.isScheduledForTick(pos, object);
+ }
+ public boolean isScheduledForTick(BlockPos blockposition, T t0) {
+ // Paper end
+ return this.tickNextTickSet.contains(new TickNextTickData<>(blockposition, t0));
}
@Override
public void scheduleTick(BlockPos pos, T object, int delay, TickPriority priority) {
- if (!this.ignore.test(object)) {
- this.addTickData(new TickNextTickData<>(pos, object, (long) delay + this.level.getGameTime(), priority));
+ // Paper start - allow overriding
+ this.schedule(pos, object, delay, priority);
+ }
+ public void schedule(BlockPos blockposition, T t0, int i, TickPriority ticklistpriority) {
+ // Paper end
+ if (!this.ignore.test(t0)) {
+ this.addTickData(new TickNextTickData<>(blockposition, t0, (long) i + this.level.getGameTime(), ticklistpriority));
}
}
@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
}
public int size() {
+ // Paper start - allow overriding
+ return this.getTotalScheduledEntries();
+ }
+ public int getTotalScheduledEntries() {
+ // Paper end
return this.tickNextTickSet.size();
}
}
diff --git a/src/main/java/net/minecraft/world/level/TickNextTickData.java b/src/main/java/net/minecraft/world/level/TickNextTickData.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/TickNextTickData.java
+++ b/src/main/java/net/minecraft/world/level/TickNextTickData.java
@@ -0,0 +0,0 @@ import net.minecraft.core.BlockPos;
public class TickNextTickData<T> {
private static final java.util.concurrent.atomic.AtomicLong COUNTER = new java.util.concurrent.atomic.AtomicLong(); // Paper - async chunk loading
- private final T type;
- public final BlockPos pos;
- public final long triggerTick;
- public final TickPriority priority;
@@ -0,0 +0,0 @@ public class TickNextTickData<T> {
public final BlockPos pos;
public final long triggerTick;
public final TickPriority priority;
- private final long c;
+ private final T type; public final T getData() { return this.type; } // Paper - OBFHELPER
+ public final BlockPos pos; public final BlockPos getPosition() { return this.pos; } // Paper - OBFHELPER
+ public final long triggerTick; public final long getTargetTick() { return this.triggerTick; } // Paper - OBFHELPER
+ public final TickPriority priority; public final TickPriority getPriority() { return this.priority; } // Paper - OBFHELPER
+ private final long c; public final long getId() { return this.c; } // Paper - OBFHELPER
+ private final int hash; // Paper
+ public int tickState; // Paper
@ -1219,14 +1074,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.hash = this.computeHash(); // Paper
}
public boolean equals(Object object) {
@Override
@@ -0,0 +0,0 @@ public class TickNextTickData<T> {
}
}
+ // Paper start - optimize hashcode
+ @Override
@Override
public int hashCode() {
+ // Paper start - optimize hashcode
+ return this.hash;
+ }
+ public final int computeHash() {
@ -1234,68 +1087,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
return this.pos.hashCode();
}
- public static <T> Comparator<Object> createTimeComparator() { // Paper - decompile fix
- return Comparator.comparingLong((nextticklistentry) -> {
- return ((TickNextTickData<T>) nextticklistentry).triggerTick; // Paper - decompile fix
- }).thenComparing((nextticklistentry) -> {
- return ((TickNextTickData<T>) nextticklistentry).priority; // Paper - decompile fix
- }).thenComparingLong((nextticklistentry) -> {
- return ((TickNextTickData<T>) nextticklistentry).c; // Paper - decompile fix
public static <T> Comparator<TickNextTickData<T>> createTimeComparator() {
- return Comparator.<TickNextTickData<T>>comparingLong((tickNextTickData) -> { // Paper - decompile fix
- return tickNextTickData.triggerTick;
- }).thenComparing((tickNextTickData) -> {
- return tickNextTickData.priority;
- }).thenComparingLong((tickNextTickData) -> {
- return tickNextTickData.c;
- });
+ // Paper start - let's not use more functional code for no reason.
+ public static <T> Comparator<Object> comparator() { return TickNextTickData.createTimeComparator(); } // Paper - OBFHELPER
+ public static <T> Comparator<Object> createTimeComparator() {
+ return (Comparator)(Comparator<TickNextTickData>)(TickNextTickData nextticklistentry, TickNextTickData nextticklistentry1) -> {
+ int i = Long.compare(nextticklistentry.getTargetTick(), nextticklistentry1.getTargetTick());
+ // Paper start - let's not use more functional code for no reason.
+ return (Comparator) (Comparator<TickNextTickData>) (TickNextTickData nextticklistentry, TickNextTickData nextticklistentry1) -> {
+ int i = Long.compare(nextticklistentry.triggerTick, nextticklistentry1.triggerTick);
+
+ if (i != 0) {
+ return i;
+ } else {
+ i = nextticklistentry.getPriority().compareTo(nextticklistentry1.getPriority());
+ i = nextticklistentry.priority.compareTo(nextticklistentry1.priority);
+ return i != 0 ? i : Long.compare(nextticklistentry.getId(), nextticklistentry1.getId());
+ }
+ };
}
+ // Paper end - let's not use more functional code for no reason.
public String toString() {
return this.type + ": " + this.pos + ", " + this.triggerTick + ", " + this.priority + ", " + this.c;
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java b/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java
@@ -0,0 +0,0 @@ import net.minecraft.nbt.IntArrayTag;
public class BoundingBox {
- public int x0;
- public int y0;
- public int z0;
- public int x1;
- public int y1;
- public int z1;
+ public int x0; public final int getMinX() { return this.x0; } // Paper - OBFHELPER
+ public int y0; public final int getMinY() { return this.y0; } // Paper - OBFHELPER
+ public int z0; public final int getMinZ() { return this.z0; } // Paper - OBFHELPER
+ public int x1; public final int getMaxX() { return this.x1; } // Paper - OBFHELPER
+ public int y1; public final int getMaxY() { return this.y1; } // Paper - OBFHELPER
+ public int z1; public final int getMaxZ() { return this.z1; } // Paper - OBFHELPER
public BoundingBox() {}
@@ -0,0 +0,0 @@ public class BoundingBox {
this.y1 = 512;
+ // Paper end - let's not use more functional code for no reason.
}
+ public final boolean intersects(BoundingBox boundingBox) { return this.intersects(boundingBox); } // Paper - OBFHELPER
public boolean intersects(BoundingBox other) {
return this.x1 >= other.x0 && this.x0 <= other.x1 && this.z1 >= other.z0 && this.z0 <= other.z1 && this.y1 >= other.y0 && this.y0 <= other.y1;
}
@@ -0,0 +0,0 @@ public class BoundingBox {
this.move(baseblockposition.getX(), baseblockposition.getY(), baseblockposition.getZ());
}
+ public final boolean hasPoint(Vec3i baseblockposition) { return this.isInside(baseblockposition); } // Paper - OBFHELPER
public boolean isInside(Vec3i vec) {
return vec.getX() >= this.x0 && vec.getX() <= this.x1 && vec.getZ() >= this.z0 && vec.getZ() <= this.z1 && vec.getY() >= this.y0 && vec.getY() <= this.y1;
}
@Override

View file

@ -70,18 +70,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return fastRandomBounded(this.next(32) & 0xFFFFFFFFL, bound);
+ }
+}
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
return this.set(Mth.floor(x), Mth.floor(y), Mth.floor(z));
}
+ public final BlockPos.MutableBlockPos setValues(final Vec3i baseblockposition) { return this.set(baseblockposition); } // Paper - OBFHELPER
public BlockPos.MutableBlockPos set(Vec3i pos) {
return this.set(pos.getX(), pos.getY(), pos.getZ());
}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
@ -108,11 +96,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change
if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder
- blockposition = this.findLightingTargetAround(this.getBlockRandomPos(j, 0, k, 15));
+ blockposition.setValues(this.findLightingTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper
- blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
+ blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper
if (this.isRainingAt(blockposition)) {
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance; // Paper
boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
@ -129,7 +117,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end
Biome biomebase = this.getBiome(blockposition);
- if (biomebase.shouldFreeze(this, blockposition1)) {
- if (biomebase.shouldFreeze((LevelReader) this, blockposition1)) {
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
+ // Paper start - optimise chunk ticking
+ blockposition.setY(downY);
@ -138,18 +126,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end
}
+ blockposition.setY(normalY); // Paper
if (flag && biomebase.shouldSnow(this, blockposition)) {
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit
}
if (flag) {
+ blockposition.setY(normalY); // Paper
if (biomebase.shouldSnow(this, blockposition)) {
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit
}
- if (flag && this.getBiome(blockposition1).getPrecipitation() == Biome.Precipitation.RAIN) {
- this.getBlockState(blockposition1).getBlock().handleRain((net.minecraft.world.level.Level) this, blockposition1);
+ // Paper start - optimise chunk ticking
+ blockposition.setY(downY);
+ if (flag && this.getBiome(blockposition).getPrecipitation() == Biome.Precipitation.RAIN) {
+ chunk.getBlockState(blockposition).getBlock().handleRain((net.minecraft.world.level.Level) this, blockposition);
+ // Paper end
- BlockState iblockdata = this.getBlockState(blockposition1);
+ blockposition.setY(downY); // Paper
+ BlockState iblockdata = this.getBlockState(blockposition); // Paper
Biome.Precipitation biomebase_precipitation = this.getBiome(blockposition).getPrecipitation();
- if (biomebase_precipitation == Biome.Precipitation.RAIN && biomebase.isColdEnoughToSnow(blockposition1)) {
+ if (biomebase_precipitation == Biome.Precipitation.RAIN && biomebase.isColdEnoughToSnow(blockposition)) { // Paper
biomebase_precipitation = Biome.Precipitation.SNOW;
}
- iblockdata.getBlock().handlePrecipitation(iblockdata, (net.minecraft.world.level.Level) this, blockposition1, biomebase_precipitation);
+ iblockdata.getBlock().handlePrecipitation(iblockdata, (net.minecraft.world.level.Level) this, blockposition, biomebase_precipitation); // Paper
}
}
@ -160,27 +154,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
if (randomTickSpeed > 0) {
- LevelChunkSection[] achunksection = chunk.getSections();
- int l = achunksection.length;
-
- for (int i1 = 0; i1 < l; ++i1) {
- LevelChunkSection chunksection = achunksection[i1];
+ gameprofilerfiller.push("randomTick");
+ timings.chunkTicksBlocks.startTiming(); // Paper
- for (int i1 = 0; i1 < l; ++i1) {
- LevelChunkSection chunksection = achunksection[i1];
+ LevelChunkSection[] sections = chunk.getSections();
- if (chunksection != LevelChunk.EMPTY_SECTION && chunksection.isRandomlyTicking()) {
- int j1 = chunksection.bottomBlockY();
+ LevelChunkSection[] sections = chunk.getSections();
- for (int k1 = 0; k1 < randomTickSpeed; ++k1) {
- BlockPos blockposition2 = this.getBlockRandomPos(j, j1, k, 15);
+ for (int sectionIndex = 0; sectionIndex < 16; ++sectionIndex) {
+ LevelChunkSection section = sections[sectionIndex];
+ if (section == null || section.tickingList.size() == 0) {
+ continue;
+ }
- for (int k1 = 0; k1 < randomTickSpeed; ++k1) {
- BlockPos blockposition2 = this.getBlockRandomPos(j, j1, k, 15);
+ int yPos = sectionIndex << 4;
- gameprofilerfiller.push("randomTick");
- BlockState iblockdata = chunksection.getBlockState(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k);
- BlockState iblockdata1 = chunksection.getBlockState(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k);
+ int yPos = sectionIndex << 4;
+ for (int a = 0; a < randomTickSpeed1; ++a) {
+ int tickingBlocks = section.tickingList.size();
+ int index = this.randomTickRandom.nextInt(16 * 16 * 16);
@ -188,8 +182,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ continue;
+ }
- if (iblockdata.isRandomlyTicking()) {
- iblockdata.randomTick(this, blockposition2, this.random);
- if (iblockdata1.isRandomlyTicking()) {
- iblockdata1.randomTick(this, blockposition2, this.random);
- }
+ long raw = section.tickingList.getRaw(index);
+ int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw);
@ -197,7 +191,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ int randomY = ((location >>> (4 + 4)) & 255) | yPos;
+ int randomZ = (location >>> 4) & 15;
- FluidState fluid = iblockdata.getFluidState();
- FluidState fluid = iblockdata1.getFluidState();
+ BlockPos blockposition2 = blockposition.setValues(j + randomX, randomY, k + randomZ);
+ BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw);
@ -220,7 +214,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- gameprofilerfiller.pop();
}
protected BlockPos findLightingTargetAround(BlockPos pos) {
private Optional<BlockPos> findLightningRod(BlockPos pos) {
diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/BitStorage.java
@ -300,23 +294,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
this.entities.remove(entity); // Paper
}
@Override
public void addEntity(Entity entity) {}
- @Override
- public int getHeight(Heightmap.Types type, int x, int z) {
+ public final int getHighestBlockY(Heightmap.Types heightmap_type, int i, int j) { return this.getHeight(heightmap_type, i, j) + 1; } // Paper - sort of an obfhelper, but without -1
+ @Override public int getHeight(Heightmap.Types type, int x, int z) { // Paper
@Override
public int getHeight(Heightmap.Types type, int x, int z) {
return ((Heightmap) this.heightmaps.get(type)).getFirstAvailable(x & 15, z & 15) - 1;
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -0,0 +0,0 @@ import net.minecraft.world.level.material.FluidState;
public class LevelChunkSection {
@@ -0,0 +0,0 @@ public class LevelChunkSection {
public static final int SECTION_HEIGHT = 16;
public static final int SECTION_SIZE = 4096;
public static final Palette<BlockState> GLOBAL_BLOCKSTATE_PALETTE = new GlobalPalette<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState());
- private final int bottomBlockY;
+ final int bottomBlockY; // Paper - private -> package-private
@ -325,15 +316,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ short tickingBlockCount; // Paper - private -> package-private
private short tickingFluidCount;
final PalettedContainer<BlockState> states; // Paper - package-private
+ public final com.destroystokyo.paper.util.maplist.IBlockDataList tickingList = new com.destroystokyo.paper.util.maplist.IBlockDataList(); // Paper
+
// Paper start - Anti-Xray - Add parameters
@Deprecated public LevelChunkSection(int yOffset) { this(yOffset, null, null, true); } // Notice for updates: Please make sure this constructor isn't used anywhere
public LevelChunkSection(int i, ChunkAccess chunk, Level world, boolean initializeBlocks) {
public LevelChunkSection(int yOffset) {
this(yOffset, (short)0, (short)0, (short)0);
@@ -0,0 +0,0 @@ public class LevelChunkSection {
--this.nonEmptyBlockCount;
if (iblockdata1.isRandomlyTicking()) {
if (blockState.isRandomlyTicking()) {
--this.tickingBlockCount;
+ // Paper start
+ this.tickingList.remove(x, y, z);
@ -361,28 +350,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
this.nonEmptyBlockCount = 0;
this.tickingBlockCount = 0;
this.tickingFluidCount = 0;
- this.states.count((iblockdata, i) -> {
+ this.states.forEachLocation((iblockdata, location) -> { // Paper
FluidState fluid = iblockdata.getFluidState();
if (!iblockdata.isAir()) {
- this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + i);
+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1);
if (iblockdata.isRandomlyTicking()) {
- this.tickingBlockCount = (short) (this.tickingBlockCount + i);
+ this.tickingBlockCount = (short) (this.tickingBlockCount + 1);
- this.states.count((state, count) -> {
+ this.states.forEachLocation((state, location) -> { // Paper
FluidState fluidState = state.getFluidState();
if (!state.isAir()) {
- this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + count);
+ this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + 1); // Paper
if (state.isRandomlyTicking()) {
- this.tickingBlockCount = (short)(this.tickingBlockCount + count);
+ // Paper start
+ this.tickingList.add(location, iblockdata);
+ this.tickingBlockCount = (short)(this.tickingBlockCount + 1);
+ this.tickingList.add(location, state);
+ // Paper end
}
}
if (!fluid.isEmpty()) {
- this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + i);
+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1);
if (fluid.isRandomlyTicking()) {
- this.tickingFluidCount = (short) (this.tickingFluidCount + i);
+ this.tickingFluidCount = (short) (this.tickingFluidCount + 1);
if (!fluidState.isEmpty()) {
- this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + count);
+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); // Paper
if (fluidState.isRandomlyTicking()) {
- this.tickingFluidCount = (short)(this.tickingFluidCount + count);
+ this.tickingFluidCount = (short) (this.tickingFluidCount + 1); // Paper
}
}
@ -404,4 +392,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
@FunctionalInterface
public interface CountConsumer<T> {
void accept(T object, int count);

View file

@ -17,66 +17,26 @@ diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -0,0 +0,0 @@ import net.minecraft.server.MCUtil;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerAdvancements;
import net.minecraft.server.ServerScoreboard;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.level.ServerPlayerGameMode;
+import net.minecraft.server.level.TicketType;
+import net.minecraft.server.network.ServerGamePacketListenerImpl;
+import net.minecraft.server.network.ServerLoginPacketListenerImpl;
+import net.minecraft.sounds.SoundEvents;
+import net.minecraft.sounds.SoundSource;
+import net.minecraft.stats.ServerStatsCounter;
+import net.minecraft.stats.Stats;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.Tag;
import net.minecraft.util.Mth;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.Level;
@@ -0,0 +0,0 @@ import io.papermc.paper.adventure.PaperAdventure; // Paper
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import net.minecraft.server.dedicated.DedicatedServer;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.server.level.ServerPlayerGameMode;
-import net.minecraft.server.network.ServerGamePacketListenerImpl;
-import net.minecraft.server.network.ServerLoginPacketListenerImpl;
-import net.minecraft.sounds.SoundEvents;
-import net.minecraft.sounds.SoundSource;
-import net.minecraft.stats.ServerStatsCounter;
-import net.minecraft.stats.Stats;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
@@ -0,0 +0,0 @@ public abstract class PlayerList {
entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
// CraftBukkit end
+ worldserver1.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, new ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
while (avoidSuffocation && !worldserver1.noCollision(entityplayer1) && entityplayer1.getY() < 256.0D) {
+ worldserver1.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
while (avoidSuffocation && !worldserver1.noCollision(entityplayer1) && entityplayer1.getY() < (double) worldserver1.getMaxBuildHeight()) {
entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ());
}
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, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
// Paper end
public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
+ public boolean collisionLoadChunks = false; // Paper
private CraftEntity bukkitEntity;
ChunkMap.TrackedEntity tracker; // Paper
+ public boolean collisionLoadChunks = false; // Paper
public Throwable addedToWorldStack; // Paper - entity debug
public CraftEntity getBukkitEntity() {
if (bukkitEntity == null) {
diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
@ -84,30 +44,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public interface CollisionGetter extends BlockGetter {
}
default boolean noCollision(@Nullable Entity entity, AABB axisalignedbb, Predicate<Entity> predicate) {
default boolean noCollision(@Nullable Entity entity, AABB box, Predicate<Entity> filter) {
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
return this.getCollisions(entity, axisalignedbb, predicate).allMatch(VoxelShape::isEmpty);
return this.getCollisions(entity, box, filter).allMatch(VoxelShape::isEmpty);
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
}
Stream<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB axisalignedbb, Predicate<Entity> predicate);
Stream<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB box, Predicate<Entity> predicate);
diff --git a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
+++ b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
@@ -0,0 +0,0 @@ import java.util.function.Consumer;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Cursor3D;
+import net.minecraft.server.MCUtil;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.Blocks;
@@ -0,0 +0,0 @@ import net.minecraft.world.phys.shapes.VoxelShape;
public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
@Nullable
- private final Entity source;
+ private final Entity source; final Entity getEntity() { return this.source; } // Paper - OBFHELPER
@ -123,8 +73,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private final BiPredicate<BlockState, BlockPos> predicate;
@@ -0,0 +0,0 @@ public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
boolean collisionCheck(Consumer<? super VoxelShape> consumer) {
while (true) {
boolean collisionCheck(Consumer<? super VoxelShape> action) {
while(true) {
if (this.cursor.advance()) {
- int i = this.cursor.nextX();
- int j = this.cursor.nextY();
@ -133,53 +83,51 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ int j = this.cursor.nextY(); final int y = j;
+ int k = this.cursor.nextZ(); final int z = k;
int l = this.cursor.getNextType();
if (l == 3) {
continue;
}
- BlockGetter iblockaccess = this.getChunk(i, k);
-
- if (iblockaccess == null) {
- BlockGetter blockGetter = this.getChunk(i, k);
- if (blockGetter == null) {
+ // Paper start - ensure we don't load chunks
+ Entity entity = this.getEntity();
+ BlockPos.MutableBlockPos blockposition_mutableblockposition = this.getMutablePos();
+ boolean far = entity != null && MCUtil.distanceSq(entity.getX(), y, entity.getZ(), x, y, z) > 14;
+ boolean far = entity != null && net.minecraft.server.MCUtil.distanceSq(entity.getX(), y, entity.getZ(), x, y, z) > 14;
+ blockposition_mutableblockposition.setValues(x, y, z);
+
+ boolean isRegionLimited = this.getCollisionAccess() instanceof WorldGenRegion;
+ BlockState iblockdata = isRegionLimited ? Blocks.VOID_AIR.defaultBlockState() : ((!far && entity instanceof ServerPlayer) || (entity != null && entity.collisionLoadChunks)
+ boolean isRegionLimited = this.getCollisionAccess() instanceof net.minecraft.server.level.WorldGenRegion;
+ BlockState blockState = isRegionLimited ? Blocks.VOID_AIR.defaultBlockState() : ((!far && entity instanceof net.minecraft.server.level.ServerPlayer) || (entity != null && entity.collisionLoadChunks)
+ ? this.getCollisionAccess().getBlockState(blockposition_mutableblockposition)
+ : this.getCollisionAccess().getTypeIfLoaded(blockposition_mutableblockposition)
+ );
+
+ if (iblockdata == null) {
+ if (!(entity instanceof ServerPlayer) || entity.level.paperConfig.preventMovingIntoUnloadedChunks) {
+ VoxelShape voxelshape3 = Shapes.of(far ? entity.getBoundingBox() : new AABB(new BlockPos(x, y, z)));
+ consumer.accept(voxelshape3);
+ if (blockState == null) {
+ if (!(entity instanceof net.minecraft.server.level.ServerPlayer) || entity.level.paperConfig.preventMovingIntoUnloadedChunks) {
+ VoxelShape voxelshape3 = Shapes.create(far ? entity.getBoundingBox() : new AABB(new BlockPos(x, y, z)));
+ action.accept(voxelshape3);
+ return true;
+ }
continue;
}
-
- this.pos.set(i, j, k);
- BlockState iblockdata = iblockaccess.getBlockState(this.pos);
+ // Paper - moved up
+ // Paper end
if (!this.predicate.test(iblockdata, this.pos) || l == 1 && !iblockdata.hasLargeCollisionShape() || l == 2 && !iblockdata.is(Blocks.MOVING_PISTON)) {
- this.pos.set(i, j, k);
- BlockState blockState = blockGetter.getBlockState(this.pos);
if (!this.predicate.test(blockState, this.pos) || l == 1 && !blockState.hasLargeCollisionShape() || l == 2 && !blockState.is(Blocks.MOVING_PISTON)) {
continue;
}
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
@@ -0,0 +0,0 @@ public final class Shapes {
if (k2 < 3) {
blockposition_mutableblockposition.set(enumaxiscycle1, i2, j2, l1);
- BlockState iblockdata = world.getBlockState(blockposition_mutableblockposition);
+ BlockState iblockdata = world.getTypeIfLoaded(blockposition_mutableblockposition); // Paper
+ if (iblockdata == null) return 0.0D; // Paper
if ((k2 != 1 || iblockdata.hasLargeCollisionShape()) && (k2 != 2 || iblockdata.is(Blocks.MOVING_PISTON))) {
initial = iblockdata.getCollisionShape((BlockGetter) world, blockposition_mutableblockposition, context).collide(enumdirection_enumaxis2, box.move((double) (-blockposition_mutableblockposition.getX()), (double) (-blockposition_mutableblockposition.getY()), (double) (-blockposition_mutableblockposition.getZ())), initial);
if (s < 3) {
mutableBlockPos.set(axisCycle, q, r, p);
- BlockState blockState = world.getBlockState(mutableBlockPos);
+ BlockState blockState = world.getTypeIfLoaded(mutableBlockPos); // Paper
+ if (blockState == null) return 0.0D; // Paper
if ((s != 1 || blockState.hasLargeCollisionShape()) && (s != 2 || blockState.is(Blocks.MOVING_PISTON))) {
initial = blockState.getCollisionShape(world, mutableBlockPos, context).collide(axis3, box.move((double)(-mutableBlockPos.getX()), (double)(-mutableBlockPos.getY()), (double)(-mutableBlockPos.getZ())), initial);
if (Math.abs(initial) < 1.0E-7D) {

View file

@ -74,11 +74,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private static final Logger LOGGER = LogManager.getLogger();
private static final int MIN_VIEW_DISTANCE = 3;
public static final int MAX_VIEW_DISTANCE = 33;
public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance();
- public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap();
- public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
+ // Paper start - faster copying
+ public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<>(); // Paper - faster copying
+ public final Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap = new ProtectedVisibleChunksMap(); // Paper - faster copying
@ -106,13 +104,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end
+ public final com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder> pendingVisibleChunks = new com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder>(); // Paper - this is used if the visible chunks is updated while iterating only
+ public transient com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder> visibleChunksClone; // Paper - used for async access of visible chunks, clone and cache only when needed
public static final int FORCED_TICKET_LEVEL = 31;
- public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap();
- public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
+ // public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); // Paper - moved up
+ // public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap; // Paper - moved up
private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads;
public final LongSet entitiesInLevel; // Paper - private -> public
public final ServerLevel level;
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
public ChunkMap(ServerLevel worldserver, LevelStorageSource.LevelStorageAccess convertable_conversionsession, DataFixer dataFixer, StructureManager definedstructuremanager, Executor workerExecutor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, Supplier<DimensionDataStorage> supplier, int i, boolean flag) {
super(new File(convertable_conversionsession.getDimensionPath(worldserver.dimension()), "region"), dataFixer, flag);
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
super(new File(session.getDimensionPath(world.dimension()), "region"), dataFixer, dsync);
- this.visibleChunkMap = this.updatingChunkMap.clone();
+ //this.visibleChunks = this.updatingChunks.clone(); // Paper - no more cloning
this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
@ -159,7 +162,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end
+
@Nullable
public ChunkHolder getVisibleChunkIfPresent(long pos) { // Paper - protected -> public
public final ChunkHolder getVisibleChunkIfPresent(long pos) { // Paper - protected -> public
- return (ChunkHolder) this.visibleChunkMap.get(pos);
+ // Paper start - mt safe get
+ if (Thread.currentThread() != this.level.thread) {
@ -173,7 +176,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
protected IntSupplier getChunkQueueLevel(long pos) {
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper end
}
protected void saveAllChunks(boolean flush) {
+ Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = this.getVisibleChunks(); // Paper remove clone of visible Chunks unless saving off main thread (watchdog kill)
@ -223,7 +226,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
void dumpChunks(Writer writer) throws IOException {
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("entity_count").addColumn("block_entity_count").build(writer);
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").build(writer);
- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator();
+ ObjectBidirectionalIterator objectbidirectionaliterator = this.getVisibleChunks().long2ObjectEntrySet().iterator(); // Paper
@ -247,8 +250,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -0,0 +0,0 @@ public class CraftWorld implements World {
return ret;
}
@Override
public int getTileEntityCount() {
+ return net.minecraft.server.MCUtil.ensureMain(() -> {
// We don't use the full world tile entity list, so we must iterate chunks
@ -260,9 +263,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
return size;
+ });
}
public int getTickableTileEntityCount() {
return world.tickableBlockEntities.size();
}
@Override
@@ -0,0 +0,0 @@ public class CraftWorld implements World {
@Override
public int getChunkCount() {
+ return net.minecraft.server.MCUtil.ensureMain(() -> {
int ret = 0;
@ -275,8 +280,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- return ret;
+ return ret; });
}
public int getPlayerCount() {
return world.players.size();
@Override
@@ -0,0 +0,0 @@ public class CraftWorld implements World {
@Override
@ -289,6 +294,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ }
+ // Paper end
Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.visibleChunkMap;
Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = this.world.getChunkSource().chunkMap.visibleChunkMap;
return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new);
}

View file

@ -39,7 +39,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/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 implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
public boolean wonGame;
private int containerUpdateDelay; // Paper
public long loginTime; // Paper
@ -47,18 +47,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Paper start - cancellable death event
public boolean queueHealthUpdatePacket = false;
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
diff --git a/src/main/java/net/minecraft/stats/StatType.java b/src/main/java/net/minecraft/stats/StatType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/stats/StatType.java
+++ b/src/main/java/net/minecraft/stats/StatType.java
@@ -0,0 +0,0 @@ public class StatType<T> implements Iterable<Stat<T>> {
return this.map.values().iterator();
}
+ public final Stat<T> get(T t) { return this.get(t); }; // Paper - OBFHELPER
public Stat<T> get(T key) {
return this.get(key, StatFormatter.DEFAULT);
}
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
@ -127,7 +115,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } else {
+ long days;
+ if (world.paperConfig.patrolPerPlayerStart) {
+ days = entityhuman.getStats().getValue(Stats.CUSTOM.get(Stats.PLAY_ONE_MINUTE)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang
+ days = entityhuman.getStats().getValue(Stats.CUSTOM.get(Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang
+ } else {
+ days = world.getDayTime() / 24000L;
+ }

View file

@ -30,19 +30,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
public void onTrackingStart(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
- ServerLevel.this.getChunkSource().addEntity(entity);
+ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - moved down below valid=true
if (entity instanceof ServerPlayer) {
ServerLevel.this.players.add((ServerPlayer) entity);
ServerLevel.this.updateSleepingPlayerList();
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
- this.getChunkSource().addEntity(entity);
+ // this.getChunkProvider().addEntity(entity); // Paper - moved down below valid=true
// CraftBukkit start - SPIGOT-5278
if (entity instanceof Drowned) {
this.navigations.add(((Drowned) entity).waterNavigation);
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
this.navigations.add(((Mob) entity).getNavigation());
}
entity.valid = true; // CraftBukkit
+ this.getChunkSource().addEntity(entity); // Paper - from above to be below valid=true
// Paper start - Set origin location when the entity is being added to the world
if (entity.origin == null) {
entity.origin = entity.getBukkitEntity().getLocation();
+ ServerLevel.this.getChunkSource().addEntity(entity);
}
public void onTrackingEnd(Entity entity) {

View file

@ -8,12 +8,12 @@ diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListener
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
private void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<ClientboundPlayerPositionPacket.RelativeArgument> set) {
+ if (player.removed) {
+ LOGGER.info("Attempt to teleport dead player {} restricted", player.getScoreboardName());
private void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<ClientboundPlayerPositionPacket.RelativeArgument> set, boolean flag) {
+ if (player.isRemoved()) {
+ LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
+ return;
+ }
// CraftBukkit start

View file

@ -11,7 +11,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/j
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
int j = entity.getType().clientTrackingRange() * 16;