EVEN MOOOOOAAAAAAARRRRRRR patches :) (#5820)

This commit is contained in:
Jake Potrebic 2021-06-13 18:06:38 -07:00
parent 9a87139683
commit ddb72c221d
52 changed files with 426 additions and 981 deletions

View file

@ -0,0 +1,26 @@
plugins {
`java-library`
checkstyle
}
java {
withSourcesJar()
withJavadocJar()
}
repositories {
mavenCentral()
maven("https://libraries.minecraft.net")
}
dependencies {
implementation(project(":Paper-API"))
api("com.mojang:brigadier:1.0.18")
compileOnly("it.unimi.dsi:fastutil")
compileOnly("org.jetbrains:annotations:18.0.0")
testImplementation("junit:junit:4.13.1")
testImplementation("org.hamcrest:hamcrest-library:1.3")
testImplementation("org.ow2.asm:asm-tree:7.3.1")
}

View file

@ -67,18 +67,10 @@ diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukki
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/block/Block.java
+++ b/src/main/java/org/bukkit/block/Block.java
@@ -0,0 +0,0 @@
package org.bukkit.block;
import java.util.Collection;
+
import org.bukkit.Chunk;
import org.bukkit.FluidCollisionMode;
import org.bukkit.Location;
@@ -0,0 +0,0 @@ public interface Block extends Metadatable {
*/
@NotNull
BoundingBox getBoundingBox();
VoxelShape getCollisionShape();
+
+ // Paper start
+ /**

View file

@ -126,19 +126,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/bukkit/entity/Skeleton.java
+++ b/src/main/java/org/bukkit/entity/Skeleton.java
@@ -0,0 +0,0 @@ package org.bukkit.entity;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
+import com.destroystokyo.paper.entity.RangedEntity;
/**
* Represents a Skeleton.
* Other skeleton-like entities, such as the {@link WitherSkeleton} or the
* {@link Stray} are not related to this type.
*/
-public interface Skeleton extends Monster {
+public interface Skeleton extends Monster, RangedEntity { // Paper
-public interface Skeleton extends AbstractSkeleton {
+public interface Skeleton extends AbstractSkeleton, com.destroystokyo.paper.entity.RangedEntity { // Paper
/**
* Gets the current type of this skeleton.
* Computes whether or not this skeleton is currently in the process of
diff --git a/src/main/java/org/bukkit/entity/Snowman.java b/src/main/java/org/bukkit/entity/Snowman.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/Snowman.java

View file

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 11 Apr 2020 21:23:42 -0400
Subject: [PATCH] Delay unsafe actions until after entity ticking is done
This will help prevent many cases of unregistering entities during entity ticking
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
public final List<ServerPlayer> players = Lists.newArrayList(); // Paper - private -> public
public final ServerChunkCache chunkSource; // Paper - public
boolean tickingEntities;
+ // Paper start
+ List<java.lang.Runnable> afterEntityTickingTasks = Lists.newArrayList();
+ public void doIfNotEntityTicking(java.lang.Runnable run) {
+ if (tickingEntities) {
+ afterEntityTickingTasks.add(run);
+ } else {
+ run.run();
+ }
+ }
+ // Paper end
private final MinecraftServer server;
public final PrimaryLevelData worldDataServer; // CraftBukkit - type
public boolean noSave;
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
timings.entityTick.stopTiming(); // Spigot
this.tickingEntities = false;
+ // Paper start
+ for (java.lang.Runnable run : this.afterEntityTickingTasks) {
+ try {
+ run.run();
+ } catch (Exception e) {
+ LOGGER.error("Error in After Entity Ticking Task", e);
+ }
+ }
+ this.afterEntityTickingTasks.clear();
+ // Paper end
this.getServer().midTickLoadChunks(); // Paper
Entity entity2;

View file

@ -1,59 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Thu, 16 Apr 2020 16:13:59 -0700
Subject: [PATCH] Optimize ChunkProviderServer's chunk level checking helper
methods
These can be hot functions (i.e entity ticking and block ticking),
so inline where possible, and avoid the abstraction of the
Either class.
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -0,0 +0,0 @@ import net.minecraft.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;
import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.entity.Entity;
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
public final boolean isInEntityTickingChunk(Entity entity) { return this.isEntityTickingChunk(entity); } // Paper - OBFHELPER
@Override public boolean isEntityTickingChunk(Entity entity) {
- long i = ChunkPos.asLong(Mth.floor(entity.getX()) >> 4, Mth.floor(entity.getZ()) >> 4);
-
- return this.checkChunkFuture(i, (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getEntityTickingChunkFuture); // CraftBukkit - decompile error
+ // Paper start - optimize is ticking ready type functions
+ // entity ticking
+ ChunkHolder playerChunk = this.getVisibleChunkIfPresent(MCUtil.getCoordinateKey(entity));
+ return playerChunk != null && playerChunk.isEntityTickingReady();
+ // Paper end - optimize is ticking ready type functions
}
public final boolean isEntityTickingChunk(ChunkPos chunkcoordintpair) { return this.isEntityTickingChunk(chunkcoordintpair); } // Paper - OBFHELPER
@Override public boolean isEntityTickingChunk(ChunkPos pos) {
- return this.checkChunkFuture(pos.toLong(), (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getEntityTickingChunkFuture); // CraftBukkit - decompile error
+ // Paper start - optimize is ticking ready type functions
+ // is entity ticking ready
+ ChunkHolder playerChunk = this.getVisibleChunkIfPresent(MCUtil.getCoordinateKey(pos));
+ return playerChunk != null && playerChunk.isEntityTickingReady();
+ // Paper end - optimize is ticking ready type functions
}
@Override
public boolean isTickingChunk(BlockPos pos) {
- long i = ChunkPos.asLong(pos.getX() >> 4, pos.getZ() >> 4);
-
- return this.checkChunkFuture(i, (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getTickingChunkFuture); // CraftBukkit - decompile error
+ // Paper start - optimize is ticking ready type functions
+ // is ticking ready
+ ChunkHolder playerChunk = this.getVisibleChunkIfPresent(MCUtil.getCoordinateKey(pos));
+ return playerChunk != null && playerChunk.isTickingReady();
+ // Paper end - optimize is ticking ready type functions
}
private boolean checkChunkFuture(long pos, Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>> futureFunction) {

View file

@ -1,175 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 3 May 2020 22:35:09 -0400
Subject: [PATCH] Optimize Voxel Shape Merging
This method shows up as super hot in profiler, and also a high "self" time.
Upon analyzing, it appears most usages of this method fall down to the final
else statement of the nasty ternary.
Upon even further analyzation, it appears then the majority of those have a
consistent list 1.... One with Infinity head and Tails.
First optimization is to detect these infinite states and immediately return that
VoxelShapeMergerList so we can avoid testing the rest for most cases.
Break the method into 2 to help the JVM promote inlining of this fast path.
Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot
with a high self time...
Well, knowing that in most cases our list 1 is actualy the same value, it allows
us to know that with an infinite list1, the result on the merger is essentially
list2 as the final values.
This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources)
and compute a deterministic result for the MergerList values.
Additionally, this lets us avoid even allocating new objects for this too, further
reducing memory usage.
diff --git a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
@@ -0,0 +0,0 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
public final class IndirectMerger implements IndexMerger {
- private final DoubleArrayList result;
+ private final DoubleList a; // Paper
private final IntArrayList firstIndices;
private final IntArrayList secondIndices;
+ // Paper start
+ private static final IntArrayList INFINITE_B_1 = new IntArrayList(new int[]{1, 1});
+ private static final IntArrayList INFINITE_B_0 = new IntArrayList(new int[]{0, 0});
+ private static final IntArrayList INFINITE_C = new IntArrayList(new int[]{0, 1});
+ // Paper end
+
protected IndirectMerger(DoubleList first, DoubleList second, boolean includeFirstOnly, boolean includeSecondOnly) {
int i = 0;
int j = 0;
@@ -0,0 +0,0 @@ public final class IndirectMerger implements IndexMerger {
int l = second.size();
int i1 = k + l;
- this.result = new DoubleArrayList(i1);
+ // Paper start - optimize common path of infinity doublelist
+ int size = first.size();
+ double tail = first.getDouble(size - 1);
+ double head = first.getDouble(0);
+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !includeFirstOnly && !includeSecondOnly && (size == 2 || size == 4)) {
+ this.a = second;
+ if (size == 2) {
+ this.firstIndices = INFINITE_B_0;
+ } else {
+ this.firstIndices = INFINITE_B_1;
+ }
+ this.secondIndices = INFINITE_C;
+ return;
+ }
+ // Paper end
+
+ this.a = new DoubleArrayList(i1);
this.firstIndices = new IntArrayList(i1);
this.secondIndices = new IntArrayList(i1);
@@ -0,0 +0,0 @@ public final class IndirectMerger implements IndexMerger {
boolean flag3 = j < l;
if (!flag2 && !flag3) {
- if (this.result.isEmpty()) {
- this.result.add(Math.min(first.getDouble(k - 1), second.getDouble(l - 1)));
+ if (this.a.isEmpty()) {
+ this.a.add(Math.min(first.getDouble(k - 1), second.getDouble(l - 1)));
}
return;
@@ -0,0 +0,0 @@ public final class IndirectMerger implements IndexMerger {
if (!(d0 >= d1 - 1.0E-7D)) { // Paper - decompile error - welcome to hell
this.firstIndices.add(i - 1);
this.secondIndices.add(j - 1);
- this.result.add(d1);
+ this.a.add(d1);
d0 = d1;
- } else if (!this.result.isEmpty()) {
+ } else if (!this.a.isEmpty()) {
this.firstIndices.set(this.firstIndices.size() - 1, i - 1);
this.secondIndices.set(this.secondIndices.size() - 1, j - 1);
}
@@ -0,0 +0,0 @@ public final class IndirectMerger implements IndexMerger {
@Override
public boolean forMergedIndexes(IndexMerger.IndexConsumer predicate) {
- for (int i = 0; i < this.result.size() - 1; ++i) {
+ for (int i = 0; i < this.a.size() - 1; ++i) {
if (!predicate.merge(this.firstIndices.getInt(i), this.secondIndices.getInt(i), i)) {
return false;
}
@@ -0,0 +0,0 @@ public final class IndirectMerger implements IndexMerger {
@Override
public DoubleList getList() {
- return this.result;
+ return this.a;
}
}
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
@@ -0,0 +0,0 @@ public final class Shapes {
}
@VisibleForTesting
- protected static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
- int j = first.size() - 1;
- int k = second.size() - 1;
+ private static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { // Paper - private
+ // Paper start - fast track the most common scenario
+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause
+ // This is actually the most common path, so jump to it straight away
+ if (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) {
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
+ }
+ // Split out rest to hopefully inline the above
+ return lessCommonMerge(size, first, second, includeFirst, includeSecond);
+ }
+
+ private static IndexMerger lessCommonMerge(int i, DoubleList doublelist, DoubleList doublelist1, boolean flag, boolean flag1) {
+ int j = doublelist.size() - 1;
+ int k = doublelist1.size() - 1;
+ // Paper note - Rewrite below as optimized order if instead of nasty ternary
- if (first instanceof CubePointRange && second instanceof CubePointRange) {
+ if (doublelist instanceof CubePointRange && doublelist1 instanceof CubePointRange) {
long l = lcm(j, k);
- if ((long) size * l <= 256L) {
+ if ((long) i * l <= 256L) {
return new DiscreteCubeMerger(j, k);
}
}
- return (IndexMerger) (first.getDouble(j) < second.getDouble(0) - 1.0E-7D ? new NonOverlappingMerger(first, second, false) : (second.getDouble(k) < first.getDouble(0) - 1.0E-7D ? new NonOverlappingMerger(second, first, true) : (j == k && Objects.equals(first, second) ? (first instanceof IdenticalMerger ? (IndexMerger) first : (second instanceof IdenticalMerger ? (IndexMerger) second : new IdenticalMerger(first))) : new IndirectMerger(first, second, includeFirst, includeSecond))));
+ // Identical happens more often than Disjoint
+ if (j == k && Objects.equals(doublelist, doublelist1)) {
+ if (doublelist instanceof IdenticalMerger) {
+ return (IndexMerger) doublelist;
+ } else if (doublelist1 instanceof IdenticalMerger) {
+ return (IndexMerger) doublelist1;
+ }
+ return new IdenticalMerger(doublelist);
+ } else if (doublelist.getDouble(j) < doublelist1.getDouble(0) - 1.0E-07) {
+ return new NonOverlappingMerger(doublelist, doublelist1, false);
+ } else if (doublelist1.getDouble(k) < doublelist.getDouble(0) - 1.0E-07) {
+ return new NonOverlappingMerger(doublelist1, doublelist, true);
+ } else {
+ return new IndirectMerger(doublelist, doublelist1, flag, flag1);
+ }
+ // Paper end
}
public interface DoubleLineConsumer {

View file

@ -5,50 +5,6 @@ Subject: [PATCH] Add Raw Byte ItemStack Serialization
Serializes using NBT which is safer for server data migrations than bukkits format.
diff --git a/src/main/java/net/minecraft/nbt/NbtIo.java b/src/main/java/net/minecraft/nbt/NbtIo.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/nbt/NbtIo.java
+++ b/src/main/java/net/minecraft/nbt/NbtIo.java
@@ -0,0 +0,0 @@ public class NbtIo {
return nbttagcompound;
}
+ public static CompoundTag readNBT(InputStream inputstream) throws IOException { return readCompressed(inputstream); } // Paper - OBFHELPER
public static CompoundTag readCompressed(InputStream stream) throws IOException {
DataInputStream datainputstream = new DataInputStream(new BufferedInputStream(new GZIPInputStream(stream)));
Throwable throwable = null;
@@ -0,0 +0,0 @@ public class NbtIo {
}
+ public static void writeNBT(CompoundTag nbttagcompound, OutputStream outputstream) throws IOException { writeCompressed(nbttagcompound, outputstream); } // Paper - OBFHELPER
public static void writeCompressed(CompoundTag tag, OutputStream stream) throws IOException {
DataOutputStream dataoutputstream = new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(stream)));
Throwable throwable = null;
diff --git a/src/main/java/net/minecraft/util/datafix/DataFixers.java b/src/main/java/net/minecraft/util/datafix/DataFixers.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/datafix/DataFixers.java
+++ b/src/main/java/net/minecraft/util/datafix/DataFixers.java
@@ -0,0 +0,0 @@ public class DataFixers {
return datafixerbuilder.build(Util.bootstrapExecutor());
}
+ public static DataFixer getDataFixer() { return getDataFixer(); } // Paper - OBFHELPER
public static DataFixer getDataFixer() {
return DataFixers.DATA_FIXER;
}
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -0,0 +0,0 @@ public final class ItemStack {
this.updateEmptyCacheFlag();
}
+ public static ItemStack fromCompound(CompoundTag nbttagcompound) { return of(nbttagcompound); } // Paper - OBFHELPER
public static ItemStack of(CompoundTag tag) {
try {
return new ItemStack(tag);
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@ -67,7 +23,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ CompoundTag compound = (item instanceof CraftItemStack ? ((CraftItemStack) item).getHandle() : CraftItemStack.asNMSCopy(item)).save(new CompoundTag());
+ compound.putInt("DataVersion", getDataVersion());
+ try {
+ net.minecraft.nbt.NbtIo.writeNBT(
+ net.minecraft.nbt.NbtIo.writeCompressed(
+ compound,
+ outputStream
+ );
@ -84,14 +40,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing");
+
+ try {
+ CompoundTag compound = net.minecraft.nbt.NbtIo.readNBT(
+ CompoundTag compound = net.minecraft.nbt.NbtIo.readCompressed(
+ new java.io.ByteArrayInputStream(data)
+ );
+ int dataVersion = compound.getInt("DataVersion");
+
+ Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!");
+ Dynamic<Tag> converted = DataFixers.getDataFixer().update(References.ITEM_STACK, new Dynamic<Tag>(NbtOps.INSTANCE, compound), dataVersion, getDataVersion());
+ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.fromCompound((CompoundTag) converted.getValue()));
+ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.of((CompoundTag) converted.getValue()));
+ } catch (IOException ex) {
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ex);
+ throw new RuntimeException();

View file

@ -9,44 +9,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -0,0 +0,0 @@ public class PaperWorldConfig {
private void lightQueueSize() {
lightQueueSize = getInt("light-queue-size", lightQueueSize);
}
+
+ public boolean phantomIgnoreCreative = true;
+ public boolean phantomOnlyAttackInsomniacs = true;
+ private void phantomSettings() {
+ phantomIgnoreCreative = getBoolean("phantoms-do-not-spawn-on-creative-players", phantomIgnoreCreative);
+ phantomOnlyAttackInsomniacs = getBoolean("phantoms-only-attack-insomniacs", phantomOnlyAttackInsomniacs);
+ }
}
+
public int noTickViewDistance;
private void viewDistance() {
this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1);
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
@@ -0,0 +0,0 @@ package net.minecraft.world.entity;
import com.google.common.base.Predicates;
import java.util.function.Predicate;
import javax.annotation.Nullable;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.stats.Stats;
+import net.minecraft.util.Mth;
import net.minecraft.world.Container;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.player.Player;
@@ -0,0 +0,0 @@ public final class EntitySelector {
public static final Predicate<Entity> NO_SPECTATORS = (entity) -> {
return !entity.isSpectator();
};
+ public static Predicate<Player> isInsomniac = (player) -> Mth.clamp(((ServerPlayer) player).getStats().getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
+ public static Predicate<Player> isInsomniac = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
private EntitySelector() {}
// Paper start
public static final Predicate<Entity> affectsSpawning = (entity) -> {
- return !entity.isSpectator() && entity.isAlive() && (entity instanceof EntityPlayer) && ((EntityPlayer) entity).affectsSpawning;
+ return !entity.isSpectator() && entity.isAlive() && (entity instanceof ServerPlayer) && ((ServerPlayer) entity).affectsSpawning;
};
// Paper end
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java

View file

@ -91,9 +91,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private int maxBuildHeight;
private String motd;
private int playerIdleTimeout;
public final long[] tickTimes; public long[] getTickTimes() { return tickTimes; } // Paper - OBFHELPER
public final long[] tickTimes;
+ // Paper start
+ public final TickTimes tickTimes5s = new TickTimes(100);
+ public final TickTimes tickTimes10s = new TickTimes(200);
@ -116,10 +116,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
this.profiler.pop();
org.spigotmc.WatchdogThread.tick(); // Spigot
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public TextFilter createTextFilterForPlayer(ServerPlayer player) {
return null;
};
}
}
+
+ // Paper start
+ public static class TickTimes {
+ private final long[] times;

View file

@ -21,38 +21,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public final CallbackExecutor callbackExecutor = new CallbackExecutor();
public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable {
- private Runnable queued;
- private final java.util.Queue<Runnable> queue = new java.util.ArrayDeque<>();
+ // Paper start - replace impl with recursive safe multi entry queue
+ // it's possible to schedule multiple tasks currently, so it's vital we change this impl
+ // If we recurse into the executor again, we will append to another queue, ensuring task order consistency
+ private java.util.ArrayDeque<Runnable> queued = new java.util.ArrayDeque<>();
+ private java.util.Queue<Runnable> queue = new java.util.ArrayDeque<>(); // Paper - remove final
@Override
public void execute(Runnable runnable) {
- if (queued != null) {
- throw new IllegalStateException("Already queued");
+ if (queued == null) {
+ queued = new java.util.ArrayDeque<>();
}
- queued = runnable;
+ queued.add(runnable);
+ if (this.queue == null) {
+ this.queue = new java.util.ArrayDeque<>();
+ }
this.queue.add(runnable);
}
@Override
public void run() {
- Runnable task = queued;
+ if (queued == null) {
+ if (this.queue == null) {
+ return;
+ }
+ java.util.ArrayDeque<Runnable> queue = queued;
queued = null;
- if (task != null) {
+ Runnable task;
+ while ((task = queue.pollFirst()) != null) {
+ java.util.Queue<Runnable> queue = this.queue;
+ this.queue = null;
+ // Paper end
Runnable task;
while ((task = this.queue.poll()) != null) {
task.run();
}
}
+ // Paper end
};
// CraftBukkit end

View file

@ -12,9 +12,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
joinMessage = PaperAdventure.asVanilla(jm); // Paper - Adventure
- server.getPlayerList().broadcastAll(new ClientboundChatPacket(joinMessage, ChatType.SYSTEM, Util.NIL_UUID)); // Paper - Adventure
- this.server.getPlayerList().broadcastAll(new ClientboundChatPacket(joinMessage, ChatType.SYSTEM, Util.NIL_UUID)); // Paper - Adventure
+ // Paper start - Removed sendAll for loop and broadcasted to console also
+ server.getPlayerList().sendMessage(joinMessage); // Paper - Adventure
+ this.server.getPlayerList().broadcastMessage(joinMessage, ChatType.SYSTEM, Util.NIL_UUID); // Paper - Adventure
+ // Paper end
}
// CraftBukkit end

View file

@ -11,7 +11,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java
@@ -0,0 +0,0 @@ public class FireBlock extends BaseFireBlock {
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState newState, LevelAccessor world, BlockPos pos, BlockPos posFrom) {
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
// CraftBukkit start
+ if (!(world instanceof ServerLevel)) return this.canSurvive(state, world, pos) ? (BlockState) this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation
if (!this.canSurvive(state, world, pos)) {

View file

@ -14,12 +14,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
protected void serverAiStep() {}
protected void pushEntities() {
+ // Paper - start don't run getEntities if we're not going to use its result
+ // Paper start - don't run getEntities if we're not going to use its result
+ int i = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
+ if (i <= 0 && level.paperConfig.maxCollisionsPerEntity <= 0) {
+ return;
+ }
+ // Paper - end don't run getEntities if we're not going to use its result
+ // Paper end - don't run getEntities if we're not going to use its result
List<Entity> list = this.level.getEntities(this, this.getBoundingBox(), EntitySelector.pushableBy(this));
if (!list.isEmpty()) {

View file

@ -9,7 +9,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
return bukkitVersion;
return this.bukkitVersion;
}
+ // Paper start - expose game version

View file

@ -33,10 +33,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// CraftBukkit end
+ final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper
+
// Paper start - distance maps
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
// Paper start - no-tick view distance
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return Either.left(chunk);
});

View file

@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
});
// Paper end - per player view distance
}
- protected void addEntity(Entity entity) {
@ -52,7 +52,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
public double maxHealthCache;
public boolean joining = true;
public boolean sentListPacket = false;
@ -75,8 +75,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ mountSavedVehicle(player, worldserver1, nbttagcompound);
+ // Paper end
// CraftBukkit start
PlayerJoinEvent playerJoinEvent = new org.bukkit.event.player.PlayerJoinEvent(cserver.getPlayer(player), PaperAdventure.asAdventure(chatmessage)); // Paper - Adventure
cserver.getPluginManager().callEvent(playerJoinEvent);
PlayerJoinEvent playerJoinEvent = new org.bukkit.event.player.PlayerJoinEvent(this.cserver.getPlayer(player), PaperAdventure.asAdventure(chatmessage)); // Paper - Adventure
this.cserver.getPluginManager().callEvent(playerJoinEvent);
@@ -0,0 +0,0 @@ public abstract class PlayerList {
player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[] { entityplayer1}));
}
@ -93,57 +93,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper start - move vehicle into method so it can be called above - short circuit around that code
+ onPlayerJoinFinish(player, worldserver1, s1);
+ }
+ private void mountSavedVehicle(ServerPlayer entityplayer, ServerLevel worldserver1, CompoundTag nbttagcompound) {
+ private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) {
+ // Paper end
if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) {
CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
// CraftBukkit start
@@ -0,0 +0,0 @@ public abstract class PlayerList {
Entity entity1;
if (entity.getUUID().equals(uuid)) {
- player.startRiding(entity, true);
+ entityplayer.startRiding(entity, true);
} else {
iterator1 = entity.getIndirectPassengers().iterator();
while (iterator1.hasNext()) {
entity1 = (Entity) iterator1.next();
if (entity1.getUUID().equals(uuid)) {
- player.startRiding(entity1, true);
+ entityplayer.startRiding(entity1, true);
break;
}
}
}
- if (!player.isPassenger()) {
+ if (!entityplayer.isPassenger()) {
PlayerList.LOGGER.warn("Couldn't reattach entity to player");
worldserver1.despawn(entity);
iterator1 = entity.getIndirectPassengers().iterator();
@@ -0,0 +0,0 @@ public abstract class PlayerList {
}
}
- player.initMenu();
+ // Paper start
+ }
+ public void onPlayerJoinFinish(ServerPlayer entityplayer, ServerLevel worldserver1, String s1) {
+ public void onPlayerJoinFinish(ServerPlayer player, ServerLevel worldserver1, String s1) {
+ // Paper end
+ entityplayer.initMenu();
player.initInventoryMenu();
// CraftBukkit - Moved from above, added world
// Paper start - Add to collideRule team if needed
final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
final PlayerTeam collideRuleTeam = scoreboard.getTeam(collideRuleTeamName);
- if (this.collideRuleTeamName != null && collideRuleTeam != null && player.getTeam() == null) {
- scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
+ if (this.collideRuleTeamName != null && collideRuleTeam != null && entityplayer.getTeam() == null) {
+ scoreboard.addPlayerToTeam(entityplayer.getScoreboardName(), collideRuleTeam);
@@ -0,0 +0,0 @@ public abstract class PlayerList {
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
}
// Paper end
// CraftBukkit - Moved from above, added world
- PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.worldDataServer.getLevelName(), player.getX(), player.getY(), player.getZ());
+ PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", entityplayer.getName().getString(), s1, entityplayer.getId(), worldserver1.worldDataServer.getLevelName(), entityplayer.getX(), entityplayer.getY(), entityplayer.getZ());
+ // CraftBukkit - Moved from above, added world
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
}
public void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) {

View file

@ -19,7 +19,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
} else {
// CraftBukkit start - Capture drops for death event
if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) {
@ -34,7 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
entityitem.setDefaultPickUpDelay();
// CraftBukkit start
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
@Nullable
public Entity teleportTo(ServerLevel worldserver, BlockPos location) {
// CraftBukkit end
@ -44,10 +44,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return null;
+ }
+ // Paper end
if (this.level instanceof ServerLevel && !this.removed) {
if (this.level instanceof ServerLevel && !this.isRemoved()) {
this.level.getProfiler().push("changeDimension");
// CraftBukkit start
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
// CraftBukkit end
this.level.getProfiler().popPush("reloading");
@ -59,7 +59,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
Entity entity = this.getType().create((Level) worldserver);
if (entity != null) {
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
// CraftBukkit start - Forward the CraftEntity to the new entity
this.getBukkitEntity().setHandle(entity);
entity.bukkitEntity = this.getBukkitEntity();
@ -70,7 +70,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// CraftBukkit end
}
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
public boolean canChangeDimensions() {

View file

@ -9,6 +9,18 @@ Adds AsyncPlayerSendCommandsEvent
Adds CommandRegisteredEvent
- Allows manipulating the CommandNode to add more children/metadata for the client
diff --git a/build.gradle.kts b/build.gradle.kts
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -0,0 +0,0 @@ repositories {
dependencies {
implementation(project(":Paper-API"))
+ implementation(project(":Paper-MojangAPI"))
// Paper start
implementation("org.jline:jline-terminal-jansi:3.12.1")
implementation("net.minecrell:terminalconsoleappender:1.2.0")
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
@ -72,14 +84,14 @@ diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListener
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
+ // Paper start
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getPlayer(), suggestions, buffer);
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, buffer);
+ suggestEvent.setCancelled(suggestions.isEmpty());
+ if (!suggestEvent.callEvent()) return;
+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), (com.mojang.brigadier.suggestion.Suggestions) suggestEvent.getSuggestions())); // CraftBukkit - decompile error // Paper
@ -87,13 +99,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
});
});
}
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
completions.forEach(builder::suggest);
- player.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join()));
+ com.mojang.brigadier.suggestion.Suggestions suggestions = builder.buildFuture().join();
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getPlayer(), suggestions, buffer);
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, buffer);
+ suggestEvent.setCancelled(suggestions.isEmpty());
+ if (!suggestEvent.callEvent()) return;
+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions()));

View file

@ -53,10 +53,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -0,0 +0,0 @@ public class CraftBlock implements Block {
AABB aabb = shape.bounds();
return new BoundingBox(this.getX() + aabb.minX, this.getY() + aabb.minY, this.getZ() + aabb.minZ, this.getX() + aabb.maxX, this.getY() + aabb.maxY, this.getZ() + aabb.maxZ);
VoxelShape shape = this.getNMS().getCollisionShape(world, position);
return new CraftVoxelShape(shape);
}
+
+ // Paper start
+ @Override
+ public com.destroystokyo.paper.block.BlockSoundGroup getSoundGroup() {

View file

@ -84,67 +84,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ .toString();
+ }
+}
diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundClientInformationPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundClientInformationPacket.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundClientInformationPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundClientInformationPacket.java
@@ -0,0 +0,0 @@ public class ServerboundClientInformationPacket implements Packet<ServerGamePack
listener.handleClientInformation(this);
}
+ public ChatVisiblity getChatVisibility() { return getChatVisibility(); } // Paper - OBFHELPER
public ChatVisiblity getChatVisibility() {
return this.chatVisibility;
}
+ public boolean hasChatColorsEnabled() { return getChatColors(); } // Paper - OBFHELPER
public boolean getChatColors() {
return this.chatColors;
}
+ public int getSkinParts() { return getModelCustomisation(); } // Paper - OBFHELPER
public int getModelCustomisation() {
return this.modelCustomisation;
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ package net.minecraft.server.level;
import com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent;
import com.google.common.collect.Lists;
+import com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent; // Paper
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.DataResult;
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
public int lastSentExp = -99999999;
public int spawnInvulnerableTime = 60;
private ChatVisiblity chatVisibility;
- private boolean canChatColor = true;
+ private boolean canChatColor = true; public boolean hasChatColorsEnabled() { return this.canChatColor; } // Paper - OBFHELPER
private long lastActionTime = Util.getMillis();
private Entity camera;
public boolean isChangingDimension;
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
public String locale = null; // CraftBukkit - add, lowercase // Paper - default to null
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
public void updateOptions(ServerboundClientInformationPacket packet) {
+ new PlayerClientOptionsChangeEvent(getBukkitEntity(), packet.language, packet.viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(packet.getChatVisibility().name()), packet.hasChatColorsEnabled(), new com.destroystokyo.paper.PaperSkinParts(packet.getSkinParts()), packet.getMainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT).callEvent(); // Paper - settings event
+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(getBukkitEntity(), packet.language, packet.viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(packet.getChatVisibility().name()), packet.getChatColors(), new com.destroystokyo.paper.PaperSkinParts(packet.getModelCustomisation()), packet.getMainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT).callEvent(); // Paper - settings event
// CraftBukkit start
if (getMainArm() != packet.getMainHand()) {
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -0,0 +0,0 @@ public abstract class Player extends LivingEntity {
private static final Map<Pose, EntityDimensions> POSES = ImmutableMap.<Pose, EntityDimensions>builder().put(Pose.STANDING, Player.STANDING_DIMENSIONS).put(Pose.SLEEPING, Player.SLEEPING_DIMENSIONS).put(Pose.FALL_FLYING, EntityDimensions.scalable(0.6F, 0.6F)).put(Pose.SWIMMING, EntityDimensions.scalable(0.6F, 0.6F)).put(Pose.SPIN_ATTACK, EntityDimensions.scalable(0.6F, 0.6F)).put(Pose.CROUCHING, EntityDimensions.scalable(0.6F, 1.5F)).put(Pose.DYING, EntityDimensions.fixed(0.2F, 0.2F)).build();
private static final int FLY_ACHIEVEMENT_SPEED = 25;
private static final EntityDataAccessor<Float> DATA_PLAYER_ABSORPTION_ID = SynchedEntityData.defineId(Player.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Integer> DATA_SCORE_ID = SynchedEntityData.defineId(Player.class, EntityDataSerializers.INT);
- protected static final EntityDataAccessor<Byte> DATA_PLAYER_MODE_CUSTOMISATION = SynchedEntityData.defineId(Player.class, EntityDataSerializers.BYTE);
+ protected static final EntityDataAccessor<Byte> DATA_PLAYER_MODE_CUSTOMISATION = SynchedEntityData.defineId(Player.class, EntityDataSerializers.BYTE); public static EntityDataAccessor<Byte> getSkinPartsWatcher() { return DATA_PLAYER_MODE_CUSTOMISATION; } // Paper - OBFHELPER
+ public static final EntityDataAccessor<Byte> DATA_PLAYER_MODE_CUSTOMISATION = SynchedEntityData.defineId(Player.class, EntityDataSerializers.BYTE); // Paper - protected -> public
protected static final EntityDataAccessor<Byte> DATA_PLAYER_MAIN_HAND = SynchedEntityData.defineId(Player.class, EntityDataSerializers.BYTE);
protected static final EntityDataAccessor<CompoundTag> DATA_SHOULDER_LEFT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
protected static final EntityDataAccessor<CompoundTag> DATA_SHOULDER_RIGHT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
@ -152,37 +113,28 @@ diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -0,0 +0,0 @@
package org.bukkit.craftbukkit.entity;
+import com.destroystokyo.paper.ClientOption.ChatVisibility;
+import com.destroystokyo.paper.PaperSkinParts;
+import com.destroystokyo.paper.ClientOption;
import com.destroystokyo.paper.Title;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
public void setViewDistance(int viewDistance) {
throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
}
+
+ @Override
+ public <T> T getClientOption(ClientOption<T> type) {
+ if(ClientOption.SKIN_PARTS.equals(type)) {
+ return type.getType().cast(new PaperSkinParts(getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.getSkinPartsWatcher())));
+ } else if(ClientOption.CHAT_COLORS_ENABLED.equals(type)) {
+ return type.getType().cast(getHandle().hasChatColorsEnabled());
+ } else if(ClientOption.CHAT_VISIBILITY.equals(type)) {
+ return type.getType().cast(getHandle().getChatVisibility() == null ? ChatVisibility.UNKNOWN : ChatVisibility.valueOf(getHandle().getChatVisibility().name()));
+ } else if(ClientOption.LOCALE.equals(type)) {
+ public <T> T getClientOption(com.destroystokyo.paper.ClientOption<T> type) {
+ if(com.destroystokyo.paper.ClientOption.SKIN_PARTS.equals(type)) {
+ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION)));
+ } else if(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED.equals(type)) {
+ return type.getType().cast(getHandle().canChatInColor());
+ } else if(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY.equals(type)) {
+ return type.getType().cast(getHandle().getChatVisibility() == null ? com.destroystokyo.paper.ClientOption.ChatVisibility.UNKNOWN : com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(getHandle().getChatVisibility().name()));
+ } else if(com.destroystokyo.paper.ClientOption.LOCALE.equals(type)) {
+ return type.getType().cast(getLocale());
+ } else if(ClientOption.MAIN_HAND.equals(type)) {
+ } else if(com.destroystokyo.paper.ClientOption.MAIN_HAND.equals(type)) {
+ return type.getType().cast(getMainHand());
+ } else if(ClientOption.VIEW_DISTANCE.equals(type)) {
+ } else if(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE.equals(type)) {
+ return type.getType().cast(getClientViewDistance());
+ }
+ throw new RuntimeException("Unknown settings type");
+ }
// Paper end
// Spigot start
@Override

View file

@ -70,25 +70,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
while (cause instanceof CompletionException && cause.getCause() != null) {
cause = cause.getCause();
}
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -0,0 +0,0 @@ public class Util {
return Util.IO_POOL;
}
+ public static void shutdownServerThreadPool() { shutdownExecutors(); } // Paper - OBFHELPER
public static void shutdownExecutors() {
shutdownExecutor(Util.BACKGROUND_EXECUTOR);
shutdownExecutor(Util.IO_POOL);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
public int autosavePeriod;
public boolean serverAutoSave = false; // Paper
public Commands vanillaCommandDispatcher;
- private boolean forceTicks;
+ public boolean forceTicks; // Paper
@ -112,10 +100,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ public volatile boolean hasFullyShutdown = false; // Paper
private final Object stopLock = new Object();
public final boolean hasStopped() {
synchronized (stopLock) {
synchronized (this.stopLock) {
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (hasStopped) return;
hasStopped = true;
if (this.hasStopped) return;
this.hasStopped = true;
}
+ // Paper start - kill main thread, and kill it hard
+ shutdownThread = Thread.currentThread();
@ -128,24 +116,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ Thread.sleep(1);
+ } catch (InterruptedException e) {}
+ }
+ // We've just obliterated the main thread, this will prevent stop from dying when removing players
+ MinecraftServer.getServer().getAllLevels().forEach(world -> {
+ world.tickingEntities = false;
+ });
+ }
+ // Paper end
// CraftBukkit end
MinecraftServer.LOGGER.info("Stopping server");
MinecraftTimings.stopServer(); // Paper
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.getProfileCache().b(false); // Paper
this.getProfileCache().save(false); // Paper
}
// Spigot end
+ // Paper start - move final shutdown items here
+ LOGGER.info("Flushing Chunk IO");
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper
+ LOGGER.info("Closing Thread Pool");
+ Util.shutdownServerThreadPool(); // Paper
+ Util.shutdownExecutors(); // Paper
+ LOGGER.info("Closing Server");
+ try {
+ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
@ -237,7 +221,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Spigot End
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.packRepository.setSelected(datapacks);
this.worldData.setDataPackConfig(getSelectedPacks(this.packRepository));
this.worldData.setDataPackConfig(MinecraftServer.getSelectedPacks(this.packRepository));
datapackresources.updateGlobals();
- this.getPlayerList().saveAll();
+ if (Thread.currentThread() != this.serverThread) return; // Paper
@ -289,25 +273,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
mutableboolean.setFalse();
list.stream().map((playerchunk) -> {
CompletableFuture completablefuture;
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -0,0 +0,0 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
private final Queue<Entity> toAddAfterTick = Queues.newArrayDeque();
public final List<ServerPlayer> players = Lists.newArrayList(); // Paper - private -> public
public final ServerChunkCache chunkSource; // Paper - public
- boolean tickingEntities;
+ public boolean tickingEntities; // Paper - expose for watchdog
// Paper start
List<java.lang.Runnable> afterEntityTickingTasks = Lists.newArrayList();
public void doIfNotEntityTicking(java.lang.Runnable run) {
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -0,0 +0,0 @@ public abstract class PlayerList {
cserver.getPluginManager().callEvent(playerQuitEvent);
this.cserver.getPluginManager().callEvent(playerQuitEvent);
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
- entityplayer.doTick(); // SPIGOT-924
@ -319,26 +290,18 @@ diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/s
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
@@ -0,0 +0,0 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Processo
@@ -0,0 +0,0 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
try {
task.run();
} catch (Exception exception) {
+ if (exception.getCause() instanceof ThreadDeath) throw exception; // Paper
BlockableEventLoop.LOGGER.fatal("Error executing task on {}", this.name(), exception);
} catch (Exception var3) {
+ if (var3.getCause() instanceof ThreadDeath) throw var3; // Paper
LOGGER.fatal("Error executing task on {}", this.name(), var3);
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
gameprofilerfiller.pop();
} catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
// Paper start - Prevent tile entity and entity crashes
String msg = "TileEntity threw exception at " + tileentity.getLevel().getWorld().getName() + ":" + tileentity.getBlockPos().getX() + "," + tileentity.getBlockPos().getY() + "," + tileentity.getBlockPos().getZ();
System.err.println(msg);
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
try {
tickConsumer.accept(entity);
@ -347,6 +310,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Paper start - Prevent tile entity and entity crashes
String msg = "Entity threw exception at " + entity.level.getWorld().getName() + ":" + entity.getX() + "," + entity.getY() + "," + entity.getZ();
System.err.println(msg);
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
gameprofilerfiller.pop();
} catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
// Paper start - Prevent tile entity and entity crashes
String msg = "TileEntity threw exception at " + LevelChunk.this.getLevel().getWorld().getName() + ":" + this.getPos().getX() + "," + this.getPos().getY() + "," + this.getPos().getZ();
System.err.println(msg);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@ -496,7 +471,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
+ server.forceTicks = true;
server.close();
this.server.close();
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
@ -535,19 +510,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private boolean restart;
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
{
if ( instance == null )
if ( WatchdogThread.instance == null )
{
+ if (timeoutTime <= 0) timeoutTime = 300; // Paper
instance = new WatchdogThread( timeoutTime * 1000L, restart );
instance.start();
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
WatchdogThread.instance.start();
} else
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
// Paper start
Logger log = Bukkit.getServer().getLogger();
long currentTime = monotonicMillis();
- if ( lastTick != 0 && timeoutTime > 0 && currentTime > lastTick + earlyWarningEvery && !Boolean.getBoolean("disable.watchdog") )
long currentTime = WatchdogThread.monotonicMillis();
- if ( this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
+ MinecraftServer server = MinecraftServer.getServer();
+ if (lastTick != 0 && timeoutTime > 0 && hasStarted && (!server.isRunning() || (currentTime > lastTick + earlyWarningEvery && !DISABLE_WATCHDOG) ))
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.hasStarted && (!server.isRunning() || (currentTime > this.lastTick + this.earlyWarningEvery && !DISABLE_WATCHDOG) )) // Paper - add property to disable
{
- boolean isLongTimeout = currentTime > lastTick + timeoutTime;
+ boolean isLongTimeout = currentTime > lastTick + timeoutTime || (!server.isRunning() && !server.hasStopped() && currentTime > lastTick + 1000);
@ -561,9 +536,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
log.log( Level.SEVERE, "------------------------------" );
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
- dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
+ dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( server.serverThread.getId(), Integer.MAX_VALUE ), log );
com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
- WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
+ WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( server.serverThread.getId(), Integer.MAX_VALUE ), log );
log.log( Level.SEVERE, "------------------------------" );
//
// Paper start - Only print full dump on long timeouts
@ -571,7 +546,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
if ( isLongTimeout )
{
- if ( restart && !MinecraftServer.getServer().hasStopped() )
- if ( this.restart && !MinecraftServer.getServer().hasStopped() )
+ if ( !server.hasStopped() )
{
- RestartCommand.restart();

View file

@ -4,19 +4,6 @@ Date: Sun, 19 Apr 2020 04:28:29 -0400
Subject: [PATCH] Load Chunks for Login Asynchronously
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
public final ChunkProgressListener progressListener;
- public final ChunkMap.ChunkDistanceManager distanceManager;
+ public final ChunkMap.ChunkDistanceManager distanceManager; public final DistanceManager getChunkDistanceManager() { return this.distanceManager; } // Paper - OBFHELPER
private final AtomicInteger tickingGenerated;
public final StructureManager structureManager; // Paper - private -> public
private final File storageFolder;
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@ -25,8 +12,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
return this.mainThreadProcessor.pollTask();
}
- private boolean runDistanceManagerUpdates() {
+ public boolean runDistanceManagerUpdates() { // Paper - private -> public
- boolean runDistanceManagerUpdates() {
+ public boolean runDistanceManagerUpdates() { // Paper - packate-private -> public
boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
boolean flag1 = this.chunkMap.promoteChunkMap();
@ -34,23 +21,15 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
+import net.minecraft.network.Connection;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.HoverEvent;
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
private static final Logger LOGGER = LogManager.getLogger();
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
public ServerGamePacketListenerImpl connection;
+ public Connection networkManager; // Paper
+ public net.minecraft.network.Connection networkManager; // Paper
public final MinecraftServer server;
public final ServerPlayerGameMode gameMode;
public final Deque<Integer> removeQueue = new ArrayDeque<>(); // Paper
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
private final PlayerAdvancements advancements;
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
public boolean joining = true;
public boolean sentListPacket = false;
public boolean supressTrackerForLogin = false; // Paper
@ -63,26 +42,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/level/TicketType.java
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
@@ -0,0 +0,0 @@ public class TicketType<T> {
public static final TicketType<ChunkPos> FORCED = create("forced", Comparator.comparingLong(ChunkPos::toLong));
public static final TicketType<ChunkPos> LIGHT = create("light", Comparator.comparingLong(ChunkPos::toLong));
public static final TicketType<BlockPos> PORTAL = create("portal", Vec3i::compareTo, 300);
public static final TicketType<ChunkPos> FORCED = TicketType.create("forced", Comparator.comparingLong(ChunkPos::toLong));
public static final TicketType<ChunkPos> LIGHT = TicketType.create("light", Comparator.comparingLong(ChunkPos::toLong));
public static final TicketType<BlockPos> PORTAL = TicketType.create("portal", Vec3i::compareTo, 300);
+ public static final TicketType<Long> LOGIN = create("login", Long::compareTo, 100); // Paper
public static final TicketType<Integer> POST_TELEPORT = create("post_teleport", Integer::compareTo, 5);
public static final TicketType<ChunkPos> UNKNOWN = create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
public static final TicketType<Unit> PLUGIN = create("plugin", (a, b) -> 0); // CraftBukkit
public static final TicketType<Integer> POST_TELEPORT = TicketType.create("post_teleport", Integer::compareTo, 5);
public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
private static final Logger LOGGER = LogManager.getLogger();
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
private static final int LATENCY_CHECK_INTERVAL = 15000;
public final Connection connection;
private final MinecraftServer server;
+ public Runnable playerJoinReady; // Paper
public ServerPlayer player;
private int tickCount;
private long keepAliveTime = Util.getMillis(); private void setLastPing(long lastPing) { this.keepAliveTime = lastPing;}; private long getLastPing() { return this.keepAliveTime;}; // Paper - OBFHELPER
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
private long keepAliveTime = Util.getMillis();
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
// CraftBukkit end
public void tick() {
@ -98,7 +77,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
this.resetPosition();
this.player.xo = this.player.getX();
this.player.yo = this.player.getY();
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
this.lastVehicle = null;
this.clientVehicleIsFloating = false;
this.aboveGroundVehicleTickCount = 0;
@ -127,8 +106,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId());
+ ServerPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.gameProfile.getId()); // Paper
if (entityplayer != null) {
this.state = ServerLoginPacketListenerImpl.State.DELAY_ACCEPT;
try {
ServerPlayer entityplayer1 = this.server.getPlayerList().processLogin(this.gameProfile, s); // CraftBukkit - add player reference
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
@ -140,16 +119,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import net.minecraft.network.protocol.game.ClientboundDisconnectPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
@@ -0,0 +0,0 @@ import net.minecraft.server.MCUtil;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerAdvancements;
import net.minecraft.server.ServerScoreboard;
+import net.minecraft.server.level.ChunkHolder;
+import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket;
@@ -0,0 +0,0 @@ public abstract class PlayerList {
private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
private final MinecraftServer server;
@ -193,12 +163,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ ServerLevel finalWorldserver = worldserver1;
+ int chunkX = loc.getBlockX() >> 4;
+ int chunkZ = loc.getBlockZ() >> 4;
+ final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
+ ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap;
+ playerChunkMap.getChunkDistanceManager().addTicketAtLevel(TicketType.LOGIN, pos, 31, pos.toLong());
+ final net.minecraft.world.level.ChunkPos pos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ);
+ net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap;
+ net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager;
+ distanceManager.addTicketAtLevel(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong());
+ worldserver1.getChunkSource().runDistanceManagerUpdates();
+ worldserver1.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, true).thenApply(chunk -> {
+ ChunkHolder updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong());
+ net.minecraft.server.level.ChunkHolder updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong());
+ if (updatingChunk != null) {
+ return updatingChunk.getEntityTickingFuture();
+ } else {
@ -227,126 +198,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ });
+ }
+
+ private void postChunkLoadJoin(ServerPlayer entityplayer, ServerLevel worldserver1, Connection networkmanager, ServerGamePacketListenerImpl playerconnection, CompoundTag nbttagcompound, String s1, String s) {
+ pendingPlayers.remove(entityplayer.getUUID(), entityplayer);
+ private void postChunkLoadJoin(ServerPlayer player, ServerLevel worldserver1, Connection networkmanager, ServerGamePacketListenerImpl playerconnection, CompoundTag nbttagcompound, String s1, String s) {
+ pendingPlayers.remove(player.getUUID(), player);
+ if (!networkmanager.isConnected()) {
+ return;
+ }
+ entityplayer.didPlayerJoinEvent = true;
+ player.didPlayerJoinEvent = true;
+ // Paper end
TranslatableComponent chatmessage;
- if (player.getGameProfile().getName().equalsIgnoreCase(s)) {
- chatmessage = new TranslatableComponent("multiplayer.player.joined", new Object[]{player.getDisplayName()});
+ if (entityplayer.getGameProfile().getName().equalsIgnoreCase(s)) {
+ chatmessage = new TranslatableComponent("multiplayer.player.joined", new Object[]{entityplayer.getDisplayName()});
} else {
- chatmessage = new TranslatableComponent("multiplayer.player.joined.renamed", new Object[]{player.getDisplayName(), s});
+ chatmessage = new TranslatableComponent("multiplayer.player.joined.renamed", new Object[]{entityplayer.getDisplayName(), s});
}
// CraftBukkit start
chatmessage.withStyle(ChatFormatting.YELLOW);
Component joinMessage = chatmessage; // Paper - Adventure
- playerconnection.teleport(player.getX(), player.getY(), player.getZ(), player.yRot, player.xRot);
- this.players.add(player);
- this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Spigot
- this.playersByUUID.put(player.getUUID(), player);
+ playerconnection.teleport(entityplayer.getX(), entityplayer.getY(), entityplayer.getZ(), entityplayer.yRot, entityplayer.xRot);
+ this.players.add(entityplayer);
+ this.playersByName.put(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT), entityplayer); // Spigot
+ this.playersByUUID.put(entityplayer.getUUID(), entityplayer);
// this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below
// Paper start - correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks
- player.supressTrackerForLogin = true;
- worldserver1.addNewPlayer(player);
- this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer);
- mountSavedVehicle(player, worldserver1, nbttagcompound);
+ entityplayer.supressTrackerForLogin = true;
+ worldserver1.addNewPlayer(entityplayer);
+ this.server.getCustomBossEvents().onPlayerConnect(entityplayer); // see commented out section below worldserver.addPlayerJoin(entityplayer);
+ mountSavedVehicle(entityplayer, worldserver1, nbttagcompound);
// Paper end
// CraftBukkit start
- PlayerJoinEvent playerJoinEvent = new org.bukkit.event.player.PlayerJoinEvent(cserver.getPlayer(player), PaperAdventure.asAdventure(chatmessage)); // Paper - Adventure
+ PlayerJoinEvent playerJoinEvent = new org.bukkit.event.player.PlayerJoinEvent(cserver.getPlayer(entityplayer), PaperAdventure.asAdventure(chatmessage)); // Paper - Adventure
cserver.getPluginManager().callEvent(playerJoinEvent);
- if (!player.connection.connection.isConnected()) {
+ if (!entityplayer.connection.connection.isConnected()) {
return;
}
@@ -0,0 +0,0 @@ public abstract class PlayerList {
// CraftBukkit end
// CraftBukkit start - sendAll above replaced with this loop
- ClientboundPlayerInfoPacket packet = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, player);
+ ClientboundPlayerInfoPacket packet = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, entityplayer);
for (int i = 0; i < this.players.size(); ++i) {
ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i);
- if (entityplayer1.getBukkitEntity().canSee(player.getBukkitEntity())) {
+ if (entityplayer1.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) {
entityplayer1.connection.send(packet);
}
- if (!player.getBukkitEntity().canSee(entityplayer1.getBukkitEntity())) {
+ if (!entityplayer.getBukkitEntity().canSee(entityplayer1.getBukkitEntity())) {
continue;
}
- player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[] { entityplayer1}));
+ entityplayer.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[] { entityplayer1}));
}
- player.sentListPacket = true;
- player.supressTrackerForLogin = false; // Paper
- ((ServerLevel)player.level).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now
+ entityplayer.sentListPacket = true;
+ entityplayer.supressTrackerForLogin = false; // Paper
+ ((ServerLevel)entityplayer.level).getChunkSource().chunkMap.addEntity(entityplayer); // Paper - track entity now
// CraftBukkit end
- player.connection.send(new ClientboundSetEntityDataPacket(player.getId(), player.getEntityData(), true)); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
+ entityplayer.connection.send(new ClientboundSetEntityDataPacket(entityplayer.getId(), entityplayer.getEntityData(), true)); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
// CraftBukkit start - Only add if the player wasn't moved in the event
- if (player.level == worldserver1 && !worldserver1.players().contains(player)) {
- worldserver1.addNewPlayer(player);
- this.server.getCustomBossEvents().onPlayerConnect(player);
+ if (entityplayer.level == worldserver1 && !worldserver1.players().contains(entityplayer)) {
+ worldserver1.addNewPlayer(entityplayer);
+ this.server.getCustomBossEvents().onPlayerConnect(entityplayer);
}
- worldserver1 = player.getLevel(); // CraftBukkit - Update in case join event changed it
+ worldserver1 = entityplayer.getLevel(); // CraftBukkit - Update in case join event changed it
// CraftBukkit end
- this.sendLevelInfo(player, worldserver1);
+ this.sendLevelInfo(entityplayer, worldserver1);
if (!this.server.getResourcePack().isEmpty()) {
- player.sendTexturePack(this.server.getResourcePack(), this.server.getResourcePackHash());
+ entityplayer.sendTexturePack(this.server.getResourcePack(), this.server.getResourcePackHash());
}
- Iterator iterator = player.getActiveEffects().iterator();
+ Iterator iterator = entityplayer.getActiveEffects().iterator();
while (iterator.hasNext()) {
MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
- playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect));
+ playerconnection.send(new ClientboundUpdateMobEffectPacket(entityplayer.getId(), mobeffect));
}
// Paper start - move vehicle into method so it can be called above - short circuit around that code
- onPlayerJoinFinish(player, worldserver1, s1);
+ onPlayerJoinFinish(entityplayer, worldserver1, s1);
}
private void mountSavedVehicle(ServerPlayer entityplayer, ServerLevel worldserver1, CompoundTag nbttagcompound) {
// Paper end
if (player.getGameProfile().getName().equalsIgnoreCase(s)) {
@@ -0,0 +0,0 @@ public abstract class PlayerList {
protected void save(ServerPlayer player) {
@ -358,9 +219,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public abstract class PlayerList {
}
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(entityplayer), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())));
- cserver.getPluginManager().callEvent(playerQuitEvent);
+ if (entityplayer.didPlayerJoinEvent) cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(this.cserver.getPlayer(entityplayer), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())));
- this.cserver.getPluginManager().callEvent(playerQuitEvent);
+ if (entityplayer.didPlayerJoinEvent) this.cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog)
@ -379,7 +240,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// CraftBukkit start
// this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
@@ -0,0 +0,0 @@ public abstract class PlayerList {
cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
// CraftBukkit end
- return playerQuitEvent.quitMessage(); // Paper - Adventure
@ -405,12 +266,12 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.yo = y;
this.zo = d4;
this.setPos(d3, y, d4);
- level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit
+ if (valid) level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit // Paper
- this.level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit
+ if (valid) this.level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit // Paper
}
public void moveTo(Vec3 vec3d) {
public void moveTo(Vec3 pos) {

View file

@ -10,7 +10,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
bworld = server.getWorld(worldName);
}
@ -23,5 +23,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+// }
+ // Paper end - Move player to spawn point if spawn in unloaded world
setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle());
((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle());
}

View file

@ -9,27 +9,16 @@ diff --git a/src/main/java/net/minecraft/util/SortedArraySet.java b/src/main/jav
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/SortedArraySet.java
+++ b/src/main/java/net/minecraft/util/SortedArraySet.java
@@ -0,0 +0,0 @@ import java.util.NoSuchElementException;
public class SortedArraySet<T> extends AbstractSet<T> {
private final Comparator<T> comparator;
- private T[] contents;
- private int size;
+ private T[] contents; private final T[] getBackingArray() { return this.contents; } // Paper - OBFHELPER
+ private int size; private final int getSize() { return this.size; } private final void setSize(int value) { this.size = value; } // Paper - OBFHELPER
private SortedArraySet(int initialCapacity, Comparator<T> comparator) {
this.comparator = comparator;
@@ -0,0 +0,0 @@ public class SortedArraySet<T> extends AbstractSet<T> {
this.contents = (T[])castRawArray(new Object[initialCapacity]);
}
}
+ // Paper start - optimise removeIf
+ @Override
+ public boolean removeIf(java.util.function.Predicate<? super T> filter) {
+ // prev. impl used an iterator, which could be n^2 and creates garbage
+ int i = 0, len = this.getSize();
+ T[] backingArray = this.getBackingArray();
+ int i = 0, len = this.size;
+ T[] backingArray = this.contents;
+
+ for (;;) {
+ if (i >= len) {
@ -55,11 +44,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ // cleanup end
+ Arrays.fill(backingArray, lastIndex, len, null);
+ this.setSize(lastIndex);
+ this.size = lastIndex;
+ return true;
+ }
+ // Paper end - optimise removeIf
+
public static <T extends Comparable<T>> SortedArraySet<T> create(int initialCapacity) {
return new SortedArraySet<>(initialCapacity, (Comparator)Comparator.naturalOrder()); // Paper - decompile fix
}
public static <T extends Comparable<T>> SortedArraySet<T> create() {
return create(10);

View file

@ -10,23 +10,6 @@ diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigati
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
@@ -0,0 +0,0 @@ import net.minecraft.core.Position;
import net.minecraft.core.Vec3i;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.server.MCUtil;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
protected final Mob mob; public Entity getEntity() { return mob; } // Paper - OBFHELPER
protected final Level level;
@Nullable
- protected Path path;
+ protected Path path; protected final Path getCurrentPath() { return this.path; } // Paper - OBFHELPER
protected double speedModifier;
protected int tick;
protected int lastStuckCheck;
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
return this.moveTo(this.createPath(x, y, z, 1), speed);
}
@ -38,21 +21,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
public boolean moveTo(Entity entity, double speed) {
+ // Paper start - Pathfinding optimizations
+ if (this.pathfindFailures > 10 && this.getCurrentPath() == null && MinecraftServer.currentTick < this.lastFailure + 40) {
+ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) {
+ return false;
+ }
+ // Paper end
Path pathentity = this.createPath(entity, 1);
- return pathentity != null && this.moveTo(pathentity, speed);
Path path = this.createPath(entity, 1);
- return path != null && this.moveTo(path, speed);
+ // Paper start - Pathfinding optimizations
+ if (pathentity != null && this.moveTo(pathentity, speed)) {
+ if (path != null && this.moveTo(path, speed)) {
+ this.lastFailure = 0;
+ this.pathfindFailures = 0;
+ return true;
+ } else {
+ this.pathfindFailures++;
+ this.lastFailure = MinecraftServer.currentTick;
+ this.lastFailure = net.minecraft.server.MinecraftServer.currentTick;
+ return false;
+ }
+ // Paper end

View file

@ -0,0 +1,121 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 3 May 2020 22:35:09 -0400
Subject: [PATCH] Optimize Voxel Shape Merging
This method shows up as super hot in profiler, and also a high "self" time.
Upon analyzing, it appears most usages of this method fall down to the final
else statement of the nasty ternary.
Upon even further analyzation, it appears then the majority of those have a
consistent list 1.... One with Infinity head and Tails.
First optimization is to detect these infinite states and immediately return that
VoxelShapeMergerList so we can avoid testing the rest for most cases.
Break the method into 2 to help the JVM promote inlining of this fast path.
Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot
with a high self time...
Well, knowing that in most cases our list 1 is actualy the same value, it allows
us to know that with an infinite list1, the result on the merger is essentially
list2 as the final values.
This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources)
and compute a deterministic result for the MergerList values.
Additionally, this lets us avoid even allocating new objects for this too, further
reducing memory usage.
diff --git a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
@@ -0,0 +0,0 @@ public class IndirectMerger implements IndexMerger {
private final int[] firstIndices;
private final int[] secondIndices;
private final int resultLength;
+ // Paper start
+ private static final int[] INFINITE_B_1 = new int[]{1, 1};
+ private static final int[] INFINITE_B_0 = new int[]{0, 0};
+ private static final int[] INFINITE_C = new int[]{0, 1};
+ // Paper end
public IndirectMerger(DoubleList first, DoubleList second, boolean includeFirstOnly, boolean includeSecondOnly) {
double d = Double.NaN;
int i = first.size();
int j = second.size();
int k = i + j;
+ // Paper start - optimize common path of infinity doublelist
+ int size = first.size();
+ double tail = first.getDouble(size - 1);
+ double head = first.getDouble(0);
+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !includeFirstOnly && !includeSecondOnly && (size == 2 || size == 4)) {
+ this.result = second.toDoubleArray();
+ this.resultLength = second.size();
+ if (size == 2) {
+ this.firstIndices = INFINITE_B_0;
+ } else {
+ this.firstIndices = INFINITE_B_1;
+ }
+ this.secondIndices = INFINITE_C;
+ return;
+ }
+ // Paper end
this.result = new double[k];
this.firstIndices = new int[k];
this.secondIndices = new int[k];
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
@@ -0,0 +0,0 @@ public final class Shapes {
}
@VisibleForTesting
- protected static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
+ private static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { // Paper - private
+ // Paper start - fast track the most common scenario
+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause
+ // This is actually the most common path, so jump to it straight away
+ if (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) {
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
+ }
+ // Split out rest to hopefully inline the above
+ return lessCommonMerge(size, first, second, includeFirst, includeSecond);
+ }
+
+ private static IndexMerger lessCommonMerge(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
int i = first.size() - 1;
int j = second.size() - 1;
+ // Paper note - Rewrite below as optimized order if instead of nasty ternary
if (first instanceof CubePointRange && second instanceof CubePointRange) {
long l = lcm(i, j);
if ((long)size * l <= 256L) {
@@ -0,0 +0,0 @@ public final class Shapes {
}
}
- if (first.getDouble(i) < second.getDouble(0) - 1.0E-7D) {
+ // Paper start - Identical happens more often than Disjoint
+ if (i == j && Objects.equals(first, second)) {
+ if (first instanceof IdenticalMerger) {
+ return (IndexMerger) first;
+ } else if (second instanceof IdenticalMerger) {
+ return (IndexMerger) second;
+ }
+ return new IdenticalMerger(first);
+ } else if (first.getDouble(i) < second.getDouble(0) - 1.0E-7D) {
return new NonOverlappingMerger(first, second, false);
} else if (second.getDouble(j) < first.getDouble(0) - 1.0E-7D) {
return new NonOverlappingMerger(second, first, true);
} else {
- return (IndexMerger)(i == j && Objects.equals(first, second) ? new IdenticalMerger(first) : new IndirectMerger(first, second, includeFirst, includeSecond));
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
}
+ // Paper end
}
public interface DoubleLineConsumer {

View file

@ -8,7 +8,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
containerUpdateDelay = level.paperConfig.containerUpdateTickRate;
}
// Paper end
@ -17,24 +17,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
this.containerMenu = this.inventoryMenu;
}
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
} else {
// CraftBukkit start
this.containerMenu = container;
- this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle()));
+ if (!isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper
// CraftBukkit end
container.addSlotListener(this);
this.initMenu(container);
return OptionalInt.of(this.containerCounter);
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player implements ContainerListener {
}
@Override
- protected boolean isImmobile() {
+ public boolean isImmobile() { // Paper - protected > public
return super.isImmobile() || (this.connection != null && this.connection.isDisconnected()); // Paper
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
@ -45,8 +36,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
//player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, windowType, CraftChatMessage.fromString(title)[0])); // Paper // Paper - comment
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
getHandle().containerMenu = container;
getHandle().containerMenu.addSlotListener(player);
player.containerMenu = container;
player.initMenu(container);
}
@@ -0,0 +0,0 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper
@ -55,5 +46,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
player.containerMenu = container;
player.containerMenu.addSlotListener(player);
player.initMenu(container);
}

View file

@ -114,14 +114,14 @@ diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java b/sr
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
@@ -0,0 +0,0 @@ import org.bukkit.entity.EntityType;
@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.Skeleton.SkeletonType;
-public class CraftSkeleton extends CraftMonster implements Skeleton {
+public class CraftSkeleton extends CraftMonster implements Skeleton, com.destroystokyo.paper.entity.CraftRangedEntity<AbstractSkeleton> { // Paper
-public class CraftSkeleton extends CraftAbstractSkeleton implements Skeleton {
+public class CraftSkeleton extends CraftAbstractSkeleton implements Skeleton, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.AbstractSkeleton> { // Paper
public CraftSkeleton(CraftServer server, AbstractSkeleton entity) {
public CraftSkeleton(CraftServer server, net.minecraft.world.entity.monster.Skeleton entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644

View file

@ -11,29 +11,21 @@ diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/ne
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
@@ -0,0 +0,0 @@ import net.minecraft.ReportedException;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; // Paper
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -0,0 +0,0 @@ public class CompoundTag implements Tag {
if (i > 512) {
throw new RuntimeException("Tried to read NBT tag with too high complexity, depth > 512");
} else {
- HashMap hashmap = Maps.newHashMap();
+ Object2ObjectOpenHashMap<String, Tag> hashmap = new Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - reduce memory footprint of NBTTagCompound
byte b0;
- Map<String, Tag> map = Maps.newHashMap();
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - reduce memory footprint of NBTTagCompound
byte b;
while((b = CompoundTag.readNamedTagType(dataInput, nbtAccounter)) != 0) {
@@ -0,0 +0,0 @@ public class CompoundTag implements Tag {
}
public CompoundTag() {
- this(Maps.newHashMap());
+ this(new Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - reduce memory footprint of NBTTagCompound
+ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - reduce memory footprint of NBTTagCompound
}
@Override
@ -42,11 +34,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@Override
public CompoundTag copy() {
- Map<String, Tag> map = Maps.newHashMap(Maps.transformValues(this.tags, Tag::copy));
+ // Paper start - reduce memory footprint of NBTTagCompound
+ Object2ObjectOpenHashMap<String, Tag> ret = new Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f);
- return new CompoundTag(map);
+ Iterator<Map.Entry<String, Tag>> iterator = (this.tags instanceof Object2ObjectOpenHashMap) ? ((Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator();
+ // Paper start - reduce memory footprint of NBTTagCompound
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f);
+ java.util.Iterator<java.util.Map.Entry<String, Tag>> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry<String, Tag> entry = iterator.next();
+ ret.put(entry.getKey(), entry.getValue().copy());
@ -56,4 +47,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - reduce memory footprint of NBTTagCompound
}
public boolean equals(Object object) {
@Override

View file

@ -13,22 +13,18 @@ diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/ma
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
@@ -0,0 +0,0 @@
package net.minecraft.world.entity.ai.goal;
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet; // Paper - remove streams from pathfindergoalselector
@@ -0,0 +0,0 @@ package net.minecraft.world.entity.ai.goal;
import java.util.EnumSet;
public abstract class Goal {
- private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class);
+ private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
+ private final OptimizedSmallEnumSet<Flag> goalTypes = new OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
+ private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
public Goal() {}
public abstract boolean canUse();
@@ -0,0 +0,0 @@ public abstract class Goal {
public void tick() {}
}
public void setFlags(EnumSet<Goal.Flag> controls) {
- this.flags.clear();
@ -39,7 +35,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - remove streams from pathfindergoalselector
}
public String toString() {
@Override
@@ -0,0 +0,0 @@ public abstract class Goal {
return this.getClass().getSimpleName();
}
@ -56,39 +53,32 @@ diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -0,0 +0,0 @@
package net.minecraft.world.entity.ai.goal;
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet; // Paper - remove streams from pathfindergoalselector
import com.google.common.collect.Sets;
import java.util.EnumMap;
import java.util.EnumSet;
+import java.util.Iterator; // Paper - remove streams from pathfindergoalselector
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
@@ -0,0 +0,0 @@ public class GoalSelector {
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap(Goal.Flag.class);
private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet(); private Set<WrappedGoal> getTasks() { return availableGoals; }// Paper - OBFHELPER
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
private final Supplier<ProfilerFiller> profiler;
- private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
+ private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
+ private final OptimizedSmallEnumSet<Goal.Flag> goalTypes = new OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
private int newGoalRate = 3;private int getTickRate() { return newGoalRate; } // Paper - OBFHELPER
private int curRate;private int getCurRate() { return curRate; } private void incRate() { this.curRate++; } // Paper TODO
+ private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
private int tickCount;
private int newGoalRate = 3;
private int curRate;
+ private static final Goal.Flag[] PATHFINDER_GOAL_TYPES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
public GoalSelector(Supplier<ProfilerFiller> profiler) {
this.profiler = profiler;
@@ -0,0 +0,0 @@ public class GoalSelector {
}
// Paper end
public void removeGoal(Goal goal) {
- this.availableGoals.stream().filter((pathfindergoalwrapped) -> {
- return pathfindergoalwrapped.getGoal() == goal;
- this.availableGoals.stream().filter((wrappedGoal) -> {
- return wrappedGoal.getGoal() == goal;
- }).filter(WrappedGoal::isRunning).forEach(WrappedGoal::stop);
- this.availableGoals.removeIf((pathfindergoalwrapped) -> {
- return pathfindergoalwrapped.getGoal() == goal;
- this.availableGoals.removeIf((wrappedGoal) -> {
- return wrappedGoal.getGoal() == goal;
- });
+ // Paper start - remove streams from pathfindergoalselector
+ for (Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ WrappedGoal goalWrapped = iterator.next();
+ if (goalWrapped.getGoal() != goal) {
+ continue;
@ -101,76 +91,57 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - remove streams from pathfindergoalselector
}
+ private static final Goal.Flag[] PATHFINDER_GOAL_TYPES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
+
public void tick() {
ProfilerFiller gameprofilerfiller = (ProfilerFiller) this.profiler.get();
gameprofilerfiller.push("goalCleanup");
- this.getRunningGoals().filter((pathfindergoalwrapped) -> {
- boolean flag;
-
- if (pathfindergoalwrapped.isRunning()) {
- Stream stream = pathfindergoalwrapped.getFlags().stream();
- EnumSet enumset = this.disabledFlags;
-
- this.disabledFlags.getClass();
- if (!stream.anyMatch(enumset::contains) && pathfindergoalwrapped.canContinueToUse()) {
- flag = false;
- return flag;
- }
+ // Paper start - remove streams from pathfindergoalselector
+ for (Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ WrappedGoal wrappedGoal = iterator.next();
+ if (!wrappedGoal.isRunning()) {
+ continue;
}
-
- flag = true;
- return flag;
ProfilerFiller profilerFiller = this.profiler.get();
profilerFiller.push("goalCleanup");
- this.getRunningGoals().filter((wrappedGoal) -> {
- return !wrappedGoal.isRunning() || wrappedGoal.getFlags().stream().anyMatch(this.disabledFlags::contains) || !wrappedGoal.canContinueToUse();
- }).forEach(Goal::stop);
- this.lockedFlags.forEach((flag, wrappedGoal) -> {
+ // Paper start - remove streams from pathfindergoalselector
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ WrappedGoal wrappedGoal = iterator.next();
if (!wrappedGoal.isRunning()) {
- this.lockedFlags.remove(flag);
+ continue;
+ }
+ if (!this.goalTypes.hasCommonElements(wrappedGoal.getGoalTypes()) && wrappedGoal.canContinueToUse()) {
+ continue;
+ }
+ wrappedGoal.stop();
+ }
+ // Paper end - remove streams from pathfindergoalselector
this.lockedFlags.forEach((pathfindergoal_type, pathfindergoalwrapped) -> {
if (!pathfindergoalwrapped.isRunning()) {
this.lockedFlags.remove(pathfindergoal_type);
@@ -0,0 +0,0 @@ public class GoalSelector {
+ this.lockedFlags.forEach((pathfindergoal_type, pathfindergoalwrapped) -> {
+ if (!pathfindergoalwrapped.isRunning()) {
+ this.lockedFlags.remove(pathfindergoal_type);
}
});
gameprofilerfiller.pop();
gameprofilerfiller.push("goalUpdate");
- this.availableGoals.stream().filter((pathfindergoalwrapped) -> {
- return !pathfindergoalwrapped.isRunning();
- }).filter((pathfindergoalwrapped) -> {
- Stream stream = pathfindergoalwrapped.getFlags().stream();
- EnumSet enumset = this.disabledFlags;
-
- this.disabledFlags.getClass();
- return stream.noneMatch(enumset::contains);
- }).filter((pathfindergoalwrapped) -> {
- return pathfindergoalwrapped.getFlags().stream().allMatch((pathfindergoal_type) -> {
- return ((WrappedGoal) this.lockedFlags.getOrDefault(pathfindergoal_type, GoalSelector.NO_GOAL)).canBeReplacedBy(pathfindergoalwrapped);
profilerFiller.pop();
profilerFiller.push("goalUpdate");
- this.availableGoals.stream().filter((wrappedGoal) -> {
- return !wrappedGoal.isRunning();
- }).filter((wrappedGoal) -> {
- return wrappedGoal.getFlags().stream().noneMatch(this.disabledFlags::contains);
- }).filter((wrappedGoal) -> {
- return wrappedGoal.getFlags().stream().allMatch((flag) -> {
- return this.lockedFlags.getOrDefault(flag, NO_GOAL).canBeReplacedBy(wrappedGoal);
- });
- }).filter(WrappedGoal::canUse).forEach((pathfindergoalwrapped) -> {
- pathfindergoalwrapped.getFlags().forEach((pathfindergoal_type) -> {
- WrappedGoal pathfindergoalwrapped1 = (WrappedGoal) this.lockedFlags.getOrDefault(pathfindergoal_type, GoalSelector.NO_GOAL);
-
- pathfindergoalwrapped1.stop();
- this.lockedFlags.put(pathfindergoal_type, pathfindergoalwrapped);
- }).filter(WrappedGoal::canUse).forEach((wrappedGoal) -> {
- wrappedGoal.getFlags().forEach((flag) -> {
- WrappedGoal wrappedGoal2 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
- wrappedGoal2.stop();
- this.lockedFlags.put(flag, wrappedGoal);
- });
- pathfindergoalwrapped.start();
- });
+
+ // Paper start - remove streams from pathfindergoalselector
+ goal_update_loop: for (Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ goal_update_loop: for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ WrappedGoal wrappedGoal = iterator.next();
+ if (wrappedGoal.isRunning()) {
+ continue;
+ }
+
+ OptimizedSmallEnumSet<Goal.Flag> wrappedGoalSet = wrappedGoal.getGoalTypes();
+ com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> wrappedGoalSet = wrappedGoal.getGoalTypes();
+
+ if (this.goalTypes.hasCommonElements(wrappedGoalSet)) {
+ continue;
@ -201,22 +172,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ wrapped.stop();
+ this.lockedFlags.put(type, wrappedGoal);
+ }
+
+ wrappedGoal.start();
wrappedGoal.start();
- });
+ }
+ // Paper end - remove streams from pathfindergoalselector
gameprofilerfiller.pop();
gameprofilerfiller.push("goalTick");
profilerFiller.pop();
profilerFiller.push("goalTick");
- this.getRunningGoals().forEach(WrappedGoal::tick);
+ // Paper start - remove streams from pathfindergoalselector
+ for (Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
+ WrappedGoal wrappedGoal = iterator.next();
+ if (wrappedGoal.isRunning()) {
+ wrappedGoal.tick();
+ }
+ }
+ // Paper end - remove streams from pathfindergoalselector
gameprofilerfiller.pop();
profilerFiller.pop();
}
@@ -0,0 +0,0 @@ public class GoalSelector {
@ -250,4 +221,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - remove streams from pathfindergoalselector
}
public boolean isRunning() { return this.isRunning(); } // Paper - OBFHELPER
public boolean isRunning() {

View file

@ -11,54 +11,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/util/thread/StrictQueue.java
+++ b/src/main/java/net/minecraft/util/thread/StrictQueue.java
@@ -0,0 +0,0 @@ public interface StrictQueue<T, F> {
public static final class FixedPriorityQueue implements StrictQueue<StrictQueue.IntRunnable, Runnable> {
- private final List<Queue<Runnable>> queueList;
+ private final List<Queue<Runnable>> queueList; private final List<Queue<Runnable>> getQueues() { return this.queueList; } // Paper - OBFHELPER
private final List<Queue<Runnable>> queueList;
public FixedPriorityQueue(int priorityCount) {
- this.queueList = (List) IntStream.range(0, priorityCount).mapToObj((j) -> {
- this.queueList = IntStream.range(0, priorityCount).mapToObj((i) -> {
- return Queues.newConcurrentLinkedQueue();
- }).collect(Collectors.toList());
+ // Paper start - remove streams
+ this.queueList = new java.util.ArrayList<>(priorityCount); // queues
+ for (int j = 0; j < priorityCount; ++j) {
+ this.getQueues().add(Queues.newConcurrentLinkedQueue());
+ this.queueList.add(Queues.newConcurrentLinkedQueue());
+ }
+ // Paper end - remove streams
}
@Nullable
@Override
public Runnable pop() {
- Iterator iterator = this.queueList.iterator();
-
- Runnable runnable;
-
- do {
- if (!iterator.hasNext()) {
- return null;
+ // Paper start - remove iterator creation
+ for (int i = 0, len = this.getQueues().size(); i < len; ++i) {
+ Queue<Runnable> queue = this.getQueues().get(i);
+ Runnable ret = queue.poll();
+ if (ret != null) {
+ return ret;
}
-
- Queue<Runnable> queue = (Queue) iterator.next();
-
- runnable = (Runnable) queue.poll();
- } while (runnable == null);
-
- return runnable;
+ }
+ return null;
+ // Paper end - remove iterator creation
}
public boolean push(StrictQueue.IntRunnable message) {
@@ -0,0 +0,0 @@ public interface StrictQueue<T, F> {
@Override
@ -66,8 +33,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- return this.queueList.stream().allMatch(Collection::isEmpty);
+ // Paper start - remove streams
+ // why are we doing streams every time we might want to execute a task?
+ for (int i = 0, len = this.getQueues().size(); i < len; ++i) {
+ Queue<Runnable> queue = this.getQueues().get(i);
+ for (int i = 0, len = this.queueList.size(); i < len; ++i) {
+ Queue<Runnable> queue = this.queueList.get(i);
+ if (!queue.isEmpty()) {
+ return false;
+ }
@ -75,5 +42,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return true;
+ // Paper end - remove streams
}
}
@Override

View file

@ -8,19 +8,19 @@ diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListener
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
@Override
public void handlePickItem(ServerboundPickItemPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
- this.player.inventory.pickSlot(packet.getSlot());
- this.player.getInventory().pickSlot(packet.getSlot());
+ // Paper start - validate pick item position
+ if (!(packet.getSlot() >= 0 && packet.getSlot() < this.player.inventory.items.size())) {
+ if (!(packet.getSlot() >= 0 && packet.getSlot() < this.player.getInventory().items.size())) {
+ ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString());
+ this.disconnect("Invalid hotbar selection (Hacking?)");
+ return;
+ }
+ this.player.inventory.pickSlot(packet.getSlot()); // Paper - Diff above if changed
+ this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed
+ // Paper end
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, this.player.inventory.selected, this.player.inventory.getItem(this.player.inventory.selected)));
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, packet.getSlot(), this.player.inventory.getItem(packet.getSlot())));
this.player.connection.send(new ClientboundSetCarriedItemPacket(this.player.inventory.selected));
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, this.player.getInventory().selected, this.player.getInventory().getItem(this.player.getInventory().selected)));
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, packet.getSlot(), this.player.getInventory().getItem(packet.getSlot())));
this.player.connection.send(new ClientboundSetCarriedItemPacket(this.player.getInventory().selected));

View file

@ -16,13 +16,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ private int numberOfRestocksToday; public int getRestocksToday(){ return this.numberOfRestocksToday; } public void setRestocksToday(int restocksToday){ this.numberOfRestocksToday = restocksToday; } // Paper OBFHELPER
private long lastRestockCheckDayTime;
private boolean assignProfessionWhenSpawned;
private static final ImmutableList<MemoryModuleType<?>> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.HOME, MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, MemoryModuleType.MEETING_POINT, MemoryModuleType.MOBS, MemoryModuleType.VISIBLE_MOBS, MemoryModuleType.VISIBLE_VILLAGER_BABIES, MemoryModuleType.NEAREST_PLAYERS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, MemoryModuleType.WALK_TARGET, new MemoryModuleType[]{MemoryModuleType.LOOK_TARGET, MemoryModuleType.INTERACTION_TARGET, MemoryModuleType.BREED_TARGET, MemoryModuleType.PATH, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.NEAREST_BED, MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.NEAREST_HOSTILE, MemoryModuleType.SECONDARY_JOB_SITE, MemoryModuleType.HIDING_PLACE, MemoryModuleType.HEARD_BELL_TIME, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.LAST_SLEPT, MemoryModuleType.LAST_WOKEN, MemoryModuleType.LAST_WORKED_AT_POI, MemoryModuleType.GOLEM_DETECTED_RECENTLY});
private static final ImmutableList<MemoryModuleType<?>> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.HOME, MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, MemoryModuleType.MEETING_POINT, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.VISIBLE_VILLAGER_BABIES, MemoryModuleType.NEAREST_PLAYERS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, MemoryModuleType.WALK_TARGET, new MemoryModuleType[]{MemoryModuleType.LOOK_TARGET, MemoryModuleType.INTERACTION_TARGET, MemoryModuleType.BREED_TARGET, MemoryModuleType.PATH, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.NEAREST_BED, MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.NEAREST_HOSTILE, MemoryModuleType.SECONDARY_JOB_SITE, MemoryModuleType.HIDING_PLACE, MemoryModuleType.HEARD_BELL_TIME, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.LAST_SLEPT, MemoryModuleType.LAST_WOKEN, MemoryModuleType.LAST_WORKED_AT_POI, MemoryModuleType.GOLEM_DETECTED_RECENTLY});
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
@@ -0,0 +0,0 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
getHandle().setVillagerXp(experience);
this.getHandle().setVillagerXp(experience);
}
+ // Paper start

View file

@ -7,4 +7,4 @@ pluginManagement {
rootProject.name = "Paper"
include("Paper-API", "Paper-Server")
include("Paper-API", "Paper-Server", "Paper-MojangAPI")

@ -1 +1 @@
Subproject commit 8503c3c9e3dca76b2ae10796d8c288b3f3101737
Subproject commit a791f93de242bf89d116fed843b889e38433e094

@ -1 +1 @@
Subproject commit 40caacc846a6349cd555d9d89cf9cf729c0b75b7
Subproject commit 85b8c1fda69f6f80e45ddd19590846c249e5b6bc