MOAR PATCHES
This commit is contained in:
parent
27a8d6da9a
commit
f55b6e04b1
34 changed files with 623 additions and 967 deletions
|
@ -1,75 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Sat, 21 Dec 2019 15:22:09 -0500
|
||||
Subject: [PATCH] Tracking Range Improvements
|
||||
|
||||
Sets tracking range of watermobs to animals instead of misc and simplifies code
|
||||
|
||||
Also ignores Enderdragon, defaulting it to Mojang's setting
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 190ddd4d9ef3472c33d46c2ead72fa0dc918054a..6da406c8403797a1cd9276ac06577c3c080a8a22 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1795,6 +1795,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity = (Entity) iterator.next();
|
||||
int j = entity.getType().clientTrackingRange() * 16;
|
||||
+ j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper
|
||||
|
||||
if (j > i) {
|
||||
i = j;
|
||||
diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
|
||||
index 8e3e36a8739a7dea1feb3785e96b7b9f19720446..b03fa9024c7f0238e1379f6ae4486db5300a70e9 100644
|
||||
--- a/src/main/java/org/spigotmc/TrackingRange.java
|
||||
+++ b/src/main/java/org/spigotmc/TrackingRange.java
|
||||
@@ -6,7 +6,6 @@ import net.minecraft.world.entity.ExperienceOrb;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.entity.decoration.Painting;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
-import net.minecraft.world.entity.monster.Ghast;
|
||||
|
||||
public class TrackingRange
|
||||
{
|
||||
@@ -25,26 +24,26 @@ public class TrackingRange
|
||||
if ( entity instanceof ServerPlayer )
|
||||
{
|
||||
return config.playerTrackingRange;
|
||||
- } else if ( entity.activationType == ActivationRange.ActivationType.MONSTER || entity.activationType == ActivationRange.ActivationType.RAIDER )
|
||||
- {
|
||||
- return config.monsterTrackingRange;
|
||||
- } else if ( entity instanceof Ghast )
|
||||
- {
|
||||
- if ( config.monsterTrackingRange > config.monsterActivationRange )
|
||||
- {
|
||||
+ // Paper start - Simplify and set water mobs to animal tracking range
|
||||
+ }
|
||||
+ switch (entity.activationType) {
|
||||
+ case RAIDER:
|
||||
+ case MONSTER:
|
||||
+ case FLYING_MONSTER:
|
||||
return config.monsterTrackingRange;
|
||||
- } else
|
||||
- {
|
||||
- return config.monsterActivationRange;
|
||||
- }
|
||||
- } else if ( entity.activationType == ActivationRange.ActivationType.ANIMAL )
|
||||
- {
|
||||
- return config.animalTrackingRange;
|
||||
- } else if ( entity instanceof ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb )
|
||||
+ case WATER:
|
||||
+ case VILLAGER:
|
||||
+ case ANIMAL:
|
||||
+ return config.animalTrackingRange;
|
||||
+ case MISC:
|
||||
+ }
|
||||
+ if ( entity instanceof ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb )
|
||||
+ // Paper end
|
||||
{
|
||||
return config.miscTrackingRange;
|
||||
} else
|
||||
{
|
||||
+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return ((net.minecraft.server.level.ServerLevel)(entity.getCommandSenderWorld())).getChunkSource().chunkMap.getLoadViewDistance(); // Paper - enderdragon is exempt
|
||||
return config.otherTrackingRange;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: AJMFactsheets <AJMFactsheets@gmail.com>
|
||||
Date: Wed, 22 Jan 2020 19:52:28 -0600
|
||||
Subject: [PATCH] Fix items vanishing through end portal
|
||||
|
||||
If the Paper configuration option "keep-spawn-loaded" is set to false,
|
||||
items entering the overworld from the end will spawn at Y = 0.
|
||||
|
||||
This is due to logic in the getHighestBlockYAt method in World.java
|
||||
only searching the heightmap if the chunk is loaded.
|
||||
|
||||
Quickly loading the exact world spawn chunk before searching the
|
||||
heightmap resolves the issue without having to load all spawn chunks.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index c6881a9a5da2caed77dea30e4906d2dd99a624c1..efc9cb6def2f4ee327329dc090d2918ff60d8e19 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2734,6 +2734,9 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||
BlockPos blockposition1;
|
||||
|
||||
if (flag1) {
|
||||
+ // Paper start - Ensure spawn chunk is always loaded before calculating Y coordinate
|
||||
+ this.level.getChunkAt(this.level.getSpawn());
|
||||
+ // Paper end
|
||||
blockposition1 = ServerLevel.END_SPAWN_POINT;
|
||||
} else {
|
||||
blockposition1 = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, destination.getSpawn());
|
|
@ -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 2c9e3dd1b9dd7bb8825a2eb9fecc2b2be348d055..868e9cdeb3c7effb398cef6f6f9c1e4fffa2db8c 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
|
||||
@@ -16,7 +16,7 @@ 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 ab65f0327766463a5e53fdd723e243464319fdbe..f4984d601d14c684e75f887f5f5d2f5a29326b15 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
|
||||
@@ -16,7 +16,7 @@ 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 edd6d63f715acef1a77eba0cf46ff8267228f4c6..9b68809b91910d2bbb82cafe23d1de5dfff4221c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -111,7 +111,17 @@ 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);
|
|
@ -1,66 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 25 Jan 2020 17:04:35 -0800
|
||||
Subject: [PATCH] Optimise getChunkAt calls for loaded chunks
|
||||
|
||||
bypass the need to get a player chunk, then get the either,
|
||||
then unwrap it...
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index eac5e799c4d26e53286a27c54b56899ba0b9ffb2..3aeb8426b0461ec572c1499116be80f968bb4104 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -470,6 +470,12 @@ public class ServerChunkCache extends ChunkSource {
|
||||
return this.getChunk(x, z, leastStatus, create);
|
||||
}, this.mainThreadProcessor).join();
|
||||
} else {
|
||||
+ // Paper start - optimise for loaded chunks
|
||||
+ LevelChunk ifLoaded = this.getChunkAtIfLoadedMainThread(x, z);
|
||||
+ if (ifLoaded != null) {
|
||||
+ return ifLoaded;
|
||||
+ }
|
||||
+ // Paper end
|
||||
ProfilerFiller gameprofilerfiller = this.level.getProfiler();
|
||||
|
||||
gameprofilerfiller.incrementCounter("getChunk");
|
||||
@@ -520,39 +526,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
if (Thread.currentThread() != this.mainThread) {
|
||||
return null;
|
||||
} else {
|
||||
- this.level.getProfiler().incrementCounter("getChunkNow");
|
||||
- long k = ChunkPos.asLong(chunkX, chunkZ);
|
||||
-
|
||||
- for (int l = 0; l < 4; ++l) {
|
||||
- if (k == this.lastChunkPos[l] && this.lastChunkStatus[l] == ChunkStatus.FULL) {
|
||||
- ChunkAccess ichunkaccess = this.lastChunk[l];
|
||||
-
|
||||
- return ichunkaccess instanceof LevelChunk ? (LevelChunk) ichunkaccess : null;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k);
|
||||
-
|
||||
- if (playerchunk == null) {
|
||||
- return null;
|
||||
- } else {
|
||||
- Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = (Either) playerchunk.getFutureIfPresent(ChunkStatus.FULL).getNow(null); // CraftBukkit - decompile error
|
||||
-
|
||||
- if (either == null) {
|
||||
- return null;
|
||||
- } else {
|
||||
- ChunkAccess ichunkaccess1 = (ChunkAccess) either.left().orElse(null); // CraftBukkit - decompile error
|
||||
-
|
||||
- if (ichunkaccess1 != null) {
|
||||
- this.storeInCache(k, ichunkaccess1, ChunkStatus.FULL);
|
||||
- if (ichunkaccess1 instanceof LevelChunk) {
|
||||
- return (LevelChunk) ichunkaccess1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return null;
|
||||
- }
|
||||
- }
|
||||
+ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - optimise for loaded chunks
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach@zachbr.io>
|
||||
Date: Sat, 8 Feb 2020 18:02:24 -0600
|
||||
Subject: [PATCH] Allow overriding the java version check
|
||||
|
||||
-DPaper.IgnoreJavaVersion=true
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 808a7688ed81bdfef623ee0a151ff8f94df2a3d7..c519ceca6f7788ca7c5d74ad1001dbc09f62681c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -181,7 +181,7 @@ 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;
|
||||
+ if (!Boolean.getBoolean("Paper.IgnoreJavaVersion")) return; // Paper
|
||||
}
|
||||
|
||||
try {
|
|
@ -1,29 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sun, 9 Feb 2020 00:19:05 -0600
|
||||
Subject: [PATCH] Add ThrownEggHatchEvent
|
||||
|
||||
Adds a new event similar to PlayerEggThrowEvent, but without the Player requirement
|
||||
(dispensers can throw eggs to hatch them, too).
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
index f3808a5e9155e1bf6c6219fc494864bb7dc61117..520eace73b569c2c77e76e0dfd18eb9c7188ec30 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
@@ -63,6 +63,16 @@ public class ThrownEgg extends ThrowableItemProjectile {
|
||||
hatchingType = event.getHatchingType();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, b0, hatchingType);
|
||||
+ event.callEvent();
|
||||
+
|
||||
+ b0 = event.getNumHatches();
|
||||
+ 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());
|
|
@ -1,407 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 27 Jan 2020 21:28:00 -0800
|
||||
Subject: [PATCH] Optimise random block ticking
|
||||
|
||||
Massive performance improvement for random block ticking.
|
||||
The performance increase comes from the fact that the vast
|
||||
majority of attempted block ticks (~95% in my testing) fail
|
||||
because the randomly selected block is not tickable.
|
||||
|
||||
Now only tickable blocks are targeted, however this means that
|
||||
the maximum number of block ticks occurs per chunk. However,
|
||||
not all chunks are going to be targeted. The percent chance
|
||||
of a chunk being targeted is based on how many tickable blocks
|
||||
are in the chunk.
|
||||
This means that while block ticks are spread out less, the
|
||||
total number of blocks ticked per world tick remains the same.
|
||||
Therefore, the chance of a random tickable block being ticked
|
||||
remains the same.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/util/math/ThreadUnsafeRandom.java b/src/main/java/com/destroystokyo/paper/util/math/ThreadUnsafeRandom.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3edc8e52e06a62ce9f8cc734fd7458b37cfaad91
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/util/math/ThreadUnsafeRandom.java
|
||||
@@ -0,0 +1,46 @@
|
||||
+package com.destroystokyo.paper.util.math;
|
||||
+
|
||||
+import java.util.Random;
|
||||
+
|
||||
+public final class ThreadUnsafeRandom extends Random {
|
||||
+
|
||||
+ // See javadoc and internal comments for java.util.Random where these values come from, how they are used, and the author for them.
|
||||
+ private static final long multiplier = 0x5DEECE66DL;
|
||||
+ private static final long addend = 0xBL;
|
||||
+ private static final long mask = (1L << 48) - 1;
|
||||
+
|
||||
+ private static long initialScramble(long seed) {
|
||||
+ return (seed ^ multiplier) & mask;
|
||||
+ }
|
||||
+
|
||||
+ private long seed;
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSeed(long seed) {
|
||||
+ // note: called by Random constructor
|
||||
+ this.seed = initialScramble(seed);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected int next(int bits) {
|
||||
+ // avoid the expensive CAS logic used by superclass
|
||||
+ return (int) (((this.seed = this.seed * multiplier + addend) & mask) >>> (48 - bits));
|
||||
+ }
|
||||
+
|
||||
+ // Taken from
|
||||
+ // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
+ // https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2016/06/25/fastrange.c
|
||||
+ // Original license is public domain
|
||||
+ public static int fastRandomBounded(final long randomInteger, final long limit) {
|
||||
+ // randomInteger must be [0, pow(2, 32))
|
||||
+ // limit must be [0, pow(2, 32))
|
||||
+ return (int)((randomInteger * limit) >>> 32);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int nextInt(int bound) {
|
||||
+ // yes this breaks random's spec
|
||||
+ // however there's nothing that uses this class that relies on it
|
||||
+ 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 b13e5d05d862ea8c6031b8071f525f00bc48f7e7..3db77d9eda98eacb099135643aff5e94751f4c7c 100644
|
||||
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
@@ -468,6 +468,7 @@ 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 bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027ea23b400b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -669,7 +669,12 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
});
|
||||
}
|
||||
|
||||
- public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
||||
+ // Paper start - optimise random block ticking
|
||||
+ private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos();
|
||||
+ private final com.destroystokyo.paper.util.math.ThreadUnsafeRandom randomTickRandom = new com.destroystokyo.paper.util.math.ThreadUnsafeRandom();
|
||||
+ // Paper end
|
||||
+
|
||||
+ public void tickChunk(LevelChunk chunk, int randomTickSpeed) { final int randomTickSpeed1 = randomTickSpeed; // Paper
|
||||
ChunkPos chunkcoordintpair = chunk.getPos();
|
||||
boolean flag = this.isRaining();
|
||||
int j = chunkcoordintpair.getMinBlockX();
|
||||
@@ -677,10 +682,10 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
ProfilerFiller gameprofilerfiller = this.getProfiler();
|
||||
|
||||
gameprofilerfiller.push("thunder");
|
||||
- BlockPos blockposition;
|
||||
+ 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
|
||||
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
|
||||
@@ -703,59 +708,77 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
}
|
||||
|
||||
gameprofilerfiller.popPush("iceandsnow");
|
||||
- if (!this.paperConfig.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow
|
||||
- blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15));
|
||||
- BlockPos blockposition1 = blockposition.below();
|
||||
+ if (!this.paperConfig.disableIceAndSnow && this.randomTickRandom.nextInt(16) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking
|
||||
+ // Paper start - optimise chunk ticking
|
||||
+ this.getRandomBlockPosition(j, 0, k, 15, blockposition);
|
||||
+ int normalY = chunk.getHighestBlockY(Heightmap.Types.MOTION_BLOCKING, blockposition.getX() & 15, blockposition.getZ() & 15);
|
||||
+ int downY = normalY - 1;
|
||||
+ blockposition.setY(normalY);
|
||||
+ // Paper end
|
||||
Biome biomebase = this.getBiome(blockposition);
|
||||
|
||||
- if (biomebase.shouldFreeze(this, blockposition1)) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
|
||||
+ // Paper start - optimise chunk ticking
|
||||
+ blockposition.setY(downY);
|
||||
+ if (biomebase.shouldFreeze(this, blockposition)) {
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
|
||||
+ // 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 && 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
|
||||
}
|
||||
}
|
||||
|
||||
- gameprofilerfiller.popPush("tickBlocks");
|
||||
- timings.chunkTicksBlocks.startTiming(); // Paper
|
||||
+ // Paper start - optimise random block ticking
|
||||
+ gameprofilerfiller.pop();
|
||||
if (randomTickSpeed > 0) {
|
||||
- LevelChunkSection[] achunksection = chunk.getSections();
|
||||
- int l = achunksection.length;
|
||||
+ 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();
|
||||
+ 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);
|
||||
+ for (int a = 0; a < randomTickSpeed1; ++a) {
|
||||
+ int tickingBlocks = section.tickingList.size();
|
||||
+ int index = this.randomTickRandom.nextInt(16 * 16 * 16);
|
||||
+ if (index >= tickingBlocks) {
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
- if (iblockdata.isRandomlyTicking()) {
|
||||
- iblockdata.randomTick(this, blockposition2, this.random);
|
||||
- }
|
||||
+ long raw = section.tickingList.getRaw(index);
|
||||
+ int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw);
|
||||
+ int randomX = location & 15;
|
||||
+ int randomY = ((location >>> (4 + 4)) & 255) | yPos;
|
||||
+ int randomZ = (location >>> 4) & 15;
|
||||
|
||||
- FluidState fluid = iblockdata.getFluidState();
|
||||
+ BlockPos blockposition2 = blockposition.setValues(j + randomX, randomY, k + randomZ);
|
||||
+ BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw);
|
||||
|
||||
- if (fluid.isRandomlyTicking()) {
|
||||
- fluid.randomTick(this, blockposition2, this.random);
|
||||
- }
|
||||
+ iblockdata.randomTick(this, blockposition2, this.randomTickRandom);
|
||||
|
||||
- gameprofilerfiller.pop();
|
||||
- }
|
||||
+ // We drop the fluid tick since LAVA is ALREADY TICKED by the above method.
|
||||
+ // TODO CHECK ON UPDATE
|
||||
}
|
||||
}
|
||||
+ gameprofilerfiller.pop();
|
||||
+ timings.chunkTicksBlocks.stopTiming(); // Paper
|
||||
+ // Paper end
|
||||
}
|
||||
- timings.chunkTicksBlocks.stopTiming(); // Paper
|
||||
- gameprofilerfiller.pop();
|
||||
}
|
||||
|
||||
protected BlockPos findLightingTargetAround(BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java
|
||||
index dd84984f28484cf7129c294222696784e128221a..9ea72751354e893cd3820befaa5df3e5e503de6e 100644
|
||||
--- a/src/main/java/net/minecraft/util/BitStorage.java
|
||||
+++ b/src/main/java/net/minecraft/util/BitStorage.java
|
||||
@@ -112,4 +112,32 @@ public class BitStorage {
|
||||
}
|
||||
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public final void forEach(DataBitConsumer consumer) {
|
||||
+ int i = 0;
|
||||
+ long[] along = this.data;
|
||||
+ int j = along.length;
|
||||
+
|
||||
+ for (int k = 0; k < j; ++k) {
|
||||
+ long l = along[k];
|
||||
+
|
||||
+ for (int i1 = 0; i1 < this.valuesPerLong; ++i1) {
|
||||
+ consumer.accept(i, (int) (l & this.mask));
|
||||
+ l >>= this.bits;
|
||||
+ ++i;
|
||||
+ if (i >= this.size) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @FunctionalInterface
|
||||
+ public static interface DataBitConsumer {
|
||||
+
|
||||
+ void accept(int location, int data);
|
||||
+
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
index 42b636c4ebb6eb83c8a9f3f5f9a766d37d065dc3..0e15ca2fb9cd1aeb4a075b8d50350dd7fd463c72 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
@@ -91,7 +91,7 @@ public class Turtle extends Animal {
|
||||
}
|
||||
|
||||
public void setHomePos(BlockPos pos) {
|
||||
- this.entityData.set(Turtle.HOME_POS, pos);
|
||||
+ this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos...
|
||||
}
|
||||
|
||||
public BlockPos getHomePos() { // Paper - public
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 1d536d77518a70bdc1a23924aea99df1042b3cd5..632f32405053fbcff2fd26fa99f98c6add9f9dc7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -1472,10 +1472,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public abstract TagContainer getTagManager();
|
||||
|
||||
public BlockPos getBlockRandomPos(int x, int y, int z, int l) {
|
||||
+ // Paper start - allow use of mutable pos
|
||||
+ BlockPos.MutableBlockPos ret = new BlockPos.MutableBlockPos();
|
||||
+ this.getRandomBlockPosition(x, y, z, l, ret);
|
||||
+ return ret.immutable();
|
||||
+ }
|
||||
+ public final BlockPos.MutableBlockPos getRandomBlockPosition(int i, int j, int k, int l, BlockPos.MutableBlockPos out) {
|
||||
+ // Paper end
|
||||
this.randValue = this.randValue * 3 + 1013904223;
|
||||
int i1 = this.randValue >> 2;
|
||||
|
||||
- return new BlockPos(x + (i1 & 15), y + (i1 >> 16 & l), z + (i1 >> 8 & 15));
|
||||
+ out.setValues(i + (i1 & 15), j + (i1 >> 16 & l), k + (i1 >> 8 & 15)); // Paper - change to setValues call
|
||||
+ return out; // Paper
|
||||
}
|
||||
|
||||
public boolean noSave() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 4fef3abe4b416cbebe1b456468b5c3e162de18f1..87d7a87a2925f2c062658e960bb5128738828d9f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -639,8 +639,8 @@ public class LevelChunk implements ChunkAccess {
|
||||
this.entities.remove(entity); // Paper
|
||||
}
|
||||
|
||||
- @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
|
||||
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 38c7c5f18fc84d4a1de2da1ddc6d3ac37c25f341..c44d32f966c61497b4a8892eb51da3a71ad031d9 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -14,12 +14,14 @@ import net.minecraft.world.level.material.FluidState;
|
||||
public class LevelChunkSection {
|
||||
|
||||
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
|
||||
short nonEmptyBlockCount; // Paper - package-private
|
||||
- private short tickingBlockCount;
|
||||
+ 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) {
|
||||
@@ -74,6 +76,9 @@ public class LevelChunkSection {
|
||||
--this.nonEmptyBlockCount;
|
||||
if (iblockdata1.isRandomlyTicking()) {
|
||||
--this.tickingBlockCount;
|
||||
+ // Paper start
|
||||
+ this.tickingList.remove(x, y, z);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +90,9 @@ public class LevelChunkSection {
|
||||
++this.nonEmptyBlockCount;
|
||||
if (state.isRandomlyTicking()) {
|
||||
++this.tickingBlockCount;
|
||||
+ // Paper start
|
||||
+ this.tickingList.add(x, y, z, state);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,23 +128,29 @@ public class LevelChunkSection {
|
||||
}
|
||||
|
||||
public void recalcBlockCounts() {
|
||||
+ // Paper start
|
||||
+ this.tickingList.clear();
|
||||
+ // Paper end
|
||||
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);
|
||||
+ // Paper start
|
||||
+ this.tickingList.add(location, iblockdata);
|
||||
+ // 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);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
index dd252372e1e380674b1191e9ea265cbb10de437b..f93316b3ae5cd5fb960fa24f8c921b5b9276d9f3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
@@ -285,6 +285,14 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public void forEachLocation(PalettedContainer.CountConsumer<T> datapaletteblock_a) {
|
||||
+ this.getDataBits().forEach((int location, int data) -> {
|
||||
+ datapaletteblock_a.accept(this.getDataPalette().getObject(data), location);
|
||||
+ });
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@FunctionalInterface
|
||||
public interface CountConsumer<T> {
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 8 Feb 2020 23:26:11 -0600
|
||||
Subject: [PATCH] Entity Jump API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index b84dab1043c56e2deb58aec8639226f98db165d1..43fbe7d220f61802ae0cb0620ad078c5df7b69bc 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2873,8 +2873,10 @@ public abstract class LivingEntity extends Entity {
|
||||
} else if (this.isInLava() && (!this.onGround || d7 > d8)) {
|
||||
this.jumpInLiquid((Tag) FluidTags.LAVA);
|
||||
} else if ((this.onGround || flag && d7 <= d8) && this.noJumpDelay == 0) {
|
||||
+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper
|
||||
this.jumpFromGround();
|
||||
this.noJumpDelay = 10;
|
||||
+ } else { this.setJumping(false); } // Paper - setJumping(false) stops a potential loop
|
||||
}
|
||||
} else {
|
||||
this.noJumpDelay = 0;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
index 1621d8748e96c6e1abb33b699a1273bb698f67d2..423bdbe25b6f2261cb5092378b0564a82faeecb4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
@@ -489,7 +489,9 @@ public class Panda extends Animal {
|
||||
Panda entitypanda = (Panda) iterator.next();
|
||||
|
||||
if (!entitypanda.isBaby() && entitypanda.onGround && !entitypanda.isInWater() && entitypanda.canPerformAction()) {
|
||||
+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper
|
||||
entitypanda.jumpFromGround();
|
||||
+ } else { this.setJumping(false); } // Paper - setJumping(false) stops a potential loop
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index a01bd035846df0e2e28dc55e2ef2f5f35b83f905..5dac3bf5a117bfbf57798238f0614558deafcd1b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -792,5 +792,19 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
public org.bukkit.inventory.EquipmentSlot getHandRaised() {
|
||||
return getHandle().getUsedItemHand() == net.minecraft.world.InteractionHand.MAIN_HAND ? org.bukkit.inventory.EquipmentSlot.HAND : org.bukkit.inventory.EquipmentSlot.OFF_HAND;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isJumping() {
|
||||
+ return getHandle().jumping;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setJumping(boolean jumping) {
|
||||
+ getHandle().setJumping(jumping);
|
||||
+ if (jumping && getHandle() instanceof Mob) {
|
||||
+ // this is needed to actually make a mob jump
|
||||
+ ((Mob) getHandle()).getJumpControl().jump();
|
||||
+ }
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 7 Feb 2020 14:36:56 -0600
|
||||
Subject: [PATCH] Add option to nerf pigmen from nether portals
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 7fbd501d70dccf869a4454e2789a5d68f2e15754..9e4591ddc4b755f4ff5a6f1078b51cb13db80480 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -594,4 +594,9 @@ 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);
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index efc9cb6def2f4ee327329dc090d2918ff60d8e19..43f77d01fceab107d3502d282205aa579d64cc4b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -277,6 +277,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||
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
|
||||
+ public boolean fromNetherPortal; // Paper
|
||||
protected int numCollisions = 0; // Paper
|
||||
public void inactiveTick() { }
|
||||
// Spigot end
|
||||
@@ -1693,6 +1694,9 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||
if (spawnedViaMobSpawner) {
|
||||
tag.putBoolean("Paper.FromMobSpawner", true);
|
||||
}
|
||||
+ if (fromNetherPortal) {
|
||||
+ tag.putBoolean("Paper.FromNetherPortal", true);
|
||||
+ }
|
||||
// Paper end
|
||||
return tag;
|
||||
} catch (Throwable throwable) {
|
||||
@@ -1827,6 +1831,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||
}
|
||||
|
||||
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");
|
||||
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 805d83a93bce20910d17c3f419bc085251b6cfc1..ae58929886921d0714bf811de92f99dc0dc120dc 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
@@ -8,6 +8,7 @@ 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;
|
||||
@@ -61,6 +62,8 @@ public class NetherPortalBlock extends Block {
|
||||
|
||||
if (entity != null) {
|
||||
entity.setPortalCooldown();
|
||||
+ entity.fromNetherPortal = true; // Paper
|
||||
+ if (world.paperConfig.nerfNetherPortalPigmen) ((Mob) entity).aware = false; // Paper
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,439 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 2 Feb 2020 04:00:40 -0600
|
||||
Subject: [PATCH] Make the GUI graph fancier
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphColor.java b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a4e641fdcccd3efcd1a2865dc6dc28d50671b995
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java
|
||||
@@ -0,0 +1,44 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import java.awt.Color;
|
||||
+
|
||||
+public class GraphColor {
|
||||
+ private static final Color[] colorLine = new Color[101];
|
||||
+ private static final Color[] colorFill = new Color[101];
|
||||
+
|
||||
+ static {
|
||||
+ for (int i = 0; i < 101; i++) {
|
||||
+ Color color = createColor(i);
|
||||
+ colorLine[i] = new Color(color.getRed() / 2, color.getGreen() / 2, color.getBlue() / 2, 255);
|
||||
+ colorFill[i] = new Color(colorLine[i].getRed(), colorLine[i].getGreen(), colorLine[i].getBlue(), 125);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static Color getLineColor(int percent) {
|
||||
+ return colorLine[percent];
|
||||
+ }
|
||||
+
|
||||
+ public static Color getFillColor(int percent) {
|
||||
+ return colorFill[percent];
|
||||
+ }
|
||||
+
|
||||
+ private static Color createColor(int percent) {
|
||||
+ if (percent <= 50) {
|
||||
+ return new Color(0X00FF00);
|
||||
+ }
|
||||
+
|
||||
+ int value = 510 - (int) (Math.min(Math.max(0, ((percent - 50) / 50F)), 1) * 510);
|
||||
+
|
||||
+ int red, green;
|
||||
+ if (value < 255) {
|
||||
+ red = 255;
|
||||
+ green = (int) (Math.sqrt(value) * 16);
|
||||
+ } else {
|
||||
+ green = 255;
|
||||
+ value = value - 255;
|
||||
+ red = 255 - (value * value / 255);
|
||||
+ }
|
||||
+
|
||||
+ return new Color(red, green, 0);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphData.java b/src/main/java/com/destroystokyo/paper/gui/GraphData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..186fc722965e403f76b1480e1c2381fc34e29049
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/GraphData.java
|
||||
@@ -0,0 +1,47 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import java.awt.Color;
|
||||
+
|
||||
+public class GraphData {
|
||||
+ private long total;
|
||||
+ private long free;
|
||||
+ private long max;
|
||||
+ private long usedMem;
|
||||
+ private int usedPercent;
|
||||
+
|
||||
+ public GraphData(long total, long free, long max) {
|
||||
+ this.total = total;
|
||||
+ this.free = free;
|
||||
+ this.max = max;
|
||||
+ this.usedMem = total - free;
|
||||
+ this.usedPercent = usedMem == 0 ? 0 : (int) (usedMem * 100L / max);
|
||||
+ }
|
||||
+
|
||||
+ public long getTotal() {
|
||||
+ return total;
|
||||
+ }
|
||||
+
|
||||
+ public long getFree() {
|
||||
+ return free;
|
||||
+ }
|
||||
+
|
||||
+ public long getMax() {
|
||||
+ return max;
|
||||
+ }
|
||||
+
|
||||
+ public long getUsedMem() {
|
||||
+ return usedMem;
|
||||
+ }
|
||||
+
|
||||
+ public int getUsedPercent() {
|
||||
+ return usedPercent;
|
||||
+ }
|
||||
+
|
||||
+ public Color getFillColor() {
|
||||
+ return GraphColor.getFillColor(usedPercent);
|
||||
+ }
|
||||
+
|
||||
+ public Color getLineColor() {
|
||||
+ return GraphColor.getLineColor(usedPercent);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0f29ad583e798c09b2fe3f568ed50cbc719e40e2
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java
|
||||
@@ -0,0 +1,41 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+
|
||||
+import javax.swing.JPanel;
|
||||
+import javax.swing.Timer;
|
||||
+import java.awt.BorderLayout;
|
||||
+import java.awt.Dimension;
|
||||
+
|
||||
+public class GuiStatsComponent extends JPanel {
|
||||
+ private final Timer timer;
|
||||
+ private final RAMGraph ramGraph;
|
||||
+
|
||||
+ public GuiStatsComponent(MinecraftServer server) {
|
||||
+ super(new BorderLayout());
|
||||
+
|
||||
+ setOpaque(false);
|
||||
+
|
||||
+ ramGraph = new RAMGraph();
|
||||
+ RAMDetails ramDetails = new RAMDetails(server);
|
||||
+
|
||||
+ add(ramGraph, "North");
|
||||
+ add(ramDetails, "Center");
|
||||
+
|
||||
+ timer = new Timer(500, (event) -> {
|
||||
+ ramGraph.update();
|
||||
+ ramDetails.update();
|
||||
+ });
|
||||
+ timer.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Dimension getPreferredSize() {
|
||||
+ return new Dimension(350, 200);
|
||||
+ }
|
||||
+
|
||||
+ public void stop() { a(); } public void a() {
|
||||
+ timer.stop();
|
||||
+ ramGraph.stop();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c0923ec75ecced2e0a1c0d3ec2c046d69af3e9a9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
|
||||
@@ -0,0 +1,73 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import net.minecraft.Util;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+
|
||||
+import javax.swing.DefaultListCellRenderer;
|
||||
+import javax.swing.DefaultListSelectionModel;
|
||||
+import javax.swing.JList;
|
||||
+import javax.swing.border.EmptyBorder;
|
||||
+import java.awt.Dimension;
|
||||
+import java.text.DecimalFormat;
|
||||
+import java.text.DecimalFormatSymbols;
|
||||
+import java.util.Locale;
|
||||
+import java.util.Vector;
|
||||
+
|
||||
+public class RAMDetails extends JList<String> {
|
||||
+ public static final DecimalFormat DECIMAL_FORMAT = Util.peek(new DecimalFormat("########0.000"), (format)
|
||||
+ -> format.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)));
|
||||
+
|
||||
+ private final MinecraftServer server;
|
||||
+
|
||||
+ public RAMDetails(MinecraftServer server) {
|
||||
+ this.server = server;
|
||||
+
|
||||
+ setBorder(new EmptyBorder(0, 10, 0, 0));
|
||||
+ setFixedCellHeight(20);
|
||||
+ setOpaque(false);
|
||||
+
|
||||
+ DefaultListCellRenderer renderer = new DefaultListCellRenderer();
|
||||
+ renderer.setOpaque(false);
|
||||
+ setCellRenderer(renderer);
|
||||
+
|
||||
+ setSelectionModel(new DefaultListSelectionModel() {
|
||||
+ @Override
|
||||
+ public void setAnchorSelectionIndex(final int anchorIndex) {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setLeadAnchorNotificationEnabled(final boolean flag) {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setLeadSelectionIndex(final int leadIndex) {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSelectionInterval(final int index0, final int index1) {
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Dimension getPreferredSize() {
|
||||
+ return new Dimension(350, 100);
|
||||
+ }
|
||||
+
|
||||
+ public void update() {
|
||||
+ GraphData data = RAMGraph.DATA.peekLast();
|
||||
+ 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");
|
||||
+ setListData(vector);
|
||||
+ }
|
||||
+
|
||||
+ public double getAverage(long[] tickTimes) {
|
||||
+ long total = 0L;
|
||||
+ for (long value : tickTimes) {
|
||||
+ total += value;
|
||||
+ }
|
||||
+ return ((double) total / (double) tickTimes.length) * 1.0E-6D;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c3e54da4ab6440811aab2f9dd1e218802ac13285
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java
|
||||
@@ -0,0 +1,144 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import javax.swing.JComponent;
|
||||
+import javax.swing.SwingUtilities;
|
||||
+import javax.swing.Timer;
|
||||
+import javax.swing.ToolTipManager;
|
||||
+import java.awt.Color;
|
||||
+import java.awt.Dimension;
|
||||
+import java.awt.Graphics;
|
||||
+import java.awt.MouseInfo;
|
||||
+import java.awt.Point;
|
||||
+import java.awt.PointerInfo;
|
||||
+import java.awt.event.MouseAdapter;
|
||||
+import java.awt.event.MouseEvent;
|
||||
+import java.text.SimpleDateFormat;
|
||||
+import java.util.Date;
|
||||
+import java.util.LinkedList;
|
||||
+import java.util.concurrent.TimeUnit;
|
||||
+
|
||||
+public class RAMGraph extends JComponent {
|
||||
+ public static final LinkedList<GraphData> DATA = new LinkedList<GraphData>() {
|
||||
+ @Override
|
||||
+ public boolean add(GraphData data) {
|
||||
+ if (size() >= 348) {
|
||||
+ remove();
|
||||
+ }
|
||||
+ return super.add(data);
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ static {
|
||||
+ GraphData empty = new GraphData(0, 0, 0);
|
||||
+ for (int i = 0; i < 350; i++) {
|
||||
+ DATA.add(empty);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private final Timer timer;
|
||||
+ private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
|
||||
+
|
||||
+ private int currentTick;
|
||||
+
|
||||
+ public RAMGraph() {
|
||||
+ ToolTipManager.sharedInstance().setInitialDelay(0);
|
||||
+
|
||||
+ addMouseListener(new MouseAdapter() {
|
||||
+ final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay();
|
||||
+ final int dismissDelayMinutes = (int) TimeUnit.MINUTES.toMillis(10);
|
||||
+
|
||||
+ @Override
|
||||
+ public void mouseEntered(MouseEvent me) {
|
||||
+ ToolTipManager.sharedInstance().setDismissDelay(dismissDelayMinutes);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void mouseExited(MouseEvent me) {
|
||||
+ ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout);
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ timer = new Timer(50, (event) -> repaint());
|
||||
+ timer.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Dimension getPreferredSize() {
|
||||
+ return new Dimension(350, 110);
|
||||
+ }
|
||||
+
|
||||
+ public void update() {
|
||||
+ Runtime jvm = Runtime.getRuntime();
|
||||
+ DATA.add(new GraphData(jvm.totalMemory(), jvm.freeMemory(), jvm.maxMemory()));
|
||||
+
|
||||
+ PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||
+ if (pointerInfo != null) {
|
||||
+ Point point = pointerInfo.getLocation();
|
||||
+ if (point != null) {
|
||||
+ Point loc = new Point(point);
|
||||
+ SwingUtilities.convertPointFromScreen(loc, this);
|
||||
+ if (this.contains(loc)) {
|
||||
+ ToolTipManager.sharedInstance().mouseMoved(
|
||||
+ new MouseEvent(this, -1, System.currentTimeMillis(), 0, loc.x, loc.y,
|
||||
+ point.x, point.y, 0, false, 0));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ currentTick++;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void paint(Graphics graphics) {
|
||||
+ graphics.setColor(new Color(0xFFFFFFFF));
|
||||
+ graphics.fillRect(0, 0, 350, 100);
|
||||
+
|
||||
+ graphics.setColor(new Color(0x888888));
|
||||
+ graphics.drawLine(1, 25, 348, 25);
|
||||
+ graphics.drawLine(1, 50, 348, 50);
|
||||
+ graphics.drawLine(1, 75, 348, 75);
|
||||
+
|
||||
+ int i = 0;
|
||||
+ for (GraphData data : DATA) {
|
||||
+ i++;
|
||||
+ if ((i + currentTick) % 120 == 0) {
|
||||
+ graphics.setColor(new Color(0x888888));
|
||||
+ graphics.drawLine(i, 1, i, 99);
|
||||
+ }
|
||||
+ int used = data.getUsedPercent();
|
||||
+ if (used > 0) {
|
||||
+ Color color = data.getLineColor();
|
||||
+ graphics.setColor(data.getFillColor());
|
||||
+ graphics.fillRect(i, 100 - used, 1, used);
|
||||
+ graphics.setColor(color);
|
||||
+ graphics.fillRect(i, 100 - used, 1, 1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ graphics.setColor(new Color(0xFF000000));
|
||||
+ graphics.drawRect(0, 0, 348, 100);
|
||||
+
|
||||
+ Point m = getMousePosition();
|
||||
+ if (m != null && m.x > 0 && m.x < 348 && m.y > 0 && m.y < 100) {
|
||||
+ GraphData data = DATA.get(m.x);
|
||||
+ int used = data.getUsedPercent();
|
||||
+ graphics.setColor(new Color(0x000000));
|
||||
+ graphics.drawLine(m.x, 1, m.x, 99);
|
||||
+ graphics.drawOval(m.x - 2, 100 - used - 2, 5, 5);
|
||||
+ graphics.setColor(data.getLineColor());
|
||||
+ graphics.fillOval(m.x - 2, 100 - used - 2, 5, 5);
|
||||
+ setToolTipText(String.format("<html><body>Used: %s mb (%s%%)<br/>%s</body></html>",
|
||||
+ Math.round(data.getUsedMem() / 1024F / 1024F),
|
||||
+ used, getTime(m.x)));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public String getTime(int halfSeconds) {
|
||||
+ int millis = (348 - halfSeconds) / 2 * 1000;
|
||||
+ return TIME_FORMAT.format(new Date((System.currentTimeMillis() - millis)));
|
||||
+ }
|
||||
+
|
||||
+ public void stop() {
|
||||
+ timer.stop();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index cec5ad5052c8cf6059e9b117117846bdb217748f..c2f747226f10479c826849af898538610a2dd659 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -259,6 +259,7 @@ 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 7038897b8fb4c18ca97b95a3b24c30b40b62b005..e33189dc8375a3034910087654607fb531061636 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -216,7 +216,7 @@ 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 2299349e701ffd5ee53cc5fe25f4d1e271cc3d65..2567c588a1dcf732800e6cf87352b020c7bb84d6 100644
|
||||
--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
@@ -91,9 +91,9 @@ public class MinecraftServerGui extends JComponent {
|
||||
|
||||
private JComponent buildInfoPanel() {
|
||||
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
|
||||
|
||||
- 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 30960738de03edf7aa8745a176b3a2be86eaf282..09414d04208a843f8d337569b53f61b34e64ed92 100644
|
||||
--- a/src/main/java/net/minecraft/server/gui/StatsComponent.java
|
||||
+++ b/src/main/java/net/minecraft/server/gui/StatsComponent.java
|
||||
@@ -13,7 +13,7 @@ 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];
|
|
@ -1,30 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Trigary <trigary0@gmail.com>
|
||||
Date: Sun, 1 Mar 2020 22:43:24 +0100
|
||||
Subject: [PATCH] add hand to BlockMultiPlaceEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index e696d2e52532df25d74a1f559e2c9ca0f3d5058d..7d9a3b65b2d6b294d3a11414289e64fac88665f0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -337,13 +337,18 @@ public class CraftEventFactory {
|
||||
}
|
||||
|
||||
org.bukkit.inventory.ItemStack item;
|
||||
+ //Paper start - add hand to BlockMultiPlaceEvent
|
||||
+ EquipmentSlot equipmentSlot;
|
||||
if (hand == InteractionHand.MAIN_HAND) {
|
||||
item = player.getInventory().getItemInMainHand();
|
||||
+ equipmentSlot = EquipmentSlot.HAND;
|
||||
} else {
|
||||
item = player.getInventory().getItemInOffHand();
|
||||
+ equipmentSlot = EquipmentSlot.OFF_HAND;
|
||||
}
|
||||
|
||||
- BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild);
|
||||
+ BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild, equipmentSlot);
|
||||
+ //Paper end
|
||||
craftServer.getPluginManager().callEvent(event);
|
||||
|
||||
return event;
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 3 Mar 2020 05:26:40 +0000
|
||||
Subject: [PATCH] Prevent teleporting dead entities
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 2b79413bb8a592a7b7093e11d3a0cce895286c8f..09a663cc53cdf8ae45352b280200c8170dbbcdfc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1468,6 +1468,10 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
|
||||
}
|
||||
|
||||
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());
|
||||
+ return;
|
||||
+ }
|
||||
// CraftBukkit start
|
||||
if (Float.isNaN(f)) {
|
||||
f = 0;
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sat, 7 Mar 2020 00:07:51 +0000
|
||||
Subject: [PATCH] Validate tripwire hook placement before update
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
index f44d4809fe87c832e4d3bda429af2254e8c746d6..20428aff54527b664d988a6a0f54236b693fda89 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
@@ -169,6 +169,7 @@ public class TripWireHookBlock extends Block {
|
||||
|
||||
this.playSound(world, pos, flag4, flag5, flag2, flag3);
|
||||
if (!beingRemoved) {
|
||||
+ if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - validate
|
||||
world.setBlock(pos, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection), 3);
|
||||
if (flag1) {
|
||||
this.notifyNeighbors(world, pos, enumdirection);
|
|
@ -1,35 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sat, 13 Apr 2019 16:50:58 -0500
|
||||
Subject: [PATCH] Add option to allow iron golems to spawn in air
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 9e4591ddc4b755f4ff5a6f1078b51cb13db80480..fe1c9dd8258ec8c3fdf343d4a44de2be2ae3d35f 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -387,6 +387,11 @@ public class PaperWorldConfig {
|
||||
scanForLegacyEnderDragon = getBoolean("game-mechanics.scan-for-legacy-ender-dragon", true);
|
||||
}
|
||||
|
||||
+ public boolean ironGolemsCanSpawnInAir = false;
|
||||
+ private void ironGolemsCanSpawnInAir() {
|
||||
+ ironGolemsCanSpawnInAir = getBoolean("iron-golems-can-spawn-in-air", ironGolemsCanSpawnInAir);
|
||||
+ }
|
||||
+
|
||||
public boolean armorStandEntityLookups = true;
|
||||
private void armorStandEntityLookups() {
|
||||
armorStandEntityLookups = getBoolean("armor-stands-do-collision-entity-lookups", true);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
index 9cedac83304847bdc92c2e97c4e6e119664c3bd0..59f0224b6a743408a03b642dd7cbe545f406c57e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
@@ -297,7 +297,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
|
||||
BlockPos blockposition1 = blockposition.below();
|
||||
BlockState iblockdata = world.getBlockState(blockposition1);
|
||||
|
||||
- if (!iblockdata.entityCanStandOn((BlockGetter) world, blockposition1, (Entity) this)) {
|
||||
+ if (!iblockdata.entityCanStandOn((BlockGetter) world, blockposition1, (Entity) this) && !level.paperConfig.ironGolemsCanSpawnInAir) { // Paper
|
||||
return false;
|
||||
} else {
|
||||
for (int i = 1; i < 3; ++i) {
|
|
@ -1,44 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zero <zero@cock.li>
|
||||
Date: Sat, 22 Feb 2020 16:10:31 -0500
|
||||
Subject: [PATCH] Configurable chance of villager zombie infection
|
||||
|
||||
This allows you to solve an issue in vanilla behavior where:
|
||||
* On easy difficulty your villagers will NEVER get infected, meaning they will always die.
|
||||
* On normal difficulty they will have a 50% of getting infected or dying.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index fe1c9dd8258ec8c3fdf343d4a44de2be2ae3d35f..525d702d78a609af987ebd2c32169b873e5c05ed 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -604,4 +604,9 @@ 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);
|
||||
+ }
|
||||
}
|
||||
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 6fecf4188fc0247143edc688c03e645376960687..1e7c2c603b967c8c606efd94ce95a17c856f78d7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -447,10 +447,14 @@ 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()) {
|
||||
return;
|
||||
}
|
||||
+ if (level.paperConfig.zombieVillagerInfectionChance != -1.0 && (this.random.nextDouble() * 100.0) > level.paperConfig.zombieVillagerInfectionChance) {
|
||||
+ return;
|
||||
+ } // Paper end
|
||||
|
||||
Villager entityvillager = (Villager) entityliving;
|
||||
// CraftBukkit start
|
|
@ -1,67 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 14 Jan 2020 14:59:08 -0800
|
||||
Subject: [PATCH] Optimise Chunk#getFluid
|
||||
|
||||
Removing the try catch and generally reducing ops should make it
|
||||
faster on its own, however removing the try catch makes it
|
||||
easier to inline due to code size
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 87d7a87a2925f2c062658e960bb5128738828d9f..8a14bdda4a408ec1e2b51efeb35467835f62b42c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -430,25 +430,29 @@ public class LevelChunk implements ChunkAccess {
|
||||
}
|
||||
|
||||
public FluidState getFluidState(int x, int y, int z) {
|
||||
- try {
|
||||
- if (y >= 0 && y >> 4 < this.sections.length) {
|
||||
- LevelChunkSection chunksection = this.sections[y >> 4];
|
||||
-
|
||||
- if (!LevelChunkSection.isEmpty(chunksection)) {
|
||||
- return chunksection.getFluidState(x & 15, y & 15, z & 15);
|
||||
+ //try { // Paper - remove try catch
|
||||
+ // Paper start - reduce the number of ops in this call
|
||||
+ int index = y >> 4;
|
||||
+ if (index >= 0 && index < this.sections.length) {
|
||||
+ LevelChunkSection chunksection = this.sections[index];
|
||||
+
|
||||
+ if (chunksection != null) {
|
||||
+ return chunksection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState();
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
+ */ // Paper - remove try catch
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
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 c44d32f966c61497b4a8892eb51da3a71ad031d9..5e7f6000df129100ef306703f325af9f60da8ae6 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -45,7 +45,7 @@ public class LevelChunkSection {
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
public void acquire() {
|
File diff suppressed because it is too large
Load diff
|
@ -1,155 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Sat, 1 Feb 2020 16:50:39 +0100
|
||||
Subject: [PATCH] Pillager patrol spawn settings and per player options
|
||||
|
||||
This adds config options for defining the spawn chance, spawn delay and
|
||||
spawn start day as well as toggles for handling the spawn delay and
|
||||
start day per player. (Based on the time played statistic)
|
||||
When not per player it will use the Vanilla mechanic of one delay per
|
||||
world and the world age for the start day.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 525d702d78a609af987ebd2c32169b873e5c05ed..6c8e9d498c9a30a1aa88494ba09c3cae012a8fa1 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -582,10 +582,21 @@ public class PaperWorldConfig {
|
||||
}
|
||||
|
||||
public boolean disablePillagerPatrols = false;
|
||||
+ public double patrolSpawnChance = 0.2;
|
||||
+ public boolean patrolPerPlayerDelay = false;
|
||||
+ public int patrolDelay = 12000;
|
||||
+ public boolean patrolPerPlayerStart = false;
|
||||
+ public int patrolStartDay = 5;
|
||||
private void pillagerSettings() {
|
||||
disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols);
|
||||
+ patrolSpawnChance = getDouble("game-mechanics.pillager-patrols.spawn-chance", patrolSpawnChance);
|
||||
+ patrolPerPlayerDelay = getBoolean("game-mechanics.pillager-patrols.spawn-delay.per-player", patrolPerPlayerDelay);
|
||||
+ patrolDelay = getInt("game-mechanics.pillager-patrols.spawn-delay.ticks", patrolDelay);
|
||||
+ patrolPerPlayerStart = getBoolean("game-mechanics.pillager-patrols.start.per-player", patrolPerPlayerStart);
|
||||
+ patrolStartDay = getInt("game-mechanics.pillager-patrols.start.day", patrolStartDay);
|
||||
}
|
||||
|
||||
+
|
||||
public boolean entitiesTargetWithFollowRange = false;
|
||||
private void entitiesTargetWithFollowRange() {
|
||||
entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 7f4e81ee3339e90b8525541dccf6dea187853cf7..a469016c43251f16913a365c4131b2448eaa4c48 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -213,6 +213,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||
public boolean wonGame;
|
||||
private int containerUpdateDelay; // Paper
|
||||
public long loginTime; // Paper
|
||||
+ public int patrolSpawnDelay; // Paper - per player patrol spawns
|
||||
// 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 ba48795a7b7cbf4622e64273ab488e26d7a862e2..b85987910cf80b1d1a04a7b772e19200f4ce4372 100644
|
||||
--- a/src/main/java/net/minecraft/stats/StatType.java
|
||||
+++ b/src/main/java/net/minecraft/stats/StatType.java
|
||||
@@ -28,6 +28,7 @@ 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 48efe133d294bb1b17e8ac8b44eea8a29f15845f..dcbe74bdb1b6e07f7b8845182576ef544493d377 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
@@ -4,11 +4,12 @@ import java.util.Random;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.stats.Stats;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.MobSpawnType;
|
||||
import net.minecraft.world.entity.SpawnGroupData;
|
||||
import net.minecraft.world.entity.monster.PatrollingMonster;
|
||||
-import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.CustomSpawner;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
@@ -20,13 +21,13 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public class PatrolSpawner implements CustomSpawner {
|
||||
|
||||
- private int nextTick;
|
||||
+ private int nextTick;private int getSpawnDelay() { return nextTick; } private void setSpawnDelay(int spawnDelay) { this.nextTick = spawnDelay; } // Paper - OBFHELPER
|
||||
|
||||
public PatrolSpawner() {}
|
||||
|
||||
@Override
|
||||
public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) {
|
||||
- if (world.paperConfig.disablePillagerPatrols) return 0; // Paper
|
||||
+ if (world.paperConfig.disablePillagerPatrols || world.paperConfig.patrolSpawnChance == 0) return 0; // Paper
|
||||
if (!spawnMonsters) {
|
||||
return 0;
|
||||
} else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) {
|
||||
@@ -34,23 +35,51 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
} else {
|
||||
Random random = world.random;
|
||||
|
||||
- --this.nextTick;
|
||||
- if (this.nextTick > 0) {
|
||||
+ // Paper start - Patrol settings
|
||||
+ // Random player selection moved up for per player spawning and configuration
|
||||
+ int j = world.players().size();
|
||||
+ if (j < 1) {
|
||||
return 0;
|
||||
+ }
|
||||
+
|
||||
+ ServerPlayer entityhuman = world.players().get(random.nextInt(j));
|
||||
+ if (entityhuman.isSpectator()) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ int patrolSpawnDelay;
|
||||
+ if (world.paperConfig.patrolPerPlayerDelay) {
|
||||
+ --entityhuman.patrolSpawnDelay;
|
||||
+ patrolSpawnDelay = entityhuman.patrolSpawnDelay;
|
||||
} else {
|
||||
- this.nextTick += 12000 + random.nextInt(1200);
|
||||
- long i = world.getDayTime() / 24000L;
|
||||
+ setSpawnDelay(getSpawnDelay() - 1);
|
||||
+ patrolSpawnDelay = getSpawnDelay();
|
||||
+ }
|
||||
+
|
||||
+ if (patrolSpawnDelay > 0) {
|
||||
+ return 0;
|
||||
+ } 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
|
||||
+ } else {
|
||||
+ days = world.getDayTime() / 24000L;
|
||||
+ }
|
||||
+ if (world.paperConfig.patrolPerPlayerDelay) {
|
||||
+ entityhuman.patrolSpawnDelay += world.paperConfig.patrolDelay + random.nextInt(1200);
|
||||
+ } else {
|
||||
+ setSpawnDelay(getSpawnDelay() + world.paperConfig.patrolDelay + random.nextInt(1200));
|
||||
+ }
|
||||
|
||||
- if (i >= 5L && world.isDay()) {
|
||||
- if (random.nextInt(5) != 0) {
|
||||
+ if (days >= world.paperConfig.patrolStartDay && world.isDay()) {
|
||||
+ if (random.nextDouble() >= world.paperConfig.patrolSpawnChance) {
|
||||
+ // Paper end
|
||||
return 0;
|
||||
} else {
|
||||
- int j = world.players().size();
|
||||
|
||||
if (j < 1) {
|
||||
return 0;
|
||||
} else {
|
||||
- Player entityhuman = (Player) world.players().get(random.nextInt(j));
|
||||
|
||||
if (entityhuman.isSpectator()) {
|
||||
return 0;
|
|
@ -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 9da0d98bc2ed7876a00a734690ed42f01b9a9a9b..9898d5c8fab63c576831bd416ccf1854ed077b0d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -643,6 +643,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1400,6 +1401,19 @@ 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 )
|
||||
{
|
||||
@@ -1466,9 +1480,21 @@ 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 43f77d01fceab107d3502d282205aa579d64cc4b..7e198b94f349d4c4d61502f5ad8c60686800d88f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -147,6 +147,7 @@ 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
|
|
@ -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 9898d5c8fab63c576831bd416ccf1854ed077b0d..c5dc41a3cf499038bd33451a189913cd3978b230 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1559,9 +1559,9 @@ 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);
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 31 Mar 2020 03:50:42 -0400
|
||||
Subject: [PATCH] Remote Connections shouldn't hold up shutdown
|
||||
|
||||
Bugs in the connection logic appears to leave stale connections even, preventing shutdown
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 4862a9519d4ba5f05b634a0335837bea9812edee..f8ddc0aa98874c7879a51e76d1a629cbdaf58812 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -397,11 +397,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
|
||||
if (this.rconThread != null) {
|
||||
- this.rconThread.stop();
|
||||
+ //this.remoteControlListener.b(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
if (this.queryThreadGs4 != null) {
|
||||
- this.queryThreadGs4.stop();
|
||||
+ //this.remoteStatusListener.b(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
System.exit(0); // CraftBukkit
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: chickeneer <emcchickeneer@gmail.com>
|
||||
Date: Tue, 17 Mar 2020 14:18:50 -0500
|
||||
Subject: [PATCH] Do not allow bees to load chunks for beehives
|
||||
|
||||
|
||||
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 9b68809b91910d2bbb82cafe23d1de5dfff4221c..81291a1174538d6d4073c6fa886b10e99b45d887 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -358,6 +358,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
if (this.hivePos == null) {
|
||||
return false;
|
||||
} else {
|
||||
+ if (!this.level.isLoadedAndInBounds(hivePos)) return false; // Paper
|
||||
BlockEntity tileentity = this.level.getBlockEntity(this.hivePos);
|
||||
|
||||
return tileentity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity) tileentity).isFireNearby();
|
||||
@@ -390,6 +391,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
}
|
||||
|
||||
private boolean doesHiveHaveSpace(BlockPos pos) {
|
||||
+ if (!this.level.isLoadedAndInBounds(pos)) return false; // Paper
|
||||
BlockEntity tileentity = this.level.getBlockEntity(pos);
|
||||
|
||||
return tileentity instanceof BeehiveBlockEntity ? !((BeehiveBlockEntity) tileentity).isFull() : false;
|
||||
@@ -632,6 +634,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
@Override
|
||||
public boolean canBeeUse() {
|
||||
if (Bee.this.hasHive() && Bee.this.wantsToEnterHive() && Bee.this.hivePos.closerThan((Position) Bee.this.position(), 2.0D)) {
|
||||
+ if (!Bee.this.level.isLoadedAndInBounds(Bee.this.hivePos)) return false; // Paper
|
||||
BlockEntity tileentity = Bee.this.level.getBlockEntity(Bee.this.hivePos);
|
||||
|
||||
if (tileentity instanceof BeehiveBlockEntity) {
|
||||
@@ -655,6 +658,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
+ if (!Bee.this.level.isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper
|
||||
BlockEntity tileentity = Bee.this.level.getBlockEntity(Bee.this.hivePos);
|
||||
|
||||
if (tileentity instanceof BeehiveBlockEntity) {
|
|
@ -1,48 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 01:42:39 -0400
|
||||
Subject: [PATCH] Prevent Double PlayerChunkMap adds crashing server
|
||||
|
||||
Suspected case would be around the technique used in .stopRiding
|
||||
Stack will identify any causer of this and warn instead of crashing.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 6da406c8403797a1cd9276ac06577c3c080a8a22..e6eeca5834a164d87f5b0e564fe6237902edaa6a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1501,6 +1501,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
protected void addEntity(Entity entity) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
|
||||
+ // Paper start - ignore and warn about illegal addEntity calls instead of crashing server
|
||||
+ if (!entity.valid || entity.level != this.level || this.entityMap.containsKey(entity.getId())) {
|
||||
+ new Throwable("[ERROR] Illegal PlayerChunkMap::addEntity for world " + this.level.getWorld().getName()
|
||||
+ + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""))
|
||||
+ .printStackTrace();
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (!(entity instanceof EnderDragonPart)) {
|
||||
EntityType<?> entitytypes = entity.getType();
|
||||
int i = entitytypes.clientTrackingRange() * 16;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index c5dc41a3cf499038bd33451a189913cd3978b230..5127bce423a83711cea94e387b3ae7866215ded5 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1525,7 +1525,7 @@ 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);
|
||||
@@ -1536,6 +1536,7 @@ 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();
|
|
@ -1,185 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 02:37:57 -0400
|
||||
Subject: [PATCH] Optimize Collision to not load chunks
|
||||
|
||||
The collision code takes an AABB and generates a cuboid of checks rather
|
||||
than a cylinder, so at high velocity this can generate a lot of chunk checks.
|
||||
|
||||
Treat an unloaded chunk as a collision for entities, and also for players if
|
||||
the "prevent moving into unloaded chunks" setting is enabled.
|
||||
|
||||
If that serting is not enabled, collisions will be ignored for players, since
|
||||
movement will load only the chunk the player enters anyways and avoids loading
|
||||
massive amounts of surrounding chunks due to large AABB lookups.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index dfdde9722bc0d83916779014b7718eef2c01b3db..86c5549196a4e9011c5240e7918b466c299be4a3 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -59,12 +59,23 @@ 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;
|
||||
@@ -90,15 +101,6 @@ 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;
|
||||
|
||||
@@ -805,6 +807,7 @@ 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) {
|
||||
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 7e198b94f349d4c4d61502f5ad8c60686800d88f..b8dcc91a191f25ca578e0858abf6c1b874fee15d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -168,6 +168,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||
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 d9e69195ee0af4dfb90bf0e8f4cc65e63f7ecf5b..1b52f2a0ce9cb847d7d57b38f4b8b6bed8de2cd9 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
@@ -54,7 +54,9 @@ public interface CollisionGetter extends BlockGetter {
|
||||
}
|
||||
|
||||
default boolean noCollision(@Nullable Entity entity, AABB axisalignedbb, Predicate<Entity> predicate) {
|
||||
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
|
||||
return this.getCollisions(entity, axisalignedbb, predicate).allMatch(VoxelShape::isEmpty);
|
||||
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
|
||||
}
|
||||
|
||||
Stream<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB axisalignedbb, 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 7208c61da48ce5e735810b6268490584e1d5c260..feca9ff34936686c0665ae0dbc926869087df3a7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
|
||||
@@ -7,6 +7,9 @@ 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;
|
||||
@@ -21,13 +24,13 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
|
||||
|
||||
@Nullable
|
||||
- private final Entity source;
|
||||
+ private final Entity source; final Entity getEntity() { return this.source; } // Paper - OBFHELPER
|
||||
private final AABB box;
|
||||
private final CollisionContext context;
|
||||
private final Cursor3D cursor;
|
||||
- private final BlockPos.MutableBlockPos pos;
|
||||
+ private final BlockPos.MutableBlockPos pos; final BlockPos.MutableBlockPos getMutablePos() { return this.pos; } // Paper - OBFHELPER
|
||||
private final VoxelShape entityShape;
|
||||
- private final CollisionGetter collisionGetter;
|
||||
+ private final CollisionGetter collisionGetter; final CollisionGetter getCollisionAccess() { return this.collisionGetter; } // Paper - OBFHELPER
|
||||
private boolean needsBorderCheck;
|
||||
private final BiPredicate<BlockState, BlockPos> predicate;
|
||||
|
||||
@@ -64,23 +67,37 @@ public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
|
||||
boolean collisionCheck(Consumer<? super VoxelShape> consumer) {
|
||||
while (true) {
|
||||
if (this.cursor.advance()) {
|
||||
- int i = this.cursor.nextX();
|
||||
- int j = this.cursor.nextY();
|
||||
- int k = this.cursor.nextZ();
|
||||
+ int i = this.cursor.nextX(); final int x = i;
|
||||
+ 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) {
|
||||
+ // 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;
|
||||
+ 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)
|
||||
+ ? 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);
|
||||
+ 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)) {
|
||||
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 fa2942d0b0424390daee2121f8959034c5352e0b..c14d5ebe16a693834ed218af8f737714065b2e17 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
@@ -249,7 +249,8 @@ 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);
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 17:16:48 -0400
|
||||
Subject: [PATCH] Don't tick dead players
|
||||
|
||||
Causes sync chunk loads and who knows what all else.
|
||||
This is safe because Spectators are skipped in unloaded chunks too in vanilla.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index a469016c43251f16913a365c4131b2448eaa4c48..286b75a27103a084a9f9d79a90716ebcad65d813 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -606,7 +606,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||
|
||||
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)
|
||||
super.tick();
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 19:31:16 -0400
|
||||
Subject: [PATCH] Dead Player's shouldn't be able to move
|
||||
|
||||
This fixes a lot of game state issues where packets were delayed for processing
|
||||
due to 1.15's new queue but processed while dead.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index 0685920073a6a2b2c6a80018d0c9009b2ef860c4..32f1b180e82f41f3ce1b49ea7d67b7d55d2b9ca7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1046,7 +1046,7 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
@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...
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,294 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 8 Apr 2020 03:06:30 -0400
|
||||
Subject: [PATCH] Optimize PlayerChunkMap memory use for visibleChunks
|
||||
|
||||
No longer clones visible chunks which is causing massive memory
|
||||
allocation issues, likely the source of Humongous Objects on large servers.
|
||||
|
||||
Instead we just synchronize, clear and rebuild, reusing the same object buffers
|
||||
as before with only 2 small objects created (FastIterator/MapEntry)
|
||||
|
||||
This should result in siginificant memory use reduction and improved GC behavior.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/util/map/Long2ObjectLinkedOpenHashMapFastCopy.java b/src/main/java/com/destroystokyo/paper/util/map/Long2ObjectLinkedOpenHashMapFastCopy.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..f6ff4d8132a95895680f5bc81f8f873e78f0bbdb
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/util/map/Long2ObjectLinkedOpenHashMapFastCopy.java
|
||||
@@ -0,0 +1,39 @@
|
||||
+package com.destroystokyo.paper.util.map;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
+
|
||||
+public class Long2ObjectLinkedOpenHashMapFastCopy<V> extends Long2ObjectLinkedOpenHashMap<V> {
|
||||
+
|
||||
+ public void copyFrom(Long2ObjectLinkedOpenHashMapFastCopy<V> map) {
|
||||
+ if (key.length != map.key.length) {
|
||||
+ key = null;
|
||||
+ key = new long[map.key.length];
|
||||
+ }
|
||||
+ if (value.length != map.value.length) {
|
||||
+ value = null;
|
||||
+ //noinspection unchecked
|
||||
+ value = (V[]) new Object[map.value.length];
|
||||
+ }
|
||||
+ if (link.length != map.link.length) {
|
||||
+ link = null;
|
||||
+ link = new long[map.link.length];
|
||||
+ }
|
||||
+ System.arraycopy(map.key, 0, this.key, 0, map.key.length);
|
||||
+ System.arraycopy(map.value, 0, this.value, 0, map.value.length);
|
||||
+ System.arraycopy(map.link, 0, this.link, 0, map.link.length);
|
||||
+ this.size = map.size;
|
||||
+ this.mask = map.mask;
|
||||
+ this.first = map.first;
|
||||
+ this.last = map.last;
|
||||
+ this.n = map.n;
|
||||
+ this.maxFill = map.maxFill;
|
||||
+ this.containsNullKey = map.containsNullKey;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Long2ObjectLinkedOpenHashMapFastCopy<V> clone() {
|
||||
+ Long2ObjectLinkedOpenHashMapFastCopy<V> clone = (Long2ObjectLinkedOpenHashMapFastCopy<V>) super.clone();
|
||||
+ clone.copyFrom(this);
|
||||
+ return clone;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
index 99c3337eec552ba47d3b8b2d8feaaa80acf2a86f..9abef8550a89df5e15ac28de1a5549d064f29122 100644
|
||||
--- a/src/main/java/net/minecraft/server/MCUtil.java
|
||||
+++ b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
@@ -616,7 +616,7 @@ public final class MCUtil {
|
||||
|
||||
ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle();
|
||||
ChunkMap chunkMap = world.getChunkSource().chunkMap;
|
||||
- Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = chunkMap.visibleChunkMap;
|
||||
+ Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = chunkMap.getVisibleChunks();
|
||||
DistanceManager chunkMapDistance = chunkMap.distanceManager;
|
||||
List<ChunkHolder> allChunks = new ArrayList<>(visibleChunks.values());
|
||||
List<ServerPlayer> players = world.players;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc08174003f4a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -104,8 +104,33 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
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
|
||||
+
|
||||
+ private class ProtectedVisibleChunksMap extends com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder> {
|
||||
+ @Override
|
||||
+ public ChunkHolder put(long k, ChunkHolder playerChunk) {
|
||||
+ throw new UnsupportedOperationException("Updating visible Chunks");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ChunkHolder remove(long k) {
|
||||
+ throw new UnsupportedOperationException("Removing visible Chunks");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ChunkHolder get(long k) {
|
||||
+ return ChunkMap.this.getVisibleChunkIfPresent(k);
|
||||
+ }
|
||||
+
|
||||
+ public ChunkHolder safeGet(long k) {
|
||||
+ return super.get(k);
|
||||
+ }
|
||||
+ }
|
||||
+ // 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
|
||||
private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads;
|
||||
public final LongSet entitiesInLevel; // Paper - private -> public
|
||||
public final ServerLevel level;
|
||||
@@ -178,7 +203,7 @@ 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);
|
||||
- this.visibleChunkMap = this.updatingChunkMap.clone();
|
||||
+ //this.visibleChunks = this.updatingChunks.clone(); // Paper - no more cloning
|
||||
this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
|
||||
this.entitiesInLevel = new LongOpenHashSet();
|
||||
this.toDrop = new LongOpenHashSet();
|
||||
@@ -270,9 +295,52 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return (ChunkHolder) this.updatingChunkMap.get(pos);
|
||||
}
|
||||
|
||||
+ // Paper start - remove cloning of visible chunks unless accessed as a collection async
|
||||
+ private static final boolean DEBUG_ASYNC_VISIBLE_CHUNKS = Boolean.getBoolean("paper.debug-async-visible-chunks");
|
||||
+ private boolean isIterating = false;
|
||||
+ private boolean hasPendingVisibleUpdate = false;
|
||||
+ public void forEachVisibleChunk(java.util.function.Consumer<ChunkHolder> consumer) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("forEachVisibleChunk");
|
||||
+ boolean prev = isIterating;
|
||||
+ isIterating = true;
|
||||
+ try {
|
||||
+ for (ChunkHolder value : this.visibleChunkMap.values()) {
|
||||
+ consumer.accept(value);
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.isIterating = prev;
|
||||
+ if (!this.isIterating && this.hasPendingVisibleUpdate) {
|
||||
+ ((ProtectedVisibleChunksMap)this.visibleChunkMap).copyFrom(this.pendingVisibleChunks);
|
||||
+ this.pendingVisibleChunks.clear();
|
||||
+ this.hasPendingVisibleUpdate = false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ public Long2ObjectLinkedOpenHashMap<ChunkHolder> getVisibleChunks() {
|
||||
+ if (Thread.currentThread() == this.level.thread) {
|
||||
+ return this.visibleChunkMap;
|
||||
+ } else {
|
||||
+ synchronized (this.visibleChunkMap) {
|
||||
+ if (DEBUG_ASYNC_VISIBLE_CHUNKS) new Throwable("Async getVisibleChunks").printStackTrace();
|
||||
+ if (this.visibleChunksClone == null) {
|
||||
+ this.visibleChunksClone = this.hasPendingVisibleUpdate ? this.pendingVisibleChunks.clone() : ((ProtectedVisibleChunksMap)this.visibleChunkMap).clone();
|
||||
+ }
|
||||
+ return this.visibleChunksClone;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Nullable
|
||||
public ChunkHolder getVisibleChunkIfPresent(long pos) { // Paper - protected -> public
|
||||
- return (ChunkHolder) this.visibleChunkMap.get(pos);
|
||||
+ // Paper start - mt safe get
|
||||
+ if (Thread.currentThread() != this.level.thread) {
|
||||
+ synchronized (this.visibleChunkMap) {
|
||||
+ return (ChunkHolder) (this.hasPendingVisibleUpdate ? this.pendingVisibleChunks.get(pos) : ((ProtectedVisibleChunksMap)this.visibleChunkMap).safeGet(pos));
|
||||
+ }
|
||||
+ }
|
||||
+ return (ChunkHolder) (this.hasPendingVisibleUpdate ? this.pendingVisibleChunks.get(pos) : ((ProtectedVisibleChunksMap)this.visibleChunkMap).safeGet(pos));
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
protected IntSupplier getChunkQueueLevel(long pos) {
|
||||
@@ -460,8 +528,9 @@ 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)
|
||||
if (flush) {
|
||||
- List<ChunkHolder> list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList());
|
||||
+ List<ChunkHolder> list = (List) visibleChunks.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper - remove cloning of visible chunks
|
||||
MutableBoolean mutableboolean = new MutableBoolean();
|
||||
|
||||
do {
|
||||
@@ -489,7 +558,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// this.i(); // Paper - nuke IOWorker
|
||||
ChunkMap.LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.storageFolder.getName());
|
||||
} else {
|
||||
- this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).forEach((playerchunk) -> {
|
||||
+ visibleChunks.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).forEach((playerchunk) -> {
|
||||
ChunkAccess ichunkaccess = (ChunkAccess) playerchunk.getChunkToSave().getNow(null); // CraftBukkit - decompile error
|
||||
|
||||
if (ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk) {
|
||||
@@ -660,7 +729,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
if (!this.modified) {
|
||||
return false;
|
||||
} else {
|
||||
- this.visibleChunkMap = this.updatingChunkMap.clone();
|
||||
+ // Paper start - stop cloning visibleChunks
|
||||
+ synchronized (this.visibleChunkMap) {
|
||||
+ if (isIterating) {
|
||||
+ hasPendingVisibleUpdate = true;
|
||||
+ this.pendingVisibleChunks.copyFrom((com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder>)this.updatingChunkMap);
|
||||
+ } else {
|
||||
+ hasPendingVisibleUpdate = false;
|
||||
+ this.pendingVisibleChunks.clear();
|
||||
+ ((ProtectedVisibleChunksMap)this.visibleChunkMap).copyFrom((com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder>)this.updatingChunkMap);
|
||||
+ this.visibleChunksClone = null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
this.modified = false;
|
||||
return true;
|
||||
}
|
||||
@@ -1139,12 +1221,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
protected Iterable<ChunkHolder> getChunks() {
|
||||
- return Iterables.unmodifiableIterable(this.visibleChunkMap.values());
|
||||
+ return Iterables.unmodifiableIterable(this.getVisibleChunks().values()); // Paper
|
||||
}
|
||||
|
||||
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);
|
||||
- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator();
|
||||
+ ObjectBidirectionalIterator objectbidirectionaliterator = this.getVisibleChunks().long2ObjectEntrySet().iterator(); // Paper
|
||||
|
||||
while (objectbidirectionaliterator.hasNext()) {
|
||||
Entry<ChunkHolder> entry = (Entry) objectbidirectionaliterator.next();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index e2b1541042bceac965411e3176d08c61f217c07f..f5de878020be9465739fba07fd7dea46b0a3ae34 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -782,7 +782,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
};
|
||||
// Paper end
|
||||
this.level.timings.chunkTicks.startTiming(); // Paper
|
||||
- this.chunkMap.getChunks().forEach((playerchunk) -> { // Paper - no... just no...
|
||||
+ this.chunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping
|
||||
Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
|
||||
|
||||
if (optional.isPresent()) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index fb74bdcf4c2935b56e92717cc5a1504fbc853d0a..1a839242e359fa32f32d0e571c6e918ac39642e9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -276,6 +276,7 @@ public class CraftWorld implements World {
|
||||
return ret;
|
||||
}
|
||||
public int getTileEntityCount() {
|
||||
+ return net.minecraft.server.MCUtil.ensureMain(() -> {
|
||||
// We don't use the full world tile entity list, so we must iterate chunks
|
||||
Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.visibleChunkMap;
|
||||
int size = 0;
|
||||
@@ -287,11 +288,13 @@ public class CraftWorld implements World {
|
||||
size += chunk.blockEntities.size();
|
||||
}
|
||||
return size;
|
||||
+ });
|
||||
}
|
||||
public int getTickableTileEntityCount() {
|
||||
return world.tickableBlockEntities.size();
|
||||
}
|
||||
public int getChunkCount() {
|
||||
+ return net.minecraft.server.MCUtil.ensureMain(() -> {
|
||||
int ret = 0;
|
||||
|
||||
for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.visibleChunkMap.values()) {
|
||||
@@ -300,7 +303,7 @@ public class CraftWorld implements World {
|
||||
}
|
||||
}
|
||||
|
||||
- return ret;
|
||||
+ return ret; });
|
||||
}
|
||||
public int getPlayerCount() {
|
||||
return world.players.size();
|
||||
@@ -425,6 +428,14 @@ public class CraftWorld implements World {
|
||||
|
||||
@Override
|
||||
public Chunk[] getLoadedChunks() {
|
||||
+ // Paper start
|
||||
+ if (Thread.currentThread() != world.getLevel().thread) {
|
||||
+ synchronized (world.getChunkSource().chunkMap.visibleChunkMap) {
|
||||
+ Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = 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);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = 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);
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 9 Apr 2020 00:09:26 -0400
|
||||
Subject: [PATCH] Mid Tick Chunk Tasks - Speed up processing of chunk loads and
|
||||
generation
|
||||
|
||||
Credit to Spotted for the idea
|
||||
|
||||
A lot of the new chunk system requires constant back and forth the main thread
|
||||
to handle priority scheduling and ensuring conflicting tasks do not run at the
|
||||
same time.
|
||||
|
||||
The issue is, these queues are only checked at either:
|
||||
|
||||
A) Sync Chunk Loads
|
||||
B) End of Tick while sleeping
|
||||
|
||||
This results in generating chunks sitting waiting for a full tick to
|
||||
complete before it will even start the next unit of work to do.
|
||||
|
||||
Additionally, this also delays loading of chunks until this same timing.
|
||||
|
||||
We will now periodically poll the chunk task queues throughout the tick,
|
||||
looking for work to do.
|
||||
We do this in a fair method that considers all worlds, not just the one being
|
||||
ticked, so that each world can get 1 task procesed each before the next pass.
|
||||
|
||||
In a view distance of 15, chunk loading performance was visually faster on the client.
|
||||
|
||||
Flying at high speed in spectator mode was able to keep up with chunk loading (as long as they are already generated)
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
index be3a62f543a5fec4739c14821fe5a443c1fa3f5b..6bff5317939635b925bb41eb7a67d1fd95715078 100644
|
||||
--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
@@ -17,6 +17,7 @@ import java.util.Map;
|
||||
public final class MinecraftTimings {
|
||||
|
||||
public static final Timing serverOversleep = Timings.ofSafe("Server Oversleep");
|
||||
+ public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks");
|
||||
public static final Timing playerListTimer = Timings.ofSafe("Player List");
|
||||
public static final Timing commandFunctionsTimer = Timings.ofSafe("Command Functions");
|
||||
public static final Timing connectionTimer = Timings.ofSafe("Connection Handler");
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
index da93d38fe63035e4ff198ada84a4431f52d97c01..ddbc8cb712c50038922eded75dd6ca85fe851078 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
@@ -410,4 +410,9 @@ public class PaperConfig {
|
||||
log("Async Chunks: Enabled - Chunks will be loaded much faster, without lag.");
|
||||
}
|
||||
}
|
||||
+
|
||||
+ public static int midTickChunkTasks = 1000;
|
||||
+ private static void midTickChunkTasks() {
|
||||
+ midTickChunkTasks = getInt("settings.chunk-tasks-per-tick", midTickChunkTasks);
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b174dee62 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1055,6 +1055,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// Paper end
|
||||
tickSection = curTime;
|
||||
}
|
||||
+ midTickChunksTasksRan = 0; // Paper
|
||||
// Spigot end
|
||||
|
||||
//MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time
|
||||
@@ -1124,7 +1125,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
}
|
||||
|
||||
- private boolean haveTime() {
|
||||
+ public boolean haveTime() { // Paper
|
||||
// CraftBukkit start
|
||||
if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken
|
||||
return this.forceTicks || this.runningTask() || Util.getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime);
|
||||
@@ -1154,6 +1155,23 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public int midTickChunksTasksRan = 0;
|
||||
+ private long midTickLastRan = 0;
|
||||
+ public void midTickLoadChunks() {
|
||||
+ if (!isSameThread() || System.nanoTime() - midTickLastRan < 1000000) {
|
||||
+ // only check once per 0.25ms incase this code is called in a hot method
|
||||
+ return;
|
||||
+ }
|
||||
+ try (co.aikar.timings.Timing ignored = co.aikar.timings.MinecraftTimings.midTickChunkTasks.startTiming()) {
|
||||
+ for (ServerLevel value : this.getAllLevels()) {
|
||||
+ value.getChunkSource().mainThreadProcessor.midTickLoadChunks();
|
||||
+ }
|
||||
+ midTickLastRan = System.nanoTime();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public TickTask wrapRunnable(Runnable runnable) {
|
||||
return new TickTask(this.tickCount, runnable);
|
||||
@@ -1240,6 +1258,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// Paper start - move oversleep into full server tick
|
||||
isOversleep = true;MinecraftTimings.serverOversleep.startTiming();
|
||||
this.managedBlock(() -> {
|
||||
+ midTickLoadChunks(); // will only do loads since we are still considered !canSleepForTick
|
||||
return !this.canOversleep();
|
||||
});
|
||||
isOversleep = false;MinecraftTimings.serverOversleep.stopTiming();
|
||||
@@ -1318,13 +1337,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
protected void tickChildren(BooleanSupplier shouldKeepTicking) {
|
||||
+ midTickLoadChunks(); // Paper
|
||||
MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper
|
||||
this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit
|
||||
MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper
|
||||
+ midTickLoadChunks(); // Paper
|
||||
this.profiler.push("commandFunctions");
|
||||
MinecraftTimings.commandFunctionsTimer.startTiming(); // Spigot // Paper
|
||||
this.getFunctions().tick();
|
||||
MinecraftTimings.commandFunctionsTimer.stopTiming(); // Spigot // Paper
|
||||
+ midTickLoadChunks(); // Paper
|
||||
this.profiler.popPush("levels");
|
||||
Iterator iterator = this.getAllLevels().iterator();
|
||||
|
||||
@@ -1335,7 +1357,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
processQueue.remove().run();
|
||||
}
|
||||
MinecraftTimings.processQueueTimer.stopTiming(); // Spigot
|
||||
-
|
||||
+ midTickLoadChunks(); // Paper
|
||||
MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper
|
||||
// Send time updates to everyone, it will get the right time from the world the player is in.
|
||||
// Paper start - optimize time updates
|
||||
@@ -1377,9 +1399,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.profiler.push("tick");
|
||||
|
||||
try {
|
||||
+ midTickLoadChunks(); // Paper
|
||||
worldserver.timings.doTick.startTiming(); // Spigot
|
||||
worldserver.tick(shouldKeepTicking);
|
||||
worldserver.timings.doTick.stopTiming(); // Spigot
|
||||
+ midTickLoadChunks(); // Paper
|
||||
} catch (Throwable throwable) {
|
||||
// Spigot Start
|
||||
CrashReport crashreport;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index f5de878020be9465739fba07fd7dea46b0a3ae34..3744cce8611ac01b1b6c76cd3c4890795c1f06a2 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -22,6 +22,7 @@ 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;
|
||||
@@ -719,6 +720,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
this.level.getProfiler().push("purge");
|
||||
this.level.timings.doChunkMap.startTiming(); // Spigot
|
||||
this.distanceManager.purgeStaleTickets();
|
||||
+ this.level.getServer().midTickLoadChunks(); // Paper
|
||||
this.runDistanceManagerUpdates();
|
||||
this.level.timings.doChunkMap.stopTiming(); // Spigot
|
||||
this.level.getProfiler().popPush("chunks");
|
||||
@@ -728,6 +730,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
this.level.timings.doChunkUnload.startTiming(); // Spigot
|
||||
this.level.getProfiler().popPush("unload");
|
||||
this.chunkMap.tick(shouldKeepTicking);
|
||||
+ this.level.getServer().midTickLoadChunks(); // Paper
|
||||
this.level.timings.doChunkUnload.stopTiming(); // Spigot
|
||||
this.level.getProfiler().pop();
|
||||
this.clearCache();
|
||||
@@ -782,7 +785,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
};
|
||||
// Paper end
|
||||
this.level.timings.chunkTicks.startTiming(); // Paper
|
||||
- this.chunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping
|
||||
+ final int[] chunksTicked = {0}; this.chunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping
|
||||
Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
|
||||
|
||||
if (optional.isPresent()) {
|
||||
@@ -806,6 +809,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
//this.world.timings.chunkTicks.startTiming(); // Spigot // Paper
|
||||
this.level.tickChunk(chunk, k);
|
||||
//this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper
|
||||
+ if (chunksTicked[0]++ % 10 == 0) this.level.getServer().midTickLoadChunks(); // Paper
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -963,6 +967,41 @@ public class ServerChunkCache extends ChunkSource {
|
||||
super.doRunTask(task);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private long lastMidTickChunkTask = 0;
|
||||
+ public boolean pollChunkLoadTasks() {
|
||||
+ if (com.destroystokyo.paper.io.chunk.ChunkTaskManager.pollChunkWaitQueue() || ServerChunkCache.this.level.asyncChunkTaskManager.pollNextChunkTask()) {
|
||||
+ try {
|
||||
+ ServerChunkCache.this.runDistanceManagerUpdates();
|
||||
+ } finally {
|
||||
+ // from below: process pending Chunk loadCallback() and unloadCallback() after each run task
|
||||
+ chunkMap.callbackExecutor.run();
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ public void midTickLoadChunks() {
|
||||
+ 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()) {}
|
||||
+
|
||||
+ if (System.nanoTime() - lastMidTickChunkTask < 200000) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (;server.midTickChunksTasksRan < com.destroystokyo.paper.PaperConfig.midTickChunkTasks && server.haveTime();) {
|
||||
+ if (this.pollTask()) {
|
||||
+ server.midTickChunksTasksRan++;
|
||||
+ lastMidTickChunkTask = System.nanoTime();
|
||||
+ } else {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
protected boolean pollTask() {
|
||||
// CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 5127bce423a83711cea94e387b3ae7866215ded5..4e75cc5e52a5295e32ccadb371702a405bb518bb 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -565,6 +565,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
}
|
||||
timings.scheduledBlocks.stopTiming(); // Paper
|
||||
|
||||
+ this.getServer().midTickLoadChunks(); // Paper
|
||||
gameprofilerfiller.popPush("raid");
|
||||
this.timings.raids.startTiming(); // Paper - timings
|
||||
this.raids.tick();
|
||||
@@ -573,6 +574,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
timings.doSounds.startTiming(); // Spigot
|
||||
this.runBlockEvents();
|
||||
timings.doSounds.stopTiming(); // Spigot
|
||||
+ this.getServer().midTickLoadChunks(); // Paper
|
||||
this.handlingTick = false;
|
||||
gameprofilerfiller.popPush("entities");
|
||||
boolean flag3 = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
|
||||
@@ -639,6 +641,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
timings.entityTick.stopTiming(); // Spigot
|
||||
|
||||
this.tickingEntities = false;
|
||||
+ this.getServer().midTickLoadChunks(); // Paper
|
||||
|
||||
Entity entity2;
|
||||
|
||||
@@ -648,6 +651,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
}
|
||||
|
||||
timings.tickEntities.stopTiming(); // Spigot
|
||||
+ this.getServer().midTickLoadChunks(); // Paper
|
||||
this.tickBlockEntities();
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 9 Apr 2020 21:20:33 -0400
|
||||
Subject: [PATCH] Don't move existing players to world spawn
|
||||
|
||||
This can cause a nasty server lag the spawn chunks are not kept loaded
|
||||
or they aren't finished loading yet, or if the world spawn radius is
|
||||
larger than the keep loaded range.
|
||||
|
||||
By skipping this, we avoid potential for a large spike on server start.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 286b75a27103a084a9f9d79a90716ebcad65d813..162b1a8c6ab57aafa4f6deefc842755a8e14208e 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -251,7 +251,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||
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
|
||||
@@ -303,6 +303,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
+ public final void moveToSpawn(ServerLevel worldserver) { fudgeSpawnLocation(worldserver); } // Paper - OBFHELPER
|
||||
private void fudgeSpawnLocation(ServerLevel world) {
|
||||
BlockPos blockposition = world.getSpawn();
|
||||
|
||||
@@ -480,7 +481,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||
position = Vec3.atCenterOf(((ServerLevel) world).getSpawn());
|
||||
}
|
||||
this.level = world;
|
||||
- this.setPos(position.x(), position.y(), position.z());
|
||||
+ this.setPosRaw(position.x(), position.y(), position.z()); // Paper - don't register to chunks yet
|
||||
}
|
||||
this.gameMode.setLevel((ServerLevel) world);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 86c5549196a4e9011c5240e7918b466c299be4a3..30666fca36b683158ff60302684b5093f5536e24 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -204,6 +204,8 @@ public abstract class PlayerList {
|
||||
worldserver1 = worldserver;
|
||||
}
|
||||
|
||||
+ if (nbttagcompound == null) player.moveToSpawn(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";
|
Loading…
Add table
Add a link
Reference in a new issue