This commit is contained in:
Nassim Jahnke
2024-12-13 20:30:07 +01:00
parent 4091c6ac4d
commit c3d5f253fe
12 changed files with 155 additions and 170 deletions

View File

@@ -0,0 +1,63 @@
--- a/net/minecraft/util/SimpleBitStorage.java
+++ b/net/minecraft/util/SimpleBitStorage.java
@@ -204,8 +_,8 @@
private final long mask;
private final int size;
private final int valuesPerLong;
- private final int divideMul;
- private final int divideAdd;
+ private final int divideMul; private final long divideMulUnsigned; // Paper - Perf: Optimize SimpleBitStorage; referenced in b(int) with 2 Integer.toUnsignedLong calls
+ private final int divideAdd; private final long divideAddUnsigned; // Paper - Perf: Optimize SimpleBitStorage
private final int divideShift;
public SimpleBitStorage(int bits, int size, int[] data) {
@@ -248,8 +_,8 @@
this.mask = (1L << bits) - 1L;
this.valuesPerLong = (char)(64 / bits);
int i = 3 * (this.valuesPerLong - 1);
- this.divideMul = MAGIC[i + 0];
- this.divideAdd = MAGIC[i + 1];
+ this.divideMul = MAGIC[i + 0]; this.divideMulUnsigned = Integer.toUnsignedLong(this.divideMul); // Paper - Perf: Optimize SimpleBitStorage
+ this.divideAdd = MAGIC[i + 1]; this.divideAddUnsigned = Integer.toUnsignedLong(this.divideAdd); // Paper - Perf: Optimize SimpleBitStorage
this.divideShift = MAGIC[i + 2];
int i1 = (size + this.valuesPerLong - 1) / this.valuesPerLong;
if (data != null) {
@@ -264,15 +_,11 @@
}
private int cellIndex(int index) {
- long l = Integer.toUnsignedLong(this.divideMul);
- long l1 = Integer.toUnsignedLong(this.divideAdd);
- return (int)(index * l + l1 >> 32 >> this.divideShift);
+ return (int)(index * this.divideMulUnsigned + this.divideAddUnsigned >> 32 >> this.divideShift); // Paper - Perf: Optimize SimpleBitStorage
}
@Override
- public int getAndSet(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, this.mask, (long)value);
+ public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
int i = this.cellIndex(index);
long l = this.data[i];
int i1 = (index - i * this.valuesPerLong) * this.bits;
@@ -282,9 +_,7 @@
}
@Override
- public void set(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, this.mask, (long)value);
+ public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
int i = this.cellIndex(index);
long l = this.data[i];
int i1 = (index - i * this.valuesPerLong) * this.bits;
@@ -292,8 +_,7 @@
}
@Override
- public int get(int index) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
+ public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage
int i = this.cellIndex(index);
long l = this.data[i];
int i1 = (index - i * this.valuesPerLong) * this.bits;

View File

