9
0
mirror of https://github.com/SparklyPower/SparklyPaper.git synced 2025-12-19 15:09:27 +00:00

Update Tuinity, remove Airplane patches for now

This commit is contained in:
MrPowerGamerBR
2021-07-27 21:03:39 -03:00
parent 8abb9117c8
commit 6f7af0038e
30 changed files with 9 additions and 2243 deletions

View File

@@ -3,7 +3,7 @@ version = 1.17.1-R0.1-SNAPSHOT
mcVersion = 1.17.1 mcVersion = 1.17.1
packageVersion = 1_17_R1 packageVersion = 1_17_R1
tuinityRef = ea43797d5aa099543c0111314ae08e09e6ce7329 tuinityRef = e4b092272731f380727b0f69c32c03039cb429bb
org.gradle.jvmargs=-Xmx2G org.gradle.jvmargs=-Xmx2G

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] new fork who dis - Rebrand to SparklyPaper
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index ab8de6c4e3c0bea2b9f498da00adf88e987d2364..8fc6315cf8afa10866f7a15c7a02f0d88f113007 100644 index b7e5bdcfe04ab7d8d8d453a787849963640262a5..5df9abac33825f69fc181dd20be4522164cfe1c6 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -36,7 +36,7 @@ repositories { @@ -34,7 +34,7 @@ repositories {
} }
dependencies { dependencies {
@@ -17,13 +17,13 @@ index ab8de6c4e3c0bea2b9f498da00adf88e987d2364..8fc6315cf8afa10866f7a15c7a02f0d8
implementation("com.destroystokyo.paper:paper-mojangapi:1.16.5-R0.1-SNAPSHOT") // Tuinity implementation("com.destroystokyo.paper:paper-mojangapi:1.16.5-R0.1-SNAPSHOT") // Tuinity
// Paper start // Paper start
implementation("org.jline:jline-terminal-jansi:3.12.1") implementation("org.jline:jline-terminal-jansi:3.12.1")
@@ -88,7 +88,7 @@ tasks.jar { @@ -86,7 +86,7 @@ tasks.jar {
attributes( attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main", "Main-Class" to "org.bukkit.craftbukkit.Main",
"Implementation-Title" to "CraftBukkit", "Implementation-Title" to "CraftBukkit",
- "Implementation-Version" to "git-Tuinity-$implementationVersion", // Tuinity - "Implementation-Version" to "git-Tuinity-$implementationVersion", // Tuinity
+ "Implementation-Version" to "git-SparklyPaper-$implementationVersion", // SparklyPaper + "Implementation-Version" to "git-SparklyPaper-$implementationVersion", // SparklyPaper
"Implementation-Vendor" to SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date()), // Paper "Implementation-Vendor" to date, // Paper
"Specification-Title" to "Bukkit", "Specification-Title" to "Bukkit",
"Specification-Version" to project.version, "Specification-Version" to project.version,
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -40,10 +40,10 @@ index f25bb4214cffd0050241ea229b6acb0c16b2b0a5..c5390c532b62042c81103c750af6e88b
public SystemReport fillSystemReport(SystemReport details) { public SystemReport fillSystemReport(SystemReport details) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 4342bc5aad49fe372d561296a6b63818a443d089..1250780c864052fe6b9876d74398121e38861346 100644 index 1ec307d705087eec9d867f9f8e8858ac388f3846..ecbae283bc99fcba1e48dcebe4f970e0734e9467 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -230,7 +230,7 @@ import javax.annotation.Nullable; // Paper @@ -239,7 +239,7 @@ import javax.annotation.Nullable; // Paper
import javax.annotation.Nonnull; // Paper import javax.annotation.Nonnull; // Paper
public final class CraftServer implements Server { public final class CraftServer implements Server {

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] idk
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index ab8de6c4e3c0bea2b9f498da00adf88e987d2364..fbd71fc0d2619278565537cd565a99282d84f587 100644 index 5df9abac33825f69fc181dd20be4522164cfe1c6..36fe79d2cbf1941c0b02b8de3c8070241bc5f68e 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -184,7 +184,7 @@ abstract class IncludeMappings : BaseTask() { @@ -182,7 +182,7 @@ abstract class IncludeMappings : BaseTask() {
} }
val includeMappings = tasks.register<IncludeMappings>("includeMappings") { val includeMappings = tasks.register<IncludeMappings>("includeMappings") {

View File

@@ -1,161 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sat, 31 Oct 2020 18:43:02 -0500
Subject: [PATCH] Strip raytracing for EntityLiving#hasLineOfSight
The IBlockAccess#rayTrace method is very wasteful in both allocations,
and in logic. While EntityLiving#hasLineOfSight provides static
parameters for collisions with blocks and fluids, the method still does
a lot of dynamic checks for both of these, which result in extra work.
As well, since the fluid collision option is set to NONE, the entire
fluid collision system is completely unneeded, yet used anyways.
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index ed745776316c5346ee1b44c8f022c40359b7e642..402b785b5fd0e1c3c5c02505dca332990ec64e37 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3428,7 +3428,10 @@ public abstract class LivingEntity extends Entity {
Vec3 vec3d1 = new Vec3(entity.getX(), entity.getEyeY(), entity.getZ());
// Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists
- return vec3d1.distanceTo(vec3d) > 128.0D ? false : this.level.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() == HitResult.Type.MISS;
+ // Airplane start
+ //return vec3d1.distanceTo(vec3d) > 128.0D ? false : this.level.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() == HitResult.Type.MISS;
+ return this.level.rayTraceDirect(vec3d, vec3d1, net.minecraft.world.phys.shapes.CollisionContext.of(this)) == net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ // Airplane end
}
}
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
index ec781ab232d12cedb5f0236860377c4917c576d7..ced4b354e83ad68f8f1aacdefe2f0ce0035bd4a7 100644
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
@@ -73,6 +73,16 @@ public interface BlockGetter extends LevelHeightAccessor {
});
}
+ // Airplane start - broken down variant of below rayTraceBlock, used by World#rayTraceDirect
+ default net.minecraft.world.phys.BlockHitResult.Type rayTraceBlockDirect(Vec3 vec3d, Vec3 vec3d1, BlockPos blockposition, BlockState iblockdata, net.minecraft.world.phys.shapes.CollisionContext voxelshapecoll) {
+ if (iblockdata.isAir()) return null; // Tuinity - optimise air cases
+ VoxelShape voxelshape = ClipContext.Block.COLLIDER.get(iblockdata, this, blockposition, voxelshapecoll);
+ net.minecraft.world.phys.BlockHitResult movingobjectpositionblock = this.clipWithInteractionOverride(vec3d, vec3d1, blockposition, voxelshape, iblockdata);
+
+ return movingobjectpositionblock == null ? null : movingobjectpositionblock.getType();
+ }
+ // Airplane end
+
// CraftBukkit start - moved block handling into separate method for use by Block#rayTrace
default BlockHitResult rayTraceBlock(ClipContext raytrace1, BlockPos blockposition) {
// Paper start - Prevent raytrace from loading chunks
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 61a4dea715689b0ce9247040db5dd2080ee2e167..a2bb8eee5ef4a5043026af20f78bb43a5006e6b4 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -453,6 +453,91 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return null;
}
+ // Airplane start - broken down method of raytracing for EntityLiving#hasLineOfSight, replaces IBlockAccess#rayTrace(RayTrace)
+ public net.minecraft.world.phys.BlockHitResult.Type rayTraceDirect(net.minecraft.world.phys.Vec3 vec3d, net.minecraft.world.phys.Vec3 vec3d1, net.minecraft.world.phys.shapes.CollisionContext voxelshapecoll) {
+ // most of this code comes from IBlockAccess#a(RayTrace, BiFunction, Function), but removes the needless functions
+ if (vec3d.equals(vec3d1)) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+
+ double endX = Mth.lerp(-1.0E-7D, vec3d1.x, vec3d.x);
+ double endY = Mth.lerp(-1.0E-7D, vec3d1.y, vec3d.y);
+ double endZ = Mth.lerp(-1.0E-7D, vec3d1.z, vec3d.z);
+
+ double startX = Mth.lerp(-1.0E-7D, vec3d.x, vec3d1.x);
+ double startY = Mth.lerp(-1.0E-7D, vec3d.y, vec3d1.y);
+ double startZ = Mth.lerp(-1.0E-7D, vec3d.z, vec3d1.z);
+
+ int currentX = Mth.floor(startX);
+ int currentY = Mth.floor(startY);
+ int currentZ = Mth.floor(startZ);
+
+ BlockPos.MutableBlockPos currentBlock = new BlockPos.MutableBlockPos(currentX, currentY, currentZ);
+
+ LevelChunk chunk = this.getChunkIfLoaded(currentBlock);
+ if (chunk == null) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+
+ net.minecraft.world.phys.BlockHitResult.Type initialCheck = this.rayTraceBlockDirect(vec3d, vec3d1, currentBlock, chunk.getBlockState(currentBlock), voxelshapecoll);
+
+ if (initialCheck != null) {
+ return initialCheck;
+ }
+
+ double diffX = endX - startX;
+ double diffY = endY - startY;
+ double diffZ = endZ - startZ;
+
+ int xDirection = Mth.sign(diffX);
+ int yDirection = Mth.sign(diffY);
+ int zDirection = Mth.sign(diffZ);
+
+ double normalizedX = xDirection == 0 ? Double.MAX_VALUE : (double) xDirection / diffX;
+ double normalizedY = yDirection == 0 ? Double.MAX_VALUE : (double) yDirection / diffY;
+ double normalizedZ = zDirection == 0 ? Double.MAX_VALUE : (double) zDirection / diffZ;
+
+ double normalizedXDirection = normalizedX * (xDirection > 0 ? 1.0D - Mth.frac(startX) : Mth.frac(startX));
+ double normalizedYDirection = normalizedY * (yDirection > 0 ? 1.0D - Mth.frac(startY) : Mth.frac(startY));
+ double normalizedZDirection = normalizedZ * (zDirection > 0 ? 1.0D - Mth.frac(startZ) : Mth.frac(startZ));
+
+ net.minecraft.world.phys.BlockHitResult.Type result;
+
+ do {
+ if (normalizedXDirection > 1.0D && normalizedYDirection > 1.0D && normalizedZDirection > 1.0D) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+
+ if (normalizedXDirection < normalizedYDirection) {
+ if (normalizedXDirection < normalizedZDirection) {
+ currentX += xDirection;
+ normalizedXDirection += normalizedX;
+ } else {
+ currentZ += zDirection;
+ normalizedZDirection += normalizedZ;
+ }
+ } else if (normalizedYDirection < normalizedZDirection) {
+ currentY += yDirection;
+ normalizedYDirection += normalizedY;
+ } else {
+ currentZ += zDirection;
+ normalizedZDirection += normalizedZ;
+ }
+
+ currentBlock.set(currentX, currentY, currentZ);
+ if (chunk.getPos().x != currentBlock.getX() >> 4 || chunk.getPos().z != currentBlock.getZ() >> 4) {
+ chunk = this.getChunkIfLoaded(currentBlock);
+ if (chunk == null) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+ }
+ result = this.rayTraceBlockDirect(vec3d, vec3d1, currentBlock, chunk.getBlockState(currentBlock), voxelshapecoll);
+ } while (result == null);
+
+ return result;
+ }
+ // Airplane end
+
public boolean isInWorldBounds(BlockPos pos) {
return pos.isValidLocation(this); // Paper - use better/optimized check
}

View File

@@ -1,84 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sat, 31 Oct 2020 18:51:38 -0500
Subject: [PATCH] Simpler ShapelessRecipes comparison for Vanilla
Paper added a fancy sorting comparison due to Bukkit recipes breaking
the vanilla one, however this is far more advanced than what you need
for all the vanilla recipes.
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
index 6b960f0a31175bcfd8d477ee5b3c4d783303cdd5..3a81d3a58b937c9800cd0be738439cff0ba28ce9 100644
--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
@@ -25,8 +25,13 @@ public class ShapelessRecipe implements CraftingRecipe {
final String group;
final ItemStack result;
final NonNullList<Ingredient> ingredients;
+ private final boolean isBukkit; // Airplane
+ // Airplane start
public ShapelessRecipe(ResourceLocation id, String group, ItemStack output, NonNullList<Ingredient> input) {
+ this(id, group, output, input, false);
+ }
+ public ShapelessRecipe(ResourceLocation id, String group, ItemStack output, NonNullList<Ingredient> input, boolean isBukkit) { this.isBukkit = isBukkit; // Airplane end
this.id = id;
this.group = group;
this.result = output;
@@ -73,6 +78,28 @@ public class ShapelessRecipe implements CraftingRecipe {
}
public boolean matches(CraftingContainer inventory, Level world) {
+ // Airplane start
+ if (!this.isBukkit) {
+ java.util.List<Ingredient> ingredients = com.google.common.collect.Lists.newArrayList(this.ingredients.toArray(new Ingredient[0]));
+
+ inventory: for (int index = 0; index < inventory.getContainerSize(); index++) {
+ ItemStack itemStack = inventory.getItem(index);
+
+ if (!itemStack.isEmpty()) {
+ for (int i = 0; i < ingredients.size(); i++) {
+ if (ingredients.get(i).test(itemStack)) {
+ ingredients.remove(i);
+ continue inventory;
+ }
+ }
+ return false;
+ }
+ }
+
+ return ingredients.isEmpty();
+ }
+ // Airplane end
+
StackedContents autorecipestackmanager = new StackedContents();
int i = 0;
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java
index 0b3b46348ac9195bff1492ffc11fcbff7d3f5c6f..4010052c53f3a2831b4d5aa1c041d85897856acb 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java
@@ -43,6 +43,6 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe
data.set(i, toNMS(ingred.get(i), true));
}
- MinecraftServer.getServer().getRecipeManager().addRecipe(new net.minecraft.world.item.crafting.ShapelessRecipe(CraftNamespacedKey.toMinecraft(this.getKey()), this.getGroup(), CraftItemStack.asNMSCopy(this.getResult()), data));
+ MinecraftServer.getServer().getRecipeManager().addRecipe(new net.minecraft.world.item.crafting.ShapelessRecipe(CraftNamespacedKey.toMinecraft(this.getKey()), this.getGroup(), CraftItemStack.asNMSCopy(this.getResult()), data, true));
}
}

View File

@@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sun, 13 Dec 2020 17:52:35 -0600
Subject: [PATCH] Reduce projectile chunk loading
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
index 69f439851fe1ff07d827eaed274940a5783d5f6c..bfa2a1ad2bf8004d7545cd2175834fa00fcdb8bb 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
@@ -42,6 +42,37 @@ public abstract class Projectile extends Entity {
super(type, world);
}
+ // Airplane start
+ private static int loadedThisTick = 0;
+ private static int loadedTick;
+
+ private int buffered = 0;
+ @Override
+ public void setPos(double x, double y, double z) {
+ int currentTick = net.minecraft.server.MinecraftServer.currentTick;
+ if (loadedTick != currentTick) {
+ loadedTick = currentTick;
+ loadedThisTick = 0;
+ }
+ int previousX = Mth.floor(this.getX()) >> 4, previousZ = Mth.floor(this.getX()) >> 4;
+ int newX = Mth.floor(z) >> 4, newZ = Mth.floor(z) >> 4;
+ if (previousX != newX || previousZ != newZ) {
+ boolean isLoaded = ((net.minecraft.server.level.ServerChunkCache) this.level.getChunkSource()).getChunkAtIfLoadedMainThreadNoCache(newX, newZ) != null;
+ if (!isLoaded) {
+ if (loadedThisTick > 10) { // Airplane 10 = max chunks to load from projectiles in a tick todo config
+ if (++buffered > 20) { // Airplane 20 = max chunks a single projectile loads overall todo config
+ this.discard();
+ }
+ return;
+ }
+ loadedThisTick++;
+ }
+ buffered = 0;
+ }
+ super.setPos(x, y, z);
+ }
+ // Airplane start
+
public void setOwner(@Nullable Entity entity) {
if (entity != null) {
this.ownerUUID = entity.getUUID();

View File

@@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sun, 13 Dec 2020 17:53:08 -0600
Subject: [PATCH] Only check for spooky season once an hour
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
index 153194d937d210e2e4fd8864e4a3c000f85d7e2e..1d415a91b9c90603e8f738dbafe7a5ea57ef14cc 100644
--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java
+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
@@ -254,13 +254,22 @@ public class Bat extends AmbientCreature {
}
}
+ // Airplane start - only check for spooky season once an hour
+ private static boolean isSpookySeason = false;
+ private static final int ONE_HOUR = 20 * 60 * 60;
+ private static int lastSpookyCheck = -ONE_HOUR;
private static boolean isHalloween() {
+ if (net.minecraft.server.MinecraftServer.currentTick - lastSpookyCheck > ONE_HOUR) {
LocalDate localdate = LocalDate.now();
int i = localdate.get(ChronoField.DAY_OF_MONTH);
int j = localdate.get(ChronoField.MONTH_OF_YEAR);
- return j == 10 && i >= 20 || j == 11 && i <= 3;
+ isSpookySeason = j == 10 && i >= 20 || j == 11 && i <= 3;
+ lastSpookyCheck = net.minecraft.server.MinecraftServer.currentTick;
+ }
+ return isSpookySeason;
}
+ // Airplane end
@Override
protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) {

View File

@@ -1,109 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Thu, 7 Jan 2021 11:49:36 -0600
Subject: [PATCH] Optimize random calls in chunk ticking
Especially at over 30,000 chunks these random calls are fairly heavy. We
use a different method here for checking lightning, and for checking
ice.
Lightning: Each chunk now keeps an int of how many ticks until the
lightning should strike. This int is a random number from 0 to 100000 * 2,
the multiplication is required to keep the probability the same.
Ice and snow: We just generate a single random number 0-16 and increment
it, while checking if it's 0 for the current chunk.
Depending on configuration for things that tick in a chunk, this is a
5-10% improvement.
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index db39671881b622189961b39309a323a1b35d680e..5309e9060766c6f16bce6156c6d84e26b1dbb6b1 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -981,6 +981,7 @@ public class ServerChunkCache extends ChunkSource {
}
// Paper end - optimize isOutisdeRange
this.level.getProfiler().push("pollingChunks");
+ this.level.resetIceAndSnowTick(); // Airplane - reset ice & snow tick random
int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
boolean flag2 = level.ticksPerAnimalSpawns != 0L && worlddata.getGameTime() % level.ticksPerAnimalSpawns == 0L; // CraftBukkit
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 7642170bf5a0eaa11110238fa5cf1a7e1ff20a20..bb51d9c842a3b1bc517b378194c61a6c30b629c3 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -881,6 +881,8 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
private final com.tuinity.tuinity.util.math.ThreadUnsafeRandom randomTickRandom = new com.tuinity.tuinity.util.math.ThreadUnsafeRandom();
// Paper end
+ private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Airplane
+
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
ChunkPos chunkcoordintpair = chunk.getPos();
boolean flag = this.isRaining();
@@ -891,7 +893,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
gameprofilerfiller.push("thunder");
final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change
- if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder
+ if (!this.paperConfig.disableThunder && flag && this.isThundering() && chunk.shouldDoLightning(this.random)) { // Paper - Disable thunder // Airplane - replace random with shouldDoLightning
blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper
if (this.isRainingAt(blockposition)) {
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
@@ -915,7 +917,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
gameprofilerfiller.popPush("iceandsnow");
- if (!this.paperConfig.disableIceAndSnow && this.randomTickRandom.nextInt(16) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking
+ if (!this.paperConfig.disableIceAndSnow && (this.currentIceAndSnowTick++ & 15) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking // Airplane - optimize further random ticking
// Paper start - optimise chunk ticking
this.getRandomBlockPosition(j, 0, k, 15, blockposition);
int normalY = chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, blockposition.getX() & 15, blockposition.getZ() & 15) + 1;
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 54e23d303aad286ab46c3e5f9b17a5f9922e2942..4785cbd47e15f78c0302f1dc9bd904a4839ef8e4 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -172,6 +172,18 @@ public class LevelChunk implements ChunkAccess {
}
// Tuinity end - rewrite light engine
+ // Airplane start - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively
+ private int lightningTick;
+ // shouldDoLightning compiles down to 29 bytes, which with the default of 35 byte inlining should guarantee an inline
+ public final boolean shouldDoLightning(java.util.Random random) {
+ if (this.lightningTick-- <= 0) {
+ this.lightningTick = random.nextInt(100000) << 1;
+ return true;
+ }
+ return false;
+ }
+ // Airplane end
+
public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes) {
this(world, pos, biomes, UpgradeData.EMPTY, EmptyTickList.empty(), EmptyTickList.empty(), 0L, (LevelChunkSection[]) null, (Consumer) null);
}
@@ -220,6 +232,7 @@ public class LevelChunk implements ChunkAccess {
this.postProcessing = new ShortList[world.getSectionsCount()];
// CraftBukkit start
this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
+ this.lightningTick = this.level.random.nextInt(100000) << 1; // Airplane - initialize lightning tick
}
public org.bukkit.Chunk bukkitChunk;

View File

@@ -1,77 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Thu, 4 Feb 2021 23:28:46 -0600
Subject: [PATCH] Cache palette array
The reasoning for reusing it in ChunkRegionLoader is because ThreadLocal
lookups are fairly expensive, and if we put it in DataPaletteBlock the
ThreadLocal lookup would happen 18 times.
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
index ebeb3e3b0619b034a9681da999e9ac33cc241718..5b5ada474cff54b424946fc628d30f25a6774684 100644
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -263,13 +263,17 @@ public class PalettedContainer<T> implements PaletteResize<T> {
}
+ // Airplane start - allow reusing int array
public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey) { // Paper - synchronize
+ this.write(nbt, paletteKey, dataKey, new int[4096]);
+ }
+ public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey, int[] is) { // Paper - synchronize // Airplane end
try {
this.acquire();
HashMapPalette<T> hashMapPalette = new HashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer);
T object = this.defaultValue;
int i = hashMapPalette.idFor(this.defaultValue);
- int[] is = new int[4096];
+ //int[] is = new int[4096]; // Airplane
for(int j = 0; j < 4096; ++j) {
T object2 = this.get(j);
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
index 917fa5a3106259c01d6a01acf770890dbdf50f1a..b9d5785a5feccd905828e7f82264c3cb48c3c773 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
@@ -485,6 +485,7 @@ public class ChunkSerializer {
return new AsyncSaveData(blockLight, skyLight, blockTickListSerialized, fluidTickListSerialized, blockEntitiesSerialized, world.getGameTime());
}
+ private static final ThreadLocal<int[]> paletteArray = ThreadLocal.withInitial(() -> new int[4096]); // Airplane
public static CompoundTag write(ServerLevel world, ChunkAccess chunk) {
return saveChunk(world, chunk, null);
}
@@ -518,6 +519,7 @@ public class ChunkSerializer {
ThreadedLevelLightEngine lightenginethreaded = world.getChunkSource().getLightEngine();
boolean flag = chunk.isLightCorrect();
+ int[] is = paletteArray.get(); // Airplane - use cached
for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) {
int finalI = i; // CraftBukkit - decompile errors
LevelChunkSection chunksection = (LevelChunkSection) Arrays.stream(achunksection).filter((chunksection1) -> {
@@ -532,7 +534,7 @@ public class ChunkSerializer {
nbttagcompound2.putByte("Y", (byte) (i & 255));
if (chunksection != LevelChunk.EMPTY_SECTION) {
- chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates");
+ chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates", is); // Airplane - reuse array
}
// Tuinity start - replace light engine

View File

@@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Thu, 4 Feb 2021 23:33:52 -0600
Subject: [PATCH] Reduce chunk loading & lookups
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
index e1e220b3e4967590a2a77370e2a6ab919ad50eaa..5d371a3e94720e24058d007474355af6aeb7cbdd 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
@@ -312,11 +312,17 @@ public class EnderMan extends Monster implements NeutralMob {
private boolean teleport(double x, double y, double z) {
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(x, y, z);
- while (blockposition_mutableblockposition.getY() > this.level.getMinBuildHeight() && !this.level.getBlockState(blockposition_mutableblockposition).getMaterial().blocksMotion()) {
+ // Airplane start - single chunk lookup
+ net.minecraft.world.level.chunk.LevelChunk chunk = this.level.getChunkIfLoaded(blockposition_mutableblockposition);
+ if (chunk == null) {
+ return false;
+ }
+ // Airplane end
+ while (blockposition_mutableblockposition.getY() > this.level.getMinBuildHeight() && !chunk.getBlockState(blockposition_mutableblockposition).getMaterial().blocksMotion()) { // Airplane
blockposition_mutableblockposition.move(Direction.DOWN);
}
- BlockState iblockdata = this.level.getBlockState(blockposition_mutableblockposition);
+ BlockState iblockdata = chunk.getBlockState(blockposition_mutableblockposition); // Airplane
boolean flag = iblockdata.getMaterial().blocksMotion();
boolean flag1 = iblockdata.getFluidState().is((Tag) FluidTags.WATER);

View File

@@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Thu, 18 Feb 2021 13:13:27 -0600
Subject: [PATCH] Skip POI finding if stuck in vehicle
Airplane
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
index efe66264ad5717bf3aac0fbda07275fb5571acc1..68188f3322a9af8eac423afc5f87bc4f88f4a5bb 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
@@ -68,6 +68,7 @@ public class AcquirePoi extends Behavior<PathfinderMob> {
@Override
protected void start(ServerLevel world, PathfinderMob entity, long time) {
this.nextScheduledStart = time + 20L + (long)world.getRandom().nextInt(20);
+ if (entity.getNavigation().isStuck()) this.nextScheduledStart += 200L; // Airplane - wait an additional 10s to check again if they're stuck
PoiManager poiManager = world.getPoiManager();
this.batchCache.long2ObjectEntrySet().removeIf((entry) -> {
return !entry.getValue().isStillValid(time);

View File

@@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sat, 13 Mar 2021 12:24:41 -0600
Subject: [PATCH] Remove iterators from inventory contains
diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java
index dace7d13787f6fb44af90792599fa16caad68052..8d414822894fc41460bb9ccc53d7b0dfd1204115 100644
--- a/src/main/java/net/minecraft/world/entity/player/Inventory.java
+++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java
@@ -688,6 +688,8 @@ public class Inventory implements Container, Nameable {
}
public boolean contains(ItemStack stack) {
+ // Airplane start - don't allocate iterators
+ /*
Iterator iterator = this.compartments.iterator();
while (iterator.hasNext()) {
@@ -702,6 +704,18 @@ public class Inventory implements Container, Nameable {
}
}
}
+ */
+ for (int i = 0; i < this.compartments.size(); i++) {
+ List<ItemStack> list = this.compartments.get(i);
+ for (int j = 0; j < list.size(); j++) {
+ ItemStack itemstack1 = list.get(j);
+
+ if (!itemstack1.isEmpty() && itemstack1.sameItem(stack)) {
+ return true;
+ }
+ }
+ }
+ // Airplane end
return false;
}

View File

@@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sat, 13 Mar 2021 15:05:28 -0600
Subject: [PATCH] Early return optimization for target finding
diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
index 3ee691d4caccbc1b3e0f52decb41d436ac0d08ec..8a0aea6b28295e03aaac1768336b1bc36d9ad9e9 100644
--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
@@ -74,9 +74,18 @@ public class TargetingConditions {
}
if (this.range > 0.0D) {
- double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0D;
- double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0D); // Paper
+ // Airplane start - check range before getting visibility
+ // d = invisibility percent, e = follow range adjusted for invisibility, f = distance
double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ());
+ double followRangeRaw = this.useFollowRange ? this.getFollowRange(baseEntity) : this.range;
+
+ if (f > followRangeRaw * followRangeRaw) { // the actual follow range will always be this value or smaller, so if the distance is larger then it never will return true after getting invis
+ return false;
+ }
+
+ double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0D;
+ double e = Math.max((followRangeRaw) * d, 2.0D); // Paper
+ // Airplane end
if (f > e * e) {
return false;
}

View File

@@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Wed, 17 Mar 2021 13:00:57 -0500
Subject: [PATCH] More debug for plugins not shutting down tasks
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 29eb6d5c43871ef7d6479864178e3b6e015903f8..b584d85bb61f2ffed81bb92520ffff0a5ccccb43 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -986,6 +986,11 @@ public final class CraftServer implements Server {
plugin.getDescription().getName(),
"This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies."
));
+ getLogger().log(Level.SEVERE, String.format("%s Stacktrace", worker.getThread().getName()));
+ StackTraceElement[] stackTrace = worker.getThread().getStackTrace();
+ for (StackTraceElement element : stackTrace) {
+ getLogger().log(Level.SEVERE, " " + element.toString());
+ }
}
}
// Paper end

View File

@@ -1,240 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Wed, 14 Apr 2021 22:58:15 -0500
Subject: [PATCH] Improve fluid direction caching
Implements a custom cache that better fits the needs of fluids
calculating whether a direction can be moved in or something. There's a
big javadoc on the FluidDirectionCache with some more information.
diff --git a/src/main/java/gg/airplane/structs/FluidDirectionCache.java b/src/main/java/gg/airplane/structs/FluidDirectionCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa8467b9dda1f7707e41f50ac7b3e9d7343723ec
--- /dev/null
+++ b/src/main/java/gg/airplane/structs/FluidDirectionCache.java
@@ -0,0 +1,136 @@
+package gg.airplane.structs;
+
+import it.unimi.dsi.fastutil.HashCommon;
+
+/**
+ * This is a replacement for the cache used in FluidTypeFlowing.
+ * The requirements for the previous cache were:
+ * - Store 200 entries
+ * - Look for the flag in the cache
+ * - If it exists, move to front of cache
+ * - If it doesn't exist, remove last entry in cache and insert in front
+ *
+ * This class accomplishes something similar, however has a few different
+ * requirements put into place to make this more optimize:
+ *
+ * - maxDistance is the most amount of entries to be checked, instead
+ * of having to check the entire list.
+ * - In combination with that, entries are all tracked by age and how
+ * frequently they're used. This enables us to remove old entries,
+ * without constantly shifting any around.
+ *
+ * Usage of the previous map would have to reset the head every single usage,
+ * shifting the entire map. Here, nothing happens except an increment when
+ * the cache is hit, and when it needs to replace an old element only a single
+ * element is modified.
+ */
+public class FluidDirectionCache<T> {
+
+ private static class FluidDirectionEntry<T> {
+ private final T data;
+ private final boolean flag;
+ private int uses = 0;
+ private int age = 0;
+
+ private FluidDirectionEntry(T data, boolean flag) {
+ this.data = data;
+ this.flag = flag;
+ }
+
+ public int getValue() {
+ return this.uses - (this.age >> 1); // age isn't as important as uses
+ }
+
+ public void incrementUses() {
+ this.uses = this.uses + 1 & Integer.MAX_VALUE;
+ }
+
+ public void incrementAge() {
+ this.age = this.age + 1 & Integer.MAX_VALUE;
+ }
+ }
+
+ private final FluidDirectionEntry[] entries;
+ private final int mask;
+ private final int maxDistance; // the most amount of entries to check for a value
+
+ public FluidDirectionCache(int size) {
+ int arraySize = HashCommon.nextPowerOfTwo(size);
+ this.entries = new FluidDirectionEntry[arraySize];
+ this.mask = arraySize - 1;
+ this.maxDistance = Math.min(arraySize, 4);
+ }
+
+ public Boolean getValue(T data) {
+ FluidDirectionEntry curr;
+ int pos;
+
+ if ((curr = this.entries[pos = HashCommon.mix(data.hashCode()) & this.mask]) == null) {
+ return null;
+ } else if (data.equals(curr.data)) {
+ curr.incrementUses();
+ return curr.flag;
+ }
+
+ int checked = 1; // start at 1 because we already checked the first spot above
+
+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) {
+ if (data.equals(curr.data)) {
+ curr.incrementUses();
+ return curr.flag;
+ } else if (++checked >= this.maxDistance) {
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ public void putValue(T data, boolean flag) {
+ FluidDirectionEntry<T> curr;
+ int pos;
+
+ if ((curr = this.entries[pos = HashCommon.mix(data.hashCode()) & this.mask]) == null) {
+ this.entries[pos] = new FluidDirectionEntry<>(data, flag); // add
+ return;
+ } else if (data.equals(curr.data)) {
+ curr.incrementUses();
+ return;
+ }
+
+ int checked = 1; // start at 1 because we already checked the first spot above
+
+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) {
+ if (data.equals(curr.data)) {
+ curr.incrementUses();
+ return;
+ } else if (++checked >= this.maxDistance) {
+ this.forceAdd(data, flag);
+ return;
+ }
+ }
+
+ this.entries[pos] = new FluidDirectionEntry<>(data, flag); // add
+ }
+
+ private void forceAdd(T data, boolean flag) {
+ int expectedPos = HashCommon.mix(data.hashCode()) & this.mask;
+
+ int toRemovePos = expectedPos;
+ FluidDirectionEntry entryToRemove = this.entries[toRemovePos];
+
+ for (int i = expectedPos + 1; i < expectedPos + this.maxDistance; i++) {
+ int pos = i & this.mask;
+ FluidDirectionEntry entry = this.entries[pos];
+ if (entry.getValue() < entryToRemove.getValue()) {
+ toRemovePos = pos;
+ entryToRemove = entry;
+ }
+
+ entry.incrementAge(); // use this as a mechanism to age the other entries
+ }
+
+ // remove the least used/oldest entry
+ this.entries[toRemovePos] = new FluidDirectionEntry(data, flag);
+ }
+}
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
index 6e3e873efa1f50f53cb6503bde8a981f9cefd006..32d15354ceb46fb06b1c36049d3a8bfba718acaf 100644
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
@@ -45,6 +45,8 @@ public abstract class FlowingFluid extends Fluid {
public static final BooleanProperty FALLING = BlockStateProperties.FALLING;
public static final IntegerProperty LEVEL = BlockStateProperties.LEVEL_FLOWING;
private static final int CACHE_SIZE = 200;
+ // Airplane start - use our own cache
+ /*
private static final ThreadLocal<Object2ByteLinkedOpenHashMap<Block.BlockStatePairKey>> OCCLUSION_CACHE = ThreadLocal.withInitial(() -> {
Object2ByteLinkedOpenHashMap<Block.BlockStatePairKey> object2bytelinkedopenhashmap = new Object2ByteLinkedOpenHashMap<Block.BlockStatePairKey>(200) {
protected void rehash(int i) {}
@@ -53,6 +55,14 @@ public abstract class FlowingFluid extends Fluid {
object2bytelinkedopenhashmap.defaultReturnValue((byte) 127);
return object2bytelinkedopenhashmap;
});
+ */
+
+ private static final ThreadLocal<gg.airplane.structs.FluidDirectionCache<Block.BlockStatePairKey>> localFluidDirectionCache = ThreadLocal.withInitial(() -> {
+ // Airplane todo - mess with this number for performance
+ // with 2048 it seems very infrequent on a small world that it has to remove old entries
+ return new gg.airplane.structs.FluidDirectionCache<>(2048);
+ });
+ // Airplane end
private final Map<FluidState, VoxelShape> shapes = Maps.newIdentityHashMap();
public FlowingFluid() {}
@@ -240,6 +250,8 @@ public abstract class FlowingFluid extends Fluid {
}
private boolean canPassThroughWall(Direction face, BlockGetter world, BlockPos pos, BlockState state, BlockPos fromPos, BlockState fromState) {
+ // Airplane start - modify to use our cache
+ /*
Object2ByteLinkedOpenHashMap object2bytelinkedopenhashmap;
if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) {
@@ -247,9 +259,16 @@ public abstract class FlowingFluid extends Fluid {
} else {
object2bytelinkedopenhashmap = null;
}
+ */
+ gg.airplane.structs.FluidDirectionCache<Block.BlockStatePairKey> cache = null;
+
+ if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) {
+ cache = localFluidDirectionCache.get();
+ }
Block.BlockStatePairKey block_a;
+ /*
if (object2bytelinkedopenhashmap != null) {
block_a = new Block.BlockStatePairKey(state, fromState, face);
byte b0 = object2bytelinkedopenhashmap.getAndMoveToFirst(block_a);
@@ -260,11 +279,22 @@ public abstract class FlowingFluid extends Fluid {
} else {
block_a = null;
}
+ */
+ if (cache != null) {
+ block_a = new Block.BlockStatePairKey(state, fromState, face);
+ Boolean flag = cache.getValue(block_a);
+ if (flag != null) {
+ return flag;
+ }
+ } else {
+ block_a = null;
+ }
VoxelShape voxelshape = state.getCollisionShape(world, pos);
VoxelShape voxelshape1 = fromState.getCollisionShape(world, fromPos);
boolean flag = !Shapes.mergedFaceOccludes(voxelshape, voxelshape1, face);
+ /*
if (object2bytelinkedopenhashmap != null) {
if (object2bytelinkedopenhashmap.size() == 200) {
object2bytelinkedopenhashmap.removeLastByte();
@@ -272,6 +302,11 @@ public abstract class FlowingFluid extends Fluid {
object2bytelinkedopenhashmap.putAndMoveToFirst(block_a, (byte) (flag ? 1 : 0));
}
+ */
+ if (cache != null) {
+ cache.putValue(block_a, flag);
+ }
+ // Airplane end
return flag;
}

View File

@@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Mon, 26 Apr 2021 10:52:56 -0500
Subject: [PATCH] Cache climbing check for activation
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 402b785b5fd0e1c3c5c02505dca332990ec64e37..c22bf8f7df311ae3f2973667764e9768bcc9065d 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -142,7 +142,6 @@ import org.bukkit.event.entity.EntityTeleportEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
// CraftBukkit end
-import co.aikar.timings.MinecraftTimings; // Paper
public abstract class LivingEntity extends Entity {
@@ -1824,6 +1823,20 @@ public abstract class LivingEntity extends Entity {
return this.lastClimbablePos;
}
+
+ // Airplane start
+ private boolean cachedOnClimable = false;
+ private BlockPos lastClimbingPosition = null;
+
+ public boolean onClimableCached() {
+ if (!this.blockPosition().equals(this.lastClimbingPosition)) {
+ this.cachedOnClimable = this.onClimbable();
+ this.lastClimbingPosition = this.blockPosition();
+ }
+ return this.cachedOnClimable;
+ }
+ // Airplane end
+
public boolean onClimbable() {
if (this.isSpectator()) {
return false;
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 966639cc6ba6684bfb52e91ac047808cf4d003e4..6d1ed4bf941610fb9210a32f944a4b916527138f 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -276,7 +276,7 @@ public class ActivationRange
if ( entity instanceof LivingEntity )
{
LivingEntity living = (LivingEntity) entity;
- if ( living.onClimbable() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0 ) // Paper
+ if ( living.onClimableCached() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0 ) // Paper // Airplane - use cached
{
return 1; // Paper
}

View File

@@ -1,66 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sun, 9 May 2021 16:49:49 -0500
Subject: [PATCH] Use array for gamerule storage
diff --git a/src/main/java/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java
index e7ca5d6fb8922e7e8065864f736b06056be080a0..833ad6fbedfc275b3fde640b0e873f23e61acc3b 100644
--- a/src/main/java/net/minecraft/world/level/GameRules.java
+++ b/src/main/java/net/minecraft/world/level/GameRules.java
@@ -90,6 +90,7 @@ public class GameRules {
public static final GameRules.Key<GameRules.BooleanValue> RULE_UNIVERSAL_ANGER = GameRules.register("universalAnger", GameRules.Category.MOBS, GameRules.BooleanValue.create(false));
public static final GameRules.Key<GameRules.IntegerValue> RULE_PLAYERS_SLEEPING_PERCENTAGE = GameRules.register("playersSleepingPercentage", GameRules.Category.PLAYER, GameRules.IntegerValue.create(100));
private final Map<GameRules.Key<?>, GameRules.Value<?>> rules;
+ private final GameRules.Value<?>[] gameruleArray;
private static <T extends GameRules.Value<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
GameRules.Key<T> gamerules_gamerulekey = new GameRules.Key<>(name, category);
@@ -108,17 +109,33 @@ public class GameRules {
}
public GameRules() {
- this.rules = (Map) GameRules.GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
+ // Airplane start - use this to ensure gameruleArray is initialized
+ this((Map) GameRules.GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
return ((GameRules.Type) entry.getValue()).createRule();
- }));
+ })));
+ // Airplane end
}
private GameRules(Map<GameRules.Key<?>, GameRules.Value<?>> rules) {
this.rules = rules;
+
+ // Airplane start
+ int arraySize = rules.keySet().stream().mapToInt(key -> key.gameRuleIndex).max().orElse(-1) + 1;
+ GameRules.Value<?>[] values = new GameRules.Value[arraySize];
+
+ for (Entry<GameRules.Key<?>, GameRules.Value<?>> entry : rules.entrySet()) {
+ values[entry.getKey().gameRuleIndex] = entry.getValue();
+ }
+
+ this.gameruleArray = values;
+ // Airplane end
}
public <T extends GameRules.Value<T>> T getRule(GameRules.Key<T> key) {
- return (T) this.rules.get(key); // CraftBukkit - decompile error
+ // Airplane start
+ return key == null ? null : (T) this.gameruleArray[key.gameRuleIndex];
+ //return (T) this.rules.get(key); // CraftBukkit - decompile error
+ // Airplane end
}
public CompoundTag createTag() {
@@ -177,6 +194,10 @@ public class GameRules {
}
public static final class Key<T extends GameRules.Value<T>> {
+ // Airplane start
+ private static int lastGameRuleIndex = 0;
+ public final int gameRuleIndex = lastGameRuleIndex++;
+ // Airplane end
final String id;
private final GameRules.Category category;

View File

@@ -1,117 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sun, 9 May 2021 18:35:05 -0500
Subject: [PATCH] Make EntityCollisionContext a live representation
While Context is in the name, it is not used as a context. Instead it is
always created, use temporarily, then thrown away. This means having a
lot of fields to initialize and make space for is useless. I cannot find
anywhere in the codebase where this is used as a context which may be
saved for later, so this should be safe assuming plugins don't use it
for some strange reason.
diff --git a/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java b/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java
index fcb7bd9f3b6b6ada0f2e5692bce32ab76b8798a7..61c2096f2c034dbc3ad33b193b058c7d0d05e909 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java
@@ -22,55 +22,82 @@ public class EntityCollisionContext implements CollisionContext {
return defaultValue;
}
};
- private final boolean descending;
- private final double entityBottom;
- private final ItemStack heldItem;
- private final ItemStack footItem;
- private final Predicate<Fluid> canStandOnFluid;
- private final Optional<Entity> entity;
+ // Airplane start - remove these and pray no plugin uses them
+ //private final boolean descending;
+ //private final double entityBottom;
+ //private final ItemStack heldItem;
+ //private final ItemStack footItem;
+ //private final Predicate<Fluid> canStandOnFluid;
+ // Airplane end
+ private final @org.jetbrains.annotations.Nullable Entity entity; // Airplane
protected EntityCollisionContext(boolean descending, double minY, ItemStack boots, ItemStack heldItem, Predicate<Fluid> walkOnFluidPredicate, Optional<Entity> entity) {
- this.descending = descending;
- this.entityBottom = minY;
- this.footItem = boots;
- this.heldItem = heldItem;
- this.canStandOnFluid = walkOnFluidPredicate;
- this.entity = entity;
+ // Airplane start
+ //this.descending = descending;
+ //this.entityBottom = minY;
+ //this.footItem = boots;
+ //this.heldItem = heldItem;
+ ///this.canStandOnFluid = walkOnFluidPredicate;
+ this.entity = entity.orElse(null);
+ // Airplane end
}
@Deprecated
protected EntityCollisionContext(Entity entity) {
+ // Airplane start - remove unneeded things
+ /*
this(entity.isDescending(), entity.getY(), entity instanceof LivingEntity ? ((LivingEntity)entity).getItemBySlot(EquipmentSlot.FEET) : ItemStack.EMPTY, entity instanceof LivingEntity ? ((LivingEntity)entity).getMainHandItem() : ItemStack.EMPTY, entity instanceof LivingEntity ? ((LivingEntity)entity)::canStandOnFluid : (fluid) -> {
return false;
}, Optional.of(entity));
+ */
+ this.entity = entity;
+ // Airplane end
}
@Override
public boolean hasItemOnFeet(Item item) {
- return this.footItem.is(item);
+ // Airplane start
+ Entity entity = this.entity;
+ if (entity instanceof LivingEntity livingEntity) {
+ return livingEntity.getItemBySlot(EquipmentSlot.FEET).is(item);
+ }
+ return ItemStack.EMPTY.is(item);
+ // Airplane end
}
@Override
public boolean isHoldingItem(Item item) {
- return this.heldItem.is(item);
+ // Airplane start
+ Entity entity = this.entity;
+ if (entity instanceof LivingEntity livingEntity) {
+ return livingEntity.getMainHandItem().is(item);
+ }
+ return ItemStack.EMPTY.is(item);
+ // Airplane end
}
@Override
public boolean canStandOnFluid(FluidState state, FlowingFluid fluid) {
- return this.canStandOnFluid.test(fluid) && !state.getType().isSame(fluid);
+ // Airplane start
+ Entity entity = this.entity;
+ if (entity instanceof LivingEntity livingEntity) {
+ return livingEntity.canStandOnFluid(fluid) && !state.getType().isSame(fluid);
+ }
+ return false;
+ // Airplane end
}
@Override
public boolean isDescending() {
- return this.descending;
+ return this.entity != null && this.entity.isDescending(); // Airplane
}
@Override
public boolean isAbove(VoxelShape shape, BlockPos pos, boolean defaultValue) {
- return this.entityBottom > (double)pos.getY() + shape.max(Direction.Axis.Y) - (double)1.0E-5F;
+ return (this.entity == null ? -Double.MAX_VALUE : entity.getY()) > (double)pos.getY() + shape.max(Direction.Axis.Y) - (double)1.0E-5F; // Airplane
}
public Optional<Entity> getEntity() {
- return this.entity;
+ return Optional.ofNullable(this.entity); // Airplane
}
}

View File

@@ -1,491 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Wed, 19 May 2021 13:08:26 -0500
Subject: [PATCH] Improve container checking with a bitset
diff --git a/src/main/java/gg/airplane/structs/ItemListWithBitset.java b/src/main/java/gg/airplane/structs/ItemListWithBitset.java
new file mode 100644
index 0000000000000000000000000000000000000000..04565b596f7579eb22263ef844513aeba3437eb3
--- /dev/null
+++ b/src/main/java/gg/airplane/structs/ItemListWithBitset.java
@@ -0,0 +1,105 @@
+package gg.airplane.structs;
+
+import net.minecraft.core.NonNullList;
+import net.minecraft.world.item.ItemStack;
+import org.apache.commons.lang.Validate;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+
+public class ItemListWithBitset extends NonNullList<ItemStack> {
+ public static ItemListWithBitset fromNonNullList(NonNullList<ItemStack> list) {
+ if (list instanceof ItemListWithBitset) {
+ return (ItemListWithBitset) list;
+ }
+ return new ItemListWithBitset(list);
+ }
+
+ private static ItemStack[] createArray(int size) {
+ ItemStack[] array = new ItemStack[size];
+ Arrays.fill(array, ItemStack.EMPTY);
+ return array;
+ }
+
+ private final ItemStack[] items;
+
+ private long bitSet = 0;
+ private final long allBits;
+
+ private ItemListWithBitset(NonNullList<ItemStack> list) {
+ this(list.size());
+
+ for (int i = 0; i < list.size(); i++) {
+ this.set(i, list.get(i));
+ }
+ }
+
+ public ItemListWithBitset(int size) {
+ super(null, ItemStack.EMPTY);
+
+ Validate.isTrue(size < Long.BYTES * 8, "size is too large");
+
+ this.items = createArray(size);
+ this.allBits = ((1L << size) - 1);
+ }
+
+ public boolean isCompletelyEmpty() {
+ return this.bitSet == 0;
+ }
+
+ public boolean hasFullStacks() {
+ return (this.bitSet & this.allBits) == allBits;
+ }
+
+ @Override
+ public ItemStack set(int index, @NotNull ItemStack itemStack) {
+ ItemStack existing = this.items[index];
+
+ this.items[index] = itemStack;
+
+ if (itemStack == ItemStack.EMPTY) {
+ this.bitSet &= ~(1L << index);
+ } else {
+ this.bitSet |= 1L << index;
+ }
+
+ return existing;
+ }
+
+ @NotNull
+ @Override
+ public ItemStack get(int var0) {
+ return this.items[var0];
+ }
+
+ @Override
+ public int size() {
+ return this.items.length;
+ }
+
+ @Override
+ public void clear() {
+ Arrays.fill(this.items, ItemStack.EMPTY);
+ }
+
+ // these are unsupported for block inventories which have a static size
+ @Override
+ public void add(int var0, ItemStack var1) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ItemStack remove(int var0) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return "ItemListWithBitset{" +
+ "items=" + Arrays.toString(items) +
+ ", bitSet=" + Long.toString(bitSet, 2) +
+ ", allBits=" + Long.toString(allBits, 2) +
+ ", size=" + this.items.length +
+ '}';
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 937888b9c36a5bfaf661bfd740b12a634558f527..2ddd63954c98948602949ff53a7f8905c729da71 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -579,6 +579,21 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
return result;
}
+ // Airplane start - skip type lookup if already completed, but still run check
+ public BlockEntity getAndCheckTileEntity(BlockState data, BlockPos pos) {
+ BlockEntity result = super.getTileEntity(pos, false);
+
+ // copied from above
+ if (result != null && !data.isAir()) {
+ if (!result.getType().isValid(data)) {
+ result = fixTileEntity(pos, data, result);
+ }
+ }
+
+ return result;
+ }
+ // Airplane end
+
private BlockEntity fixTileEntity(BlockPos pos, BlockState type, BlockEntity found) {
this.getCraftServer().getLogger().log(Level.SEVERE, "Block at {0}, {1}, {2} is {3} but has {4}" + ". "
+ "Bukkit will attempt to fix this, but there may be additional damage that we cannot recover.", new Object[]{pos.getX(), pos.getY(), pos.getZ(), type, found});
diff --git a/src/main/java/net/minecraft/world/CompoundContainer.java b/src/main/java/net/minecraft/world/CompoundContainer.java
index 087ae3a6b49872a3580eb1a572bdbc493711a77a..5ef8657197beea06c1dcad6a32968c56a823b182 100644
--- a/src/main/java/net/minecraft/world/CompoundContainer.java
+++ b/src/main/java/net/minecraft/world/CompoundContainer.java
@@ -1,5 +1,6 @@
package net.minecraft.world;
+import net.minecraft.core.Direction; // Airplane
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
@@ -72,6 +73,23 @@ public class CompoundContainer implements Container {
this.container2 = second;
}
+ // Airplane start
+ @Override
+ public boolean hasEmptySlot(Direction enumdirection) {
+ return this.container1.hasEmptySlot(null) || this.container2.hasEmptySlot(null);
+ }
+
+ @Override
+ public boolean isCompletelyFull(Direction enumdirection) {
+ return this.container1.isCompletelyFull(null) && this.container2.isCompletelyFull(null);
+ }
+
+ @Override
+ public boolean isCompletelyEmpty(Direction enumdirection) {
+ return this.container1.isCompletelyEmpty(null) && this.container2.isCompletelyEmpty(null);
+ }
+ // Airplane end
+
@Override
public int getContainerSize() {
return this.container1.getContainerSize() + this.container2.getContainerSize();
diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java
index 7437f01ca8f416e2c9150250e324af4725a4efb6..bdcd0e38a3ba904811112f41d8bfbfc0902ef190 100644
--- a/src/main/java/net/minecraft/world/Container.java
+++ b/src/main/java/net/minecraft/world/Container.java
@@ -1,6 +1,8 @@
package net.minecraft.world;
import java.util.Set;
+
+import net.minecraft.core.Direction; // Airplane
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@@ -9,6 +11,63 @@ import org.bukkit.craftbukkit.entity.CraftHumanEntity;
// CraftBukkit end
public interface Container extends Clearable {
+ // Airplane start - allow the inventory to override and optimize these frequent calls
+ default boolean hasEmptySlot(@org.jetbrains.annotations.Nullable Direction enumdirection) { // there is a slot with 0 items in it
+ if (this instanceof WorldlyContainer worldlyContainer) {
+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) {
+ if (this.getItem(i).isEmpty()) {
+ return true;
+ }
+ }
+ } else {
+ int size = this.getContainerSize();
+ for (int i = 0; i < size; i++) {
+ if (this.getItem(i).isEmpty()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ default boolean isCompletelyFull(@org.jetbrains.annotations.Nullable Direction enumdirection) { // every stack is maxed
+ if (this instanceof WorldlyContainer worldlyContainer) {
+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) {
+ ItemStack itemStack = this.getItem(i);
+ if (itemStack.getCount() < itemStack.getMaxStackSize()) {
+ return false;
+ }
+ }
+ } else {
+ int size = this.getContainerSize();
+ for (int i = 0; i < size; i++) {
+ ItemStack itemStack = this.getItem(i);
+ if (itemStack.getCount() < itemStack.getMaxStackSize()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ default boolean isCompletelyEmpty(@org.jetbrains.annotations.Nullable Direction enumdirection) {
+ if (this instanceof WorldlyContainer worldlyContainer) {
+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) {
+ if (!this.getItem(i).isEmpty()) {
+ return false;
+ }
+ }
+ } else {
+ int size = this.getContainerSize();
+ for (int i = 0; i < size; i++) {
+ if (!this.getItem(i).isEmpty()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ // Airplane end
int LARGE_MAX_STACK_SIZE = 64;
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
index f57864ce919ef4721cfb5913c636fe8903ce4cc1..4792d3d60e60202face2eb851c9f5b122dcfc19d 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
@@ -40,7 +40,7 @@ import org.bukkit.inventory.InventoryHolder;
public abstract class AbstractMinecartContainer extends AbstractMinecart implements Container, MenuProvider {
- private NonNullList<ItemStack> itemStacks;
+ private gg.airplane.structs.ItemListWithBitset itemStacks; // Airplane
@Nullable
public ResourceLocation lootTable;
public long lootTableSeed;
@@ -89,12 +89,12 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
protected AbstractMinecartContainer(EntityType<?> type, Level world) {
super(type, world);
- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513
+ this.itemStacks = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 // Airplane
}
protected AbstractMinecartContainer(EntityType<?> type, double x, double y, double z, Level world) {
super(type, world, x, y, z);
- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513
+ this.itemStacks = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 // Airplane
}
@Override
@@ -217,7 +217,7 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
this.lootableData.loadNbt(nbt); // Paper
- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
+ this.itemStacks = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // Airplane
if (nbt.contains("LootTable", 8)) {
this.lootTable = new ResourceLocation(nbt.getString("LootTable"));
this.lootTableSeed = nbt.getLong("LootTableSeed");
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
index 52de9852f87d346714a950b60a0004d386ac10f0..305a8f5ea917c7e242011fa98a3e161517afe9be 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
@@ -32,7 +32,7 @@ import org.bukkit.entity.HumanEntity;
public class ChestBlockEntity extends RandomizableContainerBlockEntity implements LidBlockEntity {
private static final int EVENT_SET_OPEN_COUNT = 1;
- private NonNullList<ItemStack> items;
+ private gg.airplane.structs.ItemListWithBitset items; // Airplane
public final ContainerOpenersCounter openersCounter;
private final ChestLidController chestLidController;
@@ -66,9 +66,10 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
}
// CraftBukkit end
+ private final boolean isNative = getClass().equals(ChestBlockEntity.class); // Airplane
protected ChestBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
- this.items = NonNullList.withSize(27, ItemStack.EMPTY);
+ this.items = new gg.airplane.structs.ItemListWithBitset(27); // Airplane - use with bitset
this.openersCounter = new ContainerOpenersCounter() {
@Override
protected void onOpen(Level world, BlockPos pos, BlockState state) {
@@ -99,6 +100,23 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
this.chestLidController = new ChestLidController();
}
+ // Airplane start
+ @Override
+ public boolean hasEmptySlot(Direction enumdirection) {
+ return isNative ? !this.items.hasFullStacks() : super.hasEmptySlot(enumdirection);
+ }
+
+ @Override
+ public boolean isCompletelyFull(Direction enumdirection) {
+ return isNative ? this.items.hasFullStacks() && super.isCompletelyFull(enumdirection) : super.isCompletelyFull(enumdirection);
+ }
+
+ @Override
+ public boolean isCompletelyEmpty(Direction enumdirection) {
+ return isNative && this.items.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection);
+ }
+ // Airplane end
+
public ChestBlockEntity(BlockPos pos, BlockState state) {
this(BlockEntityType.CHEST, pos, state);
}
@@ -116,7 +134,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
+ this.items = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // Airplane
if (!this.tryLoadLootTable(nbt)) {
ContainerHelper.loadAllItems(nbt, this.items);
}
@@ -189,7 +207,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
@Override
protected void setItems(NonNullList<ItemStack> list) {
- this.items = list;
+ this.items = gg.airplane.structs.ItemListWithBitset.fromNonNullList(list); // Airplane
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 3b1442bf4c83650369e925d76f07dc67c6cbbc83..80ae677938ad0ed79bc63974a1fec62e49506713 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -44,7 +44,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public static final int MOVE_ITEM_SPEED = 8;
public static final int HOPPER_CONTAINER_SIZE = 5;
- private NonNullList<ItemStack> items;
+ private gg.airplane.structs.ItemListWithBitset items; // Airplane
private int cooldownTime;
private long tickedGameTime;
@@ -80,14 +80,31 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public HopperBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.HOPPER, pos, state);
- this.items = NonNullList.withSize(5, ItemStack.EMPTY);
+ this.items = new gg.airplane.structs.ItemListWithBitset(5); // Airplane
this.cooldownTime = -1;
}
+ // Airplane start
+ @Override
+ public boolean hasEmptySlot(Direction enumdirection) {
+ return !this.items.hasFullStacks();
+ }
+
+ @Override
+ public boolean isCompletelyFull(Direction enumdirection) {
+ return this.items.hasFullStacks() && super.isCompletelyFull(enumdirection);
+ }
+
+ @Override
+ public boolean isCompletelyEmpty(Direction enumdirection) {
+ return this.items.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection);
+ }
+ // Airplane end
+
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
+ this.items = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // Airplane
if (!this.tryLoadLootTable(nbt)) {
ContainerHelper.loadAllItems(nbt, this.items);
}
@@ -160,7 +177,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
flag = HopperBlockEntity.a(world, pos, state, (Container) blockEntity, blockEntity); // CraftBukkit
}
- if (!blockEntity.inventoryFull()) {
+ if (!blockEntity.items.hasFullStacks() || !blockEntity.inventoryFull()) { // Airplane - use bitset first
flag |= booleansupplier.getAsBoolean();
}
@@ -199,7 +216,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
skipPushModeEventFire = skipHopperEvents;
boolean foundItem = false;
for (int i = 0; i < hopper.getContainerSize(); ++i) {
- ItemStack item = hopper.getItem(i);
+ ItemStack item = hopper.getItem(i); // Airplane
if (!item.isEmpty()) {
foundItem = true;
ItemStack origItemStack = item;
@@ -403,12 +420,18 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
private static boolean isFullContainer(Container inventory, Direction direction) {
- return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams
+ // Airplane start - use bitsets
+ //return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams
+ return inventory.isCompletelyFull(direction);
+ // Airplane end
}
private static boolean isEmptyContainer(Container inv, Direction facing) {
// Paper start
- return allMatch(inv, facing, IS_EMPTY_TEST);
+ // Airplane start - use bitsets
+ //return allMatch(inv, facing, IS_EMPTY_TEST);
+ return inv.isCompletelyEmpty(facing);
+ // Airplane end
}
private static boolean allMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
if (iinventory instanceof WorldlyContainer) {
@@ -585,7 +608,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (HopperBlockEntity.canPlaceItemInContainer(to, stack, slot, enumdirection)) {
boolean flag = false;
- boolean flag1 = to.isEmpty();
+ boolean flag1 = to.isCompletelyEmpty(enumdirection); // Airplane
if (itemstack1.isEmpty()) {
IGNORE_TILE_UPDATES = true; // Paper
@@ -667,7 +690,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (block instanceof WorldlyContainerHolder) {
object = ((WorldlyContainerHolder) block).getContainer(iblockdata, world, blockposition);
} else if (iblockdata.hasBlockEntity()) {
- BlockEntity tileentity = world.getBlockEntity(blockposition);
+ BlockEntity tileentity = ((net.minecraft.server.level.ServerLevel) world).getAndCheckTileEntity(iblockdata, blockposition); // Airplane - skip validation step, which does 2nd type lookup
if (tileentity instanceof Container) {
object = (Container) tileentity;
@@ -726,7 +749,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Override
protected void setItems(NonNullList<ItemStack> list) {
- this.items = list;
+ this.items = gg.airplane.structs.ItemListWithBitset.fromNonNullList(list); // Airplane
}
public static void entityInside(Level world, BlockPos pos, BlockState state, Entity entity, HopperBlockEntity blockEntity) {
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
index ed3518fe7c841d9e1a9c97626acaa3d765a6d76f..ac564148956beb984650341c5c0994573f4f7225 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
@@ -96,13 +96,8 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
public boolean isEmpty() {
this.unpackLootTable((Player)null);
// Paper start
- for (ItemStack itemStack : this.getItems()) {
- if (!itemStack.isEmpty()) {
- return false;
- }
- }
+ return this.isCompletelyEmpty(null); // Airplane - use super
// Paper end
- return true;
}
@Override

View File

@@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Thu, 20 May 2021 12:05:47 -0500
Subject: [PATCH] Better checking for useless move packets
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index a00627e0fa38632449042f59c053b4dac13e58bf..d77a10c6ae7e1515085ff7a18db9e3e14ebb8012 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -174,6 +174,7 @@ public class ServerEntity {
boolean flag4 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L;
if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround() && !(com.tuinity.tuinity.config.TuinityConfig.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Tuinity - send full pos for hard colliding entities to prevent collision problems due to desync
+ if (flag2 || flag3 || this.entity instanceof AbstractArrow) { // Airplane
if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) {
if (flag2) {
packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.isOnGround());
@@ -183,6 +184,7 @@ public class ServerEntity {
} else {
packet1 = new ClientboundMoveEntityPacket.PosRot(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), (byte) i, (byte) j, this.entity.isOnGround());
}
+ } // Airplane
} else {
this.wasOnGround = this.entity.isOnGround();
this.teleportDelay = 0;

View File

@@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Tue, 1 Jun 2021 18:06:29 -0500
Subject: [PATCH] Patch Paper to use fast item merge raytracing
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
index 158719d46c96bb733a00e08c8285f41a48406abf..2dac4bc346eb1dde1f8d92c3e5b9648b2c433617 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -243,10 +243,16 @@ public class ItemEntity extends Entity {
if (entityitem.isMergable()) {
// Paper Start - Fix items merging through walls
if (this.level.paperConfig.fixItemsMergingThroughWalls) {
+ // Airplane start - skip the allocations
+ /*
net.minecraft.world.level.ClipContext rayTrace = new net.minecraft.world.level.ClipContext(this.position(), entityitem.position(),
net.minecraft.world.level.ClipContext.Block.COLLIDER, net.minecraft.world.level.ClipContext.Fluid.NONE, this);
net.minecraft.world.phys.BlockHitResult rayTraceResult = level.clip(rayTrace);
if (rayTraceResult.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
+ */
+ if (level.rayTraceDirect(this.position(), entityitem.position(), net.minecraft.world.phys.shapes.CollisionContext.of(this)) ==
+ net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
+ // Airplane end
}
// Paper End
this.tryToMerge(entityitem);

View File

@@ -1,181 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Tue, 22 Jun 2021 14:49:50 -0500
Subject: [PATCH] Use aging cache for biome temperatures
diff --git a/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java b/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7f297ebb569f7c1f205e967ca485be70013a714
--- /dev/null
+++ b/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java
@@ -0,0 +1,119 @@
+package gg.airplane.structs;
+
+import it.unimi.dsi.fastutil.HashCommon;
+
+/**
+ * A replacement for the cache used in Biome.
+ */
+public class Long2FloatAgingCache {
+
+ private static class AgingEntry {
+ private long data;
+ private float value;
+ private int uses = 0;
+ private int age = 0;
+
+ private AgingEntry(long data, float value) {
+ this.data = data;
+ this.value = value;
+ }
+
+ public void replace(long data, float flag) {
+ this.data = data;
+ this.value = flag;
+ }
+
+ public int getValue() {
+ return this.uses - (this.age >> 1); // age isn't as important as uses
+ }
+
+ public void incrementUses() {
+ this.uses = this.uses + 1 & Integer.MAX_VALUE;
+ }
+
+ public void incrementAge() {
+ this.age = this.age + 1 & Integer.MAX_VALUE;
+ }
+ }
+
+ private final AgingEntry[] entries;
+ private final int mask;
+ private final int maxDistance; // the most amount of entries to check for a value
+
+ public Long2FloatAgingCache(int size) {
+ int arraySize = HashCommon.nextPowerOfTwo(size);
+ this.entries = new AgingEntry[arraySize];
+ this.mask = arraySize - 1;
+ this.maxDistance = Math.min(arraySize, 4);
+ }
+
+ public float getValue(long data) {
+ AgingEntry curr;
+ int pos;
+
+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) {
+ return Float.NaN;
+ } else if (data == curr.data) {
+ curr.incrementUses();
+ return curr.value;
+ }
+
+ int checked = 1; // start at 1 because we already checked the first spot above
+
+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) {
+ if (data == curr.data) {
+ curr.incrementUses();
+ return curr.value;
+ } else if (++checked >= this.maxDistance) {
+ break;
+ }
+ }
+
+ return Float.NaN;
+ }
+
+ public void putValue(long data, float value) {
+ AgingEntry curr;
+ int pos;
+
+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) {
+ this.entries[pos] = new AgingEntry(data, value); // add
+ return;
+ } else if (data == curr.data) {
+ curr.incrementUses();
+ return;
+ }
+
+ int checked = 1; // start at 1 because we already checked the first spot above
+
+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) {
+ if (data == curr.data) {
+ curr.incrementUses();
+ return;
+ } else if (++checked >= this.maxDistance) {
+ this.forceAdd(data, value);
+ return;
+ }
+ }
+
+ this.entries[pos] = new AgingEntry(data, value); // add
+ }
+
+ private void forceAdd(long data, float value) {
+ int expectedPos = HashCommon.mix(HashCommon.long2int(data)) & this.mask;
+ AgingEntry entryToRemove = this.entries[expectedPos];
+
+ for (int i = expectedPos + 1; i < expectedPos + this.maxDistance; i++) {
+ int pos = i & this.mask;
+ AgingEntry entry = this.entries[pos];
+ if (entry.getValue() < entryToRemove.getValue()) {
+ entryToRemove = entry;
+ }
+
+ entry.incrementAge(); // use this as a mechanism to age the other entries
+ }
+
+ // remove the least used/oldest entry
+ entryToRemove.replace(data, value);
+ }
+}
diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java
index a7a7e6cd87270e64a92448f03f8b0b0c7e375ec7..0ea6fedf6e660bc133fd5eb34d3d9bac3e581f32 100644
--- a/src/main/java/net/minecraft/world/level/biome/Biome.java
+++ b/src/main/java/net/minecraft/world/level/biome/Biome.java
@@ -104,8 +104,10 @@ public final class Biome {
private final float scale;
private final Biome.BiomeCategory biomeCategory;
private final BiomeSpecialEffects specialEffects;
- private final ThreadLocal<Long2FloatLinkedOpenHashMap> temperatureCache = ThreadLocal.withInitial(() -> {
+ // Airplane start - use our cache
+ private final ThreadLocal<gg.airplane.structs.Long2FloatAgingCache> temperatureCache = ThreadLocal.withInitial(() -> {
return Util.make(() -> {
+ /*
Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = new Long2FloatLinkedOpenHashMap(1024, 0.25F) {
@Override
protected void rehash(int i) {
@@ -113,6 +115,10 @@ public final class Biome {
};
long2FloatLinkedOpenHashMap.defaultReturnValue(Float.NaN);
return long2FloatLinkedOpenHashMap;
+
+ */
+ return new gg.airplane.structs.Long2FloatAgingCache(TEMPERATURE_CACHE_SIZE);
+ // Airplane end
});
});
@@ -154,17 +160,15 @@ public final class Biome {
public final float getTemperature(BlockPos blockPos) {
long l = blockPos.asLong();
- Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = this.temperatureCache.get();
- float f = long2FloatLinkedOpenHashMap.get(l);
+ // Airplane start
+ gg.airplane.structs.Long2FloatAgingCache cache = this.temperatureCache.get();
+ float f = cache.getValue(l);
if (!Float.isNaN(f)) {
return f;
} else {
float g = this.getHeightAdjustedTemperature(blockPos);
- if (long2FloatLinkedOpenHashMap.size() == 1024) {
- long2FloatLinkedOpenHashMap.removeFirstFloat();
- }
-
- long2FloatLinkedOpenHashMap.put(l, g);
+ cache.putValue(l, g);
+ // Airplane end
return g;
}
}

View File

@@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Tue, 22 Jun 2021 15:01:21 -0500
Subject: [PATCH] Cache world height in the chunk, as it's final
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 4785cbd47e15f78c0302f1dc9bd904a4839ef8e4..ee2d00ccbe2d11324bb97fc43a213ed7ba1f111a 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -184,11 +184,13 @@ public class LevelChunk implements ChunkAccess {
}
// Airplane end
+ private final int levelHeight; private final int minBuildHeight; // Airplane
public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes) {
this(world, pos, biomes, UpgradeData.EMPTY, EmptyTickList.empty(), EmptyTickList.empty(), 0L, (LevelChunkSection[]) null, (Consumer) null);
}
public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes, UpgradeData upgradeData, TickList<Block> blockTickScheduler, TickList<Fluid> fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sections, @Nullable Consumer<LevelChunk> loadToWorldConsumer) {
+ this.levelHeight = world.getHeight(); this.minBuildHeight = world.getMinBuildHeight(); // Airplane
// Tuinity start
this.blockNibbles = StarLightEngine.getFilledEmptyLight(world);
this.skyNibbles = StarLightEngine.getFilledEmptyLight(world);
@@ -1303,13 +1305,17 @@ public class LevelChunk implements ChunkAccess {
}
@Override
- public int getMinBuildHeight() {
- return this.level.getMinBuildHeight();
+ // Airplane start
+ public final int getMinBuildHeight() {
+ return this.minBuildHeight;
+ // Airplane end
}
@Override
- public int getHeight() {
- return this.level.getHeight();
+ // Airplane start
+ public final int getHeight() {
+ return this.levelHeight;
+ // Airplane end
}
@Override

View File

@@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Tue, 22 Jun 2021 15:04:37 -0500
Subject: [PATCH] Use thread unsafe random for mob spawning
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 2ddd63954c98948602949ff53a7f8905c729da71..da4f0dc296c674e3ec393a724f6e2e595da536a0 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -893,7 +893,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
// Paper start - optimise random block ticking
private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos();
- private final com.tuinity.tuinity.util.math.ThreadUnsafeRandom randomTickRandom = new com.tuinity.tuinity.util.math.ThreadUnsafeRandom();
+ private final com.tuinity.tuinity.util.math.ThreadUnsafeRandom randomTickRandom = new com.tuinity.tuinity.util.math.ThreadUnsafeRandom(); public java.util.Random getThreadUnsafeRandom() { return this.randomTickRandom; } // Airplane - getter
// Paper end
private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Airplane
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 0059f0488acc22ebddc2faf4c5879f9f0c24fd14..074e25789152b8194797d6a3bae242e08f6be577 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -407,12 +407,12 @@ public final class NaturalSpawner {
return spawnGroup == MobCategory.MONSTER && world.getBlockState(pos.below()).is(Blocks.NETHER_BRICKS) && structureAccessor.getStructureAt(pos, false, StructureFeature.NETHER_BRIDGE).isValid() ? StructureFeature.NETHER_BRIDGE.getSpecialEnemies() : chunkGenerator.getMobsAt(biome != null ? biome : world.getBiome(pos), structureAccessor, spawnGroup, pos);
}
- private static BlockPos getRandomPosWithin(Level world, LevelChunk chunk) {
+ private static BlockPos getRandomPosWithin(ServerLevel world, LevelChunk chunk) { // Airplane - accept serverlevel
ChunkPos chunkcoordintpair = chunk.getPos();
- int i = chunkcoordintpair.getMinBlockX() + world.random.nextInt(16);
- int j = chunkcoordintpair.getMinBlockZ() + world.random.nextInt(16);
+ int i = chunkcoordintpair.getMinBlockX() + world.getThreadUnsafeRandom().nextInt(16); // Airplane - use thread unsafe random
+ int j = chunkcoordintpair.getMinBlockZ() + world.getThreadUnsafeRandom().nextInt(16); // Airplane
int k = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, j) + 1;
- int l = Mth.randomBetweenInclusive(world.random, world.getMinBuildHeight(), k);
+ int l = Mth.randomBetweenInclusive(world.getThreadUnsafeRandom(), world.getMinBuildHeight(), k); // Airplane
return new BlockPos(i, l, j);
}

View File

@@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Tue, 22 Jun 2021 15:08:21 -0500
Subject: [PATCH] Remove streams and iterators from range check
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index b9b985268f5627a238c302f81400a05bfd7c592d..c82ae84190273609b0f5f533eb41a0e5363c16bf 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -2453,8 +2453,28 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
return ChunkMap.this.level.getServer().getScaledTrackingDistance(initialDistance);
}
+ private static int getHighestRange(Entity parent, int highest) {
+ List<Entity> passengers = parent.getPassengers();
+
+ for (int i = 0, size = passengers.size(); i < size; i++) {
+ Entity entity = passengers.get(i);
+ int range = entity.getType().clientTrackingRange() * 16;
+ range = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, range); // Paper
+
+ if (range > highest) { // Paper - we need the lowest range thanks to the fact that our tracker doesn't account for passenger logic // Tuinity - not anymore!
+ highest = range;
+ }
+
+ highest = getHighestRange(entity, highest);
+ }
+
+ return highest;
+ }
+
private int getEffectiveRange() {
int i = this.range;
+ // Airplane start - remove iterators and streams
+ /*
Iterator iterator = this.entity.getIndirectPassengers().iterator();
while (iterator.hasNext()) {
@@ -2466,6 +2486,9 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
i = j;
}
}
+ */
+ i = getHighestRange(this.entity, i);
+ // Airplane end
return this.scaledRange(i);
}

View File

@@ -1,60 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul <paul@technove.co>
Date: Tue, 29 Jun 2021 02:19:34 -0500
Subject: [PATCH] Remove streams from getting nearby players
This results in a 3% improvement at 20,000 entities, but more
importantly is the heaviest part of the entity tracker currently.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index ca7718053a6a2eb715ea3671bd4bc15304ede420..da267ed0ff0a4c4f18272e65ac055e48f7a17915 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -355,17 +355,36 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.isLegacyTrackingEntity = isLegacyTrackingEntity;
}
+ private org.spigotmc.TrackingRange.TrackingRangeType getFurthestEntity(Entity entity, net.minecraft.server.level.ChunkMap chunkMap, org.spigotmc.TrackingRange.TrackingRangeType type, int range) {
+ List<Entity> passengers = entity.getPassengers();
+ for (int i = 0, size = passengers.size(); i < size; i++) {
+ Entity passenger = passengers.get(i);
+ org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType;
+ int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal());
+ if (passengerRange > range) {
+ type = passengerType;
+ range = passengerRange;
+ }
+
+ type = this.getFurthestEntity(passenger, chunkMap, type, range);
+ }
+
+ return type;
+ }
+
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> getPlayersInTrackRange() {
// Tuinity start - determine highest range of passengers
if (this.passengers.isEmpty()) {
return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()]
.getObjectsInRange(MCUtil.getCoordinateKey(this));
}
- Iterable<Entity> passengers = this.getIndirectPassengers();
+ //Iterable<Entity> passengers = this.getIndirectPassengers(); // Airplane
net.minecraft.server.level.ChunkMap chunkMap = ((ServerLevel)this.level).getChunkSource().chunkMap;
org.spigotmc.TrackingRange.TrackingRangeType type = this.trackingRangeType;
int range = chunkMap.getEntityTrackerRange(type.ordinal());
+ // Airplane start - use getFurthestEntity to skip getIndirectPassengers
+ /*
for (Entity passenger : passengers) {
org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType;
int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal());
@@ -374,6 +393,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
range = passengerRange;
}
}
+ */
+ type = this.getFurthestEntity(this, chunkMap, type, range);
+ // Airplane end
return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this));
// Tuinity end - determine highest range of passengers

View File

@@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul <paul@technove.co>
Date: Tue, 29 Jun 2021 02:24:23 -0500
Subject: [PATCH] Skip cloning loot parameters
Small improvement in CPU, much larger improvement in allocations. As a
new loot context is created every time a player moves (along with a lot
of other times) the constant cloning churns out a lot of useless
objects.
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java b/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java
index 05b64f2730bfe836bd1d72dcfccd9f536908a099..39e941a6a315e2a9fc0f47eb39ef9d2b58069f90 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java
@@ -41,8 +41,10 @@ public class LootContext {
this.level = world;
this.lootTables = tableGetter;
this.conditions = conditionGetter;
- this.params = ImmutableMap.copyOf(parameters);
- this.dynamicDrops = ImmutableMap.copyOf(drops);
+ // Airplane start - use unmodifiable maps instead of immutable ones to skip the copy
+ this.params = java.util.Collections.unmodifiableMap(parameters);
+ this.dynamicDrops = java.util.Collections.unmodifiableMap(drops);
+ // Airplane end
}
public boolean hasParam(LootContextParam<?> parameter) {

View File

@@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul <paul@technove.co>
Date: Fri, 2 Jul 2021 14:18:27 -0500
Subject: [PATCH] Fix Paper#6045, block goal shouldn't load chunks
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
index c28ade67f6a59146064a57bf016a646197f47ac4..419e6275a400f587f57e81684520072a93654aae 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
@@ -114,6 +114,7 @@ public abstract class MoveToBlockGoal extends Goal {
for(int m = 0; m <= l; m = m > 0 ? -m : 1 - m) {
for(int n = m < l && m > -l ? l : 0; n <= l; n = n > 0 ? -n : 1 - n) {
mutableBlockPos.setWithOffset(blockPos, m, k - 1, n);
+ if (!this.mob.level.hasChunkAt(mutableBlockPos)) continue; // Airplane - if this block isn't loaded, continue
if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level, mutableBlockPos)) {
this.blockPos = mutableBlockPos;
setTargetPosition(mutableBlockPos.immutable()); // Paper

View File

@@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul <paul@technove.co>
Date: Fri, 2 Jul 2021 17:02:32 -0500
Subject: [PATCH] Quicker sequencing of futures for chunk gen
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 81f4f26a6b83079d36acd1fd86dede0eb1116c01..621c4b42185b3c65903408b6285ba56fa42e626a 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -315,6 +315,10 @@ public class Util {
}
public static <V> CompletableFuture<List<V>> sequence(List<? extends CompletableFuture<? extends V>> futures) {
+ // Airplane start - faster sequencing without all of.. _that_
+ return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]))
+ .thenApply(unused -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList()));
+ /*
return futures.stream().reduce(CompletableFuture.completedFuture(Lists.newArrayList()), (completableFuture, completableFuture2) -> {
return completableFuture2.thenCombine(completableFuture, (object, list) -> {
List<V> list2 = Lists.newArrayListWithCapacity(list.size() + 1);
@@ -330,6 +334,8 @@ public class Util {
return list3;
});
});
+ */
+ // Airplane end
}
public static <V> CompletableFuture<List<V>> sequenceFailFast(List<? extends CompletableFuture<? extends V>> futures) {

View File

@@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul <paul@technove.co>
Date: Fri, 2 Jul 2021 18:27:12 -0500
Subject: [PATCH] Remove lambda from ticking guard
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index b714fd0ca551e6c98b351de6e9e6fc16b220be7c..6a1d9793d39eca96241bfd216745841a52b91e29 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -833,7 +833,20 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
}
gameprofilerfiller.push("tick");
- this.guardEntityTick(this::tickNonPassenger, entity);
+ // Airplane start - copied from this.guardEntityTick
+ try {
+ this.tickNonPassenger(entity); // Airplane - changed
+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick
+ } catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
+ // Paper start - Prevent tile entity and entity crashes
+ final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
+ MinecraftServer.LOGGER.error(msg, throwable);
+ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable)));
+ entity.discard();
+ // Paper end
+ }
+ // Airplane end
gameprofilerfiller.pop();
}
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index a2bb8eee5ef4a5043026af20f78bb43a5006e6b4..08973ad1d8699f4957957bbad4fdd4eb01ea3169 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1073,13 +1073,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
try {
tickConsumer.accept(entity);
MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick
- } catch (Throwable throwable) {
+ } catch (Throwable throwable) { // Airplane - diff on change ServerLevel.tick
if (throwable instanceof ThreadDeath) throw throwable; // Paper
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
MinecraftServer.LOGGER.error(msg, throwable);
getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable)));
- entity.discard();
+ entity.discard(); // Airplane - diff on change ServerLevel.tick
// Paper end
}
}