diff --git a/patches/server/0001-Airplane-Server-Changes.patch b/patches/server/0001-Airplane-Server-Changes.patch
index e53583262..47e7344b5 100644
--- a/patches/server/0001-Airplane-Server-Changes.patch
+++ b/patches/server/0001-Airplane-Server-Changes.patch
@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
diff --git a/build.gradle.kts b/build.gradle.kts
-index cb1a931417073908be5c7aa1af710477775b3dbd..d28ed33187f146bbaad6ebd4247cd798d84b3173 100644
+index cb1a931417073908be5c7aa1af710477775b3dbd..fdc3f2390d8d0124102cbff386e8a981c6f92c22 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,9 +2,12 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCach
@@ -64,7 +64,7 @@ index cb1a931417073908be5c7aa1af710477775b3dbd..d28ed33187f146bbaad6ebd4247cd798
"Main-Class" to "org.bukkit.craftbukkit.Main",
"Implementation-Title" to "CraftBukkit",
"Implementation-Version" to "git-Paper-$implementationVersion",
-+ "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane // Tuinity
++ "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane
"Implementation-Vendor" to date, // Paper
"Specification-Title" to "Bukkit",
"Specification-Version" to project.version,
@@ -159,40 +159,32 @@ index e143e4514789f707938a67fab4d313d5c55dc870..361b05c3211704edbbe921a042d4daae
int timingHistoryInterval = getInt("timings.history-interval", 300);
int timingHistoryLength = getInt("timings.history-length", 3600);
timingsServerName = getString("timings.server-name", "Unknown Server");
-diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
-index ece77f5ea4b14bbed7c070131b3251ea86764538..8642f3eaa4035243afd629b78ddb8cd2430323dd 100644
---- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
-+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
-@@ -31,8 +31,8 @@ public class PaperVersionFetcher implements VersionFetcher {
- @Nonnull
- @Override
- public Component getVersionMessage(@Nonnull String serverVersion) {
-- String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]");
-- final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
-+ String[] parts = serverVersion.substring("git-Airplane-".length()).split("[-\\s]"); // Tuinity
-+ final Component updateMessage = getUpdateStatusMessage("TECHNOVE/Airplane", GITHUB_BRANCH_NAME, parts[0]); // Tuinity
- final Component history = getHistory();
+diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+index 416ecbdf244716c2fb1277d7d1df697fe6f77756..86edf7ddd025b54b2fc1907a306168bd56dd5396 100644
+--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+@@ -268,6 +268,9 @@ public class PaperWorldConfig {
- return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage;
-@@ -56,13 +56,13 @@ public class PaperVersionFetcher implements VersionFetcher {
+ public int softDespawnDistance;
+ public int hardDespawnDistance;
++ // Airplane start - separate squared values
++ public int softDespawnDistanceSq;
++ public int hardDespawnDistanceSq;
+ private void despawnDistances() {
+ softDespawnDistance = getInt("despawn-ranges.soft", 32); // 32^2 = 1024, Minecraft Default
+ hardDespawnDistance = getInt("despawn-ranges.hard", 128); // 128^2 = 16384, Minecraft Default
+@@ -278,8 +281,9 @@ public class PaperWorldConfig {
- private static Component getUpdateStatusMessage(@Nonnull String repo, @Nonnull String branch, @Nonnull String versionInfo) {
- int distance;
-- try {
-- int jenkinsBuild = Integer.parseInt(versionInfo);
-- distance = fetchDistanceFromSiteApi(jenkinsBuild, getMinecraftVersion());
-- } catch (NumberFormatException ignored) {
-+ //try {
-+ // int jenkinsBuild = Integer.parseInt(versionInfo);
-+ // distance = fetchDistanceFromSiteApi(jenkinsBuild, getMinecraftVersion());
-+ //} catch (NumberFormatException ignored) {
- versionInfo = versionInfo.replace("\"", "");
- distance = fetchDistanceFromGitHub(repo, branch, versionInfo);
-- }
-+ //}
+ log("Living Entity Despawn Ranges: Soft: " + softDespawnDistance + " Hard: " + hardDespawnDistance);
- switch (distance) {
- case -1:
+- softDespawnDistance = softDespawnDistance*softDespawnDistance;
+- hardDespawnDistance = hardDespawnDistance*hardDespawnDistance;
++ softDespawnDistanceSq = softDespawnDistance*softDespawnDistance;
++ hardDespawnDistanceSq = hardDespawnDistance*hardDespawnDistance;
++ // Airplane end
+ }
+
+ public boolean keepSpawnInMemory;
diff --git a/src/main/java/gg/airplane/AirplaneCommand.java b/src/main/java/gg/airplane/AirplaneCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..89c89e633f14b5820147e734b1b7ad8cadfdce80
@@ -550,6 +542,149 @@ index 0000000000000000000000000000000000000000..1a9d71739019d12772bec6076b195552
+ setLevel(Level.ALL);
+ }
+}
+diff --git a/src/main/java/gg/airplane/AirplaneVersionFetcher.java b/src/main/java/gg/airplane/AirplaneVersionFetcher.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..e79ec7919e6cf160fec1cb981d85f0f33c316b41
+--- /dev/null
++++ b/src/main/java/gg/airplane/AirplaneVersionFetcher.java
+@@ -0,0 +1,137 @@
++package gg.airplane;
++
++import com.destroystokyo.paper.VersionHistoryManager;
++import com.destroystokyo.paper.util.VersionFetcher;
++import com.google.gson.Gson;
++import com.google.gson.JsonObject;
++import net.kyori.adventure.text.Component;
++import net.kyori.adventure.text.JoinConfiguration;
++import net.kyori.adventure.text.format.NamedTextColor;
++import net.kyori.adventure.text.format.TextDecoration;
++import org.bukkit.craftbukkit.CraftServer;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++
++import java.io.IOException;
++import java.net.URI;
++import java.net.http.HttpClient;
++import java.net.http.HttpRequest;
++import java.net.http.HttpResponse;
++import java.nio.charset.StandardCharsets;
++import java.util.concurrent.TimeUnit;
++import java.util.logging.Level;
++import java.util.logging.Logger;
++
++import static net.kyori.adventure.text.Component.text;
++import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
++import static net.kyori.adventure.text.format.NamedTextColor.RED;
++
++public class AirplaneVersionFetcher implements VersionFetcher {
++
++ private static final Logger LOGGER = Logger.getLogger("AirplaneVersionFetcher");
++ private static final HttpClient client = HttpClient.newHttpClient();
++
++ private static final URI JENKINS_URI = URI.create("https://ci.tivy.ca/job/Airplane-1.17/lastSuccessfulBuild/buildNumber");
++ private static final String GITHUB_FORMAT = "https://api.github.com/repos/TECHNOVE/Airplane/compare/ver/1.17...%s";
++
++ private static final HttpResponse.BodyHandler JSON_OBJECT_BODY_HANDLER = responseInfo -> HttpResponse.BodySubscribers.mapping(
++ HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8),
++ string -> new Gson().fromJson(string, JsonObject.class)
++ );
++
++ @Override
++ public long getCacheTime() {
++ return TimeUnit.MINUTES.toMillis(30);
++ }
++
++ @Override
++ public @NotNull Component getVersionMessage(final @NotNull String serverVersion) {
++ final String[] parts = CraftServer.class.getPackage().getImplementationVersion().split("-");
++ @NotNull Component component;
++
++ if (parts.length != 3) {
++ component = text("Unknown server version.", RED);
++ } else {
++ final String versionString = parts[2];
++
++ try {
++ component = this.fetchJenkinsVersion(Integer.parseInt(versionString));
++ } catch (NumberFormatException e) {
++ component = this.fetchGithubVersion(versionString.substring(1, versionString.length() - 1));
++ }
++ }
++
++ final @Nullable Component history = this.getHistory();
++ return history != null ? Component.join(JoinConfiguration.noSeparators(), component, Component.newline(), this.getHistory()) : component;
++ }
++
++ private @NotNull Component fetchJenkinsVersion(final int versionNumber) {
++ final HttpRequest request = HttpRequest.newBuilder(JENKINS_URI).build();
++ try {
++ final HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
++ if (response.statusCode() != 200) {
++ return text("Received invalid status code (" + response.statusCode() + ") from server.", RED);
++ }
++
++ int latestVersionNumber;
++ try {
++ latestVersionNumber = Integer.parseInt(response.body());
++ } catch (NumberFormatException e) {
++ LOGGER.log(Level.WARNING, "Received invalid response from Jenkins \"" + response.body() + "\".");
++ return text("Received invalid response from server.", RED);
++ }
++
++ final int versionDiff = latestVersionNumber - versionNumber;
++ return this.getResponseMessage(versionDiff);
++ } catch (IOException | InterruptedException e) {
++ LOGGER.log(Level.WARNING, "Failed to look up version from Jenkins", e);
++ return text("Failed to retrieve version from server.", RED);
++ }
++ }
++
++ // Based off code contributed by Techcable in Paper/GH-65
++ private @NotNull Component fetchGithubVersion(final @NotNull String hash) {
++ final URI uri = URI.create(String.format(GITHUB_FORMAT, hash));
++ final HttpRequest request = HttpRequest.newBuilder(uri).build();
++ try {
++ final HttpResponse response = client.send(request, JSON_OBJECT_BODY_HANDLER);
++ if (response.statusCode() != 200) {
++ return text("Received invalid status code (" + response.statusCode() + ") from server.", RED);
++ }
++
++ final JsonObject obj = response.body();
++ final int versionDiff = obj.get("behind_by").getAsInt();
++
++ return this.getResponseMessage(versionDiff);
++ } catch (IOException | InterruptedException e) {
++ LOGGER.log(Level.WARNING, "Failed to look up version from GitHub", e);
++ return text("Failed to retrieve version from server.", RED);
++ }
++ }
++
++ private @NotNull Component getResponseMessage(final int versionDiff) {
++ return switch (Math.max(-1, Math.min(1, versionDiff))) {
++ case -1 ->
++ text("You are running an unsupported version of Airplane.", RED);
++ case 0 ->
++ text("You are on the latest version!", GREEN);
++ default ->
++ text("You are running " + versionDiff + " version" + (versionDiff == 1 ? "" : "s") + " beyond. " +
++ "Please update your server when possible to maintain stability, security, and receive the latest optimizations.", RED);
++ };
++ }
++
++ private @Nullable Component getHistory() {
++ final VersionHistoryManager.VersionData data = VersionHistoryManager.INSTANCE.getVersionData();
++ if (data == null) {
++ return null;
++ }
++
++ final String oldVersion = data.getOldVersion();
++ if (oldVersion == null) {
++ return null;
++ }
++
++ return Component.text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC);
++ }
++}
diff --git a/src/main/java/gg/airplane/commands/AirplaneCommands.java b/src/main/java/gg/airplane/commands/AirplaneCommands.java
new file mode 100644
index 0000000000000000000000000000000000000000..807cf274619b8f7be839e249cb62b9817876ca04
@@ -650,6 +785,390 @@ index 0000000000000000000000000000000000000000..f9a71ff3edd7e7b6cda680e5a156373b
+ }
+
+}
+diff --git a/src/main/java/gg/airplane/entity/CollisionCache.java b/src/main/java/gg/airplane/entity/CollisionCache.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..3822fc6b78419e681ff838bc2050c4f8fb3e90eb
+--- /dev/null
++++ b/src/main/java/gg/airplane/entity/CollisionCache.java
+@@ -0,0 +1,244 @@
++package gg.airplane.entity;
++
++import io.papermc.paper.util.CollisionUtil;
++import io.papermc.paper.util.WorldUtil;
++import net.minecraft.core.BlockPos;
++import net.minecraft.core.SectionPos;
++import net.minecraft.server.level.ServerChunkCache;
++import net.minecraft.util.Mth;
++import net.minecraft.world.entity.Entity;
++import net.minecraft.world.level.CollisionGetter;
++import net.minecraft.world.level.block.Blocks;
++import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.chunk.LevelChunk;
++import net.minecraft.world.level.chunk.LevelChunkSection;
++import net.minecraft.world.phys.AABB;
++import net.minecraft.world.phys.shapes.CollisionContext;
++import net.minecraft.world.phys.shapes.Shapes;
++import net.minecraft.world.phys.shapes.VoxelShape;
++import org.bukkit.craftbukkit.util.UnsafeList;
++import org.jetbrains.annotations.NotNull;
++import org.simpleyaml.utils.Validate;
++
++import java.util.HashSet;
++import java.util.List;
++import java.util.Set;
++import java.util.function.BiPredicate;
++
++public class CollisionCache {
++
++ private static record BlockEntry(int x, int y, int z, BlockState state, VoxelShape shape){}
++
++ @NotNull
++ private final Entity entity;
++ private final UnsafeList blocks = new UnsafeList<>();
++ private Set chunkToList = new HashSet<>();
++
++ private boolean dirty = true;
++
++ private int previousMinBlockX;
++ private int previousMaxBlockX;
++ private int previousMinBlockY;
++ private int previousMaxBlockY;
++ private int previousMinBlockZ;
++ private int previousMaxBlockZ;
++
++ public CollisionCache(@NotNull Entity entity) {
++ this.entity = entity;
++ }
++
++ public int getId() {
++ return this.entity.getId();
++ }
++
++ public void dirtySection(@NotNull SectionPos sectionPos) {
++ this.dirty = true;
++ }
++
++ public void onRemove() {
++ this.blocks.setSize(0);
++
++ for (CollisionCacheList collisionCaches : this.chunkToList) {
++ collisionCaches.remove(this);
++ }
++ this.chunkToList.clear();
++ this.dirty = false;
++ }
++
++ public boolean getCollisions(final CollisionGetter view, AABB aabb, List into, boolean collidesWithUnloaded, boolean checkOnly, BiPredicate predicate) {
++ boolean ret = false;
++
++ int minBlockX = Mth.floor(aabb.minX - CollisionUtil.COLLISION_EPSILON) - 1;
++ int maxBlockX = Mth.floor(aabb.maxX + CollisionUtil.COLLISION_EPSILON) + 1;
++
++ int minBlockY = Mth.floor(aabb.minY - CollisionUtil.COLLISION_EPSILON) - 1;
++ int maxBlockY = Mth.floor(aabb.maxY + CollisionUtil.COLLISION_EPSILON) + 1;
++
++ int minBlockZ = Mth.floor(aabb.minZ - CollisionUtil.COLLISION_EPSILON) - 1;
++ int maxBlockZ = Mth.floor(aabb.maxZ + CollisionUtil.COLLISION_EPSILON) + 1;
++
++ // if nothing changed and the location didn't move out of our area, use previous set
++ if (!this.dirty && minBlockX >= this.previousMinBlockX && maxBlockX <= this.previousMaxBlockX &&
++ minBlockY >= this.previousMinBlockY && maxBlockY <= this.previousMaxBlockY &&
++ minBlockZ >= this.previousMinBlockZ && maxBlockZ <= this.previousMaxBlockZ) {
++ if (checkOnly) {
++ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
++ for (int i = 0, length = this.blocks.size(); i < length; i++) {
++ BlockEntry entry = this.blocks.unsafeGet(i);
++ if (entry.shape.intersects(aabb) && predicate.test(entry.state, pos.set(entry.x, entry.y, entry.z))) {
++ return true;
++ }
++ }
++ } else {
++ for (int i = 0, length = this.blocks.size(); i < length; i++) {
++ ret |= CollisionUtil.addBoxesToIfIntersects(this.blocks.unsafeGet(i).shape, aabb, into);
++ }
++ }
++
++ return ret;
++ } else if (checkOnly) {
++ // tl;dr this is only used by inWall right now, and we don't want to generate a cache for inWall because it'll always be smaller than a move cache anyways
++ return CollisionUtil.getCollisionsForBlocksOrWorldBorder(view, this.entity, aabb, into, false, collidesWithUnloaded, false, checkOnly, predicate);
++ }
++
++ Validate.isTrue(predicate == null, "predicate cannot be used without checkOnly");
++
++ this.previousMinBlockX = minBlockX;
++ this.previousMaxBlockX = maxBlockX;
++
++ this.previousMinBlockY = minBlockY;
++ this.previousMaxBlockY = maxBlockY;
++
++ this.previousMinBlockZ = minBlockZ;
++ this.previousMaxBlockZ = maxBlockZ;
++
++ // remove old shapes, since we missed cache
++ this.blocks.setSize(0);
++ this.dirty = false;
++
++ final int minSection = WorldUtil.getMinSection(this.entity.level);
++ final int maxSection = WorldUtil.getMaxSection(this.entity.level);
++ final int minBlock = minSection << 4;
++ final int maxBlock = (maxSection << 4) | 15;
++
++ BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
++ CollisionContext collisionShape = null;
++
++ // special cases:
++ if (minBlockY > maxBlock || maxBlockY < minBlock) {
++ // no point in checking
++ if (!this.chunkToList.isEmpty()) {
++ for (CollisionCacheList collisionCaches : this.chunkToList) {
++ collisionCaches.remove(this);
++ }
++ this.chunkToList.clear();
++ }
++ return ret;
++ }
++
++ int minYIterate = Math.max(minBlock, minBlockY);
++ int maxYIterate = Math.min(maxBlock, maxBlockY);
++
++ int minChunkX = minBlockX >> 4;
++ int maxChunkX = maxBlockX >> 4;
++
++ int minChunkZ = minBlockZ >> 4;
++ int maxChunkZ = maxBlockZ >> 4;
++
++ ServerChunkCache chunkProvider = (ServerChunkCache) this.entity.level.getChunkSource();
++
++ Set cacheLists = new HashSet<>(this.blocks.size());
++
++ for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
++ int minZ = currChunkZ == minChunkZ ? minBlockZ & 15 : 0; // coordinate in chunk
++ int maxZ = currChunkZ == maxChunkZ ? maxBlockZ & 15 : 15; // coordinate in chunk
++
++ for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
++ int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk
++ int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 15; // coordinate in chunk
++
++ int chunkXGlobalPos = currChunkX << 4;
++ int chunkZGlobalPos = currChunkZ << 4;
++
++ LevelChunk chunk = chunkProvider.getChunkAtIfLoadedImmediately(currChunkX, currChunkZ);
++
++ if (chunk == null) {
++ if (collidesWithUnloaded) {
++ into.add(CollisionUtil.getBoxForChunk(currChunkX, currChunkZ));
++ ret = true;
++ }
++ continue;
++ }
++
++ LevelChunkSection[] sections = chunk.getSections();
++
++ // bound y
++
++ for (int currY = minYIterate; currY <= maxYIterate; ++currY) {
++ int sectionIndex = SectionPos.blockToSectionCoord(currY) - minSection;
++
++ CollisionCacheList cacheList = chunk.collisionCaches[sectionIndex];
++ if (cacheLists.add(cacheList)) {
++ cacheList.add(this);
++ }
++
++ LevelChunkSection section = sections[sectionIndex];
++ if (section == null || section.isEmpty()) {
++ // empty
++ // skip to next section
++ currY = (currY & ~(15)) + 15; // increment by 15: iterator loop increments by the extra one
++ continue;
++ }
++
++ net.minecraft.world.level.chunk.PalettedContainer blocks = section.states;
++
++ for (int currZ = minZ; currZ <= maxZ; ++currZ) {
++ for (int currX = minX; currX <= maxX; ++currX) {
++ int localBlockIndex = (currX) | (currZ << 4) | ((currY & 15) << 8);
++ int blockX = currX | chunkXGlobalPos;
++ int blockY = currY;
++ int blockZ = currZ | chunkZGlobalPos;
++
++ int edgeCount = ((blockX == minBlockX || blockX == maxBlockX) ? 1 : 0) +
++ ((blockY == minBlockY || blockY == maxBlockY) ? 1 : 0) +
++ ((blockZ == minBlockZ || blockZ == maxBlockZ) ? 1 : 0);
++ if (edgeCount == 3) {
++ continue;
++ }
++
++ BlockState blockData = blocks.get(localBlockIndex);
++ if (blockData.isAir()) {
++ continue;
++ }
++
++ if ((edgeCount != 1 || blockData.shapeExceedsCube()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON)) {
++ mutablePos.set(blockX, blockY, blockZ);
++ if (collisionShape == null) {
++ collisionShape = new CollisionUtil.LazyEntityCollisionContext(entity);
++ }
++ VoxelShape voxelshape2 = blockData.getCollisionShape(this.entity.level, mutablePos, collisionShape);
++ if (voxelshape2 != Shapes.empty()) {
++ VoxelShape voxelshape3 = voxelshape2.move((double) blockX, (double) blockY, (double) blockZ);
++
++ this.blocks.add(new BlockEntry(blockX, blockY, blockZ, blockData, voxelshape3));
++
++ ret |= CollisionUtil.addBoxesToIfIntersects(voxelshape3, aabb, into);
++ }
++ }
++ }
++ }
++ }
++ }
++ }
++
++ for (CollisionCacheList cache : this.chunkToList) {
++ if (!cacheLists.contains(cache)) {
++ cache.remove(this);
++ }
++ }
++ this.chunkToList = cacheLists;
++
++ return ret;
++ }
++
++}
+diff --git a/src/main/java/gg/airplane/entity/CollisionCacheList.java b/src/main/java/gg/airplane/entity/CollisionCacheList.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..017da9e1461250a0fd8baacdcca203d6949244fc
+--- /dev/null
++++ b/src/main/java/gg/airplane/entity/CollisionCacheList.java
+@@ -0,0 +1,128 @@
++package gg.airplane.entity;
++
++import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
++
++import java.util.Arrays;
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * @see com.destroystokyo.paper.util.maplist.EntityList
++ */
++public class CollisionCacheList implements Iterable {
++
++ protected final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f);
++
++ {
++ this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE);
++ }
++
++ protected static final CollisionCache[] EMPTY_LIST = new CollisionCache[0];
++
++ protected CollisionCache[] entities = EMPTY_LIST;
++ protected int count;
++
++ public int size() {
++ return this.count;
++ }
++
++ public boolean contains(final CollisionCache entity) {
++ return this.entityToIndex.containsKey(entity.getId());
++ }
++
++ public boolean remove(final CollisionCache entity) {
++ final int index = this.entityToIndex.remove(entity.getId());
++ if (index == Integer.MIN_VALUE) {
++ return false;
++ }
++
++ // move the entity at the end to this index
++ final int endIndex = --this.count;
++ final CollisionCache end = this.entities[endIndex];
++ if (index != endIndex) {
++ // not empty after this call
++ this.entityToIndex.put(end.getId(), index); // update index
++ }
++ this.entities[index] = end;
++ this.entities[endIndex] = null;
++
++ return true;
++ }
++
++ public boolean add(final CollisionCache entity) {
++ final int count = this.count;
++ final int currIndex = this.entityToIndex.putIfAbsent(entity.getId(), count);
++
++ if (currIndex != Integer.MIN_VALUE) {
++ return false; // already in this list
++ }
++
++ CollisionCache[] list = this.entities;
++
++ if (list.length == count) {
++ // resize required
++ list = this.entities = Arrays.copyOf(list, (int) Math.max(4L, count * 2L)); // overflow results in negative
++ }
++
++ list[count] = entity;
++ this.count = count + 1;
++
++ return true;
++ }
++
++ public CollisionCache getChecked(final int index) {
++ if (index < 0 || index >= this.count) {
++ throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count);
++ }
++ return this.entities[index];
++ }
++
++ public CollisionCache getUnchecked(final int index) {
++ return this.entities[index];
++ }
++
++ public CollisionCache[] getRawData() {
++ return this.entities;
++ }
++
++ public void clear() {
++ this.entityToIndex.clear();
++ Arrays.fill(this.entities, 0, this.count, null);
++ this.count = 0;
++ }
++
++ @Override
++ public Iterator iterator() {
++ return new Iterator() {
++
++ CollisionCache lastRet;
++ int current;
++
++ @Override
++ public boolean hasNext() {
++ return this.current < CollisionCacheList.this.count;
++ }
++
++ @Override
++ public CollisionCache next() {
++ if (this.current >= CollisionCacheList.this.count) {
++ throw new NoSuchElementException();
++ }
++ return this.lastRet = CollisionCacheList.this.entities[this.current++];
++ }
++
++ @Override
++ public void remove() {
++ final CollisionCache lastRet = this.lastRet;
++
++ if (lastRet == null) {
++ throw new IllegalStateException();
++ }
++ this.lastRet = null;
++
++ CollisionCacheList.this.remove(lastRet);
++ --this.current;
++ }
++ };
++ }
++}
diff --git a/src/main/java/gg/airplane/flare/CustomCategories.java b/src/main/java/gg/airplane/flare/CustomCategories.java
new file mode 100644
index 0000000000000000000000000000000000000000..031700b291ce71eac7de2ff3423a9bbfd8de4ac6
@@ -1646,6 +2165,24 @@ index 0000000000000000000000000000000000000000..a7f297ebb569f7c1f205e967ca485be7
+ entryToRemove.replace(data, value);
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/util/CollisionUtil.java b/src/main/java/io/papermc/paper/util/CollisionUtil.java
+index 98ca1199a823cdf55b913396ce0a24554e85f116..840142d340d4569772552b961f829ca921b15dc4 100644
+--- a/src/main/java/io/papermc/paper/util/CollisionUtil.java
++++ b/src/main/java/io/papermc/paper/util/CollisionUtil.java
+@@ -547,6 +547,13 @@ public final class CollisionUtil {
+ return ret;
+ }
+
++ public static boolean getEntityCollisionsWithCache(final net.minecraft.world.level.Level getter, Entity entity, AABB aabb, List into,
++ final boolean loadChunks, final boolean collidesWithUnloaded,
++ final boolean checkBorder, final boolean checkOnly, final BiPredicate predicate) {
++ return entity.collisionCache.getCollisions(getter, aabb, into, collidesWithUnloaded, checkOnly, predicate) ||
++ getEntityHardCollisions(getter, entity, aabb, into, checkOnly, null);
++ }
++
+ public static boolean getEntityHardCollisions(final CollisionGetter getter, final Entity entity, AABB aabb,
+ final List into, final boolean checkOnly, final Predicate predicate) {
+ if (isEmpty(aabb) || !(getter instanceof EntityGetter entityGetter)) {
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 505546d32eea4682452dbac02311433157f6a30e..5c7b9ad379f3c272e15648dd16f4df9245d927da 100644
--- a/src/main/java/net/minecraft/Util.java
@@ -1949,21 +2486,22 @@ index 7437f01ca8f416e2c9150250e324af4725a4efb6..bdcd0e38a3ba904811112f41d8bfbfc0
int LARGE_MAX_STACK_SIZE = 64;
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index e17bda0d13bae337cfad5ae31b118aa7a85499fc..69fe6b0c774ec1f15e49826a2dc36d9288e3ae86 100644
+index e17bda0d13bae337cfad5ae31b118aa7a85499fc..d35cdcf2ee7568ad5caf52588db54e9c6f607d4b 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -338,6 +338,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -338,6 +338,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
protected int numCollisions = 0; // Paper
public void inactiveTick() { }
// Spigot end
+ // Airplane start
+ public int activatedPriority = gg.airplane.AirplaneConfig.maximumActivationPrio; // golf score
+ public final BlockPos.MutableBlockPos cachedBlockPos = new BlockPos.MutableBlockPos(); // used where needed
++ public final gg.airplane.entity.CollisionCache collisionCache = new gg.airplane.entity.CollisionCache(this);
+ // Airplane end
public float getBukkitYaw() {
return this.yRot;
-@@ -362,17 +366,36 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -362,17 +367,36 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.isLegacyTrackingEntity = isLegacyTrackingEntity;
}
@@ -2001,7 +2539,7 @@ index e17bda0d13bae337cfad5ae31b118aa7a85499fc..69fe6b0c774ec1f15e49826a2dc36d92
for (Entity passenger : passengers) {
org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType;
int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal());
-@@ -381,6 +404,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -381,6 +405,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
range = passengerRange;
}
}
@@ -2011,18 +2549,38 @@ index e17bda0d13bae337cfad5ae31b118aa7a85499fc..69fe6b0c774ec1f15e49826a2dc36d92
return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this));
}
-@@ -2441,9 +2467,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -1264,8 +1291,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+ }
+ }
+
+- io.papermc.paper.util.CollisionUtil.getCollisions(world, this, collisionBox, potentialCollisions, false, true,
+- false, false, null, null);
++ // Airplane start - use collision cache
++ io.papermc.paper.util.CollisionUtil.getEntityCollisionsWithCache(world, this, collisionBox, potentialCollisions, false, true,
++ false, false, null);
++ // Airplane end
+
+ if (io.papermc.paper.util.CollisionUtil.isCollidingWithBorderEdge(world.getWorldBorder(), collisionBox)) {
+ io.papermc.paper.util.CollisionUtil.addBoxesToIfIntersects(world.getWorldBorder().getCollisionShape(), collisionBox, potentialCollisions);
+@@ -2440,10 +2469,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+ AABB axisalignedbb = AABB.ofSize(this.getEyePosition(), (double) f, 1.0E-6D, (double) f);
// Paper start
- return io.papermc.paper.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this.level, this, axisalignedbb, null,
+- return io.papermc.paper.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this.level, this, axisalignedbb, null,
- false, false, false, true, (iblockdata, blockposition) -> {
- return iblockdata.isSuffocating(this.level, blockposition);
- });
++ return io.papermc.paper.util.CollisionUtil.getEntityCollisionsWithCache(this.level, this, axisalignedbb, null, // Airplane - use cache
+ false, false, false, true, this.level.isAlmostSuffocating); // Airplane - don't allocate lambda here
// Paper end
}
}
-@@ -3834,12 +3858,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -3830,16 +3857,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+ }
+
+ public boolean updateFluidHeightAndDoFluidPushing(Tag tag, double d0) {
+- if (this.touchingUnloadedChunk()) {
++ if (false && this.touchingUnloadedChunk()) { // Airplane - cost of a lookup here is the same cost as below, so skip
return false;
} else {
AABB axisalignedbb = this.getBoundingBox().deflate(0.001D);
@@ -2043,7 +2601,7 @@ index e17bda0d13bae337cfad5ae31b118aa7a85499fc..69fe6b0c774ec1f15e49826a2dc36d92
double d1 = 0.0D;
boolean flag = this.isPushedByFluid();
boolean flag1 = false;
-@@ -3847,14 +3873,62 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -3847,14 +3876,62 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
int k1 = 0;
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
@@ -2083,7 +2641,7 @@ index e17bda0d13bae337cfad5ae31b118aa7a85499fc..69fe6b0c774ec1f15e49826a2dc36d92
+
+ net.minecraft.world.level.chunk.ChunkAccess chunk = this.level.getChunkIfLoadedImmediately(currChunkX, currChunkZ);
+ if (chunk == null) {
-+ continue;
++ return false; // if we're touching an unloaded chunk then it's false
+ }
+
+ net.minecraft.world.level.chunk.LevelChunkSection[] sections = chunk.getSections();
@@ -2112,7 +2670,7 @@ index e17bda0d13bae337cfad5ae31b118aa7a85499fc..69fe6b0c774ec1f15e49826a2dc36d92
if (d2 >= axisalignedbb.minY) {
flag1 = true;
-@@ -3871,9 +3945,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -3871,9 +3948,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
}
}
@@ -2183,7 +2741,7 @@ index 1018f4640bab5876c5e0afb5b88f71437fb79662..5905f02cb695ca619ebcd13cad2fc6df
}
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
-index 8a864238e154e2131834d013652746b7e7a78c97..b8e512e1c4b00b468b2d22add5653b98f4a2c81a 100644
+index 8a864238e154e2131834d013652746b7e7a78c97..6051fd771dd989f2903b854b6564252a847a74e3 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -207,10 +207,10 @@ public abstract class Mob extends LivingEntity {
@@ -2199,6 +2757,26 @@ index 8a864238e154e2131834d013652746b7e7a78c97..b8e512e1c4b00b468b2d22add5653b98
this.targetSelector.tick();
}
}
+@@ -801,16 +801,16 @@ public abstract class Mob extends LivingEntity {
+ int i = this.getType().getCategory().getDespawnDistance();
+ int j = i * i;
+
+- if (d0 > (double) level.paperConfig.hardDespawnDistance) { // CraftBukkit - remove isTypeNotPersistent() check // Paper - custom despawn distances
++ if (d0 > (double) level.paperConfig.hardDespawnDistanceSq) { // CraftBukkit - remove isTypeNotPersistent() check // Paper - custom despawn distances // Airplane
+ this.discard();
+ }
+
+ int k = this.getType().getCategory().getNoDespawnDistance();
+ int l = k * k;
+
+- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > level.paperConfig.softDespawnDistance) { // CraftBukkit - remove isTypeNotPersistent() check // Paper - custom despawn distances
++ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > level.paperConfig.softDespawnDistanceSq) { // CraftBukkit - remove isTypeNotPersistent() check // Paper - custom despawn distances // Airplane
+ this.discard();
+- } else if (d0 < level.paperConfig.softDespawnDistance) { // Paper - custom despawn distances
++ } else if (d0 < level.paperConfig.softDespawnDistanceSq) { // Paper - custom despawn distances // Airplane
+ this.noActionTime = 0;
+ }
+ }
@@ -838,9 +838,11 @@ public abstract class Mob extends LivingEntity {
this.sensing.tick();
this.level.getProfiler().pop();
@@ -2790,7 +3368,7 @@ index e7ca5d6fb8922e7e8065864f736b06056be080a0..833ad6fbedfc275b3fde640b0e873f23
final String id;
private final GameRules.Category category;
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index f936e9f9a9fa655fa997d6862b5ed54c04169d35..8b8daa771288492b4a02cb40c1b376b65e210e5b 100644
+index f936e9f9a9fa655fa997d6862b5ed54c04169d35..24d772c18d5a448154909e4a51964ba29485a5c2 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -176,6 +176,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -2802,7 +3380,37 @@ index f936e9f9a9fa655fa997d6862b5ed54c04169d35..8b8daa771288492b4a02cb40c1b376b6
// Paper start - fix and optimise world upgrading
// copied from below
public static ResourceKey getDimensionKey(DimensionType manager) {
-@@ -452,6 +454,91 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -311,6 +313,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+ }
+ // Paper end - optimise checkDespawn
+
++ // Airplane start - ensure these get inlined
++ private final int minBuildHeight, minSection, height, maxBuildHeight, maxSection;
++ @Override public final int getMaxBuildHeight() { return this.maxBuildHeight; }
++ @Override public final int getMinSection() { return this.minSection; }
++ @Override public final int getMaxSection() { return this.maxSection; }
++ @Override public final int getMinBuildHeight() { return this.minBuildHeight; }
++ @Override public final int getHeight() { return this.height; }
++ // Airplane end
++
+ protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, final DimensionType dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor
+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
+ this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper
+@@ -329,6 +340,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+ this.profiler = supplier;
+ this.levelData = worlddatamutable;
+ this.dimensionType = dimensionmanager;
++ // Airplane start
++ this.minBuildHeight = dimensionmanager.minY();
++ this.minSection = SectionPos.blockToSectionCoord(this.minBuildHeight);
++ this.height = dimensionmanager.height();
++ this.maxBuildHeight = this.minBuildHeight + this.height;
++ this.maxSection = SectionPos.blockToSectionCoord(this.maxBuildHeight - 1) + 1;
++ // Airplane end
+ this.dimension = resourcekey;
+ this.isClientSide = flag;
+ if (dimensionmanager.coordinateScale() != 1.0D) {
+@@ -452,6 +470,91 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return null;
}
@@ -2894,7 +3502,7 @@ index f936e9f9a9fa655fa997d6862b5ed54c04169d35..8b8daa771288492b4a02cb40c1b376b6
public boolean isInWorldBounds(BlockPos pos) {
return pos.isValidLocation(this); // Paper - use better/optimized check
}
-@@ -987,13 +1074,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -987,13 +1090,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
try {
tickConsumer.accept(entity);
MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick
@@ -2910,7 +3518,7 @@ index f936e9f9a9fa655fa997d6862b5ed54c04169d35..8b8daa771288492b4a02cb40c1b376b6
// Paper end
}
}
-@@ -1447,6 +1534,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -1447,6 +1550,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
}
public ProfilerFiller getProfiler() {
@@ -3202,10 +3810,10 @@ index ed3518fe7c841d9e1a9c97626acaa3d765a6d76f..ac564148956beb984650341c5c099457
@Override
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 86686c24b0b7de4b4bfadbc77419a8872a8e86ee..e265980f07d95a7912bf8873819033e51ef04c98 100644
+index 86686c24b0b7de4b4bfadbc77419a8872a8e86ee..db7904b1bb402a36684b97c443336630762aeaf9 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
-@@ -172,11 +172,25 @@ public class LevelChunk implements ChunkAccess {
+@@ -172,6 +172,20 @@ public class LevelChunk implements ChunkAccess {
}
// Paper end - rewrite light engine
@@ -3221,17 +3829,25 @@ index 86686c24b0b7de4b4bfadbc77419a8872a8e86ee..e265980f07d95a7912bf8873819033e5
+ }
+ // Airplane end
+
-+ private final int levelHeight; private final int minBuildHeight; // Airplane
++ public final gg.airplane.entity.CollisionCacheList[] collisionCaches; // 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 blockTickScheduler, TickList fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sections, @Nullable Consumer loadToWorldConsumer) {
-+ this.levelHeight = world.getHeight(); this.minBuildHeight = world.getMinBuildHeight(); // Airplane
- // Paper start
- this.blockNibbles = StarLightEngine.getFilledEmptyLight(world);
- this.skyNibbles = StarLightEngine.getFilledEmptyLight(world);
-@@ -220,6 +234,7 @@ public class LevelChunk implements ChunkAccess {
+@@ -209,6 +223,12 @@ public class LevelChunk implements ChunkAccess {
+ this.inhabitedTime = inhabitedTime;
+ this.postLoad = loadToWorldConsumer;
+ this.sections = new LevelChunkSection[world.getSectionsCount()];
++ // Airplane start
++ this.collisionCaches = new gg.airplane.entity.CollisionCacheList[world.getSectionsCount()];
++ for (int i = 0; i < this.collisionCaches.length; i++) {
++ this.collisionCaches[i] = new gg.airplane.entity.CollisionCacheList();
++ }
++ // Airplane end
+ if (sections != null) {
+ if (this.sections.length == sections.length) {
+ System.arraycopy(sections, 0, this.sections, 0, this.sections.length);
+@@ -220,6 +240,7 @@ public class LevelChunk implements ChunkAccess {
this.postProcessing = new ShortList[world.getSectionsCount()];
// CraftBukkit start
this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
@@ -3239,28 +3855,24 @@ index 86686c24b0b7de4b4bfadbc77419a8872a8e86ee..e265980f07d95a7912bf8873819033e5
}
public org.bukkit.Chunk bukkitChunk;
-@@ -1296,13 +1311,17 @@ public class LevelChunk implements ChunkAccess {
- }
+@@ -655,6 +676,17 @@ public class LevelChunk implements ChunkAccess {
+ int i1 = blockposition.getZ() & 15;
+ BlockState iblockdata1 = chunksection.setBlockState(k, l, i1, iblockdata);
- @Override
-- public int getMinBuildHeight() {
-- return this.level.getMinBuildHeight();
-+ // Airplane start
-+ public final int getMinBuildHeight() {
-+ return this.minBuildHeight;
++ // Airplane start - notify dirty
++ SectionPos pos = SectionPos.of(this.chunkPos, j);
++ gg.airplane.entity.CollisionCache[] caches = this.collisionCaches[j].getRawData();
++ for (int index = 0; index < caches.length; index++) {
++ gg.airplane.entity.CollisionCache cache = caches[index];
++ if (cache != null) {
++ cache.dirtySection(pos);
++ }
++ }
+ // Airplane end
- }
-
- @Override
-- public int getHeight() {
-- return this.level.getHeight();
-+ // Airplane start
-+ public final int getHeight() {
-+ return this.levelHeight;
-+ // Airplane end
- }
-
- @Override
++
+ if (iblockdata1 == iblockdata) {
+ return null;
+ } else {
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
index 72e3264dc74822f746fb84fec0be400047d2d9f5..831e2dbe530daf63ac9e681a92af2740fa18ac8c 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -3377,6 +3989,23 @@ index 3b13f6ea36a3bfecabe09221eb5c48dddab119db..c02b9104c0cc1a7319cca29d5e32a5c2
@Nullable
@Override
public T get(int id) {
+diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
+index 1ed6573e0ca6b353d1de3b4486e199a5db9aa447..125a067ac989ba05e796c1aa5c28206dbe08eb50 100644
+--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
++++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
+@@ -606,6 +606,12 @@ public class PersistentEntitySectionManager implements A
+ PersistentEntitySectionManager.this.knownUuids.remove(this.entity.getUUID());
+ this.entity.setLevelCallback(PersistentEntitySectionManager.Callback.NULL);
+ PersistentEntitySectionManager.this.removeSectionIfEmpty(this.currentSectionKey, this.currentSection);
++
++ // Airplane start
++ if (this.entity instanceof Entity realEntity) {
++ realEntity.collisionCache.onRemove();
++ }
++ // Airplane end
+ }
+ }
+ }
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 7fda7da544b2d0bbd3803d88ee34c92350a8b8ef..adf91f3006a2d224c957f08520f93f761c3ba832 100644
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
@@ -3661,6 +4290,19 @@ index 909b2c98e7a9117d2f737245e4661792ffafb744..9da898c6f44832b4421b8c2745e3121b
+ return org.bukkit.Bukkit.getServer(); // Airplane - impl
}
+ @Override
+diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+index 408863b137b7bda3f3e654ac3665ddeefb6d9e7b..efbe385b3a78f4bd0dee6b63d78999513433b79b 100644
+--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+@@ -394,7 +394,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
+
+ @Override
+ public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
+- return new com.destroystokyo.paper.PaperVersionFetcher();
++ return new gg.airplane.AirplaneVersionFetcher(); // Airplane
+ }
+
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
index d752720f2f234b9dbd2117333fee1bfad663ec02..9868b3a9a35cea9689c76ea9b62f2732ab61c94c 100644
diff --git a/patches/server/0003-Rebrand.patch b/patches/server/0003-Rebrand.patch
index 2297d7a6e..19b82cf97 100644
--- a/patches/server/0003-Rebrand.patch
+++ b/patches/server/0003-Rebrand.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Rebrand
diff --git a/build.gradle.kts b/build.gradle.kts
-index d28ed33187f146bbaad6ebd4247cd798d84b3173..f304212a962911fe9bf6a5dd2336ee9850f58f0a 100644
+index fdc3f2390d8d0124102cbff386e8a981c6f92c22..f304212a962911fe9bf6a5dd2336ee9850f58f0a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -31,7 +31,7 @@ repositories {
@@ -31,7 +31,7 @@ index d28ed33187f146bbaad6ebd4247cd798d84b3173..f304212a962911fe9bf6a5dd2336ee98
"Main-Class" to "org.bukkit.craftbukkit.Main",
"Implementation-Title" to "CraftBukkit",
- "Implementation-Version" to "git-Paper-$implementationVersion",
-- "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane // Tuinity
+- "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane
+ "Implementation-Version" to "git-Purpur-$implementationVersion", // Airplane // Purpur
"Implementation-Vendor" to date, // Paper
"Specification-Title" to "Bukkit",
@@ -46,7 +46,7 @@ index d28ed33187f146bbaad6ebd4247cd798d84b3173..f304212a962911fe9bf6a5dd2336ee98
workingDir = rootProject.layout.projectDirectory.dir(
providers.gradleProperty("runWorkDir").forUseAtConfigurationTime().orElse("run")
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
-index 8642f3eaa4035243afd629b78ddb8cd2430323dd..1e401e34eff6a74d4593d19e5ca5d4afc0fbaae1 100644
+index ece77f5ea4b14bbed7c070131b3251ea86764538..aadd6550a5892e403f7b0bbef008461c1566a1bb 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -19,8 +19,8 @@ import java.util.stream.StreamSupport;
@@ -64,8 +64,8 @@ index 8642f3eaa4035243afd629b78ddb8cd2430323dd..1e401e34eff6a74d4593d19e5ca5d4af
@Nonnull
@Override
public Component getVersionMessage(@Nonnull String serverVersion) {
-- String[] parts = serverVersion.substring("git-Airplane-".length()).split("[-\\s]"); // Tuinity
-- final Component updateMessage = getUpdateStatusMessage("TECHNOVE/Airplane", GITHUB_BRANCH_NAME, parts[0]); // Tuinity
+- String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]");
+- final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
+ String[] parts = serverVersion.substring("git-Purpur-".length()).split("[-\\s]"); // Airplane // Purpur
+ final Component updateMessage = getUpdateStatusMessage("pl3xgaming/Purpur", "ver/" + getMinecraftVersion(), parts[0]); // Airplane // Purpur
final Component history = getHistory();
@@ -80,31 +80,7 @@ index 8642f3eaa4035243afd629b78ddb8cd2430323dd..1e401e34eff6a74d4593d19e5ca5d4af
org.bukkit.Bukkit.getLogger().warning("Pattern: " + VER_PATTERN.toString());
org.bukkit.Bukkit.getLogger().warning("Version: " + org.bukkit.Bukkit.getBukkitVersion());
}
-@@ -56,13 +56,18 @@ public class PaperVersionFetcher implements VersionFetcher {
-
- private static Component getUpdateStatusMessage(@Nonnull String repo, @Nonnull String branch, @Nonnull String versionInfo) {
- int distance;
-- //try {
-- // int jenkinsBuild = Integer.parseInt(versionInfo);
-- // distance = fetchDistanceFromSiteApi(jenkinsBuild, getMinecraftVersion());
-- //} catch (NumberFormatException ignored) {
-+ // Purpur start - put all this back, yet again
-+ try {
-+ int buildNumber = Integer.parseInt(versionInfo);
-+ distance = fetchDistanceFromSiteApi(buildNumber, getMinecraftVersion());
-+ if (distance < 0) {
-+ distance = fetchDistanceFromJenkins(buildNumber);
-+ }
-+ } catch (NumberFormatException ignored) {
- versionInfo = versionInfo.replace("\"", "");
- distance = fetchDistanceFromGitHub(repo, branch, versionInfo);
-- //}
-+ }
-+ // Purpur end
-
- switch (distance) {
- case -1:
-@@ -85,15 +90,11 @@ public class PaperVersionFetcher implements VersionFetcher {
+@@ -85,15 +85,11 @@ public class PaperVersionFetcher implements VersionFetcher {
if (siteApiVersion == null) { return -1; }
try {
try (BufferedReader reader = Resources.asCharSource(
@@ -122,29 +98,6 @@ index 8642f3eaa4035243afd629b78ddb8cd2430323dd..1e401e34eff6a74d4593d19e5ca5d4af
return latest - jenkinsBuild;
} catch (JsonSyntaxException ex) {
ex.printStackTrace();
-@@ -105,6 +106,22 @@ public class PaperVersionFetcher implements VersionFetcher {
- }
- }
-
-+ // Purpur start
-+ private static int fetchDistanceFromJenkins(int jenkinsBuild) {
-+ try {
-+ try (BufferedReader reader = Resources.asCharSource(new URL(JENKINS_URL), Charsets.UTF_8).openBufferedStream()) {
-+ return Integer.decode(reader.readLine()) - jenkinsBuild;
-+ } catch (NumberFormatException ex) {
-+ ex.printStackTrace();
-+ return -2;
-+ }
-+ } catch (IOException e) {
-+ e.printStackTrace();
-+ return -1;
-+ }
-+ }
-+ // Purpur end
-+
- // Contributed by Techcable in GH-65
- private static int fetchDistanceFromGitHub(@Nonnull String repo, @Nonnull String branch, @Nonnull String hash) {
- try {
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
index e0b1f0671d16ddddcb6725acd25a1d1d69e42701..8c3c68465197fafc14849dc38a572e309931e2a2 100644
--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
@@ -203,6 +156,19 @@ index c987e7c46afe6c41339e8e08bf2bfabe8c1ba098..e28807ab2613982c87d8c7daab3bea60
private final String serverVersion;
private final String bukkitVersion = Versioning.getBukkitVersion();
private final Logger logger = Logger.getLogger("Minecraft");
+diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+index efbe385b3a78f4bd0dee6b63d78999513433b79b..ac64c94048edb8b8b2e049ed1b0c366eadbb01be 100644
+--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+@@ -394,7 +394,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
+
+ @Override
+ public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
+- return new gg.airplane.AirplaneVersionFetcher(); // Airplane
++ return new com.destroystokyo.paper.PaperVersionFetcher(); // Airplane // Purpur
+ }
+
+ @Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
index 1788d79ea489e446d3d9f541693d4ba3dfc26015..e7d740e191c5ac408ba1fa493e9367dd52900a02 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
diff --git a/patches/server/0004-Purpur-config-files.patch b/patches/server/0004-Purpur-config-files.patch
index f80125c7f..89e433508 100644
--- a/patches/server/0004-Purpur-config-files.patch
+++ b/patches/server/0004-Purpur-config-files.patch
@@ -101,7 +101,7 @@ index d9bee4649ce376e8ef44720161bbeb4139e1132a..25cd8b550a81cf144fed62f32320cd2e
io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc.
io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 8b8daa771288492b4a02cb40c1b376b65e210e5b..d59f402622b93abc44b331f42cccdb785689aeda 100644
+index 24d772c18d5a448154909e4a51964ba29485a5c2..061af7fc45564c297958e2f08cd0a2fbd64a5c8e 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -168,6 +168,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -113,7 +113,7 @@ index 8b8daa771288492b4a02cb40c1b376b65e210e5b..d59f402622b93abc44b331f42cccdb78
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
public static BlockPos lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
-@@ -316,6 +318,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -325,6 +327,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, final DimensionType dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper
diff --git a/patches/server/0006-Component-related-conveniences.patch b/patches/server/0006-Component-related-conveniences.patch
index 82619ab29..f6b36d711 100644
--- a/patches/server/0006-Component-related-conveniences.patch
+++ b/patches/server/0006-Component-related-conveniences.patch
@@ -103,10 +103,10 @@ index ea1f7c8bf220982a086d4ae1663ae445b8c6cebd..dc5492b45bfa97c0e1237096764b79c8
this.server.sendMessage(message, sender);
Iterator iterator = this.players.iterator();
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 69fe6b0c774ec1f15e49826a2dc36d9288e3ae86..a00c38b224d6c5ff3bc0b75ad97e1e0cb1140af9 100644
+index d35cdcf2ee7568ad5caf52588db54e9c6f607d4b..7a954d7495636a27149a55b58436183e18e028dd 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -3617,6 +3617,34 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -3620,6 +3620,34 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
return SlotAccess.NULL;
}
diff --git a/patches/server/0007-Ridables.patch b/patches/server/0007-Ridables.patch
index ec949a0ed..084fbcf38 100644
--- a/patches/server/0007-Ridables.patch
+++ b/patches/server/0007-Ridables.patch
@@ -86,7 +86,7 @@ index d75bb089ee91bba87aba51ea95fcfe54b8c0a8ab..0f86e3896805e2f6a0e30c421522f031
if ((entity instanceof AbstractFish && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) {
ServerGamePacketListenerImpl.this.send(new ClientboundAddMobPacket((AbstractFish) entity));
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index a00c38b224d6c5ff3bc0b75ad97e1e0cb1140af9..af2287a9255a311ad4811edce7693e9cbe9d4741 100644
+index 7a954d7495636a27149a55b58436183e18e028dd..643f0c878352fd205f928aaa083cde59c911f926 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -230,7 +230,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
@@ -107,7 +107,7 @@ index a00c38b224d6c5ff3bc0b75ad97e1e0cb1140af9..af2287a9255a311ad4811edce7693e9c
private float eyeHeight;
public boolean isInPowderSnow;
public boolean wasInPowderSnow;
-@@ -2634,6 +2634,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -2637,6 +2637,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.passengers = ImmutableList.copyOf(list);
}
@@ -120,7 +120,7 @@ index a00c38b224d6c5ff3bc0b75ad97e1e0cb1140af9..af2287a9255a311ad4811edce7693e9c
}
return true; // CraftBukkit
}
-@@ -2674,6 +2680,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -2677,6 +2683,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
return false;
}
// Spigot end
@@ -135,7 +135,7 @@ index a00c38b224d6c5ff3bc0b75ad97e1e0cb1140af9..af2287a9255a311ad4811edce7693e9c
if (this.passengers.size() == 1 && this.passengers.get(0) == entity) {
this.passengers = ImmutableList.of();
} else {
-@@ -4333,4 +4347,41 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -4336,4 +4350,41 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
return ((ServerChunkCache) level.getChunkSource()).isPositionTicking(this);
}
// Paper end
@@ -262,7 +262,7 @@ index 5905f02cb695ca619ebcd13cad2fc6dff564f5d9..12ed24bf13079be5dcf5adb95c7cc0f6
// Paper end
if (!this.level.isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
-index b8e512e1c4b00b468b2d22add5653b98f4a2c81a..4cf2bc22e1b6452d056b7bc85f84b6177d1091dc 100644
+index 6051fd771dd989f2903b854b6564252a847a74e3..6106274009fcd8b43373e2fa9080183d6f6e36b3 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -140,6 +140,8 @@ public abstract class Mob extends LivingEntity {
diff --git a/patches/server/0054-Fix-the-dead-lagging-the-server.patch b/patches/server/0054-Fix-the-dead-lagging-the-server.patch
index f87b05925..503126bda 100644
--- a/patches/server/0054-Fix-the-dead-lagging-the-server.patch
+++ b/patches/server/0054-Fix-the-dead-lagging-the-server.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Fix the dead lagging the server
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index c2820fd6502b49ad33e0947339a703335bceb30c..aac2d74c588e78b6873e2bbd60f855e8d0b0d043 100644
+index 1ab4456b67b1b439b3b0e96f85de0fe104a5b2f8..082f8ede1d1839da7682a9cbb1ce16540f06b8ad 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -1769,6 +1769,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -1772,6 +1772,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
this.setYHeadRot(yaw); // Paper - Update head rotation
diff --git a/patches/server/0066-Configurable-void-damage-height-and-damage.patch b/patches/server/0066-Configurable-void-damage-height-and-damage.patch
index 216d087a1..b78c85484 100644
--- a/patches/server/0066-Configurable-void-damage-height-and-damage.patch
+++ b/patches/server/0066-Configurable-void-damage-height-and-damage.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Configurable void damage height and damage
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index aac2d74c588e78b6873e2bbd60f855e8d0b0d043..6dea19c28b66868ba10c4e51e3fca6f2ee6a366c 100644
+index 082f8ede1d1839da7682a9cbb1ce16540f06b8ad..9b33986d0b163597e9475b2ebe225780d1a33ec9 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -799,7 +799,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -800,7 +800,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public void checkOutOfWorld() {
// Paper start - Configurable nether ceiling damage
diff --git a/patches/server/0067-Add-canSaveToDisk-to-Entity.patch b/patches/server/0067-Add-canSaveToDisk-to-Entity.patch
index 9f7cef87f..8bc320a04 100644
--- a/patches/server/0067-Add-canSaveToDisk-to-Entity.patch
+++ b/patches/server/0067-Add-canSaveToDisk-to-Entity.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Add canSaveToDisk to Entity
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 0d9a161e4e9e497104ebea60d89dbc702afe6fe0..160f08cc4cae0fbc7914e1589888a3fceb423b0a 100644
+index 9b33986d0b163597e9475b2ebe225780d1a33ec9..9dbfa489bea660fc49411ed564ff74130a1585dc 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -4384,5 +4384,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -4387,5 +4387,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public boolean processClick(InteractionHand hand) {
return false;
}
diff --git a/patches/server/0082-Add-allow-water-in-end-world-option.patch b/patches/server/0082-Add-allow-water-in-end-world-option.patch
index 915227d25..5875c07a7 100644
--- a/patches/server/0082-Add-allow-water-in-end-world-option.patch
+++ b/patches/server/0082-Add-allow-water-in-end-world-option.patch
@@ -27,10 +27,10 @@ index 69c992ef0c526adf35907de7726832605187beb6..6356d5fdb349063071c9119ae776c22e
return true;
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index d59f402622b93abc44b331f42cccdb785689aeda..4253e200927aeec8bc4805bd9b2cadcebdfcc1aa 100644
+index 061af7fc45564c297958e2f08cd0a2fbd64a5c8e..bd5762f1ecbeb994ce41aab77fbbb0b6e110fe56 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -1585,4 +1585,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -1601,4 +1601,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
}
}
diff --git a/patches/server/0098-Stop-squids-floating-on-top-of-water.patch b/patches/server/0098-Stop-squids-floating-on-top-of-water.patch
index 2c9bd4a85..89264a4af 100644
--- a/patches/server/0098-Stop-squids-floating-on-top-of-water.patch
+++ b/patches/server/0098-Stop-squids-floating-on-top-of-water.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Stop squids floating on top of water
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 160f08cc4cae0fbc7914e1589888a3fceb423b0a..d21d173ce17c7e8965c4cbce506e8c46eb21b615 100644
+index 9dbfa489bea660fc49411ed564ff74130a1585dc..60bed04e92f6b9e99b680369e53feea0cf399886 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -3896,11 +3896,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -3899,11 +3899,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.yRotO = this.getYRot();
}
@@ -19,7 +19,7 @@ index 160f08cc4cae0fbc7914e1589888a3fceb423b0a..d21d173ce17c7e8965c4cbce506e8c46
+ // Purpur end
+
public boolean updateFluidHeightAndDoFluidPushing(Tag tag, double d0) {
- if (this.touchingUnloadedChunk()) {
+ if (false && this.touchingUnloadedChunk()) { // Airplane - cost of a lookup here is the same cost as below, so skip
return false;
} else {
- AABB axisalignedbb = this.getBoundingBox().deflate(0.001D);
diff --git a/patches/server/0101-Entities-can-use-portals-configuration.patch b/patches/server/0101-Entities-can-use-portals-configuration.patch
index 137fe3c73..e52b9a969 100644
--- a/patches/server/0101-Entities-can-use-portals-configuration.patch
+++ b/patches/server/0101-Entities-can-use-portals-configuration.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Entities can use portals configuration
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index d21d173ce17c7e8965c4cbce506e8c46eb21b615..e798ff01ad1cd7b94d644304d4949b0ef147dd51 100644
+index 60bed04e92f6b9e99b680369e53feea0cf399886..0820f4131692a9911e80df979ec1a4342ee76e58 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -2734,7 +2734,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -2737,7 +2737,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public void handleInsidePortal(BlockPos pos) {
if (this.isOnPortalCooldown()) {
this.setPortalCooldown();
@@ -17,7 +17,7 @@ index d21d173ce17c7e8965c4cbce506e8c46eb21b615..e798ff01ad1cd7b94d644304d4949b0e
if (!this.level.isClientSide && !pos.equals(this.portalEntrancePos)) {
this.portalEntrancePos = pos.immutable();
}
-@@ -3385,7 +3385,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -3388,7 +3388,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
public boolean canChangeDimensions() {
diff --git a/patches/server/0112-Stonecutter-damage.patch b/patches/server/0112-Stonecutter-damage.patch
index b7f19bb97..753bf8a4d 100644
--- a/patches/server/0112-Stonecutter-damage.patch
+++ b/patches/server/0112-Stonecutter-damage.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Stonecutter damage
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index ca42df1fd3e3ae24ebd6441d74db5e750cd01bdc..99a73372e2a39f7149f839b3d14fc3ca4bbeb8d7 100644
+index 0820f4131692a9911e80df979ec1a4342ee76e58..ee2dd53fb2527a2e322ca9c385a8a1fa5c2131b2 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -1034,7 +1034,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -1035,7 +1035,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
// CraftBukkit end
diff --git a/patches/server/0118-Add-adjustable-breeding-cooldown-to-config.patch b/patches/server/0118-Add-adjustable-breeding-cooldown-to-config.patch
index 81adb5912..6dbb435ca 100644
--- a/patches/server/0118-Add-adjustable-breeding-cooldown-to-config.patch
+++ b/patches/server/0118-Add-adjustable-breeding-cooldown-to-config.patch
@@ -33,7 +33,7 @@ index 43841b5c77beb73169e2ff1645afe1234d8f74c7..d5d9f8e9c7119ae159a085aa414fc7f3
entityageable.setBaby(true);
entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 4253e200927aeec8bc4805bd9b2cadcebdfcc1aa..e2d942fbc65c82e9e0d6b1ec81bb77b480ff7627 100644
+index bd5762f1ecbeb994ce41aab77fbbb0b6e110fe56..7a0462425f62ce1fb197fa2670e102286ef4c865 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -189,6 +189,49 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -86,7 +86,7 @@ index 4253e200927aeec8bc4805bd9b2cadcebdfcc1aa..e2d942fbc65c82e9e0d6b1ec81bb77b4
public CraftWorld getWorld() {
return this.world;
}
-@@ -319,6 +362,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -328,6 +371,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper
this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((ServerLevel) this, ((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), env); // Purpur
diff --git a/patches/server/0151-Movement-options-for-armor-stands.patch b/patches/server/0151-Movement-options-for-armor-stands.patch
index e392d8c9f..87cc619ef 100644
--- a/patches/server/0151-Movement-options-for-armor-stands.patch
+++ b/patches/server/0151-Movement-options-for-armor-stands.patch
@@ -17,10 +17,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 98d47b29763fbffedcc351b1e33400ce7e329f1c..3ad67d65990feaedbb67ed15fe50032c0fd0fdc2 100644
+index ee2dd53fb2527a2e322ca9c385a8a1fa5c2131b2..e096e5268330b47be2e629abdc34ed4ff54009d9 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -1621,7 +1621,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -1624,7 +1624,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
return this.isInWater() || flag;
}
@@ -30,7 +30,7 @@ index 98d47b29763fbffedcc351b1e33400ce7e329f1c..3ad67d65990feaedbb67ed15fe50032c
this.wasTouchingWater = false;
} else if (this.updateFluidHeightAndDoFluidPushing((Tag) FluidTags.WATER, 0.014D)) {
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
-index 796ab61f4513c02b0d55d34044d2f7084c447796..d119f8ab447bc17deabc494463de496161c9b126 100644
+index bb710e62477df3048d5219f1edfa9ffdefacb41d..aee5db3cdbc49de995780d0b0e219d0878a5f304 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -99,10 +99,12 @@ public class ArmorStand extends LivingEntity {
@@ -66,7 +66,7 @@ index 796ab61f4513c02b0d55d34044d2f7084c447796..d119f8ab447bc17deabc494463de4961
+ // Purpur end
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
-index 8eda95b6b8c71fdc2c1938304b51c626f66235bd..6a4170e60bf845ac33a7f65c0082617da584f99d 100644
+index 31c1e612a40c13e97b3784db9ef211265bb6f3f6..d330d23e63e3da106e8a44545792adfffc8d7918 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -103,10 +103,16 @@ public class PurpurWorldConfig {
diff --git a/patches/server/0152-Fix-stuck-in-portals.patch b/patches/server/0152-Fix-stuck-in-portals.patch
index 672485782..23e9099a3 100644
--- a/patches/server/0152-Fix-stuck-in-portals.patch
+++ b/patches/server/0152-Fix-stuck-in-portals.patch
@@ -17,10 +17,10 @@ index a2542b5d72393b6e0a06bd5e21c1e4e9a7f52860..33e36a80edbc80f0f562842ed690dccc
// CraftBukkit end
this.setLevel(worldserver);
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 7b0696ddb8c1d815b5bf5897865703579add0728..e4bb19855fd2cf885742f56d06e76faa85965b0b 100644
+index e096e5268330b47be2e629abdc34ed4ff54009d9..3c5347c0d4b65ced4b942504b1cdb8aab53016a5 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -2731,12 +2731,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -2734,12 +2734,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
return Vec3.directionFromRotation(this.getRotationVector());
}
diff --git a/patches/server/0174-Drowning-Settings.patch b/patches/server/0174-Drowning-Settings.patch
index f5088b8ee..14ff5a657 100644
--- a/patches/server/0174-Drowning-Settings.patch
+++ b/patches/server/0174-Drowning-Settings.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Drowning Settings
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index e4bb19855fd2cf885742f56d06e76faa85965b0b..a134831402f97de8deb59657227f98f1dbe3783b 100644
+index 3c5347c0d4b65ced4b942504b1cdb8aab53016a5..ce57f04a3e8395b90a46c50cab0b0cd6ecf8b3c2 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -2965,7 +2965,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -2968,7 +2968,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
public int getMaxAirSupply() {
diff --git a/patches/server/0185-Configurable-damage-settings-for-magma-blocks.patch b/patches/server/0185-Configurable-damage-settings-for-magma-blocks.patch
index 0bf705125..007cd6d00 100644
--- a/patches/server/0185-Configurable-damage-settings-for-magma-blocks.patch
+++ b/patches/server/0185-Configurable-damage-settings-for-magma-blocks.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Configurable damage settings for magma blocks
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 5536eb0f669b038e414cfdbf385b1f1cf3b4b2dd..585054a070701d7ca3edd386ec7ef8627e093797 100644
+index ce57f04a3e8395b90a46c50cab0b0cd6ecf8b3c2..8b7732ad47feddaf66f7db998a9ccbecea43d53b 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -1034,7 +1034,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -1035,7 +1035,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
// CraftBukkit end
diff --git a/patches/server/0204-API-for-any-mob-to-burn-daylight.patch b/patches/server/0204-API-for-any-mob-to-burn-daylight.patch
index 76b84967f..e1cd2f9f4 100644
--- a/patches/server/0204-API-for-any-mob-to-burn-daylight.patch
+++ b/patches/server/0204-API-for-any-mob-to-burn-daylight.patch
@@ -6,10 +6,10 @@ Subject: [PATCH] API for any mob to burn daylight
Co-authored by: Encode42
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index d432cf2f9bbe539d572c226dbbe70354a09a9c22..6105519cb28da034a70c3330af7bae105b692866 100644
+index 8b7732ad47feddaf66f7db998a9ccbecea43d53b..6d425a5eafec8b25ce15fb4c36ea1148f5bd92aa 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -4397,5 +4397,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -4400,5 +4400,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public boolean canSaveToDisk() {
return true;
}
@@ -89,7 +89,7 @@ index e1308770c3510f54da40b2ff38d08186bac22518..214bc2bcbcb88a9a62d2151a62aaa57b
public boolean isSensitiveToWater() {
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
-index a52ea8628f70861a80c2d62301da1cbf478b477f..5e62ecb980199f8dba97703403ef811167a24ec5 100644
+index 91081d8aa571f54a2f56b4dd341e9559f0a2e27a..02a227e1239ca3a1d54d746ea14b6ae7b12d1cd0 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -1643,17 +1643,7 @@ public abstract class Mob extends LivingEntity {
diff --git a/patches/server/0209-Add-toggle-for-end-portal-safe-teleporting.patch b/patches/server/0209-Add-toggle-for-end-portal-safe-teleporting.patch
index 01dc3a21e..a9f69214a 100644
--- a/patches/server/0209-Add-toggle-for-end-portal-safe-teleporting.patch
+++ b/patches/server/0209-Add-toggle-for-end-portal-safe-teleporting.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Add toggle for end portal safe teleporting
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 12662cb04b247bd46b3e1fab060e1c17a56e84a3..4ddbd66221d3a3e319335e2b0eefadc9adc64c8f 100644
+index 6d425a5eafec8b25ce15fb4c36ea1148f5bd92aa..b8dcebde55c73b283c13b3d82dd07388dad3eb9d 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -2782,7 +2782,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -2785,7 +2785,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
this.processPortalCooldown();