@@ -0,0 +1,70 @@
--- a/net/minecraft/util/SpawnUtil.java
+++ b/net/minecraft/util/SpawnUtil.java
@@ -16,6 +_,7 @@
import net.minecraft.world.level.block.state.BlockState;
public class SpawnUtil {
+
public static <T extends Mob> Optional<T> trySpawnMob(
EntityType<T> entityType,
EntitySpawnReason spawnReason,
@@ -27,6 +_,24 @@
SpawnUtil.Strategy strategy,
boolean checkCollision
) {
+ // CraftBukkit start
+ return trySpawnMob(entityType, spawnReason, level, pos, attempts, range, yOffset, strategy, checkCollision, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT, null); // Paper - pre creature spawn event
+ }
+
+ public static <T extends Mob> Optional<T> trySpawnMob(
+ EntityType<T> entityType,
+ EntitySpawnReason spawnReason,
+ ServerLevel level,
+ BlockPos pos,
+ int attempts,
+ int range,
+ int yOffset,
+ SpawnUtil.Strategy strategy,
+ boolean checkCollision,
+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason,
+ @javax.annotation.Nullable Runnable onAbort // Paper - pre creature spawn event
+ ) {
+ // CraftBukkit end
BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
for (int i = 0; i < attempts; i++) {
@@ -39,15 +_,32 @@
!checkCollision
|| level.noCollision(entityType.getSpawnAABB(mutableBlockPos.getX() + 0.5, mutableBlockPos.getY(), mutableBlockPos.getZ() + 0.5))
)) {
+ // Paper start - PreCreatureSpawnEvent
+ final com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
+ io.papermc.paper.util.MCUtil.toLocation(level, pos),
+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entityType),
+ reason
+ );
+ if (!event.callEvent()) {
+ if (event.shouldAbortSpawn()) {
+ if (onAbort != null) {
+ onAbort.run();
+ }
+ return Optional.empty();
+ }
+ break;
+ }
+ // Paper end - PreCreatureSpawnEvent
T mob = (T)entityType.create(level, null, mutableBlockPos, spawnReason, false, false);
if (mob != null) {
if (mob.checkSpawnRules(level, spawnReason) && mob.checkSpawnObstruction(level)) {
- level.addFreshEntityWithPassengers(mob);
+ level.addFreshEntityWithPassengers(mob, reason); // CraftBukkit
+ if (mob.isRemoved()) return Optional.empty(); // CraftBukkit
mob.playAmbientSound();
return Optional.of(mob);
}
- mob.discard();
+ mob.discard(null); // CraftBukkit - add Bukkit remove cause
}
}
}

View File

@@ -0,0 +1,28 @@
--- a/net/minecraft/util/StringUtil.java
+++ b/net/minecraft/util/StringUtil.java
@@ -85,6 +_,25 @@
return stringBuilder.toString();
}
+ // Paper start - Username validation
+ public static boolean isReasonablePlayerName(final String name) {
+ if (name.isEmpty() || name.length() > 16) {
+ return false;
+ }
+
+ for (int i = 0, len = name.length(); i < len; ++i) {
+ final char c = name.charAt(i);
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_' || c == '.')) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+ // Paper end - Username validation
+
public static boolean isWhitespace(int character) {
return Character.isWhitespace(character) || Character.isSpaceChar(character);
}

View File

@@ -0,0 +1,45 @@
--- a/net/minecraft/util/TickThrottler.java
+++ b/net/minecraft/util/TickThrottler.java
@@ -3,7 +_,7 @@
public class TickThrottler {
private final int incrementStep;
private final int threshold;
- private int count;
+ private final java.util.concurrent.atomic.AtomicInteger count = new java.util.concurrent.atomic.AtomicInteger(); // CraftBukkit - multithreaded field
public TickThrottler(int incrementStep, int threshold) {
this.incrementStep = incrementStep;
@@ -11,16 +_,31 @@
}
public void increment() {
- this.count = this.count + this.incrementStep;
+ this.count.addAndGet(this.incrementStep); // CraftBukkit - use thread-safe field access instead
}
public void tick() {
+ // CraftBukkit start
+ for (int val; (val = this.count.get()) > 0 && !this.count.compareAndSet(val, val - 1); ) ;
+ /* Use thread-safe field access instead
if (this.count > 0) {
this.count--;
}
+ */
+ // CraftBukkit end
}
public boolean isUnderThreshold() {
- return this.count < this.threshold;
+ // CraftBukkit start - use thread-safe field access instead
+ return this.count.get() < this.threshold;
+ }
+
+ public boolean isIncrementAndUnderThreshold() {
+ return this.isIncrementAndUnderThreshold(this.incrementStep, this.threshold);
+ }
+
+ public boolean isIncrementAndUnderThreshold(int incrementStep, int threshold) {
+ return this.count.addAndGet(incrementStep) < threshold;
+ // CraftBukkit end
}
}

View File

@@ -0,0 +1,32 @@
--- a/net/minecraft/util/ZeroBitStorage.java
+++ b/net/minecraft/util/ZeroBitStorage.java
@@ -13,21 +_,21 @@
}
@Override
- public int getAndSet(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, 0L, (long)value);
+ public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage
return 0;
}
@Override
- public void set(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, 0L, (long)value);
+ public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage
}
@Override
- public int get(int index) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
+ public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
return 0;
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
+++ b/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
@@ -41,7 +_,7 @@
private static void ifChunkExists(LevelReader level, @Nullable SectionPos sectionPos, Consumer<GameEventListenerRegistry> dispatcherConsumer) {
if (sectionPos != null) {
- ChunkAccess chunk = level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.FULL, false);
+ ChunkAccess chunk = level.getChunkIfLoadedImmediately(sectionPos.getX(), sectionPos.getZ()); // Paper - Perf: can cause sync loads while completing a chunk, resulting in deadlock
if (chunk != null) {
dispatcherConsumer.accept(chunk.getListenerRegistry(sectionPos.y()));
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/level/gameevent/GameEvent.java
+++ b/net/minecraft/world/level/gameevent/GameEvent.java
@@ -85,7 +_,7 @@
}
private static Holder.Reference<GameEvent> register(String name, int notificationRadius) {
- return Registry.registerForHolder(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(name), new GameEvent(notificationRadius));
+ return io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerForHolderWithListeners(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(name), new GameEvent(notificationRadius)); // Paper - run with listeners
}
public record Context(@Nullable Entity sourceEntity, @Nullable BlockState affectedState) {

View File

@@ -0,0 +1,40 @@
--- a/net/minecraft/world/level/gameevent/GameEventDispatcher.java
+++ b/net/minecraft/world/level/gameevent/GameEventDispatcher.java
@@ -11,6 +_,13 @@
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftGameEvent;
+import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.event.world.GenericGameEvent;
+// CraftBukkit end
+
public class GameEventDispatcher {
private final ServerLevel level;
@@ -21,6 +_,14 @@
public void post(Holder<GameEvent> gameEvent, Vec3 pos, GameEvent.Context context) {
int notificationRadius = gameEvent.value().notificationRadius();
BlockPos blockPos = BlockPos.containing(pos);
+ // CraftBukkit start
+ GenericGameEvent apiEvent = new GenericGameEvent(CraftGameEvent.minecraftToBukkit(gameEvent.value()), CraftLocation.toBukkit(blockPos, this.level.getWorld()), (context.sourceEntity() == null) ? null : context.sourceEntity().getBukkitEntity(), notificationRadius, !Bukkit.isPrimaryThread());
+ this.level.getCraftServer().getPluginManager().callEvent(apiEvent);
+ if (apiEvent.isCancelled()) {
+ return;
+ }
+ notificationRadius = apiEvent.getRadius();
+ // CraftBukkit end
int sectionPosCoord = SectionPos.blockToSectionCoord(blockPos.getX() - notificationRadius);
int sectionPosCoord1 = SectionPos.blockToSectionCoord(blockPos.getY() - notificationRadius);
int sectionPosCoord2 = SectionPos.blockToSectionCoord(blockPos.getZ() - notificationRadius);
@@ -39,7 +_,7 @@
for (int i = sectionPosCoord; i <= sectionPosCoord3; i++) {
for (int i1 = sectionPosCoord2; i1 <= sectionPosCoord5; i1++) {
- ChunkAccess chunkNow = this.level.getChunkSource().getChunkNow(i, i1);
+ ChunkAccess chunkNow = this.level.getChunkIfLoadedImmediately(i, i1); // Paper - Use getChunkIfLoadedImmediately
if (chunkNow != null) {
for (int i2 = sectionPosCoord1; i2 <= sectionPosCoord4; i2++) {
flag |= chunkNow.getListenerRegistry(i2).visitInRangeListeners(gameEvent, pos, context, listenerVisitor);