diff --git a/patches/server/0006-ConcurrentUtil.patch b/patches/server/0006-ConcurrentUtil.patch new file mode 100644 index 0000000000..065818eebe --- /dev/null +++ b/patches/server/0006-ConcurrentUtil.patch @@ -0,0 +1,6864 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 23 Jan 2022 22:58:11 -0800 +Subject: [PATCH] ConcurrentUtil + + +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/collection/MultiThreadedQueue.java b/src/main/java/ca/spottedleaf/concurrentutil/collection/MultiThreadedQueue.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f4415f782b32fed25da98e44b172f717c4d46e34 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/collection/MultiThreadedQueue.java +@@ -0,0 +1,1402 @@ ++package ca.spottedleaf.concurrentutil.collection; ++ ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import ca.spottedleaf.concurrentutil.util.Validate; ++import java.lang.invoke.VarHandle; ++import java.util.ArrayList; ++import java.util.Collection; ++import java.util.Iterator; ++import java.util.List; ++import java.util.NoSuchElementException; ++import java.util.Queue; ++import java.util.Spliterator; ++import java.util.Spliterators; ++import java.util.function.Consumer; ++import java.util.function.IntFunction; ++import java.util.function.Predicate; ++ ++/** ++ * MT-Safe linked first in first out ordered queue. ++ * ++ * This queue should out-perform {@link java.util.concurrent.ConcurrentLinkedQueue} in high-contention reads/writes, and is ++ * not any slower in lower contention reads/writes. ++ *

++ * Note that this queue breaks the specification laid out by {@link Collection}, see {@link #preventAdds()} and {@link Collection#add(Object)}. ++ *

++ *

++ * This queue will only unlink linked nodes through the {@link #peek()} and {@link #poll()} methods, and this is only if ++ * they are at the head of the queue. ++ *

++ * @param Type of element in this queue. ++ */ ++public class MultiThreadedQueue implements Queue { ++ ++ protected volatile LinkedNode head; /* Always non-null, high chance of being the actual head */ ++ ++ protected volatile LinkedNode tail; /* Always non-null, high chance of being the actual tail */ ++ ++ /* Note that it is possible to reach head from tail. */ ++ ++ /* IMPL NOTE: Leave hashCode and equals to their defaults */ ++ ++ protected static final VarHandle HEAD_HANDLE = ConcurrentUtil.getVarHandle(MultiThreadedQueue.class, "head", LinkedNode.class); ++ protected static final VarHandle TAIL_HANDLE = ConcurrentUtil.getVarHandle(MultiThreadedQueue.class, "tail", LinkedNode.class); ++ ++ /* head */ ++ ++ protected final void setHeadPlain(final LinkedNode newHead) { ++ HEAD_HANDLE.set(this, newHead); ++ } ++ ++ protected final void setHeadOpaque(final LinkedNode newHead) { ++ HEAD_HANDLE.setOpaque(this, newHead); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getHeadPlain() { ++ return (LinkedNode)HEAD_HANDLE.get(this); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getHeadOpaque() { ++ return (LinkedNode)HEAD_HANDLE.getOpaque(this); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getHeadAcquire() { ++ return (LinkedNode)HEAD_HANDLE.getAcquire(this); ++ } ++ ++ /* tail */ ++ ++ protected final void setTailPlain(final LinkedNode newTail) { ++ TAIL_HANDLE.set(this, newTail); ++ } ++ ++ protected final void setTailOpaque(final LinkedNode newTail) { ++ TAIL_HANDLE.setOpaque(this, newTail); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getTailPlain() { ++ return (LinkedNode)TAIL_HANDLE.get(this); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getTailOpaque() { ++ return (LinkedNode)TAIL_HANDLE.getOpaque(this); ++ } ++ ++ /** ++ * Constructs a {@code MultiThreadedQueue}, initially empty. ++ *

++ * The returned object may not be published without synchronization. ++ *

++ */ ++ public MultiThreadedQueue() { ++ final LinkedNode value = new LinkedNode<>(null, null); ++ this.setHeadPlain(value); ++ this.setTailPlain(value); ++ } ++ ++ /** ++ * Constructs a {@code MultiThreadedQueue}, initially containing all elements in the specified {@code collection}. ++ *

++ * The returned object may not be published without synchronization. ++ *

++ * @param collection The specified collection. ++ * @throws NullPointerException If {@code collection} is {@code null} or contains {@code null} elements. ++ */ ++ public MultiThreadedQueue(final Iterable collection) { ++ final Iterator elements = collection.iterator(); ++ ++ if (!elements.hasNext()) { ++ final LinkedNode value = new LinkedNode<>(null, null); ++ this.setHeadPlain(value); ++ this.setTailPlain(value); ++ return; ++ } ++ ++ final LinkedNode head = new LinkedNode<>(Validate.notNull(elements.next(), "Null element"), null); ++ LinkedNode tail = head; ++ ++ while (elements.hasNext()) { ++ final LinkedNode next = new LinkedNode<>(Validate.notNull(elements.next(), "Null element"), null); ++ tail.setNextPlain(next); ++ tail = next; ++ } ++ ++ this.setHeadPlain(head); ++ this.setTailPlain(tail); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public E remove() throws NoSuchElementException { ++ final E ret = this.poll(); ++ ++ if (ret == null) { ++ throw new NoSuchElementException(); ++ } ++ ++ return ret; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

++ * Contrary to the specification of {@link Collection#add}, this method will fail to add the element to this queue ++ * and return {@code false} if this queue is add-blocked. ++ *

++ */ ++ @Override ++ public boolean add(final E element) { ++ return this.offer(element); ++ } ++ ++ /** ++ * Adds the specified element to the tail of this queue. If this queue is currently add-locked, then the queue is ++ * released from that lock and this element is added. The unlock operation and addition of the specified ++ * element is atomic. ++ * @param element The specified element. ++ * @return {@code true} if this queue previously allowed additions ++ */ ++ public boolean forceAdd(final E element) { ++ final LinkedNode node = new LinkedNode<>(element, null); ++ ++ return !this.forceAppendList(node, node); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public E element() throws NoSuchElementException { ++ final E ret = this.peek(); ++ ++ if (ret == null) { ++ throw new NoSuchElementException(); ++ } ++ ++ return ret; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

++ * This method may also return {@code false} to indicate an element was not added if this queue is add-blocked. ++ *

++ */ ++ @Override ++ public boolean offer(final E element) { ++ Validate.notNull(element, "Null element"); ++ ++ final LinkedNode node = new LinkedNode<>(element, null); ++ ++ return this.appendList(node, node); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public E peek() { ++ for (LinkedNode head = this.getHeadOpaque(), curr = head;;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ if (this.getHeadOpaque() == head && curr != head) { ++ this.setHeadOpaque(curr); ++ } ++ return element; ++ } ++ ++ if (next == null || curr == next) { ++ return null; ++ } ++ curr = next; ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public E poll() { ++ return this.removeHead(); ++ } ++ ++ /** ++ * Retrieves and removes the head of this queue if it matches the specified predicate. If this queue is empty ++ * or the head does not match the predicate, this function returns {@code null}. ++ *

++ * The predicate may be invoked multiple or no times in this call. ++ *

++ * @param predicate The specified predicate. ++ * @return The head if it matches the predicate, or {@code null} if it did not or this queue is empty. ++ */ ++ public E pollIf(final Predicate predicate) { ++ return this.removeHead(Validate.notNull(predicate, "Null predicate")); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public void clear() { ++ //noinspection StatementWithEmptyBody ++ while (this.poll() != null); ++ } ++ ++ /** ++ * Prevents elements from being added to this queue. Once this is called, any attempt to add to this queue will fail. ++ *

++ * This function is MT-Safe. ++ *

++ * @return {@code true} if the queue was modified to prevent additions, {@code false} if it already prevented additions. ++ */ ++ public boolean preventAdds() { ++ final LinkedNode deadEnd = new LinkedNode<>(null, null); ++ deadEnd.setNextPlain(deadEnd); ++ ++ if (!this.appendList(deadEnd, deadEnd)) { ++ return false; ++ } ++ ++ this.setTailPlain(deadEnd); /* (try to) Ensure tail is set for the following #allowAdds call */ ++ return true; ++ } ++ ++ /** ++ * Allows elements to be added to this queue once again. Note that this function has undefined behaviour if ++ * {@link #preventAdds()} is not called beforehand. The benefit of this function over {@link #tryAllowAdds()} ++ * is that this function might perform better. ++ *

++ * This function is not MT-Safe. ++ *

++ */ ++ public void allowAdds() { ++ LinkedNode tail = this.getTailPlain(); ++ ++ /* We need to find the tail given the cas on tail isn't atomic (nor volatile) in this.appendList */ ++ /* Thus it is possible for an outdated tail to be set */ ++ while (tail != (tail = tail.getNextPlain())) {} ++ ++ tail.setNextVolatile(null); ++ } ++ ++ /** ++ * Tries to allow elements to be added to this queue. Returns {@code true} if the queue was previous add-locked, ++ * {@code false} otherwise. ++ *

++ * This function is MT-Safe, however it should not be used with {@link #allowAdds()}. ++ *

++ * @return {@code true} if the queue was previously add-locked, {@code false} otherwise. ++ */ ++ public boolean tryAllowAdds() { ++ LinkedNode tail = this.getTailPlain(); ++ ++ for (int failures = 0;;) { ++ /* We need to find the tail given the cas on tail isn't atomic (nor volatile) in this.appendList */ ++ /* Thus it is possible for an outdated tail to be set */ ++ while (tail != (tail = tail.getNextAcquire())) { ++ if (tail == null) { ++ return false; ++ } ++ } ++ ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (tail == (tail = tail.compareExchangeNextVolatile(tail, null))) { ++ return true; ++ } ++ ++ if (tail == null) { ++ return false; ++ } ++ ++failures; ++ } ++ } ++ ++ /** ++ * Atomically adds the specified element to this queue or allows additions to the queue. If additions ++ * are not allowed, the element is not added. ++ *

++ * This function is MT-Safe. ++ *

++ * @param element The specified element. ++ * @return {@code true} if the queue now allows additions, {@code false} if the element was added. ++ */ ++ public boolean addOrAllowAdds(final E element) { ++ Validate.notNull(element, "Null element"); ++ int failures = 0; ++ ++ final LinkedNode append = new LinkedNode<>(element, null); ++ ++ for (LinkedNode currTail = this.getTailOpaque(), curr = currTail;;) { ++ /* It has been experimentally shown that placing the read before the backoff results in significantly greater performance */ ++ /* It is likely due to a cache miss caused by another write to the next field */ ++ final LinkedNode next = curr.getNextVolatile(); ++ ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (next == null) { ++ final LinkedNode compared = curr.compareExchangeNextVolatile(null, append); ++ ++ if (compared == null) { ++ /* Added */ ++ /* Avoid CASing on tail more than we need to */ ++ /* CAS to avoid setting an out-of-date tail */ ++ if (this.getTailOpaque() == currTail) { ++ this.setTailOpaque(append); ++ } ++ return false; // we added ++ } ++ ++ ++failures; ++ curr = compared; ++ continue; ++ } else if (next == curr) { ++ final LinkedNode compared = curr.compareExchangeNextVolatile(curr, null); ++ ++ if (compared == curr) { ++ return true; // we let additions through ++ } ++ ++ ++failures; ++ ++ if (compared != null) { ++ curr = compared; ++ } ++ continue; ++ } ++ ++ if (curr == currTail) { ++ /* Tail is likely not up-to-date */ ++ curr = next; ++ } else { ++ /* Try to update to tail */ ++ if (currTail == (currTail = this.getTailOpaque())) { ++ curr = next; ++ } else { ++ curr = currTail; ++ } ++ } ++ } ++ } ++ ++ /** ++ * Atomically removes the head from this queue if it exists, otherwise prevents additions to this queue if no ++ * head is removed. ++ *

++ * This function is MT-Safe. ++ *

++ * If the queue is already add-blocked and empty then no operation is performed. ++ * @return {@code null} if the queue is now add-blocked or was previously add-blocked, else returns ++ * an non-null value which was the previous head of queue. ++ */ ++ public E pollOrBlockAdds() { ++ int failures = 0; ++ for (LinkedNode head = this.getHeadOpaque(), curr = head;;) { ++ final E currentVal = curr.getElementVolatile(); ++ final LinkedNode next = curr.getNextOpaque(); ++ ++ if (next == curr) { ++ return null; /* Additions are already blocked */ ++ } ++ ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (currentVal != null) { ++ if (curr.getAndSetElementVolatile(null) == null) { ++ ++failures; ++ continue; ++ } ++ ++ /* "CAS" to avoid setting an out-of-date head */ ++ if (this.getHeadOpaque() == head) { ++ this.setHeadOpaque(next != null ? next : curr); ++ } ++ ++ return currentVal; ++ } ++ ++ if (next == null) { ++ /* Try to update stale head */ ++ if (curr != head && this.getHeadOpaque() == head) { ++ this.setHeadOpaque(curr); ++ } ++ ++ final LinkedNode compared = curr.compareExchangeNextVolatile(null, curr); ++ ++ if (compared != null) { ++ // failed to block additions ++ curr = compared; ++ ++failures; ++ continue; ++ } ++ ++ return null; /* We blocked additions */ ++ } ++ ++ if (head == curr) { ++ /* head is likely not up-to-date */ ++ curr = next; ++ } else { ++ /* Try to update to head */ ++ if (head == (head = this.getHeadOpaque())) { ++ curr = next; ++ } else { ++ curr = head; ++ } ++ } ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean remove(final Object object) { ++ Validate.notNull(object, "Null object to remove"); ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ if ((element == object || element.equals(object)) && curr.getAndSetElementVolatile(null) == element) { ++ return true; ++ } ++ } ++ ++ if (next == curr || next == null) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return false; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean removeIf(final Predicate filter) { ++ Validate.notNull(filter, "Null filter"); ++ ++ boolean ret = false; ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ ret |= filter.test(element) && curr.getAndSetElementVolatile(null) == element; ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return ret; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean removeAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ boolean ret = false; ++ ++ /* Volatile is required to synchronize with the write to the first element */ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ ret |= collection.contains(element) && curr.getAndSetElementVolatile(null) == element; ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return ret; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean retainAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ boolean ret = false; ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ ret |= !collection.contains(element) && curr.getAndSetElementVolatile(null) == element; ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return ret; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public Object[] toArray() { ++ final List ret = new ArrayList<>(); ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ ret.add(element); ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return ret.toArray(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public T[] toArray(final T[] array) { ++ final List ret = new ArrayList<>(); ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ //noinspection unchecked ++ ret.add((T)element); ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return ret.toArray(array); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public T[] toArray(final IntFunction generator) { ++ Validate.notNull(generator, "Null generator"); ++ ++ final List ret = new ArrayList<>(); ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ //noinspection unchecked ++ ret.add((T)element); ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return ret.toArray(generator); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public String toString() { ++ final StringBuilder builder = new StringBuilder(); ++ ++ builder.append("MultiThreadedQueue: {elements: {"); ++ ++ int deadEntries = 0; ++ int totalEntries = 0; ++ int aliveEntries = 0; ++ ++ boolean addLocked = false; ++ ++ for (LinkedNode curr = this.getHeadOpaque();; ++totalEntries) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element == null) { ++ ++deadEntries; ++ } else { ++ ++aliveEntries; ++ } ++ ++ if (totalEntries != 0) { ++ builder.append(", "); ++ } ++ ++ builder.append(totalEntries).append(": \"").append(element).append('"'); ++ ++ if (next == null) { ++ break; ++ } ++ if (curr == next) { ++ addLocked = true; ++ break; ++ } ++ curr = next; ++ } ++ ++ builder.append("}, total_entries: \"").append(totalEntries).append("\", alive_entries: \"").append(aliveEntries) ++ .append("\", dead_entries:").append(deadEntries).append("\", add_locked: \"").append(addLocked) ++ .append("\"}"); ++ ++ return builder.toString(); ++ } ++ ++ /** ++ * Adds all elements from the specified collection to this queue. The addition is atomic. ++ * @param collection The specified collection. ++ * @return {@code true} if all elements were added successfully, or {@code false} if this queue is add-blocked, or ++ * {@code false} if the specified collection contains no elements. ++ */ ++ @Override ++ public boolean addAll(final Collection collection) { ++ return this.addAll((Iterable)collection); ++ } ++ ++ /** ++ * Adds all elements from the specified iterable object to this queue. The addition is atomic. ++ * @param iterable The specified iterable object. ++ * @return {@code true} if all elements were added successfully, or {@code false} if this queue is add-blocked, or ++ * {@code false} if the specified iterable contains no elements. ++ */ ++ public boolean addAll(final Iterable iterable) { ++ Validate.notNull(iterable, "Null iterable"); ++ ++ final Iterator elements = iterable.iterator(); ++ if (!elements.hasNext()) { ++ return false; ++ } ++ ++ /* Build a list of nodes to append */ ++ /* This is an much faster due to the fact that zero additional synchronization is performed */ ++ ++ final LinkedNode head = new LinkedNode<>(Validate.notNull(elements.next(), "Null element"), null); ++ LinkedNode tail = head; ++ ++ while (elements.hasNext()) { ++ final LinkedNode next = new LinkedNode<>(Validate.notNull(elements.next(), "Null element"), null); ++ tail.setNextPlain(next); ++ tail = next; ++ } ++ ++ return this.appendList(head, tail); ++ } ++ ++ /** ++ * Adds all of the elements from the specified array to this queue. ++ * @param items The specified array. ++ * @return {@code true} if all elements were added successfully, or {@code false} if this queue is add-blocked, or ++ * {@code false} if the specified array has a length of 0. ++ */ ++ public boolean addAll(final E[] items) { ++ return this.addAll(items, 0, items.length); ++ } ++ ++ /** ++ * Adds all of the elements from the specified array to this queue. ++ * @param items The specified array. ++ * @param off The offset in the array. ++ * @param len The number of items. ++ * @return {@code true} if all elements were added successfully, or {@code false} if this queue is add-blocked, or ++ * {@code false} if the specified array has a length of 0. ++ */ ++ public boolean addAll(final E[] items, final int off, final int len) { ++ Validate.notNull(items, "Items may not be null"); ++ Validate.arrayBounds(off, len, items.length, "Items array indices out of bounds"); ++ ++ if (len == 0) { ++ return false; ++ } ++ ++ final LinkedNode head = new LinkedNode<>(Validate.notNull(items[off], "Null element"), null); ++ LinkedNode tail = head; ++ ++ for (int i = 1; i < len; ++i) { ++ final LinkedNode next = new LinkedNode<>(Validate.notNull(items[off + i], "Null element"), null); ++ tail.setNextPlain(next); ++ tail = next; ++ } ++ ++ return this.appendList(head, tail); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean containsAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ for (final Object element : collection) { ++ if (!this.contains(element)) { ++ return false; ++ } ++ } ++ return false; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public Iterator iterator() { ++ return new LinkedIterator<>(this.getHeadOpaque()); ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

++ * Note that this function is computed non-atomically and in O(n) time. The value returned may not be representative of ++ * the queue in its current state. ++ *

++ */ ++ @Override ++ public int size() { ++ int size = 0; ++ ++ /* Volatile is required to synchronize with the write to the first element */ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ ++size; ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return size; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean isEmpty() { ++ return this.peek() == null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean contains(final Object object) { ++ Validate.notNull(object, "Null object"); ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null && (element == object || element.equals(object))) { ++ return true; ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return false; ++ } ++ ++ /** ++ * Finds the first element in this queue that matches the predicate. ++ * @param predicate The predicate to test elements against. ++ * @return The first element that matched the predicate, {@code null} if none matched. ++ */ ++ public E find(final Predicate predicate) { ++ Validate.notNull(predicate, "Null predicate"); ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null && predicate.test(element)) { ++ return element; ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ ++ return null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public void forEach(final Consumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ for (LinkedNode curr = this.getHeadOpaque();;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E element = curr.getElementPlain(); /* Likely in sync */ ++ ++ if (element != null) { ++ action.accept(element); ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ } ++ ++ // return true if normal addition, false if the queue previously disallowed additions ++ protected final boolean forceAppendList(final LinkedNode head, final LinkedNode tail) { ++ int failures = 0; ++ ++ for (LinkedNode currTail = this.getTailOpaque(), curr = currTail;;) { ++ /* It has been experimentally shown that placing the read before the backoff results in significantly greater performance */ ++ /* It is likely due to a cache miss caused by another write to the next field */ ++ final LinkedNode next = curr.getNextVolatile(); ++ ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (next == null || next == curr) { ++ final LinkedNode compared = curr.compareExchangeNextVolatile(next, head); ++ ++ if (compared == next) { ++ /* Added */ ++ /* Avoid CASing on tail more than we need to */ ++ /* "CAS" to avoid setting an out-of-date tail */ ++ if (this.getTailOpaque() == currTail) { ++ this.setTailOpaque(tail); ++ } ++ return next != curr; ++ } ++ ++ ++failures; ++ curr = compared; ++ continue; ++ } ++ ++ if (curr == currTail) { ++ /* Tail is likely not up-to-date */ ++ curr = next; ++ } else { ++ /* Try to update to tail */ ++ if (currTail == (currTail = this.getTailOpaque())) { ++ curr = next; ++ } else { ++ curr = currTail; ++ } ++ } ++ } ++ } ++ ++ // return true if successful, false otherwise ++ protected final boolean appendList(final LinkedNode head, final LinkedNode tail) { ++ int failures = 0; ++ ++ for (LinkedNode currTail = this.getTailOpaque(), curr = currTail;;) { ++ /* It has been experimentally shown that placing the read before the backoff results in significantly greater performance */ ++ /* It is likely due to a cache miss caused by another write to the next field */ ++ final LinkedNode next = curr.getNextVolatile(); ++ ++ if (next == curr) { ++ /* Additions are stopped */ ++ return false; ++ } ++ ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (next == null) { ++ final LinkedNode compared = curr.compareExchangeNextVolatile(null, head); ++ ++ if (compared == null) { ++ /* Added */ ++ /* Avoid CASing on tail more than we need to */ ++ /* CAS to avoid setting an out-of-date tail */ ++ if (this.getTailOpaque() == currTail) { ++ this.setTailOpaque(tail); ++ } ++ return true; ++ } ++ ++ ++failures; ++ curr = compared; ++ continue; ++ } ++ ++ if (curr == currTail) { ++ /* Tail is likely not up-to-date */ ++ curr = next; ++ } else { ++ /* Try to update to tail */ ++ if (currTail == (currTail = this.getTailOpaque())) { ++ curr = next; ++ } else { ++ curr = currTail; ++ } ++ } ++ } ++ } ++ ++ protected final E removeHead(final Predicate predicate) { ++ int failures = 0; ++ for (LinkedNode head = this.getHeadOpaque(), curr = head;;) { ++ // volatile here synchronizes-with writes to element ++ final LinkedNode next = curr.getNextVolatile(); ++ final E currentVal = curr.getElementPlain(); ++ ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (currentVal != null) { ++ if (!predicate.test(currentVal)) { ++ /* Try to update stale head */ ++ if (curr != head && this.getHeadOpaque() == head) { ++ this.setHeadOpaque(curr); ++ } ++ return null; ++ } ++ if (curr.getAndSetElementVolatile(null) == null) { ++ /* Failed to get head */ ++ if (curr == (curr = next) || next == null) { ++ return null; ++ } ++ ++failures; ++ continue; ++ } ++ ++ /* "CAS" to avoid setting an out-of-date head */ ++ if (this.getHeadOpaque() == head) { ++ this.setHeadOpaque(next != null ? next : curr); ++ } ++ ++ return currentVal; ++ } ++ ++ if (curr == next || next == null) { ++ /* Try to update stale head */ ++ if (curr != head && this.getHeadOpaque() == head) { ++ this.setHeadOpaque(curr); ++ } ++ return null; /* End of queue */ ++ } ++ ++ if (head == curr) { ++ /* head is likely not up-to-date */ ++ curr = next; ++ } else { ++ /* Try to update to head */ ++ if (head == (head = this.getHeadOpaque())) { ++ curr = next; ++ } else { ++ curr = head; ++ } ++ } ++ } ++ } ++ ++ protected final E removeHead() { ++ int failures = 0; ++ for (LinkedNode head = this.getHeadOpaque(), curr = head;;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ final E currentVal = curr.getElementPlain(); ++ ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (currentVal != null) { ++ if (curr.getAndSetElementVolatile(null) == null) { ++ /* Failed to get head */ ++ if (curr == (curr = next) || next == null) { ++ return null; ++ } ++ ++failures; ++ continue; ++ } ++ ++ /* "CAS" to avoid setting an out-of-date head */ ++ if (this.getHeadOpaque() == head) { ++ this.setHeadOpaque(next != null ? next : curr); ++ } ++ ++ return currentVal; ++ } ++ ++ if (curr == next || next == null) { ++ /* Try to update stale head */ ++ if (curr != head && this.getHeadOpaque() == head) { ++ this.setHeadOpaque(curr); ++ } ++ return null; /* End of queue */ ++ } ++ ++ if (head == curr) { ++ /* head is likely not up-to-date */ ++ curr = next; ++ } else { ++ /* Try to update to head */ ++ if (head == (head = this.getHeadOpaque())) { ++ curr = next; ++ } else { ++ curr = head; ++ } ++ } ++ } ++ } ++ ++ /** ++ * Empties the queue into the specified consumer. This function is optimized for single-threaded reads, and should ++ * be faster than a loop on {@link #poll()}. ++ *

++ * This function is not MT-Safe. This function cannot be called with other read operations ({@link #peek()}, {@link #poll()}, ++ * {@link #clear()}, etc). ++ * Write operations are safe to be called concurrently. ++ *

++ * @param consumer The consumer to accept the elements. ++ * @return The total number of elements drained. ++ */ ++ public int drain(final Consumer consumer) { ++ return this.drain(consumer, false, ConcurrentUtil::rethrow); ++ } ++ ++ /** ++ * Empties the queue into the specified consumer. This function is optimized for single-threaded reads, and should ++ * be faster than a loop on {@link #poll()}. ++ *

++ * If {@code preventAdds} is {@code true}, then after this function returns the queue is guaranteed to be empty and ++ * additions to the queue will fail. ++ *

++ *

++ * This function is not MT-Safe. This function cannot be called with other read operations ({@link #peek()}, {@link #poll()}, ++ * {@link #clear()}, etc). ++ * Write operations are safe to be called concurrently. ++ *

++ * @param consumer The consumer to accept the elements. ++ * @param preventAdds Whether to prevent additions to this queue after draining. ++ * @return The total number of elements drained. ++ */ ++ public int drain(final Consumer consumer, final boolean preventAdds) { ++ return this.drain(consumer, preventAdds, ConcurrentUtil::rethrow); ++ } ++ ++ /** ++ * Empties the queue into the specified consumer. This function is optimized for single-threaded reads, and should ++ * be faster than a loop on {@link #poll()}. ++ *

++ * If {@code preventAdds} is {@code true}, then after this function returns the queue is guaranteed to be empty and ++ * additions to the queue will fail. ++ *

++ *

++ * This function is not MT-Safe. This function cannot be called with other read operations ({@link #peek()}, {@link #poll()}, ++ * {@link #clear()}, {@link #remove(Object)} etc). ++ * Only write operations are safe to be called concurrently. ++ *

++ * @param consumer The consumer to accept the elements. ++ * @param preventAdds Whether to prevent additions to this queue after draining. ++ * @param exceptionHandler Invoked when the consumer raises an exception. ++ * @return The total number of elements drained. ++ */ ++ public int drain(final Consumer consumer, final boolean preventAdds, final Consumer exceptionHandler) { ++ Validate.notNull(consumer, "Null consumer"); ++ Validate.notNull(exceptionHandler, "Null exception handler"); ++ ++ /* This function assumes proper synchronization is made to ensure drain and no other read function are called concurrently */ ++ /* This allows plain write usages instead of opaque or higher */ ++ int total = 0; ++ ++ final LinkedNode head = this.getHeadAcquire(); /* Required to synchronize with the write to the first element field */ ++ LinkedNode curr = head; ++ ++ for (;;) { ++ /* Volatile acquires with the write to the element field */ ++ final E currentVal = curr.getElementPlain(); ++ LinkedNode next = curr.getNextVolatile(); ++ ++ if (next == curr) { ++ /* Add-locked nodes always have a null value */ ++ break; ++ } ++ ++ if (currentVal == null) { ++ if (next == null) { ++ if (preventAdds && (next = curr.compareExchangeNextVolatile(null, curr)) != null) { ++ // failed to prevent adds, continue ++ curr = next; ++ continue; ++ } else { ++ // we're done here ++ break; ++ } ++ } ++ curr = next; ++ continue; ++ } ++ ++ try { ++ consumer.accept(currentVal); ++ } catch (final Exception ex) { ++ this.setHeadOpaque(next != null ? next : curr); /* Avoid perf penalty (of reiterating) if the exception handler decides to re-throw */ ++ curr.setElementOpaque(null); /* set here, we might re-throw */ ++ ++ exceptionHandler.accept(ex); ++ } ++ ++ curr.setElementOpaque(null); ++ ++ ++total; ++ ++ if (next == null) { ++ if (preventAdds && (next = curr.compareExchangeNextVolatile(null, curr)) != null) { ++ /* Retry with next value */ ++ curr = next; ++ continue; ++ } ++ break; ++ } ++ ++ curr = next; ++ } ++ if (curr != head) { ++ this.setHeadOpaque(curr); /* While this may be a plain write, eventually publish it for methods such as find. */ ++ } ++ return total; ++ } ++ ++ @Override ++ public Spliterator spliterator() { // TODO implement ++ return Spliterators.spliterator(this, Spliterator.CONCURRENT | ++ Spliterator.NONNULL | Spliterator.ORDERED); ++ } ++ ++ protected static final class LinkedNode { ++ ++ protected volatile Object element; ++ protected volatile LinkedNode next; ++ ++ protected static final VarHandle ELEMENT_HANDLE = ConcurrentUtil.getVarHandle(LinkedNode.class, "element", Object.class); ++ protected static final VarHandle NEXT_HANDLE = ConcurrentUtil.getVarHandle(LinkedNode.class, "next", LinkedNode.class); ++ ++ protected LinkedNode(final Object element, final LinkedNode next) { ++ ELEMENT_HANDLE.set(this, element); ++ NEXT_HANDLE.set(this, next); ++ } ++ ++ /* element */ ++ ++ @SuppressWarnings("unchecked") ++ protected final E getElementPlain() { ++ return (E)ELEMENT_HANDLE.get(this); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final E getElementVolatile() { ++ return (E)ELEMENT_HANDLE.getVolatile(this); ++ } ++ ++ protected final void setElementPlain(final E update) { ++ ELEMENT_HANDLE.set(this, (Object)update); ++ } ++ ++ protected final void setElementOpaque(final E update) { ++ ELEMENT_HANDLE.setOpaque(this, (Object)update); ++ } ++ ++ protected final void setElementVolatile(final E update) { ++ ELEMENT_HANDLE.setVolatile(this, (Object)update); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final E getAndSetElementVolatile(final E update) { ++ return (E)ELEMENT_HANDLE.getAndSet(this, update); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final E compareExchangeElementVolatile(final E expect, final E update) { ++ return (E)ELEMENT_HANDLE.compareAndExchange(this, expect, update); ++ } ++ ++ /* next */ ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getNextPlain() { ++ return (LinkedNode)NEXT_HANDLE.get(this); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getNextOpaque() { ++ return (LinkedNode)NEXT_HANDLE.getOpaque(this); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getNextAcquire() { ++ return (LinkedNode)NEXT_HANDLE.getAcquire(this); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode getNextVolatile() { ++ return (LinkedNode)NEXT_HANDLE.getVolatile(this); ++ } ++ ++ protected final void setNextPlain(final LinkedNode next) { ++ NEXT_HANDLE.set(this, next); ++ } ++ ++ protected final void setNextVolatile(final LinkedNode next) { ++ NEXT_HANDLE.setVolatile(this, next); ++ } ++ ++ @SuppressWarnings("unchecked") ++ protected final LinkedNode compareExchangeNextVolatile(final LinkedNode expect, final LinkedNode set) { ++ return (LinkedNode)NEXT_HANDLE.compareAndExchange(this, expect, set); ++ } ++ } ++ ++ protected static final class LinkedIterator implements Iterator { ++ ++ protected LinkedNode curr; /* last returned by next() */ ++ protected LinkedNode next; /* next to return from next() */ ++ protected E nextElement; /* cached to avoid a race condition with removing or polling */ ++ ++ protected LinkedIterator(final LinkedNode start) { ++ /* setup nextElement and next */ ++ for (LinkedNode curr = start;;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ ++ final E element = curr.getElementPlain(); ++ ++ if (element != null) { ++ this.nextElement = element; ++ this.next = curr; ++ break; ++ } ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ curr = next; ++ } ++ } ++ ++ protected final void findNext() { ++ /* only called if this.nextElement != null, which means this.next != null */ ++ for (LinkedNode curr = this.next;;) { ++ final LinkedNode next = curr.getNextVolatile(); ++ ++ if (next == null || next == curr) { ++ break; ++ } ++ ++ final E element = next.getElementPlain(); ++ ++ if (element != null) { ++ this.nextElement = element; ++ this.curr = this.next; /* this.next will be the value returned from next(), set this.curr for remove() */ ++ this.next = next; ++ return; ++ } ++ curr = next; ++ } ++ ++ /* out of nodes to iterate */ ++ /* keep curr for remove() calls */ ++ this.next = null; ++ this.nextElement = null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean hasNext() { ++ return this.nextElement != null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public E next() { ++ final E element = this.nextElement; ++ ++ if (element == null) { ++ throw new NoSuchElementException(); ++ } ++ ++ this.findNext(); ++ ++ return element; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public void remove() { ++ if (this.curr == null) { ++ throw new IllegalStateException(); ++ } ++ ++ this.curr.setElementVolatile(null); ++ this.curr = null; ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/completable/Completable.java b/src/main/java/ca/spottedleaf/concurrentutil/completable/Completable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a1ad3308f9c3545a604b635896259a1cd3382b2a +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/completable/Completable.java +@@ -0,0 +1,98 @@ ++package ca.spottedleaf.concurrentutil.completable; ++ ++import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; ++import ca.spottedleaf.concurrentutil.executor.Cancellable; ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import com.mojang.logging.LogUtils; ++import org.slf4j.Logger; ++import java.util.function.BiConsumer; ++ ++public final class Completable { ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ ++ private final MultiThreadedQueue> waiters = new MultiThreadedQueue<>(); ++ private T result; ++ private Throwable throwable; ++ private volatile boolean completed; ++ ++ public boolean isCompleted() { ++ return this.completed; ++ } ++ ++ /** ++ * Note: Can only use after calling {@link #addAsynchronousWaiter(BiConsumer)}, as this function performs zero ++ * synchronisation ++ */ ++ public T getResult() { ++ return this.result; ++ } ++ ++ /** ++ * Note: Can only use after calling {@link #addAsynchronousWaiter(BiConsumer)}, as this function performs zero ++ * synchronisation ++ */ ++ public Throwable getThrowable() { ++ return this.throwable; ++ } ++ ++ public Cancellable addAsynchronousWaiter(final BiConsumer consumer) { ++ if (this.waiters.add(consumer)) { ++ return new CancellableImpl(consumer); ++ } ++ return null; ++ } ++ ++ private void completeAllWaiters(final T result, final Throwable throwable) { ++ this.completed = true; ++ BiConsumer waiter; ++ while ((waiter = this.waiters.pollOrBlockAdds()) != null) { ++ this.completeWaiter(waiter, result, throwable); ++ } ++ } ++ ++ private void completeWaiter(final BiConsumer consumer, final T result, final Throwable throwable) { ++ try { ++ consumer.accept(result, throwable); ++ } catch (final ThreadDeath death) { ++ throw death; ++ } catch (final Throwable throwable2) { ++ LOGGER.error("Failed to complete callback " + ConcurrentUtil.genericToString(consumer), throwable2); ++ } ++ } ++ ++ public Cancellable addWaiter(final BiConsumer consumer) { ++ if (this.waiters.add(consumer)) { ++ return new CancellableImpl(consumer); ++ } ++ this.completeWaiter(consumer, this.result, this.throwable); ++ return new CancellableImpl(consumer); ++ } ++ ++ public void complete(final T result) { ++ this.result = result; ++ this.completeAllWaiters(result, null); ++ } ++ ++ public void completeWithThrowable(final Throwable throwable) { ++ if (throwable == null) { ++ throw new NullPointerException("Throwable cannot be null"); ++ } ++ this.throwable = throwable; ++ this.completeAllWaiters(null, throwable); ++ } ++ ++ private final class CancellableImpl implements Cancellable { ++ ++ private final BiConsumer waiter; ++ ++ private CancellableImpl(final BiConsumer waiter) { ++ this.waiter = waiter; ++ } ++ ++ @Override ++ public boolean cancel() { ++ return Completable.this.waiters.remove(this.waiter); ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/executor/BaseExecutor.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/BaseExecutor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..716a0fd3f558df748e355069746272facb91de22 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/BaseExecutor.java +@@ -0,0 +1,198 @@ ++package ca.spottedleaf.concurrentutil.executor; ++ ++import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import java.util.function.BooleanSupplier; ++ ++public interface BaseExecutor { ++ ++ /** ++ * Returns whether every task scheduled to this queue has been removed and executed or cancelled. If no tasks have been queued, ++ * returns {@code true}. ++ * ++ * @return {@code true} if all tasks that have been queued have finished executing or no tasks have been queued, {@code false} otherwise. ++ */ ++ public default boolean haveAllTasksExecuted() { ++ // order is important ++ // if new tasks are scheduled between the reading of these variables, scheduled is guaranteed to be higher - ++ // so our check fails, and we try again ++ final long completed = this.getTotalTasksExecuted(); ++ final long scheduled = this.getTotalTasksScheduled(); ++ ++ return completed == scheduled; ++ } ++ ++ /** ++ * Returns the number of tasks that have been scheduled or execute or are pending to be scheduled. ++ */ ++ public long getTotalTasksScheduled(); ++ ++ /** ++ * Returns the number of tasks that have fully been executed. ++ */ ++ public long getTotalTasksExecuted(); ++ ++ ++ /** ++ * Waits until this queue has had all of its tasks executed (NOT removed). See {@link #haveAllTasksExecuted()} ++ *

++ * This call is most effective after a {@link #shutdown()} call, as the shutdown call guarantees no tasks can ++ * be executed and the waitUntilAllExecuted call makes sure the queue is empty. Effectively, using shutdown then using ++ * waitUntilAllExecuted ensures this queue is empty - and most importantly, will remain empty. ++ *

++ *

++ * This method is not guaranteed to be immediately responsive to queue state, so calls may take significantly more ++ * time than expected. Effectively, do not rely on this call being fast - even if there are few tasks scheduled. ++ *

++ *

++ * Note: Interruptions to the the current thread have no effect. Interrupt status is also not affected by this cal. ++ *

++ * ++ * @throws IllegalStateException If the current thread is not allowed to wait ++ */ ++ public default void waitUntilAllExecuted() throws IllegalStateException { ++ long failures = 9L; // start out at 1ms ++ ++ while (!this.haveAllTasksExecuted()) { ++ Thread.yield(); ++ failures = ConcurrentUtil.linearLongBackoff(failures, 500_000L, 5_000_000L); // 500us, 5ms ++ } ++ } ++ ++ /** ++ * Executes the next available task. ++ *

++ * If there is a task with priority {@link PrioritisedExecutor.Priority#BLOCKING} available, then that such task is executed. ++ *

++ *

++ * If there is a task with priority {@link PrioritisedExecutor.Priority#IDLE} available then that task is only executed ++ * when there are no other tasks available with a higher priority. ++ *

++ *

++ * If there are no tasks that have priority {@link PrioritisedExecutor.Priority#BLOCKING} or {@link PrioritisedExecutor.Priority#IDLE}, then ++ * this function will be biased to execute tasks that have higher priorities. ++ *

++ * ++ * @return {@code true} if a task was executed, {@code false} otherwise ++ * @throws IllegalStateException If the current thread is not allowed to execute a task ++ */ ++ public boolean executeTask() throws IllegalStateException; ++ ++ /** ++ * Executes all queued tasks. ++ * ++ * @return {@code true} if a task was executed, {@code false} otherwise ++ * @throws IllegalStateException If the current thread is not allowed to execute a task ++ */ ++ public default boolean executeAll() { ++ if (!this.executeTask()) { ++ return false; ++ } ++ ++ while (this.executeTask()); ++ ++ return true; ++ } ++ ++ /** ++ * Waits and executes tasks until the condition returns {@code true}. ++ *

++ * WARNING: This function is not suitable for waiting until a deadline! ++ * Use {@link #executeUntil(long)} or {@link #executeConditionally(BooleanSupplier, long)} instead. ++ *

++ */ ++ public default void executeConditionally(final BooleanSupplier condition) { ++ long failures = 0; ++ while (!condition.getAsBoolean()) { ++ if (this.executeTask()) { ++ failures = failures >>> 2; ++ } else { ++ failures = ConcurrentUtil.linearLongBackoff(failures, 100_000L, 10_000_000L); // 100us, 10ms ++ } ++ } ++ } ++ ++ /** ++ * Waits and executes tasks until the condition returns {@code true} or {@code System.nanoTime() >= deadline}. ++ */ ++ public default void executeConditionally(final BooleanSupplier condition, final long deadline) { ++ long failures = 0; ++ // double check deadline; we don't know how expensive the condition is ++ while ((System.nanoTime() < deadline) && !condition.getAsBoolean() && (System.nanoTime() < deadline)) { ++ if (this.executeTask()) { ++ failures = failures >>> 2; ++ } else { ++ failures = ConcurrentUtil.linearLongBackoffDeadline(failures, 100_000L, 10_000_000L, deadline); // 100us, 10ms ++ } ++ } ++ } ++ ++ /** ++ * Waits and executes tasks until {@code System.nanoTime() >= deadline}. ++ */ ++ public default void executeUntil(final long deadline) { ++ long failures = 0; ++ while (System.nanoTime() < deadline) { ++ if (this.executeTask()) { ++ failures = failures >>> 2; ++ } else { ++ failures = ConcurrentUtil.linearLongBackoffDeadline(failures, 100_000L, 10_000_000L, deadline); // 100us, 10ms ++ } ++ } ++ } ++ ++ /** ++ * Prevent further additions to this queue. Attempts to add after this call has completed (potentially during) will ++ * result in {@link IllegalStateException} being thrown. ++ *

++ * This operation is atomic with respect to other shutdown calls ++ *

++ *

++ * After this call has completed, regardless of return value, this queue will be shutdown. ++ *

++ * ++ * @return {@code true} if the queue was shutdown, {@code false} if it has shut down already ++ * @throws UnsupportedOperationException If this queue does not support shutdown ++ */ ++ public default boolean shutdown() throws UnsupportedOperationException { ++ throw new UnsupportedOperationException(); ++ } ++ ++ /** ++ * Returns whether this queue has shut down. Effectively, whether new tasks will be rejected - this method ++ * does not indicate whether all of the tasks scheduled have been executed. ++ * @return Returns whether this queue has shut down. ++ */ ++ public default boolean isShutdown() { ++ return false; ++ } ++ ++ public static interface BaseTask extends Cancellable { ++ ++ /** ++ * Causes a lazily queued task to become queued or executed ++ * ++ * @throws IllegalStateException If the backing queue has shutdown ++ * @return {@code true} If the task was queued, {@code false} if the task was already queued/cancelled/executed ++ */ ++ public boolean queue(); ++ ++ /** ++ * Forces this task to be marked as completed. ++ * ++ * @return {@code true} if the task was cancelled, {@code false} if the task has already completed or is being completed. ++ */ ++ @Override ++ public boolean cancel(); ++ ++ /** ++ * Executes this task. This will also mark the task as completing. ++ *

++ * Exceptions thrown from the runnable will be rethrown. ++ *

++ * ++ * @return {@code true} if this task was executed, {@code false} if it was already marked as completed. ++ */ ++ public boolean execute(); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/executor/Cancellable.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/Cancellable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..11449056361bb6c5a055f543cdd135c4113757c6 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/Cancellable.java +@@ -0,0 +1,14 @@ ++package ca.spottedleaf.concurrentutil.executor; ++ ++/** ++ * Interface specifying that something can be cancelled. ++ */ ++public interface Cancellable { ++ ++ /** ++ * Tries to cancel this task. If the task is in a stage that is too late to be cancelled, then this function ++ * will return {@code false}. If the task is already cancelled, then this function returns {@code false}. Only ++ * when this function successfully stops this task from being completed will it return {@code true}. ++ */ ++ public boolean cancel(); ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/DelayedPrioritisedTask.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/DelayedPrioritisedTask.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3ce10053d4ec51855ad7012abb5d97df1c0e557a +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/DelayedPrioritisedTask.java +@@ -0,0 +1,170 @@ ++package ca.spottedleaf.concurrentutil.executor.standard; ++ ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import java.lang.invoke.VarHandle; ++ ++public class DelayedPrioritisedTask { ++ ++ protected volatile int priority; ++ protected static final VarHandle PRIORITY_HANDLE = ConcurrentUtil.getVarHandle(DelayedPrioritisedTask.class, "priority", int.class); ++ ++ protected static final int PRIORITY_SET = Integer.MIN_VALUE >>> 0; ++ ++ protected final int getPriorityVolatile() { ++ return (int)PRIORITY_HANDLE.getVolatile((DelayedPrioritisedTask)this); ++ } ++ ++ protected final int compareAndExchangePriorityVolatile(final int expect, final int update) { ++ return (int)PRIORITY_HANDLE.compareAndExchange((DelayedPrioritisedTask)this, (int)expect, (int)update); ++ } ++ ++ protected final int getAndOrPriorityVolatile(final int val) { ++ return (int)PRIORITY_HANDLE.getAndBitwiseOr((DelayedPrioritisedTask)this, (int)val); ++ } ++ ++ protected final void setPriorityPlain(final int val) { ++ PRIORITY_HANDLE.set((DelayedPrioritisedTask)this, (int)val); ++ } ++ ++ protected volatile PrioritisedExecutor.PrioritisedTask task; ++ protected static final VarHandle TASK_HANDLE = ConcurrentUtil.getVarHandle(DelayedPrioritisedTask.class, "task", PrioritisedExecutor.PrioritisedTask.class); ++ ++ protected PrioritisedExecutor.PrioritisedTask getTaskPlain() { ++ return (PrioritisedExecutor.PrioritisedTask)TASK_HANDLE.get((DelayedPrioritisedTask)this); ++ } ++ ++ protected PrioritisedExecutor.PrioritisedTask getTaskVolatile() { ++ return (PrioritisedExecutor.PrioritisedTask)TASK_HANDLE.getVolatile((DelayedPrioritisedTask)this); ++ } ++ ++ protected final PrioritisedExecutor.PrioritisedTask compareAndExchangeTaskVolatile(final PrioritisedExecutor.PrioritisedTask expect, final PrioritisedExecutor.PrioritisedTask update) { ++ return (PrioritisedExecutor.PrioritisedTask)TASK_HANDLE.compareAndExchange((DelayedPrioritisedTask)this, (PrioritisedExecutor.PrioritisedTask)expect, (PrioritisedExecutor.PrioritisedTask)update); ++ } ++ ++ public DelayedPrioritisedTask(final PrioritisedExecutor.Priority priority) { ++ this.setPriorityPlain(priority.priority); ++ } ++ ++ // only public for debugging ++ public int getPriorityInternal() { ++ return this.getPriorityVolatile(); ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask getTask() { ++ return this.getTaskVolatile(); ++ } ++ ++ public void setTask(final PrioritisedExecutor.PrioritisedTask task) { ++ int priority = this.getPriorityVolatile(); ++ ++ if (this.compareAndExchangeTaskVolatile(null, task) != null) { ++ throw new IllegalStateException("setTask() called twice"); ++ } ++ ++ int failures = 0; ++ for (;;) { ++ task.setPriority(PrioritisedExecutor.Priority.getPriority(priority)); ++ ++ if (priority == (priority = this.compareAndExchangePriorityVolatile(priority, priority | PRIORITY_SET))) { ++ return; ++ } ++ ++ ++failures; ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ } ++ } ++ ++ public PrioritisedExecutor.Priority getPriority() { ++ final int priority = this.getPriorityVolatile(); ++ if ((priority & PRIORITY_SET) != 0) { ++ return this.task.getPriority(); ++ } ++ ++ return PrioritisedExecutor.Priority.getPriority(priority); ++ } ++ ++ public void raisePriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ int failures = 0; ++ for (int curr = this.getPriorityVolatile();;) { ++ if ((curr & PRIORITY_SET) != 0) { ++ this.getTaskPlain().raisePriority(priority); ++ return; ++ } ++ ++ if (!priority.isLowerPriority(curr)) { ++ return; ++ } ++ ++ if (curr == (curr = this.compareAndExchangePriorityVolatile(curr, priority.priority))) { ++ return; ++ } ++ ++ // failed, retry ++ ++ ++failures; ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ } ++ } ++ ++ public void setPriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ int failures = 0; ++ for (int curr = this.getPriorityVolatile();;) { ++ if ((curr & PRIORITY_SET) != 0) { ++ this.getTaskPlain().setPriority(priority); ++ return; ++ } ++ ++ if (curr == (curr = this.compareAndExchangePriorityVolatile(curr, priority.priority))) { ++ return; ++ } ++ ++ // failed, retry ++ ++ ++failures; ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ } ++ } ++ ++ public void lowerPriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ int failures = 0; ++ for (int curr = this.getPriorityVolatile();;) { ++ if ((curr & PRIORITY_SET) != 0) { ++ this.getTaskPlain().lowerPriority(priority); ++ return; ++ } ++ ++ if (!priority.isHigherPriority(curr)) { ++ return; ++ } ++ ++ if (curr == (curr = this.compareAndExchangePriorityVolatile(curr, priority.priority))) { ++ return; ++ } ++ ++ // failed, retry ++ ++ ++failures; ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedExecutor.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedExecutor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e5d8ff730ba9d83efc2d80782de313a718bf55b3 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedExecutor.java +@@ -0,0 +1,246 @@ ++package ca.spottedleaf.concurrentutil.executor.standard; ++ ++import ca.spottedleaf.concurrentutil.executor.BaseExecutor; ++ ++public interface PrioritisedExecutor extends BaseExecutor { ++ ++ public static enum Priority { ++ ++ /** ++ * Priority value indicating the task has completed or is being completed. ++ * This priority cannot be used to schedule tasks. ++ */ ++ COMPLETING(-1), ++ ++ /** ++ * Absolute highest priority, should only be used for when a task is blocking a time-critical thread. ++ */ ++ BLOCKING(), ++ ++ /** ++ * Should only be used for urgent but not time-critical tasks. ++ */ ++ HIGHEST(), ++ ++ /** ++ * Two priorities above normal. ++ */ ++ HIGHER(), ++ ++ /** ++ * One priority above normal. ++ */ ++ HIGH(), ++ ++ /** ++ * Default priority. ++ */ ++ NORMAL(), ++ ++ /** ++ * One priority below normal. ++ */ ++ LOW(), ++ ++ /** ++ * Two priorities below normal. ++ */ ++ LOWER(), ++ ++ /** ++ * Use for tasks that should eventually execute, but are not needed to. ++ */ ++ LOWEST(), ++ ++ /** ++ * Use for tasks that can be delayed indefinitely. ++ */ ++ IDLE(); ++ ++ // returns whether the priority can be scheduled ++ public static boolean isValidPriority(final Priority priority) { ++ return priority != null && priority != Priority.COMPLETING; ++ } ++ ++ // returns the higher priority of the two ++ public static PrioritisedExecutor.Priority max(final Priority p1, final Priority p2) { ++ return p1.isHigherOrEqualPriority(p2) ? p1 : p2; ++ } ++ ++ // returns the lower priroity of the two ++ public static PrioritisedExecutor.Priority min(final Priority p1, final Priority p2) { ++ return p1.isLowerOrEqualPriority(p2) ? p1 : p2; ++ } ++ ++ public boolean isHigherOrEqualPriority(final Priority than) { ++ return this.priority <= than.priority; ++ } ++ ++ public boolean isHigherPriority(final Priority than) { ++ return this.priority < than.priority; ++ } ++ ++ public boolean isLowerOrEqualPriority(final Priority than) { ++ return this.priority >= than.priority; ++ } ++ ++ public boolean isLowerPriority(final Priority than) { ++ return this.priority > than.priority; ++ } ++ ++ public boolean isHigherOrEqualPriority(final int than) { ++ return this.priority <= than; ++ } ++ ++ public boolean isHigherPriority(final int than) { ++ return this.priority < than; ++ } ++ ++ public boolean isLowerOrEqualPriority(final int than) { ++ return this.priority >= than; ++ } ++ ++ public boolean isLowerPriority(final int than) { ++ return this.priority > than; ++ } ++ ++ public static boolean isHigherOrEqualPriority(final int priority, final int than) { ++ return priority <= than; ++ } ++ ++ public static boolean isHigherPriority(final int priority, final int than) { ++ return priority < than; ++ } ++ ++ public static boolean isLowerOrEqualPriority(final int priority, final int than) { ++ return priority >= than; ++ } ++ ++ public static boolean isLowerPriority(final int priority, final int than) { ++ return priority > than; ++ } ++ ++ static final PrioritisedExecutor.Priority[] PRIORITIES = PrioritisedExecutor.Priority.values(); ++ ++ /** includes special priorities */ ++ public static final int TOTAL_PRIORITIES = PRIORITIES.length; ++ ++ public static final int TOTAL_SCHEDULABLE_PRIORITIES = TOTAL_PRIORITIES - 1; ++ ++ public static PrioritisedExecutor.Priority getPriority(final int priority) { ++ return PRIORITIES[priority + 1]; ++ } ++ ++ private static int priorityCounter; ++ ++ private static int nextCounter() { ++ return priorityCounter++; ++ } ++ ++ public final int priority; ++ ++ Priority() { ++ this(nextCounter()); ++ } ++ ++ Priority(final int priority) { ++ this.priority = priority; ++ } ++ } ++ ++ /** ++ * Queues or executes a task at {@link Priority#NORMAL} priority. ++ * @param task The task to run. ++ * ++ * @throws IllegalStateException If this queue has shutdown. ++ * @throws NullPointerException If the task is null ++ * @return {@code null} if the current thread immediately executed the task, else returns the prioritised task ++ * associated with the parameter ++ */ ++ public default PrioritisedTask queueRunnable(final Runnable task) { ++ return this.queueRunnable(task, PrioritisedExecutor.Priority.NORMAL); ++ } ++ ++ /** ++ * Queues or executes a task. ++ * ++ * @param task The task to run. ++ * @param priority The priority for the task. ++ * ++ * @throws IllegalStateException If this queue has shutdown. ++ * @throws NullPointerException If the task is null ++ * @throws IllegalArgumentException If the priority is invalid. ++ * @return {@code null} if the current thread immediately executed the task, else returns the prioritised task ++ * associated with the parameter ++ */ ++ public PrioritisedTask queueRunnable(final Runnable task, final PrioritisedExecutor.Priority priority); ++ ++ /** ++ * Creates, but does not execute or queue the task. The task must later be queued via {@link BaseExecutor.BaseTask#queue()}. ++ * ++ * @param task The task to run. ++ * ++ * @throws IllegalStateException If this queue has shutdown. ++ * @throws NullPointerException If the task is null ++ * @throws IllegalArgumentException If the priority is invalid. ++ * @throws UnsupportedOperationException If this executor does not support lazily queueing tasks ++ * @return The prioritised task associated with the parameters ++ */ ++ public default PrioritisedExecutor.PrioritisedTask createTask(final Runnable task) { ++ return this.createTask(task, PrioritisedExecutor.Priority.NORMAL); ++ } ++ ++ /** ++ * Creates, but does not execute or queue the task. The task must later be queued via {@link BaseExecutor.BaseTask#queue()}. ++ * ++ * @param task The task to run. ++ * @param priority The priority for the task. ++ * ++ * @throws IllegalStateException If this queue has shutdown. ++ * @throws NullPointerException If the task is null ++ * @throws IllegalArgumentException If the priority is invalid. ++ * @throws UnsupportedOperationException If this executor does not support lazily queueing tasks ++ * @return The prioritised task associated with the parameters ++ */ ++ public PrioritisedExecutor.PrioritisedTask createTask(final Runnable task, final PrioritisedExecutor.Priority priority); ++ ++ public static interface PrioritisedTask extends BaseTask { ++ ++ /** ++ * Returns the current priority. Note that {@link PrioritisedExecutor.Priority#COMPLETING} will be returned ++ * if this task is completing or has completed. ++ */ ++ public PrioritisedExecutor.Priority getPriority(); ++ ++ /** ++ * Attempts to set this task's priority level to the level specified. ++ * ++ * @param priority Specified priority level. ++ * ++ * @throws IllegalArgumentException If the priority is invalid ++ * @return {@code true} if successful, {@code false} if this task is completing or has completed or the queue ++ * this task was scheduled on was shutdown, or if the priority was already at the specified level. ++ */ ++ public boolean setPriority(final PrioritisedExecutor.Priority priority); ++ ++ /** ++ * Attempts to raise the priority to the priority level specified. ++ * ++ * @param priority Priority specified ++ * ++ * @throws IllegalArgumentException If the priority is invalid ++ * @return {@code false} if the current task is completing, {@code true} if the priority was raised to the specified level or was already at the specified level or higher. ++ */ ++ public boolean raisePriority(final PrioritisedExecutor.Priority priority); ++ ++ /** ++ * Attempts to lower the priority to the priority level specified. ++ * ++ * @param priority Priority specified ++ * ++ * @throws IllegalArgumentException If the priority is invalid ++ * @return {@code false} if the current task is completing, {@code true} if the priority was lowered to the specified level or was already at the specified level or lower. ++ */ ++ public boolean lowerPriority(final PrioritisedExecutor.Priority priority); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedQueueExecutorThread.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedQueueExecutorThread.java +new file mode 100644 +index 0000000000000000000000000000000000000000..91fe0f7049122f62f05ba09c24cba5d758340cff +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedQueueExecutorThread.java +@@ -0,0 +1,297 @@ ++package ca.spottedleaf.concurrentutil.executor.standard; ++ ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import com.mojang.logging.LogUtils; ++import org.slf4j.Logger; ++import java.lang.invoke.VarHandle; ++import java.util.concurrent.locks.LockSupport; ++ ++/** ++ * Thread which will continuously drain from a specified queue. ++ *

++ * Note: When using this thread, queue additions to the underlying {@link #queue} are not sufficient to get this thread ++ * to execute the task. The function {@link #notifyTasks()} must be used after scheduling a task. For expected behaviour ++ * of task scheduling (thread wakes up after tasks are scheduled), use the methods provided on {@link PrioritisedExecutor} ++ * methods. ++ *

++ */ ++public class PrioritisedQueueExecutorThread extends Thread implements PrioritisedExecutor { ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ ++ protected final PrioritisedExecutor queue; ++ ++ protected volatile boolean threadShutdown; ++ ++ protected static final VarHandle THREAD_PARKED_HANDLE = ConcurrentUtil.getVarHandle(PrioritisedQueueExecutorThread.class, "threadParked", boolean.class); ++ protected volatile boolean threadParked; ++ ++ protected volatile boolean halted; ++ ++ protected final long spinWaitTime; ++ ++ static final long DEFAULT_SPINWAIT_TIME = (long)(0.1e6);// 0.1ms ++ ++ public PrioritisedQueueExecutorThread(final PrioritisedExecutor queue) { ++ this(queue, DEFAULT_SPINWAIT_TIME); // 0.1ms ++ } ++ ++ public PrioritisedQueueExecutorThread(final PrioritisedExecutor queue, final long spinWaitTime) { // in ns ++ this.queue = queue; ++ this.spinWaitTime = spinWaitTime; ++ } ++ ++ @Override ++ public void run() { ++ final long spinWaitTime = this.spinWaitTime; ++ ++ main_loop: ++ for (;;) { ++ this.pollTasks(); ++ ++ // spinwait ++ ++ final long start = System.nanoTime(); ++ ++ for (;;) { ++ // If we are interrupted for any reason, park() will always return immediately. Clear so that we don't needlessly use cpu in such an event. ++ Thread.interrupted(); ++ Thread.yield(); ++ LockSupport.parkNanos("Spinwaiting on tasks", 10_000L); // 10us ++ ++ if (this.pollTasks()) { ++ // restart loop, found tasks ++ continue main_loop; ++ } ++ ++ if (this.handleClose()) { ++ return; // we're done ++ } ++ ++ if ((System.nanoTime() - start) >= spinWaitTime) { ++ break; ++ } ++ } ++ ++ if (this.handleClose()) { ++ return; ++ } ++ ++ this.setThreadParkedVolatile(true); ++ ++ // We need to parse here to avoid a race condition where a thread queues a task before we set parked to true ++ // (i.e it will not notify us) ++ if (this.pollTasks()) { ++ this.setThreadParkedVolatile(false); ++ continue; ++ } ++ ++ if (this.handleClose()) { ++ return; ++ } ++ ++ // we don't need to check parked before sleeping, but we do need to check parked in a do-while loop ++ // LockSupport.park() can fail for any reason ++ while (this.getThreadParkedVolatile()) { ++ Thread.interrupted(); ++ LockSupport.park("Waiting on tasks"); ++ } ++ } ++ } ++ ++ protected boolean pollTasks() { ++ boolean ret = false; ++ ++ for (;;) { ++ if (this.halted) { ++ break; ++ } ++ try { ++ if (!this.queue.executeTask()) { ++ break; ++ } ++ ret = true; ++ } catch (final ThreadDeath death) { ++ throw death; // goodbye world... ++ } catch (final Throwable throwable) { ++ LOGGER.error("Exception thrown from prioritized runnable task in thread '" + this.getName() + "'", throwable); ++ } ++ } ++ ++ return ret; ++ } ++ ++ protected boolean handleClose() { ++ if (this.threadShutdown) { ++ this.pollTasks(); // this ensures we've emptied the queue ++ return true; ++ } ++ return false; ++ } ++ ++ /** ++ * Notify this thread that a task has been added to its queue ++ * @return {@code true} if this thread was waiting for tasks, {@code false} if it is executing tasks ++ */ ++ public boolean notifyTasks() { ++ if (this.getThreadParkedVolatile() && this.exchangeThreadParkedVolatile(false)) { ++ LockSupport.unpark(this); ++ return true; ++ } ++ return false; ++ } ++ ++ @Override ++ public PrioritisedTask createTask(final Runnable task, final Priority priority) { ++ final PrioritisedExecutor.PrioritisedTask queueTask = this.queue.createTask(task, priority); ++ ++ // need to override queue() to notify us of tasks ++ return new PrioritisedTask() { ++ @Override ++ public Priority getPriority() { ++ return queueTask.getPriority(); ++ } ++ ++ @Override ++ public boolean setPriority(final Priority priority) { ++ return queueTask.setPriority(priority); ++ } ++ ++ @Override ++ public boolean raisePriority(final Priority priority) { ++ return queueTask.raisePriority(priority); ++ } ++ ++ @Override ++ public boolean lowerPriority(final Priority priority) { ++ return queueTask.lowerPriority(priority); ++ } ++ ++ @Override ++ public boolean queue() { ++ final boolean ret = queueTask.queue(); ++ if (ret) { ++ PrioritisedQueueExecutorThread.this.notifyTasks(); ++ } ++ return ret; ++ } ++ ++ @Override ++ public boolean cancel() { ++ return queueTask.cancel(); ++ } ++ ++ @Override ++ public boolean execute() { ++ return queueTask.execute(); ++ } ++ }; ++ } ++ ++ @Override ++ public PrioritisedExecutor.PrioritisedTask queueRunnable(final Runnable task, final PrioritisedExecutor.Priority priority) { ++ final PrioritisedExecutor.PrioritisedTask ret = this.queue.queueRunnable(task, priority); ++ ++ this.notifyTasks(); ++ ++ return ret; ++ } ++ ++ @Override ++ public boolean haveAllTasksExecuted() { ++ return this.queue.haveAllTasksExecuted(); ++ } ++ ++ @Override ++ public long getTotalTasksExecuted() { ++ return this.queue.getTotalTasksExecuted(); ++ } ++ ++ @Override ++ public long getTotalTasksScheduled() { ++ return this.queue.getTotalTasksScheduled(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ * @throws IllegalStateException If the current thread is {@code this} thread, or the underlying queue throws this exception. ++ */ ++ @Override ++ public void waitUntilAllExecuted() throws IllegalStateException { ++ if (Thread.currentThread() == this) { ++ throw new IllegalStateException("Cannot block on our own queue"); ++ } ++ this.queue.waitUntilAllExecuted(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ * @throws IllegalStateException Always ++ */ ++ @Override ++ public boolean executeTask() throws IllegalStateException { ++ throw new IllegalStateException(); ++ } ++ ++ /** ++ * Closes this queue executor's queue. Optionally waits for all tasks in queue to be executed if {@code wait} is true. ++ *

++ * This function is MT-Safe. ++ *

++ * @param wait If this call is to wait until the queue is empty and there are no tasks executing in the queue. ++ * @param killQueue Whether to shutdown this thread's queue ++ * @return whether this thread shut down the queue ++ * @see #halt(boolean) ++ */ ++ public boolean close(final boolean wait, final boolean killQueue) { ++ final boolean ret = killQueue && this.queue.shutdown(); ++ this.threadShutdown = true; ++ ++ // force thread to respond to the shutdown ++ this.setThreadParkedVolatile(false); ++ LockSupport.unpark(this); ++ ++ if (wait) { ++ this.waitUntilAllExecuted(); ++ } ++ ++ return ret; ++ } ++ ++ ++ /** ++ * Causes this thread to exit without draining the queue. To ensure tasks are completed, use {@link #close(boolean, boolean)}. ++ *

++ * This is not safe to call with {@link #close(boolean, boolean)} if wait = true, in which case ++ * the waiting thread may block indefinitely. ++ *

++ *

++ * This function is MT-Safe. ++ *

++ * @param killQueue Whether to shutdown this thread's queue ++ * @see #close(boolean, boolean) ++ */ ++ public void halt(final boolean killQueue) { ++ if (killQueue) { ++ this.queue.shutdown(); ++ } ++ this.threadShutdown = true; ++ this.halted = true; ++ ++ // force thread to respond to the shutdown ++ this.setThreadParkedVolatile(false); ++ LockSupport.unpark(this); ++ } ++ ++ protected final boolean getThreadParkedVolatile() { ++ return (boolean)THREAD_PARKED_HANDLE.getVolatile(this); ++ } ++ ++ protected final boolean exchangeThreadParkedVolatile(final boolean value) { ++ return (boolean)THREAD_PARKED_HANDLE.getAndSet(this, value); ++ } ++ ++ protected final void setThreadParkedVolatile(final boolean value) { ++ THREAD_PARKED_HANDLE.setVolatile(this, value); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadPool.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadPool.java +new file mode 100644 +index 0000000000000000000000000000000000000000..26fa2caa18a9194e57574a4a7fa9f7a4265740e0 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadPool.java +@@ -0,0 +1,579 @@ ++package ca.spottedleaf.concurrentutil.executor.standard; ++ ++import com.mojang.logging.LogUtils; ++import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; ++import org.slf4j.Logger; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.Comparator; ++import java.util.TreeSet; ++import java.util.concurrent.atomic.AtomicBoolean; ++import java.util.function.BiConsumer; ++ ++public final class PrioritisedThreadPool { ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ ++ protected final PrioritisedThread[] threads; ++ protected final TreeSet queues = new TreeSet<>(PrioritisedPoolExecutorImpl.comparator()); ++ protected final String name; ++ protected final long queueMaxHoldTime; ++ ++ protected final ReferenceOpenHashSet nonShutdownQueues = new ReferenceOpenHashSet<>(); ++ protected final ReferenceOpenHashSet activeQueues = new ReferenceOpenHashSet<>(); ++ ++ protected boolean shutdown; ++ ++ protected long schedulingIdGenerator; ++ ++ protected static final long DEFAULT_QUEUE_HOLD_TIME = (long)(5.0e6); ++ ++ public PrioritisedThreadPool(final String name, final int threads) { ++ this(name, threads, null); ++ } ++ ++ public PrioritisedThreadPool(final String name, final int threads, final BiConsumer threadModifier) { ++ this(name, threads, threadModifier, DEFAULT_QUEUE_HOLD_TIME); // 5ms ++ } ++ ++ public PrioritisedThreadPool(final String name, final int threads, final BiConsumer threadModifier, ++ final long queueHoldTime) { // in ns ++ if (threads <= 0) { ++ throw new IllegalArgumentException("Thread count must be > 0, not " + threads); ++ } ++ if (name == null) { ++ throw new IllegalArgumentException("Name cannot be null"); ++ } ++ this.name = name; ++ this.queueMaxHoldTime = queueHoldTime; ++ ++ this.threads = new PrioritisedThread[threads]; ++ for (int i = 0; i < threads; ++i) { ++ this.threads[i] = new PrioritisedThread(this); ++ ++ // set default attributes ++ this.threads[i].setName("Prioritised thread for pool '" + name + "' #" + i); ++ this.threads[i].setUncaughtExceptionHandler((final Thread thread, final Throwable throwable) -> { ++ LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); ++ }); ++ ++ // let thread modifier override defaults ++ if (threadModifier != null) { ++ threadModifier.accept(this.threads[i], Integer.valueOf(i)); ++ } ++ ++ // now the thread can start ++ this.threads[i].start(); ++ } ++ } ++ ++ public Thread[] getThreads() { ++ return Arrays.copyOf(this.threads, this.threads.length, Thread[].class); ++ } ++ ++ public PrioritisedPoolExecutor createExecutor(final String name, final int parallelism) { ++ synchronized (this.nonShutdownQueues) { ++ if (this.shutdown) { ++ throw new IllegalStateException("Queue is shutdown: " + this.toString()); ++ } ++ final PrioritisedPoolExecutorImpl ret = new PrioritisedPoolExecutorImpl(this, name, Math.min(Math.max(1, parallelism), this.threads.length)); ++ ++ this.nonShutdownQueues.add(ret); ++ ++ synchronized (this.activeQueues) { ++ this.activeQueues.add(ret); ++ } ++ ++ return ret; ++ } ++ } ++ ++ /** ++ * Prevents creation of new queues, shutdowns all non-shutdown queues if specified ++ */ ++ public void halt(final boolean shutdownQueues) { ++ synchronized (this.nonShutdownQueues) { ++ this.shutdown = true; ++ } ++ if (shutdownQueues) { ++ final ArrayList queuesToShutdown; ++ synchronized (this.nonShutdownQueues) { ++ this.shutdown = true; ++ queuesToShutdown = new ArrayList<>(this.nonShutdownQueues); ++ } ++ ++ for (final PrioritisedPoolExecutorImpl queue : queuesToShutdown) { ++ queue.shutdown(); ++ } ++ } ++ ++ ++ for (final PrioritisedThread thread : this.threads) { ++ // can't kill queue, queue is null ++ thread.halt(false); ++ } ++ } ++ ++ /** ++ * Waits until all threads in this pool have shutdown, or until the specified time has passed. ++ * @param msToWait Maximum time to wait. ++ * @return {@code false} if the maximum time passed, {@code true} otherwise. ++ */ ++ public boolean join(final long msToWait) { ++ try { ++ return this.join(msToWait, false); ++ } catch (final InterruptedException ex) { ++ throw new IllegalStateException(ex); ++ } ++ } ++ ++ /** ++ * Waits until all threads in this pool have shutdown, or until the specified time has passed. ++ * @param msToWait Maximum time to wait. ++ * @return {@code false} if the maximum time passed, {@code true} otherwise. ++ * @throws InterruptedException If this thread is interrupted. ++ */ ++ public boolean joinInterruptable(final long msToWait) throws InterruptedException { ++ return this.join(msToWait, true); ++ } ++ ++ protected final boolean join(final long msToWait, final boolean interruptable) throws InterruptedException { ++ final long nsToWait = msToWait * (1000 * 1000); ++ final long start = System.nanoTime(); ++ final long deadline = start + nsToWait; ++ boolean interrupted = false; ++ try { ++ for (final PrioritisedThread thread : this.threads) { ++ for (;;) { ++ if (!thread.isAlive()) { ++ break; ++ } ++ final long current = System.nanoTime(); ++ if (current >= deadline) { ++ return false; ++ } ++ ++ try { ++ thread.join(Math.max(1L, (deadline - current) / (1000 * 1000))); ++ } catch (final InterruptedException ex) { ++ if (interruptable) { ++ throw ex; ++ } ++ interrupted = true; ++ } ++ } ++ } ++ ++ return true; ++ } finally { ++ if (interrupted) { ++ Thread.currentThread().interrupt(); ++ } ++ } ++ } ++ ++ public void shutdown(final boolean wait) { ++ final ArrayList queuesToShutdown; ++ synchronized (this.nonShutdownQueues) { ++ this.shutdown = true; ++ queuesToShutdown = new ArrayList<>(this.nonShutdownQueues); ++ } ++ ++ for (final PrioritisedPoolExecutorImpl queue : queuesToShutdown) { ++ queue.shutdown(); ++ } ++ ++ for (final PrioritisedThread thread : this.threads) { ++ // none of these can be true or else NPE ++ thread.close(false, false); ++ } ++ ++ if (wait) { ++ final ArrayList queues; ++ synchronized (this.activeQueues) { ++ queues = new ArrayList<>(this.activeQueues); ++ } ++ for (final PrioritisedPoolExecutorImpl queue : queues) { ++ queue.waitUntilAllExecuted(); ++ } ++ } ++ } ++ ++ protected static final class PrioritisedThread extends PrioritisedQueueExecutorThread { ++ ++ protected final PrioritisedThreadPool pool; ++ protected final AtomicBoolean alertedHighPriority = new AtomicBoolean(); ++ ++ public PrioritisedThread(final PrioritisedThreadPool pool) { ++ super(null); ++ this.pool = pool; ++ } ++ ++ public boolean alertHighPriorityExecutor() { ++ if (!this.notifyTasks()) { ++ if (!this.alertedHighPriority.get()) { ++ this.alertedHighPriority.set(true); ++ } ++ return false; ++ } ++ ++ return true; ++ } ++ ++ private boolean isAlertedHighPriority() { ++ return this.alertedHighPriority.get() && this.alertedHighPriority.getAndSet(false); ++ } ++ ++ @Override ++ protected boolean pollTasks() { ++ final PrioritisedThreadPool pool = this.pool; ++ final TreeSet queues = this.pool.queues; ++ ++ boolean ret = false; ++ for (;;) { ++ if (this.halted) { ++ break; ++ } ++ // try to find a queue ++ // note that if and ONLY IF the queues set is empty, this means there are no tasks for us to execute. ++ // so we can only break when it's empty ++ final PrioritisedPoolExecutorImpl queue; ++ // select queue ++ synchronized (queues) { ++ queue = queues.pollFirst(); ++ if (queue == null) { ++ // no tasks to execute ++ break; ++ } ++ ++ queue.schedulingId = ++pool.schedulingIdGenerator; ++ // we own this queue now, so increment the executor count ++ // do we also need to push this queue up for grabs for another executor? ++ if (++queue.concurrentExecutors < queue.maximumExecutors) { ++ // re-add to queues ++ // it's very important this is done in the same synchronised block for polling, as this prevents ++ // us from possibly later adding a queue that should not exist in the set ++ queues.add(queue); ++ queue.isQueued = true; ++ } else { ++ queue.isQueued = false; ++ } ++ // note: we cannot drain entries from the queue while holding this lock, as it will cause deadlock ++ // the queue addition holds the per-queue lock first then acquires the lock we have now, but if we ++ // try to poll now we don't hold the per queue lock but we do hold the global lock... ++ } ++ ++ // parse tasks as long as we are allowed ++ final long start = System.nanoTime(); ++ final long deadline = start + pool.queueMaxHoldTime; ++ do { ++ try { ++ if (this.halted) { ++ break; ++ } ++ if (!queue.executeTask()) { ++ // no more tasks, try next queue ++ break; ++ } ++ ret = true; ++ } catch (final ThreadDeath death) { ++ throw death; // goodbye world... ++ } catch (final Throwable throwable) { ++ LOGGER.error("Exception thrown from thread '" + this.getName() + "' in queue '" + queue.toString() + "'", throwable); ++ } ++ } while (!this.isAlertedHighPriority() && System.nanoTime() <= deadline); ++ ++ synchronized (queues) { ++ // decrement executors, we are no longer executing ++ if (queue.isQueued) { ++ queues.remove(queue); ++ queue.isQueued = false; ++ } ++ if (--queue.concurrentExecutors == 0 && queue.scheduledPriority == null) { ++ // reset scheduling id once the queue is empty again ++ // this will ensure empty queues are not prioritised suddenly over active queues once tasks are ++ // queued ++ queue.schedulingId = 0L; ++ } ++ ++ // ensure the executor is queued for execution again ++ if (!queue.isHalted && queue.scheduledPriority != null) { // make sure it actually has tasks ++ queues.add(queue); ++ queue.isQueued = true; ++ } ++ } ++ } ++ ++ return ret; ++ } ++ } ++ ++ public interface PrioritisedPoolExecutor extends PrioritisedExecutor { ++ ++ /** ++ * Removes this queue from the thread pool without shutting the queue down or waiting for queued tasks to be executed ++ */ ++ public void halt(); ++ ++ /** ++ * Returns whether this executor is scheduled to run tasks or is running tasks, otherwise it returns whether ++ * this queue is not halted and not shutdown. ++ */ ++ public boolean isActive(); ++ } ++ ++ protected static final class PrioritisedPoolExecutorImpl extends PrioritisedThreadedTaskQueue implements PrioritisedPoolExecutor { ++ ++ protected final PrioritisedThreadPool pool; ++ protected final long[] priorityCounts = new long[Priority.TOTAL_SCHEDULABLE_PRIORITIES]; ++ protected long schedulingId; ++ protected int concurrentExecutors; ++ protected Priority scheduledPriority; ++ ++ protected final String name; ++ protected final int maximumExecutors; ++ protected boolean isQueued; ++ ++ public PrioritisedPoolExecutorImpl(final PrioritisedThreadPool pool, final String name, final int maximumExecutors) { ++ this.pool = pool; ++ this.name = name; ++ this.maximumExecutors = maximumExecutors; ++ } ++ ++ public static Comparator comparator() { ++ return (final PrioritisedPoolExecutorImpl p1, final PrioritisedPoolExecutorImpl p2) -> { ++ if (p1 == p2) { ++ return 0; ++ } ++ ++ // prefer higher priority ++ final int priorityCompare = p1.scheduledPriority.ordinal() - p2.scheduledPriority.ordinal(); ++ if (priorityCompare != 0) { ++ return priorityCompare; ++ } ++ ++ // try to spread out the executors so that each can have threads executing ++ final int executorCompare = p1.concurrentExecutors - p2.concurrentExecutors; ++ if (executorCompare != 0) { ++ return executorCompare; ++ } ++ ++ // if all else fails here we just choose whichever executor was queued first ++ return Long.compare(p1.schedulingId, p2.schedulingId); ++ }; ++ } ++ ++ private boolean isHalted; ++ ++ @Override ++ public void halt() { ++ final PrioritisedThreadPool pool = this.pool; ++ final TreeSet queues = pool.queues; ++ synchronized (queues) { ++ if (this.isHalted) { ++ return; ++ } ++ this.isHalted = true; ++ if (this.isQueued) { ++ queues.remove(this); ++ this.isQueued = false; ++ } ++ } ++ synchronized (pool.nonShutdownQueues) { ++ pool.nonShutdownQueues.remove(this); ++ } ++ synchronized (pool.activeQueues) { ++ pool.activeQueues.remove(this); ++ } ++ } ++ ++ @Override ++ public boolean isActive() { ++ final PrioritisedThreadPool pool = this.pool; ++ final TreeSet queues = pool.queues; ++ ++ synchronized (queues) { ++ if (this.concurrentExecutors != 0) { ++ return true; ++ } ++ synchronized (pool.activeQueues) { ++ if (pool.activeQueues.contains(this)) { ++ return true; ++ } ++ } ++ } ++ ++ return false; ++ } ++ ++ private long totalQueuedTasks = 0L; ++ ++ @Override ++ protected void priorityChange(final PrioritisedThreadedTaskQueue.PrioritisedTask task, final Priority from, final Priority to) { ++ // Note: The superclass' queue lock is ALWAYS held when inside this method. So we do NOT need to do any additional synchronisation ++ // for accessing this queue's state. ++ final long[] priorityCounts = this.priorityCounts; ++ final boolean shutdown = this.isShutdown(); ++ ++ if (from == null && to == Priority.COMPLETING) { ++ throw new IllegalStateException("Cannot complete task without queueing it first"); ++ } ++ ++ // we should only notify for queueing of tasks, not changing priorities ++ final boolean shouldNotifyTasks = from == null; ++ ++ final Priority scheduledPriority = this.scheduledPriority; ++ if (from != null) { ++ --priorityCounts[from.priority]; ++ } ++ if (to != Priority.COMPLETING) { ++ ++priorityCounts[to.priority]; ++ } ++ final long totalQueuedTasks; ++ if (to == Priority.COMPLETING) { ++ totalQueuedTasks = --this.totalQueuedTasks; ++ } else if (from == null) { ++ totalQueuedTasks = ++this.totalQueuedTasks; ++ } else { ++ totalQueuedTasks = this.totalQueuedTasks; ++ } ++ ++ // find new highest priority ++ int highest = Math.min(to == Priority.COMPLETING ? Priority.IDLE.priority : to.priority, scheduledPriority == null ? Priority.IDLE.priority : scheduledPriority.priority); ++ int lowestPriority = priorityCounts.length; // exclusive ++ for (;highest < lowestPriority; ++highest) { ++ final long count = priorityCounts[highest]; ++ if (count < 0) { ++ throw new IllegalStateException("Priority " + highest + " has " + count + " scheduled tasks"); ++ } ++ ++ if (count != 0) { ++ break; ++ } ++ } ++ ++ final Priority newPriority; ++ if (highest == lowestPriority) { ++ // no tasks left ++ newPriority = null; ++ } else if (shutdown) { ++ // whichever is lower, the actual greatest priority or simply HIGHEST ++ // this is so shutdown automatically gets priority ++ newPriority = Priority.getPriority(Math.min(highest, Priority.HIGHEST.priority)); ++ } else { ++ newPriority = Priority.getPriority(highest); ++ } ++ ++ final int executorsWanted; ++ boolean shouldNotifyHighPriority = false; ++ ++ final PrioritisedThreadPool pool = this.pool; ++ final TreeSet queues = pool.queues; ++ ++ synchronized (queues) { ++ if (!this.isQueued) { ++ // see if we need to be queued ++ if (newPriority != null) { ++ if (this.schedulingId == 0L) { ++ this.schedulingId = ++pool.schedulingIdGenerator; ++ } ++ this.scheduledPriority = newPriority; // must be updated before queue add ++ if (!this.isHalted && this.concurrentExecutors < this.maximumExecutors) { ++ shouldNotifyHighPriority = newPriority.isHigherOrEqualPriority(Priority.HIGH); ++ queues.add(this); ++ this.isQueued = true; ++ } ++ } else { ++ // do not queue ++ this.scheduledPriority = null; ++ } ++ } else { ++ // see if we need to NOT be queued ++ if (newPriority == null) { ++ queues.remove(this); ++ this.scheduledPriority = null; ++ this.isQueued = false; ++ } else if (scheduledPriority != newPriority) { ++ // if our priority changed, we need to update it - which means removing and re-adding into the queue ++ queues.remove(this); ++ // only now can we update scheduledPriority, since we are no longer in queue ++ this.scheduledPriority = newPriority; ++ queues.add(this); ++ shouldNotifyHighPriority = (scheduledPriority == null || scheduledPriority.isLowerPriority(Priority.HIGH)) && newPriority.isHigherOrEqualPriority(Priority.HIGH); ++ } ++ } ++ ++ if (this.isQueued) { ++ executorsWanted = Math.min(this.maximumExecutors - this.concurrentExecutors, (int)totalQueuedTasks); ++ } else { ++ executorsWanted = 0; ++ } ++ } ++ ++ if (newPriority == null && shutdown) { ++ synchronized (pool.activeQueues) { ++ pool.activeQueues.remove(this); ++ } ++ } ++ ++ // Wake up the number of executors we want ++ if (executorsWanted > 0 || (shouldNotifyTasks | shouldNotifyHighPriority)) { ++ int notified = 0; ++ for (final PrioritisedThread thread : pool.threads) { ++ if ((shouldNotifyHighPriority ? thread.alertHighPriorityExecutor() : thread.notifyTasks()) ++ && (++notified >= executorsWanted)) { ++ break; ++ } ++ } ++ } ++ } ++ ++ @Override ++ public boolean shutdown() { ++ final boolean ret = super.shutdown(); ++ if (!ret) { ++ return ret; ++ } ++ ++ final PrioritisedThreadPool pool = this.pool; ++ ++ // remove from active queues ++ synchronized (pool.nonShutdownQueues) { ++ pool.nonShutdownQueues.remove(this); ++ } ++ ++ final TreeSet queues = pool.queues; ++ ++ // try and shift around our priority ++ synchronized (queues) { ++ if (this.scheduledPriority == null) { ++ // no tasks are queued, ensure we aren't in activeQueues ++ synchronized (pool.activeQueues) { ++ pool.activeQueues.remove(this); ++ } ++ ++ return ret; ++ } ++ ++ // try to set scheduled priority to HIGHEST so it drains faster ++ ++ if (this.scheduledPriority.isHigherOrEqualPriority(Priority.HIGHEST)) { ++ // already at target priority (highest or above) ++ return ret; ++ } ++ ++ // shift priority to HIGHEST ++ ++ if (this.isQueued) { ++ queues.remove(this); ++ this.scheduledPriority = Priority.HIGHEST; ++ queues.add(this); ++ } else { ++ this.scheduledPriority = Priority.HIGHEST; ++ } ++ } ++ ++ return ret; ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadedTaskQueue.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadedTaskQueue.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b71404be2c82f7db35272b367af861e94d6c73d3 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadedTaskQueue.java +@@ -0,0 +1,378 @@ ++package ca.spottedleaf.concurrentutil.executor.standard; ++ ++import java.util.ArrayDeque; ++import java.util.concurrent.atomic.AtomicLong; ++ ++public class PrioritisedThreadedTaskQueue implements PrioritisedExecutor { ++ ++ protected final ArrayDeque[] queues = new ArrayDeque[Priority.TOTAL_SCHEDULABLE_PRIORITIES]; { ++ for (int i = 0; i < Priority.TOTAL_SCHEDULABLE_PRIORITIES; ++i) { ++ this.queues[i] = new ArrayDeque<>(); ++ } ++ } ++ ++ // Use AtomicLong to separate from the queue field, we don't want false sharing here. ++ protected final AtomicLong totalScheduledTasks = new AtomicLong(); ++ protected final AtomicLong totalCompletedTasks = new AtomicLong(); ++ ++ // this is here to prevent failures to queue stalling flush() calls (as the schedule calls would increment totalScheduledTasks without this check) ++ protected volatile boolean hasShutdown; ++ ++ protected long taskIdGenerator = 0; ++ ++ @Override ++ public PrioritisedExecutor.PrioritisedTask queueRunnable(final Runnable task, final PrioritisedExecutor.Priority priority) throws IllegalStateException, IllegalArgumentException { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Priority " + priority + " is invalid"); ++ } ++ if (task == null) { ++ throw new NullPointerException("Task cannot be null"); ++ } ++ ++ if (this.hasShutdown) { ++ // prevent us from stalling flush() calls by incrementing scheduled tasks when we really didn't schedule something ++ throw new IllegalStateException("Queue has shutdown"); ++ } ++ ++ final PrioritisedTask ret; ++ ++ synchronized (this.queues) { ++ if (this.hasShutdown) { ++ throw new IllegalStateException("Queue has shutdown"); ++ } ++ this.getAndAddTotalScheduledTasksVolatile(1L); ++ ++ ret = new PrioritisedTask(this.taskIdGenerator++, task, priority, this); ++ ++ this.queues[ret.priority.priority].add(ret); ++ ++ // call priority change callback (note: only after we successfully queue!) ++ this.priorityChange(ret, null, priority); ++ } ++ ++ return ret; ++ } ++ ++ @Override ++ public PrioritisedExecutor.PrioritisedTask createTask(final Runnable task, final Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Priority " + priority + " is invalid"); ++ } ++ if (task == null) { ++ throw new NullPointerException("Task cannot be null"); ++ } ++ ++ return new PrioritisedTask(task, priority, this); ++ } ++ ++ @Override ++ public long getTotalTasksScheduled() { ++ return this.totalScheduledTasks.get(); ++ } ++ ++ @Override ++ public long getTotalTasksExecuted() { ++ return this.totalCompletedTasks.get(); ++ } ++ ++ // callback method for subclasses to override ++ // from is null when a task is immediately created ++ protected void priorityChange(final PrioritisedTask task, final Priority from, final Priority to) {} ++ ++ /** ++ * Polls the highest priority task currently available. {@code null} if none. This will mark the ++ * returned task as completed. ++ */ ++ protected PrioritisedTask poll() { ++ return this.poll(Priority.IDLE); ++ } ++ ++ protected PrioritisedTask poll(final PrioritisedExecutor.Priority minPriority) { ++ final ArrayDeque[] queues = this.queues; ++ synchronized (queues) { ++ final int max = minPriority.priority; ++ for (int i = 0; i <= max; ++i) { ++ final ArrayDeque queue = queues[i]; ++ PrioritisedTask task; ++ while ((task = queue.pollFirst()) != null) { ++ if (task.trySetCompleting(i)) { ++ return task; ++ } ++ } ++ } ++ } ++ ++ return null; ++ } ++ ++ /** ++ * Polls and executes the highest priority task currently available. Exceptions thrown during task execution will ++ * be rethrown. ++ * @return {@code true} if a task was executed, {@code false} otherwise. ++ */ ++ @Override ++ public boolean executeTask() { ++ final PrioritisedTask task = this.poll(); ++ ++ if (task != null) { ++ task.executeInternal(); ++ return true; ++ } ++ ++ return false; ++ } ++ ++ @Override ++ public boolean shutdown() { ++ synchronized (this.queues) { ++ if (this.hasShutdown) { ++ return false; ++ } ++ this.hasShutdown = true; ++ } ++ return true; ++ } ++ ++ @Override ++ public boolean isShutdown() { ++ return this.hasShutdown; ++ } ++ ++ /* totalScheduledTasks */ ++ ++ protected final long getTotalScheduledTasksVolatile() { ++ return this.totalScheduledTasks.get(); ++ } ++ ++ protected final long getAndAddTotalScheduledTasksVolatile(final long value) { ++ return this.totalScheduledTasks.getAndAdd(value); ++ } ++ ++ /* totalCompletedTasks */ ++ ++ protected final long getTotalCompletedTasksVolatile() { ++ return this.totalCompletedTasks.get(); ++ } ++ ++ protected final long getAndAddTotalCompletedTasksVolatile(final long value) { ++ return this.totalCompletedTasks.getAndAdd(value); ++ } ++ ++ protected static final class PrioritisedTask implements PrioritisedExecutor.PrioritisedTask { ++ protected final PrioritisedThreadedTaskQueue queue; ++ protected long id; ++ protected static final long NOT_SCHEDULED_ID = -1L; ++ ++ protected Runnable runnable; ++ protected volatile PrioritisedExecutor.Priority priority; ++ ++ protected PrioritisedTask(final long id, final Runnable runnable, final PrioritisedExecutor.Priority priority, final PrioritisedThreadedTaskQueue queue) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ this.priority = priority; ++ this.runnable = runnable; ++ this.queue = queue; ++ this.id = id; ++ } ++ ++ protected PrioritisedTask(final Runnable runnable, final PrioritisedExecutor.Priority priority, final PrioritisedThreadedTaskQueue queue) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ this.priority = priority; ++ this.runnable = runnable; ++ this.queue = queue; ++ this.id = NOT_SCHEDULED_ID; ++ } ++ ++ @Override ++ public boolean queue() { ++ if (this.queue.hasShutdown) { ++ throw new IllegalStateException("Queue has shutdown"); ++ } ++ ++ synchronized (this.queue.queues) { ++ if (this.queue.hasShutdown) { ++ throw new IllegalStateException("Queue has shutdown"); ++ } ++ ++ final PrioritisedExecutor.Priority priority = this.priority; ++ if (priority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ if (this.id != NOT_SCHEDULED_ID) { ++ return false; ++ } ++ ++ this.queue.getAndAddTotalScheduledTasksVolatile(1L); ++ this.id = this.queue.taskIdGenerator++; ++ this.queue.queues[priority.priority].add(this); ++ ++ this.queue.priorityChange(this, null, priority); ++ ++ return true; ++ } ++ } ++ ++ protected boolean trySetCompleting(final int minPriority) { ++ final PrioritisedExecutor.Priority oldPriority = this.priority; ++ if (oldPriority != PrioritisedExecutor.Priority.COMPLETING && oldPriority.isHigherOrEqualPriority(minPriority)) { ++ this.priority = PrioritisedExecutor.Priority.COMPLETING; ++ if (this.id != NOT_SCHEDULED_ID) { ++ this.queue.priorityChange(this, oldPriority, PrioritisedExecutor.Priority.COMPLETING); ++ } ++ return true; ++ } ++ ++ return false; ++ } ++ ++ @Override ++ public PrioritisedExecutor.Priority getPriority() { ++ return this.priority; ++ } ++ ++ @Override ++ public boolean setPriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ synchronized (this.queue.queues) { ++ final PrioritisedExecutor.Priority curr = this.priority; ++ ++ if (curr == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ if (curr == priority) { ++ return true; ++ } ++ ++ this.priority = priority; ++ if (this.id != NOT_SCHEDULED_ID) { ++ this.queue.queues[priority.priority].add(this); ++ ++ // call priority change callback ++ this.queue.priorityChange(this, curr, priority); ++ } ++ } ++ ++ return true; ++ } ++ ++ @Override ++ public boolean raisePriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ synchronized (this.queue.queues) { ++ final PrioritisedExecutor.Priority curr = this.priority; ++ ++ if (curr == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ if (curr.isHigherOrEqualPriority(priority)) { ++ return true; ++ } ++ ++ this.priority = priority; ++ if (this.id != NOT_SCHEDULED_ID) { ++ this.queue.queues[priority.priority].add(this); ++ ++ // call priority change callback ++ this.queue.priorityChange(this, curr, priority); ++ } ++ } ++ ++ return true; ++ } ++ ++ @Override ++ public boolean lowerPriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ synchronized (this.queue.queues) { ++ final PrioritisedExecutor.Priority curr = this.priority; ++ ++ if (curr == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ if (curr.isLowerOrEqualPriority(priority)) { ++ return true; ++ } ++ ++ this.priority = priority; ++ if (this.id != NOT_SCHEDULED_ID) { ++ this.queue.queues[priority.priority].add(this); ++ ++ // call priority change callback ++ this.queue.priorityChange(this, curr, priority); ++ } ++ } ++ ++ return true; ++ } ++ ++ @Override ++ public boolean cancel() { ++ final long id; ++ synchronized (this.queue.queues) { ++ final Priority oldPriority = this.priority; ++ if (oldPriority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ this.priority = PrioritisedExecutor.Priority.COMPLETING; ++ // call priority change callback ++ if ((id = this.id) != NOT_SCHEDULED_ID) { ++ this.queue.priorityChange(this, oldPriority, PrioritisedExecutor.Priority.COMPLETING); ++ } ++ } ++ this.runnable = null; ++ if (id != NOT_SCHEDULED_ID) { ++ this.queue.getAndAddTotalCompletedTasksVolatile(1L); ++ } ++ return true; ++ } ++ ++ protected void executeInternal() { ++ try { ++ final Runnable execute = this.runnable; ++ this.runnable = null; ++ execute.run(); ++ } finally { ++ if (this.id != NOT_SCHEDULED_ID) { ++ this.queue.getAndAddTotalCompletedTasksVolatile(1L); ++ } ++ } ++ } ++ ++ @Override ++ public boolean execute() { ++ synchronized (this.queue.queues) { ++ final Priority oldPriority = this.priority; ++ if (oldPriority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ this.priority = PrioritisedExecutor.Priority.COMPLETING; ++ // call priority change callback ++ if (this.id != NOT_SCHEDULED_ID) { ++ this.queue.priorityChange(this, oldPriority, PrioritisedExecutor.Priority.COMPLETING); ++ } ++ } ++ ++ this.executeInternal(); ++ return true; ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRHashTable.java b/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRHashTable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a037bb57bedc0cde6b979f5c1f9669678fa7bd16 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRHashTable.java +@@ -0,0 +1,1673 @@ ++package ca.spottedleaf.concurrentutil.map; ++ ++import ca.spottedleaf.concurrentutil.util.ArrayUtil; ++import ca.spottedleaf.concurrentutil.util.CollectionUtil; ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import ca.spottedleaf.concurrentutil.util.Validate; ++import io.papermc.paper.util.IntegerUtil; ++import java.lang.invoke.VarHandle; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.Collection; ++import java.util.Iterator; ++import java.util.List; ++import java.util.Map; ++import java.util.NoSuchElementException; ++import java.util.Set; ++import java.util.Spliterator; ++import java.util.Spliterators; ++import java.util.function.BiConsumer; ++import java.util.function.BiFunction; ++import java.util.function.BiPredicate; ++import java.util.function.Consumer; ++import java.util.function.Function; ++import java.util.function.IntFunction; ++import java.util.function.Predicate; ++ ++/** ++ *

++ * Note: Not really tested, use at your own risk. ++ *

++ * This map is safe for reading from multiple threads, however it is only safe to write from a single thread. ++ * {@code null} keys or values are not permitted. Writes to values in this map are guaranteed to be ordered by release semantics, ++ * however immediate visibility to other threads is not guaranteed. However, writes are guaranteed to be made visible eventually. ++ * Reads are ordered by acquire semantics. ++ *

++ * Iterators cannot be modified concurrently, and its backing map cannot be modified concurrently. There is no ++ * fast-fail attempt made by iterators, thus modifying the iterator's backing map while iterating will have undefined ++ * behaviour. ++ *

++ *

++ * Subclasses should override {@link #clone()} to return correct instances of this class. ++ *

++ * @param {@inheritDoc} ++ * @param {@inheritDoc} ++ */ ++public class SWMRHashTable implements Map, Iterable> { ++ ++ protected int size; ++ ++ protected TableEntry[] table; ++ ++ protected final float loadFactor; ++ ++ protected static final VarHandle SIZE_HANDLE = ConcurrentUtil.getVarHandle(SWMRHashTable.class, "size", int.class); ++ protected static final VarHandle TABLE_HANDLE = ConcurrentUtil.getVarHandle(SWMRHashTable.class, "table", TableEntry[].class); ++ ++ /* size */ ++ ++ protected final int getSizePlain() { ++ return (int)SIZE_HANDLE.get(this); ++ } ++ ++ protected final int getSizeOpaque() { ++ return (int)SIZE_HANDLE.getOpaque(this); ++ } ++ ++ protected final int getSizeAcquire() { ++ return (int)SIZE_HANDLE.getAcquire(this); ++ } ++ ++ protected final void setSizePlain(final int value) { ++ SIZE_HANDLE.set(this, value); ++ } ++ ++ protected final void setSizeOpaque(final int value) { ++ SIZE_HANDLE.setOpaque(this, value); ++ } ++ ++ protected final void setSizeRelease(final int value) { ++ SIZE_HANDLE.setRelease(this, value); ++ } ++ ++ /* table */ ++ ++ protected final TableEntry[] getTablePlain() { ++ //noinspection unchecked ++ return (TableEntry[])TABLE_HANDLE.get(this); ++ } ++ ++ protected final TableEntry[] getTableAcquire() { ++ //noinspection unchecked ++ return (TableEntry[])TABLE_HANDLE.getAcquire(this); ++ } ++ ++ protected final void setTablePlain(final TableEntry[] table) { ++ TABLE_HANDLE.set(this, table); ++ } ++ ++ protected final void setTableRelease(final TableEntry[] table) { ++ TABLE_HANDLE.setRelease(this, table); ++ } ++ ++ protected static final int DEFAULT_CAPACITY = 16; ++ protected static final float DEFAULT_LOAD_FACTOR = 0.75f; ++ protected static final int MAXIMUM_CAPACITY = Integer.MIN_VALUE >>> 1; ++ ++ /** ++ * Constructs this map with a capacity of {@code 16} and load factor of {@code 0.75f}. ++ */ ++ public SWMRHashTable() { ++ this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); ++ } ++ ++ /** ++ * Constructs this map with the specified capacity and load factor of {@code 0.75f}. ++ * @param capacity specified initial capacity, > 0 ++ */ ++ public SWMRHashTable(final int capacity) { ++ this(capacity, DEFAULT_LOAD_FACTOR); ++ } ++ ++ /** ++ * Constructs this map with the specified capacity and load factor. ++ * @param capacity specified capacity, > 0 ++ * @param loadFactor specified load factor, > 0 && finite ++ */ ++ public SWMRHashTable(final int capacity, final float loadFactor) { ++ final int tableSize = getCapacityFor(capacity); ++ ++ if (loadFactor <= 0.0 || !Float.isFinite(loadFactor)) { ++ throw new IllegalArgumentException("Invalid load factor: " + loadFactor); ++ } ++ ++ //noinspection unchecked ++ final TableEntry[] table = new TableEntry[tableSize]; ++ this.setTablePlain(table); ++ ++ if (tableSize == MAXIMUM_CAPACITY) { ++ this.threshold = -1; ++ } else { ++ this.threshold = getTargetCapacity(tableSize, loadFactor); ++ } ++ ++ this.loadFactor = loadFactor; ++ } ++ ++ /** ++ * Constructs this map with a capacity of {@code 16} or the specified map's size, whichever is larger, and ++ * with a load factor of {@code 0.75f}. ++ * All of the specified map's entries are copied into this map. ++ * @param other The specified map. ++ */ ++ public SWMRHashTable(final Map other) { ++ this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, other); ++ } ++ ++ /** ++ * Constructs this map with a minimum capacity of the specified capacity or the specified map's size, whichever is larger, and ++ * with a load factor of {@code 0.75f}. ++ * All of the specified map's entries are copied into this map. ++ * @param capacity specified capacity, > 0 ++ * @param other The specified map. ++ */ ++ public SWMRHashTable(final int capacity, final Map other) { ++ this(capacity, DEFAULT_LOAD_FACTOR, other); ++ } ++ ++ /** ++ * Constructs this map with a min capacity of the specified capacity or the specified map's size, whichever is larger, and ++ * with the specified load factor. ++ * All of the specified map's entries are copied into this map. ++ * @param capacity specified capacity, > 0 ++ * @param loadFactor specified load factor, > 0 && finite ++ * @param other The specified map. ++ */ ++ public SWMRHashTable(final int capacity, final float loadFactor, final Map other) { ++ this(Math.max(Validate.notNull(other, "Null map").size(), capacity), loadFactor); ++ this.putAll(other); ++ } ++ ++ public final float getLoadFactor() { ++ return this.loadFactor; ++ } ++ ++ protected static int getCapacityFor(final int capacity) { ++ if (capacity <= 0) { ++ throw new IllegalArgumentException("Invalid capacity: " + capacity); ++ } ++ if (capacity >= MAXIMUM_CAPACITY) { ++ return MAXIMUM_CAPACITY; ++ } ++ return IntegerUtil.roundCeilLog2(capacity); ++ } ++ ++ /** Callers must still use acquire when reading the value of the entry. */ ++ protected final TableEntry getEntryForOpaque(final K key) { ++ final int hash = SWMRHashTable.getHash(key); ++ final TableEntry[] table = this.getTableAcquire(); ++ ++ for (TableEntry curr = ArrayUtil.getOpaque(table, hash & (table.length - 1)); curr != null; curr = curr.getNextOpaque()) { ++ if (hash == curr.hash && (key == curr.key || curr.key.equals(key))) { ++ return curr; ++ } ++ } ++ ++ return null; ++ } ++ ++ protected final TableEntry getEntryForPlain(final K key) { ++ final int hash = SWMRHashTable.getHash(key); ++ final TableEntry[] table = this.getTablePlain(); ++ ++ for (TableEntry curr = table[hash & (table.length - 1)]; curr != null; curr = curr.getNextPlain()) { ++ if (hash == curr.hash && (key == curr.key || curr.key.equals(key))) { ++ return curr; ++ } ++ } ++ ++ return null; ++ } ++ ++ /* MT-Safe */ ++ ++ /** must be deterministic given a key */ ++ private static int getHash(final Object key) { ++ int hash = key == null ? 0 : key.hashCode(); ++ // inlined IntegerUtil#hash0 ++ hash *= 0x36935555; ++ hash ^= hash >>> 16; ++ return hash; ++ } ++ ++ static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash ++ static final int spread(int h) { ++ return (h ^ (h >>> 16)) & HASH_BITS; ++ } ++ ++ // rets -1 if capacity*loadFactor is too large ++ protected static int getTargetCapacity(final int capacity, final float loadFactor) { ++ final double ret = (double)capacity * (double)loadFactor; ++ if (Double.isInfinite(ret) || ret >= ((double)Integer.MAX_VALUE)) { ++ return -1; ++ } ++ ++ return (int)ret; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean equals(final Object obj) { ++ if (this == obj) { ++ return true; ++ } ++ /* Make no attempt to deal with concurrent modifications */ ++ if (!(obj instanceof Map)) { ++ return false; ++ } ++ final Map other = (Map)obj; ++ ++ if (this.size() != other.size()) { ++ return false; ++ } ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ final V value = curr.getValueAcquire(); ++ ++ final Object otherValue = other.get(curr.key); ++ if (otherValue == null || (value != otherValue && value.equals(otherValue))) { ++ return false; ++ } ++ } ++ } ++ ++ return true; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public int hashCode() { ++ /* Make no attempt to deal with concurrent modifications */ ++ int hash = 0; ++ final TableEntry[] table = this.getTableAcquire(); ++ ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ hash += curr.hashCode(); ++ } ++ } ++ ++ return hash; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public String toString() { ++ final StringBuilder builder = new StringBuilder(64); ++ builder.append("SingleWriterMultiReaderHashMap:{"); ++ ++ this.forEach((final K key, final V value) -> { ++ builder.append("{key: \"").append(key).append("\", value: \"").append(value).append("\"}"); ++ }); ++ ++ return builder.append('}').toString(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public SWMRHashTable clone() { ++ return new SWMRHashTable<>(this.getTableAcquire().length, this.loadFactor, this); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public Iterator> iterator() { ++ return new EntryIterator<>(this.getTableAcquire(), this); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public void forEach(final Consumer> action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ action.accept(curr); ++ } ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public void forEach(final BiConsumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ final V value = curr.getValueAcquire(); ++ ++ action.accept(curr.key, value); ++ } ++ } ++ } ++ ++ /** ++ * Provides the specified consumer with all keys contained within this map. ++ * @param action The specified consumer. ++ */ ++ public void forEachKey(final Consumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ action.accept(curr.key); ++ } ++ } ++ } ++ ++ /** ++ * Provides the specified consumer with all values contained within this map. Equivalent to {@code map.values().forEach(Consumer)}. ++ * @param action The specified consumer. ++ */ ++ public void forEachValue(final Consumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ final V value = curr.getValueAcquire(); ++ ++ action.accept(value); ++ } ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V get(final Object key) { ++ Validate.notNull(key, "Null key"); ++ ++ //noinspection unchecked ++ final TableEntry entry = this.getEntryForOpaque((K)key); ++ return entry == null ? null : entry.getValueAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean containsKey(final Object key) { ++ Validate.notNull(key, "Null key"); ++ ++ // note: we need to use getValueAcquire, so that the reads from this map are ordered by acquire semantics ++ return this.get(key) != null; ++ } ++ ++ /** ++ * Returns {@code true} if this map contains an entry with the specified key and value at some point during this call. ++ * @param key The specified key. ++ * @param value The specified value. ++ * @return {@code true} if this map contains an entry with the specified key and value. ++ */ ++ public boolean contains(final Object key, final Object value) { ++ Validate.notNull(key, "Null key"); ++ ++ //noinspection unchecked ++ final TableEntry entry = this.getEntryForOpaque((K)key); ++ ++ if (entry == null) { ++ return false; ++ } ++ ++ final V entryVal = entry.getValueAcquire(); ++ return entryVal == value || entryVal.equals(value); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean containsValue(final Object value) { ++ Validate.notNull(value, "Null value"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ final V currVal = curr.getValueAcquire(); ++ if (currVal == value || currVal.equals(value)) { ++ return true; ++ } ++ } ++ } ++ ++ return false; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V getOrDefault(final Object key, final V defaultValue) { ++ Validate.notNull(key, "Null key"); ++ ++ //noinspection unchecked ++ final TableEntry entry = this.getEntryForOpaque((K)key); ++ ++ return entry == null ? defaultValue : entry.getValueAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public int size() { ++ return this.getSizeAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean isEmpty() { ++ return this.getSizeAcquire() == 0; ++ } ++ ++ protected Set keyset; ++ protected Collection values; ++ protected Set> entrySet; ++ ++ @Override ++ public Set keySet() { ++ return this.keyset == null ? this.keyset = new KeySet<>(this) : this.keyset; ++ } ++ ++ @Override ++ public Collection values() { ++ return this.values == null ? this.values = new ValueCollection<>(this) : this.values; ++ } ++ ++ @Override ++ public Set> entrySet() { ++ return this.entrySet == null ? this.entrySet = new EntrySet<>(this) : this.entrySet; ++ } ++ ++ /* Non-MT-Safe */ ++ ++ protected int threshold; ++ ++ protected final void checkResize(final int minCapacity) { ++ if (minCapacity <= this.threshold || this.threshold < 0) { ++ return; ++ } ++ ++ final TableEntry[] table = this.getTablePlain(); ++ int newCapacity = minCapacity >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : IntegerUtil.roundCeilLog2(minCapacity); ++ if (newCapacity < 0) { ++ newCapacity = MAXIMUM_CAPACITY; ++ } ++ if (newCapacity <= table.length) { ++ if (newCapacity == MAXIMUM_CAPACITY) { ++ return; ++ } ++ newCapacity = table.length << 1; ++ } ++ ++ //noinspection unchecked ++ final TableEntry[] newTable = new TableEntry[newCapacity]; ++ final int indexMask = newCapacity - 1; ++ ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry entry = table[i]; entry != null; entry = entry.getNextPlain()) { ++ final int hash = entry.hash; ++ final int index = hash & indexMask; ++ ++ /* we need to create a new entry since there could be reading threads */ ++ final TableEntry insert = new TableEntry<>(hash, entry.key, entry.getValuePlain()); ++ ++ final TableEntry prev = newTable[index]; ++ ++ newTable[index] = insert; ++ insert.setNextPlain(prev); ++ } ++ } ++ ++ if (newCapacity == MAXIMUM_CAPACITY) { ++ this.threshold = -1; /* No more resizing */ ++ } else { ++ this.threshold = getTargetCapacity(newCapacity, this.loadFactor); ++ } ++ this.setTableRelease(newTable); /* use release to publish entries in table */ ++ } ++ ++ protected final int addToSize(final int num) { ++ final int newSize = this.getSizePlain() + num; ++ ++ this.setSizeOpaque(newSize); ++ this.checkResize(newSize); ++ ++ return newSize; ++ } ++ ++ protected final int removeFromSize(final int num) { ++ final int newSize = this.getSizePlain() - num; ++ ++ this.setSizeOpaque(newSize); ++ ++ return newSize; ++ } ++ ++ /* Cannot be used to perform downsizing */ ++ protected final int removeFromSizePlain(final int num) { ++ final int newSize = this.getSizePlain() - num; ++ ++ this.setSizePlain(newSize); ++ ++ return newSize; ++ } ++ ++ protected final V put(final K key, final V value, final boolean onlyIfAbsent) { ++ final TableEntry[] table = this.getTablePlain(); ++ final int hash = SWMRHashTable.getHash(key); ++ final int index = hash & (table.length - 1); ++ ++ final TableEntry head = table[index]; ++ if (head == null) { ++ final TableEntry insert = new TableEntry<>(hash, key, value); ++ ArrayUtil.setRelease(table, index, insert); ++ this.addToSize(1); ++ return null; ++ } ++ ++ for (TableEntry curr = head;;) { ++ if (curr.hash == hash && (key == curr.key || curr.key.equals(key))) { ++ if (onlyIfAbsent) { ++ return curr.getValuePlain(); ++ } ++ ++ final V currVal = curr.getValuePlain(); ++ curr.setValueRelease(value); ++ return currVal; ++ } ++ ++ final TableEntry next = curr.getNextPlain(); ++ if (next != null) { ++ curr = next; ++ continue; ++ } ++ ++ final TableEntry insert = new TableEntry<>(hash, key, value); ++ ++ curr.setNextRelease(insert); ++ this.addToSize(1); ++ return null; ++ } ++ } ++ ++ /** ++ * Removes a key-value pair from this map if the specified predicate returns true. The specified predicate is ++ * tested with every entry in this map. Returns the number of key-value pairs removed. ++ * @param predicate The predicate to test key-value pairs against. ++ * @return The total number of key-value pairs removed from this map. ++ */ ++ public int removeIf(final BiPredicate predicate) { ++ Validate.notNull(predicate, "Null predicate"); ++ ++ int removed = 0; ++ ++ final TableEntry[] table = this.getTablePlain(); ++ ++ bin_iteration_loop: ++ for (int i = 0, len = table.length; i < len; ++i) { ++ TableEntry curr = table[i]; ++ if (curr == null) { ++ continue; ++ } ++ ++ /* Handle bin nodes first */ ++ while (predicate.test(curr.key, curr.getValuePlain())) { ++ ++removed; ++ this.removeFromSizePlain(1); /* required in case predicate throws an exception */ ++ ++ ArrayUtil.setRelease(table, i, curr = curr.getNextPlain()); ++ ++ if (curr == null) { ++ continue bin_iteration_loop; ++ } ++ } ++ ++ TableEntry prev; ++ ++ /* curr at this point is the bin node */ ++ ++ for (prev = curr, curr = curr.getNextPlain(); curr != null;) { ++ /* If we want to remove, then we should hold prev, as it will be a valid entry to link on */ ++ if (predicate.test(curr.key, curr.getValuePlain())) { ++ ++removed; ++ this.removeFromSizePlain(1); /* required in case predicate throws an exception */ ++ ++ prev.setNextRelease(curr = curr.getNextPlain()); ++ } else { ++ prev = curr; ++ curr = curr.getNextPlain(); ++ } ++ } ++ } ++ ++ return removed; ++ } ++ ++ /** ++ * Removes a key-value pair from this map if the specified predicate returns true. The specified predicate is ++ * tested with every entry in this map. Returns the number of key-value pairs removed. ++ * @param predicate The predicate to test key-value pairs against. ++ * @return The total number of key-value pairs removed from this map. ++ */ ++ public int removeEntryIf(final Predicate> predicate) { ++ Validate.notNull(predicate, "Null predicate"); ++ ++ int removed = 0; ++ ++ final TableEntry[] table = this.getTablePlain(); ++ ++ bin_iteration_loop: ++ for (int i = 0, len = table.length; i < len; ++i) { ++ TableEntry curr = table[i]; ++ if (curr == null) { ++ continue; ++ } ++ ++ /* Handle bin nodes first */ ++ while (predicate.test(curr)) { ++ ++removed; ++ this.removeFromSizePlain(1); /* required in case predicate throws an exception */ ++ ++ ArrayUtil.setRelease(table, i, curr = curr.getNextPlain()); ++ ++ if (curr == null) { ++ continue bin_iteration_loop; ++ } ++ } ++ ++ TableEntry prev; ++ ++ /* curr at this point is the bin node */ ++ ++ for (prev = curr, curr = curr.getNextPlain(); curr != null;) { ++ /* If we want to remove, then we should hold prev, as it will be a valid entry to link on */ ++ if (predicate.test(curr)) { ++ ++removed; ++ this.removeFromSizePlain(1); /* required in case predicate throws an exception */ ++ ++ prev.setNextRelease(curr = curr.getNextPlain()); ++ } else { ++ prev = curr; ++ curr = curr.getNextPlain(); ++ } ++ } ++ } ++ ++ return removed; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V put(final K key, final V value) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(value, "Null value"); ++ ++ return this.put(key, value, false); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V putIfAbsent(final K key, final V value) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(value, "Null value"); ++ ++ return this.put(key, value, true); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean remove(final Object key, final Object value) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(value, "Null value"); ++ ++ final TableEntry[] table = this.getTablePlain(); ++ final int hash = SWMRHashTable.getHash(key); ++ final int index = hash & (table.length - 1); ++ ++ final TableEntry head = table[index]; ++ if (head == null) { ++ return false; ++ } ++ ++ if (head.hash == hash && (head.key == key || head.key.equals(key))) { ++ final V currVal = head.getValuePlain(); ++ ++ if (currVal != value && !currVal.equals(value)) { ++ return false; ++ } ++ ++ ArrayUtil.setRelease(table, index, head.getNextPlain()); ++ this.removeFromSize(1); ++ ++ return true; ++ } ++ ++ for (TableEntry curr = head.getNextPlain(), prev = head; curr != null; prev = curr, curr = curr.getNextPlain()) { ++ if (curr.hash == hash && (curr.key == key || curr.key.equals(key))) { ++ final V currVal = curr.getValuePlain(); ++ ++ if (currVal != value && !currVal.equals(value)) { ++ return false; ++ } ++ ++ prev.setNextRelease(curr.getNextPlain()); ++ this.removeFromSize(1); ++ ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ ++ protected final V remove(final Object key, final int hash) { ++ final TableEntry[] table = this.getTablePlain(); ++ final int index = (table.length - 1) & hash; ++ ++ final TableEntry head = table[index]; ++ if (head == null) { ++ return null; ++ } ++ ++ if (hash == head.hash && (head.key == key || head.key.equals(key))) { ++ ArrayUtil.setRelease(table, index, head.getNextPlain()); ++ this.removeFromSize(1); ++ ++ return head.getValuePlain(); ++ } ++ ++ for (TableEntry curr = head.getNextPlain(), prev = head; curr != null; prev = curr, curr = curr.getNextPlain()) { ++ if (curr.hash == hash && (key == curr.key || curr.key.equals(key))) { ++ prev.setNextRelease(curr.getNextPlain()); ++ this.removeFromSize(1); ++ ++ return curr.getValuePlain(); ++ } ++ } ++ ++ return null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V remove(final Object key) { ++ Validate.notNull(key, "Null key"); ++ ++ return this.remove(key, SWMRHashTable.getHash(key)); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean replace(final K key, final V oldValue, final V newValue) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(oldValue, "Null oldValue"); ++ Validate.notNull(newValue, "Null newValue"); ++ ++ final TableEntry entry = this.getEntryForPlain(key); ++ if (entry == null) { ++ return false; ++ } ++ ++ final V currValue = entry.getValuePlain(); ++ if (currValue == oldValue || currValue.equals(oldValue)) { ++ entry.setValueRelease(newValue); ++ return true; ++ } ++ ++ return false; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V replace(final K key, final V value) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(value, "Null value"); ++ ++ final TableEntry entry = this.getEntryForPlain(key); ++ if (entry == null) { ++ return null; ++ } ++ ++ final V prev = entry.getValuePlain(); ++ entry.setValueRelease(value); ++ return prev; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public void replaceAll(final BiFunction function) { ++ Validate.notNull(function, "Null function"); ++ ++ final TableEntry[] table = this.getTablePlain(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = table[i]; curr != null; curr = curr.getNextPlain()) { ++ final V value = curr.getValuePlain(); ++ ++ final V newValue = function.apply(curr.key, value); ++ if (newValue == null) { ++ throw new NullPointerException(); ++ } ++ ++ curr.setValueRelease(newValue); ++ } ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public void putAll(final Map map) { ++ Validate.notNull(map, "Null map"); ++ ++ final int size = map.size(); ++ this.checkResize(Math.max(this.getSizePlain() + size/2, size)); /* preemptively resize */ ++ map.forEach(this::put); ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

++ * This call is non-atomic and the order that which entries are removed is undefined. The clear operation itself ++ * is release ordered, that is, after the clear operation is performed a release fence is performed. ++ *

++ */ ++ @Override ++ public void clear() { ++ Arrays.fill(this.getTablePlain(), null); ++ this.setSizeRelease(0); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V compute(final K key, final BiFunction remappingFunction) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(remappingFunction, "Null remappingFunction"); ++ ++ final int hash = SWMRHashTable.getHash(key); ++ final TableEntry[] table = this.getTablePlain(); ++ final int index = hash & (table.length - 1); ++ ++ for (TableEntry curr = table[index], prev = null;;prev = curr, curr = curr.getNextPlain()) { ++ if (curr == null) { ++ final V newVal = remappingFunction.apply(key ,null); ++ ++ if (newVal == null) { ++ return null; ++ } ++ ++ final TableEntry insert = new TableEntry<>(hash, key, newVal); ++ if (prev == null) { ++ ArrayUtil.setRelease(table, index, insert); ++ } else { ++ prev.setNextRelease(insert); ++ } ++ ++ this.addToSize(1); ++ ++ return newVal; ++ } ++ ++ if (curr.hash == hash && (curr.key == key || curr.key.equals(key))) { ++ final V newVal = remappingFunction.apply(key, curr.getValuePlain()); ++ ++ if (newVal != null) { ++ curr.setValueRelease(newVal); ++ return newVal; ++ } ++ ++ if (prev == null) { ++ ArrayUtil.setRelease(table, index, curr.getNextPlain()); ++ } else { ++ prev.setNextRelease(curr.getNextPlain()); ++ } ++ ++ this.removeFromSize(1); ++ ++ return null; ++ } ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V computeIfPresent(final K key, final BiFunction remappingFunction) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(remappingFunction, "Null remappingFunction"); ++ ++ final int hash = SWMRHashTable.getHash(key); ++ final TableEntry[] table = this.getTablePlain(); ++ final int index = hash & (table.length - 1); ++ ++ for (TableEntry curr = table[index], prev = null; curr != null; prev = curr, curr = curr.getNextPlain()) { ++ if (curr.hash != hash || (curr.key != key && !curr.key.equals(key))) { ++ continue; ++ } ++ ++ final V newVal = remappingFunction.apply(key, curr.getValuePlain()); ++ if (newVal != null) { ++ curr.setValueRelease(newVal); ++ return newVal; ++ } ++ ++ if (prev == null) { ++ ArrayUtil.setRelease(table, index, curr.getNextPlain()); ++ } else { ++ prev.setNextRelease(curr.getNextPlain()); ++ } ++ ++ this.removeFromSize(1); ++ ++ return null; ++ } ++ ++ return null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V computeIfAbsent(final K key, final Function mappingFunction) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(mappingFunction, "Null mappingFunction"); ++ ++ final int hash = SWMRHashTable.getHash(key); ++ final TableEntry[] table = this.getTablePlain(); ++ final int index = hash & (table.length - 1); ++ ++ for (TableEntry curr = table[index], prev = null;;prev = curr, curr = curr.getNextPlain()) { ++ if (curr != null) { ++ if (curr.hash == hash && (curr.key == key || curr.key.equals(key))) { ++ return curr.getValuePlain(); ++ } ++ continue; ++ } ++ ++ final V newVal = mappingFunction.apply(key); ++ ++ if (newVal == null) { ++ return null; ++ } ++ ++ final TableEntry insert = new TableEntry<>(hash, key, newVal); ++ if (prev == null) { ++ ArrayUtil.setRelease(table, index, insert); ++ } else { ++ prev.setNextRelease(insert); ++ } ++ ++ this.addToSize(1); ++ ++ return newVal; ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V merge(final K key, final V value, final BiFunction remappingFunction) { ++ Validate.notNull(key, "Null key"); ++ Validate.notNull(value, "Null value"); ++ Validate.notNull(remappingFunction, "Null remappingFunction"); ++ ++ final int hash = SWMRHashTable.getHash(key); ++ final TableEntry[] table = this.getTablePlain(); ++ final int index = hash & (table.length - 1); ++ ++ for (TableEntry curr = table[index], prev = null;;prev = curr, curr = curr.getNextPlain()) { ++ if (curr == null) { ++ final TableEntry insert = new TableEntry<>(hash, key, value); ++ if (prev == null) { ++ ArrayUtil.setRelease(table, index, insert); ++ } else { ++ prev.setNextRelease(insert); ++ } ++ ++ this.addToSize(1); ++ ++ return value; ++ } ++ ++ if (curr.hash == hash && (curr.key == key || curr.key.equals(key))) { ++ final V newVal = remappingFunction.apply(curr.getValuePlain(), value); ++ ++ if (newVal != null) { ++ curr.setValueRelease(newVal); ++ return newVal; ++ } ++ ++ if (prev == null) { ++ ArrayUtil.setRelease(table, index, curr.getNextPlain()); ++ } else { ++ prev.setNextRelease(curr.getNextPlain()); ++ } ++ ++ this.removeFromSize(1); ++ ++ return null; ++ } ++ } ++ } ++ ++ protected static final class TableEntry implements Map.Entry { ++ ++ protected final int hash; ++ protected final K key; ++ protected V value; ++ ++ protected TableEntry next; ++ ++ protected static final VarHandle VALUE_HANDLE = ConcurrentUtil.getVarHandle(TableEntry.class, "value", Object.class); ++ protected static final VarHandle NEXT_HANDLE = ConcurrentUtil.getVarHandle(TableEntry.class, "next", TableEntry.class); ++ ++ /* value */ ++ ++ protected final V getValuePlain() { ++ //noinspection unchecked ++ return (V)VALUE_HANDLE.get(this); ++ } ++ ++ protected final V getValueAcquire() { ++ //noinspection unchecked ++ return (V)VALUE_HANDLE.getAcquire(this); ++ } ++ ++ protected final void setValueRelease(final V to) { ++ VALUE_HANDLE.setRelease(this, to); ++ } ++ ++ /* next */ ++ ++ protected final TableEntry getNextPlain() { ++ //noinspection unchecked ++ return (TableEntry)NEXT_HANDLE.get(this); ++ } ++ ++ protected final TableEntry getNextOpaque() { ++ //noinspection unchecked ++ return (TableEntry)NEXT_HANDLE.getOpaque(this); ++ } ++ ++ protected final void setNextPlain(final TableEntry next) { ++ NEXT_HANDLE.set(this, next); ++ } ++ ++ protected final void setNextRelease(final TableEntry next) { ++ NEXT_HANDLE.setRelease(this, next); ++ } ++ ++ protected TableEntry(final int hash, final K key, final V value) { ++ this.hash = hash; ++ this.key = key; ++ this.value = value; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public K getKey() { ++ return this.key; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V getValue() { ++ return this.getValueAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public V setValue(final V value) { ++ if (value == null) { ++ throw new NullPointerException(); ++ } ++ ++ final V curr = this.getValuePlain(); ++ ++ this.setValueRelease(value); ++ return curr; ++ } ++ ++ protected static int hash(final Object key, final Object value) { ++ return key.hashCode() ^ (value == null ? 0 : value.hashCode()); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public int hashCode() { ++ return hash(this.key, this.getValueAcquire()); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean equals(final Object obj) { ++ if (this == obj) { ++ return true; ++ } ++ ++ if (!(obj instanceof Map.Entry)) { ++ return false; ++ } ++ final Map.Entry other = (Map.Entry)obj; ++ final Object otherKey = other.getKey(); ++ final Object otherValue = other.getValue(); ++ ++ final K thisKey = this.getKey(); ++ final V thisVal = this.getValueAcquire(); ++ return (thisKey == otherKey || thisKey.equals(otherKey)) && ++ (thisVal == otherValue || thisVal.equals(otherValue)); ++ } ++ } ++ ++ ++ protected static abstract class TableEntryIterator implements Iterator { ++ ++ protected final TableEntry[] table; ++ protected final SWMRHashTable map; ++ ++ /* bin which our current element resides on */ ++ protected int tableIndex; ++ ++ protected TableEntry currEntry; /* curr entry, null if no more to iterate or if curr was removed or if we've just init'd */ ++ protected TableEntry nextEntry; /* may not be on the same bin as currEntry */ ++ ++ protected TableEntryIterator(final TableEntry[] table, final SWMRHashTable map) { ++ this.table = table; ++ this.map = map; ++ int tableIndex = 0; ++ for (int len = table.length; tableIndex < len; ++tableIndex) { ++ final TableEntry entry = ArrayUtil.getOpaque(table, tableIndex); ++ if (entry != null) { ++ this.nextEntry = entry; ++ this.tableIndex = tableIndex + 1; ++ return; ++ } ++ } ++ this.tableIndex = tableIndex; ++ } ++ ++ @Override ++ public boolean hasNext() { ++ return this.nextEntry != null; ++ } ++ ++ protected final TableEntry advanceEntry() { ++ final TableEntry[] table = this.table; ++ final int tableLength = table.length; ++ int tableIndex = this.tableIndex; ++ final TableEntry curr = this.nextEntry; ++ if (curr == null) { ++ return null; ++ } ++ ++ this.currEntry = curr; ++ ++ // set up nextEntry ++ ++ // find next in chain ++ TableEntry next = curr.getNextOpaque(); ++ ++ if (next != null) { ++ this.nextEntry = next; ++ return curr; ++ } ++ ++ // nothing in chain, so find next available bin ++ for (;tableIndex < tableLength; ++tableIndex) { ++ next = ArrayUtil.getOpaque(table, tableIndex); ++ if (next != null) { ++ this.nextEntry = next; ++ this.tableIndex = tableIndex + 1; ++ return curr; ++ } ++ } ++ ++ this.nextEntry = null; ++ this.tableIndex = tableIndex; ++ return curr; ++ } ++ ++ @Override ++ public void remove() { ++ final TableEntry curr = this.currEntry; ++ if (curr == null) { ++ throw new IllegalStateException(); ++ } ++ ++ this.map.remove(curr.key, curr.hash); ++ ++ this.currEntry = null; ++ } ++ } ++ ++ protected static final class ValueIterator extends TableEntryIterator { ++ ++ protected ValueIterator(final TableEntry[] table, final SWMRHashTable map) { ++ super(table, map); ++ } ++ ++ @Override ++ public V next() { ++ final TableEntry entry = this.advanceEntry(); ++ ++ if (entry == null) { ++ throw new NoSuchElementException(); ++ } ++ ++ return entry.getValueAcquire(); ++ } ++ } ++ ++ protected static final class KeyIterator extends TableEntryIterator { ++ ++ protected KeyIterator(final TableEntry[] table, final SWMRHashTable map) { ++ super(table, map); ++ } ++ ++ @Override ++ public K next() { ++ final TableEntry curr = this.advanceEntry(); ++ ++ if (curr == null) { ++ throw new NoSuchElementException(); ++ } ++ ++ return curr.key; ++ } ++ } ++ ++ protected static final class EntryIterator extends TableEntryIterator> { ++ ++ protected EntryIterator(final TableEntry[] table, final SWMRHashTable map) { ++ super(table, map); ++ } ++ ++ @Override ++ public Map.Entry next() { ++ final TableEntry curr = this.advanceEntry(); ++ ++ if (curr == null) { ++ throw new NoSuchElementException(); ++ } ++ ++ return curr; ++ } ++ } ++ ++ protected static abstract class ViewCollection implements Collection { ++ ++ protected final SWMRHashTable map; ++ ++ protected ViewCollection(final SWMRHashTable map) { ++ this.map = map; ++ } ++ ++ @Override ++ public boolean add(final T element) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean addAll(final Collection collections) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean removeAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ boolean modified = false; ++ for (final Object element : collection) { ++ modified |= this.remove(element); ++ } ++ return modified; ++ } ++ ++ @Override ++ public int size() { ++ return this.map.size(); ++ } ++ ++ @Override ++ public boolean isEmpty() { ++ return this.size() == 0; ++ } ++ ++ @Override ++ public void clear() { ++ this.map.clear(); ++ } ++ ++ @Override ++ public boolean containsAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ for (final Object element : collection) { ++ if (!this.contains(element)) { ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ ++ @Override ++ public Object[] toArray() { ++ final List list = new ArrayList<>(this.size()); ++ ++ this.forEach(list::add); ++ ++ return list.toArray(); ++ } ++ ++ @Override ++ public E[] toArray(final E[] array) { ++ final List list = new ArrayList<>(this.size()); ++ ++ this.forEach(list::add); ++ ++ return list.toArray(array); ++ } ++ ++ @Override ++ public E[] toArray(final IntFunction generator) { ++ final List list = new ArrayList<>(this.size()); ++ ++ this.forEach(list::add); ++ ++ return list.toArray(generator); ++ } ++ ++ @Override ++ public int hashCode() { ++ int hash = 0; ++ for (final T element : this) { ++ hash += element == null ? 0 : element.hashCode(); ++ } ++ return hash; ++ } ++ ++ @Override ++ public Spliterator spliterator() { // TODO implement ++ return Spliterators.spliterator(this, Spliterator.NONNULL); ++ } ++ } ++ ++ protected static abstract class ViewSet extends ViewCollection implements Set { ++ ++ protected ViewSet(final SWMRHashTable map) { ++ super(map); ++ } ++ ++ @Override ++ public boolean equals(final Object obj) { ++ if (this == obj) { ++ return true; ++ } ++ ++ if (!(obj instanceof Set)) { ++ return false; ++ } ++ ++ final Set other = (Set)obj; ++ if (other.size() != this.size()) { ++ return false; ++ } ++ ++ return this.containsAll(other); ++ } ++ } ++ ++ protected static final class EntrySet extends ViewSet> implements Set> { ++ ++ protected EntrySet(final SWMRHashTable map) { ++ super(map); ++ } ++ ++ @Override ++ public boolean remove(final Object object) { ++ if (!(object instanceof Map.Entry)) { ++ return false; ++ } ++ final Map.Entry entry = (Map.Entry)object; ++ ++ final Object key; ++ final Object value; ++ ++ try { ++ key = entry.getKey(); ++ value = entry.getValue(); ++ } catch (final IllegalStateException ex) { ++ return false; ++ } ++ ++ return this.map.remove(key, value); ++ } ++ ++ @Override ++ public boolean removeIf(final Predicate> filter) { ++ Validate.notNull(filter, "Null filter"); ++ ++ return this.map.removeEntryIf(filter) != 0; ++ } ++ ++ @Override ++ public boolean retainAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ return this.map.removeEntryIf((final Map.Entry entry) -> { ++ return !collection.contains(entry); ++ }) != 0; ++ } ++ ++ @Override ++ public Iterator> iterator() { ++ return new EntryIterator<>(this.map.getTableAcquire(), this.map); ++ } ++ ++ @Override ++ public void forEach(final Consumer> action) { ++ this.map.forEach(action); ++ } ++ ++ @Override ++ public boolean contains(final Object object) { ++ if (!(object instanceof Map.Entry)) { ++ return false; ++ } ++ final Map.Entry entry = (Map.Entry)object; ++ ++ final Object key; ++ final Object value; ++ ++ try { ++ key = entry.getKey(); ++ value = entry.getValue(); ++ } catch (final IllegalStateException ex) { ++ return false; ++ } ++ ++ return this.map.contains(key, value); ++ } ++ ++ @Override ++ public String toString() { ++ return CollectionUtil.toString(this, "SWMRHashTableEntrySet"); ++ } ++ } ++ ++ protected static final class KeySet extends ViewSet { ++ ++ protected KeySet(final SWMRHashTable map) { ++ super(map); ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return new KeyIterator<>(this.map.getTableAcquire(), this.map); ++ } ++ ++ @Override ++ public void forEach(final Consumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ this.map.forEachKey(action); ++ } ++ ++ @Override ++ public boolean contains(final Object key) { ++ Validate.notNull(key, "Null key"); ++ ++ return this.map.containsKey(key); ++ } ++ ++ @Override ++ public boolean remove(final Object key) { ++ Validate.notNull(key, "Null key"); ++ ++ return this.map.remove(key) != null; ++ } ++ ++ @Override ++ public boolean retainAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ return this.map.removeIf((final K key, final V value) -> { ++ return !collection.contains(key); ++ }) != 0; ++ } ++ ++ @Override ++ public boolean removeIf(final Predicate filter) { ++ Validate.notNull(filter, "Null filter"); ++ ++ return this.map.removeIf((final K key, final V value) -> { ++ return filter.test(key); ++ }) != 0; ++ } ++ ++ @Override ++ public String toString() { ++ return CollectionUtil.toString(this, "SWMRHashTableKeySet"); ++ } ++ } ++ ++ protected static final class ValueCollection extends ViewSet implements Collection { ++ ++ protected ValueCollection(final SWMRHashTable map) { ++ super(map); ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return new ValueIterator<>(this.map.getTableAcquire(), this.map); ++ } ++ ++ @Override ++ public void forEach(final Consumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ this.map.forEachValue(action); ++ } ++ ++ @Override ++ public boolean contains(final Object object) { ++ Validate.notNull(object, "Null object"); ++ ++ return this.map.containsValue(object); ++ } ++ ++ @Override ++ public boolean remove(final Object object) { ++ Validate.notNull(object, "Null object"); ++ ++ final Iterator itr = this.iterator(); ++ while (itr.hasNext()) { ++ final V val = itr.next(); ++ if (val == object || val.equals(object)) { ++ itr.remove(); ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ ++ @Override ++ public boolean removeIf(final Predicate filter) { ++ Validate.notNull(filter, "Null filter"); ++ ++ return this.map.removeIf((final K key, final V value) -> { ++ return filter.test(value); ++ }) != 0; ++ } ++ ++ @Override ++ public boolean retainAll(final Collection collection) { ++ Validate.notNull(collection, "Null collection"); ++ ++ return this.map.removeIf((final K key, final V value) -> { ++ return !collection.contains(value); ++ }) != 0; ++ } ++ ++ @Override ++ public String toString() { ++ return CollectionUtil.toString(this, "SWMRHashTableValues"); ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRLong2ObjectHashTable.java b/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRLong2ObjectHashTable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1e98f778ffa0a7bb00ebccaaa8bde075183e41f0 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRLong2ObjectHashTable.java +@@ -0,0 +1,672 @@ ++package ca.spottedleaf.concurrentutil.map; ++ ++import ca.spottedleaf.concurrentutil.util.ArrayUtil; ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import ca.spottedleaf.concurrentutil.util.Validate; ++import io.papermc.paper.util.IntegerUtil; ++import java.lang.invoke.VarHandle; ++import java.util.Arrays; ++import java.util.function.Consumer; ++import java.util.function.LongConsumer; ++ ++// trimmed down version of SWMRHashTable ++public class SWMRLong2ObjectHashTable { ++ ++ protected int size; ++ ++ protected TableEntry[] table; ++ ++ protected final float loadFactor; ++ ++ protected static final VarHandle SIZE_HANDLE = ConcurrentUtil.getVarHandle(SWMRLong2ObjectHashTable.class, "size", int.class); ++ protected static final VarHandle TABLE_HANDLE = ConcurrentUtil.getVarHandle(SWMRLong2ObjectHashTable.class, "table", TableEntry[].class); ++ ++ /* size */ ++ ++ protected final int getSizePlain() { ++ return (int)SIZE_HANDLE.get(this); ++ } ++ ++ protected final int getSizeOpaque() { ++ return (int)SIZE_HANDLE.getOpaque(this); ++ } ++ ++ protected final int getSizeAcquire() { ++ return (int)SIZE_HANDLE.getAcquire(this); ++ } ++ ++ protected final void setSizePlain(final int value) { ++ SIZE_HANDLE.set(this, value); ++ } ++ ++ protected final void setSizeOpaque(final int value) { ++ SIZE_HANDLE.setOpaque(this, value); ++ } ++ ++ protected final void setSizeRelease(final int value) { ++ SIZE_HANDLE.setRelease(this, value); ++ } ++ ++ /* table */ ++ ++ protected final TableEntry[] getTablePlain() { ++ //noinspection unchecked ++ return (TableEntry[])TABLE_HANDLE.get(this); ++ } ++ ++ protected final TableEntry[] getTableAcquire() { ++ //noinspection unchecked ++ return (TableEntry[])TABLE_HANDLE.getAcquire(this); ++ } ++ ++ protected final void setTablePlain(final TableEntry[] table) { ++ TABLE_HANDLE.set(this, table); ++ } ++ ++ protected final void setTableRelease(final TableEntry[] table) { ++ TABLE_HANDLE.setRelease(this, table); ++ } ++ ++ protected static final int DEFAULT_CAPACITY = 16; ++ protected static final float DEFAULT_LOAD_FACTOR = 0.75f; ++ protected static final int MAXIMUM_CAPACITY = Integer.MIN_VALUE >>> 1; ++ ++ /** ++ * Constructs this map with a capacity of {@code 16} and load factor of {@code 0.75f}. ++ */ ++ public SWMRLong2ObjectHashTable() { ++ this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); ++ } ++ ++ /** ++ * Constructs this map with the specified capacity and load factor of {@code 0.75f}. ++ * @param capacity specified initial capacity, > 0 ++ */ ++ public SWMRLong2ObjectHashTable(final int capacity) { ++ this(capacity, DEFAULT_LOAD_FACTOR); ++ } ++ ++ /** ++ * Constructs this map with the specified capacity and load factor. ++ * @param capacity specified capacity, > 0 ++ * @param loadFactor specified load factor, > 0 && finite ++ */ ++ public SWMRLong2ObjectHashTable(final int capacity, final float loadFactor) { ++ final int tableSize = getCapacityFor(capacity); ++ ++ if (loadFactor <= 0.0 || !Float.isFinite(loadFactor)) { ++ throw new IllegalArgumentException("Invalid load factor: " + loadFactor); ++ } ++ ++ //noinspection unchecked ++ final TableEntry[] table = new TableEntry[tableSize]; ++ this.setTablePlain(table); ++ ++ if (tableSize == MAXIMUM_CAPACITY) { ++ this.threshold = -1; ++ } else { ++ this.threshold = getTargetCapacity(tableSize, loadFactor); ++ } ++ ++ this.loadFactor = loadFactor; ++ } ++ ++ /** ++ * Constructs this map with a capacity of {@code 16} or the specified map's size, whichever is larger, and ++ * with a load factor of {@code 0.75f}. ++ * All of the specified map's entries are copied into this map. ++ * @param other The specified map. ++ */ ++ public SWMRLong2ObjectHashTable(final SWMRLong2ObjectHashTable other) { ++ this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, other); ++ } ++ ++ /** ++ * Constructs this map with a minimum capacity of the specified capacity or the specified map's size, whichever is larger, and ++ * with a load factor of {@code 0.75f}. ++ * All of the specified map's entries are copied into this map. ++ * @param capacity specified capacity, > 0 ++ * @param other The specified map. ++ */ ++ public SWMRLong2ObjectHashTable(final int capacity, final SWMRLong2ObjectHashTable other) { ++ this(capacity, DEFAULT_LOAD_FACTOR, other); ++ } ++ ++ /** ++ * Constructs this map with a min capacity of the specified capacity or the specified map's size, whichever is larger, and ++ * with the specified load factor. ++ * All of the specified map's entries are copied into this map. ++ * @param capacity specified capacity, > 0 ++ * @param loadFactor specified load factor, > 0 && finite ++ * @param other The specified map. ++ */ ++ public SWMRLong2ObjectHashTable(final int capacity, final float loadFactor, final SWMRLong2ObjectHashTable other) { ++ this(Math.max(Validate.notNull(other, "Null map").size(), capacity), loadFactor); ++ this.putAll(other); ++ } ++ ++ public final float getLoadFactor() { ++ return this.loadFactor; ++ } ++ ++ protected static int getCapacityFor(final int capacity) { ++ if (capacity <= 0) { ++ throw new IllegalArgumentException("Invalid capacity: " + capacity); ++ } ++ if (capacity >= MAXIMUM_CAPACITY) { ++ return MAXIMUM_CAPACITY; ++ } ++ return IntegerUtil.roundCeilLog2(capacity); ++ } ++ ++ /** Callers must still use acquire when reading the value of the entry. */ ++ protected final TableEntry getEntryForOpaque(final long key) { ++ final int hash = SWMRLong2ObjectHashTable.getHash(key); ++ final TableEntry[] table = this.getTableAcquire(); ++ ++ for (TableEntry curr = ArrayUtil.getOpaque(table, hash & (table.length - 1)); curr != null; curr = curr.getNextOpaque()) { ++ if (key == curr.key) { ++ return curr; ++ } ++ } ++ ++ return null; ++ } ++ ++ protected final TableEntry getEntryForPlain(final long key) { ++ final int hash = SWMRLong2ObjectHashTable.getHash(key); ++ final TableEntry[] table = this.getTablePlain(); ++ ++ for (TableEntry curr = table[hash & (table.length - 1)]; curr != null; curr = curr.getNextPlain()) { ++ if (key == curr.key) { ++ return curr; ++ } ++ } ++ ++ return null; ++ } ++ ++ /* MT-Safe */ ++ ++ /** must be deterministic given a key */ ++ protected static int getHash(final long key) { ++ return (int)it.unimi.dsi.fastutil.HashCommon.mix(key); ++ } ++ ++ // rets -1 if capacity*loadFactor is too large ++ protected static int getTargetCapacity(final int capacity, final float loadFactor) { ++ final double ret = (double)capacity * (double)loadFactor; ++ if (Double.isInfinite(ret) || ret >= ((double)Integer.MAX_VALUE)) { ++ return -1; ++ } ++ ++ return (int)ret; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean equals(final Object obj) { ++ if (this == obj) { ++ return true; ++ } ++ /* Make no attempt to deal with concurrent modifications */ ++ if (!(obj instanceof SWMRLong2ObjectHashTable)) { ++ return false; ++ } ++ final SWMRLong2ObjectHashTable other = (SWMRLong2ObjectHashTable)obj; ++ ++ if (this.size() != other.size()) { ++ return false; ++ } ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ final V value = curr.getValueAcquire(); ++ ++ final Object otherValue = other.get(curr.key); ++ if (otherValue == null || (value != otherValue && value.equals(otherValue))) { ++ return false; ++ } ++ } ++ } ++ ++ return true; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public int hashCode() { ++ /* Make no attempt to deal with concurrent modifications */ ++ int hash = 0; ++ final TableEntry[] table = this.getTableAcquire(); ++ ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ hash += curr.hashCode(); ++ } ++ } ++ ++ return hash; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public String toString() { ++ final StringBuilder builder = new StringBuilder(64); ++ builder.append("SingleWriterMultiReaderHashMap:{"); ++ ++ this.forEach((final long key, final V value) -> { ++ builder.append("{key: \"").append(key).append("\", value: \"").append(value).append("\"}"); ++ }); ++ ++ return builder.append('}').toString(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public SWMRLong2ObjectHashTable clone() { ++ return new SWMRLong2ObjectHashTable<>(this.getTableAcquire().length, this.loadFactor, this); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public void forEach(final Consumer> action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ action.accept(curr); ++ } ++ } ++ } ++ ++ @FunctionalInterface ++ public static interface BiLongObjectConsumer { ++ public void accept(final long key, final V value); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public void forEach(final BiLongObjectConsumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ final V value = curr.getValueAcquire(); ++ ++ action.accept(curr.key, value); ++ } ++ } ++ } ++ ++ /** ++ * Provides the specified consumer with all keys contained within this map. ++ * @param action The specified consumer. ++ */ ++ public void forEachKey(final LongConsumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ action.accept(curr.key); ++ } ++ } ++ } ++ ++ /** ++ * Provides the specified consumer with all values contained within this map. Equivalent to {@code map.values().forEach(Consumer)}. ++ * @param action The specified consumer. ++ */ ++ public void forEachValue(final Consumer action) { ++ Validate.notNull(action, "Null action"); ++ ++ final TableEntry[] table = this.getTableAcquire(); ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry curr = ArrayUtil.getOpaque(table, i); curr != null; curr = curr.getNextOpaque()) { ++ final V value = curr.getValueAcquire(); ++ ++ action.accept(value); ++ } ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public V get(final long key) { ++ final TableEntry entry = this.getEntryForOpaque(key); ++ return entry == null ? null : entry.getValueAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public boolean containsKey(final long key) { ++ // note: we need to use getValueAcquire, so that the reads from this map are ordered by acquire semantics ++ return this.get(key) != null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public V getOrDefault(final long key, final V defaultValue) { ++ final TableEntry entry = this.getEntryForOpaque(key); ++ ++ return entry == null ? defaultValue : entry.getValueAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public int size() { ++ return this.getSizeAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public boolean isEmpty() { ++ return this.getSizeAcquire() == 0; ++ } ++ ++ /* Non-MT-Safe */ ++ ++ protected int threshold; ++ ++ protected final void checkResize(final int minCapacity) { ++ if (minCapacity <= this.threshold || this.threshold < 0) { ++ return; ++ } ++ ++ final TableEntry[] table = this.getTablePlain(); ++ int newCapacity = minCapacity >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : IntegerUtil.roundCeilLog2(minCapacity); ++ if (newCapacity < 0) { ++ newCapacity = MAXIMUM_CAPACITY; ++ } ++ if (newCapacity <= table.length) { ++ if (newCapacity == MAXIMUM_CAPACITY) { ++ return; ++ } ++ newCapacity = table.length << 1; ++ } ++ ++ //noinspection unchecked ++ final TableEntry[] newTable = new TableEntry[newCapacity]; ++ final int indexMask = newCapacity - 1; ++ ++ for (int i = 0, len = table.length; i < len; ++i) { ++ for (TableEntry entry = table[i]; entry != null; entry = entry.getNextPlain()) { ++ final long key = entry.key; ++ final int hash = SWMRLong2ObjectHashTable.getHash(key); ++ final int index = hash & indexMask; ++ ++ /* we need to create a new entry since there could be reading threads */ ++ final TableEntry insert = new TableEntry<>(key, entry.getValuePlain()); ++ ++ final TableEntry prev = newTable[index]; ++ ++ newTable[index] = insert; ++ insert.setNextPlain(prev); ++ } ++ } ++ ++ if (newCapacity == MAXIMUM_CAPACITY) { ++ this.threshold = -1; /* No more resizing */ ++ } else { ++ this.threshold = getTargetCapacity(newCapacity, this.loadFactor); ++ } ++ this.setTableRelease(newTable); /* use release to publish entries in table */ ++ } ++ ++ protected final int addToSize(final int num) { ++ final int newSize = this.getSizePlain() + num; ++ ++ this.setSizeOpaque(newSize); ++ this.checkResize(newSize); ++ ++ return newSize; ++ } ++ ++ protected final int removeFromSize(final int num) { ++ final int newSize = this.getSizePlain() - num; ++ ++ this.setSizeOpaque(newSize); ++ ++ return newSize; ++ } ++ ++ protected final V put(final long key, final V value, final boolean onlyIfAbsent) { ++ final TableEntry[] table = this.getTablePlain(); ++ final int hash = SWMRLong2ObjectHashTable.getHash(key); ++ final int index = hash & (table.length - 1); ++ ++ final TableEntry head = table[index]; ++ if (head == null) { ++ final TableEntry insert = new TableEntry<>(key, value); ++ ArrayUtil.setRelease(table, index, insert); ++ this.addToSize(1); ++ return null; ++ } ++ ++ for (TableEntry curr = head;;) { ++ if (key == curr.key) { ++ if (onlyIfAbsent) { ++ return curr.getValuePlain(); ++ } ++ ++ final V currVal = curr.getValuePlain(); ++ curr.setValueRelease(value); ++ return currVal; ++ } ++ ++ final TableEntry next = curr.getNextPlain(); ++ if (next != null) { ++ curr = next; ++ continue; ++ } ++ ++ final TableEntry insert = new TableEntry<>(key, value); ++ ++ curr.setNextRelease(insert); ++ this.addToSize(1); ++ return null; ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public V put(final long key, final V value) { ++ Validate.notNull(value, "Null value"); ++ ++ return this.put(key, value, false); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public V putIfAbsent(final long key, final V value) { ++ Validate.notNull(value, "Null value"); ++ ++ return this.put(key, value, true); ++ } ++ ++ protected final V remove(final long key, final int hash) { ++ final TableEntry[] table = this.getTablePlain(); ++ final int index = (table.length - 1) & hash; ++ ++ final TableEntry head = table[index]; ++ if (head == null) { ++ return null; ++ } ++ ++ if (head.key == key) { ++ ArrayUtil.setRelease(table, index, head.getNextPlain()); ++ this.removeFromSize(1); ++ ++ return head.getValuePlain(); ++ } ++ ++ for (TableEntry curr = head.getNextPlain(), prev = head; curr != null; prev = curr, curr = curr.getNextPlain()) { ++ if (key == curr.key) { ++ prev.setNextRelease(curr.getNextPlain()); ++ this.removeFromSize(1); ++ ++ return curr.getValuePlain(); ++ } ++ } ++ ++ return null; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public V remove(final long key) { ++ return this.remove(key, SWMRLong2ObjectHashTable.getHash(key)); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public void putAll(final SWMRLong2ObjectHashTable map) { ++ Validate.notNull(map, "Null map"); ++ ++ final int size = map.size(); ++ this.checkResize(Math.max(this.getSizePlain() + size/2, size)); /* preemptively resize */ ++ map.forEach(this::put); ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

++ * This call is non-atomic and the order that which entries are removed is undefined. The clear operation itself ++ * is release ordered, that is, after the clear operation is performed a release fence is performed. ++ *

++ */ ++ public void clear() { ++ Arrays.fill(this.getTablePlain(), null); ++ this.setSizeRelease(0); ++ } ++ ++ public static final class TableEntry { ++ ++ protected final long key; ++ protected V value; ++ ++ protected TableEntry next; ++ ++ protected static final VarHandle VALUE_HANDLE = ConcurrentUtil.getVarHandle(TableEntry.class, "value", Object.class); ++ protected static final VarHandle NEXT_HANDLE = ConcurrentUtil.getVarHandle(TableEntry.class, "next", TableEntry.class); ++ ++ /* value */ ++ ++ protected final V getValuePlain() { ++ //noinspection unchecked ++ return (V)VALUE_HANDLE.get(this); ++ } ++ ++ protected final V getValueAcquire() { ++ //noinspection unchecked ++ return (V)VALUE_HANDLE.getAcquire(this); ++ } ++ ++ protected final void setValueRelease(final V to) { ++ VALUE_HANDLE.setRelease(this, to); ++ } ++ ++ /* next */ ++ ++ protected final TableEntry getNextPlain() { ++ //noinspection unchecked ++ return (TableEntry)NEXT_HANDLE.get(this); ++ } ++ ++ protected final TableEntry getNextOpaque() { ++ //noinspection unchecked ++ return (TableEntry)NEXT_HANDLE.getOpaque(this); ++ } ++ ++ protected final void setNextPlain(final TableEntry next) { ++ NEXT_HANDLE.set(this, next); ++ } ++ ++ protected final void setNextRelease(final TableEntry next) { ++ NEXT_HANDLE.setRelease(this, next); ++ } ++ ++ protected TableEntry(final long key, final V value) { ++ this.key = key; ++ this.value = value; ++ } ++ ++ public long getKey() { ++ return this.key; ++ } ++ ++ public V getValue() { ++ return this.getValueAcquire(); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public V setValue(final V value) { ++ if (value == null) { ++ throw new NullPointerException(); ++ } ++ ++ final V curr = this.getValuePlain(); ++ ++ this.setValueRelease(value); ++ return curr; ++ } ++ ++ protected static int hash(final long key, final Object value) { ++ return SWMRLong2ObjectHashTable.getHash(key) ^ (value == null ? 0 : value.hashCode()); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public int hashCode() { ++ return hash(this.key, this.getValueAcquire()); ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean equals(final Object obj) { ++ if (this == obj) { ++ return true; ++ } ++ ++ if (!(obj instanceof TableEntry)) { ++ return false; ++ } ++ final TableEntry other = (TableEntry)obj; ++ final long otherKey = other.getKey(); ++ final long thisKey = this.getKey(); ++ final Object otherValue = other.getValueAcquire(); ++ final V thisVal = this.getValueAcquire(); ++ return (thisKey == otherKey) && (thisVal == otherValue || thisVal.equals(otherValue)); ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/util/ArrayUtil.java b/src/main/java/ca/spottedleaf/concurrentutil/util/ArrayUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ebb1ab06165addb173fea4d295001fe37f4e79d3 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/util/ArrayUtil.java +@@ -0,0 +1,816 @@ ++package ca.spottedleaf.concurrentutil.util; ++ ++import java.lang.invoke.VarHandle; ++ ++public final class ArrayUtil { ++ ++ public static final VarHandle BOOLEAN_ARRAY_HANDLE = ConcurrentUtil.getArrayHandle(boolean[].class); ++ ++ public static final VarHandle BYTE_ARRAY_HANDLE = ConcurrentUtil.getArrayHandle(byte[].class); ++ ++ public static final VarHandle SHORT_ARRAY_HANDLE = ConcurrentUtil.getArrayHandle(short[].class); ++ ++ public static final VarHandle INT_ARRAY_HANDLE = ConcurrentUtil.getArrayHandle(int[].class); ++ ++ public static final VarHandle LONG_ARRAY_HANDLE = ConcurrentUtil.getArrayHandle(long[].class); ++ ++ public static final VarHandle OBJECT_ARRAY_HANDLE = ConcurrentUtil.getArrayHandle(Object[].class); ++ ++ private ArrayUtil() { ++ throw new RuntimeException(); ++ } ++ ++ /* byte array */ ++ ++ public static byte getPlain(final byte[] array, final int index) { ++ return (byte)BYTE_ARRAY_HANDLE.get(array, index); ++ } ++ ++ public static byte getOpaque(final byte[] array, final int index) { ++ return (byte)BYTE_ARRAY_HANDLE.getOpaque(array, index); ++ } ++ ++ public static byte getAcquire(final byte[] array, final int index) { ++ return (byte)BYTE_ARRAY_HANDLE.getAcquire(array, index); ++ } ++ ++ public static byte getVolatile(final byte[] array, final int index) { ++ return (byte)BYTE_ARRAY_HANDLE.getVolatile(array, index); ++ } ++ ++ public static void setPlain(final byte[] array, final int index, final byte value) { ++ BYTE_ARRAY_HANDLE.set(array, index, value); ++ } ++ ++ public static void setOpaque(final byte[] array, final int index, final byte value) { ++ BYTE_ARRAY_HANDLE.setOpaque(array, index, value); ++ } ++ ++ public static void setRelease(final byte[] array, final int index, final byte value) { ++ BYTE_ARRAY_HANDLE.setRelease(array, index, value); ++ } ++ ++ public static void setVolatile(final byte[] array, final int index, final byte value) { ++ BYTE_ARRAY_HANDLE.setVolatile(array, index, value); ++ } ++ ++ public static void setVolatileContended(final byte[] array, final int index, final byte param) { ++ int failures = 0; ++ ++ for (byte curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return; ++ } ++ } ++ } ++ ++ public static byte compareAndExchangeVolatile(final byte[] array, final int index, final byte expect, final byte update) { ++ return (byte)BYTE_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static byte getAndAddVolatile(final byte[] array, final int index, final byte param) { ++ return (byte)BYTE_ARRAY_HANDLE.getAndAdd(array, index, param); ++ } ++ ++ public static byte getAndAndVolatile(final byte[] array, final int index, final byte param) { ++ return (byte)BYTE_ARRAY_HANDLE.getAndBitwiseAnd(array, index, param); ++ } ++ ++ public static byte getAndOrVolatile(final byte[] array, final int index, final byte param) { ++ return (byte)BYTE_ARRAY_HANDLE.getAndBitwiseOr(array, index, param); ++ } ++ ++ public static byte getAndXorVolatile(final byte[] array, final int index, final byte param) { ++ return (byte)BYTE_ARRAY_HANDLE.getAndBitwiseXor(array, index, param); ++ } ++ ++ public static byte getAndSetVolatile(final byte[] array, final int index, final byte param) { ++ return (byte)BYTE_ARRAY_HANDLE.getAndSet(array, index, param); ++ } ++ ++ public static byte compareAndExchangeVolatileContended(final byte[] array, final int index, final byte expect, final byte update) { ++ return (byte)BYTE_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static byte getAndAddVolatileContended(final byte[] array, final int index, final byte param) { ++ int failures = 0; ++ ++ for (byte curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (byte) (curr + param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static byte getAndAndVolatileContended(final byte[] array, final int index, final byte param) { ++ int failures = 0; ++ ++ for (byte curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (byte) (curr & param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static byte getAndOrVolatileContended(final byte[] array, final int index, final byte param) { ++ int failures = 0; ++ ++ for (byte curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (byte) (curr | param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static byte getAndXorVolatileContended(final byte[] array, final int index, final byte param) { ++ int failures = 0; ++ ++ for (byte curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (byte) (curr ^ param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static byte getAndSetVolatileContended(final byte[] array, final int index, final byte param) { ++ int failures = 0; ++ ++ for (byte curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return curr; ++ } ++ } ++ } ++ ++ /* short array */ ++ ++ public static short getPlain(final short[] array, final int index) { ++ return (short)SHORT_ARRAY_HANDLE.get(array, index); ++ } ++ ++ public static short getOpaque(final short[] array, final int index) { ++ return (short)SHORT_ARRAY_HANDLE.getOpaque(array, index); ++ } ++ ++ public static short getAcquire(final short[] array, final int index) { ++ return (short)SHORT_ARRAY_HANDLE.getAcquire(array, index); ++ } ++ ++ public static short getVolatile(final short[] array, final int index) { ++ return (short)SHORT_ARRAY_HANDLE.getVolatile(array, index); ++ } ++ ++ public static void setPlain(final short[] array, final int index, final short value) { ++ SHORT_ARRAY_HANDLE.set(array, index, value); ++ } ++ ++ public static void setOpaque(final short[] array, final int index, final short value) { ++ SHORT_ARRAY_HANDLE.setOpaque(array, index, value); ++ } ++ ++ public static void setRelease(final short[] array, final int index, final short value) { ++ SHORT_ARRAY_HANDLE.setRelease(array, index, value); ++ } ++ ++ public static void setVolatile(final short[] array, final int index, final short value) { ++ SHORT_ARRAY_HANDLE.setVolatile(array, index, value); ++ } ++ ++ public static void setVolatileContended(final short[] array, final int index, final short param) { ++ int failures = 0; ++ ++ for (short curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return; ++ } ++ } ++ } ++ ++ public static short compareAndExchangeVolatile(final short[] array, final int index, final short expect, final short update) { ++ return (short)SHORT_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static short getAndAddVolatile(final short[] array, final int index, final short param) { ++ return (short)SHORT_ARRAY_HANDLE.getAndAdd(array, index, param); ++ } ++ ++ public static short getAndAndVolatile(final short[] array, final int index, final short param) { ++ return (short)SHORT_ARRAY_HANDLE.getAndBitwiseAnd(array, index, param); ++ } ++ ++ public static short getAndOrVolatile(final short[] array, final int index, final short param) { ++ return (short)SHORT_ARRAY_HANDLE.getAndBitwiseOr(array, index, param); ++ } ++ ++ public static short getAndXorVolatile(final short[] array, final int index, final short param) { ++ return (short)SHORT_ARRAY_HANDLE.getAndBitwiseXor(array, index, param); ++ } ++ ++ public static short getAndSetVolatile(final short[] array, final int index, final short param) { ++ return (short)SHORT_ARRAY_HANDLE.getAndSet(array, index, param); ++ } ++ ++ public static short compareAndExchangeVolatileContended(final short[] array, final int index, final short expect, final short update) { ++ return (short)SHORT_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static short getAndAddVolatileContended(final short[] array, final int index, final short param) { ++ int failures = 0; ++ ++ for (short curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (short) (curr + param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static short getAndAndVolatileContended(final short[] array, final int index, final short param) { ++ int failures = 0; ++ ++ for (short curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (short) (curr & param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static short getAndOrVolatileContended(final short[] array, final int index, final short param) { ++ int failures = 0; ++ ++ for (short curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (short) (curr | param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static short getAndXorVolatileContended(final short[] array, final int index, final short param) { ++ int failures = 0; ++ ++ for (short curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (short) (curr ^ param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static short getAndSetVolatileContended(final short[] array, final int index, final short param) { ++ int failures = 0; ++ ++ for (short curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return curr; ++ } ++ } ++ } ++ ++ /* int array */ ++ ++ public static int getPlain(final int[] array, final int index) { ++ return (int)INT_ARRAY_HANDLE.get(array, index); ++ } ++ ++ public static int getOpaque(final int[] array, final int index) { ++ return (int)INT_ARRAY_HANDLE.getOpaque(array, index); ++ } ++ ++ public static int getAcquire(final int[] array, final int index) { ++ return (int)INT_ARRAY_HANDLE.getAcquire(array, index); ++ } ++ ++ public static int getVolatile(final int[] array, final int index) { ++ return (int)INT_ARRAY_HANDLE.getVolatile(array, index); ++ } ++ ++ public static void setPlain(final int[] array, final int index, final int value) { ++ INT_ARRAY_HANDLE.set(array, index, value); ++ } ++ ++ public static void setOpaque(final int[] array, final int index, final int value) { ++ INT_ARRAY_HANDLE.setOpaque(array, index, value); ++ } ++ ++ public static void setRelease(final int[] array, final int index, final int value) { ++ INT_ARRAY_HANDLE.setRelease(array, index, value); ++ } ++ ++ public static void setVolatile(final int[] array, final int index, final int value) { ++ INT_ARRAY_HANDLE.setVolatile(array, index, value); ++ } ++ ++ public static void setVolatileContended(final int[] array, final int index, final int param) { ++ int failures = 0; ++ ++ for (int curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return; ++ } ++ } ++ } ++ ++ public static int compareAndExchangeVolatile(final int[] array, final int index, final int expect, final int update) { ++ return (int)INT_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static int getAndAddVolatile(final int[] array, final int index, final int param) { ++ return (int)INT_ARRAY_HANDLE.getAndAdd(array, index, param); ++ } ++ ++ public static int getAndAndVolatile(final int[] array, final int index, final int param) { ++ return (int)INT_ARRAY_HANDLE.getAndBitwiseAnd(array, index, param); ++ } ++ ++ public static int getAndOrVolatile(final int[] array, final int index, final int param) { ++ return (int)INT_ARRAY_HANDLE.getAndBitwiseOr(array, index, param); ++ } ++ ++ public static int getAndXorVolatile(final int[] array, final int index, final int param) { ++ return (int)INT_ARRAY_HANDLE.getAndBitwiseXor(array, index, param); ++ } ++ ++ public static int getAndSetVolatile(final int[] array, final int index, final int param) { ++ return (int)INT_ARRAY_HANDLE.getAndSet(array, index, param); ++ } ++ ++ public static int compareAndExchangeVolatileContended(final int[] array, final int index, final int expect, final int update) { ++ return (int)INT_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static int getAndAddVolatileContended(final int[] array, final int index, final int param) { ++ int failures = 0; ++ ++ for (int curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (int) (curr + param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static int getAndAndVolatileContended(final int[] array, final int index, final int param) { ++ int failures = 0; ++ ++ for (int curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (int) (curr & param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static int getAndOrVolatileContended(final int[] array, final int index, final int param) { ++ int failures = 0; ++ ++ for (int curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (int) (curr | param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static int getAndXorVolatileContended(final int[] array, final int index, final int param) { ++ int failures = 0; ++ ++ for (int curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (int) (curr ^ param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static int getAndSetVolatileContended(final int[] array, final int index, final int param) { ++ int failures = 0; ++ ++ for (int curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return curr; ++ } ++ } ++ } ++ ++ /* long array */ ++ ++ public static long getPlain(final long[] array, final int index) { ++ return (long)LONG_ARRAY_HANDLE.get(array, index); ++ } ++ ++ public static long getOpaque(final long[] array, final int index) { ++ return (long)LONG_ARRAY_HANDLE.getOpaque(array, index); ++ } ++ ++ public static long getAcquire(final long[] array, final int index) { ++ return (long)LONG_ARRAY_HANDLE.getAcquire(array, index); ++ } ++ ++ public static long getVolatile(final long[] array, final int index) { ++ return (long)LONG_ARRAY_HANDLE.getVolatile(array, index); ++ } ++ ++ public static void setPlain(final long[] array, final int index, final long value) { ++ LONG_ARRAY_HANDLE.set(array, index, value); ++ } ++ ++ public static void setOpaque(final long[] array, final int index, final long value) { ++ LONG_ARRAY_HANDLE.setOpaque(array, index, value); ++ } ++ ++ public static void setRelease(final long[] array, final int index, final long value) { ++ LONG_ARRAY_HANDLE.setRelease(array, index, value); ++ } ++ ++ public static void setVolatile(final long[] array, final int index, final long value) { ++ LONG_ARRAY_HANDLE.setVolatile(array, index, value); ++ } ++ ++ public static void setVolatileContended(final long[] array, final int index, final long param) { ++ int failures = 0; ++ ++ for (long curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return; ++ } ++ } ++ } ++ ++ public static long compareAndExchangeVolatile(final long[] array, final int index, final long expect, final long update) { ++ return (long)LONG_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static long getAndAddVolatile(final long[] array, final int index, final long param) { ++ return (long)LONG_ARRAY_HANDLE.getAndAdd(array, index, param); ++ } ++ ++ public static long getAndAndVolatile(final long[] array, final int index, final long param) { ++ return (long)LONG_ARRAY_HANDLE.getAndBitwiseAnd(array, index, param); ++ } ++ ++ public static long getAndOrVolatile(final long[] array, final int index, final long param) { ++ return (long)LONG_ARRAY_HANDLE.getAndBitwiseOr(array, index, param); ++ } ++ ++ public static long getAndXorVolatile(final long[] array, final int index, final long param) { ++ return (long)LONG_ARRAY_HANDLE.getAndBitwiseXor(array, index, param); ++ } ++ ++ public static long getAndSetVolatile(final long[] array, final int index, final long param) { ++ return (long)LONG_ARRAY_HANDLE.getAndSet(array, index, param); ++ } ++ ++ public static long compareAndExchangeVolatileContended(final long[] array, final int index, final long expect, final long update) { ++ return (long)LONG_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static long getAndAddVolatileContended(final long[] array, final int index, final long param) { ++ int failures = 0; ++ ++ for (long curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (long) (curr + param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static long getAndAndVolatileContended(final long[] array, final int index, final long param) { ++ int failures = 0; ++ ++ for (long curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (long) (curr & param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static long getAndOrVolatileContended(final long[] array, final int index, final long param) { ++ int failures = 0; ++ ++ for (long curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (long) (curr | param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static long getAndXorVolatileContended(final long[] array, final int index, final long param) { ++ int failures = 0; ++ ++ for (long curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (long) (curr ^ param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static long getAndSetVolatileContended(final long[] array, final int index, final long param) { ++ int failures = 0; ++ ++ for (long curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return curr; ++ } ++ } ++ } ++ ++ /* boolean array */ ++ ++ public static boolean getPlain(final boolean[] array, final int index) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.get(array, index); ++ } ++ ++ public static boolean getOpaque(final boolean[] array, final int index) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.getOpaque(array, index); ++ } ++ ++ public static boolean getAcquire(final boolean[] array, final int index) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.getAcquire(array, index); ++ } ++ ++ public static boolean getVolatile(final boolean[] array, final int index) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.getVolatile(array, index); ++ } ++ ++ public static void setPlain(final boolean[] array, final int index, final boolean value) { ++ BOOLEAN_ARRAY_HANDLE.set(array, index, value); ++ } ++ ++ public static void setOpaque(final boolean[] array, final int index, final boolean value) { ++ BOOLEAN_ARRAY_HANDLE.setOpaque(array, index, value); ++ } ++ ++ public static void setRelease(final boolean[] array, final int index, final boolean value) { ++ BOOLEAN_ARRAY_HANDLE.setRelease(array, index, value); ++ } ++ ++ public static void setVolatile(final boolean[] array, final int index, final boolean value) { ++ BOOLEAN_ARRAY_HANDLE.setVolatile(array, index, value); ++ } ++ ++ public static void setVolatileContended(final boolean[] array, final int index, final boolean param) { ++ int failures = 0; ++ ++ for (boolean curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return; ++ } ++ } ++ } ++ ++ public static boolean compareAndExchangeVolatile(final boolean[] array, final int index, final boolean expect, final boolean update) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static boolean getAndOrVolatile(final boolean[] array, final int index, final boolean param) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.getAndBitwiseOr(array, index, param); ++ } ++ ++ public static boolean getAndXorVolatile(final boolean[] array, final int index, final boolean param) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.getAndBitwiseXor(array, index, param); ++ } ++ ++ public static boolean getAndSetVolatile(final boolean[] array, final int index, final boolean param) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.getAndSet(array, index, param); ++ } ++ ++ public static boolean compareAndExchangeVolatileContended(final boolean[] array, final int index, final boolean expect, final boolean update) { ++ return (boolean)BOOLEAN_ARRAY_HANDLE.compareAndExchange(array, index, expect, update); ++ } ++ ++ public static boolean getAndAndVolatileContended(final boolean[] array, final int index, final boolean param) { ++ int failures = 0; ++ ++ for (boolean curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (boolean) (curr & param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static boolean getAndOrVolatileContended(final boolean[] array, final int index, final boolean param) { ++ int failures = 0; ++ ++ for (boolean curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (boolean) (curr | param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static boolean getAndXorVolatileContended(final boolean[] array, final int index, final boolean param) { ++ int failures = 0; ++ ++ for (boolean curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, (boolean) (curr ^ param)))) { ++ return curr; ++ } ++ } ++ } ++ ++ public static boolean getAndSetVolatileContended(final boolean[] array, final int index, final boolean param) { ++ int failures = 0; ++ ++ for (boolean curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return curr; ++ } ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static T getPlain(final T[] array, final int index) { ++ final Object ret = OBJECT_ARRAY_HANDLE.get((Object[])array, index); ++ return (T)ret; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static T getOpaque(final T[] array, final int index) { ++ final Object ret = OBJECT_ARRAY_HANDLE.getOpaque((Object[])array, index); ++ return (T)ret; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static T getAcquire(final T[] array, final int index) { ++ final Object ret = OBJECT_ARRAY_HANDLE.getAcquire((Object[])array, index); ++ return (T)ret; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static T getVolatile(final T[] array, final int index) { ++ final Object ret = OBJECT_ARRAY_HANDLE.getVolatile((Object[])array, index); ++ return (T)ret; ++ } ++ ++ public static void setPlain(final T[] array, final int index, final T value) { ++ OBJECT_ARRAY_HANDLE.set((Object[])array, index, (Object)value); ++ } ++ ++ public static void setOpaque(final T[] array, final int index, final T value) { ++ OBJECT_ARRAY_HANDLE.setOpaque((Object[])array, index, (Object)value); ++ } ++ ++ public static void setRelease(final T[] array, final int index, final T value) { ++ OBJECT_ARRAY_HANDLE.setRelease((Object[])array, index, (Object)value); ++ } ++ ++ public static void setVolatile(final T[] array, final int index, final T value) { ++ OBJECT_ARRAY_HANDLE.setVolatile((Object[])array, index, (Object)value); ++ } ++ ++ public static void setVolatileContended(final T[] array, final int index, final T param) { ++ int failures = 0; ++ ++ for (T curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return; ++ } ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static T compareAndExchangeVolatile(final T[] array, final int index, final T expect, final T update) { ++ final Object ret = OBJECT_ARRAY_HANDLE.compareAndExchange((Object[])array, index, (Object)expect, (Object)update); ++ return (T)ret; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static T getAndSetVolatile(final T[] array, final int index, final T param) { ++ final Object ret = BYTE_ARRAY_HANDLE.getAndSet((Object[])array, index, (Object)param); ++ return (T)ret; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static T compareAndExchangeVolatileContended(final T[] array, final int index, final T expect, final T update) { ++ final Object ret = OBJECT_ARRAY_HANDLE.compareAndExchange((Object[])array, index, (Object)expect, (Object)update); ++ return (T)ret; ++ } ++ ++ public static T getAndSetVolatileContended(final T[] array, final int index, final T param) { ++ int failures = 0; ++ ++ for (T curr = getVolatile(array, index);;++failures) { ++ for (int i = 0; i < failures; ++i) { ++ ConcurrentUtil.backoff(); ++ } ++ ++ if (curr == (curr = compareAndExchangeVolatileContended(array, index, curr, param))) { ++ return curr; ++ } ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/util/CollectionUtil.java b/src/main/java/ca/spottedleaf/concurrentutil/util/CollectionUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9420b9822de99d3a31224642452835b0c986f7b4 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/util/CollectionUtil.java +@@ -0,0 +1,31 @@ ++package ca.spottedleaf.concurrentutil.util; ++ ++import java.util.Collection; ++ ++public final class CollectionUtil { ++ ++ public static String toString(final Collection collection, final String name) { ++ return CollectionUtil.toString(collection, name, new StringBuilder(name.length() + 128)).toString(); ++ } ++ ++ public static StringBuilder toString(final Collection collection, final String name, final StringBuilder builder) { ++ builder.append(name).append("{elements={"); ++ ++ boolean first = true; ++ ++ for (final Object element : collection) { ++ if (!first) { ++ builder.append(", "); ++ } ++ first = false; ++ ++ builder.append('"').append(element).append('"'); ++ } ++ ++ return builder.append("}}"); ++ } ++ ++ private CollectionUtil() { ++ throw new RuntimeException(); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/util/ConcurrentUtil.java b/src/main/java/ca/spottedleaf/concurrentutil/util/ConcurrentUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..23ae82e55696a7e2ff0e0f9609c0df6a48bb8d1d +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/util/ConcurrentUtil.java +@@ -0,0 +1,166 @@ ++package ca.spottedleaf.concurrentutil.util; ++ ++import java.lang.invoke.MethodHandles; ++import java.lang.invoke.VarHandle; ++import java.util.concurrent.locks.LockSupport; ++ ++public final class ConcurrentUtil { ++ ++ public static String genericToString(final Object object) { ++ return object == null ? "null" : object.getClass().getName() + ":" + object.hashCode() + ":" + object.toString(); ++ } ++ ++ public static void rethrow(Throwable exception) { ++ rethrow0(exception); ++ } ++ ++ private static void rethrow0(Throwable thr) throws T { ++ throw (T)thr; ++ } ++ ++ public static VarHandle getVarHandle(final Class lookIn, final String fieldName, final Class fieldType) { ++ try { ++ return MethodHandles.privateLookupIn(lookIn, MethodHandles.lookup()).findVarHandle(lookIn, fieldName, fieldType); ++ } catch (final Exception ex) { ++ throw new RuntimeException(ex); // unreachable ++ } ++ } ++ ++ public static VarHandle getStaticVarHandle(final Class lookIn, final String fieldName, final Class fieldType) { ++ try { ++ return MethodHandles.privateLookupIn(lookIn, MethodHandles.lookup()).findStaticVarHandle(lookIn, fieldName, fieldType); ++ } catch (final Exception ex) { ++ throw new RuntimeException(ex); // unreachable ++ } ++ } ++ ++ /** ++ * Non-exponential backoff algorithm to use in lightly contended areas. ++ * @see ConcurrentUtil#exponentiallyBackoffSimple(long) ++ * @see ConcurrentUtil#exponentiallyBackoffComplex(long) ++ */ ++ public static void backoff() { ++ Thread.onSpinWait(); ++ } ++ ++ /** ++ * Backoff algorithm to use for a short held lock (i.e compareAndExchange operation). Generally this should not be ++ * used when a thread can block another thread. Instead, use {@link ConcurrentUtil#exponentiallyBackoffComplex(long)}. ++ * @param counter The current counter. ++ * @return The counter plus 1. ++ * @see ConcurrentUtil#backoff() ++ * @see ConcurrentUtil#exponentiallyBackoffComplex(long) ++ */ ++ public static long exponentiallyBackoffSimple(final long counter) { ++ for (long i = 0; i < counter; ++i) { ++ backoff(); ++ } ++ return counter + 1L; ++ } ++ ++ /** ++ * Backoff algorithm to use for a lock that can block other threads (i.e if another thread contending with this thread ++ * can be thrown off the scheduler). This lock should not be used for simple locks such as compareAndExchange. ++ * @param counter The current counter. ++ * @return The next (if any) step in the backoff logic. ++ * @see ConcurrentUtil#backoff() ++ * @see ConcurrentUtil#exponentiallyBackoffSimple(long) ++ */ ++ public static long exponentiallyBackoffComplex(final long counter) { ++ // TODO experimentally determine counters ++ if (counter < 100L) { ++ return exponentiallyBackoffSimple(counter); ++ } ++ if (counter < 1_200L) { ++ Thread.yield(); ++ LockSupport.parkNanos(1_000L); ++ return counter + 1L; ++ } ++ // scale 0.1ms (100us) per failure ++ Thread.yield(); ++ LockSupport.parkNanos(100_000L * counter); ++ return counter + 1; ++ } ++ ++ /** ++ * Simple exponential backoff that will linearly increase the time per failure, according to the scale. ++ * @param counter The current failure counter. ++ * @param scale Time per failure, in ns. ++ * @param max The maximum time to wait for, in ns. ++ * @return The next counter. ++ */ ++ public static long linearLongBackoff(long counter, final long scale, long max) { ++ counter = Math.min(Long.MAX_VALUE, counter + 1); // prevent overflow ++ max = Math.max(0, max); ++ ++ if (scale <= 0L) { ++ return counter; ++ } ++ ++ long time = scale * counter; ++ ++ if (time > max || time / scale != counter) { ++ time = max; ++ } ++ ++ boolean interrupted = Thread.interrupted(); ++ if (time > 1_000_000L) { // 1ms ++ Thread.yield(); ++ } ++ LockSupport.parkNanos(time); ++ if (interrupted) { ++ Thread.currentThread().interrupt(); ++ } ++ return counter; ++ } ++ ++ /** ++ * Simple exponential backoff that will linearly increase the time per failure, according to the scale. ++ * @param counter The current failure counter. ++ * @param scale Time per failure, in ns. ++ * @param max The maximum time to wait for, in ns. ++ * @param deadline The deadline in ns. Deadline time source: {@link System#nanoTime()}. ++ * @return The next counter. ++ */ ++ public static long linearLongBackoffDeadline(long counter, final long scale, long max, long deadline) { ++ counter = Math.min(Long.MAX_VALUE, counter + 1); // prevent overflow ++ max = Math.max(0, max); ++ ++ if (scale <= 0L) { ++ return counter; ++ } ++ ++ long time = scale * counter; ++ ++ // check overflow ++ if (time / scale != counter) { ++ // overflew ++ --counter; ++ time = max; ++ } else if (time > max) { ++ time = max; ++ } ++ ++ final long currTime = System.nanoTime(); ++ final long diff = deadline - currTime; ++ if (diff <= 0) { ++ return counter; ++ } ++ if (diff <= 1_500_000L) { // 1.5ms ++ time = 100_000L; // 100us ++ } else if (time > 1_000_000L) { // 1ms ++ Thread.yield(); ++ } ++ ++ boolean interrupted = Thread.interrupted(); ++ LockSupport.parkNanos(time); ++ if (interrupted) { ++ Thread.currentThread().interrupt(); ++ } ++ return counter; ++ } ++ ++ public static VarHandle getArrayHandle(final Class type) { ++ return MethodHandles.arrayElementVarHandle(type); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/concurrentutil/util/Validate.java b/src/main/java/ca/spottedleaf/concurrentutil/util/Validate.java +new file mode 100644 +index 0000000000000000000000000000000000000000..382177d0d162fa3139c9078a873ce2504a2b17b2 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/concurrentutil/util/Validate.java +@@ -0,0 +1,28 @@ ++package ca.spottedleaf.concurrentutil.util; ++ ++public final class Validate { ++ ++ public static T notNull(final T obj) { ++ if (obj == null) { ++ throw new NullPointerException(); ++ } ++ return obj; ++ } ++ ++ public static T notNull(final T obj, final String msgIfNull) { ++ if (obj == null) { ++ throw new NullPointerException(msgIfNull); ++ } ++ return obj; ++ } ++ ++ public static void arrayBounds(final int off, final int len, final int arrayLength, final String msgPrefix) { ++ if (off < 0 || len < 0 || (arrayLength - off) < len) { ++ throw new ArrayIndexOutOfBoundsException(msgPrefix + ": off: " + off + ", len: " + len + ", array length: " + arrayLength); ++ } ++ } ++ ++ private Validate() { ++ throw new RuntimeException(); ++ } ++} diff --git a/patches/server/0006-CB-fixes.patch b/patches/server/0007-CB-fixes.patch similarity index 97% rename from patches/server/0006-CB-fixes.patch rename to patches/server/0007-CB-fixes.patch index b5c9b287e2..e0daaa9d40 100644 --- a/patches/server/0006-CB-fixes.patch +++ b/patches/server/0007-CB-fixes.patch @@ -17,7 +17,7 @@ Subject: [PATCH] CB fixes Co-authored-by: Spottedleaf diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 1a23437b9fa17846fd28163ae930d21a6bb00138..4f1e8d36c363eb74e8f1e593f35a7bb8550f8918 100644 +index bbdde701a16480b0b4b29e8fb6b5b5d987db0ce3..aa396df025115c7fd866cbc63a44c2c17abfde84 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -293,7 +293,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -67,7 +67,7 @@ index 9998e1c94b72b90dd3ba4bcce1b4b3653b9b1b2b..963ad3ce1ef83888ae1537ff01accdbb this.registryAccess = registryManager; this.structureTemplateManager = structureTemplateManager; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 3620b8a76b5c13d33ec32e4a0d7fc7fa7290f220..5550dbea555a99ee1612609093292db79a625c94 100644 +index 7c3d02a8a3bac227692ad2349981bc8c6c600341..4dd952faac05f553b28d1252296b0587369865f4 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2278,7 +2278,13 @@ public final class CraftServer implements Server { diff --git a/patches/server/0007-MC-Utils.patch b/patches/server/0008-MC-Utils.patch similarity index 90% rename from patches/server/0007-MC-Utils.patch rename to patches/server/0008-MC-Utils.patch index 271f065ad0..2d9248eb2a 100644 --- a/patches/server/0007-MC-Utils.patch +++ b/patches/server/0008-MC-Utils.patch @@ -4528,9 +4528,284 @@ index 207f1c1fc9d4451d27047bb8362bded8cd53e32f..021a26a6b1c258deffc26c035ab52a4e if (packet.isSkippable()) { throw new SkipPacketException(var10); } else { +diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java +new file mode 100644 +index 0000000000000000000000000000000000000000..83dc09f6526206690c474b50a7a6e71cefc93ab4 +--- /dev/null ++++ b/src/main/java/net/minecraft/server/ChunkSystem.java +@@ -0,0 +1,269 @@ ++package net.minecraft.server; ++ ++import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; ++import com.destroystokyo.paper.util.SneakyThrow; ++import com.mojang.datafixers.util.Either; ++import com.mojang.logging.LogUtils; ++import io.papermc.paper.util.CoordinateUtils; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.TicketType; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.LevelChunk; ++import org.bukkit.Bukkit; ++import org.slf4j.Logger; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.concurrent.CompletableFuture; ++import java.util.function.Consumer; ++ ++public final class ChunkSystem { ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ ++ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { ++ scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); ++ } ++ ++ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { ++ level.chunkSource.mainThreadProcessor.execute(run); ++ } ++ ++ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, ++ final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, ++ final Consumer onComplete) { ++ if (gen) { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ return; ++ } ++ scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { ++ if (chunk == null) { ++ onComplete.accept(null); ++ } else { ++ if (chunk.getStatus().isOrAfter(toStatus)) { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ } else { ++ onComplete.accept(null); ++ } ++ } ++ }); ++ } ++ ++ static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); ++ ++ private static long chunkLoadCounter = 0L; ++ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, ++ final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { ++ if (!Bukkit.isPrimaryThread()) { ++ scheduleChunkTask(level, chunkX, chunkZ, () -> { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ }, priority); ++ return; ++ } ++ ++ final int minLevel = 33 + ChunkStatus.getDistance(toStatus); ++ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; ++ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ level.chunkSource.runDistanceManagerUpdates(); ++ ++ final Consumer loadCallback = (final ChunkAccess chunk) -> { ++ try { ++ if (onComplete != null) { ++ onComplete.accept(chunk); ++ } ++ } catch (final ThreadDeath death) { ++ throw death; ++ } catch (final Throwable thr) { ++ LOGGER.error("Exception handling chunk load callback", thr); ++ SneakyThrow.sneaky(thr); ++ } finally { ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); ++ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ } ++ }; ++ ++ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); ++ ++ if (holder == null || holder.getTicketLevel() > minLevel) { ++ loadCallback.accept(null); ++ return; ++ } ++ ++ final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); ++ ++ if (loadFuture.isDone()) { ++ loadCallback.accept(loadFuture.join().left().orElse(null)); ++ return; ++ } ++ ++ loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { ++ if (thr != null) { ++ loadCallback.accept(null); ++ return; ++ } ++ loadCallback.accept(either.left().orElse(null)); ++ }, (final Runnable r) -> { ++ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ }); ++ } ++ ++ public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, ++ final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, ++ final PrioritisedExecutor.Priority priority, final Consumer onComplete) { ++ if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { ++ throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); ++ } ++ ++ if (!Bukkit.isPrimaryThread()) { ++ scheduleChunkTask(level, chunkX, chunkZ, () -> { ++ scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ }, priority); ++ return; ++ } ++ ++ final int minLevel = 33 - (toStatus.ordinal() - 1); ++ final int radius = toStatus.ordinal() - 1; ++ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; ++ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ level.chunkSource.runDistanceManagerUpdates(); ++ ++ final Consumer loadCallback = (final LevelChunk chunk) -> { ++ try { ++ if (onComplete != null) { ++ onComplete.accept(chunk); ++ } ++ } catch (final ThreadDeath death) { ++ throw death; ++ } catch (final Throwable thr) { ++ LOGGER.error("Exception handling chunk load callback", thr); ++ SneakyThrow.sneaky(thr); ++ } finally { ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); ++ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ } ++ }; ++ ++ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); ++ ++ if (holder == null || holder.getTicketLevel() > minLevel) { ++ loadCallback.accept(null); ++ return; ++ } ++ ++ final CompletableFuture> tickingState; ++ switch (toStatus) { ++ case BORDER: { ++ tickingState = holder.getFullChunkFuture(); ++ break; ++ } ++ case TICKING: { ++ tickingState = holder.getTickingChunkFuture(); ++ break; ++ } ++ case ENTITY_TICKING: { ++ tickingState = holder.getEntityTickingChunkFuture(); ++ break; ++ } ++ default: { ++ throw new IllegalStateException("Cannot reach here"); ++ } ++ } ++ ++ if (tickingState.isDone()) { ++ loadCallback.accept(tickingState.join().left().orElse(null)); ++ return; ++ } ++ ++ tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { ++ if (thr != null) { ++ loadCallback.accept(null); ++ return; ++ } ++ loadCallback.accept(either.left().orElse(null)); ++ }, (final Runnable r) -> { ++ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ }); ++ } ++ ++ public static List getVisibleChunkHolders(final ServerLevel level) { ++ return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); ++ } ++ ++ public static List getUpdatingChunkHolders(final ServerLevel level) { ++ return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); ++ } ++ ++ public static int getVisibleChunkHolderCount(final ServerLevel level) { ++ return level.chunkSource.chunkMap.visibleChunkMap.size(); ++ } ++ ++ public static int getUpdatingChunkHolderCount(final ServerLevel level) { ++ return level.chunkSource.chunkMap.updatingChunkMap.size(); ++ } ++ ++ public static boolean hasAnyChunkHolders(final ServerLevel level) { ++ return getUpdatingChunkHolderCount(level) != 0; ++ } ++ ++ public static void onEntityPreAdd(final ServerLevel level, final Entity entity) { ++ ++ } ++ ++ public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { ++ final ChunkMap chunkMap = level.chunkSource.chunkMap; ++ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { ++ chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); ++ } ++ } ++ ++ public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { ++ final ChunkMap chunkMap = level.chunkSource.chunkMap; ++ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { ++ chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); ++ } ++ } ++ ++ public static void onChunkBorder(LevelChunk chunk, ChunkHolder holder) { ++ chunk.playerChunk = holder; ++ } ++ ++ public static void onChunkNotBorder(LevelChunk chunk, ChunkHolder holder) { ++ ++ } ++ ++ public static void onChunkTicking(LevelChunk chunk, ChunkHolder holder) { ++ chunk.level.getChunkSource().tickingChunks.add(chunk); ++ } ++ ++ public static void onChunkNotTicking(LevelChunk chunk, ChunkHolder holder) { ++ chunk.level.getChunkSource().tickingChunks.remove(chunk); ++ } ++ ++ public static void onChunkEntityTicking(LevelChunk chunk, ChunkHolder holder) { ++ chunk.level.getChunkSource().entityTickingChunks.add(chunk); ++ } ++ ++ public static void onChunkNotEntityTicking(LevelChunk chunk, ChunkHolder holder) { ++ chunk.level.getChunkSource().entityTickingChunks.remove(chunk); ++ } ++ ++ private ChunkSystem() { ++ throw new RuntimeException(); ++ } ++} diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java new file mode 100644 -index 0000000000000000000000000000000000000000..9f292deee1b793d52b5774304318e940128d1e26 +index 0000000000000000000000000000000000000000..b310d51b7fe3e8cef0a450674725969fe1ce78a4 --- /dev/null +++ b/src/main/java/net/minecraft/server/MCUtil.java @@ -0,0 +1,511 @@ @@ -4845,7 +5120,7 @@ index 0000000000000000000000000000000000000000..9f292deee1b793d52b5774304318e940 + * @return + */ + public static void ensureMain(String reason, Runnable run) { -+ if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread) { ++ if (!isMainThread()) { + if (reason != null) { + new IllegalStateException("Asynchronous " + reason + "!").printStackTrace(); + } @@ -4870,7 +5145,7 @@ index 0000000000000000000000000000000000000000..9f292deee1b793d52b5774304318e940 + * @return + */ + public static T ensureMain(String reason, Supplier run) { -+ if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread) { ++ if (!isMainThread()) { + if (reason != null) { + new IllegalStateException("Asynchronous " + reason + "! Blocking thread until it returns ").printStackTrace(); + } @@ -5046,7 +5321,7 @@ index 0000000000000000000000000000000000000000..9f292deee1b793d52b5774304318e940 + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index b7d44c4a961ad3881bbf8f87f1595be79e3467f6..3aadba90ab32388b9e8ef96f182fa263c760f53b 100644 +index 80a3c56fb5e73c09c542b17aac952fb63081a662..805a1773d55e2551911e5b8e69052e23f630359b 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -282,6 +282,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop chunkToSave; @Nullable private final DebugBuffer chunkToSaveHistory; -@@ -73,6 +73,8 @@ public class ChunkHolder { +@@ -73,6 +73,18 @@ public class ChunkHolder { private boolean resendLight; private CompletableFuture pendingFullStateConfirmation; + private final ChunkMap chunkMap; // Paper ++ ++ // Paper start ++ public void onChunkAdd() { ++ ++ } ++ ++ public void onChunkRemove() { ++ ++ } ++ // Paper end + public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size()); this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -@@ -93,8 +95,23 @@ public class ChunkHolder { +@@ -93,8 +105,23 @@ public class ChunkHolder { this.queueLevel = this.oldTicketLevel; this.setTicketLevel(level); this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()]; @@ -5146,7 +5431,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 // CraftBukkit start public LevelChunk getFullChunkNow() { // Note: We use the oldTicketLevel for isLoaded checks. -@@ -119,20 +136,20 @@ public class ChunkHolder { +@@ -119,20 +146,20 @@ public class ChunkHolder { return ChunkHolder.getStatus(this.ticketLevel).isOrAfter(leastStatus) ? this.getFutureIfPresentUnchecked(leastStatus) : ChunkHolder.UNLOADED_CHUNK_FUTURE; } @@ -5171,7 +5456,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 CompletableFuture> completablefuture = this.getTickingChunkFuture(); Either either = (Either) completablefuture.getNow(null); // CraftBukkit - decompile error -@@ -140,7 +157,7 @@ public class ChunkHolder { +@@ -140,7 +167,7 @@ public class ChunkHolder { } @Nullable @@ -5180,7 +5465,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 CompletableFuture> completablefuture = this.getFullChunkFuture(); Either either = (Either) completablefuture.getNow(null); // CraftBukkit - decompile error -@@ -161,6 +178,21 @@ public class ChunkHolder { +@@ -161,6 +188,21 @@ public class ChunkHolder { return null; } @@ -5202,7 +5487,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 @Nullable public ChunkAccess getLastAvailable() { for (int i = ChunkHolder.CHUNK_STATUSES.size() - 1; i >= 0; --i) { -@@ -179,7 +211,7 @@ public class ChunkHolder { +@@ -179,7 +221,7 @@ public class ChunkHolder { return null; } @@ -5211,7 +5496,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 return this.chunkToSave; } -@@ -360,11 +392,11 @@ public class ChunkHolder { +@@ -360,11 +402,11 @@ public class ChunkHolder { return ChunkHolder.getFullChunkStatus(this.ticketLevel); } @@ -5225,7 +5510,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 return this.ticketLevel; } -@@ -453,14 +485,27 @@ public class ChunkHolder { +@@ -453,14 +495,31 @@ public class ChunkHolder { this.wasAccessibleSinceLastSave |= flag3; if (!flag2 && flag3) { @@ -5236,16 +5521,20 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 + this.fullChunkFuture.thenAccept(either -> { + final Optional left = either.left(); + if (left.isPresent() && ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { -+ // note: Here is a very good place to add callbacks to logic waiting on this. + LevelChunk fullChunk = either.left().get(); + ChunkHolder.this.isFullChunkReady = true; -+ fullChunk.playerChunk = ChunkHolder.this; ++ net.minecraft.server.ChunkSystem.onChunkBorder(fullChunk, this); + } + }); this.updateChunkToSave(this.fullChunkFuture, "full"); } if (flag2 && !flag3) { ++ // Paper start ++ if (this.isFullChunkReady) { ++ net.minecraft.server.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().left().get(), this); // Paper ++ } ++ // Paper end this.fullChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; + ++this.fullChunkCreateCount; // Paper - cache ticking ready status @@ -5253,7 +5542,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 } boolean flag4 = playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.TICKING); -@@ -469,12 +514,29 @@ public class ChunkHolder { +@@ -469,11 +528,25 @@ public class ChunkHolder { if (!flag4 && flag5) { this.tickingChunkFuture = chunkStorage.prepareTickingChunk(this); this.scheduleFullChunkPromotion(chunkStorage, this.tickingChunkFuture, executor, ChunkHolder.FullChunkStatus.TICKING); @@ -5262,9 +5551,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 + either.ifLeft(chunk -> { + // note: Here is a very good place to add callbacks to logic waiting on this. + ChunkHolder.this.isTickingReady = true; -+ // Paper start - ticking chunk set -+ ChunkHolder.this.chunkMap.level.getChunkSource().tickingChunks.add(chunk); -+ // Paper end - ticking chunk set ++ net.minecraft.server.ChunkSystem.onChunkTicking(chunk, this); + }); + }); + // Paper end @@ -5273,18 +5560,16 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 if (flag4 && !flag5) { - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); ++ // Paper start ++ if (this.isTickingReady) { ++ net.minecraft.server.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper ++ } ++ // Paper end + this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage this.tickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -+ // Paper start - ticking chunk set -+ LevelChunk chunkIfCached = this.getFullChunkNowUnchecked(); -+ if (chunkIfCached != null) { -+ this.chunkMap.level.getChunkSource().tickingChunks.remove(chunkIfCached); -+ } -+ // Paper end - ticking chunk set } - boolean flag6 = playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.ENTITY_TICKING); -@@ -487,12 +549,28 @@ public class ChunkHolder { +@@ -487,11 +560,24 @@ public class ChunkHolder { this.entityTickingChunkFuture = chunkStorage.prepareEntityTickingChunk(this.pos); this.scheduleFullChunkPromotion(chunkStorage, this.entityTickingChunkFuture, executor, ChunkHolder.FullChunkStatus.ENTITY_TICKING); @@ -5292,9 +5577,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 + this.entityTickingChunkFuture.thenAccept(either -> { + either.ifLeft(chunk -> { + ChunkHolder.this.isEntityTickingReady = true; -+ // Paper start - entity ticking chunk set -+ ChunkHolder.this.chunkMap.level.getChunkSource().entityTickingChunks.add(chunk); -+ // Paper end - entity ticking chunk set ++ net.minecraft.server.ChunkSystem.onChunkEntityTicking(chunk, this); + }); + }); + // Paper end @@ -5303,18 +5586,16 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 if (flag6 && !flag7) { - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); ++ // Paper start ++ if (this.isEntityTickingReady) { ++ net.minecraft.server.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); ++ } ++ // Paper end + this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage this.entityTickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -+ // Paper start - entity ticking chunk set -+ LevelChunk chunkIfCached = this.getFullChunkNowUnchecked(); -+ if (chunkIfCached != null) { -+ this.chunkMap.level.getChunkSource().entityTickingChunks.remove(chunkIfCached); -+ } -+ // Paper end - entity ticking chunk set } - if (!playerchunk_state1.isOrAfter(playerchunk_state)) { -@@ -608,4 +686,18 @@ public class ChunkHolder { +@@ -608,4 +694,18 @@ public class ChunkHolder { } }; } @@ -5334,7 +5615,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..90fcb4dc89643b1c706ea4554595a842 + // Paper end } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..6304a5b78ab1f3ef2478c7e2c493ebd760b5508e 100644 +index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70a8650f25 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -63,6 +63,7 @@ import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; @@ -5428,19 +5709,78 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..6304a5b78ab1f3ef2478c7e2c493ebd7 private CompletableFuture, ChunkHolder.ChunkLoadingFailure>> getChunkRangeFuture(ChunkPos centerChunk, int margin, IntFunction distanceToStatus) { List>> list = new ArrayList(); List list1 = new ArrayList(); -@@ -442,6 +505,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -398,9 +461,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + }; + + stringbuilder.append("Updating:").append(System.lineSeparator()); +- this.updatingChunkMap.values().forEach(consumer); ++ net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).forEach(consumer); // Paper + stringbuilder.append("Visible:").append(System.lineSeparator()); +- this.visibleChunkMap.values().forEach(consumer); ++ net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(consumer); // Paper + CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading"); + CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading"); + +@@ -442,8 +505,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider holder.setTicketLevel(level); } else { holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); + // Paper start -+ for (int index = 0, len = this.regionManagers.size(); index < len; ++index) { -+ this.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); -+ } ++ net.minecraft.server.ChunkSystem.onChunkHolderCreate(this.level, holder); + // Paper end } ++ // Paper start ++ holder.onChunkAdd(); ++ // Paper end this.updatingChunkMap.put(pos, holder); -@@ -559,7 +627,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.modified = true; + } +@@ -465,7 +534,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + protected void saveAllChunks(boolean flush) { + if (flush) { +- List list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); ++ List list = (List) net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper + MutableBoolean mutableboolean = new MutableBoolean(); + + do { +@@ -494,7 +563,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + }); + this.flushWorker(); + } else { +- this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded); ++ net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); + } + + } +@@ -513,7 +582,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + public boolean hasWork() { +- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); ++ return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || net.minecraft.server.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper + } + + private void processUnloads(BooleanSupplier shouldKeepTicking) { +@@ -524,6 +593,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); + + if (playerchunk != null) { ++ playerchunk.onChunkRemove(); // Paper + this.pendingUnloads.put(j, playerchunk); + this.modified = true; + ++i; +@@ -541,7 +611,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + int l = 0; +- ObjectIterator objectiterator = this.visibleChunkMap.values().iterator(); ++ Iterator objectiterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper + + while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { + if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { +@@ -559,7 +629,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (completablefuture1 != completablefuture) { this.scheduleUnload(pos, holder); } else { @@ -5448,26 +5788,66 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..6304a5b78ab1f3ef2478c7e2c493ebd7 + // Paper start + boolean removed; + if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -+ for (int index = 0, len = this.regionManagers.size(); index < len; ++index) { -+ this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); -+ } ++ net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); + // Paper end if (ichunkaccess instanceof LevelChunk) { ((LevelChunk) ichunkaccess).setLoaded(false); } -@@ -575,7 +649,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -575,7 +649,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.lightEngine.tryScheduleUpdate(); this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); +- } + } else if (removed) { // Paper start -+ for (int index = 0, len = this.regionManagers.size(); index < len; ++index) { -+ this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); - } -+ } // Paper end ++ net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); ++ } // Paper end } }; -@@ -1145,6 +1223,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -956,7 +1032,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + this.viewDistance = j; + this.distanceManager.updatePlayerTickets(this.viewDistance + 1); +- ObjectIterator objectiterator = this.updatingChunkMap.values().iterator(); ++ Iterator objectiterator = net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper + + while (objectiterator.hasNext()) { + ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); +@@ -999,7 +1075,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + public int size() { +- return this.visibleChunkMap.size(); ++ return net.minecraft.server.ChunkSystem.getVisibleChunkHolderCount(this.level); // Paper + } + + public DistanceManager getDistanceManager() { +@@ -1007,19 +1083,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + protected Iterable getChunks() { +- return Iterables.unmodifiableIterable(this.visibleChunkMap.values()); ++ return Iterables.unmodifiableIterable(net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level)); // Paper + } + + void dumpChunks(Writer writer) throws IOException { + CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); + TickingTracker tickingtracker = this.distanceManager.tickingTracker(); +- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator(); ++ Iterator objectbidirectionaliterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper + + while (objectbidirectionaliterator.hasNext()) { +- Entry entry = (Entry) objectbidirectionaliterator.next(); +- long i = entry.getLongKey(); ++ ChunkHolder playerchunk = objectbidirectionaliterator.next(); // Paper ++ long i = playerchunk.pos.toLong(); // Paper + ChunkPos chunkcoordintpair = new ChunkPos(i); +- ChunkHolder playerchunk = (ChunkHolder) entry.getValue(); ++ // Paper + Optional optional = Optional.ofNullable(playerchunk.getLastAvailable()); + Optional optional1 = optional.flatMap((ichunkaccess) -> { + return ichunkaccess instanceof LevelChunk ? Optional.of((LevelChunk) ichunkaccess) : Optional.empty(); +@@ -1145,6 +1221,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (!flag1) { this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player); } @@ -5475,7 +5855,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..6304a5b78ab1f3ef2478c7e2c493ebd7 } else { SectionPos sectionposition = player.getLastSectionPos(); -@@ -1152,6 +1231,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1152,6 +1229,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (!flag2) { this.distanceManager.removePlayer(sectionposition, player); } @@ -5483,7 +5863,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..6304a5b78ab1f3ef2478c7e2c493ebd7 } for (int k = i - this.viewDistance - 1; k <= i + this.viewDistance + 1; ++k) { -@@ -1264,6 +1344,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1264,6 +1342,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -5492,7 +5872,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..6304a5b78ab1f3ef2478c7e2c493ebd7 } @Override -@@ -1467,7 +1549,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1467,7 +1547,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public class ChunkDistanceManager extends DistanceManager { protected ChunkDistanceManager(Executor workerExecutor, Executor mainThreadExecutor) { @@ -5534,7 +5914,7 @@ index 6c98676827ceb6999f340fa2b06a0b3e1cb4cae2..f08089b8672454acf8c2309e850466b3 while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9f2e36fbf 100644 +index ce88976db29b9e9524dbe45b16721ef90afb692b..96323a83d917516edf4b6951d1e881d2f5513bd0 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -50,6 +50,7 @@ import net.minecraft.world.level.storage.LevelStorageSource; @@ -5545,7 +5925,7 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9 public static final List CHUNK_STATUSES = ChunkStatus.getStatusList(); private final DistanceManager distanceManager; final ServerLevel level; -@@ -68,6 +69,334 @@ public class ServerChunkCache extends ChunkSource { +@@ -68,6 +69,151 @@ public class ServerChunkCache extends ChunkSource { @Nullable @VisibleForDebug private NaturalSpawner.SpawnState lastSpawnState; @@ -5597,7 +5977,7 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9 + + LevelChunk cachedChunk = this.lastLoadedChunks[cacheKey]; + if (cachedChunk != null && cachedChunk.locX == x & cachedChunk.locZ == z) { -+ return this.lastLoadedChunks[cacheKey]; ++ return cachedChunk; + } + + long chunkKey = ChunkPos.asLong(x, z); @@ -5623,80 +6003,24 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9 + long chunkFutureAwaitCounter; // Paper - private -> package private + + public void getEntityTickingChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ if (Thread.currentThread() != this.mainThread) { -+ this.mainThreadProcessor.execute(() -> { -+ ServerChunkCache.this.getEntityTickingChunkAsync(x, z, onLoad); -+ }); -+ return; -+ } -+ this.getChunkFutureAsynchronously(x, z, 31, ChunkHolder::getEntityTickingChunkFuture, onLoad); ++ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ this.level, x, z, ChunkHolder.FullChunkStatus.ENTITY_TICKING, true, ++ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad ++ ); + } + + public void getTickingChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ if (Thread.currentThread() != this.mainThread) { -+ this.mainThreadProcessor.execute(() -> { -+ ServerChunkCache.this.getTickingChunkAsync(x, z, onLoad); -+ }); -+ return; -+ } -+ this.getChunkFutureAsynchronously(x, z, 32, ChunkHolder::getTickingChunkFuture, onLoad); ++ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ this.level, x, z, ChunkHolder.FullChunkStatus.TICKING, true, ++ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad ++ ); + } + + public void getFullChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ if (Thread.currentThread() != this.mainThread) { -+ this.mainThreadProcessor.execute(() -> { -+ ServerChunkCache.this.getFullChunkAsync(x, z, onLoad); -+ }); -+ return; -+ } -+ this.getChunkFutureAsynchronously(x, z, 33, ChunkHolder::getFullChunkFuture, onLoad); -+ } -+ -+ private void getChunkFutureAsynchronously(int x, int z, int ticketLevel, java.util.function.Function>> futureGet, java.util.function.Consumer onLoad) { -+ if (Thread.currentThread() != this.mainThread) { -+ throw new IllegalStateException(); -+ } -+ ChunkPos chunkPos = new ChunkPos(x, z); -+ Long identifier = this.chunkFutureAwaitCounter++; -+ this.distanceManager.addTicket(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, identifier); -+ this.runDistanceManagerUpdates(); -+ -+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong()); -+ -+ if (chunk == null) { -+ throw new IllegalStateException("Expected playerchunk " + chunkPos + " in world '" + this.level.getWorld().getName() + "'"); -+ } -+ -+ CompletableFuture> future = futureGet.apply(chunk); -+ -+ future.whenCompleteAsync((either, throwable) -> { -+ try { -+ if (throwable != null) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to complete future await for chunk " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "'", throwable); -+ } else if (either.right().isPresent()) { -+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to complete future await for chunk " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "': " + either.right().get().toString()); -+ } -+ -+ try { -+ if (onLoad != null) { -+ onLoad.accept(either == null ? null : either.left().orElse(null)); // indicate failure to the callback. -+ } -+ } catch (Throwable thr) { -+ if (thr instanceof ThreadDeath) { -+ throw (ThreadDeath)thr; -+ } -+ net.minecraft.server.MinecraftServer.LOGGER.error("Load callback for future await failed " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "'", thr); -+ return; -+ } -+ } finally { -+ // due to odd behaviour with CB unload implementation we need to have these AFTER the load callback. -+ ServerChunkCache.this.distanceManager.addTicket(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos); -+ ServerChunkCache.this.distanceManager.removeTicket(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, identifier); -+ } -+ }, this.mainThreadProcessor); ++ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ this.level, x, z, ChunkHolder.FullChunkStatus.BORDER, true, ++ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad ++ ); + } + // Paper end + @@ -5739,67 +6063,6 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9 + } + } + -+ void getChunkAtAsynchronously(int chunkX, int chunkZ, int ticketLevel, -+ java.util.function.Consumer consumer) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, ticketLevel, (ChunkHolder chunkHolder) -> { -+ if (ticketLevel <= 33) { -+ return (CompletableFuture)chunkHolder.getFullChunkFuture(); -+ } else { -+ return chunkHolder.getOrScheduleFuture(ChunkHolder.getStatus(ticketLevel), ServerChunkCache.this.chunkMap); -+ } -+ }, consumer); -+ } -+ -+ void getChunkAtAsynchronously(int chunkX, int chunkZ, int ticketLevel, -+ java.util.function.Function>> function, -+ java.util.function.Consumer consumer) { -+ if (Thread.currentThread() != this.mainThread) { -+ throw new IllegalStateException(); -+ } -+ -+ ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -+ Long identifier = Long.valueOf(this.chunkFutureAwaitCounter++); -+ this.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, identifier); -+ this.runDistanceManagerUpdates(); -+ -+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong()); -+ -+ if (chunk == null) { -+ throw new IllegalStateException("Expected playerchunk " + chunkPos + " in world '" + this.level.getWorld().getName() + "'"); -+ } -+ -+ CompletableFuture> future = function.apply(chunk); -+ -+ future.whenCompleteAsync((either, throwable) -> { -+ try { -+ if (throwable != null) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ LOGGER.error("Failed to complete future await for chunk " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "'", throwable); -+ } else if (either.right().isPresent()) { -+ LOGGER.error("Failed to complete future await for chunk " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "': " + either.right().get().toString()); -+ } -+ -+ try { -+ if (consumer != null) { -+ consumer.accept(either == null ? null : either.left().orElse(null)); // indicate failure to the callback. -+ } -+ } catch (Throwable thr) { -+ if (thr instanceof ThreadDeath) { -+ throw (ThreadDeath)thr; -+ } -+ LOGGER.error("Load callback for future await failed " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "'", thr); -+ return; -+ } -+ } finally { -+ // due to odd behaviour with CB unload implementation we need to have these AFTER the load callback. -+ ServerChunkCache.this.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos); -+ ServerChunkCache.this.removeTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, identifier); -+ } -+ }, this.mainThreadProcessor); -+ } -+ + public void addTicketAtLevel(TicketType ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) { + this.distanceManager.addTicket(ticketType, chunkPos, ticketLevel, identifier); + } @@ -5808,79 +6071,13 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9 + this.distanceManager.removeTicket(ticketType, chunkPos, ticketLevel, identifier); + } + -+ void chunkLoadAccept(int chunkX, int chunkZ, ChunkAccess chunk, java.util.function.Consumer consumer) { -+ try { -+ consumer.accept(chunk); -+ } catch (Throwable throwable) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ LOGGER.error("Load callback for chunk " + chunkX + "," + chunkZ + " in world '" + this.level.getWorld().getName() + "' threw an exception", throwable); -+ } -+ } -+ -+ public final void getChunkAtAsynchronously(int chunkX, int chunkZ, ChunkStatus status, boolean gen, boolean allowSubTicketLevel, java.util.function.Consumer onLoad) { -+ // try to fire sync -+ int chunkStatusTicketLevel = 33 + ChunkStatus.getDistance(status); -+ ChunkHolder playerChunk = this.chunkMap.getUpdatingChunkIfPresent(io.papermc.paper.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ if (playerChunk != null) { -+ ChunkStatus holderStatus = playerChunk.getChunkHolderStatus(); -+ ChunkAccess immediate = playerChunk.getAvailableChunkNow(); -+ if (immediate != null) { -+ if (allowSubTicketLevel ? immediate.getStatus().isOrAfter(status) : (playerChunk.getTicketLevel() <= chunkStatusTicketLevel && holderStatus != null && holderStatus.isOrAfter(status))) { -+ this.chunkLoadAccept(chunkX, chunkZ, immediate, onLoad); -+ return; -+ } else { -+ if (gen || (!allowSubTicketLevel && immediate.getStatus().isOrAfter(status))) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } else { -+ this.chunkLoadAccept(chunkX, chunkZ, null, onLoad); -+ return; -+ } -+ } -+ } -+ } -+ -+ // need to fire async -+ -+ if (gen && !allowSubTicketLevel) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } -+ -+ this.getChunkAtAsynchronously(chunkX, chunkZ, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.EMPTY), (ChunkAccess chunk) -> { -+ if (chunk == null) { -+ throw new IllegalStateException("Chunk cannot be null"); -+ } -+ -+ if (!chunk.getStatus().isOrAfter(status)) { -+ if (gen) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } else { -+ ServerChunkCache.this.chunkLoadAccept(chunkX, chunkZ, null, onLoad); -+ return; -+ } -+ } else { -+ if (allowSubTicketLevel) { -+ ServerChunkCache.this.chunkLoadAccept(chunkX, chunkZ, chunk, onLoad); -+ return; -+ } else { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } -+ } -+ }); -+ } -+ -+ final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet tickingChunks = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); -+ final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entityTickingChunks = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); ++ public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet tickingChunks = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); ++ public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entityTickingChunks = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); + // Paper end public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory) { this.level = world; -@@ -120,6 +449,49 @@ public class ServerChunkCache extends ChunkSource { +@@ -120,6 +266,49 @@ public class ServerChunkCache extends ChunkSource { this.lastChunk[0] = chunk; } @@ -5930,7 +6127,7 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9 @Nullable @Override public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { -@@ -327,6 +699,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -327,6 +516,12 @@ public class ServerChunkCache extends ChunkSource { } } @@ -5944,7 +6141,7 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..186a8f5895fedbaf27a7949d9bdbb1a9 ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 4f1e8d36c363eb74e8f1e593f35a7bb8550f8918..95c3273d2379509cf6cd51a718f18b8697908932 100644 +index aa396df025115c7fd866cbc63a44c2c17abfde84..b2f79a0c9caa6783816afc36531c94378e832cb7 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -168,6 +168,7 @@ import org.bukkit.event.weather.LightningStrikeEvent; @@ -5955,7 +6152,7 @@ index 4f1e8d36c363eb74e8f1e593f35a7bb8550f8918..95c3273d2379509cf6cd51a718f18b86 public class ServerLevel extends Level implements WorldGenLevel { -@@ -223,6 +224,96 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -223,6 +224,98 @@ public class ServerLevel extends Level implements WorldGenLevel { return convertable.dimensionType; } @@ -5989,11 +6186,11 @@ index 4f1e8d36c363eb74e8f1e593f35a7bb8550f8918..95c3273d2379509cf6cd51a718f18b86 + return true; + } + -+ public final void loadChunksForMoveAsync(AABB axisalignedbb, double toX, double toZ, ++ public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority, + java.util.function.Consumer> onLoad) { + if (Thread.currentThread() != this.thread) { + this.getChunkSource().mainThreadProcessor.execute(() -> { -+ this.loadChunksForMoveAsync(axisalignedbb, toX, toZ, onLoad); ++ this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad); + }); + return; + } @@ -6043,7 +6240,9 @@ index 4f1e8d36c363eb74e8f1e593f35a7bb8550f8918..95c3273d2379509cf6cd51a718f18b86 + + for (int cx = minChunkX; cx <= maxChunkX; ++cx) { + for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { -+ chunkProvider.getChunkAtAsynchronously(cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, false, consumer); ++ net.minecraft.server.ChunkSystem.scheduleChunkLoad( ++ this, cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, priority, consumer ++ ); + } + } + } @@ -6053,7 +6252,7 @@ index 4f1e8d36c363eb74e8f1e593f35a7bb8550f8918..95c3273d2379509cf6cd51a718f18b86 public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { // Holder holder = worlddimension.typeHolder(); // CraftBukkit - decompile error diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index d9424f016060d7a2b446801c64c6cc0c3d826fb8..4759a0eceeccf28b62cb8865b423235d47d07443 100644 +index e2ed77972fcec43fef5f3af044479849f78901a9..84564ca128d2dfc79c0b5a13b699cf6fc80bdea7 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -243,6 +243,8 @@ public class ServerPlayer extends Player { @@ -6790,6 +6989,128 @@ index 9668a960dbd3b4ff3c0635df2fb7cc1af289d235..603111a52346f678aba0fd66b010d8f3 @Override public BlockState getBlockState(BlockPos pos) { int i = pos.getY(); +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 dfd1afc57664dd18c11f8a2547616074ccc55690..ab7eadf2fc4c4598fa89068332eaaf9a8e0a100f 100644 +--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java ++++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +@@ -90,6 +90,18 @@ public class PersistentEntitySectionManager implements A + } + + private boolean addEntity(T entity, boolean existing) { ++ // Paper start - chunk system hooks ++ if (existing) { ++ // I don't want to know why this is a generic type. ++ Entity entityCasted = (Entity)entity; ++ boolean wasRemoved = entityCasted.isRemoved(); ++ net.minecraft.server.ChunkSystem.onEntityPreAdd((net.minecraft.server.level.ServerLevel)entityCasted.level, entityCasted); ++ if (!wasRemoved && entityCasted.isRemoved()) { ++ // removed by callback ++ return false; ++ } ++ } ++ // Paper end - chunk system hooks + if (!this.addEntityUuid(entity)) { + return false; + } else { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..6d9469d577dcbb9d5b5b703cf47c8863e0b43b13 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -234,8 +234,8 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public Chunk[] getLoadedChunks() { +- Long2ObjectLinkedOpenHashMap chunks = this.world.getChunkSource().chunkMap.visibleChunkMap; +- return chunks.values().stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); ++ List chunks = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world); // Paper ++ return chunks.stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); + } + + @Override +@@ -310,7 +310,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean refreshChunk(int x, int z) { +- ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.visibleChunkMap.get(ChunkPos.asLong(x, z)); ++ ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); + if (playerChunk == null) return false; + + playerChunk.getTickingChunkFuture().thenAccept(either -> { +@@ -1943,4 +1943,32 @@ public class CraftWorld extends CraftRegionAccessor implements World { + return this.spigot; + } + // Spigot end ++ // Paper start ++ public java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { ++ if (Bukkit.isPrimaryThread()) { ++ net.minecraft.world.level.chunk.LevelChunk immediate = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); ++ if (immediate != null) { ++ return java.util.concurrent.CompletableFuture.completedFuture(immediate.getBukkitChunk()); ++ } ++ } ++ ++ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority; ++ if (urgent) { ++ priority = ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER; ++ } else { ++ priority = ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL; ++ } ++ ++ java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); ++ ++ net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { ++ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { ++ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c; ++ ret.complete(chunk == null ? null : chunk.getBukkitChunk()); ++ }); ++ }); ++ ++ return ret; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index ef27c0f94355ec7be4a314a0f93bc1c146012210..71c1595b59b757441304a158367d750ed509e4d1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1128,4 +1128,37 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return this.spigot; + } + // Spigot end ++ ++ // Paper start ++ @Override ++ public java.util.concurrent.CompletableFuture teleportAsync(Location location, TeleportCause cause) { ++ Preconditions.checkArgument(location != null, "location"); ++ location.checkFinite(); ++ Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. ++ ++ net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle(); ++ java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); ++ ++ world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), ++ this instanceof CraftPlayer ? ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER : ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, (list) -> { ++ net.minecraft.server.level.ServerChunkCache chunkProviderServer = world.getChunkSource(); ++ for (net.minecraft.world.level.chunk.ChunkAccess chunk : list) { ++ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); ++ } ++ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { ++ try { ++ ret.complete(CraftEntity.this.teleport(locationClone, cause) ? Boolean.TRUE : Boolean.FALSE); ++ } catch (Throwable throwable) { ++ if (throwable instanceof ThreadDeath) { ++ throw (ThreadDeath)throwable; ++ } ++ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to teleport entity " + CraftEntity.this, throwable); ++ ret.completeExceptionally(throwable); ++ } ++ }); ++ }); ++ ++ return ret; ++ } ++ // Paper end + } diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index 2f52148f36e56c503e619634eedd3d46d9f44938..054fcc3713f02e358dfe049491c8d1689ccc750b 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -7013,7 +7334,7 @@ index 0000000000000000000000000000000000000000..909b2c98e7a9117d2f737245e4661792 + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 96bbfe115f4fcd9b5bfe733ee8e0a64f5dcf4198..8c5165c449f740e51aad3f41405aaad1cfe5c657 100644 +index 3568b1a579716bee7f749eb944784b59b361f6df..d805ac4274fb6149bf8efea6b771ecfe79aea76f 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -100,8 +100,17 @@ public final class CraftMagicNumbers implements UnsafeValues { diff --git a/patches/server/0008-Adventure.patch b/patches/server/0009-Adventure.patch similarity index 99% rename from patches/server/0008-Adventure.patch rename to patches/server/0009-Adventure.patch index 92350d9dc2..4e3bfbad3a 100644 --- a/patches/server/0008-Adventure.patch +++ b/patches/server/0009-Adventure.patch @@ -2691,7 +2691,7 @@ index 4dd952faac05f553b28d1252296b0587369865f4..6139a06453e370865889f47644a6840f + // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..cf7762e76a2d35acdfc12627e9750fbec766d555 100644 +index 6d9469d577dcbb9d5b5b703cf47c8863e0b43b13..9a6820b10e4164cc38d269853b5c2a49175cb890 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -150,6 +150,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -2702,10 +2702,10 @@ index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..cf7762e76a2d35acdfc12627e9750fbe private static final Random rand = new Random(); -@@ -1943,4 +1944,18 @@ public class CraftWorld extends CraftRegionAccessor implements World { - return this.spigot; +@@ -1970,5 +1971,18 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + return ret; } - // Spigot end + + // Paper start - implement pointers + @Override @@ -2719,7 +2719,7 @@ index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..cf7762e76a2d35acdfc12627e9750fbe + + return this.adventure$pointers; + } -+ // Paper end + // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java index e8d71985f2e96574081e4f609d62a3b8bded8249..681b58e6de48cccac82c7b6833f6fcea46d83dde 100644 @@ -3089,7 +3089,7 @@ index 53b5af4179cc4bc4d5646f183da5e327a45237ac..a859a675b4bc543e139358223cc92ad5 public net.minecraft.world.item.enchantment.Enchantment getHandle() { return this.target; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index ef27c0f94355ec7be4a314a0f93bc1c146012210..64687b0e04f619576f3e7f4fec0b559408048d38 100644 +index 71c1595b59b757441304a158367d750ed509e4d1..7c9dcf62f85bb3ddffb4eadb3961d7b356c503f8 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -196,6 +196,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { diff --git a/patches/server/0009-Paper-command.patch b/patches/server/0010-Paper-command.patch similarity index 99% rename from patches/server/0009-Paper-command.patch rename to patches/server/0010-Paper-command.patch index 7a3a1c2956..a1cbd38e7e 100644 --- a/patches/server/0009-Paper-command.patch +++ b/patches/server/0010-Paper-command.patch @@ -559,7 +559,7 @@ index 08ae7a96e93c0d8547f560b3f753804525621c6b..8f29bb843fc456384f7b4e216afca501 this.setPvpAllowed(dedicatedserverproperties.pvp); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index e4f8ccb45a16c35b5256e209435840609d527695..82199864f2046528358af08d4aa4a283fa3e7ffd 100644 +index 6139a06453e370865889f47644a6840fce2934f2..295318717fc603b3adc58fbda39bd65e97462b88 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -896,6 +896,7 @@ public final class CraftServer implements Server { diff --git a/patches/server/0012-Timings-v2.patch b/patches/server/0012-Timings-v2.patch index df9edbac22..71da852f12 100644 --- a/patches/server/0012-Timings-v2.patch +++ b/patches/server/0012-Timings-v2.patch @@ -997,7 +997,7 @@ index f4a6a6addbba65b3415320977048aeba0eadba63..c905602d23cdf3af1de7ab4419f11856 } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 6304a5b78ab1f3ef2478c7e2c493ebd760b5508e..ca1e483819bffc948fab10f88563084aa75d1484 100644 +index 1fbe1b6de925f71763f79fe3d2371b70a8650f25..2a9e5fb8164f79b0f9c1cb5497216e51f9df3454 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -1,8 +1,10 @@ @@ -1011,7 +1011,7 @@ index 6304a5b78ab1f3ef2478c7e2c493ebd760b5508e..ca1e483819bffc948fab10f88563084a import com.google.common.collect.Lists; import com.google.common.collect.Queues; import com.google.common.collect.Sets; -@@ -854,6 +856,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -852,6 +854,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ChunkStatus chunkstatus = ChunkHolder.getStatus(chunkHolder.getTicketLevel()); return !chunkstatus.isOrAfter(ChunkStatus.FULL) ? ChunkHolder.UNLOADED_CHUNK : either.mapLeft((ichunkaccess) -> { @@ -1019,7 +1019,7 @@ index 6304a5b78ab1f3ef2478c7e2c493ebd760b5508e..ca1e483819bffc948fab10f88563084a ChunkPos chunkcoordintpair = chunkHolder.getPos(); ProtoChunk protochunk = (ProtoChunk) ichunkaccess; LevelChunk chunk; -@@ -878,6 +881,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -876,6 +879,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } return chunk; @@ -1027,7 +1027,7 @@ index 6304a5b78ab1f3ef2478c7e2c493ebd760b5508e..ca1e483819bffc948fab10f88563084a }); }, (runnable) -> { ProcessorHandle mailbox = this.mainThreadMailbox; -@@ -1430,6 +1434,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1428,6 +1432,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider List list = Lists.newArrayList(); List list1 = this.level.players(); ObjectIterator objectiterator = this.entityMap.values().iterator(); @@ -1035,7 +1035,7 @@ index 6304a5b78ab1f3ef2478c7e2c493ebd760b5508e..ca1e483819bffc948fab10f88563084a ChunkMap.TrackedEntity playerchunkmap_entitytracker; -@@ -1454,14 +1459,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1452,14 +1457,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider playerchunkmap_entitytracker.serverEntity.sendChanges(); } } @@ -1054,10 +1054,10 @@ index 6304a5b78ab1f3ef2478c7e2c493ebd760b5508e..ca1e483819bffc948fab10f88563084a } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 186a8f5895fedbaf27a7949d9bdbb1a9f2e36fbf..86acdd910eebb8beac4536942119c9e97580ff2e 100644 +index 96323a83d917516edf4b6951d1e881d2f5513bd0..514111ed7fe8aec0d5f15f7a8f157d5872a56e4f 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -517,13 +517,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -334,13 +334,15 @@ public class ServerChunkCache extends ChunkSource { } gameprofilerfiller.incrementCounter("getChunkCacheMiss"); @@ -1075,7 +1075,7 @@ index 186a8f5895fedbaf27a7949d9bdbb1a9f2e36fbf..86acdd910eebb8beac4536942119c9e9 ichunkaccess = (ChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { return ichunkaccess1; }, (playerchunk_failure) -> { -@@ -721,7 +723,9 @@ public class ServerChunkCache extends ChunkSource { +@@ -538,7 +540,9 @@ public class ServerChunkCache extends ChunkSource { public void save(boolean flush) { this.runDistanceManagerUpdates(); @@ -1085,7 +1085,7 @@ index 186a8f5895fedbaf27a7949d9bdbb1a9f2e36fbf..86acdd910eebb8beac4536942119c9e9 } @Override -@@ -760,7 +764,9 @@ public class ServerChunkCache extends ChunkSource { +@@ -577,7 +581,9 @@ public class ServerChunkCache extends ChunkSource { this.level.timings.doChunkMap.stopTiming(); // Spigot this.level.getProfiler().popPush("chunks"); if (tickChunks) { @@ -1095,7 +1095,7 @@ index 186a8f5895fedbaf27a7949d9bdbb1a9f2e36fbf..86acdd910eebb8beac4536942119c9e9 } this.level.timings.doChunkUnload.startTiming(); // Spigot -@@ -789,13 +795,16 @@ public class ServerChunkCache extends ChunkSource { +@@ -606,13 +612,16 @@ public class ServerChunkCache extends ChunkSource { boolean flag1 = level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit gameprofilerfiller.push("naturalSpawnCount"); @@ -1112,7 +1112,7 @@ index 186a8f5895fedbaf27a7949d9bdbb1a9f2e36fbf..86acdd910eebb8beac4536942119c9e9 while (iterator.hasNext()) { ChunkHolder playerchunk = (ChunkHolder) iterator.next(); -@@ -824,27 +833,27 @@ public class ServerChunkCache extends ChunkSource { +@@ -641,27 +650,27 @@ public class ServerChunkCache extends ChunkSource { } if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { @@ -1146,7 +1146,7 @@ index 186a8f5895fedbaf27a7949d9bdbb1a9f2e36fbf..86acdd910eebb8beac4536942119c9e9 } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145c9c61273 100644 +index b2f79a0c9caa6783816afc36531c94378e832cb7..99d44faab5b5da244fdc170c73d73723c174c8fd 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1,6 +1,8 @@ @@ -1166,7 +1166,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.generator.CustomWorldChunkManager; import org.bukkit.craftbukkit.util.CraftNamespacedKey; -@@ -447,7 +448,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -449,7 +450,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.updateSkyBrightness(); this.tickTime(); gameprofilerfiller.popPush("tickPending"); @@ -1175,7 +1175,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 if (!this.isDebug()) { j = this.getGameTime(); gameprofilerfiller.push("blockTicks"); -@@ -456,12 +457,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -458,12 +459,16 @@ public class ServerLevel extends Level implements WorldGenLevel { this.fluidTicks.tick(j, 65536, this::tickFluid); gameprofilerfiller.pop(); } @@ -1193,7 +1193,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 gameprofilerfiller.popPush("blockEvents"); timings.doSounds.startTiming(); // Spigot this.runBlockEvents(); -@@ -628,6 +633,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -630,6 +635,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } gameprofilerfiller.popPush("tickBlocks"); @@ -1201,7 +1201,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 if (randomTickSpeed > 0) { LevelChunkSection[] achunksection = chunk.getSections(); int l = achunksection.length; -@@ -660,6 +666,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -662,6 +668,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } } @@ -1209,7 +1209,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 gameprofilerfiller.pop(); } -@@ -894,14 +901,22 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -896,14 +903,22 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void tickNonPassenger(Entity entity) { @@ -1233,7 +1233,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 entity.setOldPosAndRot(); ProfilerFiller gameprofilerfiller = this.getProfiler(); -@@ -920,7 +935,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -922,7 +937,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.tickPassenger(entity, entity1); } @@ -1242,7 +1242,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 } -@@ -962,6 +977,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -964,6 +979,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (!savingDisabled) { org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit @@ -1250,7 +1250,7 @@ index a60af68365b4cb0e09061e1956d2ae6790659bc0..28669f2e9c4a49322fe44c730b2ed145 if (progressListener != null) { progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); } -@@ -971,7 +987,10 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -973,7 +989,10 @@ public class ServerLevel extends Level implements WorldGenLevel { progressListener.progressStage(Component.translatable("menu.savingChunks")); } diff --git a/patches/server/0010-Not-implemeneted.patch b/patches/server/0013-Not-implemeneted.patch similarity index 88% rename from patches/server/0010-Not-implemeneted.patch rename to patches/server/0013-Not-implemeneted.patch index 55e55d31d4..3f8aab22dd 100644 --- a/patches/server/0010-Not-implemeneted.patch +++ b/patches/server/0013-Not-implemeneted.patch @@ -7,13 +7,14 @@ Currently a placeholder patch. diff --git a/src/main/java/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java new file mode 100644 -index 0000000000000000000000000000000000000000..be130b03ca116fd6d104df26c32312db1655b09e +index 0000000000000000000000000000000000000000..d59885ee9c8b29d5bac34dce0597e345e5358c77 --- /dev/null +++ b/src/main/java/io/papermc/paper/util/TickThread.java -@@ -0,0 +1,78 @@ +@@ -0,0 +1,79 @@ +package io.papermc.paper.util; + +import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import org.bukkit.Bukkit; +import java.util.concurrent.atomic.AtomicInteger; @@ -42,15 +43,15 @@ index 0000000000000000000000000000000000000000..be130b03ca116fd6d104df26c32312db + } + } + -+ public static void ensureTickThread(final int chunkX, final int chunkZ, final String reason) { -+ if (!isTickThreadFor(chunkX, chunkZ)) { ++ public static void ensureTickThread(final ServerLevel world, final int chunkX, final int chunkZ, final String reason) { ++ if (!isTickThreadFor(world, chunkX, chunkZ)) { + MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); + throw new IllegalStateException(reason); + } + } + + public static void ensureTickThread(final Entity entity, final String reason) { -+ if (!isTickThreadFor(entity.chunkPosition().x, entity.chunkPosition().z)) { ++ if (!isTickThreadFor(entity)) { + MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); + throw new IllegalStateException(reason); + } @@ -81,7 +82,7 @@ index 0000000000000000000000000000000000000000..be130b03ca116fd6d104df26c32312db + return Bukkit.isPrimaryThread(); + } + -+ public static boolean isTickThreadFor(final int chunkX, final int chunkZ) { ++ public static boolean isTickThreadFor(final ServerLevel world, final int chunkX, final int chunkZ) { + return Bukkit.isPrimaryThread(); + } + diff --git a/patches/server/0320-ChunkMapDistance-CME.patch b/patches/server/0014-ChunkMapDistance-CME.patch similarity index 90% rename from patches/server/0320-ChunkMapDistance-CME.patch rename to patches/server/0014-ChunkMapDistance-CME.patch index 74fcd81751..956878857c 100644 --- a/patches/server/0320-ChunkMapDistance-CME.patch +++ b/patches/server/0014-ChunkMapDistance-CME.patch @@ -5,7 +5,7 @@ Subject: [PATCH] ChunkMapDistance CME diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 90fcb4dc89643b1c706ea4554595a842198558a1..6e7d09cd48048957a14835b857ac708aafe8f664 100644 +index 0873134f1f6de0c372ba28b89a20302c9a0115d8..e30893d6cbe3b42338d04453d0f452babeb61d8a 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -73,6 +73,7 @@ public class ChunkHolder { @@ -15,9 +15,9 @@ index 90fcb4dc89643b1c706ea4554595a842198558a1..6e7d09cd48048957a14835b857ac708a + boolean isUpdateQueued = false; // Paper private final ChunkMap chunkMap; // Paper - public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { + // Paper start diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index ab785bfc29c0b120b7c6fed2d15460c86e020291..1e066a35b53b1f71a0e6376a22d51fc4c0a412dc 100644 +index f08089b8672454acf8c2309e850466b335248692..6181f675d7addde30f7018b4cd46fe061a14da51 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -52,7 +52,16 @@ public abstract class DistanceManager { diff --git a/patches/server/0015-Do-not-copy-visible-chunks.patch b/patches/server/0015-Do-not-copy-visible-chunks.patch new file mode 100644 index 0000000000..0f5350c531 --- /dev/null +++ b/patches/server/0015-Do-not-copy-visible-chunks.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 21 Mar 2021 11:22:10 -0700 +Subject: [PATCH] Do not copy visible chunks + +For servers with a lot of chunk holders, copying for each +tickDistanceManager call can take up quite a bit in +the function. I saw approximately 1/3rd of the function +on the copy. + +diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java +index 83dc09f6526206690c474b50a7a6e71cefc93ab4..7f76c304f5eb3c2f27b348918588ab67b795b1ba 100644 +--- a/src/main/java/net/minecraft/server/ChunkSystem.java ++++ b/src/main/java/net/minecraft/server/ChunkSystem.java +@@ -202,19 +202,24 @@ public final class ChunkSystem { + } + + public static List getVisibleChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); ++ if (Bukkit.isPrimaryThread()) { ++ return level.chunkSource.chunkMap.updatingChunks.getVisibleValuesCopy(); ++ } ++ synchronized (level.chunkSource.chunkMap.updatingChunks) { ++ return level.chunkSource.chunkMap.updatingChunks.getVisibleValuesCopy(); ++ } + } + + public static List getUpdatingChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); ++ return level.chunkSource.chunkMap.updatingChunks.getUpdatingValuesCopy(); + } + + public static int getVisibleChunkHolderCount(final ServerLevel level) { +- return level.chunkSource.chunkMap.visibleChunkMap.size(); ++ return level.chunkSource.chunkMap.updatingChunks.getVisibleMap().size(); + } + + public static int getUpdatingChunkHolderCount(final ServerLevel level) { +- return level.chunkSource.chunkMap.updatingChunkMap.size(); ++ return level.chunkSource.chunkMap.updatingChunks.getUpdatingMap().size(); + } + + public static boolean hasAnyChunkHolders(final ServerLevel level) { +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 2a9e5fb8164f79b0f9c1cb5497216e51f9df3454..ea27e6b1340a42c675bc68ed75f100569114be7a 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -121,9 +121,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private static final int MIN_VIEW_DISTANCE = 3; + public static final int MAX_VIEW_DISTANCE = 33; + public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance(); ++ // Paper start - Don't copy ++ public final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object updatingChunks = new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(); ++ // Paper end - Don't copy + public static final int FORCED_TICKET_LEVEL = 31; +- public final Long2ObjectLinkedOpenHashMap updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); +- public volatile Long2ObjectLinkedOpenHashMap visibleChunkMap; ++ // Paper - Don't copy + private final Long2ObjectLinkedOpenHashMap pendingUnloads; + public final LongSet entitiesInLevel; + public final ServerLevel level; +@@ -224,7 +226,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { + super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); +- this.visibleChunkMap = this.updatingChunkMap.clone(); ++ // Paper - don't copy + this.pendingUnloads = new Long2ObjectLinkedOpenHashMap(); + this.entitiesInLevel = new LongOpenHashSet(); + this.toDrop = new LongOpenHashSet(); +@@ -327,12 +329,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + @Nullable + public ChunkHolder getUpdatingChunkIfPresent(long pos) { +- return (ChunkHolder) this.updatingChunkMap.get(pos); ++ return this.updatingChunks.getUpdating(pos); // Paper - Don't copy + } + + @Nullable + public ChunkHolder getVisibleChunkIfPresent(long pos) { +- return (ChunkHolder) this.visibleChunkMap.get(pos); ++ // Paper start - Don't copy ++ if (Thread.currentThread() == this.level.thread) { ++ return this.updatingChunks.getVisible(pos); ++ } ++ return this.updatingChunks.getVisibleAsync(pos); ++ // Paper end - Don't copy + } + + protected IntSupplier getChunkQueueLevel(long pos) { +@@ -515,7 +522,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper start + holder.onChunkAdd(); + // Paper end +- this.updatingChunkMap.put(pos, holder); ++ this.updatingChunks.queueUpdate(pos, holder); // Paper - Don't copy + this.modified = true; + } + +@@ -592,7 +599,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { + long j = longiterator.nextLong(); +- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); ++ ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy + + if (playerchunk != null) { + playerchunk.onChunkRemove(); // Paper +@@ -672,7 +679,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + if (!this.modified) { + return false; + } else { +- this.visibleChunkMap = this.updatingChunkMap.clone(); ++ // Paper start - Don't copy ++ synchronized (this.updatingChunks) { ++ this.updatingChunks.performUpdates(); ++ } ++ // Paper end - Don't copy ++ + this.modified = false; + return true; + } diff --git a/patches/server/0321-Chunk-debug-command.patch b/patches/server/0016-Chunk-debug-command.patch similarity index 90% rename from patches/server/0321-Chunk-debug-command.patch rename to patches/server/0016-Chunk-debug-command.patch index 79c5f0f128..79581b2b72 100644 --- a/patches/server/0321-Chunk-debug-command.patch +++ b/patches/server/0016-Chunk-debug-command.patch @@ -32,7 +32,7 @@ https://bugs.mojang.com/browse/MC-141484?focusedCommentId=528273&page=com.atlass https://bugs.mojang.com/browse/MC-141484?focusedCommentId=528577&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-528577 diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java -index cd4936ef114b504df8649fba8f1823d94a4bb2a2..395c43f6440c1e0e47919eef096ea8a8d552ccec 100644 +index b3a58bf4b654e336826dc04da9e2f80ff8b9a9a7..8e773f522521d2dd6349c87b582a3337b76f161f 100644 --- a/src/main/java/io/papermc/paper/command/PaperCommand.java +++ b/src/main/java/io/papermc/paper/command/PaperCommand.java @@ -1,5 +1,6 @@ @@ -52,7 +52,7 @@ index cd4936ef114b504df8649fba8f1823d94a4bb2a2..395c43f6440c1e0e47919eef096ea8a8 .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) diff --git a/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java new file mode 100644 -index 0000000000000000000000000000000000000000..029ad37df71e74d9feb57e4b31b3602e55d49113 +index 0000000000000000000000000000000000000000..28a9550449be9a212f054b02e43fbd8a3781efcf --- /dev/null +++ b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java @@ -0,0 +1,166 @@ @@ -148,14 +148,14 @@ index 0000000000000000000000000000000000000000..029ad37df71e74d9feb57e4b31b3602e + int ticking = 0; + int entityTicking = 0; + -+ for (final ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunkMap.values()) { ++ for (final ChunkHolder chunk : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(world)) { + if (chunk.getFullChunkNowUnchecked() == null) { + continue; + } + + ++total; + -+ ChunkHolder.FullChunkStatus state = ChunkHolder.getFullChunkStatus(chunk.getTicketLevel()); ++ ChunkHolder.FullChunkStatus state = chunk.getFullStatus(); + + switch (state) { + case INACCESSIBLE -> ++inactive; @@ -223,17 +223,25 @@ index 0000000000000000000000000000000000000000..029ad37df71e74d9feb57e4b31b3602e + +} diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index 162aa7718488a74980843944e0d026ccfd5a65a5..4e29c0a983727fc839a4bcde01d3286396b3587d 100644 +index b310d51b7fe3e8cef0a450674725969fe1ce78a4..2e56c52e3ee45b0304a9e6a5eab863ef96b2aab0 100644 --- a/src/main/java/net/minecraft/server/MCUtil.java +++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -9,13 +9,27 @@ import net.minecraft.core.BlockPos; +@@ -1,15 +1,27 @@ + package net.minecraft.server; + + import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonObject; ++import com.google.gson.internal.Streams; ++import com.google.gson.stream.JsonWriter; ++import com.mojang.datafixers.util.Either; + import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; + import java.lang.ref.Cleaner; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; - import net.minecraft.nbt.CompoundTag; - import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.DistanceManager; -+import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.Ticket; @@ -244,42 +252,26 @@ index 162aa7718488a74980843944e0d026ccfd5a65a5..4e29c0a983727fc839a4bcde01d32863 +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; import org.apache.commons.lang.exception.ExceptionUtils; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonObject; -+import com.google.gson.internal.Streams; -+import com.google.gson.stream.JsonWriter; - import com.mojang.authlib.GameProfile; -+import com.mojang.datafixers.util.Either; -+import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import org.bukkit.Location; import org.bukkit.block.BlockFace; - import org.bukkit.craftbukkit.CraftWorld; -@@ -24,8 +38,11 @@ import org.spigotmc.AsyncCatcher; +@@ -19,8 +31,11 @@ import org.spigotmc.AsyncCatcher; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.io.*; -+import java.util.ArrayList; ++import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Queue; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; -@@ -541,6 +558,172 @@ public final class MCUtil { - return null; +@@ -505,6 +520,163 @@ public final class MCUtil { + } } + public static ChunkStatus getChunkStatus(ChunkHolder chunk) { -+ List statuses = net.minecraft.server.level.ServerChunkCache.CHUNK_STATUSES; -+ for (int i = statuses.size() - 1; i >= 0; --i) { -+ ChunkStatus curr = statuses.get(i); -+ CompletableFuture> future = chunk.getFutureIfPresentUnchecked(curr); -+ if (future != ChunkHolder.UNLOADED_CHUNK_FUTURE) { -+ return curr; -+ } -+ } -+ return null; // unloaded ++ return chunk.getChunkHolderStatus(); + } + + public static void dumpChunks(File file) throws IOException { @@ -337,9 +329,8 @@ index 162aa7718488a74980843944e0d026ccfd5a65a5..4e29c0a983727fc839a4bcde01d32863 + + ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle(); + ChunkMap chunkMap = world.getChunkSource().chunkMap; -+ Long2ObjectLinkedOpenHashMap visibleChunks = chunkMap.visibleChunkMap; + DistanceManager chunkMapDistance = chunkMap.distanceManager; -+ List allChunks = new ArrayList<>(visibleChunks.values()); ++ List allChunks = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(world); + List players = world.players; + + int fullLoadedChunks = 0; @@ -362,7 +353,7 @@ index 162aa7718488a74980843944e0d026ccfd5a65a5..4e29c0a983727fc839a4bcde01d32863 + worldData.addProperty("view-distance", world.spigotConfig.viewDistance); + worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); + worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); -+ worldData.addProperty("visible-chunk-count", visibleChunks.size()); ++ worldData.addProperty("visible-chunk-count", allChunks.size()); + worldData.addProperty("loaded-chunk-count", chunkMap.entitiesInLevel.size()); + worldData.addProperty("verified-fully-loaded-chunks", fullLoadedChunks); + @@ -431,7 +422,7 @@ index 162aa7718488a74980843944e0d026ccfd5a65a5..4e29c0a983727fc839a4bcde01d32863 + + String fileData = stringWriter.toString(); + -+ try (PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) { ++ try (PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)) { + out.print(fileData); + } + } diff --git a/patches/server/0718-Make-CallbackExecutor-strict-again.patch b/patches/server/0017-Make-CallbackExecutor-strict-again.patch similarity index 93% rename from patches/server/0718-Make-CallbackExecutor-strict-again.patch rename to patches/server/0017-Make-CallbackExecutor-strict-again.patch index 5a1db21f68..e37cf530bb 100644 --- a/patches/server/0718-Make-CallbackExecutor-strict-again.patch +++ b/patches/server/0017-Make-CallbackExecutor-strict-again.patch @@ -10,10 +10,10 @@ schedules. Effectively, use the callback executor as a tool of finding issues rather than hiding these issues. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index b659a058a0b6eb6b1827aacbd703e15fcbb1609c..2418f1c0dc050d224bb866e62f414a55900d9652 100644 +index ea27e6b1340a42c675bc68ed75f100569114be7a..4da0cbe58dad0f66e0d056c71684120514dcac6a 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -165,17 +165,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -157,17 +157,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public final CallbackExecutor callbackExecutor = new CallbackExecutor(); public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable { diff --git a/patches/server/0426-Delay-Chunk-Unloads-based-on-Player-Movement.patch b/patches/server/0018-Delay-Chunk-Unloads-based-on-Player-Movement.patch similarity index 93% rename from patches/server/0426-Delay-Chunk-Unloads-based-on-Player-Movement.patch rename to patches/server/0018-Delay-Chunk-Unloads-based-on-Player-Movement.patch index 21c409adc6..bd5e8ce10c 100644 --- a/patches/server/0426-Delay-Chunk-Unloads-based-on-Player-Movement.patch +++ b/patches/server/0018-Delay-Chunk-Unloads-based-on-Player-Movement.patch @@ -17,10 +17,10 @@ This allows servers with smaller worlds who do less long distance exploring to s wasting cpu cycles on saving/unloading/reloading chunks repeatedly. diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 62118348d6fb00f063507debb488e1ff431d139c..9bc956068df3baabb9f8e02ee74a6397de2bf587 100644 +index 6181f675d7addde30f7018b4cd46fe061a14da51..aaf6344d3187ceada947ce6ee0fbba91ca0271a3 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -212,6 +212,27 @@ public abstract class DistanceManager { +@@ -198,6 +198,27 @@ public abstract class DistanceManager { boolean removed = false; // CraftBukkit if (arraysetsorted.remove(ticket)) { removed = true; // CraftBukkit @@ -76,10 +76,10 @@ index ffc43e5d3d0563c9e9c171064511b2c65ddf67e1..f1128f0d4a9a0241ac6c9bc18dd13b43 } } diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java -index 78fbb4c3e52e900956ae0811aaf934c81ee5ea48..8770fe0db46b01e8b608637df4f1a669a3f4cdde 100644 +index 0d536d72ac918fbd403397ff369d10143ee9c204..dfa08dbf025ed702a864280a540e0169b9f33cbd 100644 --- a/src/main/java/net/minecraft/server/level/TicketType.java +++ b/src/main/java/net/minecraft/server/level/TicketType.java -@@ -28,6 +28,7 @@ public class TicketType { +@@ -26,6 +26,7 @@ public class TicketType { public static final TicketType UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1); public static final TicketType PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit public static final TicketType PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit diff --git a/patches/server/0252-Asynchronous-chunk-IO-and-loading.patch b/patches/server/0019-Asynchronous-chunk-IO-and-loading.patch similarity index 95% rename from patches/server/0252-Asynchronous-chunk-IO-and-loading.patch rename to patches/server/0019-Asynchronous-chunk-IO-and-loading.patch index 2a51a5d5f0..cf7bd1b0ad 100644 --- a/patches/server/0252-Asynchronous-chunk-IO-and-loading.patch +++ b/patches/server/0019-Asynchronous-chunk-IO-and-loading.patch @@ -2266,7 +2266,7 @@ index a5e438a834826161c52ca9db57d234d9ff80a591..b8bc1b9b8e8a33df90a963f9f9769292 @Override diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 97b29bcb20e199c2d02457f8025e67e2d4a925fc..8fda43173012ed3134ed1f114143ceaad66cae4a 100644 +index a48a12a31a3d09a9373b688dcc093035f8f8a300..0c59ca1a22449893adcfa851198f057ce69bb7e3 100644 --- a/src/main/java/net/minecraft/server/Main.java +++ b/src/main/java/net/minecraft/server/Main.java @@ -245,6 +245,7 @@ public class Main { @@ -2278,11 +2278,11 @@ index 97b29bcb20e199c2d02457f8025e67e2d4a925fc..8fda43173012ed3134ed1f114143ceaa DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, config.get(), ops.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::new); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 78f7f5603f6949c6aa92726d99e93ebdfea2b637..802b7767dd0878cf6d2e52bea74d5664f7d0664f 100644 +index 53be6189d3fa6a65a09996683913fbbf5133dcb7..d53fb6bba90936c1182b0687d014964cef81694f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -956,7 +956,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { ++ if (++saved[0] >= maxAsyncSaves) { ++ saved[0] = 0; ++ com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.flush(); ++ } ++ }; ++ // Paper end - do not overload I/O threads with too much work when saving + if (flush) { + List list = (List) net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper + MutableBoolean mutableboolean = new MutableBoolean(); +@@ -574,6 +585,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + }).filter((ichunkaccess) -> { + return ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk; + }).filter(this::save).forEach((ichunkaccess) -> { ++ onChunkSave.run(); // Paper - do not overload I/O threads with too much work when saving + mutableboolean.setTrue(); + }); + } while (mutableboolean.isTrue()); +@@ -581,7 +593,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.processUnloads(() -> { return true; }); @@ -2310,9 +2335,9 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 + //this.flushWorker(); // Paper - nuke IOWorker + this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour } else { - this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded); + net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); } -@@ -572,11 +574,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -591,11 +604,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider protected void tick(BooleanSupplier shouldKeepTicking) { ProfilerFiller gameprofilerfiller = this.level.getProfiler(); @@ -2328,7 +2353,7 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 } gameprofilerfiller.pop(); -@@ -639,7 +645,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -658,7 +675,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ((LevelChunk) ichunkaccess).setLoaded(false); } @@ -2346,7 +2371,7 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 if (this.entitiesInLevel.remove(pos) && ichunkaccess instanceof LevelChunk) { LevelChunk chunk = (LevelChunk) ichunkaccess; -@@ -705,32 +720,54 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -727,32 +753,54 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private CompletableFuture> scheduleChunkLoad(ChunkPos pos) { @@ -2420,7 +2445,7 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 return nbt.contains("Status", 8); } -@@ -969,7 +1006,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -991,7 +1039,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -2469,7 +2494,7 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 this.poiManager.flush(chunk.getPos()); if (!chunk.isUnsaved()) { return false; -@@ -981,7 +1059,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1003,7 +1092,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ChunkStatus chunkstatus = chunk.getStatus(); if (chunkstatus.getChunkType() != ChunkStatus.ChunkType.LEVELCHUNK) { @@ -2478,7 +2503,7 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 return false; } -@@ -991,9 +1069,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1013,9 +1102,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } this.level.getProfiler().incrementCounter("chunkSave"); @@ -2496,7 +2521,7 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 this.markPosition(chunkcoordintpair, chunkstatus.getChunkType()); return true; } catch (Exception exception) { -@@ -1002,6 +1086,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1023,6 +1118,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return false; } } @@ -2504,7 +2529,7 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 } private boolean isExistingChunkFull(ChunkPos pos) { -@@ -1135,6 +1220,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1156,6 +1252,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -2541,10 +2566,10 @@ index 7793d6c254c418847d3b5b65e5232bf8192b561b..47cb3be2d778a55bfbe733a9cc2965c8 return this.read(chunkPos).thenApplyAsync((optional) -> { return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index f08089b8672454acf8c2309e850466b335248692..ab785bfc29c0b120b7c6fed2d15460c86e020291 100644 +index aaf6344d3187ceada947ce6ee0fbba91ca0271a3..1d6ab658c48bb765f66624f276ec7b05cf33c1d5 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -384,7 +384,7 @@ public abstract class DistanceManager { +@@ -402,7 +402,7 @@ public abstract class DistanceManager { } public void removeTicketsOnClosing() { @@ -2554,10 +2579,10 @@ index f08089b8672454acf8c2309e850466b335248692..ab785bfc29c0b120b7c6fed2d15460c8 while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index a81644df294c739b72fc638cd06a3976250caa50..d66ec02b09bb7ae46aae8e55f00626139f074ae3 100644 +index 514111ed7fe8aec0d5f15f7a8f157d5872a56e4f..3ff5e35e45a71dc03552dedb65c7338317e9d0a9 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -491,10 +491,111 @@ public class ServerChunkCache extends ChunkSource { +@@ -308,10 +308,111 @@ public class ServerChunkCache extends ChunkSource { return ret; } // Paper end @@ -2669,7 +2694,7 @@ index a81644df294c739b72fc638cd06a3976250caa50..d66ec02b09bb7ae46aae8e55f0062613 if (Thread.currentThread() != this.mainThread) { return (ChunkAccess) CompletableFuture.supplyAsync(() -> { return this.getChunk(x, z, leastStatus, create); -@@ -517,13 +618,18 @@ public class ServerChunkCache extends ChunkSource { +@@ -334,13 +435,18 @@ public class ServerChunkCache extends ChunkSource { } gameprofilerfiller.incrementCounter("getChunkCacheMiss"); @@ -2689,7 +2714,7 @@ index a81644df294c739b72fc638cd06a3976250caa50..d66ec02b09bb7ae46aae8e55f0062613 this.level.timings.syncChunkLoad.stopTiming(); // Paper } // Paper ichunkaccess = (ChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { -@@ -610,6 +716,11 @@ public class ServerChunkCache extends ChunkSource { +@@ -427,6 +533,11 @@ public class ServerChunkCache extends ChunkSource { } private CompletableFuture> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { @@ -2701,7 +2726,7 @@ index a81644df294c739b72fc638cd06a3976250caa50..d66ec02b09bb7ae46aae8e55f0062613 ChunkPos chunkcoordintpair = new ChunkPos(chunkX, chunkZ); long k = chunkcoordintpair.toLong(); int l = 33 + ChunkStatus.getDistance(leastStatus); -@@ -1033,11 +1144,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -841,11 +952,12 @@ public class ServerChunkCache extends ChunkSource { // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { try { @@ -2716,10 +2741,10 @@ index a81644df294c739b72fc638cd06a3976250caa50..d66ec02b09bb7ae46aae8e55f0062613 } finally { chunkMap.callbackExecutor.run(); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 6e804d560b44d8bfd0b184632e49d52fdb7879fb..02d4211b9c3a485ac23cce199d7edc7e4d445067 100644 +index 99d44faab5b5da244fdc170c73d73723c174c8fd..2f7646e2bcc9622d8579eec25b56615da5a84d06 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -317,6 +317,78 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -315,6 +315,78 @@ public class ServerLevel extends Level implements WorldGenLevel { } } } @@ -2798,7 +2823,7 @@ index 6e804d560b44d8bfd0b184632e49d52fdb7879fb..02d4211b9c3a485ac23cce199d7edc7e // Paper end // Add env and gen to constructor, IWorldDataServer -> WorldDataServer -@@ -399,6 +471,8 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -397,6 +469,8 @@ public class ServerLevel extends Level implements WorldGenLevel { this.sleepStatus = new SleepStatus(); this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit @@ -2808,7 +2833,7 @@ index 6e804d560b44d8bfd0b184632e49d52fdb7879fb..02d4211b9c3a485ac23cce199d7edc7e public void setWeatherParameters(int clearDuration, int rainDuration, boolean raining, boolean thundering) { diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java -index 0d536d72ac918fbd403397ff369d10143ee9c204..be677d437d17b74c6188ce1bd5fc6fdc228fd92f 100644 +index dfa08dbf025ed702a864280a540e0169b9f33cbd..10fa6cec911950f72407ae7f45c8cf48caa9421a 100644 --- a/src/main/java/net/minecraft/server/level/TicketType.java +++ b/src/main/java/net/minecraft/server/level/TicketType.java @@ -8,6 +8,7 @@ import net.minecraft.world.level.ChunkPos; @@ -2820,11 +2845,11 @@ index 0d536d72ac918fbd403397ff369d10143ee9c204..be677d437d17b74c6188ce1bd5fc6fdc private final String name; private final Comparator comparator; diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0bac1fa4637d7132871b8f57b0431724bc9aa8c1..d991354d65305ab7d02666f7c3362e4136c3f6af 100644 +index cdc24defe649644ceade1c6cfcfe20c29ca936c1..5072d4dc1f7f77c61e3cc72c1101cb95f6596ce7 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -799,6 +799,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper +@@ -784,6 +784,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + this.disconnect(Component.translatable("disconnect.spam")); return; } + // Paper start @@ -2835,8 +2860,8 @@ index 0bac1fa4637d7132871b8f57b0431724bc9aa8c1..d991354d65305ab7d02666f7c3362e41 + } + // Paper end // CraftBukkit end - // Paper start - async tab completion - TAB_COMPLETE_EXECUTOR.execute(() -> { + StringReader stringreader = new StringReader(packet.getCommand()); + diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java index 821052e93ee753db6aaf499bbf39dc30598fe72f..2955c1ee153c410ea45fe367bac8597621c9bbd0 100644 --- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java @@ -3285,7 +3310,7 @@ index c56946f86565ad1ac41bb7b655c113f648d2f539..694778b5c23dbe9c8603c3483476b525 } } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index 2d74ab966a1291895b6248a67a31fe4802b3773f..038e2177182c94baa4af24f9111cf155ec342dfe 100644 +index d51bafd2f5a763b8a49c835ab74a7cf60caa1ab6..7412da51c2eae70f17f4883f7223303d570c8402 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -44,6 +44,7 @@ public class RegionFile implements AutoCloseable { @@ -3305,7 +3330,7 @@ index 2d74ab966a1291895b6248a67a31fe4802b3773f..038e2177182c94baa4af24f9111cf155 int i = this.getOffset(pos); if (i == 0) { -@@ -395,6 +396,11 @@ public class RegionFile implements AutoCloseable { +@@ -393,6 +394,11 @@ public class RegionFile implements AutoCloseable { } public void close() throws IOException { @@ -3317,7 +3342,7 @@ index 2d74ab966a1291895b6248a67a31fe4802b3773f..038e2177182c94baa4af24f9111cf155 try { this.padToFullSector(); } finally { -@@ -404,6 +410,10 @@ public class RegionFile implements AutoCloseable { +@@ -402,6 +408,10 @@ public class RegionFile implements AutoCloseable { this.file.close(); } } @@ -3329,7 +3354,7 @@ index 2d74ab966a1291895b6248a67a31fe4802b3773f..038e2177182c94baa4af24f9111cf155 } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 5a35e5040726a981ae91f018f05b91c178a54ba0..9d7adf17851202adf03bf9feff3577069e324bc6 100644 +index 8ba1c073387fa21a20bd42a873ec3cc314eae64e..6fa0bc18ab05b9fb05521f46c5dadb695f1ec05b 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -29,11 +29,32 @@ public class RegionFileStorage implements AutoCloseable { @@ -3365,7 +3390,7 @@ index 5a35e5040726a981ae91f018f05b91c178a54ba0..9d7adf17851202adf03bf9feff357706 + // Paper end return regionfile; } else { - if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - configurable + if (this.regionCache.size() >= 256) { @@ -48,6 +69,12 @@ public class RegionFileStorage implements AutoCloseable { RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync); @@ -3410,13 +3435,13 @@ index 5a35e5040726a981ae91f018f05b91c178a54ba0..9d7adf17851202adf03bf9feff357706 - RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit + RegionFile regionfile = this.getRegionFile(pos, false, true); // CraftBukkit // Paper + try { // Paper - int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper if (nbt == null) { -@@ -169,9 +201,12 @@ public class RegionFileStorage implements AutoCloseable { - net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk", laste); + regionfile.clear(pos); +@@ -156,9 +188,12 @@ public class RegionFileStorage implements AutoCloseable { + } } - // Paper end + + } finally { // Paper start + regionfile.fileLock.unlock(); + } // Paper end @@ -3427,7 +3452,7 @@ index 5a35e5040726a981ae91f018f05b91c178a54ba0..9d7adf17851202adf03bf9feff357706 ExceptionCollector exceptionsuppressor = new ExceptionCollector<>(); ObjectIterator objectiterator = this.regionCache.values().iterator(); -@@ -188,7 +223,7 @@ public class RegionFileStorage implements AutoCloseable { +@@ -175,7 +210,7 @@ public class RegionFileStorage implements AutoCloseable { exceptionsuppressor.throwIfPresent(); } @@ -3554,95 +3579,14 @@ index 8a4750dd8f604062c4ea452f7b97b05a0c8d583a..678bd36581ead3a225e3a6e24b78e5db } + // Paper end } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 153c2e8bc317d9bff834645102235434e82716e1..0d939dc855d4e03df9a95d318e769d842892d46d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1956,6 +1956,34 @@ public class CraftWorld extends CraftRegionAccessor implements World { - public DragonBattle getEnderDragonBattle() { - return (this.getHandle().dragonFight() == null) ? null : new CraftDragonBattle(this.getHandle().dragonFight()); - } -+ // Paper start -+ @Override -+ public java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { -+ if (Bukkit.isPrimaryThread()) { -+ net.minecraft.world.level.chunk.LevelChunk immediate = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); -+ if (immediate != null) { -+ return java.util.concurrent.CompletableFuture.completedFuture(immediate.getBukkitChunk()); -+ } -+ } else { -+ java.util.concurrent.CompletableFuture future = new java.util.concurrent.CompletableFuture(); -+ world.getServer().execute(() -> { -+ getChunkAtAsync(x, z, gen, urgent).whenComplete((chunk, err) -> { -+ if (err != null) { -+ future.completeExceptionally(err); -+ } else { -+ future.complete(chunk); -+ } -+ }); -+ }); -+ return future; -+ } -+ -+ return this.world.getChunkSource().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> { -+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null); -+ return java.util.concurrent.CompletableFuture.completedFuture(chunk == null ? null : chunk.getBukkitChunk()); -+ }, net.minecraft.server.MinecraftServer.getServer()); -+ } -+ // Paper end - - @Override - public PersistentDataContainer getPersistentDataContainer() { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index e6b75dfa1a59c9f1f6afde7b4538abf8d51b7261..41920b979ab259fc27a57dde64abdba8c3be3185 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -533,6 +533,37 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - this.entity.setYHeadRot(yaw); - } - -+ // Paper start -+ @Override -+ public java.util.concurrent.CompletableFuture teleportAsync(Location location, TeleportCause cause) { -+ Preconditions.checkArgument(location != null, "location"); -+ location.checkFinite(); -+ Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. -+ -+ net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle(); -+ java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); -+ -+ world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), location.getX(), location.getZ(), (list) -> { -+ net.minecraft.server.level.ServerChunkCache chunkProviderServer = world.getChunkSource(); -+ for (net.minecraft.world.level.chunk.ChunkAccess chunk : list) { -+ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); -+ } -+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { -+ try { -+ ret.complete(CraftEntity.this.teleport(locationClone, cause) ? Boolean.TRUE : Boolean.FALSE); -+ } catch (Throwable throwable) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ ret.completeExceptionally(throwable); -+ } -+ }); -+ }); -+ -+ return ret; -+ } -+ // Paper end -+ - @Override - public boolean teleport(Location location) { - return this.teleport(location, TeleportCause.PLUGIN); diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index 06efdd7aa6d35a670e81c4f303618a7ba301396a..e62f085de1678568d422ef0eda5b9bfbd8b4d556 100644 +index 335120afc88a8fc1543c2e6df516fd728e3ab032..581cde7a74e00bee1ce69086132d5f871d206399 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -116,6 +116,7 @@ public class WatchdogThread extends Thread - // Paper end - Different message for short timeout +@@ -83,6 +83,7 @@ public class WatchdogThread extends Thread + // log.log( Level.SEVERE, "------------------------------" ); - log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper + log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" ); + com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); log.log( Level.SEVERE, "------------------------------" ); diff --git a/patches/server/0461-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch b/patches/server/0020-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch similarity index 87% rename from patches/server/0461-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch rename to patches/server/0020-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch index 71afd9f90e..0f3896c168 100644 --- a/patches/server/0461-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch +++ b/patches/server/0020-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch @@ -67,11 +67,95 @@ index af40e473521f408aa0e112953c43bdbce164a48b..68860a3b6db2aa50373d71aec9502c18 } } +diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java +index 7f76c304f5eb3c2f27b348918588ab67b795b1ba..1b1bfd5f92f85f46ad9661a0a64a2a1b4c33a80d 100644 +--- a/src/main/java/net/minecraft/server/ChunkSystem.java ++++ b/src/main/java/net/minecraft/server/ChunkSystem.java +@@ -55,6 +55,19 @@ public final class ChunkSystem { + + static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); + ++ // Paper start - priority ++ private static int getPriorityBoost(final PrioritisedExecutor.Priority priority) { ++ if (priority.isLowerOrEqualPriority(PrioritisedExecutor.Priority.NORMAL)) { ++ return 0; ++ } ++ ++ int dist = PrioritisedExecutor.Priority.BLOCKING.ordinal() - PrioritisedExecutor.Priority.NORMAL.ordinal(); ++ ++ ++ return (net.minecraft.server.level.DistanceManager.URGENT_PRIORITY * (priority.ordinal() - PrioritisedExecutor.Priority.NORMAL.ordinal())) / dist; ++ } ++ // Paper end - priority ++ + private static long chunkLoadCounter = 0L; + public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, + final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { +@@ -68,12 +81,19 @@ public final class ChunkSystem { + final int minLevel = 33 + ChunkStatus.getDistance(toStatus); + final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; + final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ final int priorityBoost = getPriorityBoost(priority); + + if (addTicket) { + level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); + } + level.chunkSource.runDistanceManagerUpdates(); + ++ if (priorityBoost == net.minecraft.server.level.DistanceManager.URGENT_PRIORITY) { ++ level.chunkSource.markUrgent(chunkPos); ++ } else if (priorityBoost != 0) { ++ level.chunkSource.markHighPriority(chunkPos, priorityBoost); ++ } ++ + final Consumer loadCallback = (final ChunkAccess chunk) -> { + try { + if (onComplete != null) { +@@ -89,6 +109,11 @@ public final class ChunkSystem { + level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); + level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); + } ++ if (priorityBoost == net.minecraft.server.level.DistanceManager.URGENT_PRIORITY) { ++ level.chunkSource.clearUrgent(chunkPos); ++ } else if (priorityBoost != 0) { ++ level.chunkSource.clearPriorityTickets(chunkPos); ++ } + } + }; + +@@ -135,12 +160,17 @@ public final class ChunkSystem { + final int radius = toStatus.ordinal() - 1; + final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; + final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ final int priorityBoost = getPriorityBoost(priority); + + if (addTicket) { + level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); + } + level.chunkSource.runDistanceManagerUpdates(); + ++ if (priorityBoost != 0) { ++ level.chunkSource.markAreaHighPriority(chunkPos, priorityBoost, radius); ++ } ++ + final Consumer loadCallback = (final LevelChunk chunk) -> { + try { + if (onComplete != null) { +@@ -156,6 +186,9 @@ public final class ChunkSystem { + level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); + level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); + } ++ if (priorityBoost != 0) { ++ level.chunkSource.clearAreaPriorityTickets(chunkPos, radius); ++ } + } + }; + diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index 4e29c0a983727fc839a4bcde01d3286396b3587d..613988c9ea892ab15516e1c8b4f376d52415ae34 100644 +index 2e56c52e3ee45b0304a9e6a5eab863ef96b2aab0..5eb6ce20ee17d87db0f6c2dcee96d6d0891d6c50 100644 --- a/src/main/java/net/minecraft/server/MCUtil.java +++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -681,6 +681,7 @@ public final class MCUtil { +@@ -634,6 +634,7 @@ public final class MCUtil { chunkData.addProperty("x", playerChunk.pos.x); chunkData.addProperty("z", playerChunk.pos.z); chunkData.addProperty("ticket-level", playerChunk.getTicketLevel()); @@ -80,7 +164,7 @@ index 4e29c0a983727fc839a4bcde01d3286396b3587d..613988c9ea892ab15516e1c8b4f376d5 chunkData.addProperty("queued-for-unload", chunkMap.toDrop.contains(playerChunk.pos.longKey)); chunkData.addProperty("status", status == null ? "unloaded" : status.toString()); diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 36a9d52d9af3bc398010c52dc16ab23e53f2702a..ece4cd0de061969d4d2f07560e6cf38e631098b3 100644 +index e30893d6cbe3b42338d04453d0f452babeb61d8a..a52932d665ca45a5e066d7cef0ec0313d1c3f69f 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -60,7 +60,7 @@ public class ChunkHolder { @@ -100,7 +184,7 @@ index 36a9d52d9af3bc398010c52dc16ab23e53f2702a..ece4cd0de061969d4d2f07560e6cf38e boolean isUpdateQueued = false; // Paper private final ChunkMap chunkMap; // Paper -@@ -448,12 +449,18 @@ public class ChunkHolder { +@@ -438,12 +439,18 @@ public class ChunkHolder { }); } @@ -119,7 +203,7 @@ index 36a9d52d9af3bc398010c52dc16ab23e53f2702a..ece4cd0de061969d4d2f07560e6cf38e ChunkStatus chunkstatus = ChunkHolder.getStatus(this.oldTicketLevel); ChunkStatus chunkstatus1 = ChunkHolder.getStatus(this.ticketLevel); boolean flag = this.oldTicketLevel <= ChunkMap.MAX_CHUNK_DISTANCE; -@@ -464,9 +471,22 @@ public class ChunkHolder { +@@ -454,9 +461,22 @@ public class ChunkHolder { // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins. if (playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> { @@ -143,22 +227,21 @@ index 36a9d52d9af3bc398010c52dc16ab23e53f2702a..ece4cd0de061969d4d2f07560e6cf38e // Minecraft will apply the chunks tick lists to the world once the chunk got loaded, and then store the tick // lists again inside the chunk once the chunk becomes inaccessible and set the chunk's needsSaving flag. // These actions may however happen deferred, so we manually set the needsSaving flag already here. -@@ -523,12 +543,14 @@ public class ChunkHolder { +@@ -501,11 +521,13 @@ public class ChunkHolder { this.scheduleFullChunkPromotion(chunkStorage, this.fullChunkFuture, executor, ChunkHolder.FullChunkStatus.BORDER); // Paper start - cache ticking ready status this.fullChunkFuture.thenAccept(either -> { + io.papermc.paper.util.TickThread.ensureTickThread("Async full chunk future completion"); // Paper final Optional left = either.left(); if (left.isPresent() && ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { - // note: Here is a very good place to add callbacks to logic waiting on this. LevelChunk fullChunk = either.left().get(); ChunkHolder.this.isFullChunkReady = true; - fullChunk.playerChunk = ChunkHolder.this; -+ this.chunkMap.distanceManager.clearPriorityTickets(pos); + net.minecraft.server.ChunkSystem.onChunkBorder(fullChunk, this); ++ this.chunkMap.distanceManager.clearPriorityTickets(pos); // Paper - chunk priority } }); this.updateChunkToSave(this.fullChunkFuture, "full"); -@@ -549,6 +571,7 @@ public class ChunkHolder { +@@ -531,6 +553,7 @@ public class ChunkHolder { this.scheduleFullChunkPromotion(chunkStorage, this.tickingChunkFuture, executor, ChunkHolder.FullChunkStatus.TICKING); // Paper start - cache ticking ready status this.tickingChunkFuture.thenAccept(either -> { @@ -166,15 +249,15 @@ index 36a9d52d9af3bc398010c52dc16ab23e53f2702a..ece4cd0de061969d4d2f07560e6cf38e either.ifLeft(chunk -> { // note: Here is a very good place to add callbacks to logic waiting on this. ChunkHolder.this.isTickingReady = true; -@@ -584,6 +607,7 @@ public class ChunkHolder { +@@ -563,6 +586,7 @@ public class ChunkHolder { this.scheduleFullChunkPromotion(chunkStorage, this.entityTickingChunkFuture, executor, ChunkHolder.FullChunkStatus.ENTITY_TICKING); // Paper start - cache ticking ready status this.entityTickingChunkFuture.thenAccept(either -> { + io.papermc.paper.util.TickThread.ensureTickThread("Async full chunk future completion"); // Paper either.ifLeft(chunk -> { ChunkHolder.this.isEntityTickingReady = true; - // Paper start - entity ticking chunk set -@@ -610,16 +634,45 @@ public class ChunkHolder { + net.minecraft.server.ChunkSystem.onChunkEntityTicking(chunk, this); +@@ -586,16 +610,45 @@ public class ChunkHolder { this.demoteFullChunk(chunkStorage, playerchunk_state1); } @@ -223,7 +306,7 @@ index 36a9d52d9af3bc398010c52dc16ab23e53f2702a..ece4cd0de061969d4d2f07560e6cf38e }); } }).exceptionally((throwable) -> { -@@ -744,7 +797,134 @@ public class ChunkHolder { +@@ -696,7 +749,134 @@ public class ChunkHolder { }; } @@ -360,7 +443,7 @@ index 36a9d52d9af3bc398010c52dc16ab23e53f2702a..ece4cd0de061969d4d2f07560e6cf38e return this.isEntityTickingReady; } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb620315c80 100644 +index c3bbaf32373a32417f8b83f386f8cf327c6e0893..46bfaf04867d913c1782d851de101d913376c63a 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -131,6 +131,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -371,7 +454,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 public ChunkGenerator generator; private RandomState randomState; public final Supplier overworldDataStorage; -@@ -334,6 +335,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -267,6 +268,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } this.mainThreadExecutor = mainThreadExecutor; @@ -387,7 +470,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 ProcessorMailbox threadedmailbox = ProcessorMailbox.create(executor, "worldgen"); Objects.requireNonNull(mainThreadExecutor); -@@ -449,6 +459,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -309,6 +319,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }); } @@ -422,10 +505,10 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 + } + // Paper end + - // Paper start - public void updatePlayerMobTypeMap(Entity entity) { - if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { -@@ -559,6 +600,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { + double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8); + double d1 = (double) SectionPos.sectionToBlockCoord(pos.z, 8); +@@ -399,6 +440,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider List list1 = new ArrayList(); int j = centerChunk.x; int k = centerChunk.z; @@ -433,7 +516,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 for (int l = -margin; l <= margin; ++l) { for (int i1 = -margin; i1 <= margin; ++i1) { -@@ -577,6 +619,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -417,6 +459,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ChunkStatus chunkstatus = (ChunkStatus) distanceToStatus.apply(j1); CompletableFuture> completablefuture = playerchunk.getOrScheduleFuture(chunkstatus, this); @@ -448,7 +531,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 list1.add(playerchunk); list.add(completablefuture); -@@ -934,11 +984,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -733,11 +783,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (requiredStatus == ChunkStatus.EMPTY) { return this.scheduleChunkLoad(chunkcoordintpair); } else { @@ -469,7 +552,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 if (optional.isPresent() && ((ChunkAccess) optional.get()).getStatus().isOrAfter(requiredStatus)) { CompletableFuture> completablefuture = requiredStatus.load(this.level, this.structureTemplateManager, this.lightEngine, (ichunkaccess) -> { -@@ -950,6 +1008,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -749,6 +807,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } else { return this.scheduleChunkGeneration(holder, requiredStatus); } @@ -477,7 +560,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 } } -@@ -989,14 +1048,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -788,14 +847,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }; CompletableFuture chunkSaveFuture = this.level.asyncChunkTaskManager.getChunkSaveFuture(pos.x, pos.z); @@ -507,7 +590,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 return ret; // Paper end - Async chunk io } -@@ -1075,7 +1144,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -874,7 +943,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.releaseLightTicket(chunkcoordintpair); return CompletableFuture.completedFuture(Either.right(playerchunk_failure)); }); @@ -519,7 +602,7 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 } protected void releaseLightTicket(ChunkPos pos) { -@@ -1159,7 +1231,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -957,7 +1029,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider long i = chunkHolder.getPos().toLong(); Objects.requireNonNull(chunkHolder); @@ -529,10 +612,10 @@ index 4d74eb7883c72fb42275fc5358917244bb36181d..7b1781faed02a5b5fa37ca6f079d1fb6 } diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 9bc956068df3baabb9f8e02ee74a6397de2bf587..b2df5e18ce5260a9781052db7afb0b9786fb887c 100644 +index 1d6ab658c48bb765f66624f276ec7b05cf33c1d5..b9b56068cdacd984f873cfb2a06a312e9912893d 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -128,6 +128,7 @@ public abstract class DistanceManager { +@@ -114,6 +114,7 @@ public abstract class DistanceManager { } private static int getTicketLevelAt(SortedArraySet> tickets) { @@ -540,15 +623,15 @@ index 9bc956068df3baabb9f8e02ee74a6397de2bf587..b2df5e18ce5260a9781052db7afb0b97 return !tickets.isEmpty() ? ((Ticket) tickets.first()).getTicketLevel() : ChunkMap.MAX_CHUNK_DISTANCE + 1; } -@@ -142,6 +143,7 @@ public abstract class DistanceManager { +@@ -128,6 +129,7 @@ public abstract class DistanceManager { public boolean runAllUpdates(ChunkMap chunkStorage) { - //this.f.a(); // Paper - no longer used + this.naturalSpawnChunkCounter.runAllUpdates(); this.tickingTicketsTracker.runAllUpdates(); + org.spigotmc.AsyncCatcher.catchOp("DistanceManagerTick"); // Paper this.playerTicketManager.runAllUpdates(); int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE); boolean flag = i != 0; -@@ -152,11 +154,13 @@ public abstract class DistanceManager { +@@ -138,11 +140,13 @@ public abstract class DistanceManager { // Paper start if (!this.pendingChunkUpdates.isEmpty()) { @@ -562,7 +645,7 @@ index 9bc956068df3baabb9f8e02ee74a6397de2bf587..b2df5e18ce5260a9781052db7afb0b97 // Paper end return true; } else { -@@ -192,8 +196,10 @@ public abstract class DistanceManager { +@@ -178,8 +182,10 @@ public abstract class DistanceManager { return flag; } } @@ -573,7 +656,7 @@ index 9bc956068df3baabb9f8e02ee74a6397de2bf587..b2df5e18ce5260a9781052db7afb0b97 SortedArraySet> arraysetsorted = this.getTickets(i); int j = DistanceManager.getTicketLevelAt(arraysetsorted); Ticket ticket1 = (Ticket) arraysetsorted.addOrGet(ticket); -@@ -207,7 +213,9 @@ public abstract class DistanceManager { +@@ -193,7 +199,9 @@ public abstract class DistanceManager { } boolean removeTicket(long i, Ticket ticket) { // CraftBukkit - void -> boolean @@ -583,7 +666,7 @@ index 9bc956068df3baabb9f8e02ee74a6397de2bf587..b2df5e18ce5260a9781052db7afb0b97 boolean removed = false; // CraftBukkit if (arraysetsorted.remove(ticket)) { -@@ -239,7 +247,12 @@ public abstract class DistanceManager { +@@ -225,7 +233,12 @@ public abstract class DistanceManager { this.tickets.remove(i); } @@ -597,7 +680,7 @@ index 9bc956068df3baabb9f8e02ee74a6397de2bf587..b2df5e18ce5260a9781052db7afb0b97 return removed; // CraftBukkit } -@@ -289,6 +302,112 @@ public abstract class DistanceManager { +@@ -275,6 +288,112 @@ public abstract class DistanceManager { }); } @@ -711,10 +794,10 @@ index 9bc956068df3baabb9f8e02ee74a6397de2bf587..b2df5e18ce5260a9781052db7afb0b97 Ticket ticket = new Ticket<>(TicketType.FORCED, 31, pos); long i = pos.toLong(); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 585892f19bc0aea89889a358c0407f2975b9efe5..918fda0fbbafa39ce0f421dcaf10f8dcf1e5dabb 100644 +index 3ff5e35e45a71dc03552dedb65c7338317e9d0a9..2400212e65c72d3ce6604b3cf200db0ae7032f2a 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -590,6 +590,26 @@ public class ServerChunkCache extends ChunkSource { +@@ -407,6 +407,30 @@ public class ServerChunkCache extends ChunkSource { return CompletableFuture.completedFuture(either); }, this.mainThreadProcessor); } @@ -737,11 +820,15 @@ index 585892f19bc0aea89889a358c0407f2975b9efe5..918fda0fbbafa39ce0f421dcaf10f8dc + + public void clearPriorityTickets(ChunkPos coords) { + this.distanceManager.clearPriorityTickets(coords); ++ } ++ ++ public void clearUrgent(ChunkPos coords) { ++ this.distanceManager.clearUrgent(coords); + } // Paper end - async chunk io @Nullable -@@ -630,6 +650,8 @@ public class ServerChunkCache extends ChunkSource { +@@ -441,6 +465,8 @@ public class ServerChunkCache extends ChunkSource { Objects.requireNonNull(completablefuture); if (!completablefuture.isDone()) { // Paper // Paper start - async chunk io/loading @@ -750,7 +837,7 @@ index 585892f19bc0aea89889a358c0407f2975b9efe5..918fda0fbbafa39ce0f421dcaf10f8dc this.level.asyncChunkTaskManager.raisePriority(x1, z1, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY); com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.level, x1, z1); // Paper end -@@ -638,6 +660,8 @@ public class ServerChunkCache extends ChunkSource { +@@ -448,6 +474,8 @@ public class ServerChunkCache extends ChunkSource { chunkproviderserver_b.managedBlock(completablefuture::isDone); com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug this.level.timings.syncChunkLoad.stopTiming(); // Paper @@ -759,7 +846,7 @@ index 585892f19bc0aea89889a358c0407f2975b9efe5..918fda0fbbafa39ce0f421dcaf10f8dc } // Paper ichunkaccess = (ChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { return ichunkaccess1; -@@ -711,10 +735,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -553,10 +581,12 @@ public class ServerChunkCache extends ChunkSource { if (create && !currentlyUnloading) { // CraftBukkit end this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); @@ -772,7 +859,7 @@ index 585892f19bc0aea89889a358c0407f2975b9efe5..918fda0fbbafa39ce0f421dcaf10f8dc this.runDistanceManagerUpdates(); playerchunk = this.getVisibleChunkIfPresent(k); gameprofilerfiller.pop(); -@@ -724,7 +750,13 @@ public class ServerChunkCache extends ChunkSource { +@@ -566,7 +596,13 @@ public class ServerChunkCache extends ChunkSource { } } @@ -787,7 +874,7 @@ index 585892f19bc0aea89889a358c0407f2975b9efe5..918fda0fbbafa39ce0f421dcaf10f8dc } private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) { -@@ -776,6 +808,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -618,6 +654,7 @@ public class ServerChunkCache extends ChunkSource { } public boolean runDistanceManagerUpdates() { @@ -796,10 +883,10 @@ index 585892f19bc0aea89889a358c0407f2975b9efe5..918fda0fbbafa39ce0f421dcaf10f8dc boolean flag1 = this.chunkMap.promoteChunkMap(); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 0720b748ed42bbd2a12cc5de79224f609a5e29be..6f2b52165c1935511790a429792d3754251537c8 100644 +index 9ab4588e4e512176b881ad4c252e400ff6ea97bd..4adf2d503015cac85b12fbaae833b33eeeb44403 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -194,6 +194,7 @@ public class ServerPlayer extends Player { +@@ -191,6 +191,7 @@ public class ServerPlayer extends Player { private int lastRecordedArmor = Integer.MIN_VALUE; private int lastRecordedLevel = Integer.MIN_VALUE; private int lastRecordedExperience = Integer.MIN_VALUE; @@ -807,9 +894,9 @@ index 0720b748ed42bbd2a12cc5de79224f609a5e29be..6f2b52165c1935511790a429792d3754 private float lastSentHealth = -1.0E8F; private int lastSentFood = -99999999; private boolean lastFoodSaturationZero = true; -@@ -338,6 +339,21 @@ public class ServerPlayer extends Player { +@@ -318,6 +319,21 @@ public class ServerPlayer extends Player { + this.bukkitPickUpLoot = true; this.maxHealthCache = this.getMaxHealth(); - this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper } + // Paper start - Chunk priority + public BlockPos getPointInFront(double inFront) { @@ -1099,7 +1186,7 @@ index f1128f0d4a9a0241ac6c9bc18dd13b431c616bb1..2b2b7851d5f68bcdb41d58bcc64740ba protected Ticket(TicketType type, int level, T argument) { this.type = type; diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java -index 8770fe0db46b01e8b608637df4f1a669a3f4cdde..3c1698ba0d3bc412ab957777d9b5211dbc555208 100644 +index 10fa6cec911950f72407ae7f45c8cf48caa9421a..478109526cff7ceb0565cea3b5e97b9a07fbf8d1 100644 --- a/src/main/java/net/minecraft/server/level/TicketType.java +++ b/src/main/java/net/minecraft/server/level/TicketType.java @@ -9,6 +9,8 @@ import net.minecraft.world.level.ChunkPos; @@ -1112,33 +1199,22 @@ index 8770fe0db46b01e8b608637df4f1a669a3f4cdde..3c1698ba0d3bc412ab957777d9b5211d private final String name; private final Comparator comparator; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 9819bb3c36e314103236832a133906957255ee7a..3ca3275f7f66410217b86ba8ca09d85ef64f3f83 100644 +index 5833cc3d5014dad82607afc4d643b6bed885be64..8e0f73dcef189442450b4518437fb3a1c34b9a47 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -179,6 +179,7 @@ public abstract class PlayerList { +@@ -177,6 +177,7 @@ public abstract class PlayerList { } public void placeNewPlayer(Connection connection, ServerPlayer player) { + player.isRealPlayer = true; // Paper - Chunk priority - ServerPlayer prev = pendingPlayers.put(player.getUUID(), player);// Paper - if (prev != null) { - disconnectPendingPlayer(prev); -@@ -294,8 +295,8 @@ public abstract class PlayerList { - net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap; - net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager; - distanceManager.addTicket(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong()); -- worldserver1.getChunkSource().runDistanceManagerUpdates(); -- worldserver1.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, true).thenApply(chunk -> { -+ worldserver1.getChunkSource().markAreaHighPriority(pos, 28, 3); // Paper - Chunk priority -+ worldserver1.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, false).thenApply(chunk -> { // Paper - Chunk priority - net.minecraft.server.level.ChunkHolder updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong()); - if (updatingChunk != null) { - return updatingChunk.getEntityTickingChunkFuture(); + GameProfile gameprofile = player.getGameProfile(); + GameProfileCache usercache = this.server.getProfileCache(); + Optional optional = usercache.get(gameprofile.getId()); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 258aa2ee24742d48be08940f147e1d998e667fb8..7e36e53d44b5efbd6498caecb717bec1dcbec96d 100644 +index 47a05aa42739f4cfce828c0de42b4f1da467093e..70c338f5bf605d2f51a21670634c716177cd6f97 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -293,7 +293,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -212,7 +212,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { private BlockPos blockPosition; private ChunkPos chunkPosition; private Vec3 deltaMovement; @@ -1148,10 +1224,10 @@ index 258aa2ee24742d48be08940f147e1d998e667fb8..7e36e53d44b5efbd6498caecb717bec1 public float yRotO; public float xRotO; 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 f8a3048fa80758d82f2e92d48bd3cd2c585ae6c2..2981ba61e347b8660082ff946521fc7f219d2c0d 100644 +index 58a245b2ca6e65d491694142ad04d38236b46434..893051059df51133a127b0870e27ab67461052fa 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -141,7 +141,7 @@ public class LevelChunk extends ChunkAccess { +@@ -134,7 +134,7 @@ public class LevelChunk extends ChunkAccess { return NEIGHBOUR_CACHE_RADIUS; } @@ -1160,7 +1236,7 @@ index f8a3048fa80758d82f2e92d48bd3cd2c585ae6c2..2981ba61e347b8660082ff946521fc7f private long neighbourChunksLoadedBitset; private final LevelChunk[] loadedNeighbourChunks = new LevelChunk[(NEIGHBOUR_CACHE_RADIUS * 2 + 1) * (NEIGHBOUR_CACHE_RADIUS * 2 + 1)]; -@@ -693,6 +693,7 @@ public class LevelChunk extends ChunkAccess { +@@ -653,6 +653,7 @@ public class LevelChunk extends ChunkAccess { // CraftBukkit start public void loadCallback() { @@ -1168,7 +1244,7 @@ index f8a3048fa80758d82f2e92d48bd3cd2c585ae6c2..2981ba61e347b8660082ff946521fc7f // Paper start - neighbour cache int chunkX = this.chunkPos.x; int chunkZ = this.chunkPos.z; -@@ -747,6 +748,7 @@ public class LevelChunk extends ChunkAccess { +@@ -707,6 +708,7 @@ public class LevelChunk extends ChunkAccess { } public void unloadCallback() { @@ -1176,41 +1252,3 @@ index f8a3048fa80758d82f2e92d48bd3cd2c585ae6c2..2981ba61e347b8660082ff946521fc7f org.bukkit.Server server = this.level.getCraftServer(); org.bukkit.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(this.bukkitChunk, this.isUnsaved()); server.getPluginManager().callEvent(unloadEvent); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index b234ba968e82ddf1e8f7c84d3a17659e3beda2b3..af22fa8aa8ddef4d592564b14d0114cc6f903fca 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2077,6 +2077,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - return future; - } - -+ // Paper start - Chunk priority -+ if (!urgent) { -+ // If not urgent, at least use a slightly boosted priority -+ world.getChunkSource().markHighPriority(new ChunkPos(x, z), 1); -+ } -+ // Paper end - return this.world.getChunkSource().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> { - net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null); - if (chunk != null) addTicket(x, z); // Paper -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 0fda8c27c717bd030b826c5c7267b880f9d1f6b9..8db930d54ad97435e367aa670466d8a072ca0b23 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1047,6 +1047,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - throw new UnsupportedOperationException("Cannot set rotation of players. Consider teleporting instead."); - } - -+ // Paper start - Chunk priority -+ @Override -+ public java.util.concurrent.CompletableFuture teleportAsync(Location loc, @javax.annotation.Nonnull PlayerTeleportEvent.TeleportCause cause) { -+ ((CraftWorld)loc.getWorld()).getHandle().getChunkSource().markAreaHighPriority( -+ new net.minecraft.world.level.ChunkPos(net.minecraft.util.Mth.floor(loc.getX()) >> 4, -+ net.minecraft.util.Mth.floor(loc.getZ()) >> 4), 28, 3); // Load area high priority -+ return super.teleportAsync(loc, cause); -+ } -+ // Paper end -+ - @Override - public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) { - Preconditions.checkArgument(location != null, "location"); diff --git a/patches/server/0013-Add-command-line-option-to-load-extra-plugin-jars-no.patch b/patches/server/0021-Add-command-line-option-to-load-extra-plugin-jars-no.patch similarity index 97% rename from patches/server/0013-Add-command-line-option-to-load-extra-plugin-jars-no.patch rename to patches/server/0021-Add-command-line-option-to-load-extra-plugin-jars-no.patch index f7a089ab62..5bb64f964f 100644 --- a/patches/server/0013-Add-command-line-option-to-load-extra-plugin-jars-no.patch +++ b/patches/server/0021-Add-command-line-option-to-load-extra-plugin-jars-no.patch @@ -7,7 +7,7 @@ Subject: [PATCH] Add command line option to load extra plugin jars not in the ex: java -jar paperclip.jar nogui -add-plugin=/path/to/plugin.jar -add-plugin=/path/to/another/plugin_jar.jar diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 5badb27d2060b0b13c54f8945848afbeb775fc6c..45c51529c9f94dfbd575ca94acd3c025bdb909e9 100644 +index eb5c7e15366ee5902d8c754a1e9daec50d26fb17..37fefdf0d96cd2b6e23b6e69ee5a8db16f0e51da 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -405,10 +405,15 @@ public final class CraftServer implements Server { diff --git a/patches/server/0014-Configurable-cactus-bamboo-and-reed-growth-heights.patch b/patches/server/0022-Configurable-cactus-bamboo-and-reed-growth-heights.patch similarity index 100% rename from patches/server/0014-Configurable-cactus-bamboo-and-reed-growth-heights.patch rename to patches/server/0022-Configurable-cactus-bamboo-and-reed-growth-heights.patch diff --git a/patches/server/0015-Configurable-baby-zombie-movement-speed.patch b/patches/server/0023-Configurable-baby-zombie-movement-speed.patch similarity index 100% rename from patches/server/0015-Configurable-baby-zombie-movement-speed.patch rename to patches/server/0023-Configurable-baby-zombie-movement-speed.patch diff --git a/patches/server/0016-Configurable-fishing-time-ranges.patch b/patches/server/0024-Configurable-fishing-time-ranges.patch similarity index 100% rename from patches/server/0016-Configurable-fishing-time-ranges.patch rename to patches/server/0024-Configurable-fishing-time-ranges.patch diff --git a/patches/server/0017-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch b/patches/server/0025-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch similarity index 100% rename from patches/server/0017-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch rename to patches/server/0025-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch diff --git a/patches/server/0018-Add-configurable-despawn-distances-for-living-entiti.patch b/patches/server/0026-Add-configurable-despawn-distances-for-living-entiti.patch similarity index 100% rename from patches/server/0018-Add-configurable-despawn-distances-for-living-entiti.patch rename to patches/server/0026-Add-configurable-despawn-distances-for-living-entiti.patch diff --git a/patches/server/0019-Allow-for-toggling-of-spawn-chunks.patch b/patches/server/0027-Allow-for-toggling-of-spawn-chunks.patch similarity index 100% rename from patches/server/0019-Allow-for-toggling-of-spawn-chunks.patch rename to patches/server/0027-Allow-for-toggling-of-spawn-chunks.patch diff --git a/patches/server/0020-Drop-falling-block-and-tnt-entities-at-the-specified.patch b/patches/server/0028-Drop-falling-block-and-tnt-entities-at-the-specified.patch similarity index 100% rename from patches/server/0020-Drop-falling-block-and-tnt-entities-at-the-specified.patch rename to patches/server/0028-Drop-falling-block-and-tnt-entities-at-the-specified.patch diff --git a/patches/server/0021-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch b/patches/server/0029-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch similarity index 95% rename from patches/server/0021-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch rename to patches/server/0029-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch index 15e19a0a94..40bf559133 100644 --- a/patches/server/0021-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch +++ b/patches/server/0029-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Show 'Paper' in client crashes, server lists, and Mojang diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 53be6189d3fa6a65a09996683913fbbf5133dcb7..e6acf596c2c62134e8d2e499d273aa326f792451 100644 +index d53fb6bba90936c1182b0687d014964cef81694f..645eaf7e6717486b583c49724c5891d5c270c38f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1432,7 +1432,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index cdc24defe649644ceade1c6cfcfe20c29ca936c1..4fe65f979e8c3c15aea2211035745a71aef0feeb 100644 +index 5072d4dc1f7f77c61e3cc72c1101cb95f6596ce7..451dd594a2acc6fbc7112b9ecfa737c942f10a3c 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2026,7 +2026,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2033,7 +2033,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic return true; } @@ -33,7 +33,7 @@ index cdc24defe649644ceade1c6cfcfe20c29ca936c1..4fe65f979e8c3c15aea2211035745a71 for (int i = 0; i < message.length(); ++i) { if (!SharedConstants.isAllowedChatCharacter(message.charAt(i))) { return true; -@@ -2043,7 +2043,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2050,7 +2050,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic } OutgoingPlayerChatMessage outgoing = OutgoingPlayerChatMessage.create(original); @@ -42,7 +42,7 @@ index cdc24defe649644ceade1c6cfcfe20c29ca936c1..4fe65f979e8c3c15aea2211035745a71 this.handleCommand(s); } else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { // Do nothing, this is coming from a plugin -@@ -2146,7 +2146,29 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2153,7 +2153,29 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic } } diff --git a/patches/server/0048-All-chunks-are-slime-spawn-chunks-toggle.patch b/patches/server/0056-All-chunks-are-slime-spawn-chunks-toggle.patch similarity index 100% rename from patches/server/0048-All-chunks-are-slime-spawn-chunks-toggle.patch rename to patches/server/0056-All-chunks-are-slime-spawn-chunks-toggle.patch diff --git a/patches/server/0049-Expose-server-CommandMap.patch b/patches/server/0057-Expose-server-CommandMap.patch similarity index 87% rename from patches/server/0049-Expose-server-CommandMap.patch rename to patches/server/0057-Expose-server-CommandMap.patch index 1eb15fa1c0..4270ea1e72 100644 --- a/patches/server/0049-Expose-server-CommandMap.patch +++ b/patches/server/0057-Expose-server-CommandMap.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Expose server CommandMap diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index b61a98f2711c8aeca65e6e782c07ace05c56fbe8..4c0f321128271f77a54b1ed814033cdd8a712350 100644 +index 1c6577bbbc005131661cbb4667cff6494b8fe5e4..fd3ccc1726cd73e9f5be3f936115e2431c77183c 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1983,6 +1983,7 @@ public final class CraftServer implements Server { diff --git a/patches/server/0050-Be-a-bit-more-informative-in-maxHealth-exception.patch b/patches/server/0058-Be-a-bit-more-informative-in-maxHealth-exception.patch similarity index 100% rename from patches/server/0050-Be-a-bit-more-informative-in-maxHealth-exception.patch rename to patches/server/0058-Be-a-bit-more-informative-in-maxHealth-exception.patch diff --git a/patches/server/0051-Ensure-inv-drag-is-in-bounds.patch b/patches/server/0059-Ensure-inv-drag-is-in-bounds.patch similarity index 100% rename from patches/server/0051-Ensure-inv-drag-is-in-bounds.patch rename to patches/server/0059-Ensure-inv-drag-is-in-bounds.patch diff --git a/patches/server/0052-Player-Tab-List-and-Title-APIs.patch b/patches/server/0060-Player-Tab-List-and-Title-APIs.patch similarity index 98% rename from patches/server/0052-Player-Tab-List-and-Title-APIs.patch rename to patches/server/0060-Player-Tab-List-and-Title-APIs.patch index 09f96b3601..9d0c41ec61 100644 --- a/patches/server/0052-Player-Tab-List-and-Title-APIs.patch +++ b/patches/server/0060-Player-Tab-List-and-Title-APIs.patch @@ -63,7 +63,7 @@ index bd808eb312ade7122973a47f4b96505829511da5..bf0f9cab7c66c089f35b851e799ba4a4 // Paper end buf.writeComponent(this.text); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index b73b202a3c68ba559b65245186a97025bda25134..383168bc9af2174cbe6a0c914d0dbbc8b9d3d156 100644 +index 2666e55d72fd7731a2bde42d690762a2747dac90..f4f704ec29cb9eb2f4de2b77261a54169bb40a93 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1,5 +1,6 @@ diff --git a/patches/server/0053-Add-configurable-portal-search-radius.patch b/patches/server/0061-Add-configurable-portal-search-radius.patch similarity index 96% rename from patches/server/0053-Add-configurable-portal-search-radius.patch rename to patches/server/0061-Add-configurable-portal-search-radius.patch index e209c92ee2..911f221d1d 100644 --- a/patches/server/0053-Add-configurable-portal-search-radius.patch +++ b/patches/server/0061-Add-configurable-portal-search-radius.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add configurable portal search radius diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 45aca8dde5b6f1a3aef907b1a74809e7f4aa66e4..d95f2f0757a339917ff8061ae3cf169bbed054bf 100644 +index a761c5b3551c7a87b8d04b03f5640805007fbcd3..3bf89827afc515ffae0f79532b38c5f31ba014f6 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -2937,7 +2937,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0054-Add-velocity-warnings.patch b/patches/server/0062-Add-velocity-warnings.patch similarity index 90% rename from patches/server/0054-Add-velocity-warnings.patch rename to patches/server/0062-Add-velocity-warnings.patch index 649ff7887d..1f75e318ba 100644 --- a/patches/server/0054-Add-velocity-warnings.patch +++ b/patches/server/0062-Add-velocity-warnings.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add velocity warnings diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 4c0f321128271f77a54b1ed814033cdd8a712350..fe4bf2bdd43d4d85c62d3939305dbecc1ae01eb9 100644 +index fd3ccc1726cd73e9f5be3f936115e2431c77183c..c1c86dc95d610bb391191317fa0c0e4c8e41d198 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -280,6 +280,7 @@ public final class CraftServer implements Server { @@ -17,7 +17,7 @@ index 4c0f321128271f77a54b1ed814033cdd8a712350..fe4bf2bdd43d4d85c62d3939305dbecc static { ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index f79f2867b62e25e9bf8e1102d12bcd07c913675b..e1ae00c1639b4ff18e061d86b006ff733494bb00 100644 +index fba18e3c6903d4ed8233b4d32ed07bf08311ca27..8b4f1ef248d0b13927cbf634a0e2a97eb93c8ae4 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -450,10 +450,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @@ -62,7 +62,7 @@ index f79f2867b62e25e9bf8e1102d12bcd07c913675b..e1ae00c1639b4ff18e061d86b006ff73 public double getHeight() { return this.getHandle().getBbHeight(); diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index d5863b0b06384b25eaa33572fa02649795463ed8..2693cc933d746e40d8a47d96c6cb6799f0a2472f 100644 +index f8018902365e9115ae0132885a2546d115b24c36..600c012b2bf119ddd6760b0401a2c6a22453609e 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java @@ -80,7 +80,19 @@ public class WatchdogThread extends Thread @@ -85,4 +85,4 @@ index d5863b0b06384b25eaa33572fa02649795463ed8..2693cc933d746e40d8a47d96c6cb6799 + // Paper end log.log( Level.SEVERE, "------------------------------" ); log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper - WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); + com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper diff --git a/patches/server/0055-Configurable-inter-world-teleportation-safety.patch b/patches/server/0063-Configurable-inter-world-teleportation-safety.patch similarity index 94% rename from patches/server/0055-Configurable-inter-world-teleportation-safety.patch rename to patches/server/0063-Configurable-inter-world-teleportation-safety.patch index 5f2a39c0d7..4863fd9b13 100644 --- a/patches/server/0055-Configurable-inter-world-teleportation-safety.patch +++ b/patches/server/0063-Configurable-inter-world-teleportation-safety.patch @@ -16,7 +16,7 @@ The wanted destination was on top of the emerald block however the player ended This only is the case if the player is teleporting between worlds. diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 97307be401ca8a5207aa7b96a6f7961f9fc76786..3794d05b17378ebf517199adbbfd54a395ef6b37 100644 +index f4f704ec29cb9eb2f4de2b77261a54169bb40a93..d91f69639724aeeb4264f86cf8f76edc22567649 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1050,7 +1050,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0056-Add-exception-reporting-event.patch b/patches/server/0064-Add-exception-reporting-event.patch similarity index 96% rename from patches/server/0056-Add-exception-reporting-event.patch rename to patches/server/0064-Add-exception-reporting-event.patch index 3875f2110a..fb76a4b5df 100644 --- a/patches/server/0056-Add-exception-reporting-event.patch +++ b/patches/server/0064-Add-exception-reporting-event.patch @@ -49,10 +49,10 @@ index 0000000000000000000000000000000000000000..f699ce18ca044f813e194ef2786b7ea8 + } +} diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index ca1e483819bffc948fab10f88563084aa75d1484..1c73599e37e9b830ff0ab9bcc9edc7b63daa6ca1 100644 +index 46bfaf04867d913c1782d851de101d913376c63a..4af8cee31d20e5dcec510439795e7e90fc668128 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -999,6 +999,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1187,6 +1187,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return true; } catch (Exception exception) { ChunkMap.LOGGER.error("Failed to save chunk {},{}", new Object[]{chunkcoordintpair.x, chunkcoordintpair.z, exception}); @@ -143,7 +143,7 @@ index b37e04a0c466dacf52e74a4d4fb0885511c2abc1..878fc7f57178bff0e42fd01434f0aaa2 } 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 a438025a2102fa911a6941cd9723c84743113dc7..2704a05766d42b0277fa6308820b88371db00ace 100644 +index 51b53bbed1dbd344d8646d4827e44ee7215524a9..a4e121365717036dfc27eec86549d6dbac1ffc1a 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -1,6 +1,7 @@ @@ -175,7 +175,7 @@ index a438025a2102fa911a6941cd9723c84743113dc7..2704a05766d42b0277fa6308820b8837 // CraftBukkit end } } -@@ -1052,6 +1059,7 @@ public class LevelChunk extends ChunkAccess { +@@ -1054,6 +1061,7 @@ public class LevelChunk extends ChunkAccess { // Paper start - Prevent tile entity and entity crashes final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ()); net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable); @@ -184,10 +184,10 @@ index a438025a2102fa911a6941cd9723c84743113dc7..2704a05766d42b0277fa6308820b8837 // Paper end // Spigot start diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index d51bafd2f5a763b8a49c835ab74a7cf60caa1ab6..fbf5f01a9a7968194fc85589ca7f9fa328da4881 100644 +index 7412da51c2eae70f17f4883f7223303d570c8402..8adebb8408cc22ae7e9e89721645e5dd27a41cd8 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -274,6 +274,7 @@ public class RegionFile implements AutoCloseable { +@@ -275,6 +275,7 @@ public class RegionFile implements AutoCloseable { return true; } } catch (IOException ioexception) { @@ -195,7 +195,7 @@ index d51bafd2f5a763b8a49c835ab74a7cf60caa1ab6..fbf5f01a9a7968194fc85589ca7f9fa3 return false; } } -@@ -355,6 +356,7 @@ public class RegionFile implements AutoCloseable { +@@ -356,6 +357,7 @@ public class RegionFile implements AutoCloseable { ((java.nio.Buffer) bytebuffer).position(5); // CraftBukkit - decompile error filechannel.write(bytebuffer); } catch (Throwable throwable) { diff --git a/patches/server/0057-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch b/patches/server/0065-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch similarity index 100% rename from patches/server/0057-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch rename to patches/server/0065-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch diff --git a/patches/server/0058-Disable-Scoreboards-for-non-players-by-default.patch b/patches/server/0066-Disable-Scoreboards-for-non-players-by-default.patch similarity index 90% rename from patches/server/0058-Disable-Scoreboards-for-non-players-by-default.patch rename to patches/server/0066-Disable-Scoreboards-for-non-players-by-default.patch index 65ba2b1f02..f95a3237bf 100644 --- a/patches/server/0058-Disable-Scoreboards-for-non-players-by-default.patch +++ b/patches/server/0066-Disable-Scoreboards-for-non-players-by-default.patch @@ -11,7 +11,7 @@ So avoid looking up scoreboards and short circuit to the "not on a team" logic which is most likely to be true. diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index d95f2f0757a339917ff8061ae3cf169bbed054bf..0f50355ea57101e71df6990c1e19c7b927f5c306 100644 +index 3bf89827afc515ffae0f79532b38c5f31ba014f6..4218d5aa5b4ba77d304b91c6c6cd9fa9cdaaa532 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -2575,6 +2575,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { @@ -23,7 +23,7 @@ index d95f2f0757a339917ff8061ae3cf169bbed054bf..0f50355ea57101e71df6990c1e19c7b9 } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index c1c0757852c4925bcd1debe79a3946c972c4be70..d6e5f48fca5a965fc073ecca29ba5e24a4cd52f2 100644 +index 0d61cb2b7af48bbc60b04be6a4767ccba2b29ffb..3023e714961d1b565d9e8659e07ccc4dab729f2f 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -823,6 +823,7 @@ public abstract class LivingEntity extends Entity { diff --git a/patches/server/0059-Add-methods-for-working-with-arrows-stuck-in-living-.patch b/patches/server/0067-Add-methods-for-working-with-arrows-stuck-in-living-.patch similarity index 100% rename from patches/server/0059-Add-methods-for-working-with-arrows-stuck-in-living-.patch rename to patches/server/0067-Add-methods-for-working-with-arrows-stuck-in-living-.patch diff --git a/patches/server/0060-Chunk-Save-Reattempt.patch b/patches/server/0068-Chunk-Save-Reattempt.patch similarity index 73% rename from patches/server/0060-Chunk-Save-Reattempt.patch rename to patches/server/0068-Chunk-Save-Reattempt.patch index 82a269b220..a10ae30efd 100644 --- a/patches/server/0060-Chunk-Save-Reattempt.patch +++ b/patches/server/0068-Chunk-Save-Reattempt.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Chunk Save Reattempt We commonly have "Stream Closed" errors on chunk saving, so this code should re-try to save the chunk in the event of failure and hopefully prevent rollbacks. diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index fbf5f01a9a7968194fc85589ca7f9fa328da4881..2d74ab966a1291895b6248a67a31fe4802b3773f 100644 +index 8adebb8408cc22ae7e9e89721645e5dd27a41cd8..038e2177182c94baa4af24f9111cf155ec342dfe 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -274,7 +274,7 @@ public class RegionFile implements AutoCloseable { +@@ -275,7 +275,7 @@ public class RegionFile implements AutoCloseable { return true; } } catch (IOException ioexception) { @@ -19,33 +19,33 @@ index fbf5f01a9a7968194fc85589ca7f9fa328da4881..2d74ab966a1291895b6248a67a31fe48 } } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 8ba1c073387fa21a20bd42a873ec3cc314eae64e..eaf22cec54b512e0f57606f50627d5fe9b39bd5c 100644 +index 6fa0bc18ab05b9fb05521f46c5dadb695f1ec05b..4210c43104de01200b149e13ffab09dea37c5caf 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -131,6 +131,7 @@ public class RegionFileStorage implements AutoCloseable { - +@@ -163,6 +163,7 @@ public class RegionFileStorage implements AutoCloseable { protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { - RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit + RegionFile regionfile = this.getRegionFile(pos, false, true); // CraftBukkit // Paper + try { // Paper + int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper if (nbt == null) { regionfile.clear(pos); -@@ -156,6 +157,18 @@ public class RegionFileStorage implements AutoCloseable { +@@ -187,7 +188,18 @@ public class RegionFileStorage implements AutoCloseable { + dataoutputstream.close(); } } - -+ // Paper start -+ return; ++ // Paper start ++ return; + } catch (Exception ex) { + laste = ex; + } + } -+ + + if (laste != null) { + com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(laste); -+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk", laste); ++ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk " + pos, laste); + } + // Paper end - } - - public void close() throws IOException { + } finally { // Paper start + regionfile.fileLock.unlock(); + } // Paper end diff --git a/patches/server/0061-Complete-resource-pack-API.patch b/patches/server/0069-Complete-resource-pack-API.patch similarity index 96% rename from patches/server/0061-Complete-resource-pack-API.patch rename to patches/server/0069-Complete-resource-pack-API.patch index d92f972605..de2eef11b5 100644 --- a/patches/server/0061-Complete-resource-pack-API.patch +++ b/patches/server/0069-Complete-resource-pack-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Complete resource pack API diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 4fe65f979e8c3c15aea2211035745a71aef0feeb..bcd95c61ba98604552c3269e974e27b88658f38e 100644 +index 451dd594a2acc6fbc7112b9ecfa737c942f10a3c..e4f1b7fca8046df11f7e212c316385f82ce45322 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1756,8 +1756,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1763,8 +1763,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic ServerGamePacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName()); this.disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); } diff --git a/patches/server/0062-Default-loading-permissions.yml-before-plugins.patch b/patches/server/0070-Default-loading-permissions.yml-before-plugins.patch similarity index 95% rename from patches/server/0062-Default-loading-permissions.yml-before-plugins.patch rename to patches/server/0070-Default-loading-permissions.yml-before-plugins.patch index 2492bada58..6b823b51be 100644 --- a/patches/server/0062-Default-loading-permissions.yml-before-plugins.patch +++ b/patches/server/0070-Default-loading-permissions.yml-before-plugins.patch @@ -16,7 +16,7 @@ modify that. Under the previous logic, plugins were unable (cleanly) override pe A config option has been added for those who depend on the previous behavior, but I don't expect that. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index fe4bf2bdd43d4d85c62d3939305dbecc1ae01eb9..63eabacf2743d14bb02147869e51491e392b96bf 100644 +index c1c86dc95d610bb391191317fa0c0e4c8e41d198..2df58a9f40843abca02125d5f094129a8a75caf5 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -462,6 +462,7 @@ public final class CraftServer implements Server { diff --git a/patches/server/0063-Allow-Reloading-of-Custom-Permissions.patch b/patches/server/0071-Allow-Reloading-of-Custom-Permissions.patch similarity index 94% rename from patches/server/0063-Allow-Reloading-of-Custom-Permissions.patch rename to patches/server/0071-Allow-Reloading-of-Custom-Permissions.patch index 88c1b9b95a..fa49c037a8 100644 --- a/patches/server/0063-Allow-Reloading-of-Custom-Permissions.patch +++ b/patches/server/0071-Allow-Reloading-of-Custom-Permissions.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Allow Reloading of Custom Permissions https://github.com/PaperMC/Paper/issues/49 diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 63eabacf2743d14bb02147869e51491e392b96bf..858707ce778fad5bbdcc31e61de57dbfed2f94b4 100644 +index 2df58a9f40843abca02125d5f094129a8a75caf5..d4016a8890fff0805bacab3e5a556e7316c9ab25 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2537,5 +2537,23 @@ public final class CraftServer implements Server { diff --git a/patches/server/0064-Remove-Metadata-on-reload.patch b/patches/server/0072-Remove-Metadata-on-reload.patch similarity index 93% rename from patches/server/0064-Remove-Metadata-on-reload.patch rename to patches/server/0072-Remove-Metadata-on-reload.patch index dce360d5ec..7e8fa9271c 100644 --- a/patches/server/0064-Remove-Metadata-on-reload.patch +++ b/patches/server/0072-Remove-Metadata-on-reload.patch @@ -7,7 +7,7 @@ Metadata is not meant to persist reload as things break badly with non primitive This will remove metadata on reload so it does not crash everything if a plugin uses it. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 858707ce778fad5bbdcc31e61de57dbfed2f94b4..460d95ece9a9ba053a50d5a1cf69ac3bc85131a3 100644 +index d4016a8890fff0805bacab3e5a556e7316c9ab25..9a3b5b491256537d54c5fd0ac1646b3eb726187d 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -950,8 +950,16 @@ public final class CraftServer implements Server { diff --git a/patches/server/0065-Handle-Item-Meta-Inconsistencies.patch b/patches/server/0073-Handle-Item-Meta-Inconsistencies.patch similarity index 100% rename from patches/server/0065-Handle-Item-Meta-Inconsistencies.patch rename to patches/server/0073-Handle-Item-Meta-Inconsistencies.patch diff --git a/patches/server/0066-Configurable-Non-Player-Arrow-Despawn-Rate.patch b/patches/server/0074-Configurable-Non-Player-Arrow-Despawn-Rate.patch similarity index 100% rename from patches/server/0066-Configurable-Non-Player-Arrow-Despawn-Rate.patch rename to patches/server/0074-Configurable-Non-Player-Arrow-Despawn-Rate.patch diff --git a/patches/server/0067-Add-World-Util-Methods.patch b/patches/server/0075-Add-World-Util-Methods.patch similarity index 96% rename from patches/server/0067-Add-World-Util-Methods.patch rename to patches/server/0075-Add-World-Util-Methods.patch index 20d322962d..72c0c64816 100644 --- a/patches/server/0067-Add-World-Util-Methods.patch +++ b/patches/server/0075-Add-World-Util-Methods.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Add World Util Methods Methods that can be used for other patches to help improve logic. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 5d693946111a73e25fcbff2475a2f47a44066fbf..8f1c2d8e6cd0500f7e51d134cb5ea549752a1184 100644 +index 3a41a346e886918160eccaee57118747e33f6cc1..7e663cb0a214d59baaa6d3da75a8e2fca05cc56d 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -216,7 +216,7 @@ public class ServerLevel extends Level implements WorldGenLevel { diff --git a/patches/server/0068-Custom-replacement-for-eaten-items.patch b/patches/server/0076-Custom-replacement-for-eaten-items.patch similarity index 100% rename from patches/server/0068-Custom-replacement-for-eaten-items.patch rename to patches/server/0076-Custom-replacement-for-eaten-items.patch diff --git a/patches/server/0069-handle-NaN-health-absorb-values-and-repair-bad-data.patch b/patches/server/0077-handle-NaN-health-absorb-values-and-repair-bad-data.patch similarity index 96% rename from patches/server/0069-handle-NaN-health-absorb-values-and-repair-bad-data.patch rename to patches/server/0077-handle-NaN-health-absorb-values-and-repair-bad-data.patch index edc3918f65..9e4b4b1cbb 100644 --- a/patches/server/0069-handle-NaN-health-absorb-values-and-repair-bad-data.patch +++ b/patches/server/0077-handle-NaN-health-absorb-values-and-repair-bad-data.patch @@ -44,7 +44,7 @@ index 1dcf41a4105c05c3182afa8585dee20723d2c136..54e7fa7a483e15c440f562559601292c } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index b85ca8bded5157adad810b9a50ca0fe377597c93..edd750b20a3367a1fb00ed5df593102730a8f26a 100644 +index 6ae934c6c7c50dd38ff2e762fddfe650e97aa4ae..da91150f7462c2743d7394b148ddb52e9af8b797 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1932,6 +1932,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0070-Use-a-Shared-Random-for-Entities.patch b/patches/server/0078-Use-a-Shared-Random-for-Entities.patch similarity index 97% rename from patches/server/0070-Use-a-Shared-Random-for-Entities.patch rename to patches/server/0078-Use-a-Shared-Random-for-Entities.patch index a843fc1916..fa08041dbb 100644 --- a/patches/server/0070-Use-a-Shared-Random-for-Entities.patch +++ b/patches/server/0078-Use-a-Shared-Random-for-Entities.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Use a Shared Random for Entities Reduces memory usage and provides ensures more randomness, Especially since a lot of garbage entity objects get created. diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0f50355ea57101e71df6990c1e19c7b927f5c306..829dc369891c0d120da6ed00ab981c6fd204596d 100644 +index 4218d5aa5b4ba77d304b91c6c6cd9fa9cdaaa532..72915f876d456a28ea3609e46861412052065f37 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -159,6 +159,79 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0071-Configurable-spawn-chances-for-skeleton-horses.patch b/patches/server/0079-Configurable-spawn-chances-for-skeleton-horses.patch similarity index 90% rename from patches/server/0071-Configurable-spawn-chances-for-skeleton-horses.patch rename to patches/server/0079-Configurable-spawn-chances-for-skeleton-horses.patch index 95175f6fe6..0af7b6e1ad 100644 --- a/patches/server/0071-Configurable-spawn-chances-for-skeleton-horses.patch +++ b/patches/server/0079-Configurable-spawn-chances-for-skeleton-horses.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configurable spawn chances for skeleton horses diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 8f1c2d8e6cd0500f7e51d134cb5ea549752a1184..22e0612183be9e419d52ac2274dc728900433249 100644 +index 7e663cb0a214d59baaa6d3da75a8e2fca05cc56d..44600f8915f04f0baf3f877dff43d23e1b8ad93a 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -587,7 +587,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -663,7 +663,7 @@ public class ServerLevel extends Level implements WorldGenLevel { blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); if (this.isRainingAt(blockposition)) { DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); diff --git a/patches/server/0072-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch b/patches/server/0080-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch similarity index 98% rename from patches/server/0072-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch rename to patches/server/0080-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch index a013493ee6..4c1319763c 100644 --- a/patches/server/0072-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch +++ b/patches/server/0080-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch @@ -88,7 +88,7 @@ index 3dff0f7c3ccd04a67b2153e402d801de2341e520..7b320357973202423c29743d922b72dc @Override public FluidState getFluidState(BlockPos pos) { 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 2704a05766d42b0277fa6308820b88371db00ace..a508b7c6dbf9f7acdca77c219d7dd2492cd7c6b8 100644 +index a4e121365717036dfc27eec86549d6dbac1ffc1a..4c4f44457d2066ea37cf48e37a282d8896649bc5 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -296,12 +296,29 @@ public class LevelChunk extends ChunkAccess { diff --git a/patches/server/0073-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch b/patches/server/0081-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch similarity index 96% rename from patches/server/0073-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch rename to patches/server/0081-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch index 5109b67c42..ed5e601ed1 100644 --- a/patches/server/0073-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch +++ b/patches/server/0081-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener Saves on some object allocation and processing when no plugin listens to this diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 40ea9d30c5d9a0936ba495adea4d96775bce2e06..00424041950529973eaf33f4d312dbd1038ae675 100644 +index a65d86f7b48bf1fbc2186804a8c05921363c7272..4fc75c6086c7f41414b73b901c7a90f06267a089 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1356,6 +1356,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { return worldserver + " " + worldserver.dimension().location(); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 22e0612183be9e419d52ac2274dc728900433249..bd60bb4a1fa7f3c38c651f72bc58dffcd5736b43 100644 +index 44600f8915f04f0baf3f877dff43d23e1b8ad93a..79c22c0eb5adf6e08f7978272b8482fe53c4a45a 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -215,6 +215,7 @@ public class ServerLevel extends Level implements WorldGenLevel { diff --git a/patches/server/0074-Entity-AddTo-RemoveFrom-World-Events.patch b/patches/server/0082-Entity-AddTo-RemoveFrom-World-Events.patch similarity index 83% rename from patches/server/0074-Entity-AddTo-RemoveFrom-World-Events.patch rename to patches/server/0082-Entity-AddTo-RemoveFrom-World-Events.patch index 1bb60c8efa..bc343d006f 100644 --- a/patches/server/0074-Entity-AddTo-RemoveFrom-World-Events.patch +++ b/patches/server/0082-Entity-AddTo-RemoveFrom-World-Events.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Entity AddTo/RemoveFrom World Events diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index bd60bb4a1fa7f3c38c651f72bc58dffcd5736b43..c94fc95adfce7ec4ab3d881f1667f2f54ae38393 100644 +index 79c22c0eb5adf6e08f7978272b8482fe53c4a45a..14f55837c8614633b9a6edf7d35af465fbf8aa17 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2119,6 +2119,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2195,6 +2195,7 @@ public class ServerLevel extends Level implements WorldGenLevel { entity.setOrigin(entity.getOriginVector().toLocation(getWorld())); } // Paper end @@ -16,7 +16,7 @@ index bd60bb4a1fa7f3c38c651f72bc58dffcd5736b43..c94fc95adfce7ec4ab3d881f1667f2f5 } public void onTrackingEnd(Entity entity) { -@@ -2194,6 +2195,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2270,6 +2271,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } } // CraftBukkit end diff --git a/patches/server/0075-Configurable-Chunk-Inhabited-Time.patch b/patches/server/0083-Configurable-Chunk-Inhabited-Time.patch similarity index 92% rename from patches/server/0075-Configurable-Chunk-Inhabited-Time.patch rename to patches/server/0083-Configurable-Chunk-Inhabited-Time.patch index 3dc363ab29..44d87ae0db 100644 --- a/patches/server/0075-Configurable-Chunk-Inhabited-Time.patch +++ b/patches/server/0083-Configurable-Chunk-Inhabited-Time.patch @@ -11,7 +11,7 @@ For people who want all chunks to be treated equally, you can chose a fixed valu This allows to fine-tune vanilla gameplay. 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 a508b7c6dbf9f7acdca77c219d7dd2492cd7c6b8..e9fae214f60fe682087d41cfaa55a1b25e5f4331 100644 +index 4c4f44457d2066ea37cf48e37a282d8896649bc5..e63086aba2512051fe1321f6e7e72b40276f5dde 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -281,6 +281,13 @@ public class LevelChunk extends ChunkAccess { diff --git a/patches/server/0076-EntityPathfindEvent.patch b/patches/server/0084-EntityPathfindEvent.patch similarity index 100% rename from patches/server/0076-EntityPathfindEvent.patch rename to patches/server/0084-EntityPathfindEvent.patch diff --git a/patches/server/0077-Sanitise-RegionFileCache-and-make-configurable.patch b/patches/server/0085-Sanitise-RegionFileCache-and-make-configurable.patch similarity index 86% rename from patches/server/0077-Sanitise-RegionFileCache-and-make-configurable.patch rename to patches/server/0085-Sanitise-RegionFileCache-and-make-configurable.patch index 071a254a0c..c1c284728b 100644 --- a/patches/server/0077-Sanitise-RegionFileCache-and-make-configurable.patch +++ b/patches/server/0085-Sanitise-RegionFileCache-and-make-configurable.patch @@ -11,11 +11,11 @@ The implementation uses a LinkedHashMap as an LRU cache (modified from HashMap). The maximum size of the RegionFileCache is also made configurable. diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index eaf22cec54b512e0f57606f50627d5fe9b39bd5c..5a35e5040726a981ae91f018f05b91c178a54ba0 100644 +index 4210c43104de01200b149e13ffab09dea37c5caf..b790bb574546fef1969584529e49dbcf1403e198 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -36,7 +36,7 @@ public class RegionFileStorage implements AutoCloseable { - if (regionfile != null) { +@@ -57,7 +57,7 @@ public class RegionFileStorage implements AutoCloseable { + // Paper end return regionfile; } else { - if (this.regionCache.size() >= 256) { diff --git a/patches/server/0078-Do-not-load-chunks-for-Pathfinding.patch b/patches/server/0086-Do-not-load-chunks-for-Pathfinding.patch similarity index 100% rename from patches/server/0078-Do-not-load-chunks-for-Pathfinding.patch rename to patches/server/0086-Do-not-load-chunks-for-Pathfinding.patch diff --git a/patches/server/0079-Add-PlayerUseUnknownEntityEvent.patch b/patches/server/0087-Add-PlayerUseUnknownEntityEvent.patch similarity index 95% rename from patches/server/0079-Add-PlayerUseUnknownEntityEvent.patch rename to patches/server/0087-Add-PlayerUseUnknownEntityEvent.patch index 63947ccb44..b9bcde6187 100644 --- a/patches/server/0079-Add-PlayerUseUnknownEntityEvent.patch +++ b/patches/server/0087-Add-PlayerUseUnknownEntityEvent.patch @@ -20,10 +20,10 @@ index 8834ed411a7db86b4d2b88183a1315317107d719..c45b5ab6776f3ac79f856c3a6467c510 static final ServerboundInteractPacket.Action ATTACK_ACTION = new ServerboundInteractPacket.Action() { @Override diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index bcd95c61ba98604552c3269e974e27b88658f38e..33237c6a9f8885abdd5379d17be2b71ad7c2204e 100644 +index e4f1b7fca8046df11f7e212c316385f82ce45322..1161ed7ba2a32a42fb092f3f76af0bba958c44ae 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2635,8 +2635,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2642,8 +2642,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic }); } } diff --git a/patches/server/0080-Configurable-Grass-Spread-Tick-Rate.patch b/patches/server/0088-Configurable-Grass-Spread-Tick-Rate.patch similarity index 100% rename from patches/server/0080-Configurable-Grass-Spread-Tick-Rate.patch rename to patches/server/0088-Configurable-Grass-Spread-Tick-Rate.patch diff --git a/patches/server/0081-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch b/patches/server/0089-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch similarity index 82% rename from patches/server/0081-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch rename to patches/server/0089-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch index d56c30920d..02bb35bb40 100644 --- a/patches/server/0081-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch +++ b/patches/server/0089-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix Cancelling BlockPlaceEvent triggering physics diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index c94fc95adfce7ec4ab3d881f1667f2f54ae38393..14e618db89745942893f82d57f5383fcca6c41e9 100644 +index 14f55837c8614633b9a6edf7d35af465fbf8aa17..af3eab8bb09ca86a38724f38417b03a55b6bb06c 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1365,6 +1365,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1441,6 +1441,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public void updateNeighborsAt(BlockPos pos, Block sourceBlock) { diff --git a/patches/server/0082-Optimize-DataBits.patch b/patches/server/0090-Optimize-DataBits.patch similarity index 100% rename from patches/server/0082-Optimize-DataBits.patch rename to patches/server/0090-Optimize-DataBits.patch diff --git a/patches/server/0083-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch b/patches/server/0091-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch similarity index 100% rename from patches/server/0083-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch rename to patches/server/0091-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch diff --git a/patches/server/0084-Configurable-Player-Collision.patch b/patches/server/0092-Configurable-Player-Collision.patch similarity index 94% rename from patches/server/0084-Configurable-Player-Collision.patch rename to patches/server/0092-Configurable-Player-Collision.patch index 6a8a20af72..e72b7dc458 100644 --- a/patches/server/0084-Configurable-Player-Collision.patch +++ b/patches/server/0092-Configurable-Player-Collision.patch @@ -18,7 +18,7 @@ index 1294b38262505b0d54089e428df9b363219de1f0..ee37ec0de1ca969144824427ae42b0c8 buf.writeComponent(this.playerPrefix); buf.writeComponent(this.playerSuffix); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 00424041950529973eaf33f4d312dbd1038ae675..0dffb6e8d6f4edfb4dfaa6b24e81d72356446ebc 100644 +index 4fc75c6086c7f41414b73b901c7a90f06267a089..23e9a4ba6b108aa7a7fb8e0c4a765986380eefbd 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -580,6 +580,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop pendingBlockEntityTickers = Lists.newArrayList(); private boolean tickingBlockEntities; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 40d6b00fb40db167c6c80b6a3f79eb82d08cdfb9..40dd3913ac630899206a506ea9dfc58de634f391 100644 +index 0ed46cdd443ac42a7d57ee59f6f04fd9e9259c16..b2e693b6a799568c6196c1f805f0153ea69b8bd2 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -152,6 +152,57 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -152,6 +152,56 @@ public class CraftWorld extends CraftRegionAccessor implements World { private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY); private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers @@ -42,9 +42,8 @@ index 40d6b00fb40db167c6c80b6a3f79eb82d08cdfb9..40dd3913ac630899206a506ea9dfc58d + @Override + public int getTileEntityCount() { + // We don't use the full world tile entity list, so we must iterate chunks -+ Long2ObjectLinkedOpenHashMap chunks = world.getChunkSource().chunkMap.visibleChunkMap; + int size = 0; -+ for (ChunkHolder playerchunk : chunks.values()) { ++ for (ChunkHolder playerchunk : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world)) { + net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk(); + if (chunk == null) { + continue; @@ -63,7 +62,7 @@ index 40d6b00fb40db167c6c80b6a3f79eb82d08cdfb9..40dd3913ac630899206a506ea9dfc58d + public int getChunkCount() { + int ret = 0; + -+ for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.visibleChunkMap.values()) { ++ for (ChunkHolder chunkHolder : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world)) { + if (chunkHolder.getTickingChunk() != null) { + ++ret; + } diff --git a/patches/server/0123-Enforce-Sync-Player-Saves.patch b/patches/server/0131-Enforce-Sync-Player-Saves.patch similarity index 87% rename from patches/server/0123-Enforce-Sync-Player-Saves.patch rename to patches/server/0131-Enforce-Sync-Player-Saves.patch index a514731ac4..84ab1f0188 100644 --- a/patches/server/0123-Enforce-Sync-Player-Saves.patch +++ b/patches/server/0131-Enforce-Sync-Player-Saves.patch @@ -7,10 +7,10 @@ Saving players async is extremely dangerous. This will force it to main the same way we handle async chunk loads. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b4f29bed0332489ccae54cfb7a7f90e4df89743f..23687ae4a06be741a82cec1178d891aed4640084 100644 +index a474241c66a532791d9734ab9a9f6529f5414169..40d1f5433f3f1277663c65be2f85aaee5652f88a 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1041,11 +1041,13 @@ public abstract class PlayerList { +@@ -1042,11 +1042,13 @@ public abstract class PlayerList { } public void saveAll() { diff --git a/patches/server/0124-Don-t-allow-entities-to-ride-themselves-572.patch b/patches/server/0132-Don-t-allow-entities-to-ride-themselves-572.patch similarity index 90% rename from patches/server/0124-Don-t-allow-entities-to-ride-themselves-572.patch rename to patches/server/0132-Don-t-allow-entities-to-ride-themselves-572.patch index 89c1907eee..5f23a31a41 100644 --- a/patches/server/0124-Don-t-allow-entities-to-ride-themselves-572.patch +++ b/patches/server/0132-Don-t-allow-entities-to-ride-themselves-572.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Don't allow entities to ride themselves - #572 diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0fe534337ea72b338583039644f1f2b5be76d385..0c9cabfb5ff3733ac857889482474555b17b4e5c 100644 +index 32d230dc6968306dd6e322ffd6a820380e3c88b1..f7a8c947ef639d0d9cf8e527f8a0072432cba0c5 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -2319,6 +2319,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0125-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch b/patches/server/0133-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch similarity index 100% rename from patches/server/0125-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch rename to patches/server/0133-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch diff --git a/patches/server/0126-Cap-Entity-Collisions.patch b/patches/server/0134-Cap-Entity-Collisions.patch similarity index 95% rename from patches/server/0126-Cap-Entity-Collisions.patch rename to patches/server/0134-Cap-Entity-Collisions.patch index 9c60d092a6..9fc626bec9 100644 --- a/patches/server/0126-Cap-Entity-Collisions.patch +++ b/patches/server/0134-Cap-Entity-Collisions.patch @@ -12,7 +12,7 @@ just as it does in Vanilla, but entity pushing logic will be capped. You can set this to 0 to disable collisions. diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0c9cabfb5ff3733ac857889482474555b17b4e5c..778549f30d941352014983adb0e7a4457e6eb11b 100644 +index f7a8c947ef639d0d9cf8e527f8a0072432cba0c5..a676fa481ad3e3ac60cf5ba9d86acd61bea329ca 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -379,6 +379,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0127-Remove-CraftScheduler-Async-Task-Debugger.patch b/patches/server/0135-Remove-CraftScheduler-Async-Task-Debugger.patch similarity index 100% rename from patches/server/0127-Remove-CraftScheduler-Async-Task-Debugger.patch rename to patches/server/0135-Remove-CraftScheduler-Async-Task-Debugger.patch diff --git a/patches/server/0128-Do-not-let-armorstands-drown.patch b/patches/server/0136-Do-not-let-armorstands-drown.patch similarity index 100% rename from patches/server/0128-Do-not-let-armorstands-drown.patch rename to patches/server/0136-Do-not-let-armorstands-drown.patch diff --git a/patches/server/0129-Make-targetSize-more-aggressive-in-the-chunk-unload-.patch b/patches/server/0137-Make-targetSize-more-aggressive-in-the-chunk-unload-.patch similarity index 81% rename from patches/server/0129-Make-targetSize-more-aggressive-in-the-chunk-unload-.patch rename to patches/server/0137-Make-targetSize-more-aggressive-in-the-chunk-unload-.patch index bfb9bf42db..6a3c1b57fe 100644 --- a/patches/server/0129-Make-targetSize-more-aggressive-in-the-chunk-unload-.patch +++ b/patches/server/0137-Make-targetSize-more-aggressive-in-the-chunk-unload-.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Make targetSize more aggressive in the chunk unload queue diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 1c73599e37e9b830ff0ab9bcc9edc7b63daa6ca1..dd318c213742299fca1335fadf1f4465b471d7ea 100644 +index 4af8cee31d20e5dcec510439795e7e90fc668128..e086135936e4f6c109cd09a4e4df350702b3510a 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -233,7 +233,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -247,7 +247,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.entityMap = new Int2ObjectOpenHashMap(); this.chunkTypeCache = new Long2ByteOpenHashMap(); this.chunkSaveCooldowns = new Long2LongOpenHashMap(); @@ -17,15 +17,15 @@ index 1c73599e37e9b830ff0ab9bcc9edc7b63daa6ca1..dd318c213742299fca1335fadf1f4465 this.structureTemplateManager = structureTemplateManager; Path path = session.getDimensionPath(world.dimension()); -@@ -588,7 +588,6 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -674,7 +674,6 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private void processUnloads(BooleanSupplier shouldKeepTicking) { LongIterator longiterator = this.toDrop.iterator(); - for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { long j = longiterator.nextLong(); - ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); -@@ -601,7 +600,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy +@@ -688,7 +687,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } diff --git a/patches/server/0130-Properly-handle-async-calls-to-restart-the-server.patch b/patches/server/0138-Properly-handle-async-calls-to-restart-the-server.patch similarity index 97% rename from patches/server/0130-Properly-handle-async-calls-to-restart-the-server.patch rename to patches/server/0138-Properly-handle-async-calls-to-restart-the-server.patch index 22e1461d66..dda388b4c6 100644 --- a/patches/server/0130-Properly-handle-async-calls-to-restart-the-server.patch +++ b/patches/server/0138-Properly-handle-async-calls-to-restart-the-server.patch @@ -30,7 +30,7 @@ will have plugins and worlds saving to the disk has a high potential to result in corruption/dataloss. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 8c9bc0995f5b59e05a4ecebbe2bfb5d65ec92dcf..81e54058bc5e034b076e2bad1115c53950b3b39b 100644 +index da790861a3689195446040e8e7d2f898eee3068e..7f392cb74778de9854704895337bc78901552b44 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -221,6 +221,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0.0D; if (this.player.isOnGround() && !packet.isOnGround() && flag) { diff --git a/patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch b/patches/server/0165-handle-ServerboundKeepAlivePacket-async.patch similarity index 92% rename from patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch rename to patches/server/0165-handle-ServerboundKeepAlivePacket-async.patch index 05c48ce612..39a68612c6 100644 --- a/patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch +++ b/patches/server/0165-handle-ServerboundKeepAlivePacket-async.patch @@ -15,10 +15,10 @@ also adding some additional logging in order to help work out what is causing random disconnections for clients. diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 9eb204ba4df5064fcca40c9445a5fc6a10d1b3aa..96091153862433ffe2fdc90c00f1cc6be02e8977 100644 +index b44fd3e73d2d15736ac2bbcc7d99ae44c7459d4b..c6330fa43f205c28f3a494269933482c14f75afb 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3233,14 +3233,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -3240,14 +3240,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic @Override public void handleKeepAlive(ServerboundKeepAlivePacket packet) { diff --git a/patches/server/0158-Expose-client-protocol-version-and-virtual-host.patch b/patches/server/0166-Expose-client-protocol-version-and-virtual-host.patch similarity index 95% rename from patches/server/0158-Expose-client-protocol-version-and-virtual-host.patch rename to patches/server/0166-Expose-client-protocol-version-and-virtual-host.patch index 424b1bde62..e5c31b05c4 100644 --- a/patches/server/0158-Expose-client-protocol-version-and-virtual-host.patch +++ b/patches/server/0166-Expose-client-protocol-version-and-virtual-host.patch @@ -60,7 +60,7 @@ index 0000000000000000000000000000000000000000..a5a7624f1f372a26b982836cd31cff15 + +} diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index c06f1e1f08c3a854031b48ecc49e35aeb0d9b628..b132a5ca649833043b81578a2439901eaf4c4ab5 100644 +index 9b96d05094c3b83f6388d479fdca8800453ccd1d..308b720a58320aab1e2616542bbdd2e2fc5869ee 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -89,6 +89,10 @@ public class Connection extends SimpleChannelInboundHandler> { @@ -90,7 +90,7 @@ index 9016aced079108aeae09f030a672467a953ef93f..4170bda451df3db43e7d57d87d1abb81 @Override diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 198d679a0f46324b2ec483d474cff0829bbd6844..1c620dc2e798c9d4f0816753362cab8564037ca0 100644 +index a5418b1c78e1f1eb9f552450367717fee9487193..460e237a3237d5965b2ef85d32113682ee04e52d 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -218,6 +218,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0159-revert-serverside-behavior-of-keepalives.patch b/patches/server/0167-revert-serverside-behavior-of-keepalives.patch similarity index 97% rename from patches/server/0159-revert-serverside-behavior-of-keepalives.patch rename to patches/server/0167-revert-serverside-behavior-of-keepalives.patch index 27d0bf3171..8657cdbcbe 100644 --- a/patches/server/0159-revert-serverside-behavior-of-keepalives.patch +++ b/patches/server/0167-revert-serverside-behavior-of-keepalives.patch @@ -17,7 +17,7 @@ from networking or during connections flood of chunk packets on slower clients, at the cost of dead connections being kept open for longer. diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 96091153862433ffe2fdc90c00f1cc6be02e8977..90b09d4fcb267dff4ab3c910948876a4408abcd1 100644 +index c6330fa43f205c28f3a494269933482c14f75afb..322ecd7671c9b1a6c359455d47ec617b7da00bdc 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -256,7 +256,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic diff --git a/patches/server/0160-Send-attack-SoundEffects-only-to-players-who-can-see.patch b/patches/server/0168-Send-attack-SoundEffects-only-to-players-who-can-see.patch similarity index 100% rename from patches/server/0160-Send-attack-SoundEffects-only-to-players-who-can-see.patch rename to patches/server/0168-Send-attack-SoundEffects-only-to-players-who-can-see.patch diff --git a/patches/server/0161-Add-PlayerArmorChangeEvent.patch b/patches/server/0169-Add-PlayerArmorChangeEvent.patch similarity index 100% rename from patches/server/0161-Add-PlayerArmorChangeEvent.patch rename to patches/server/0169-Add-PlayerArmorChangeEvent.patch diff --git a/patches/server/0162-Prevent-logins-from-being-processed-when-the-player-.patch b/patches/server/0170-Prevent-logins-from-being-processed-when-the-player-.patch similarity index 100% rename from patches/server/0162-Prevent-logins-from-being-processed-when-the-player-.patch rename to patches/server/0170-Prevent-logins-from-being-processed-when-the-player-.patch diff --git a/patches/server/0163-Fix-MC-117075-TE-Unload-Lag-Spike.patch b/patches/server/0171-Fix-MC-117075-TE-Unload-Lag-Spike.patch similarity index 100% rename from patches/server/0163-Fix-MC-117075-TE-Unload-Lag-Spike.patch rename to patches/server/0171-Fix-MC-117075-TE-Unload-Lag-Spike.patch diff --git a/patches/server/0164-use-CB-BlockState-implementations-for-captured-block.patch b/patches/server/0172-use-CB-BlockState-implementations-for-captured-block.patch similarity index 100% rename from patches/server/0164-use-CB-BlockState-implementations-for-captured-block.patch rename to patches/server/0172-use-CB-BlockState-implementations-for-captured-block.patch diff --git a/patches/server/0165-API-to-get-a-BlockState-without-a-snapshot.patch b/patches/server/0173-API-to-get-a-BlockState-without-a-snapshot.patch similarity index 100% rename from patches/server/0165-API-to-get-a-BlockState-without-a-snapshot.patch rename to patches/server/0173-API-to-get-a-BlockState-without-a-snapshot.patch diff --git a/patches/server/0166-AsyncTabCompleteEvent.patch b/patches/server/0174-AsyncTabCompleteEvent.patch similarity index 97% rename from patches/server/0166-AsyncTabCompleteEvent.patch rename to patches/server/0174-AsyncTabCompleteEvent.patch index ab9832afe8..0172c62c70 100644 --- a/patches/server/0166-AsyncTabCompleteEvent.patch +++ b/patches/server/0174-AsyncTabCompleteEvent.patch @@ -16,10 +16,10 @@ Also adds isCommand and getLocation to the sync TabCompleteEvent Co-authored-by: Aikar diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 90b09d4fcb267dff4ab3c910948876a4408abcd1..d5861e01f7bc18a95f9287128aa829a28780e8c4 100644 +index 322ecd7671c9b1a6c359455d47ec617b7da00bdc..9d66ce602f2c71107659774d5a8a1e19071de214 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -784,27 +784,58 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -784,12 +784,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic } @@ -37,6 +37,10 @@ index 90b09d4fcb267dff4ab3c910948876a4408abcd1..d5861e01f7bc18a95f9287128aa829a2 + server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper return; } + // Paper start +@@ -800,18 +804,45 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + } + // Paper end // CraftBukkit end + // Paper start - async tab completion + TAB_COMPLETE_EXECUTOR.execute(() -> { diff --git a/patches/server/0167-PlayerPickupExperienceEvent.patch b/patches/server/0175-PlayerPickupExperienceEvent.patch similarity index 100% rename from patches/server/0167-PlayerPickupExperienceEvent.patch rename to patches/server/0175-PlayerPickupExperienceEvent.patch diff --git a/patches/server/0168-Ability-to-apply-mending-to-XP-API.patch b/patches/server/0176-Ability-to-apply-mending-to-XP-API.patch similarity index 96% rename from patches/server/0168-Ability-to-apply-mending-to-XP-API.patch rename to patches/server/0176-Ability-to-apply-mending-to-XP-API.patch index ff01f4a8ad..d301f387f5 100644 --- a/patches/server/0168-Ability-to-apply-mending-to-XP-API.patch +++ b/patches/server/0176-Ability-to-apply-mending-to-XP-API.patch @@ -10,7 +10,7 @@ of giving the player experience points. Both an API To standalone mend, and apply mending logic to .giveExp has been added. diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 4ad178d99da224927b785d586bb2057ddd73ccd8..d1271b9c31502407dfeaf8eb47b73f515bf6c0fd 100644 +index 460e237a3237d5965b2ef85d32113682ee04e52d..299f2a8c45462d8070312c98554dbcc05298c681 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1365,7 +1365,37 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0169-PlayerNaturallySpawnCreaturesEvent.patch b/patches/server/0177-PlayerNaturallySpawnCreaturesEvent.patch similarity index 88% rename from patches/server/0169-PlayerNaturallySpawnCreaturesEvent.patch rename to patches/server/0177-PlayerNaturallySpawnCreaturesEvent.patch index 31e7dfcc83..e702a822a8 100644 --- a/patches/server/0169-PlayerNaturallySpawnCreaturesEvent.patch +++ b/patches/server/0177-PlayerNaturallySpawnCreaturesEvent.patch @@ -9,10 +9,10 @@ from triggering monster spawns on a server. Also a highly more effecient way to blanket block spawns in a world diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index dd318c213742299fca1335fadf1f4465b471d7ea..cb261ab455eb2234159ba49b1c2f6c34b079973f 100644 +index e086135936e4f6c109cd09a4e4df350702b3510a..09a2680162ed9f1d82830778fea6b05a34ab382b 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1157,7 +1157,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1375,7 +1375,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange; chunkRange = (chunkRange > 8) ? 8 : chunkRange; @@ -23,7 +23,7 @@ index dd318c213742299fca1335fadf1f4465b471d7ea..cb261ab455eb2234159ba49b1c2f6c34 // Spigot end long i = chunkcoordintpair.toLong(); -@@ -1174,6 +1176,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1392,6 +1394,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } entityplayer = (ServerPlayer) iterator.next(); @@ -40,10 +40,10 @@ index dd318c213742299fca1335fadf1f4465b471d7ea..cb261ab455eb2234159ba49b1c2f6c34 return true; diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 86acdd910eebb8beac4536942119c9e97580ff2e..a81644df294c739b72fc638cd06a3976250caa50 100644 +index 2400212e65c72d3ce6604b3cf200db0ae7032f2a..f2775bc2c9137b7b81080f3113340923469bb46d 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -819,6 +819,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -784,6 +784,15 @@ public class ServerChunkCache extends ChunkSource { boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit Collections.shuffle(list); @@ -60,7 +60,7 @@ index 86acdd910eebb8beac4536942119c9e97580ff2e..a81644df294c739b72fc638cd06a3976 while (iterator1.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 8f4b8e4911d5c3bb82c9ac246c041c0eb51a3123..a9497e21c87e785631788968bc4922f6261169f9 100644 +index 5d214b7dd4f6d7feff0a1904ce6573cffd258a1c..a214916ff80885af262165d5936b8bdf2056cbed 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1,5 +1,6 @@ @@ -70,7 +70,7 @@ index 8f4b8e4911d5c3bb82c9ac246c041c0eb51a3123..a9497e21c87e785631788968bc4922f6 import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Either; -@@ -245,6 +246,7 @@ public class ServerPlayer extends Player { +@@ -246,6 +247,7 @@ public class ServerPlayer extends Player { public Integer clientViewDistance; public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent // CraftBukkit end diff --git a/patches/server/0170-Add-setPlayerProfile-API-for-Skulls.patch b/patches/server/0178-Add-setPlayerProfile-API-for-Skulls.patch similarity index 100% rename from patches/server/0170-Add-setPlayerProfile-API-for-Skulls.patch rename to patches/server/0178-Add-setPlayerProfile-API-for-Skulls.patch diff --git a/patches/server/0171-PreCreatureSpawnEvent.patch b/patches/server/0179-PreCreatureSpawnEvent.patch similarity index 100% rename from patches/server/0171-PreCreatureSpawnEvent.patch rename to patches/server/0179-PreCreatureSpawnEvent.patch diff --git a/patches/server/0172-Fill-Profile-Property-Events.patch b/patches/server/0180-Fill-Profile-Property-Events.patch similarity index 100% rename from patches/server/0172-Fill-Profile-Property-Events.patch rename to patches/server/0180-Fill-Profile-Property-Events.patch diff --git a/patches/server/0173-PlayerAdvancementCriterionGrantEvent.patch b/patches/server/0181-PlayerAdvancementCriterionGrantEvent.patch similarity index 100% rename from patches/server/0173-PlayerAdvancementCriterionGrantEvent.patch rename to patches/server/0181-PlayerAdvancementCriterionGrantEvent.patch diff --git a/patches/server/0174-Add-ArmorStand-Item-Meta.patch b/patches/server/0182-Add-ArmorStand-Item-Meta.patch similarity index 100% rename from patches/server/0174-Add-ArmorStand-Item-Meta.patch rename to patches/server/0182-Add-ArmorStand-Item-Meta.patch diff --git a/patches/server/0175-Extend-Player-Interact-cancellation.patch b/patches/server/0183-Extend-Player-Interact-cancellation.patch similarity index 100% rename from patches/server/0175-Extend-Player-Interact-cancellation.patch rename to patches/server/0183-Extend-Player-Interact-cancellation.patch diff --git a/patches/server/0176-Tameable-getOwnerUniqueId-API.patch b/patches/server/0184-Tameable-getOwnerUniqueId-API.patch similarity index 100% rename from patches/server/0176-Tameable-getOwnerUniqueId-API.patch rename to patches/server/0184-Tameable-getOwnerUniqueId-API.patch diff --git a/patches/server/0177-Toggleable-player-crits-helps-mitigate-hacked-client.patch b/patches/server/0185-Toggleable-player-crits-helps-mitigate-hacked-client.patch similarity index 100% rename from patches/server/0177-Toggleable-player-crits-helps-mitigate-hacked-client.patch rename to patches/server/0185-Toggleable-player-crits-helps-mitigate-hacked-client.patch diff --git a/patches/server/0178-Disable-Explicit-Network-Manager-Flushing.patch b/patches/server/0186-Disable-Explicit-Network-Manager-Flushing.patch similarity index 94% rename from patches/server/0178-Disable-Explicit-Network-Manager-Flushing.patch rename to patches/server/0186-Disable-Explicit-Network-Manager-Flushing.patch index 2afe051024..52b1cd9a42 100644 --- a/patches/server/0178-Disable-Explicit-Network-Manager-Flushing.patch +++ b/patches/server/0186-Disable-Explicit-Network-Manager-Flushing.patch @@ -12,7 +12,7 @@ flushing on the netty event loop, so it won't do the flush on the main thread. Renable flushing by passing -Dpaper.explicit-flush=true diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index b132a5ca649833043b81578a2439901eaf4c4ab5..30073d1e0c61ad94119fc0859a17b011087b6fcc 100644 +index 308b720a58320aab1e2616542bbdd2e2fc5869ee..2643c3d99c11bc6783386502c7e21293b6dfa345 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -92,6 +92,7 @@ public class Connection extends SimpleChannelInboundHandler> { diff --git a/patches/server/0179-Implement-extended-PaperServerListPingEvent.patch b/patches/server/0187-Implement-extended-PaperServerListPingEvent.patch similarity index 99% rename from patches/server/0179-Implement-extended-PaperServerListPingEvent.patch rename to patches/server/0187-Implement-extended-PaperServerListPingEvent.patch index 51f0b253c4..c9dccdb403 100644 --- a/patches/server/0179-Implement-extended-PaperServerListPingEvent.patch +++ b/patches/server/0187-Implement-extended-PaperServerListPingEvent.patch @@ -190,7 +190,7 @@ index 67455a5ba75c9b816213e44d6872c5ddf8e27e98..23efad80934930beadf15e65781551d4 public ClientboundStatusResponsePacket(ServerStatus metadata) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 68072a78d241bcfb54a206e7b85f038d51e26e58..bb50ca7bcbdf46d29bd749050674dc18d7e282e4 100644 +index 2d474f3bf38545d2703f1f8f80419dc774e15bf6..401b883109f0ab7b30dcdc5c0ea28fc7aa3a0822 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -2,6 +2,9 @@ package net.minecraft.server; diff --git a/patches/server/0180-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch b/patches/server/0188-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch similarity index 100% rename from patches/server/0180-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch rename to patches/server/0188-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch diff --git a/patches/server/0181-Player.setPlayerProfile-API.patch b/patches/server/0189-Player.setPlayerProfile-API.patch similarity index 100% rename from patches/server/0181-Player.setPlayerProfile-API.patch rename to patches/server/0189-Player.setPlayerProfile-API.patch diff --git a/patches/server/0182-getPlayerUniqueId-API.patch b/patches/server/0190-getPlayerUniqueId-API.patch similarity index 94% rename from patches/server/0182-getPlayerUniqueId-API.patch rename to patches/server/0190-getPlayerUniqueId-API.patch index 0b83ebb1eb..08d3bcf224 100644 --- a/patches/server/0182-getPlayerUniqueId-API.patch +++ b/patches/server/0190-getPlayerUniqueId-API.patch @@ -9,7 +9,7 @@ In Offline Mode, will return an Offline UUID This is a more performant way to obtain a UUID for a name than loading an OfflinePlayer diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index be5982fea6f354131e4562e2a109b4c56c77bcd9..e8becfe4cfb0b431d99a78b7726e96afbdefcf12 100644 +index 565ae5e0dc0db9aaf694003cb30e9af3ff6fc78d..94e0134dcf644ed8f2835ddceb2f1e09c1d8c6a4 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1708,6 +1708,25 @@ public final class CraftServer implements Server { diff --git a/patches/server/0183-Improved-Async-Task-Scheduler.patch b/patches/server/0191-Improved-Async-Task-Scheduler.patch similarity index 100% rename from patches/server/0183-Improved-Async-Task-Scheduler.patch rename to patches/server/0191-Improved-Async-Task-Scheduler.patch diff --git a/patches/server/0184-Make-legacy-ping-handler-more-reliable.patch b/patches/server/0192-Make-legacy-ping-handler-more-reliable.patch similarity index 100% rename from patches/server/0184-Make-legacy-ping-handler-more-reliable.patch rename to patches/server/0192-Make-legacy-ping-handler-more-reliable.patch diff --git a/patches/server/0185-Call-PaperServerListPingEvent-for-legacy-pings.patch b/patches/server/0193-Call-PaperServerListPingEvent-for-legacy-pings.patch similarity index 100% rename from patches/server/0185-Call-PaperServerListPingEvent-for-legacy-pings.patch rename to patches/server/0193-Call-PaperServerListPingEvent-for-legacy-pings.patch diff --git a/patches/server/0186-Flag-to-disable-the-channel-limit.patch b/patches/server/0194-Flag-to-disable-the-channel-limit.patch similarity index 95% rename from patches/server/0186-Flag-to-disable-the-channel-limit.patch rename to patches/server/0194-Flag-to-disable-the-channel-limit.patch index 60f9eed621..86fb71be62 100644 --- a/patches/server/0186-Flag-to-disable-the-channel-limit.patch +++ b/patches/server/0194-Flag-to-disable-the-channel-limit.patch @@ -9,7 +9,7 @@ e.g. servers which allow and support the usage of mod packs. provide an optional flag to disable this check, at your own risk. diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 32554bad10cccec164bc36063333244344c16473..c63831b9ec29ea1589cc87fbe4615f6dfddce473 100644 +index 31bcabd4c6ac3aa261c439a154ba7eb0f8caa0b8..7234e96d6d956d84fbcbcb321c1fb05906da6adb 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -167,6 +167,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0187-Add-openSign-method-to-HumanEntity.patch b/patches/server/0195-Add-openSign-method-to-HumanEntity.patch similarity index 100% rename from patches/server/0187-Add-openSign-method-to-HumanEntity.patch rename to patches/server/0195-Add-openSign-method-to-HumanEntity.patch diff --git a/patches/server/0188-Configurable-sprint-interruption-on-attack.patch b/patches/server/0196-Configurable-sprint-interruption-on-attack.patch similarity index 100% rename from patches/server/0188-Configurable-sprint-interruption-on-attack.patch rename to patches/server/0196-Configurable-sprint-interruption-on-attack.patch diff --git a/patches/server/0189-Fix-exploit-that-allowed-colored-signs-to-be-created.patch b/patches/server/0197-Fix-exploit-that-allowed-colored-signs-to-be-created.patch similarity index 90% rename from patches/server/0189-Fix-exploit-that-allowed-colored-signs-to-be-created.patch rename to patches/server/0197-Fix-exploit-that-allowed-colored-signs-to-be-created.patch index 250b4dfb89..90921a4e32 100644 --- a/patches/server/0189-Fix-exploit-that-allowed-colored-signs-to-be-created.patch +++ b/patches/server/0197-Fix-exploit-that-allowed-colored-signs-to-be-created.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix exploit that allowed colored signs to be created diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index d5861e01f7bc18a95f9287128aa829a28780e8c4..727350fb397e9be2917fa383dc6b8abeb15670e7 100644 +index 9d66ce602f2c71107659774d5a8a1e19071de214..9b7e1b11c499fe78869487e2ba056043e1e10fff 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3247,9 +3247,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -3254,9 +3254,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic FilteredText filteredtext = (FilteredText) signText.get(i); if (this.player.isTextFilteringEnabled()) { diff --git a/patches/server/0190-EndermanEscapeEvent.patch b/patches/server/0198-EndermanEscapeEvent.patch similarity index 100% rename from patches/server/0190-EndermanEscapeEvent.patch rename to patches/server/0198-EndermanEscapeEvent.patch diff --git a/patches/server/0191-Enderman.teleportRandomly.patch b/patches/server/0199-Enderman.teleportRandomly.patch similarity index 100% rename from patches/server/0191-Enderman.teleportRandomly.patch rename to patches/server/0199-Enderman.teleportRandomly.patch diff --git a/patches/server/0192-Block-Enderpearl-Travel-Exploit.patch b/patches/server/0200-Block-Enderpearl-Travel-Exploit.patch similarity index 93% rename from patches/server/0192-Block-Enderpearl-Travel-Exploit.patch rename to patches/server/0200-Block-Enderpearl-Travel-Exploit.patch index e1f3da6f02..7a04fe5676 100644 --- a/patches/server/0192-Block-Enderpearl-Travel-Exploit.patch +++ b/patches/server/0200-Block-Enderpearl-Travel-Exploit.patch @@ -12,10 +12,10 @@ This disables that by not saving the thrower when the chunk is unloaded. This is mainly useful for survival servers that do not allow freeform teleporting. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 652c909eaa9e76c29427b7220adf9fe4947c2e84..c0a53e0effda295b9a4a798a0c7b29bd6ed9e435 100644 +index 4a6c03f421d81b694ca8670994c9322d4425922b..3162951ff50d65d0d2fcf55d0606208dc28b9146 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2073,6 +2073,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2149,6 +2149,12 @@ public class ServerLevel extends Level implements WorldGenLevel { public void onTickingEnd(Entity entity) { ServerLevel.this.entityTickList.remove(entity); diff --git a/patches/server/0193-Expand-World.spawnParticle-API-and-add-Builder.patch b/patches/server/0201-Expand-World.spawnParticle-API-and-add-Builder.patch similarity index 92% rename from patches/server/0193-Expand-World.spawnParticle-API-and-add-Builder.patch rename to patches/server/0201-Expand-World.spawnParticle-API-and-add-Builder.patch index 18756fe570..8fc08a8246 100644 --- a/patches/server/0193-Expand-World.spawnParticle-API-and-add-Builder.patch +++ b/patches/server/0201-Expand-World.spawnParticle-API-and-add-Builder.patch @@ -10,10 +10,10 @@ Adds an option to control the force mode of the particle. This adds a new Builder API which is much friendlier to use. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index c0a53e0effda295b9a4a798a0c7b29bd6ed9e435..3d3926a14229d922fb7b7e76c9babb031bf7d9ab 100644 +index 3162951ff50d65d0d2fcf55d0606208dc28b9146..3cd979a88be53fb2f5b785fa98d7b5c0c705e1f9 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1486,12 +1486,17 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1562,12 +1562,17 @@ public class ServerLevel extends Level implements WorldGenLevel { } public int sendParticles(ServerPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) { @@ -34,10 +34,10 @@ index c0a53e0effda295b9a4a798a0c7b29bd6ed9e435..3d3926a14229d922fb7b7e76c9babb03 if (this.sendParticles(entityplayer, force, d0, d1, d2, packetplayoutworldparticles)) { // CraftBukkit diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 40dd3913ac630899206a506ea9dfc58de634f391..d7502ef49d15b13d6f38da5bfc183de47962ecba 100644 +index b2e693b6a799568c6196c1f805f0153ea69b8bd2..0654af81e20a75c3b0b8e11e824f680f3eb01626 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1820,11 +1820,17 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1819,11 +1819,17 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) { diff --git a/patches/server/0194-Prevent-Frosted-Ice-from-loading-holding-chunks.patch b/patches/server/0202-Prevent-Frosted-Ice-from-loading-holding-chunks.patch similarity index 100% rename from patches/server/0194-Prevent-Frosted-Ice-from-loading-holding-chunks.patch rename to patches/server/0202-Prevent-Frosted-Ice-from-loading-holding-chunks.patch diff --git a/patches/server/0195-EndermanAttackPlayerEvent.patch b/patches/server/0203-EndermanAttackPlayerEvent.patch similarity index 100% rename from patches/server/0195-EndermanAttackPlayerEvent.patch rename to patches/server/0203-EndermanAttackPlayerEvent.patch diff --git a/patches/server/0196-WitchConsumePotionEvent.patch b/patches/server/0204-WitchConsumePotionEvent.patch similarity index 100% rename from patches/server/0196-WitchConsumePotionEvent.patch rename to patches/server/0204-WitchConsumePotionEvent.patch diff --git a/patches/server/0197-WitchThrowPotionEvent.patch b/patches/server/0205-WitchThrowPotionEvent.patch similarity index 100% rename from patches/server/0197-WitchThrowPotionEvent.patch rename to patches/server/0205-WitchThrowPotionEvent.patch diff --git a/patches/server/0198-Allow-spawning-Item-entities-with-World.spawnEntity.patch b/patches/server/0206-Allow-spawning-Item-entities-with-World.spawnEntity.patch similarity index 100% rename from patches/server/0198-Allow-spawning-Item-entities-with-World.spawnEntity.patch rename to patches/server/0206-Allow-spawning-Item-entities-with-World.spawnEntity.patch diff --git a/patches/server/0199-WitchReadyPotionEvent.patch b/patches/server/0207-WitchReadyPotionEvent.patch similarity index 100% rename from patches/server/0199-WitchReadyPotionEvent.patch rename to patches/server/0207-WitchReadyPotionEvent.patch diff --git a/patches/server/0200-ItemStack-getMaxItemUseDuration.patch b/patches/server/0208-ItemStack-getMaxItemUseDuration.patch similarity index 100% rename from patches/server/0200-ItemStack-getMaxItemUseDuration.patch rename to patches/server/0208-ItemStack-getMaxItemUseDuration.patch diff --git a/patches/server/0201-Implement-EntityTeleportEndGatewayEvent.patch b/patches/server/0209-Implement-EntityTeleportEndGatewayEvent.patch similarity index 100% rename from patches/server/0201-Implement-EntityTeleportEndGatewayEvent.patch rename to patches/server/0209-Implement-EntityTeleportEndGatewayEvent.patch diff --git a/patches/server/0202-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch b/patches/server/0210-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch similarity index 100% rename from patches/server/0202-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch rename to patches/server/0210-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch diff --git a/patches/server/0203-Fix-CraftEntity-hashCode.patch b/patches/server/0211-Fix-CraftEntity-hashCode.patch similarity index 94% rename from patches/server/0203-Fix-CraftEntity-hashCode.patch rename to patches/server/0211-Fix-CraftEntity-hashCode.patch index 99f647d7b3..26e3d9d00b 100644 --- a/patches/server/0203-Fix-CraftEntity-hashCode.patch +++ b/patches/server/0211-Fix-CraftEntity-hashCode.patch @@ -21,7 +21,7 @@ check is essentially the same as this.getHandle() == other.getHandle() However, replaced it too to make it clearer of intent. diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 41753b72ac6fdf0314d60dbe1ffb60e79b3e4af8..e6b75dfa1a59c9f1f6afde7b4538abf8d51b7261 100644 +index 5a8e31d3e1078559f17151a8f9a9cbaec58b1942..f70cc39d7fdd9308fd328007fcadbaab1780ad5f 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -807,14 +807,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { diff --git a/patches/server/0204-Configurable-Alternative-LootPool-Luck-Formula.patch b/patches/server/0212-Configurable-Alternative-LootPool-Luck-Formula.patch similarity index 100% rename from patches/server/0204-Configurable-Alternative-LootPool-Luck-Formula.patch rename to patches/server/0212-Configurable-Alternative-LootPool-Luck-Formula.patch diff --git a/patches/server/0205-Print-Error-details-when-failing-to-save-player-data.patch b/patches/server/0213-Print-Error-details-when-failing-to-save-player-data.patch similarity index 100% rename from patches/server/0205-Print-Error-details-when-failing-to-save-player-data.patch rename to patches/server/0213-Print-Error-details-when-failing-to-save-player-data.patch diff --git a/patches/server/0206-Make-shield-blocking-delay-configurable.patch b/patches/server/0214-Make-shield-blocking-delay-configurable.patch similarity index 100% rename from patches/server/0206-Make-shield-blocking-delay-configurable.patch rename to patches/server/0214-Make-shield-blocking-delay-configurable.patch diff --git a/patches/server/0207-Improve-EntityShootBowEvent.patch b/patches/server/0215-Improve-EntityShootBowEvent.patch similarity index 100% rename from patches/server/0207-Improve-EntityShootBowEvent.patch rename to patches/server/0215-Improve-EntityShootBowEvent.patch diff --git a/patches/server/0208-PlayerReadyArrowEvent.patch b/patches/server/0216-PlayerReadyArrowEvent.patch similarity index 100% rename from patches/server/0208-PlayerReadyArrowEvent.patch rename to patches/server/0216-PlayerReadyArrowEvent.patch diff --git a/patches/server/0209-Implement-EntityKnockbackByEntityEvent.patch b/patches/server/0217-Implement-EntityKnockbackByEntityEvent.patch similarity index 100% rename from patches/server/0209-Implement-EntityKnockbackByEntityEvent.patch rename to patches/server/0217-Implement-EntityKnockbackByEntityEvent.patch diff --git a/patches/server/0210-Expand-Explosions-API.patch b/patches/server/0218-Expand-Explosions-API.patch similarity index 89% rename from patches/server/0210-Expand-Explosions-API.patch rename to patches/server/0218-Expand-Explosions-API.patch index 65c44e48dd..890d08a4f6 100644 --- a/patches/server/0210-Expand-Explosions-API.patch +++ b/patches/server/0218-Expand-Explosions-API.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Expand Explosions API Add Entity as a Source capability, and add more API choices, and on Location. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index d7502ef49d15b13d6f38da5bfc183de47962ecba..7a89e5c37699762def7501754e0376f04818c6ed 100644 +index 0654af81e20a75c3b0b8e11e824f680f3eb01626..3347e42bf45be9d640ee267bc2e0df8f241ce45c 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -714,6 +714,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -713,6 +713,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source) { return !this.world.explode(source == null ? null : ((CraftEntity) source).getHandle(), x, y, z, power, setFire, breakBlocks ? Explosion.BlockInteraction.BREAK : Explosion.BlockInteraction.NONE).wasCanceled; } diff --git a/patches/server/0211-LivingEntity-Hand-Raised-Item-Use-API.patch b/patches/server/0219-LivingEntity-Hand-Raised-Item-Use-API.patch similarity index 100% rename from patches/server/0211-LivingEntity-Hand-Raised-Item-Use-API.patch rename to patches/server/0219-LivingEntity-Hand-Raised-Item-Use-API.patch diff --git a/patches/server/0212-RangedEntity-API.patch b/patches/server/0220-RangedEntity-API.patch similarity index 100% rename from patches/server/0212-RangedEntity-API.patch rename to patches/server/0220-RangedEntity-API.patch diff --git a/patches/server/0213-Add-config-to-disable-ender-dragon-legacy-check.patch b/patches/server/0221-Add-config-to-disable-ender-dragon-legacy-check.patch similarity index 100% rename from patches/server/0213-Add-config-to-disable-ender-dragon-legacy-check.patch rename to patches/server/0221-Add-config-to-disable-ender-dragon-legacy-check.patch diff --git a/patches/server/0214-Implement-World.getEntity-UUID-API.patch b/patches/server/0222-Implement-World.getEntity-UUID-API.patch similarity index 85% rename from patches/server/0214-Implement-World.getEntity-UUID-API.patch rename to patches/server/0222-Implement-World.getEntity-UUID-API.patch index 5c3dc04177..49d3106298 100644 --- a/patches/server/0214-Implement-World.getEntity-UUID-API.patch +++ b/patches/server/0222-Implement-World.getEntity-UUID-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Implement World.getEntity(UUID) API diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 7a89e5c37699762def7501754e0376f04818c6ed..124c1b07067a889ffeb5b9994b0b3be4d3e64540 100644 +index 3347e42bf45be9d640ee267bc2e0df8f241ce45c..ff842f952d744a13eb563407edc21d03d43ddd66 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1048,6 +1048,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1047,6 +1047,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { return list; } diff --git a/patches/server/0215-InventoryCloseEvent-Reason-API.patch b/patches/server/0223-InventoryCloseEvent-Reason-API.patch similarity index 93% rename from patches/server/0215-InventoryCloseEvent-Reason-API.patch rename to patches/server/0223-InventoryCloseEvent-Reason-API.patch index d62c930502..c4c5b1b14e 100644 --- a/patches/server/0215-InventoryCloseEvent-Reason-API.patch +++ b/patches/server/0223-InventoryCloseEvent-Reason-API.patch @@ -7,10 +7,10 @@ Allows you to determine why an inventory was closed, enabling plugin developers to "confirm" things based on if it was player triggered close or not. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0b1676f71e8da09af3cc0db1c6c17059a6bcf60c..45038c25904d919e0b69deaecdc09272df05bab4 100644 +index 3cd979a88be53fb2f5b785fa98d7b5c0c705e1f9..e13fa5d2ed02b5fe8f9f9d124d15dd5374a7f472 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1159,7 +1159,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1235,7 +1235,7 @@ public class ServerLevel extends Level implements WorldGenLevel { for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) { if (tileentity instanceof net.minecraft.world.Container) { for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) { @@ -19,7 +19,7 @@ index 0b1676f71e8da09af3cc0db1c6c17059a6bcf60c..45038c25904d919e0b69deaecdc09272 } } } -@@ -2163,7 +2163,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2239,7 +2239,7 @@ public class ServerLevel extends Level implements WorldGenLevel { // Spigot Start if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) { @@ -29,10 +29,10 @@ index 0b1676f71e8da09af3cc0db1c6c17059a6bcf60c..45038c25904d919e0b69deaecdc09272 } // Spigot End diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 4eb69b62b4c3f568cad83fdc4b19cbde2c588be7..35a6dd9cfed631f66e31c71911433ec880711905 100644 +index a214916ff80885af262165d5936b8bdf2056cbed..4b9af6ef008a297438bfc583025d235d07d9b780 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -610,7 +610,7 @@ public class ServerPlayer extends Player { +@@ -626,7 +626,7 @@ public class ServerPlayer extends Player { } // Paper end if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) { @@ -41,7 +41,7 @@ index 4eb69b62b4c3f568cad83fdc4b19cbde2c588be7..35a6dd9cfed631f66e31c71911433ec8 this.containerMenu = this.inventoryMenu; } -@@ -803,7 +803,7 @@ public class ServerPlayer extends Player { +@@ -819,7 +819,7 @@ public class ServerPlayer extends Player { // SPIGOT-943 - only call if they have an inventory open if (this.containerMenu != this.inventoryMenu) { @@ -50,7 +50,7 @@ index 4eb69b62b4c3f568cad83fdc4b19cbde2c588be7..35a6dd9cfed631f66e31c71911433ec8 } net.kyori.adventure.text.Component deathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure -@@ -1441,7 +1441,7 @@ public class ServerPlayer extends Player { +@@ -1457,7 +1457,7 @@ public class ServerPlayer extends Player { } // CraftBukkit end if (this.containerMenu != this.inventoryMenu) { @@ -59,7 +59,7 @@ index 4eb69b62b4c3f568cad83fdc4b19cbde2c588be7..35a6dd9cfed631f66e31c71911433ec8 } // this.nextContainerCounter(); // CraftBukkit - moved up -@@ -1469,7 +1469,13 @@ public class ServerPlayer extends Player { +@@ -1485,7 +1485,13 @@ public class ServerPlayer extends Player { @Override public void closeContainer() { @@ -75,7 +75,7 @@ index 4eb69b62b4c3f568cad83fdc4b19cbde2c588be7..35a6dd9cfed631f66e31c71911433ec8 this.doCloseContainer(); } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 727350fb397e9be2917fa383dc6b8abeb15670e7..f7552186d8a5144c23d495bdc6a450e55d8f40d1 100644 +index 9b7e1b11c499fe78869487e2ba056043e1e10fff..68d46505791e0c29b22fa266c70c996b0f10713c 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -219,6 +219,7 @@ import org.bukkit.event.inventory.ClickType; @@ -86,7 +86,7 @@ index 727350fb397e9be2917fa383dc6b8abeb15670e7..f7552186d8a5144c23d495bdc6a450e5 import org.bukkit.event.inventory.InventoryCreativeEvent; import org.bukkit.event.inventory.InventoryType.SlotType; import org.bukkit.event.inventory.SmithItemEvent; -@@ -2773,10 +2774,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2780,10 +2781,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic @Override public void handleContainerClose(ServerboundContainerClosePacket packet) { @@ -104,10 +104,10 @@ index 727350fb397e9be2917fa383dc6b8abeb15670e7..f7552186d8a5144c23d495bdc6a450e5 this.player.doCloseContainer(); } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 8d46d3a77fa9717075dcfef44a42948c2f274182..04a41c3ab90fcdfaedb1646137fb5dde12a9331b 100644 +index bf5cfdae384e44b3cef5d7edb69a559803f583a4..0629b2df97119e242d10e41a707ba47894ce6d69 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -507,7 +507,7 @@ public abstract class PlayerList { +@@ -508,7 +508,7 @@ public abstract class PlayerList { // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it // See SPIGOT-5799, SPIGOT-6145 if (entityplayer.containerMenu != entityplayer.inventoryMenu) { diff --git a/patches/server/0216-Vex-get-setSummoner-API.patch b/patches/server/0224-Vex-get-setSummoner-API.patch similarity index 100% rename from patches/server/0216-Vex-get-setSummoner-API.patch rename to patches/server/0224-Vex-get-setSummoner-API.patch diff --git a/patches/server/0217-Refresh-player-inventory-when-cancelling-PlayerInter.patch b/patches/server/0225-Refresh-player-inventory-when-cancelling-PlayerInter.patch similarity index 90% rename from patches/server/0217-Refresh-player-inventory-when-cancelling-PlayerInter.patch rename to patches/server/0225-Refresh-player-inventory-when-cancelling-PlayerInter.patch index f381a0ed77..882f5bc09a 100644 --- a/patches/server/0217-Refresh-player-inventory-when-cancelling-PlayerInter.patch +++ b/patches/server/0225-Refresh-player-inventory-when-cancelling-PlayerInter.patch @@ -16,10 +16,10 @@ Refresh the player inventory when PlayerInteractEntityEvent is cancelled to avoid this problem. diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index f7552186d8a5144c23d495bdc6a450e55d8f40d1..abd3899c41c8c8be53cab04d946d15e621369d9a 100644 +index 68d46505791e0c29b22fa266c70c996b0f10713c..38d9abe5f34c17b66c8eaf40fac87fc16786f095 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2658,6 +2658,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2665,6 +2665,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic } if (event.isCancelled()) { diff --git a/patches/server/0218-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch b/patches/server/0226-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch similarity index 100% rename from patches/server/0218-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch rename to patches/server/0226-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch diff --git a/patches/server/0219-add-more-information-to-Entity.toString.patch b/patches/server/0227-add-more-information-to-Entity.toString.patch similarity index 95% rename from patches/server/0219-add-more-information-to-Entity.toString.patch rename to patches/server/0227-add-more-information-to-Entity.toString.patch index 2fc7c9e63f..b441179e4f 100644 --- a/patches/server/0219-add-more-information-to-Entity.toString.patch +++ b/patches/server/0227-add-more-information-to-Entity.toString.patch @@ -6,7 +6,7 @@ Subject: [PATCH] add more information to Entity.toString() UUID, ticks lived, valid, dead diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 2e7b3de046bace7c4c275654a0f1e9066790db0c..3ef34b1da06eac4b160e56966c2e441cf9fa2f89 100644 +index 81fd2e443de0b85b340b48e66bc5fb0acad5d60a..dd00721df47c84629cc5399dd558c531f6cea1cc 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -2902,7 +2902,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0220-Add-CraftMagicNumbers.isSupportedApiVersion.patch b/patches/server/0228-Add-CraftMagicNumbers.isSupportedApiVersion.patch similarity index 90% rename from patches/server/0220-Add-CraftMagicNumbers.isSupportedApiVersion.patch rename to patches/server/0228-Add-CraftMagicNumbers.isSupportedApiVersion.patch index 2d9be80ee1..c90009e730 100644 --- a/patches/server/0220-Add-CraftMagicNumbers.isSupportedApiVersion.patch +++ b/patches/server/0228-Add-CraftMagicNumbers.isSupportedApiVersion.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add CraftMagicNumbers.isSupportedApiVersion() diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index e6ffdbeb55eaeb8c2ea7c01a5206242f54756f2b..bd8f051496aae64d317ae0cff9f21662f016c62b 100644 +index df814f6bd071cef89cd4275e11aadc8311abd0f4..5893b764d3fceccef8704f1f90a5c826d6012166 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -426,6 +426,11 @@ public final class CraftMagicNumbers implements UnsafeValues { diff --git a/patches/server/0221-EnderDragon-Events.patch b/patches/server/0229-EnderDragon-Events.patch similarity index 100% rename from patches/server/0221-EnderDragon-Events.patch rename to patches/server/0229-EnderDragon-Events.patch diff --git a/patches/server/0222-PlayerElytraBoostEvent.patch b/patches/server/0230-PlayerElytraBoostEvent.patch similarity index 100% rename from patches/server/0222-PlayerElytraBoostEvent.patch rename to patches/server/0230-PlayerElytraBoostEvent.patch diff --git a/patches/server/0223-PlayerLaunchProjectileEvent.patch b/patches/server/0231-PlayerLaunchProjectileEvent.patch similarity index 100% rename from patches/server/0223-PlayerLaunchProjectileEvent.patch rename to patches/server/0231-PlayerLaunchProjectileEvent.patch diff --git a/patches/server/0224-Improve-BlockPosition-inlining.patch b/patches/server/0232-Improve-BlockPosition-inlining.patch similarity index 100% rename from patches/server/0224-Improve-BlockPosition-inlining.patch rename to patches/server/0232-Improve-BlockPosition-inlining.patch diff --git a/patches/server/0225-Option-to-prevent-armor-stands-from-doing-entity-loo.patch b/patches/server/0233-Option-to-prevent-armor-stands-from-doing-entity-loo.patch similarity index 100% rename from patches/server/0225-Option-to-prevent-armor-stands-from-doing-entity-loo.patch rename to patches/server/0233-Option-to-prevent-armor-stands-from-doing-entity-loo.patch diff --git a/patches/server/0226-Vanished-players-don-t-have-rights.patch b/patches/server/0234-Vanished-players-don-t-have-rights.patch similarity index 100% rename from patches/server/0226-Vanished-players-don-t-have-rights.patch rename to patches/server/0234-Vanished-players-don-t-have-rights.patch diff --git a/patches/server/0227-Allow-disabling-armour-stand-ticking.patch b/patches/server/0235-Allow-disabling-armour-stand-ticking.patch similarity index 100% rename from patches/server/0227-Allow-disabling-armour-stand-ticking.patch rename to patches/server/0235-Allow-disabling-armour-stand-ticking.patch diff --git a/patches/server/0228-SkeletonHorse-Additions.patch b/patches/server/0236-SkeletonHorse-Additions.patch similarity index 100% rename from patches/server/0228-SkeletonHorse-Additions.patch rename to patches/server/0236-SkeletonHorse-Additions.patch diff --git a/patches/server/0229-Don-t-call-getItemMeta-on-hasItemMeta.patch b/patches/server/0237-Don-t-call-getItemMeta-on-hasItemMeta.patch similarity index 100% rename from patches/server/0229-Don-t-call-getItemMeta-on-hasItemMeta.patch rename to patches/server/0237-Don-t-call-getItemMeta-on-hasItemMeta.patch diff --git a/patches/server/0230-Implement-Expanded-ArmorStand-API.patch b/patches/server/0238-Implement-Expanded-ArmorStand-API.patch similarity index 100% rename from patches/server/0230-Implement-Expanded-ArmorStand-API.patch rename to patches/server/0238-Implement-Expanded-ArmorStand-API.patch diff --git a/patches/server/0231-AnvilDamageEvent.patch b/patches/server/0239-AnvilDamageEvent.patch similarity index 100% rename from patches/server/0231-AnvilDamageEvent.patch rename to patches/server/0239-AnvilDamageEvent.patch diff --git a/patches/server/0232-Add-hand-to-bucket-events.patch b/patches/server/0240-Add-hand-to-bucket-events.patch similarity index 100% rename from patches/server/0232-Add-hand-to-bucket-events.patch rename to patches/server/0240-Add-hand-to-bucket-events.patch diff --git a/patches/server/0233-Add-TNTPrimeEvent.patch b/patches/server/0241-Add-TNTPrimeEvent.patch similarity index 100% rename from patches/server/0233-Add-TNTPrimeEvent.patch rename to patches/server/0241-Add-TNTPrimeEvent.patch diff --git a/patches/server/0234-Break-up-and-make-tab-spam-limits-configurable.patch b/patches/server/0242-Break-up-and-make-tab-spam-limits-configurable.patch similarity index 97% rename from patches/server/0234-Break-up-and-make-tab-spam-limits-configurable.patch rename to patches/server/0242-Break-up-and-make-tab-spam-limits-configurable.patch index d6f929806f..f414623882 100644 --- a/patches/server/0234-Break-up-and-make-tab-spam-limits-configurable.patch +++ b/patches/server/0242-Break-up-and-make-tab-spam-limits-configurable.patch @@ -22,7 +22,7 @@ to take the burden of this into their own hand without having to rely on plugins doing unsafe things. diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index abd3899c41c8c8be53cab04d946d15e621369d9a..0bac1fa4637d7132871b8f57b0431724bc9aa8c1 100644 +index 38d9abe5f34c17b66c8eaf40fac87fc16786f095..d991354d65305ab7d02666f7c3362e4136c3f6af 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -262,6 +262,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic diff --git a/patches/server/0235-MC-135506-Experience-should-save-as-Integers.patch b/patches/server/0243-MC-135506-Experience-should-save-as-Integers.patch similarity index 100% rename from patches/server/0235-MC-135506-Experience-should-save-as-Integers.patch rename to patches/server/0243-MC-135506-Experience-should-save-as-Integers.patch diff --git a/patches/server/0236-Remove-unnecessary-itemmeta-handling.patch b/patches/server/0244-Remove-unnecessary-itemmeta-handling.patch similarity index 100% rename from patches/server/0236-Remove-unnecessary-itemmeta-handling.patch rename to patches/server/0244-Remove-unnecessary-itemmeta-handling.patch diff --git a/patches/server/0237-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch b/patches/server/0245-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch similarity index 93% rename from patches/server/0237-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch rename to patches/server/0245-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch index db9ee43cf3..6bd58ca835 100644 --- a/patches/server/0237-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch +++ b/patches/server/0245-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch @@ -8,10 +8,10 @@ Add -Ddebug.entities=true to your JVM flags to gain more information 1.17: Needs to be reworked for new entity storage system diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index cb261ab455eb2234159ba49b1c2f6c34b079973f..7793d6c254c418847d3b5b65e5232bf8192b561b 100644 +index 09a2680162ed9f1d82830778fea6b05a34ab382b..8d0f7fb501aa5caa36b7dd273a8a7c7f959759cb 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1396,6 +1396,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1614,6 +1614,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } else { ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas()); @@ -19,7 +19,7 @@ index cb261ab455eb2234159ba49b1c2f6c34b079973f..7793d6c254c418847d3b5b65e5232bf8 this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); playerchunkmap_entitytracker.updatePlayers(this.level.players()); if (entity instanceof ServerPlayer) { -@@ -1438,7 +1439,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1656,7 +1657,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (playerchunkmap_entitytracker1 != null) { playerchunkmap_entitytracker1.broadcastRemoved(); } @@ -29,7 +29,7 @@ index cb261ab455eb2234159ba49b1c2f6c34b079973f..7793d6c254c418847d3b5b65e5232bf8 protected void tick() { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 5029436157fe7279a2a583f06b7d02a0413d2178..cfaa5a5df9ae2fb0147d66b41de91e6b771b769c 100644 +index e13fa5d2ed02b5fe8f9f9d124d15dd5374a7f472..377ebed70c5008d69701bd919f22ad4506dd129c 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -216,6 +216,9 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -42,7 +42,7 @@ index 5029436157fe7279a2a583f06b7d02a0413d2178..cfaa5a5df9ae2fb0147d66b41de91e6b @Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI return this.chunkSource.getChunk(x, z, false); -@@ -1121,7 +1124,28 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1197,7 +1200,28 @@ public class ServerLevel extends Level implements WorldGenLevel { // CraftBukkit start private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot @@ -72,7 +72,7 @@ index 5029436157fe7279a2a583f06b7d02a0413d2178..cfaa5a5df9ae2fb0147d66b41de91e6b return false; } else { diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 3ef34b1da06eac4b160e56966c2e441cf9fa2f89..ed79a9d5a822370a9a285e58773669a00b159054 100644 +index dd00721df47c84629cc5399dd558c531f6cea1cc..29c71c951ce7114dfb24f0c99c3bf8c2a6f6144f 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -235,6 +235,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0238-Add-Early-Warning-Feature-to-WatchDog.patch b/patches/server/0246-Add-Early-Warning-Feature-to-WatchDog.patch similarity index 95% rename from patches/server/0238-Add-Early-Warning-Feature-to-WatchDog.patch rename to patches/server/0246-Add-Early-Warning-Feature-to-WatchDog.patch index beb82f3bbd..7cac64f958 100644 --- a/patches/server/0238-Add-Early-Warning-Feature-to-WatchDog.patch +++ b/patches/server/0246-Add-Early-Warning-Feature-to-WatchDog.patch @@ -9,7 +9,7 @@ thread dumps at an interval until the point of crash. This will help diagnose what was going on in that time before the crash. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index e7cd33be3c74ca79f9f0fecea010081b24a14417..ac36f50fd721b0087248bfb733fe4ea78a115778 100644 +index 401b883109f0ab7b30dcdc5c0ea28fc7aa3a0822..802b7767dd0878cf6d2e52bea74d5664f7d0664f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1061,6 +1061,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 56b1c585d1c330bf9b904ebf8ef0b8be47102aa3..e4f991578d4ee581e65f2edb7d32640ff36a01bd 100644 +index 6d95d572092ad50ffa92c2e1731fd59c6dfd7a44..f48866aff156eb1fb5e673b93becada744a04bc5 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1875,14 +1875,58 @@ public class ServerPlayer extends Player { +@@ -1891,14 +1891,58 @@ public class ServerPlayer extends Player { } public void setCamera(@Nullable Entity entity) { diff --git a/patches/server/0272-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch b/patches/server/0279-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch similarity index 100% rename from patches/server/0272-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch rename to patches/server/0279-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch diff --git a/patches/server/0273-Add-more-Witch-API.patch b/patches/server/0280-Add-more-Witch-API.patch similarity index 100% rename from patches/server/0273-Add-more-Witch-API.patch rename to patches/server/0280-Add-more-Witch-API.patch diff --git a/patches/server/0274-Check-Drowned-for-Villager-Aggression-Config.patch b/patches/server/0281-Check-Drowned-for-Villager-Aggression-Config.patch similarity index 100% rename from patches/server/0274-Check-Drowned-for-Villager-Aggression-Config.patch rename to patches/server/0281-Check-Drowned-for-Villager-Aggression-Config.patch diff --git a/patches/server/0275-Add-option-to-prevent-players-from-moving-into-unloa.patch b/patches/server/0282-Add-option-to-prevent-players-from-moving-into-unloa.patch similarity index 100% rename from patches/server/0275-Add-option-to-prevent-players-from-moving-into-unloa.patch rename to patches/server/0282-Add-option-to-prevent-players-from-moving-into-unloa.patch diff --git a/patches/server/0276-Reset-players-airTicks-on-respawn.patch b/patches/server/0283-Reset-players-airTicks-on-respawn.patch similarity index 83% rename from patches/server/0276-Reset-players-airTicks-on-respawn.patch rename to patches/server/0283-Reset-players-airTicks-on-respawn.patch index ca5fce40d8..699c6e51a7 100644 --- a/patches/server/0276-Reset-players-airTicks-on-respawn.patch +++ b/patches/server/0283-Reset-players-airTicks-on-respawn.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Reset players airTicks on respawn diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index be79f80270a7400451dcaac55fba8d3ab7bdda52..5f10a2d21553a8dc8c03ea5951190860ee5a4615 100644 +index f48866aff156eb1fb5e673b93becada744a04bc5..4c35529c7ed67c2432ac67e7d8ffe295892757ff 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -2288,6 +2288,7 @@ public class ServerPlayer extends Player { +@@ -2304,6 +2304,7 @@ public class ServerPlayer extends Player { this.setHealth(this.getMaxHealth()); this.stopUsingItem(); // CraftBukkit - SPIGOT-6682: Clear active item on reset diff --git a/patches/server/0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch b/patches/server/0284-Don-t-sleep-after-profile-lookups-if-not-needed.patch similarity index 100% rename from patches/server/0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch rename to patches/server/0284-Don-t-sleep-after-profile-lookups-if-not-needed.patch diff --git a/patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch b/patches/server/0285-Improve-Server-Thread-Pool-and-Thread-Priorities.patch similarity index 98% rename from patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch rename to patches/server/0285-Improve-Server-Thread-Pool-and-Thread-Priorities.patch index 02b480cd0c..6d5902676e 100644 --- a/patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch +++ b/patches/server/0285-Improve-Server-Thread-Pool-and-Thread-Priorities.patch @@ -58,7 +58,7 @@ index 336a26733b5bf73455f8ec10347c1e08b8e866f7..4fce18c52c8144460ebf0c1e336dce71 return executorService; } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 560e213f39d82613bd1bfcfb4eb3bd7aeed1c0c6..3d1c7bfeafbad2c5b7275f75d263a3817bd3a8aa 100644 +index 802b7767dd0878cf6d2e52bea74d5664f7d0664f..df9a67733c757ab128c11d73d001dcb8624d0283 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -306,6 +306,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { @@ -35,7 +35,7 @@ index d20954b8d8683d6380ce9f4d87bd2e3a78f7488d..7205f17da0383b22b6267843c92b31d8 }); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index f02b0afc1ef85622bc801f526e1ed476f9722c2e..5f613eac047703b6f1521fcd2d802e381d5f42d5 100644 +index cb2b47df90386ffb1305062f3f34a63549151e8b..482efc1c544cdd846f7330f4be43cc3e6eb397fc 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -74,6 +74,8 @@ import net.minecraft.world.InteractionHand; @@ -105,7 +105,7 @@ index 0be0c7a323277093a6f8e476048eb9ee8712cbc9..c7e97263eee005fd673882e11c436542 // Spigot Start if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 41920b979ab259fc27a57dde64abdba8c3be3185..6029cb7d8801c471e596ba027b7e408a27c44db9 100644 +index f70cc39d7fdd9308fd328007fcadbaab1780ad5f..cd958bc3c00f53ebaf9b3ae39564d3abb6c819a1 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -1249,5 +1249,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { diff --git a/patches/server/0306-Update-entity-Metadata-for-all-tracked-players.patch b/patches/server/0313-Update-entity-Metadata-for-all-tracked-players.patch similarity index 100% rename from patches/server/0306-Update-entity-Metadata-for-all-tracked-players.patch rename to patches/server/0313-Update-entity-Metadata-for-all-tracked-players.patch diff --git a/patches/server/0307-Fire-event-on-GS4-query.patch b/patches/server/0314-Fire-event-on-GS4-query.patch similarity index 100% rename from patches/server/0307-Fire-event-on-GS4-query.patch rename to patches/server/0314-Fire-event-on-GS4-query.patch diff --git a/patches/server/0308-Implement-PlayerPostRespawnEvent.patch b/patches/server/0315-Implement-PlayerPostRespawnEvent.patch similarity index 86% rename from patches/server/0308-Implement-PlayerPostRespawnEvent.patch rename to patches/server/0315-Implement-PlayerPostRespawnEvent.patch index d5672fc9ce..53f80b7443 100644 --- a/patches/server/0308-Implement-PlayerPostRespawnEvent.patch +++ b/patches/server/0315-Implement-PlayerPostRespawnEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Implement PlayerPostRespawnEvent diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 7205f17da0383b22b6267843c92b31d8c0556caa..ee4d2f625629cf74f923592f11ecdb312de0c3ff 100644 +index 895d087fbdde840bd6b96b6c8d231fc9beeb2a0b..3f95cfe7d6e85a19c4d6c4ce2b662a4259c45477 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -727,9 +727,14 @@ public abstract class PlayerList { +@@ -728,9 +728,14 @@ public abstract class PlayerList { boolean flag2 = false; @@ -24,7 +24,7 @@ index 7205f17da0383b22b6267843c92b31d8c0556caa..ee4d2f625629cf74f923592f11ecdb31 ServerLevel worldserver1 = this.server.getLevel(entityplayer.getRespawnDimension()); if (worldserver1 != null) { Optional optional; -@@ -781,6 +786,7 @@ public abstract class PlayerList { +@@ -782,6 +787,7 @@ public abstract class PlayerList { location = respawnEvent.getRespawnLocation(); if (!flag) entityplayer.reset(); // SPIGOT-4785 @@ -32,7 +32,7 @@ index 7205f17da0383b22b6267843c92b31d8c0556caa..ee4d2f625629cf74f923592f11ecdb31 } else { location.setWorld(worldserver.getWorld()); } -@@ -838,6 +844,13 @@ public abstract class PlayerList { +@@ -839,6 +845,13 @@ public abstract class PlayerList { if (entityplayer.connection.isDisconnected()) { this.save(entityplayer); } diff --git a/patches/server/0309-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch b/patches/server/0316-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch similarity index 100% rename from patches/server/0309-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch rename to patches/server/0316-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch diff --git a/patches/server/0310-Server-Tick-Events.patch b/patches/server/0317-Server-Tick-Events.patch similarity index 93% rename from patches/server/0310-Server-Tick-Events.patch rename to patches/server/0317-Server-Tick-Events.patch index a9e742012a..60fc617e7c 100644 --- a/patches/server/0310-Server-Tick-Events.patch +++ b/patches/server/0317-Server-Tick-Events.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Server Tick Events Fires event at start and end of a server tick diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 6f6125c3896fb388e0840d3e224b826bfa10eec0..8c48544daae0f18a39511df12f7066fc0e383d2c 100644 +index a53e1bc43903c10083b713b2c5ea5459ddfd4e27..1d554a45097cdf0640788bb796b983f18af31a9f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1308,6 +1308,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> readChunk(ChunkPos chunkPos) { @@ -28,7 +28,7 @@ index 47cb3be2d778a55bfbe733a9cc2965c8bf28a47a..33483dc272dbdee74767934f4b379a67 } // CraftBukkit start -@@ -1261,6 +1265,63 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1365,6 +1369,63 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // CraftBukkit end } @@ -188,7 +188,7 @@ index 330fb8e6565a5c0490af0c5ca0e7355d81a82e58..861a25a15f1aab20e3245b6d5cdad5d2 this.padToFullSector(); } finally { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index e734d82c2863caca8abc6bb8bb82882e971c36a8..a96a6af2bcec3134b7caa32299bd07af50e83b89 100644 +index ae1cb438cec25f8fef5dea0b2fddec6e72d5f26e..2a6a4a62feb1c02bef850b0cda578f6f9d46a5e3 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -245,6 +245,7 @@ public class RegionFileStorage implements AutoCloseable { @@ -200,10 +200,10 @@ index e734d82c2863caca8abc6bb8bb82882e971c36a8..a96a6af2bcec3134b7caa32299bd07af } catch (Throwable throwable) { if (dataoutputstream != null) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 2518674a967a5fbf2229a0fdd60447a62cfbf856..cd70aa0fa7a575c3c1f6434db74c1cc8342fddb4 100644 +index acfc8796a871706827f95c43f76b535e386d8daa..868d9d13b03751b24c4b6695f97ad343ff8d0b8e 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -300,9 +300,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -299,9 +299,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean isChunkGenerated(int x, int z) { @@ -229,7 +229,7 @@ index 2518674a967a5fbf2229a0fdd60447a62cfbf856..cd70aa0fa7a575c3c1f6434db74c1cc8 throw new RuntimeException(ex); } } -@@ -413,20 +427,48 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -412,20 +426,48 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean loadChunk(int x, int z, boolean generate) { org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot diff --git a/patches/server/0325-Show-blockstate-location-if-we-failed-to-read-it.patch b/patches/server/0330-Show-blockstate-location-if-we-failed-to-read-it.patch similarity index 100% rename from patches/server/0325-Show-blockstate-location-if-we-failed-to-read-it.patch rename to patches/server/0330-Show-blockstate-location-if-we-failed-to-read-it.patch diff --git a/patches/server/0326-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch b/patches/server/0331-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch similarity index 100% rename from patches/server/0326-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch rename to patches/server/0331-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch diff --git a/patches/server/0327-Configurable-projectile-relative-velocity.patch b/patches/server/0332-Configurable-projectile-relative-velocity.patch similarity index 100% rename from patches/server/0327-Configurable-projectile-relative-velocity.patch rename to patches/server/0332-Configurable-projectile-relative-velocity.patch diff --git a/patches/server/0328-offset-item-frame-ticking.patch b/patches/server/0333-offset-item-frame-ticking.patch similarity index 100% rename from patches/server/0328-offset-item-frame-ticking.patch rename to patches/server/0333-offset-item-frame-ticking.patch diff --git a/patches/server/0329-Fix-MC-158900.patch b/patches/server/0334-Fix-MC-158900.patch similarity index 90% rename from patches/server/0329-Fix-MC-158900.patch rename to patches/server/0334-Fix-MC-158900.patch index 2254e977c6..a2856aa25e 100644 --- a/patches/server/0329-Fix-MC-158900.patch +++ b/patches/server/0334-Fix-MC-158900.patch @@ -7,10 +7,10 @@ The problem was we were checking isExpired() on the entry, but if it was expired at that point, then it would be null. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index ee4d2f625629cf74f923592f11ecdb312de0c3ff..7ca5032574ddc4fb63dbf9ef266c71042055fb2a 100644 +index 3f95cfe7d6e85a19c4d6c4ce2b662a4259c45477..d362c9c83a73b5f49b54563b423c76c8ed78dfc6 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -611,8 +611,10 @@ public abstract class PlayerList { +@@ -612,8 +612,10 @@ public abstract class PlayerList { Player player = entity.getBukkitEntity(); PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.connection.getRawAddress()).getAddress()); diff --git a/patches/server/0330-Prevent-consuming-the-wrong-itemstack.patch b/patches/server/0335-Prevent-consuming-the-wrong-itemstack.patch similarity index 100% rename from patches/server/0330-Prevent-consuming-the-wrong-itemstack.patch rename to patches/server/0335-Prevent-consuming-the-wrong-itemstack.patch diff --git a/patches/server/0331-Dont-send-unnecessary-sign-update.patch b/patches/server/0336-Dont-send-unnecessary-sign-update.patch similarity index 100% rename from patches/server/0331-Dont-send-unnecessary-sign-update.patch rename to patches/server/0336-Dont-send-unnecessary-sign-update.patch diff --git a/patches/server/0332-Add-option-to-disable-pillager-patrols.patch b/patches/server/0337-Add-option-to-disable-pillager-patrols.patch similarity index 100% rename from patches/server/0332-Add-option-to-disable-pillager-patrols.patch rename to patches/server/0337-Add-option-to-disable-pillager-patrols.patch diff --git a/patches/server/0333-Fix-AssertionError-when-player-hand-set-to-empty-typ.patch b/patches/server/0338-Fix-AssertionError-when-player-hand-set-to-empty-typ.patch similarity index 100% rename from patches/server/0333-Fix-AssertionError-when-player-hand-set-to-empty-typ.patch rename to patches/server/0338-Fix-AssertionError-when-player-hand-set-to-empty-typ.patch diff --git a/patches/server/0334-Flat-bedrock-generator-settings.patch b/patches/server/0339-Flat-bedrock-generator-settings.patch similarity index 100% rename from patches/server/0334-Flat-bedrock-generator-settings.patch rename to patches/server/0339-Flat-bedrock-generator-settings.patch diff --git a/patches/server/0335-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch b/patches/server/0340-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch similarity index 100% rename from patches/server/0335-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch rename to patches/server/0340-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch diff --git a/patches/server/0336-MC-145656-Fix-Follow-Range-Initial-Target.patch b/patches/server/0341-MC-145656-Fix-Follow-Range-Initial-Target.patch similarity index 100% rename from patches/server/0336-MC-145656-Fix-Follow-Range-Initial-Target.patch rename to patches/server/0341-MC-145656-Fix-Follow-Range-Initial-Target.patch diff --git a/patches/server/0337-Duplicate-UUID-Resolve-Option.patch b/patches/server/0342-Duplicate-UUID-Resolve-Option.patch similarity index 83% rename from patches/server/0337-Duplicate-UUID-Resolve-Option.patch rename to patches/server/0342-Duplicate-UUID-Resolve-Option.patch index 56ab60e5db..9c8f0336e7 100644 --- a/patches/server/0337-Duplicate-UUID-Resolve-Option.patch +++ b/patches/server/0342-Duplicate-UUID-Resolve-Option.patch @@ -32,11 +32,26 @@ But for those who are ok with leaving this inconsistent behavior, you may use WA It is recommended you regenerate the entities, as these were legit entities, and deserve your love. +diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java +index 1b1bfd5f92f85f46ad9661a0a64a2a1b4c33a80d..2a099fe0d514f181bf2b452d5333bc29b0d29e43 100644 +--- a/src/main/java/net/minecraft/server/ChunkSystem.java ++++ b/src/main/java/net/minecraft/server/ChunkSystem.java +@@ -260,7 +260,9 @@ public final class ChunkSystem { + } + + public static void onEntityPreAdd(final ServerLevel level, final Entity entity) { +- ++ if (net.minecraft.server.level.ChunkMap.checkDupeUUID(level, entity)) { ++ return; ++ } + } + + public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 33483dc272dbdee74767934f4b379a675162b7d1..eae2472f6dfd166cb457953ab396f85ca8c3f0f9 100644 +index 245f60eb904e26d6e7f7ca02bfa778d4f6db5d76..4b24e4d947e96ea0720f8f6bc33470e07c00310d 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -878,6 +878,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -982,6 +982,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider entity.discard(); needsRemoval = true; } @@ -44,27 +59,32 @@ index 33483dc272dbdee74767934f4b379a675162b7d1..eae2472f6dfd166cb457953ab396f85c return !needsRemoval; })); // CraftBukkit end -@@ -928,6 +929,43 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1032,6 +1033,49 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }); } + // Paper start -+ private static void checkDupeUUID(ServerLevel level, Entity entity) { ++ // rets true if to prevent the entity from being added ++ public static boolean checkDupeUUID(ServerLevel level, Entity entity) { + io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode mode = level.paperConfig().entities.spawning.duplicateUuid.mode; + if (mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.WARN + && mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.DELETE + && mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.SAFE_REGEN) { -+ return; ++ return false; + } + Entity other = level.getEntity(entity.getUUID()); + ++ if (other == null || other == entity) { ++ return false; ++ } ++ + if (mode == io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.SAFE_REGEN && other != null && !other.isRemoved() + && Objects.equals(other.getEncodeId(), entity.getEncodeId()) + && entity.getBukkitEntity().getLocation().distance(other.getBukkitEntity().getLocation()) < level.paperConfig().entities.spawning.duplicateUuid.safeRegenDeleteRange + ) { + if (ServerLevel.DEBUG_ENTITIES) LOGGER.warn("[DUPE-UUID] Duplicate UUID found used by " + other + ", deleted entity " + entity + " because it was near the duplicate and likely an actual duplicate. See https://github.com/PaperMC/Paper/issues/1223 for discussion on what this is about."); + entity.discard(); -+ return; ++ return true; + } + if (other != null && !other.isRemoved()) { + switch (mode) { @@ -76,20 +96,21 @@ index 33483dc272dbdee74767934f4b379a675162b7d1..eae2472f6dfd166cb457953ab396f85c + case DELETE: { + if (ServerLevel.DEBUG_ENTITIES) LOGGER.warn("[DUPE-UUID] Duplicate UUID found used by " + other + ", deleted entity " + entity + ". See https://github.com/PaperMC/Paper/issues/1223 for discussion on what this is about."); + entity.discard(); -+ break; ++ return true; + } + default: + if (ServerLevel.DEBUG_ENTITIES) LOGGER.warn("[DUPE-UUID] Duplicate UUID found used by " + other + ", doing nothing to " + entity + ". See https://github.com/PaperMC/Paper/issues/1223 for discussion on what this is about."); + break; + } + } ++ return false; + } + // Paper end public CompletableFuture> prepareTickingChunk(ChunkHolder holder) { ChunkPos chunkcoordintpair = holder.getPos(); CompletableFuture, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(chunkcoordintpair, 1, (i) -> { 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 dfd1afc57664dd18c11f8a2547616074ccc55690..6e3d02fb68741fc3cf7d74ec659a37e5a1ecac5c 100644 +index ab7eadf2fc4c4598fa89068332eaaf9a8e0a100f..16519a6414f6f6418de40b714555a52631980617 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -78,7 +78,22 @@ public class PersistentEntitySectionManager implements A diff --git a/patches/server/0338-Optimize-Hoppers.patch b/patches/server/0343-Optimize-Hoppers.patch similarity index 99% rename from patches/server/0338-Optimize-Hoppers.patch rename to patches/server/0343-Optimize-Hoppers.patch index d598c74d04..7e66fc243d 100644 --- a/patches/server/0338-Optimize-Hoppers.patch +++ b/patches/server/0343-Optimize-Hoppers.patch @@ -13,7 +13,7 @@ Subject: [PATCH] Optimize Hoppers * Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins) diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 5cab48d7db58446310226acfae0dc3fcc1dba920..a02b674a925f2e070ed1bd203de262b513aae0a5 100644 +index 7342c8ac1d4bb13c0d8ce6f26b1b43d76a327655..3a085c141a5a6e2df9a85d0e3969363d69824294 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1411,6 +1411,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> worldgenMailbox; public final ProcessorHandle> mainThreadMailbox; @@ -170,7 +170,7 @@ index eae2472f6dfd166cb457953ab396f85ca8c3f0f9..8ab5fd86e626958646935e460b603c87 public final ChunkProgressListener progressListener; private final ChunkStatusUpdateListener chunkStatusListener; public final ChunkMap.ChunkDistanceManager distanceManager; -@@ -261,11 +267,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -284,11 +290,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.progressListener = worldGenerationProgressListener; this.chunkStatusListener = chunkStatusChangeListener; diff --git a/patches/server/0352-Anti-Xray.patch b/patches/server/0357-Anti-Xray.patch similarity index 99% rename from patches/server/0352-Anti-Xray.patch rename to patches/server/0357-Anti-Xray.patch index 16d9b88b97..8e6fb2e557 100644 --- a/patches/server/0352-Anti-Xray.patch +++ b/patches/server/0357-Anti-Xray.patch @@ -1044,10 +1044,10 @@ index 7825d6f0fdcfda6212cff8033ec55fb7db236154..000853110c7a89f2d0403a7a2737025a public ClientboundLevelChunkWithLightPacket(FriendlyByteBuf buf) { diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 8ab5fd86e626958646935e460b603c875b8a841b..993a74bb16116622dc968f1f240fed1c377de5fa 100644 +index d60173b03baee4a66da1109795bf6a19737b8bd0..55a21a4024debc328d4829477d80c2998e291c22 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -994,7 +994,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1104,7 +1104,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider completablefuture1.thenAcceptAsync((either) -> { either.ifLeft((chunk) -> { this.tickingGenerated.getAndIncrement(); @@ -1056,7 +1056,7 @@ index 8ab5fd86e626958646935e460b603c875b8a841b..993a74bb16116622dc968f1f240fed1c this.getPlayers(chunkcoordintpair, false).forEach((entityplayer) -> { this.playerLoadedChunk(entityplayer, mutableobject, chunk); -@@ -1173,7 +1173,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1283,7 +1283,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider while (objectiterator.hasNext()) { ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); ChunkPos chunkcoordintpair = playerchunk.getPos(); @@ -1065,7 +1065,7 @@ index 8ab5fd86e626958646935e460b603c875b8a841b..993a74bb16116622dc968f1f240fed1c this.getPlayers(chunkcoordintpair, false).forEach((entityplayer) -> { SectionPos sectionposition = entityplayer.getLastSectionPos(); -@@ -1187,7 +1187,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1297,7 +1297,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -1074,7 +1074,7 @@ index 8ab5fd86e626958646935e460b603c875b8a841b..993a74bb16116622dc968f1f240fed1c if (player.level == this.level) { if (newWithinViewDistance && !oldWithinViewDistance) { ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); -@@ -1724,12 +1724,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1834,12 +1834,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -1097,10 +1097,10 @@ index 8ab5fd86e626958646935e460b603c875b8a841b..993a74bb16116622dc968f1f240fed1c List list = Lists.newArrayList(); List list1 = Lists.newArrayList(); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0013fdf7dd4074a9684eb4b93ea2735185c7ac1c..fb7954d4d4dbd35bf771b362f241294d79cf9933 100644 +index 21fdca3b4bdc49d32deaf3f11d5fecc1ed0d4626..5622917a2884e87d43abfaf58e722957931b3178 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -403,7 +403,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -405,7 +405,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { // Holder holder = worlddimension.typeHolder(); // CraftBukkit - decompile error // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error @@ -1196,7 +1196,7 @@ index 6cec5cda20531aadf8e2148908a70f8b573d7d82..dc164608bfb2fb18a1adf83fa10bac40 } 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 e9fae214f60fe682087d41cfaa55a1b25e5f4331..ee7296eb561b59a4c0fce200f1a59f66a6526cc2 100644 +index e63086aba2512051fe1321f6e7e72b40276f5dde..004c8abeafa53cdc3efa0f45742132e3ad492d70 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -93,7 +93,7 @@ public class LevelChunk extends ChunkAccess { @@ -1551,7 +1551,7 @@ index cf48c93d89da53e0ec771e5c2c8582e30b35e3f5..518dfbb7dbd4221937636cf46d27109d } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index c125f4ba687d7622290da3f0e0fef5a8a859b4d2..3a183c9c85439d9595cc5667743cd7f41cc8c727 100644 +index e8c11b59dc50fd9c5bbf073b66d0cd9c504d7c25..8cc2a35486e8c6433e722ddc5e776c3332e7c7fe 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2235,7 +2235,7 @@ public final class CraftServer implements Server { @@ -1564,10 +1564,10 @@ index c125f4ba687d7622290da3f0e0fef5a8a859b4d2..3a183c9c85439d9595cc5667743cd7f4 @Override diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index cd70aa0fa7a575c3c1f6434db74c1cc8342fddb4..21927118d1762302dc560b385fd3a4322840031f 100644 +index 868d9d13b03751b24c4b6695f97ad343ff8d0b8e..a8ab324bfbaaf946af5998402588244465dd7286 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -407,11 +407,16 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -406,11 +406,16 @@ public class CraftWorld extends CraftRegionAccessor implements World { List playersInRange = playerChunk.playerProvider.getPlayers(playerChunk.getPos(), false); if (playersInRange.isEmpty()) return; diff --git a/patches/server/0353-Implement-alternative-item-despawn-rate.patch b/patches/server/0358-Implement-alternative-item-despawn-rate.patch similarity index 100% rename from patches/server/0353-Implement-alternative-item-despawn-rate.patch rename to patches/server/0358-Implement-alternative-item-despawn-rate.patch diff --git a/patches/server/0354-Tracking-Range-Improvements.patch b/patches/server/0359-Tracking-Range-Improvements.patch similarity index 95% rename from patches/server/0354-Tracking-Range-Improvements.patch rename to patches/server/0359-Tracking-Range-Improvements.patch index 035cfe82f8..53db6644cf 100644 --- a/patches/server/0354-Tracking-Range-Improvements.patch +++ b/patches/server/0359-Tracking-Range-Improvements.patch @@ -8,10 +8,10 @@ Sets tracking range of watermobs to animals instead of misc and simplifies code Also ignores Enderdragon, defaulting it to Mojang's setting diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 993a74bb16116622dc968f1f240fed1c377de5fa..1a06d0f8eedc4ef1e9a860c873aeff746669bfce 100644 +index 55a21a4024debc328d4829477d80c2998e291c22..0b68e6c7ef63460d596050ed55039a5ba3cefb24 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1912,6 +1912,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -2022,6 +2022,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider while (iterator.hasNext()) { Entity entity = (Entity) iterator.next(); int j = entity.getType().clientTrackingRange() * 16; diff --git a/patches/server/0355-Fix-items-vanishing-through-end-portal.patch b/patches/server/0360-Fix-items-vanishing-through-end-portal.patch similarity index 93% rename from patches/server/0355-Fix-items-vanishing-through-end-portal.patch rename to patches/server/0360-Fix-items-vanishing-through-end-portal.patch index a972dd7ef4..0ed6a4eaae 100644 --- a/patches/server/0355-Fix-items-vanishing-through-end-portal.patch +++ b/patches/server/0360-Fix-items-vanishing-through-end-portal.patch @@ -13,7 +13,7 @@ Quickly loading the exact world spawn chunk before searching the heightmap resolves the issue without having to load all spawn chunks. diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index a9f1b5fe81bef3e948d128598407d23c723fc075..8576fbaedf3076e8b492c499d4176b1116e7ef56 100644 +index 022682dc729a2e595df09befc18d7d73143b7e74..240650cee26fc907f632e0c8ef3559a36460a3ba 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -3109,6 +3109,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0356-implement-optional-per-player-mob-spawns.patch b/patches/server/0361-implement-optional-per-player-mob-spawns.patch similarity index 96% rename from patches/server/0356-implement-optional-per-player-mob-spawns.patch rename to patches/server/0361-implement-optional-per-player-mob-spawns.patch index 64254218d1..804ad3cc57 100644 --- a/patches/server/0356-implement-optional-per-player-mob-spawns.patch +++ b/patches/server/0361-implement-optional-per-player-mob-spawns.patch @@ -252,10 +252,10 @@ index 0000000000000000000000000000000000000000..11de56afaf059b00fa5bec293516bcdc + } +} diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 1a06d0f8eedc4ef1e9a860c873aeff746669bfce..f20b93c6372e36016b21591d3cd63c5d7a47721e 100644 +index 0b68e6c7ef63460d596050ed55039a5ba3cefb24..9e940920f6ff6a43d7162d965936c171c55ed570 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -156,6 +156,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -159,6 +159,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final Long2LongMap chunkSaveCooldowns; private final Queue unloadQueue; int viewDistance; @@ -263,7 +263,7 @@ index 1a06d0f8eedc4ef1e9a860c873aeff746669bfce..f20b93c6372e36016b21591d3cd63c5d // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() public final CallbackExecutor callbackExecutor = new CallbackExecutor(); -@@ -185,16 +186,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -199,16 +200,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int chunkX = MCUtil.getChunkCoordinate(player.getX()); int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated @@ -295,7 +295,7 @@ index 1a06d0f8eedc4ef1e9a860c873aeff746669bfce..f20b93c6372e36016b21591d3cd63c5d } // Paper end // Paper start -@@ -282,6 +298,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -305,6 +321,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); this.regionManagers.add(this.dataRegionManager); // Paper end @@ -303,10 +303,10 @@ index 1a06d0f8eedc4ef1e9a860c873aeff746669bfce..f20b93c6372e36016b21591d3cd63c5d } protected ChunkGenerator generator() { -@@ -303,6 +320,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - }); +@@ -356,6 +373,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } } - + // Paper end + // Paper start + public void updatePlayerMobTypeMap(Entity entity) { + if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { @@ -331,15 +331,14 @@ index 1a06d0f8eedc4ef1e9a860c873aeff746669bfce..f20b93c6372e36016b21591d3cd63c5d + return entityPlayer.mobCounts[mobCategory.ordinal()]; + } + // Paper end -+ + private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8); - double d1 = (double) SectionPos.sectionToBlockCoord(pos.z, 8); diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 1e066a35b53b1f71a0e6376a22d51fc4c0a412dc..6228f2f67541da62b0ae093de987662db9643740 100644 +index b9b56068cdacd984f873cfb2a06a312e9912893d..9309ea89a440606be3e56ef634f5048a72b0009e 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -326,6 +326,12 @@ public abstract class DistanceManager { +@@ -466,6 +466,12 @@ public abstract class DistanceManager { } @@ -353,10 +352,10 @@ index 1e066a35b53b1f71a0e6376a22d51fc4c0a412dc..6228f2f67541da62b0ae093de987662d this.naturalSpawnChunkCounter.runAllUpdates(); return this.naturalSpawnChunkCounter.chunks.size(); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index d66ec02b09bb7ae46aae8e55f00626139f074ae3..de5b80fce9757517e51f2ef55340e884f2d7e3d4 100644 +index f2775bc2c9137b7b81080f3113340923469bb46d..cd3de4cd1a38c5092f6a88de4fa33d6dda7f3445 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -908,7 +908,18 @@ public class ServerChunkCache extends ChunkSource { +@@ -762,7 +762,18 @@ public class ServerChunkCache extends ChunkSource { gameprofilerfiller.push("naturalSpawnCount"); this.level.timings.countNaturalMobs.startTiming(); // Paper - timings int l = this.distanceManager.getNaturalSpawnChunkCount(); @@ -377,10 +376,10 @@ index d66ec02b09bb7ae46aae8e55f00626139f074ae3..de5b80fce9757517e51f2ef55340e884 this.lastSpawnState = spawnercreature_d; diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 5dea577aeb4fa627e4c207b8a84933c1f2b63516..1796e81889d62b691b7a709616ce08f155733597 100644 +index b36effc88b516958a7c0a46a7eb3a77a98ad3a20..582e08eaeee8fb6c777ad451ccc0436b02cac000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -235,6 +235,11 @@ public class ServerPlayer extends Player { +@@ -236,6 +236,11 @@ public class ServerPlayer extends Player { public boolean queueHealthUpdatePacket = false; public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; // Paper end @@ -392,14 +391,14 @@ index 5dea577aeb4fa627e4c207b8a84933c1f2b63516..1796e81889d62b691b7a709616ce08f1 // CraftBukkit start public String displayName; -@@ -325,6 +330,7 @@ public class ServerPlayer extends Player { +@@ -326,6 +331,7 @@ public class ServerPlayer extends Player { this.adventure$displayName = net.kyori.adventure.text.Component.text(this.getScoreboardName()); // Paper this.bukkitPickUpLoot = true; this.maxHealthCache = this.getMaxHealth(); + this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper } - - // Yes, this doesn't match Vanilla, but it's the best we can do for now. + // Paper start - Chunk priority + public BlockPos getPointInFront(double inFront) { diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java index b4098068e674b639e82c07e5d60e4e2120b4305b..fa23e9c476d4edc6176d8b8a6cb13c52d2f66a87 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java diff --git a/patches/server/0357-Avoid-hopper-searches-if-there-are-no-items.patch b/patches/server/0362-Avoid-hopper-searches-if-there-are-no-items.patch similarity index 100% rename from patches/server/0357-Avoid-hopper-searches-if-there-are-no-items.patch rename to patches/server/0362-Avoid-hopper-searches-if-there-are-no-items.patch diff --git a/patches/server/0358-Bees-get-gravity-in-void.-Fixes-MC-167279.patch b/patches/server/0363-Bees-get-gravity-in-void.-Fixes-MC-167279.patch similarity index 100% rename from patches/server/0358-Bees-get-gravity-in-void.-Fixes-MC-167279.patch rename to patches/server/0363-Bees-get-gravity-in-void.-Fixes-MC-167279.patch diff --git a/patches/server/0359-Optimise-getChunkAt-calls-for-loaded-chunks.patch b/patches/server/0364-Optimise-getChunkAt-calls-for-loaded-chunks.patch similarity index 92% rename from patches/server/0359-Optimise-getChunkAt-calls-for-loaded-chunks.patch rename to patches/server/0364-Optimise-getChunkAt-calls-for-loaded-chunks.patch index 3831aba372..080f8f5b61 100644 --- a/patches/server/0359-Optimise-getChunkAt-calls-for-loaded-chunks.patch +++ b/patches/server/0364-Optimise-getChunkAt-calls-for-loaded-chunks.patch @@ -7,10 +7,10 @@ bypass the need to get a player chunk, then get the either, then unwrap it... diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index de5b80fce9757517e51f2ef55340e884f2d7e3d4..c12c03b9e79f264ee593373f8a72ed37c0ae8514 100644 +index cd3de4cd1a38c5092f6a88de4fa33d6dda7f3445..9ef4a8dee2af8d76e5d2c27ff3490a394b9afd59 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -601,6 +601,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -442,6 +442,12 @@ public class ServerChunkCache extends ChunkSource { return this.getChunk(x, z, leastStatus, create); }, this.mainThreadProcessor).join(); } else { @@ -23,7 +23,7 @@ index de5b80fce9757517e51f2ef55340e884f2d7e3d4..c12c03b9e79f264ee593373f8a72ed37 ProfilerFiller gameprofilerfiller = this.level.getProfiler(); gameprofilerfiller.incrementCounter("getChunk"); -@@ -652,39 +658,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -497,39 +503,7 @@ public class ServerChunkCache extends ChunkSource { if (Thread.currentThread() != this.mainThread) { return null; } else { diff --git a/patches/server/0360-Add-debug-for-sync-chunk-loads.patch b/patches/server/0365-Add-debug-for-sync-chunk-loads.patch similarity index 97% rename from patches/server/0360-Add-debug-for-sync-chunk-loads.patch rename to patches/server/0365-Add-debug-for-sync-chunk-loads.patch index 1ea33e7ff0..4657aa35a9 100644 --- a/patches/server/0360-Add-debug-for-sync-chunk-loads.patch +++ b/patches/server/0365-Add-debug-for-sync-chunk-loads.patch @@ -298,10 +298,10 @@ index 0000000000000000000000000000000000000000..1120aef5b0dd983c467167f77245884e + } +} diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index c12c03b9e79f264ee593373f8a72ed37c0ae8514..509b2ee115584ce80717cc12a7ab548d103b4b92 100644 +index 9ef4a8dee2af8d76e5d2c27ff3490a394b9afd59..d97b50a7a71b8bb8dcaab35ae5f03314ad6acf7e 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -633,6 +633,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -476,6 +476,7 @@ public class ServerChunkCache extends ChunkSource { this.level.asyncChunkTaskManager.raisePriority(x1, z1, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY); com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.level, x1, z1); // Paper end @@ -310,10 +310,10 @@ index c12c03b9e79f264ee593373f8a72ed37c0ae8514..509b2ee115584ce80717cc12a7ab548d chunkproviderserver_b.managedBlock(completablefuture::isDone); com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index fb7954d4d4dbd35bf771b362f241294d79cf9933..8724396e7b2bb58b22c4f3262855f9f523dd6635 100644 +index 5622917a2884e87d43abfaf58e722957931b3178..ed8014ed36f8354aa1ae07689e9315c0c0d8867a 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -390,6 +390,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -392,6 +392,12 @@ public class ServerLevel extends Level implements WorldGenLevel { }; public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager; // Paper end diff --git a/patches/server/0361-Remove-garbage-Java-version-check.patch b/patches/server/0366-Remove-garbage-Java-version-check.patch similarity index 100% rename from patches/server/0361-Remove-garbage-Java-version-check.patch rename to patches/server/0366-Remove-garbage-Java-version-check.patch diff --git a/patches/server/0362-Add-ThrownEggHatchEvent.patch b/patches/server/0367-Add-ThrownEggHatchEvent.patch similarity index 100% rename from patches/server/0362-Add-ThrownEggHatchEvent.patch rename to patches/server/0367-Add-ThrownEggHatchEvent.patch diff --git a/patches/server/0363-Entity-Jump-API.patch b/patches/server/0368-Entity-Jump-API.patch similarity index 100% rename from patches/server/0363-Entity-Jump-API.patch rename to patches/server/0368-Entity-Jump-API.patch diff --git a/patches/server/0364-Add-option-to-nerf-pigmen-from-nether-portals.patch b/patches/server/0369-Add-option-to-nerf-pigmen-from-nether-portals.patch similarity index 96% rename from patches/server/0364-Add-option-to-nerf-pigmen-from-nether-portals.patch rename to patches/server/0369-Add-option-to-nerf-pigmen-from-nether-portals.patch index e1e7b38b6d..8f2b02bbbc 100644 --- a/patches/server/0364-Add-option-to-nerf-pigmen-from-nether-portals.patch +++ b/patches/server/0369-Add-option-to-nerf-pigmen-from-nether-portals.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add option to nerf pigmen from nether portals diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 8576fbaedf3076e8b492c499d4176b1116e7ef56..8bdaee1054f64fa5a0f4058ac3dc7d3626138ac4 100644 +index 240650cee26fc907f632e0c8ef3559a36460a3ba..185f6dd93f325b638289acd723c6cbbbedac80e1 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -386,6 +386,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0365-Make-the-GUI-graph-fancier.patch b/patches/server/0370-Make-the-GUI-graph-fancier.patch similarity index 100% rename from patches/server/0365-Make-the-GUI-graph-fancier.patch rename to patches/server/0370-Make-the-GUI-graph-fancier.patch diff --git a/patches/server/0366-add-hand-to-BlockMultiPlaceEvent.patch b/patches/server/0371-add-hand-to-BlockMultiPlaceEvent.patch similarity index 100% rename from patches/server/0366-add-hand-to-BlockMultiPlaceEvent.patch rename to patches/server/0371-add-hand-to-BlockMultiPlaceEvent.patch diff --git a/patches/server/0367-Validate-tripwire-hook-placement-before-update.patch b/patches/server/0372-Validate-tripwire-hook-placement-before-update.patch similarity index 100% rename from patches/server/0367-Validate-tripwire-hook-placement-before-update.patch rename to patches/server/0372-Validate-tripwire-hook-placement-before-update.patch diff --git a/patches/server/0368-Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/patches/server/0373-Add-option-to-allow-iron-golems-to-spawn-in-air.patch similarity index 100% rename from patches/server/0368-Add-option-to-allow-iron-golems-to-spawn-in-air.patch rename to patches/server/0373-Add-option-to-allow-iron-golems-to-spawn-in-air.patch diff --git a/patches/server/0369-Configurable-chance-of-villager-zombie-infection.patch b/patches/server/0374-Configurable-chance-of-villager-zombie-infection.patch similarity index 100% rename from patches/server/0369-Configurable-chance-of-villager-zombie-infection.patch rename to patches/server/0374-Configurable-chance-of-villager-zombie-infection.patch diff --git a/patches/server/0370-Optimise-Chunk-getFluid.patch b/patches/server/0375-Optimise-Chunk-getFluid.patch similarity index 96% rename from patches/server/0370-Optimise-Chunk-getFluid.patch rename to patches/server/0375-Optimise-Chunk-getFluid.patch index 14f1eb470a..670a1cca43 100644 --- a/patches/server/0370-Optimise-Chunk-getFluid.patch +++ b/patches/server/0375-Optimise-Chunk-getFluid.patch @@ -8,7 +8,7 @@ faster on its own, however removing the try catch makes it easier to inline due to code size diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index ee7296eb561b59a4c0fce200f1a59f66a6526cc2..5f65aa89dfb21fced457a3a9fef6ba05385b6b76 100644 +index 004c8abeafa53cdc3efa0f45742132e3ad492d70..ebe17598d3ef17cc5f0e99b876ed67936d46060d 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -381,18 +381,20 @@ public class LevelChunk extends ChunkAccess { diff --git a/patches/server/0371-Set-spigots-verbose-world-setting-to-false-by-def.patch b/patches/server/0376-Set-spigots-verbose-world-setting-to-false-by-def.patch similarity index 100% rename from patches/server/0371-Set-spigots-verbose-world-setting-to-false-by-def.patch rename to patches/server/0376-Set-spigots-verbose-world-setting-to-false-by-def.patch diff --git a/patches/server/0372-Add-tick-times-API-and-mspt-command.patch b/patches/server/0377-Add-tick-times-API-and-mspt-command.patch similarity index 100% rename from patches/server/0372-Add-tick-times-API-and-mspt-command.patch rename to patches/server/0377-Add-tick-times-API-and-mspt-command.patch diff --git a/patches/server/0373-Expose-MinecraftServer-isRunning.patch b/patches/server/0378-Expose-MinecraftServer-isRunning.patch similarity index 90% rename from patches/server/0373-Expose-MinecraftServer-isRunning.patch rename to patches/server/0378-Expose-MinecraftServer-isRunning.patch index 1cc90296d0..4bacea7d49 100644 --- a/patches/server/0373-Expose-MinecraftServer-isRunning.patch +++ b/patches/server/0378-Expose-MinecraftServer-isRunning.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Expose MinecraftServer#isRunning This allows for plugins to detect if the server is actually turning off in onDisable rather than just plugins reloading. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 051853707609fc026ab49fcd4a5a3798cdbed94a..fc1ed21c74b12b77544455e3c04453e71409c2c2 100644 +index a6f40cba559a4ca8c91b4daca0867f3be9cc94e6..a35501ea43bf3589b346b1e684c318b44ca57977 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2678,5 +2678,10 @@ public final class CraftServer implements Server { diff --git a/patches/server/0374-Add-Raw-Byte-ItemStack-Serialization.patch b/patches/server/0379-Add-Raw-Byte-ItemStack-Serialization.patch similarity index 100% rename from patches/server/0374-Add-Raw-Byte-ItemStack-Serialization.patch rename to patches/server/0379-Add-Raw-Byte-ItemStack-Serialization.patch diff --git a/patches/server/0375-Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/0380-Pillager-patrol-spawn-settings-and-per-player-option.patch similarity index 96% rename from patches/server/0375-Pillager-patrol-spawn-settings-and-per-player-option.patch rename to patches/server/0380-Pillager-patrol-spawn-settings-and-per-player-option.patch index 2caafe5a72..0b94225be1 100644 --- a/patches/server/0375-Pillager-patrol-spawn-settings-and-per-player-option.patch +++ b/patches/server/0380-Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -10,10 +10,10 @@ When not per player it will use the Vanilla mechanic of one delay per world and the world age for the start day. diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 1796e81889d62b691b7a709616ce08f155733597..84f68bb96eef7123cda3b096f992e4a2575fcd59 100644 +index 582e08eaeee8fb6c777ad451ccc0436b02cac000..71608048e941f83516631e2a3b6bf9f672d9f127 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -231,6 +231,7 @@ public class ServerPlayer extends Player { +@@ -232,6 +232,7 @@ public class ServerPlayer extends Player { public boolean wonGame; private int containerUpdateDelay; // Paper public long loginTime; // Paper diff --git a/patches/server/0376-Remote-Connections-shouldn-t-hold-up-shutdown.patch b/patches/server/0381-Remote-Connections-shouldn-t-hold-up-shutdown.patch similarity index 100% rename from patches/server/0376-Remote-Connections-shouldn-t-hold-up-shutdown.patch rename to patches/server/0381-Remote-Connections-shouldn-t-hold-up-shutdown.patch diff --git a/patches/server/0377-Do-not-allow-bees-to-load-chunks-for-beehives.patch b/patches/server/0382-Do-not-allow-bees-to-load-chunks-for-beehives.patch similarity index 100% rename from patches/server/0377-Do-not-allow-bees-to-load-chunks-for-beehives.patch rename to patches/server/0382-Do-not-allow-bees-to-load-chunks-for-beehives.patch diff --git a/patches/server/0378-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/0383-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch similarity index 87% rename from patches/server/0378-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch rename to patches/server/0383-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch index a96e57c792..0fcb7a0f21 100644 --- a/patches/server/0378-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch +++ b/patches/server/0383-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch @@ -7,10 +7,10 @@ Suspected case would be around the technique used in .stopRiding Stack will identify any causer of this and warn instead of crashing. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index f20b93c6372e36016b21591d3cd63c5d7a47721e..dab266e62f837e0efe57c0c4ae33b84c553c969c 100644 +index 9e940920f6ff6a43d7162d965936c171c55ed570..72af82374f47a1effc3d2f45beee1f611b4bb4b6 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1645,6 +1645,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1754,6 +1754,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public void addEntity(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot @@ -26,10 +26,10 @@ index f20b93c6372e36016b21591d3cd63c5d7a47721e..dab266e62f837e0efe57c0c4ae33b84c EntityType entitytypes = entity.getType(); int i = entitytypes.clientTrackingRange() * 16; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 8724396e7b2bb58b22c4f3262855f9f523dd6635..e531c2ed2432b0184878cc3fcfe0bc91a551977c 100644 +index ed8014ed36f8354aa1ae07689e9315c0c0d8867a..f5a9edf47230a1552a36ee5de4cb7560ea9ba7c4 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2292,7 +2292,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2294,7 +2294,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public void onTrackingStart(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot @@ -38,7 +38,7 @@ index 8724396e7b2bb58b22c4f3262855f9f523dd6635..e531c2ed2432b0184878cc3fcfe0bc91 if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -2326,6 +2326,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2328,6 +2328,7 @@ public class ServerLevel extends Level implements WorldGenLevel { entity.updateDynamicGameEventListener(DynamicGameEventListener::add); entity.valid = true; // CraftBukkit diff --git a/patches/server/0379-Don-t-tick-dead-players.patch b/patches/server/0384-Don-t-tick-dead-players.patch similarity index 85% rename from patches/server/0379-Don-t-tick-dead-players.patch rename to patches/server/0384-Don-t-tick-dead-players.patch index f66cc88d98..183a646d3b 100644 --- a/patches/server/0379-Don-t-tick-dead-players.patch +++ b/patches/server/0384-Don-t-tick-dead-players.patch @@ -7,10 +7,10 @@ Causes sync chunk loads and who knows what all else. This is safe because Spectators are skipped in unloaded chunks too in vanilla. diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 84f68bb96eef7123cda3b096f992e4a2575fcd59..0ad3dfc469145735f1669d4ca9a79f3fecc2ad60 100644 +index 71608048e941f83516631e2a3b6bf9f672d9f127..eae65f79bd1b286f35955bf7a0a5a116ecd12520 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -652,7 +652,7 @@ public class ServerPlayer extends Player { +@@ -668,7 +668,7 @@ public class ServerPlayer extends Player { public void doTick() { try { diff --git a/patches/server/0380-Dead-Player-s-shouldn-t-be-able-to-move.patch b/patches/server/0385-Dead-Player-s-shouldn-t-be-able-to-move.patch similarity index 100% rename from patches/server/0380-Dead-Player-s-shouldn-t-be-able-to-move.patch rename to patches/server/0385-Dead-Player-s-shouldn-t-be-able-to-move.patch diff --git a/patches/server/0381-Optimize-Collision-to-not-load-chunks.patch b/patches/server/0386-Optimize-Collision-to-not-load-chunks.patch similarity index 96% rename from patches/server/0381-Optimize-Collision-to-not-load-chunks.patch rename to patches/server/0386-Optimize-Collision-to-not-load-chunks.patch index 4b5ca48afb..df12155384 100644 --- a/patches/server/0381-Optimize-Collision-to-not-load-chunks.patch +++ b/patches/server/0386-Optimize-Collision-to-not-load-chunks.patch @@ -14,10 +14,10 @@ movement will load only the chunk the player enters anyways and avoids loading massive amounts of surrounding chunks due to large AABB lookups. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 7ca5032574ddc4fb63dbf9ef266c71042055fb2a..bec8969cae05c895a001888d020d61fd2d82a788 100644 +index d362c9c83a73b5f49b54563b423c76c8ed78dfc6..256bd12178c8dca2889fbcedb9327cc4a1164cf5 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -796,6 +796,7 @@ public abstract class PlayerList { +@@ -797,6 +797,7 @@ public abstract class PlayerList { entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); // CraftBukkit end @@ -26,7 +26,7 @@ index 7ca5032574ddc4fb63dbf9ef266c71042055fb2a..bec8969cae05c895a001888d020d61fd entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ()); } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 8bdaee1054f64fa5a0f4058ac3dc7d3626138ac4..ccfb7dfe2327cd2e187ad7909342fc137fa126db 100644 +index 185f6dd93f325b638289acd723c6cbbbedac80e1..001c1d55218671eaa9cee28ae42d756f352ff2fa 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -236,6 +236,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0382-Don-t-move-existing-players-to-world-spawn.patch b/patches/server/0387-Don-t-move-existing-players-to-world-spawn.patch similarity index 85% rename from patches/server/0382-Don-t-move-existing-players-to-world-spawn.patch rename to patches/server/0387-Don-t-move-existing-players-to-world-spawn.patch index d3ff87a9bc..0464df901c 100644 --- a/patches/server/0382-Don-t-move-existing-players-to-world-spawn.patch +++ b/patches/server/0387-Don-t-move-existing-players-to-world-spawn.patch @@ -10,10 +10,10 @@ larger than the keep loaded range. By skipping this, we avoid potential for a large spike on server start. diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 0ad3dfc469145735f1669d4ca9a79f3fecc2ad60..c2f9933796904628a55476eb9be1204b766893cf 100644 +index eae65f79bd1b286f35955bf7a0a5a116ecd12520..61f97fab1e0e3d6c9206c397cecfff868cf0d9d2 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -322,7 +322,7 @@ public class ServerPlayer extends Player { +@@ -323,7 +323,7 @@ public class ServerPlayer extends Player { this.stats = server.getPlayerList().getPlayerStats(this); this.advancements = server.getPlayerList().getPlayerAdvancements(this); this.maxUpStep = 1.0F; @@ -22,7 +22,7 @@ index 0ad3dfc469145735f1669d4ca9a79f3fecc2ad60..c2f9933796904628a55476eb9be1204b this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper -@@ -540,7 +540,7 @@ public class ServerPlayer extends Player { +@@ -556,7 +556,7 @@ public class ServerPlayer extends Player { position = Vec3.atCenterOf(((ServerLevel) world).getSharedSpawnPos()); } this.level = world; @@ -32,10 +32,10 @@ index 0ad3dfc469145735f1669d4ca9a79f3fecc2ad60..c2f9933796904628a55476eb9be1204b this.gameMode.setLevel((ServerLevel) world); } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index bec8969cae05c895a001888d020d61fd2d82a788..27dd95242c80d875de8f07e111f06e383eeec0d9 100644 +index 256bd12178c8dca2889fbcedb9327cc4a1164cf5..d9175bcd1060dbaee90e50466da3c6d816fb614e 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -215,6 +215,8 @@ public abstract class PlayerList { +@@ -216,6 +216,8 @@ public abstract class PlayerList { worldserver1 = worldserver; } diff --git a/patches/server/0383-Optimize-GoalSelector-Goal.Flag-Set-operations.patch b/patches/server/0388-Optimize-GoalSelector-Goal.Flag-Set-operations.patch similarity index 100% rename from patches/server/0383-Optimize-GoalSelector-Goal.Flag-Set-operations.patch rename to patches/server/0388-Optimize-GoalSelector-Goal.Flag-Set-operations.patch diff --git a/patches/server/0384-Improved-Watchdog-Support.patch b/patches/server/0389-Improved-Watchdog-Support.patch similarity index 98% rename from patches/server/0384-Improved-Watchdog-Support.patch rename to patches/server/0389-Improved-Watchdog-Support.patch index 4275ad252d..1ae35e0c51 100644 --- a/patches/server/0384-Improved-Watchdog-Support.patch +++ b/patches/server/0389-Improved-Watchdog-Support.patch @@ -269,10 +269,10 @@ index 637846c2dda1cf27c194ca4f16da454a62dc3f4b..648bc209938364a387c3f81dcd073db3 } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index dab266e62f837e0efe57c0c4ae33b84c553c969c..48fc5d6ca854de036013586be634b3e05e2c52bc 100644 +index 72af82374f47a1effc3d2f45beee1f611b4bb4b6..fcc9dd6e1c54e4ca16102150aa4c12ecc7de06df 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -589,6 +589,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -667,6 +667,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider MutableBoolean mutableboolean = new MutableBoolean(); do { @@ -281,10 +281,10 @@ index dab266e62f837e0efe57c0c4ae33b84c553c969c..48fc5d6ca854de036013586be634b3e0 list.stream().map((playerchunk) -> { CompletableFuture completablefuture; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 27dd95242c80d875de8f07e111f06e383eeec0d9..97c670508df6e5ee2a05a4765aafbeb23949b647 100644 +index d9175bcd1060dbaee90e50466da3c6d816fb614e..602a30f7dc51ffad9e5f5cc0b339108a2225aafd 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -517,7 +517,7 @@ public abstract class PlayerList { +@@ -518,7 +518,7 @@ public abstract class PlayerList { this.cserver.getPluginManager().callEvent(playerQuitEvent); entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); @@ -318,10 +318,10 @@ index 11a02c8259a039bbe229c5626055bceef9308b5a..c488e069a19d4bf082c94032571fcc77 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); 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 5f65aa89dfb21fced457a3a9fef6ba05385b6b76..291bcca206722c86bca6d13058d18c413c38d256 100644 +index ebe17598d3ef17cc5f0e99b876ed67936d46060d..c8444f4bfd127b7d8194aaa984505eff249ae094 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -1083,6 +1083,7 @@ public class LevelChunk extends ChunkAccess { +@@ -1085,6 +1085,7 @@ public class LevelChunk extends ChunkAccess { gameprofilerfiller.pop(); } catch (Throwable throwable) { diff --git a/patches/server/0385-Optimize-Pathfinding.patch b/patches/server/0390-Optimize-Pathfinding.patch similarity index 100% rename from patches/server/0385-Optimize-Pathfinding.patch rename to patches/server/0390-Optimize-Pathfinding.patch diff --git a/patches/server/0386-Reduce-Either-Optional-allocation.patch b/patches/server/0391-Reduce-Either-Optional-allocation.patch similarity index 100% rename from patches/server/0386-Reduce-Either-Optional-allocation.patch rename to patches/server/0391-Reduce-Either-Optional-allocation.patch diff --git a/patches/server/0387-Reduce-memory-footprint-of-NBTTagCompound.patch b/patches/server/0392-Reduce-memory-footprint-of-NBTTagCompound.patch similarity index 100% rename from patches/server/0387-Reduce-memory-footprint-of-NBTTagCompound.patch rename to patches/server/0392-Reduce-memory-footprint-of-NBTTagCompound.patch diff --git a/patches/server/0388-Prevent-opening-inventories-when-frozen.patch b/patches/server/0393-Prevent-opening-inventories-when-frozen.patch similarity index 94% rename from patches/server/0388-Prevent-opening-inventories-when-frozen.patch rename to patches/server/0393-Prevent-opening-inventories-when-frozen.patch index 80482901c6..8c7b292e06 100644 --- a/patches/server/0388-Prevent-opening-inventories-when-frozen.patch +++ b/patches/server/0393-Prevent-opening-inventories-when-frozen.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Prevent opening inventories when frozen diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index c2f9933796904628a55476eb9be1204b766893cf..5e1bb276d61ed72027f94defc3f192756af5808f 100644 +index 61f97fab1e0e3d6c9206c397cecfff868cf0d9d2..227bcd9c1cfcc6bf8dedacdca28731a8ffc7171a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -621,7 +621,7 @@ public class ServerPlayer extends Player { +@@ -637,7 +637,7 @@ public class ServerPlayer extends Player { containerUpdateDelay = level.paperConfig().tickRates.containerUpdate; } // Paper end @@ -17,7 +17,7 @@ index c2f9933796904628a55476eb9be1204b766893cf..5e1bb276d61ed72027f94defc3f19275 this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper this.containerMenu = this.inventoryMenu; } -@@ -1491,7 +1491,7 @@ public class ServerPlayer extends Player { +@@ -1507,7 +1507,7 @@ public class ServerPlayer extends Player { } else { // CraftBukkit start this.containerMenu = container; diff --git a/patches/server/0389-Optimise-ArraySetSorted-removeIf.patch b/patches/server/0394-Optimise-ArraySetSorted-removeIf.patch similarity index 97% rename from patches/server/0389-Optimise-ArraySetSorted-removeIf.patch rename to patches/server/0394-Optimise-ArraySetSorted-removeIf.patch index 1aa31112c4..eed4ea8bc2 100644 --- a/patches/server/0389-Optimise-ArraySetSorted-removeIf.patch +++ b/patches/server/0394-Optimise-ArraySetSorted-removeIf.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Optimise ArraySetSorted#removeIf Remove iterator allocation and ensure the call is always O(n) diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 6228f2f67541da62b0ae093de987662db9643740..8376439e36f0f75779d0fbefbe50b215a40c42aa 100644 +index 9309ea89a440606be3e56ef634f5048a72b0009e..1d1ea158d095bb69260929e8d84f2632a875c136 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -86,13 +86,27 @@ public abstract class DistanceManager { diff --git a/patches/server/0390-Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/0395-Don-t-run-entity-collision-code-if-not-needed.patch similarity index 100% rename from patches/server/0390-Don-t-run-entity-collision-code-if-not-needed.patch rename to patches/server/0395-Don-t-run-entity-collision-code-if-not-needed.patch diff --git a/patches/server/0391-Implement-Player-Client-Options-API.patch b/patches/server/0396-Implement-Player-Client-Options-API.patch similarity index 96% rename from patches/server/0391-Implement-Player-Client-Options-API.patch rename to patches/server/0396-Implement-Player-Client-Options-API.patch index 9b8bf897e3..5a4d2416f5 100644 --- a/patches/server/0391-Implement-Player-Client-Options-API.patch +++ b/patches/server/0396-Implement-Player-Client-Options-API.patch @@ -85,10 +85,10 @@ index 0000000000000000000000000000000000000000..b6f4400df3d8ec7e06a996de54f8cabb + } +} diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 5e1bb276d61ed72027f94defc3f192756af5808f..2a18a60fdb71f1c665bda4a6c04a1fa1ff47a83b 100644 +index 227bcd9c1cfcc6bf8dedacdca28731a8ffc7171a..49cb507ddd378b9a16b82e5c2a28531fce9c6708 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1855,6 +1855,7 @@ public class ServerPlayer extends Player { +@@ -1871,6 +1871,7 @@ public class ServerPlayer extends Player { public String locale = null; // CraftBukkit - add, lowercase // Paper - default to null public java.util.Locale adventure$locale = java.util.Locale.US; // Paper public void updateOptions(ServerboundClientInformationPacket packet) { @@ -97,7 +97,7 @@ index 5e1bb276d61ed72027f94defc3f192756af5808f..2a18a60fdb71f1c665bda4a6c04a1fa1 if (getMainArm() != packet.mainHand()) { PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 8a349c179e9abcda140546c56ea884422b409b5d..71b96630dd6543d8a4d8df5165d7182fb0f35067 100644 +index 86447a824d9749f85a6378682d4a6f74ca19875d..0fda8c27c717bd030b826c5c7267b880f9d1f6b9 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -574,6 +574,24 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0392-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch b/patches/server/0397-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch similarity index 88% rename from patches/server/0392-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch rename to patches/server/0397-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch index fe3a5aca21..48eea37bf3 100644 --- a/patches/server/0392-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch +++ b/patches/server/0397-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch @@ -7,10 +7,10 @@ Subject: [PATCH] Don't crash if player is attempted to be removed from I suspect it deals with teleporting as it uses players current x/y/z diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 8376439e36f0f75779d0fbefbe50b215a40c42aa..4a9d0fca55b71f817defcb4286154c0a47bede03 100644 +index 1d1ea158d095bb69260929e8d84f2632a875c136..f456ba4bf699e1f6bd15726a037a0047b6ca7380 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -300,8 +300,8 @@ public abstract class DistanceManager { +@@ -440,8 +440,8 @@ public abstract class DistanceManager { ObjectSet objectset = (ObjectSet) this.playersPerChunk.get(i); if (objectset == null) return; // CraftBukkit - SPIGOT-6208 diff --git a/patches/server/0393-Fix-Chunk-Post-Processing-deadlock-risk.patch b/patches/server/0398-Fix-Chunk-Post-Processing-deadlock-risk.patch similarity index 90% rename from patches/server/0393-Fix-Chunk-Post-Processing-deadlock-risk.patch rename to patches/server/0398-Fix-Chunk-Post-Processing-deadlock-risk.patch index d0b17eef56..91616ec7ae 100644 --- a/patches/server/0393-Fix-Chunk-Post-Processing-deadlock-risk.patch +++ b/patches/server/0398-Fix-Chunk-Post-Processing-deadlock-risk.patch @@ -25,10 +25,10 @@ This successfully fixed a reoccurring and highly reproducible crash for heightmaps. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 48fc5d6ca854de036013586be634b3e05e2c52bc..0fdf33bfab3191dbb582bc401f6f0b62aadacb4e 100644 +index fcc9dd6e1c54e4ca16102150aa4c12ecc7de06df..aed3da6ef2d498d3f1c9c64177bf1ba6b8157493 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -179,6 +179,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -193,6 +193,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }; // CraftBukkit end @@ -36,7 +36,7 @@ index 48fc5d6ca854de036013586be634b3e05e2c52bc..0fdf33bfab3191dbb582bc401f6f0b62 // Paper start - distance maps private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); -@@ -1023,16 +1024,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1132,16 +1133,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }); CompletableFuture> completablefuture1 = completablefuture.thenApplyAsync((either) -> { return either.mapLeft((list) -> { @@ -60,10 +60,10 @@ index 48fc5d6ca854de036013586be634b3e05e2c52bc..0fdf33bfab3191dbb582bc401f6f0b62 completablefuture1.thenAcceptAsync((either) -> { either.ifLeft((chunk) -> { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 509b2ee115584ce80717cc12a7ab548d103b4b92..42b4214a1319691e9a6cb0c5fafaeeff821f3f99 100644 +index d97b50a7a71b8bb8dcaab35ae5f03314ad6acf7e..a986051dead41f1a9f70e5e00572255e9939c4a9 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -1138,6 +1138,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -992,6 +992,7 @@ public class ServerChunkCache extends ChunkSource { return super.pollTask() || execChunkTask; // Paper } } finally { diff --git a/patches/server/0394-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch b/patches/server/0399-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch similarity index 88% rename from patches/server/0394-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch rename to patches/server/0399-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch index 1ba8c296be..de10cb2f1f 100644 --- a/patches/server/0394-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch +++ b/patches/server/0399-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch @@ -28,10 +28,10 @@ receives a deterministic result, and should no longer require 1 tick delays anymore. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 0fdf33bfab3191dbb582bc401f6f0b62aadacb4e..5187988a22b55ac783147afe455a139662b67f7d 100644 +index aed3da6ef2d498d3f1c9c64177bf1ba6b8157493..ea224e68b680c5e9ab38998f7709a4dbe3471b86 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1653,6 +1653,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1762,6 +1762,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider .printStackTrace(); return; } @@ -40,10 +40,10 @@ index 0fdf33bfab3191dbb582bc401f6f0b62aadacb4e..5187988a22b55ac783147afe455a1396 if (!(entity instanceof EnderDragonPart)) { EntityType entitytypes = entity.getType(); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 2a18a60fdb71f1c665bda4a6c04a1fa1ff47a83b..084521ed853fc2b15be355a17da8421c54716815 100644 +index 49cb507ddd378b9a16b82e5c2a28531fce9c6708..53dcb40f5217d560ee42da3d73d1e66e2620067a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -254,6 +254,7 @@ public class ServerPlayer extends Player { +@@ -255,6 +255,7 @@ public class ServerPlayer extends Player { public double maxHealthCache; public boolean joining = true; public boolean sentListPacket = false; @@ -52,10 +52,10 @@ index 2a18a60fdb71f1c665bda4a6c04a1fa1ff47a83b..084521ed853fc2b15be355a17da8421c public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 97c670508df6e5ee2a05a4765aafbeb23949b647..b48641bbe371ffacbbd659a0ee1783437267a4dc 100644 +index 602a30f7dc51ffad9e5f5cc0b339108a2225aafd..a7bc7e83b9355ef920d94fff8572528965352fb6 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -281,6 +281,12 @@ public abstract class PlayerList { +@@ -282,6 +282,12 @@ public abstract class PlayerList { this.playersByUUID.put(player.getUUID(), player); // this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below @@ -68,7 +68,7 @@ index 97c670508df6e5ee2a05a4765aafbeb23949b647..b48641bbe371ffacbbd659a0ee178343 // CraftBukkit start CraftPlayer bukkitPlayer = player.getBukkitEntity(); -@@ -319,6 +325,8 @@ public abstract class PlayerList { +@@ -320,6 +326,8 @@ public abstract class PlayerList { player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[]{entityplayer1})); } player.sentListPacket = true; @@ -77,7 +77,7 @@ index 97c670508df6e5ee2a05a4765aafbeb23949b647..b48641bbe371ffacbbd659a0ee178343 // CraftBukkit end player.connection.send(new ClientboundSetEntityDataPacket(player.getId(), player.getEntityData(), true)); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn -@@ -344,6 +352,11 @@ public abstract class PlayerList { +@@ -345,6 +353,11 @@ public abstract class PlayerList { playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect)); } @@ -89,7 +89,7 @@ index 97c670508df6e5ee2a05a4765aafbeb23949b647..b48641bbe371ffacbbd659a0ee178343 if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) { CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle"); // CraftBukkit start -@@ -392,6 +405,10 @@ public abstract class PlayerList { +@@ -393,6 +406,10 @@ public abstract class PlayerList { } } @@ -100,7 +100,7 @@ index 97c670508df6e5ee2a05a4765aafbeb23949b647..b48641bbe371ffacbbd659a0ee178343 player.initInventoryMenu(); // CraftBukkit - Moved from above, added world // Paper start - Add to collideRule team if needed -@@ -401,6 +418,7 @@ public abstract class PlayerList { +@@ -402,6 +419,7 @@ public abstract class PlayerList { scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam); } // Paper end diff --git a/patches/server/0395-Load-Chunks-for-Login-Asynchronously.patch b/patches/server/0400-Load-Chunks-for-Login-Asynchronously.patch similarity index 85% rename from patches/server/0395-Load-Chunks-for-Login-Asynchronously.patch rename to patches/server/0400-Load-Chunks-for-Login-Asynchronously.patch index 82b57d8902..8b3c658648 100644 --- a/patches/server/0395-Load-Chunks-for-Login-Asynchronously.patch +++ b/patches/server/0400-Load-Chunks-for-Login-Asynchronously.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Load Chunks for Login Asynchronously diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 67f1a8490d48f55d58268d7e34a27170792b5559..a7db54a94a5017e737ce9682a52eed7405af8cc1 100644 +index f5a9edf47230a1552a36ee5de4cb7560ea9ba7c4..a778b4b5b2413c25c2f0f0efc72ba1d362d89acf 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -170,6 +170,7 @@ import org.bukkit.event.world.GenericGameEvent; @@ -16,7 +16,7 @@ index 67f1a8490d48f55d58268d7e34a27170792b5559..a7db54a94a5017e737ce9682a52eed74 public class ServerLevel extends Level implements WorldGenLevel { -@@ -404,6 +405,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -406,6 +407,7 @@ public class ServerLevel extends Level implements WorldGenLevel { return this.getServer().getPlayerList().getPlayer(uuid); } // Paper end @@ -25,7 +25,7 @@ index 67f1a8490d48f55d58268d7e34a27170792b5559..a7db54a94a5017e737ce9682a52eed74 // Add env and gen to constructor, IWorldDataServer -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 084521ed853fc2b15be355a17da8421c54716815..acc64abd9420b81ed4c8c17cf6a9f5bc5d35f116 100644 +index 53dcb40f5217d560ee42da3d73d1e66e2620067a..971f72c1dd713077c128279a78ed37f15aedeff6 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -182,6 +182,7 @@ public class ServerPlayer extends Player { @@ -36,7 +36,7 @@ index 084521ed853fc2b15be355a17da8421c54716815..acc64abd9420b81ed4c8c17cf6a9f5bc public final MinecraftServer server; public final ServerPlayerGameMode gameMode; private final PlayerAdvancements advancements; -@@ -255,6 +256,7 @@ public class ServerPlayer extends Player { +@@ -256,6 +257,7 @@ public class ServerPlayer extends Player { public boolean joining = true; public boolean sentListPacket = false; public boolean supressTrackerForLogin = false; // Paper @@ -45,10 +45,10 @@ index 084521ed853fc2b15be355a17da8421c54716815..acc64abd9420b81ed4c8c17cf6a9f5bc public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java -index be677d437d17b74c6188ce1bd5fc6fdc228fd92f..78fbb4c3e52e900956ae0811aaf934c81ee5ea48 100644 +index 478109526cff7ceb0565cea3b5e97b9a07fbf8d1..3c1698ba0d3bc412ab957777d9b5211dbc555208 100644 --- a/src/main/java/net/minecraft/server/level/TicketType.java +++ b/src/main/java/net/minecraft/server/level/TicketType.java -@@ -23,6 +23,7 @@ public class TicketType { +@@ -25,6 +25,7 @@ public class TicketType { public static final TicketType FORCED = TicketType.create("forced", Comparator.comparingLong(ChunkPos::toLong)); public static final TicketType LIGHT = TicketType.create("light", Comparator.comparingLong(ChunkPos::toLong)); public static final TicketType PORTAL = TicketType.create("portal", Vec3i::compareTo, 300); @@ -103,7 +103,7 @@ index c83395364edb4f2ba8515326b19c4f1a436a0502..c99266d4782c5d58339e63f7564c28b4 try { ServerPlayer entityplayer1 = this.server.getPlayerList().getPlayerForLogin(this.gameProfile, s); // CraftBukkit - add player reference diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205aa0949f84 100644 +index a7bc7e83b9355ef920d94fff8572528965352fb6..32ab0cd6cb42b0ab8a14f790dfcf4b155c945d6d 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -139,6 +139,7 @@ public abstract class PlayerList { @@ -114,19 +114,21 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a // CraftBukkit start // private final Map stats; // private final Map advancements; -@@ -178,6 +179,11 @@ public abstract class PlayerList { - } - +@@ -180,6 +181,13 @@ public abstract class PlayerList { public void placeNewPlayer(Connection connection, ServerPlayer player) { -+ ServerPlayer prev = pendingPlayers.put(player.getUUID(), player);// Paper + player.isRealPlayer = true; // Paper - Chunk priority + player.loginTime = System.currentTimeMillis(); // Paper ++ // Paper start ++ ServerPlayer prev = pendingPlayers.put(player.getUUID(), player); + if (prev != null) { + disconnectPendingPlayer(prev); + } -+ player.networkManager = connection; // Paper - player.loginTime = System.currentTimeMillis(); // Paper ++ player.networkManager = connection; ++ // Paper end GameProfile gameprofile = player.getGameProfile(); GameProfileCache usercache = this.server.getProfileCache(); -@@ -191,7 +197,7 @@ public abstract class PlayerList { + Optional optional = usercache.get(gameprofile.getId()); +@@ -192,7 +200,7 @@ public abstract class PlayerList { if (nbttagcompound != null && nbttagcompound.contains("bukkit")) { CompoundTag bukkit = nbttagcompound.getCompound("bukkit"); s = bukkit.contains("lastKnownName", 8) ? bukkit.getString("lastKnownName") : s; @@ -135,7 +137,7 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a // CraftBukkit end if (nbttagcompound != null) { -@@ -218,11 +224,15 @@ public abstract class PlayerList { +@@ -219,11 +227,15 @@ public abstract class PlayerList { if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are.... player.setLevel(worldserver1); @@ -152,7 +154,7 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a // Spigot start - spawn location event Player spawnPlayer = player.getBukkitEntity(); -@@ -264,6 +274,61 @@ public abstract class PlayerList { +@@ -265,6 +277,56 @@ public abstract class PlayerList { player.getRecipeBook().sendInitialRecipeBook(player); this.updateEntireScoreboard(worldserver1.getScoreboard(), player); this.server.invalidateStatus(); @@ -164,31 +166,26 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a + final net.minecraft.world.level.ChunkPos pos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ); + net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap; + net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager; -+ distanceManager.addTicket(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong()); -+ worldserver1.getChunkSource().runDistanceManagerUpdates(); -+ worldserver1.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, true).thenApply(chunk -> { -+ net.minecraft.server.level.ChunkHolder updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong()); -+ if (updatingChunk != null) { -+ return updatingChunk.getEntityTickingChunkFuture(); -+ } else { -+ return java.util.concurrent.CompletableFuture.completedFuture(chunk); -+ } -+ }).thenAccept(chunk -> { -+ MinecraftServer.getServer().scheduleOnMain(() -> { -+ try { -+ if (!playerconnection.connection.isConnected()) { -+ return; ++ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ worldserver1, chunkX, chunkZ, net.minecraft.server.level.ChunkHolder.FullChunkStatus.ENTITY_TICKING, true, ++ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHEST, ++ (chunk) -> { ++ MinecraftServer.getServer().scheduleOnMain(() -> { ++ try { ++ if (!playerconnection.connection.isConnected()) { ++ return; ++ } ++ PlayerList.this.postChunkLoadJoin( ++ player, finalWorldserver, connection, playerconnection, ++ nbttagcompound, s1, lastKnownName ++ ); ++ distanceManager.addTicket(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong()); ++ } finally { ++ finalWorldserver.pendingLogin.remove(player); + } -+ PlayerList.this.postChunkLoadJoin( -+ player, finalWorldserver, connection, playerconnection, -+ nbttagcompound, s1, lastKnownName -+ ); -+ distanceManager.addTicket(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong()); -+ } finally { -+ finalWorldserver.pendingLogin.remove(player); -+ } -+ }); -+ }); ++ }); ++ } ++ ); + } + + public ServerPlayer getActivePlayer(UUID uuid) { @@ -214,7 +211,7 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a MutableComponent ichatmutablecomponent; if (player.getGameProfile().getName().equalsIgnoreCase(s)) { -@@ -505,6 +570,7 @@ public abstract class PlayerList { +@@ -506,6 +568,7 @@ public abstract class PlayerList { protected void save(ServerPlayer player) { if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit @@ -222,7 +219,7 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a this.playerIo.save(player); ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit -@@ -532,7 +598,7 @@ public abstract class PlayerList { +@@ -533,7 +596,7 @@ public abstract class PlayerList { } PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); @@ -231,7 +228,7 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog) -@@ -577,6 +643,13 @@ public abstract class PlayerList { +@@ -578,6 +641,13 @@ public abstract class PlayerList { // this.advancements.remove(uuid); // CraftBukkit end } @@ -245,7 +242,7 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a // CraftBukkit start // this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer})); -@@ -594,7 +667,7 @@ public abstract class PlayerList { +@@ -595,7 +665,7 @@ public abstract class PlayerList { this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity()); // CraftBukkit end @@ -254,7 +251,7 @@ index b48641bbe371ffacbbd659a0ee1783437267a4dc..b1f6dc751c3dab5220a02223f6ba205a } // CraftBukkit start - Whole method, SocketAddress to LoginListener, added hostname to signature, return EntityPlayer -@@ -613,6 +686,13 @@ public abstract class PlayerList { +@@ -614,6 +684,13 @@ public abstract class PlayerList { list.add(entityplayer); } } diff --git a/patches/server/0396-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/0401-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch similarity index 93% rename from patches/server/0396-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch rename to patches/server/0401-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch index 70e92d4754..0a1150e1ea 100644 --- a/patches/server/0396-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch +++ b/patches/server/0401-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch @@ -7,7 +7,7 @@ The code following this has better support for null worlds to move them back to the world spawn. diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index ccfb7dfe2327cd2e187ad7909342fc137fa126db..15c551347badbd0177d57c2b7d3500006eb7e0f7 100644 +index 001c1d55218671eaa9cee28ae42d756f352ff2fa..1b8f7bd5dd85136788b02cef64353d581cdf2108 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -2096,9 +2096,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0397-Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/0402-Add-PlayerAttackEntityCooldownResetEvent.patch similarity index 100% rename from patches/server/0397-Add-PlayerAttackEntityCooldownResetEvent.patch rename to patches/server/0402-Add-PlayerAttackEntityCooldownResetEvent.patch diff --git a/patches/server/0398-Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/0403-Don-t-fire-BlockFade-on-worldgen-threads.patch similarity index 100% rename from patches/server/0398-Don-t-fire-BlockFade-on-worldgen-threads.patch rename to patches/server/0403-Don-t-fire-BlockFade-on-worldgen-threads.patch diff --git a/patches/server/0399-Add-phantom-creative-and-insomniac-controls.patch b/patches/server/0404-Add-phantom-creative-and-insomniac-controls.patch similarity index 100% rename from patches/server/0399-Add-phantom-creative-and-insomniac-controls.patch rename to patches/server/0404-Add-phantom-creative-and-insomniac-controls.patch diff --git a/patches/server/0400-Fix-numerous-item-duplication-issues-and-teleport-is.patch b/patches/server/0405-Fix-numerous-item-duplication-issues-and-teleport-is.patch similarity index 99% rename from patches/server/0400-Fix-numerous-item-duplication-issues-and-teleport-is.patch rename to patches/server/0405-Fix-numerous-item-duplication-issues-and-teleport-is.patch index ffa011ceed..e5cb8f7d91 100644 --- a/patches/server/0400-Fix-numerous-item-duplication-issues-and-teleport-is.patch +++ b/patches/server/0405-Fix-numerous-item-duplication-issues-and-teleport-is.patch @@ -16,7 +16,7 @@ So even if something NEW comes up, it would be impossible to drop the same item twice because the source was destroyed. diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 15c551347badbd0177d57c2b7d3500006eb7e0f7..70978ba28cec4dd3e64bf380c0669b3bcf4a640b 100644 +index 1b8f7bd5dd85136788b02cef64353d581cdf2108..74e13ae8b1e6a9365d46f5684ee58e42658d2341 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -2226,11 +2226,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0401-Villager-Restocks-API.patch b/patches/server/0406-Villager-Restocks-API.patch similarity index 100% rename from patches/server/0401-Villager-Restocks-API.patch rename to patches/server/0406-Villager-Restocks-API.patch diff --git a/patches/server/0402-Validate-PickItem-Packet-and-kick-for-invalid.patch b/patches/server/0407-Validate-PickItem-Packet-and-kick-for-invalid.patch similarity index 100% rename from patches/server/0402-Validate-PickItem-Packet-and-kick-for-invalid.patch rename to patches/server/0407-Validate-PickItem-Packet-and-kick-for-invalid.patch diff --git a/patches/server/0403-Expose-game-version.patch b/patches/server/0408-Expose-game-version.patch similarity index 89% rename from patches/server/0403-Expose-game-version.patch rename to patches/server/0408-Expose-game-version.patch index 82cea73f25..ba5a794206 100644 --- a/patches/server/0403-Expose-game-version.patch +++ b/patches/server/0408-Expose-game-version.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Expose game version diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index bfd785af2d459061054a101def1a6c6bfd9cdda1..ed74a0295d3ade16cd3120ef6abc391f662b1263 100644 +index c8c11ec3c5c4c4d1ed09163aa6d3a4275e497e11..aac16630c83034cdb1ce14e04bfc24c39ff65454 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -579,6 +579,13 @@ public final class CraftServer implements Server { diff --git a/patches/server/0404-Optimize-Voxel-Shape-Merging.patch b/patches/server/0409-Optimize-Voxel-Shape-Merging.patch similarity index 100% rename from patches/server/0404-Optimize-Voxel-Shape-Merging.patch rename to patches/server/0409-Optimize-Voxel-Shape-Merging.patch diff --git a/patches/server/0405-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch b/patches/server/0410-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch similarity index 100% rename from patches/server/0405-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch rename to patches/server/0410-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch diff --git a/patches/server/0406-misc-debugging-dumps.patch b/patches/server/0411-misc-debugging-dumps.patch similarity index 96% rename from patches/server/0406-misc-debugging-dumps.patch rename to patches/server/0411-misc-debugging-dumps.patch index 1471756c75..1709001c6e 100644 --- a/patches/server/0406-misc-debugging-dumps.patch +++ b/patches/server/0411-misc-debugging-dumps.patch @@ -29,7 +29,7 @@ index 0000000000000000000000000000000000000000..2d5494d2813b773e60ddba6790b750a9 + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 40945909bbefa59da6be784bcf440dfb2075b670..b1f8374253d04d1468f5d57792b30f91a274b97f 100644 +index 3a4222f78a02e10ecccc03df3c580895fbb8059d..ff94b07246b5e17be53f4e7294557c6744c62248 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -871,6 +871,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop playersInMobSpawnRange; + com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playersInChunkTickRange; -+ -+ void onChunkAdd() { -+ long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos); -+ this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); -+ this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); -+ } -+ -+ void onChunkRemove() { -+ this.playersInMobSpawnRange = null; -+ this.playersInChunkTickRange = null; -+ } + // Paper end - optimise anyPlayerCloseEnoughForSpawning + public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size()); this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -@@ -97,6 +114,7 @@ public class ChunkHolder { - this.setTicketLevel(level); - this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()]; - this.chunkMap = (ChunkMap)playersWatchingChunkProvider; // Paper -+ this.onChunkAdd(); // Paper - optimise anyPlayerCloseEnoughForSpawning - } - - // Paper start diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 9077af957d284e341ca8327cb837dc9b4bb3ffee..6e27a89af794d411cce3c1c932c1f4910cec889c 100644 +index 82eceddc15dcdf592dc5bbe6f1249f537be0a91e..43ad735f57ab513311d700b42d7d0f2f1e43d0e7 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -182,11 +182,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -196,11 +196,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper // Paper start - distance maps private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); @@ -69,7 +67,7 @@ index 9077af957d284e341ca8327cb837dc9b4bb3ffee..6e27a89af794d411cce3c1c932c1f491 // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { this.playerMobDistanceMap.add(player, chunkX, chunkZ, this.distanceManager.getSimulationDistance()); -@@ -196,6 +208,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -210,6 +222,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider void removePlayerFromDistanceMaps(ServerPlayer player) { @@ -80,7 +78,7 @@ index 9077af957d284e341ca8327cb837dc9b4bb3ffee..6e27a89af794d411cce3c1c932c1f491 // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { this.playerMobDistanceMap.remove(player); -@@ -207,6 +223,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -221,6 +237,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int chunkX = MCUtil.getChunkCoordinate(player.getX()); int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated @@ -88,7 +86,7 @@ index 9077af957d284e341ca8327cb837dc9b4bb3ffee..6e27a89af794d411cce3c1c932c1f491 // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { this.playerMobDistanceMap.update(player, chunkX, chunkZ, this.distanceManager.getSimulationDistance()); -@@ -300,6 +317,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -323,6 +340,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.regionManagers.add(this.dataRegionManager); // Paper end this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper @@ -127,23 +125,7 @@ index 9077af957d284e341ca8327cb837dc9b4bb3ffee..6e27a89af794d411cce3c1c932c1f491 } protected ChunkGenerator generator() { -@@ -555,6 +604,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - holder = (ChunkHolder) this.pendingUnloads.remove(pos); - if (holder != null) { - holder.setTicketLevel(level); -+ holder.onChunkAdd(); // Paper - optimise anyPlayerCloseEnoughForSpawning - PUT HERE AFTER RE-ADDING ONLY - } else { - holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); - // Paper start -@@ -650,6 +700,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); - - if (playerchunk != null) { -+ playerchunk.onChunkRemove(); // Paper - this.pendingUnloads.put(j, playerchunk); - this.modified = true; - ++i; -@@ -1415,43 +1466,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1524,43 +1573,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return this.anyPlayerCloseEnoughForSpawning(pos, false); } @@ -224,7 +206,7 @@ index 9077af957d284e341ca8327cb837dc9b4bb3ffee..6e27a89af794d411cce3c1c932c1f491 public List getPlayersCloseForSpawning(ChunkPos pos) { diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 4a9d0fca55b71f817defcb4286154c0a47bede03..62118348d6fb00f063507debb488e1ff431d139c 100644 +index f456ba4bf699e1f6bd15726a037a0047b6ca7380..b2df5e18ce5260a9781052db7afb0b9786fb887c 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -49,7 +49,7 @@ public abstract class DistanceManager { @@ -236,16 +218,16 @@ index 4a9d0fca55b71f817defcb4286154c0a47bede03..62118348d6fb00f063507debb488e1ff private final TickingTracker tickingTicketsTracker = new TickingTracker(); private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33); // Paper start use a queue, but still keep unique requirement -@@ -140,7 +140,7 @@ public abstract class DistanceManager { +@@ -141,7 +141,7 @@ public abstract class DistanceManager { protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k); public boolean runAllUpdates(ChunkMap chunkStorage) { - this.naturalSpawnChunkCounter.runAllUpdates(); + //this.f.a(); // Paper - no longer used this.tickingTicketsTracker.runAllUpdates(); + org.spigotmc.AsyncCatcher.catchOp("DistanceManagerTick"); // Paper this.playerTicketManager.runAllUpdates(); - int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE); -@@ -289,7 +289,7 @@ public abstract class DistanceManager { +@@ -429,7 +429,7 @@ public abstract class DistanceManager { ((ObjectSet) this.playersPerChunk.computeIfAbsent(i, (j) -> { return new ObjectOpenHashSet(); })).add(player); @@ -254,7 +236,7 @@ index 4a9d0fca55b71f817defcb4286154c0a47bede03..62118348d6fb00f063507debb488e1ff this.playerTicketManager.update(i, 0, true); this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); } -@@ -303,7 +303,7 @@ public abstract class DistanceManager { +@@ -443,7 +443,7 @@ public abstract class DistanceManager { if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully. if (objectset == null || objectset.isEmpty()) { // Paper this.playersPerChunk.remove(i); @@ -263,7 +245,7 @@ index 4a9d0fca55b71f817defcb4286154c0a47bede03..62118348d6fb00f063507debb488e1ff this.playerTicketManager.update(i, Integer.MAX_VALUE, false); this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); } -@@ -347,13 +347,17 @@ public abstract class DistanceManager { +@@ -487,13 +487,17 @@ public abstract class DistanceManager { // Paper end public int getNaturalSpawnChunkCount() { @@ -286,10 +268,10 @@ index 4a9d0fca55b71f817defcb4286154c0a47bede03..62118348d6fb00f063507debb488e1ff public String getDebugStatus() { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 42b4214a1319691e9a6cb0c5fafaeeff821f3f99..1d9a0f6effa1654609f4d0752ec69eed6ab7134b 100644 +index a986051dead41f1a9f70e5e00572255e9939c4a9..70c5e151d47217d417b91105ac63f17a2eb957bf 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -873,6 +873,37 @@ public class ServerChunkCache extends ChunkSource { +@@ -727,6 +727,37 @@ public class ServerChunkCache extends ChunkSource { if (flag) { this.chunkMap.tick(); } else { @@ -327,7 +309,7 @@ index 42b4214a1319691e9a6cb0c5fafaeeff821f3f99..1d9a0f6effa1654609f4d0752ec69eed LevelData worlddata = this.level.getLevelData(); ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -@@ -916,15 +947,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -770,15 +801,7 @@ public class ServerChunkCache extends ChunkSource { boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit Collections.shuffle(list); @@ -344,7 +326,7 @@ index 42b4214a1319691e9a6cb0c5fafaeeff821f3f99..1d9a0f6effa1654609f4d0752ec69eed Iterator iterator1 = list.iterator(); while (iterator1.hasNext()) { -@@ -932,9 +955,9 @@ public class ServerChunkCache extends ChunkSource { +@@ -786,9 +809,9 @@ public class ServerChunkCache extends ChunkSource { LevelChunk chunk1 = chunkproviderserver_a.chunk; ChunkPos chunkcoordintpair = chunk1.getPos(); @@ -357,10 +339,10 @@ index 42b4214a1319691e9a6cb0c5fafaeeff821f3f99..1d9a0f6effa1654609f4d0752ec69eed } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index acc64abd9420b81ed4c8c17cf6a9f5bc5d35f116..06e711aa9a0afedda48395ba2ee369bb211584da 100644 +index 971f72c1dd713077c128279a78ed37f15aedeff6..29a03760f092a004a47e75120841d80e696b6c3d 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -262,6 +262,7 @@ public class ServerPlayer extends Player { +@@ -263,6 +263,7 @@ public class ServerPlayer extends Player { // CraftBukkit end public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper diff --git a/patches/server/0424-Use-distance-map-to-optimise-entity-tracker.patch b/patches/server/0429-Use-distance-map-to-optimise-entity-tracker.patch similarity index 96% rename from patches/server/0424-Use-distance-map-to-optimise-entity-tracker.patch rename to patches/server/0429-Use-distance-map-to-optimise-entity-tracker.patch index a1f1dae611..6b7c2e2afd 100644 --- a/patches/server/0424-Use-distance-map-to-optimise-entity-tracker.patch +++ b/patches/server/0429-Use-distance-map-to-optimise-entity-tracker.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Use distance map to optimise entity tracker Use the distance map to find candidate players for tracking. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a 100644 +index 43ad735f57ab513311d700b42d7d0f2f1e43d0e7..b0e0f85e04438affb8d8e0f75055ea83d0c03bcd 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -66,6 +66,7 @@ import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; @@ -17,7 +17,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.util.CsvOutput; -@@ -193,10 +194,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -207,10 +208,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap; // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning @@ -53,7 +53,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 // Note: players need to be explicitly added to distance maps before they can be updated this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Paper start - per player mob spawning -@@ -208,6 +234,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -222,6 +248,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider void removePlayerFromDistanceMaps(ServerPlayer player) { @@ -65,7 +65,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning this.playerMobSpawnMap.remove(player); this.playerChunkTickRangeMap.remove(player); -@@ -223,6 +254,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -237,6 +268,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int chunkX = MCUtil.getChunkCoordinate(player.getX()); int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated @@ -80,7 +80,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { -@@ -317,6 +356,45 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -340,6 +379,45 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.regionManagers.add(this.dataRegionManager); // Paper end this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper @@ -126,7 +126,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -@@ -1589,17 +1667,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1696,17 +1774,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public void move(ServerPlayer player) { @@ -145,7 +145,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 int i = SectionPos.blockToSectionCoord(player.getBlockX()); int j = SectionPos.blockToSectionCoord(player.getBlockZ()); -@@ -1726,7 +1794,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1833,7 +1901,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); @@ -154,7 +154,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -1770,7 +1838,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1877,7 +1945,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider entity.tracker = null; // Paper - We're no longer tracked } @@ -192,7 +192,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 List list = Lists.newArrayList(); List list1 = this.level.players(); ObjectIterator objectiterator = this.entityMap.values().iterator(); -@@ -1846,23 +1944,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1953,23 +2051,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider DebugPackets.sendPoiPacketsForChunk(this.level, chunk.getPos()); List list = Lists.newArrayList(); List list1 = Lists.newArrayList(); @@ -236,7 +236,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 Iterator iterator; Entity entity1; -@@ -1938,6 +2044,42 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -2045,6 +2151,42 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.lastSectionPos = SectionPos.of((EntityAccess) entity); } @@ -280,7 +280,7 @@ index 6e27a89af794d411cce3c1c932c1f4910cec889c..6188f35e2b5300b6ff4a16e4d6e0e4a8 return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false; } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 70978ba28cec4dd3e64bf380c0669b3bcf4a640b..0f85956d4d1c98225ff7cff7abad217a124f0dfc 100644 +index 74e13ae8b1e6a9365d46f5684ee58e42658d2341..0a0fb24cd12d77e0c29eb6e0a20eacfc04330bf3 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -57,6 +57,7 @@ import net.minecraft.network.syncher.EntityDataSerializers; diff --git a/patches/server/0425-Optimize-ServerLevels-chunk-level-checking-methods.patch b/patches/server/0430-Optimize-ServerLevels-chunk-level-checking-methods.patch similarity index 91% rename from patches/server/0425-Optimize-ServerLevels-chunk-level-checking-methods.patch rename to patches/server/0430-Optimize-ServerLevels-chunk-level-checking-methods.patch index 5e016b22d6..2bcf0781f9 100644 --- a/patches/server/0425-Optimize-ServerLevels-chunk-level-checking-methods.patch +++ b/patches/server/0430-Optimize-ServerLevels-chunk-level-checking-methods.patch @@ -8,10 +8,10 @@ so inline where possible, and avoid the abstraction of the Either class. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a7db54a94a5017e737ce9682a52eed7405af8cc1..22a0ca38ae03b8064db7f77dd17335ed4abc72bc 100644 +index a778b4b5b2413c25c2f0f0efc72ba1d362d89acf..c9ecc7593c299b351308634db44596a76fd0c09b 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2253,19 +2253,22 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2255,19 +2255,22 @@ public class ServerLevel extends Level implements WorldGenLevel { } private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) { @@ -52,10 +52,10 @@ index 2d41f619577b41d6420159668bbab70fb6c762eb..ed0b136e99def41d4377f2004477826b public static int getX(long pos) { 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 6e3d02fb68741fc3cf7d74ec659a37e5a1ecac5c..e53e912351a0753c429512f018281a656837bde2 100644 +index 16519a6414f6f6418de40b714555a52631980617..a5dc8e715c86c1e70a9cf3d99c9cd457a6666b70 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -383,6 +383,11 @@ public class PersistentEntitySectionManager implements A +@@ -395,6 +395,11 @@ public class PersistentEntitySectionManager implements A public LevelEntityGetter getEntityGetter() { return this.entityGetter; } diff --git a/patches/server/0427-Fix-villager-trading-demand-MC-163962.patch b/patches/server/0431-Fix-villager-trading-demand-MC-163962.patch similarity index 100% rename from patches/server/0427-Fix-villager-trading-demand-MC-163962.patch rename to patches/server/0431-Fix-villager-trading-demand-MC-163962.patch diff --git a/patches/server/0428-Maps-shouldn-t-load-chunks.patch b/patches/server/0432-Maps-shouldn-t-load-chunks.patch similarity index 100% rename from patches/server/0428-Maps-shouldn-t-load-chunks.patch rename to patches/server/0432-Maps-shouldn-t-load-chunks.patch diff --git a/patches/server/0429-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch b/patches/server/0433-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch similarity index 100% rename from patches/server/0429-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch rename to patches/server/0433-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch diff --git a/patches/server/0430-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch b/patches/server/0434-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch similarity index 100% rename from patches/server/0430-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch rename to patches/server/0434-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch diff --git a/patches/server/0431-Fix-piston-physics-inconsistency-MC-188840.patch b/patches/server/0435-Fix-piston-physics-inconsistency-MC-188840.patch similarity index 100% rename from patches/server/0431-Fix-piston-physics-inconsistency-MC-188840.patch rename to patches/server/0435-Fix-piston-physics-inconsistency-MC-188840.patch diff --git a/patches/server/0432-Fix-sand-duping.patch b/patches/server/0436-Fix-sand-duping.patch similarity index 100% rename from patches/server/0432-Fix-sand-duping.patch rename to patches/server/0436-Fix-sand-duping.patch diff --git a/patches/server/0433-Fix-missing-chunks-due-to-integer-overflow.patch b/patches/server/0437-Fix-missing-chunks-due-to-integer-overflow.patch similarity index 100% rename from patches/server/0433-Fix-missing-chunks-due-to-integer-overflow.patch rename to patches/server/0437-Fix-missing-chunks-due-to-integer-overflow.patch diff --git a/patches/server/0434-Prevent-position-desync-in-playerconnection-causing-.patch b/patches/server/0438-Prevent-position-desync-in-playerconnection-causing-.patch similarity index 100% rename from patches/server/0434-Prevent-position-desync-in-playerconnection-causing-.patch rename to patches/server/0438-Prevent-position-desync-in-playerconnection-causing-.patch diff --git a/patches/server/0435-Inventory-getHolder-method-without-block-snapshot.patch b/patches/server/0439-Inventory-getHolder-method-without-block-snapshot.patch similarity index 100% rename from patches/server/0435-Inventory-getHolder-method-without-block-snapshot.patch rename to patches/server/0439-Inventory-getHolder-method-without-block-snapshot.patch diff --git a/patches/server/0436-Improve-Arrow-API.patch b/patches/server/0440-Improve-Arrow-API.patch similarity index 100% rename from patches/server/0436-Improve-Arrow-API.patch rename to patches/server/0440-Improve-Arrow-API.patch diff --git a/patches/server/0437-Add-and-implement-PlayerRecipeBookClickEvent.patch b/patches/server/0441-Add-and-implement-PlayerRecipeBookClickEvent.patch similarity index 100% rename from patches/server/0437-Add-and-implement-PlayerRecipeBookClickEvent.patch rename to patches/server/0441-Add-and-implement-PlayerRecipeBookClickEvent.patch diff --git a/patches/server/0438-Hide-sync-chunk-writes-behind-flag.patch b/patches/server/0442-Hide-sync-chunk-writes-behind-flag.patch similarity index 100% rename from patches/server/0438-Hide-sync-chunk-writes-behind-flag.patch rename to patches/server/0442-Hide-sync-chunk-writes-behind-flag.patch diff --git a/patches/server/0439-Add-permission-for-command-blocks.patch b/patches/server/0443-Add-permission-for-command-blocks.patch similarity index 100% rename from patches/server/0439-Add-permission-for-command-blocks.patch rename to patches/server/0443-Add-permission-for-command-blocks.patch diff --git a/patches/server/0440-Ensure-Entity-AABB-s-are-never-invalid.patch b/patches/server/0444-Ensure-Entity-AABB-s-are-never-invalid.patch similarity index 95% rename from patches/server/0440-Ensure-Entity-AABB-s-are-never-invalid.patch rename to patches/server/0444-Ensure-Entity-AABB-s-are-never-invalid.patch index b5cd289e5a..756a326a3a 100644 --- a/patches/server/0440-Ensure-Entity-AABB-s-are-never-invalid.patch +++ b/patches/server/0444-Ensure-Entity-AABB-s-are-never-invalid.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Ensure Entity AABB's are never invalid diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0f85956d4d1c98225ff7cff7abad217a124f0dfc..258aa2ee24742d48be08940f147e1d998e667fb8 100644 +index 0a0fb24cd12d77e0c29eb6e0a20eacfc04330bf3..7e36e53d44b5efbd6498caecb717bec1dcbec96d 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -662,8 +662,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0441-Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/0445-Fix-Per-World-Difficulty-Remembering-Difficulty.patch similarity index 98% rename from patches/server/0441-Fix-Per-World-Difficulty-Remembering-Difficulty.patch rename to patches/server/0445-Fix-Per-World-Difficulty-Remembering-Difficulty.patch index 0bf7d5bc7e..0f8476767c 100644 --- a/patches/server/0441-Fix-Per-World-Difficulty-Remembering-Difficulty.patch +++ b/patches/server/0445-Fix-Per-World-Difficulty-Remembering-Difficulty.patch @@ -76,10 +76,10 @@ index e42df2956e2d852a5a4c8fdeda395a3efd32c44c..da83f111199a6b4c712a9bb8ab6f1d1b @Override diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 06e711aa9a0afedda48395ba2ee369bb211584da..28944fc50ea43a3ea40bd1e69c560c8fe022337e 100644 +index 29a03760f092a004a47e75120841d80e696b6c3d..be7d2275548936beade4aba02dc5b14fec95117a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1128,7 +1128,7 @@ public class ServerPlayer extends Player { +@@ -1144,7 +1144,7 @@ public class ServerPlayer extends Player { this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds this.connection.send(new ClientboundRespawnPacket(worldserver.dimensionTypeId(), worldserver.dimension(), BiomeManager.obfuscateSeed(worldserver.getSeed()), this.gameMode.getGameModeForPlayer(), this.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), true, this.getLastDeathLocation())); diff --git a/patches/server/0442-Paper-dumpitem-command.patch b/patches/server/0446-Paper-dumpitem-command.patch similarity index 100% rename from patches/server/0442-Paper-dumpitem-command.patch rename to patches/server/0446-Paper-dumpitem-command.patch diff --git a/patches/server/0443-Don-t-allow-null-UUID-s-for-chat.patch b/patches/server/0447-Don-t-allow-null-UUID-s-for-chat.patch similarity index 100% rename from patches/server/0443-Don-t-allow-null-UUID-s-for-chat.patch rename to patches/server/0447-Don-t-allow-null-UUID-s-for-chat.patch diff --git a/patches/server/0444-Improve-Legacy-Component-serialization-size.patch b/patches/server/0448-Improve-Legacy-Component-serialization-size.patch similarity index 100% rename from patches/server/0444-Improve-Legacy-Component-serialization-size.patch rename to patches/server/0448-Improve-Legacy-Component-serialization-size.patch diff --git a/patches/server/0445-Optimize-Bit-Operations-by-inlining.patch b/patches/server/0449-Optimize-Bit-Operations-by-inlining.patch similarity index 100% rename from patches/server/0445-Optimize-Bit-Operations-by-inlining.patch rename to patches/server/0449-Optimize-Bit-Operations-by-inlining.patch diff --git a/patches/server/0446-Add-Plugin-Tickets-to-API-Chunk-Methods.patch b/patches/server/0450-Add-Plugin-Tickets-to-API-Chunk-Methods.patch similarity index 84% rename from patches/server/0446-Add-Plugin-Tickets-to-API-Chunk-Methods.patch rename to patches/server/0450-Add-Plugin-Tickets-to-API-Chunk-Methods.patch index 31dc8e2524..506018715e 100644 --- a/patches/server/0446-Add-Plugin-Tickets-to-API-Chunk-Methods.patch +++ b/patches/server/0450-Add-Plugin-Tickets-to-API-Chunk-Methods.patch @@ -22,7 +22,7 @@ wants it to collect even faster, they can restore that setting back to 1 instead Not adding it to .getType() though to keep behavior consistent with vanilla for performance reasons. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 979d0116e72417eec26193cd1e106dc9d27cdbe0..c7a6143ebb2ed0a0977e1d38c8adcccf09800638 100644 +index 99a9bf12f2e3e6ac5457da53f6f12118efce5d82..58f361ad664ba45c496ab0817c7ab5e1a017b807 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -360,7 +360,7 @@ public final class CraftServer implements Server { @@ -44,10 +44,10 @@ index 979d0116e72417eec26193cd1e106dc9d27cdbe0..c7a6143ebb2ed0a0977e1d38c8adcccf this.printSaveWarning = false; console.autosavePeriod = this.configuration.getInt("ticks-per.autosave"); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 21927118d1762302dc560b385fd3a4322840031f..b234ba968e82ddf1e8f7c84d3a17659e3beda2b3 100644 +index a8ab324bfbaaf946af5998402588244465dd7286..710270775cd47e8df1146ad0636648568d45ac75 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -283,8 +283,21 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -282,8 +282,21 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public Chunk getChunkAt(int x, int z) { @@ -70,7 +70,7 @@ index 21927118d1762302dc560b385fd3a4322840031f..b234ba968e82ddf1e8f7c84d3a17659e @Override public Chunk getChunkAt(Block block) { -@@ -351,7 +364,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -350,7 +363,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { public boolean unloadChunkRequest(int x, int z) { org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot if (this.isChunkLoaded(x, z)) { @@ -79,7 +79,7 @@ index 21927118d1762302dc560b385fd3a4322840031f..b234ba968e82ddf1e8f7c84d3a17659e } return true; -@@ -434,9 +447,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -433,9 +446,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot // Paper start - Optimize this method ChunkPos chunkPos = new ChunkPos(x, z); @@ -93,7 +93,7 @@ index 21927118d1762302dc560b385fd3a4322840031f..b234ba968e82ddf1e8f7c84d3a17659e if (immediate == null) { immediate = world.getChunkSource().chunkMap.getUnloadingChunk(x, z); } -@@ -444,7 +460,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -443,7 +459,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { if (!(immediate instanceof ImposterProtoChunk) && !(immediate instanceof net.minecraft.world.level.chunk.LevelChunk)) { return false; // not full status } @@ -102,7 +102,7 @@ index 21927118d1762302dc560b385fd3a4322840031f..b234ba968e82ddf1e8f7c84d3a17659e world.getChunk(x, z); // make sure we're at ticket level 32 or lower return true; } -@@ -470,7 +486,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -469,7 +485,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { // we do this so we do not re-read the chunk data on disk } @@ -111,11 +111,11 @@ index 21927118d1762302dc560b385fd3a4322840031f..b234ba968e82ddf1e8f7c84d3a17659e world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true); return true; // Paper end -@@ -2063,6 +2079,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - return this.world.getChunkSource().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> { - net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null); -+ if (chunk != null) addTicket(x, z); // Paper - return java.util.concurrent.CompletableFuture.completedFuture(chunk == null ? null : chunk.getBukkitChunk()); - }, net.minecraft.server.MinecraftServer.getServer()); - } +@@ -2150,6 +2166,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { + net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { + net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c; ++ if (chunk != null) addTicket(x, z); // Paper + ret.complete(chunk == null ? null : chunk.getBukkitChunk()); + }); + }); diff --git a/patches/server/0447-incremental-chunk-and-player-saving.patch b/patches/server/0451-incremental-chunk-and-player-saving.patch similarity index 90% rename from patches/server/0447-incremental-chunk-and-player-saving.patch rename to patches/server/0451-incremental-chunk-and-player-saving.patch index cb5d5e6826..e993eebc44 100644 --- a/patches/server/0447-incremental-chunk-and-player-saving.patch +++ b/patches/server/0451-incremental-chunk-and-player-saving.patch @@ -53,19 +53,19 @@ index 7d2fee97f4d08eae245475c4b60c1a7ba46c840d..48650bc1c09b18f1b57d9828dfe27f51 // Paper start - move executeAll() into full server tick timing try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) { diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 4e8a79f2d3b6f52c6284bc9b0ce2423dc43a154f..36a9d52d9af3bc398010c52dc16ab23e53f2702a 100644 +index 0f75a109c06eb3113be74cf49ec560f5e2ea9cfc..ac42029596ae0c824bf33a4058ac1009740e29ea 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -92,6 +92,8 @@ public class ChunkHolder { - this.playersInChunkTickRange = null; - } +@@ -99,6 +99,8 @@ public class ChunkHolder { + com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playersInMobSpawnRange; + com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playersInChunkTickRange; // Paper end - optimise anyPlayerCloseEnoughForSpawning + long lastAutoSaveTime; // Paper - incremental autosave + long inactiveTimeStart; // Paper - incremental autosave public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size()); -@@ -502,7 +504,19 @@ public class ChunkHolder { +@@ -527,7 +529,19 @@ public class ChunkHolder { boolean flag2 = playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER); boolean flag3 = playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER); @@ -85,7 +85,7 @@ index 4e8a79f2d3b6f52c6284bc9b0ce2423dc43a154f..36a9d52d9af3bc398010c52dc16ab23e if (!flag2 && flag3) { int expectCreateCount = ++this.fullChunkCreateCount; // Paper this.fullChunkFuture = chunkStorage.prepareAccessibleChunk(this); -@@ -633,9 +647,33 @@ public class ChunkHolder { +@@ -689,8 +703,32 @@ public class ChunkHolder { } public void refreshAccessibility() { @@ -107,20 +107,19 @@ index 4e8a79f2d3b6f52c6284bc9b0ce2423dc43a154f..36a9d52d9af3bc398010c52dc16ab23e + } + } + // Paper end - } - ++ } ++ + // Paper start - incremental autosave + public boolean setHasBeenLoaded() { + this.wasAccessibleSinceLastSave = getFullChunkStatus(this.ticketLevel).isOrAfter(ChunkHolder.FullChunkStatus.BORDER); + return this.wasAccessibleSinceLastSave; -+ } + } + // Paper end -+ + public void replaceProtoChunk(ImposterProtoChunk chunk) { for (int i = 0; i < this.futures.length(); ++i) { - CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a..4d74eb7883c72fb42275fc5358917244bb36181d 100644 +index b0e0f85e04438affb8d8e0f75055ea83d0c03bcd..7493da0f1c3f8ab0ebc517347ef23fbe2747a306 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -103,6 +103,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp @@ -131,7 +130,7 @@ index 6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a..4d74eb7883c72fb42275fc5358917244 import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableObject; import org.slf4j.Logger; -@@ -712,6 +713,64 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -779,6 +780,64 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -194,13 +193,13 @@ index 6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a..4d74eb7883c72fb42275fc5358917244 + // Paper end + protected void saveAllChunks(boolean flush) { - if (flush) { - List list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); -@@ -796,13 +855,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper start - do not overload I/O threads with too much work when saving + int[] saved = new int[1]; +@@ -874,13 +933,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } int l = 0; -- ObjectIterator objectiterator = this.visibleChunkMap.values().iterator(); +- Iterator objectiterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper - - while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { - if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { @@ -211,7 +210,7 @@ index 6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a..4d74eb7883c72fb42275fc5358917244 } -@@ -840,6 +893,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -916,6 +969,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.level.unload(chunk); } @@ -219,7 +218,7 @@ index 6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a..4d74eb7883c72fb42275fc5358917244 this.lightEngine.updateChunkStatus(ichunkaccess.getPos()); this.lightEngine.tryScheduleUpdate(); -@@ -1260,6 +1314,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1367,6 +1421,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider asyncSaveData, chunk); chunk.setUnsaved(false); @@ -227,7 +226,7 @@ index 6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a..4d74eb7883c72fb42275fc5358917244 } // Paper end -@@ -1269,6 +1324,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1376,6 +1431,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (!chunk.isUnsaved()) { return false; } else { @@ -236,10 +235,10 @@ index 6188f35e2b5300b6ff4a16e4d6e0e4a846261f8a..4d74eb7883c72fb42275fc5358917244 ChunkPos chunkcoordintpair = chunk.getPos(); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 1d9a0f6effa1654609f4d0752ec69eed6ab7134b..585892f19bc0aea89889a358c0407f2975b9efe5 100644 +index 70c5e151d47217d417b91105ac63f17a2eb957bf..15b275ee91451478d1c55eae0d20e0e8f36f3a0f 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -814,6 +814,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -668,6 +668,15 @@ public class ServerChunkCache extends ChunkSource { } // Paper - Timings } @@ -256,10 +255,10 @@ index 1d9a0f6effa1654609f4d0752ec69eed6ab7134b..585892f19bc0aea89889a358c0407f29 public void close() throws IOException { // CraftBukkit start diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 22a0ca38ae03b8064db7f77dd17335ed4abc72bc..92603bc69e7782f252b2ad7b8c8a4546c9b23e12 100644 +index c9ecc7593c299b351308634db44596a76fd0c09b..8b5eac2ad96c0ebb6eae04585998cade578ff74b 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1085,6 +1085,37 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1087,6 +1087,37 @@ public class ServerLevel extends Level implements WorldGenLevel { return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos); } @@ -298,7 +297,7 @@ index 22a0ca38ae03b8064db7f77dd17335ed4abc72bc..92603bc69e7782f252b2ad7b8c8a4546 ServerChunkCache chunkproviderserver = this.getChunkSource(); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 28944fc50ea43a3ea40bd1e69c560c8fe022337e..0720b748ed42bbd2a12cc5de79224f609a5e29be 100644 +index be7d2275548936beade4aba02dc5b14fec95117a..6f2b52165c1935511790a429792d3754251537c8 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -179,6 +179,7 @@ import org.bukkit.inventory.MainHand; @@ -310,10 +309,10 @@ index 28944fc50ea43a3ea40bd1e69c560c8fe022337e..0720b748ed42bbd2a12cc5de79224f60 private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; public ServerGamePacketListenerImpl connection; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b1f6dc751c3dab5220a02223f6ba205aa0949f84..2ceddd78fb3b69eff60b5cd2b1f42c641f6ecd70 100644 +index 32ab0cd6cb42b0ab8a14f790dfcf4b155c945d6d..1850ce4566e6c5d19140cbf2636b3573f16c4239 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -571,6 +571,7 @@ public abstract class PlayerList { +@@ -569,6 +569,7 @@ public abstract class PlayerList { protected void save(ServerPlayer player) { if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit if (!player.didPlayerJoinEvent) return; // Paper - If we never fired PJE, we disconnected during login. Data has not changed, and additionally, our saved vehicle is not loaded! If we save now, we will lose our vehicle (CraftBukkit bug) @@ -321,7 +320,7 @@ index b1f6dc751c3dab5220a02223f6ba205aa0949f84..2ceddd78fb3b69eff60b5cd2b1f42c64 this.playerIo.save(player); ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit -@@ -1173,10 +1174,22 @@ public abstract class PlayerList { +@@ -1171,10 +1172,22 @@ public abstract class PlayerList { } public void saveAll() { @@ -358,7 +357,7 @@ index dc164608bfb2fb18a1adf83fa10bac4028dcac0a..a97909e77b9b28aede8c8716831c3f9a public static record TicksToSave(SerializableTickContainer blocks, SerializableTickContainer fluids) { 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 291bcca206722c86bca6d13058d18c413c38d256..f8a3048fa80758d82f2e92d48bd3cd2c585ae6c2 100644 +index c8444f4bfd127b7d8194aaa984505eff249ae094..2981ba61e347b8660082ff946521fc7f219d2c0d 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -87,6 +87,12 @@ public class LevelChunk extends ChunkAccess { diff --git a/patches/server/0448-Stop-copy-on-write-operations-for-updating-light-dat.patch b/patches/server/0452-Stop-copy-on-write-operations-for-updating-light-dat.patch similarity index 100% rename from patches/server/0448-Stop-copy-on-write-operations-for-updating-light-dat.patch rename to patches/server/0452-Stop-copy-on-write-operations-for-updating-light-dat.patch diff --git a/patches/server/0449-Support-old-UUID-format-for-NBT.patch b/patches/server/0453-Support-old-UUID-format-for-NBT.patch similarity index 100% rename from patches/server/0449-Support-old-UUID-format-for-NBT.patch rename to patches/server/0453-Support-old-UUID-format-for-NBT.patch diff --git a/patches/server/0450-Clean-up-duplicated-GameProfile-Properties.patch b/patches/server/0454-Clean-up-duplicated-GameProfile-Properties.patch similarity index 100% rename from patches/server/0450-Clean-up-duplicated-GameProfile-Properties.patch rename to patches/server/0454-Clean-up-duplicated-GameProfile-Properties.patch diff --git a/patches/server/0451-Convert-legacy-attributes-in-Item-Meta.patch b/patches/server/0455-Convert-legacy-attributes-in-Item-Meta.patch similarity index 100% rename from patches/server/0451-Convert-legacy-attributes-in-Item-Meta.patch rename to patches/server/0455-Convert-legacy-attributes-in-Item-Meta.patch diff --git a/patches/server/0452-Remove-some-streams-from-structures.patch b/patches/server/0456-Remove-some-streams-from-structures.patch similarity index 100% rename from patches/server/0452-Remove-some-streams-from-structures.patch rename to patches/server/0456-Remove-some-streams-from-structures.patch diff --git a/patches/server/0453-Remove-streams-from-classes-related-villager-gossip.patch b/patches/server/0457-Remove-streams-from-classes-related-villager-gossip.patch similarity index 100% rename from patches/server/0453-Remove-streams-from-classes-related-villager-gossip.patch rename to patches/server/0457-Remove-streams-from-classes-related-villager-gossip.patch diff --git a/patches/server/0454-Support-components-in-ItemMeta.patch b/patches/server/0458-Support-components-in-ItemMeta.patch similarity index 100% rename from patches/server/0454-Support-components-in-ItemMeta.patch rename to patches/server/0458-Support-components-in-ItemMeta.patch diff --git a/patches/server/0455-Improve-EntityTargetLivingEntityEvent-for-1.16-mobs.patch b/patches/server/0459-Improve-EntityTargetLivingEntityEvent-for-1.16-mobs.patch similarity index 100% rename from patches/server/0455-Improve-EntityTargetLivingEntityEvent-for-1.16-mobs.patch rename to patches/server/0459-Improve-EntityTargetLivingEntityEvent-for-1.16-mobs.patch diff --git a/patches/server/0456-Add-entity-liquid-API.patch b/patches/server/0460-Add-entity-liquid-API.patch similarity index 93% rename from patches/server/0456-Add-entity-liquid-API.patch rename to patches/server/0460-Add-entity-liquid-API.patch index 91b94fb4dc..0f1072e587 100644 --- a/patches/server/0456-Add-entity-liquid-API.patch +++ b/patches/server/0460-Add-entity-liquid-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add entity liquid API diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 6029cb7d8801c471e596ba027b7e408a27c44db9..c0a2cffadb762240ef8fcdec1bd1e49edd3b5c61 100644 +index cd958bc3c00f53ebaf9b3ae39564d3abb6c819a1..863cd2c84dd207f984ddad977e9fd23860247c68 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -1254,5 +1254,29 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { diff --git a/patches/server/0457-Update-itemstack-legacy-name-and-lore.patch b/patches/server/0461-Update-itemstack-legacy-name-and-lore.patch similarity index 100% rename from patches/server/0457-Update-itemstack-legacy-name-and-lore.patch rename to patches/server/0461-Update-itemstack-legacy-name-and-lore.patch diff --git a/patches/server/0458-Spawn-player-in-correct-world-on-login.patch b/patches/server/0462-Spawn-player-in-correct-world-on-login.patch similarity index 91% rename from patches/server/0458-Spawn-player-in-correct-world-on-login.patch rename to patches/server/0462-Spawn-player-in-correct-world-on-login.patch index cbcca8f896..a59a3e8562 100644 --- a/patches/server/0458-Spawn-player-in-correct-world-on-login.patch +++ b/patches/server/0462-Spawn-player-in-correct-world-on-login.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Spawn player in correct world on login diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 20bedb5ce597b8e3e96af910d88137e0a0b10066..559db90e1ba3d636ea080f47cdf274d11a1bcb89 100644 +index 1850ce4566e6c5d19140cbf2636b3573f16c4239..1cb6900489ad25ddd40a3b8c39f436c03a72b3dc 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -200,7 +200,18 @@ public abstract class PlayerList { +@@ -203,7 +203,18 @@ public abstract class PlayerList { }String lastKnownName = s; // Paper // CraftBukkit end diff --git a/patches/server/0459-Add-PrepareResultEvent.patch b/patches/server/0463-Add-PrepareResultEvent.patch similarity index 100% rename from patches/server/0459-Add-PrepareResultEvent.patch rename to patches/server/0463-Add-PrepareResultEvent.patch diff --git a/patches/server/0460-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch b/patches/server/0464-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch similarity index 100% rename from patches/server/0460-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch rename to patches/server/0464-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch diff --git a/patches/server/0462-Optimize-NetworkManager-Exception-Handling.patch b/patches/server/0465-Optimize-NetworkManager-Exception-Handling.patch similarity index 100% rename from patches/server/0462-Optimize-NetworkManager-Exception-Handling.patch rename to patches/server/0465-Optimize-NetworkManager-Exception-Handling.patch diff --git a/patches/server/0463-Optimize-the-advancement-data-player-iteration-to-be.patch b/patches/server/0466-Optimize-the-advancement-data-player-iteration-to-be.patch similarity index 100% rename from patches/server/0463-Optimize-the-advancement-data-player-iteration-to-be.patch rename to patches/server/0466-Optimize-the-advancement-data-player-iteration-to-be.patch diff --git a/patches/server/0464-Fix-arrows-never-despawning-MC-125757.patch b/patches/server/0467-Fix-arrows-never-despawning-MC-125757.patch similarity index 100% rename from patches/server/0464-Fix-arrows-never-despawning-MC-125757.patch rename to patches/server/0467-Fix-arrows-never-despawning-MC-125757.patch diff --git a/patches/server/0465-Thread-Safe-Vanilla-Command-permission-checking.patch b/patches/server/0468-Thread-Safe-Vanilla-Command-permission-checking.patch similarity index 100% rename from patches/server/0465-Thread-Safe-Vanilla-Command-permission-checking.patch rename to patches/server/0468-Thread-Safe-Vanilla-Command-permission-checking.patch diff --git a/patches/server/0466-Fix-SPIGOT-5989.patch b/patches/server/0469-Fix-SPIGOT-5989.patch similarity index 90% rename from patches/server/0466-Fix-SPIGOT-5989.patch rename to patches/server/0469-Fix-SPIGOT-5989.patch index 9d1324f0e2..111dc3b220 100644 --- a/patches/server/0466-Fix-SPIGOT-5989.patch +++ b/patches/server/0469-Fix-SPIGOT-5989.patch @@ -10,10 +10,10 @@ This fixes that by checking if the modified spawn location is still at a respawn anchor. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 2700a1337e08727078e52b90b477ff7291c8af8d..0cbfbd9f274974674970def11e5d76ba9e663e16 100644 +index 1cb6900489ad25ddd40a3b8c39f436c03a72b3dc..8fd4494fcd29e92856938792b922ee3ef0102604 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -845,6 +845,7 @@ public abstract class PlayerList { +@@ -842,6 +842,7 @@ public abstract class PlayerList { // Paper start boolean isBedSpawn = false; boolean isRespawn = false; @@ -21,7 +21,7 @@ index 2700a1337e08727078e52b90b477ff7291c8af8d..0cbfbd9f274974674970def11e5d76ba // Paper end // CraftBukkit start - fire PlayerRespawnEvent -@@ -855,7 +856,7 @@ public abstract class PlayerList { +@@ -852,7 +853,7 @@ public abstract class PlayerList { Optional optional; if (blockposition != null) { @@ -30,7 +30,7 @@ index 2700a1337e08727078e52b90b477ff7291c8af8d..0cbfbd9f274974674970def11e5d76ba } else { optional = Optional.empty(); } -@@ -899,7 +900,12 @@ public abstract class PlayerList { +@@ -896,7 +897,12 @@ public abstract class PlayerList { } // Spigot End @@ -44,7 +44,7 @@ index 2700a1337e08727078e52b90b477ff7291c8af8d..0cbfbd9f274974674970def11e5d76ba if (!flag) entityplayer.reset(); // SPIGOT-4785 isRespawn = true; // Paper } else { -@@ -937,8 +943,12 @@ public abstract class PlayerList { +@@ -934,8 +940,12 @@ public abstract class PlayerList { } // entityplayer1.initInventoryMenu(); entityplayer1.setHealth(entityplayer1.getHealth()); diff --git a/patches/server/0467-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch b/patches/server/0470-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch similarity index 100% rename from patches/server/0467-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch rename to patches/server/0470-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch diff --git a/patches/server/0468-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch b/patches/server/0471-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch similarity index 100% rename from patches/server/0468-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch rename to patches/server/0471-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch diff --git a/patches/server/0469-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch b/patches/server/0472-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch similarity index 100% rename from patches/server/0469-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch rename to patches/server/0472-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch diff --git a/patches/server/0470-Add-missing-strikeLighting-call-to-World-spigot-stri.patch b/patches/server/0473-Add-missing-strikeLighting-call-to-World-spigot-stri.patch similarity index 83% rename from patches/server/0470-Add-missing-strikeLighting-call-to-World-spigot-stri.patch rename to patches/server/0473-Add-missing-strikeLighting-call-to-World-spigot-stri.patch index 2fc1e0bde7..4c6955f7fd 100644 --- a/patches/server/0470-Add-missing-strikeLighting-call-to-World-spigot-stri.patch +++ b/patches/server/0473-Add-missing-strikeLighting-call-to-World-spigot-stri.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Add missing strikeLighting call to diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index af22fa8aa8ddef4d592564b14d0114cc6f903fca..566636192c8c5858999c80c31b068aeb5bace1e6 100644 +index 710270775cd47e8df1146ad0636648568d45ac75..04896192121039ef6a3be103d59a9d687d7f6c05 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2172,6 +2172,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2136,6 +2136,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { lightning.moveTo( loc.getX(), loc.getY(), loc.getZ() ); lightning.visualOnly = true; lightning.isSilent = isSilent; diff --git a/patches/server/0471-Fix-some-rails-connecting-improperly.patch b/patches/server/0474-Fix-some-rails-connecting-improperly.patch similarity index 100% rename from patches/server/0471-Fix-some-rails-connecting-improperly.patch rename to patches/server/0474-Fix-some-rails-connecting-improperly.patch diff --git a/patches/server/0472-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch b/patches/server/0475-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch similarity index 100% rename from patches/server/0472-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch rename to patches/server/0475-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch diff --git a/patches/server/0473-Do-not-let-the-server-load-chunks-from-newer-version.patch b/patches/server/0476-Do-not-let-the-server-load-chunks-from-newer-version.patch similarity index 100% rename from patches/server/0473-Do-not-let-the-server-load-chunks-from-newer-version.patch rename to patches/server/0476-Do-not-let-the-server-load-chunks-from-newer-version.patch diff --git a/patches/server/0474-Brand-support.patch b/patches/server/0477-Brand-support.patch similarity index 96% rename from patches/server/0474-Brand-support.patch rename to patches/server/0477-Brand-support.patch index 5cfc2a82a7..1a2c0f5d4b 100644 --- a/patches/server/0474-Brand-support.patch +++ b/patches/server/0477-Brand-support.patch @@ -56,10 +56,10 @@ index 487003209da9fce5c365be041a7b9643404bce8e..ecd3d2cb0a4da4360c420f8c733a5898 return (!this.player.joining && !this.connection.isConnected()) || this.processedDisconnect; // Paper } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 8db930d54ad97435e367aa670466d8a072ca0b23..1ab74f26cf47372b89b74a077fe06e48f08581a7 100644 +index 0fda8c27c717bd030b826c5c7267b880f9d1f6b9..10e1be2349df779b911848f70e4b8f0e351b1de7 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2691,6 +2691,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2681,6 +2681,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { // Paper end }; diff --git a/patches/server/0475-Add-setMaxPlayers-API.patch b/patches/server/0478-Add-setMaxPlayers-API.patch similarity index 89% rename from patches/server/0475-Add-setMaxPlayers-API.patch rename to patches/server/0478-Add-setMaxPlayers-API.patch index d0c4c40d25..0efd813c6f 100644 --- a/patches/server/0475-Add-setMaxPlayers-API.patch +++ b/patches/server/0478-Add-setMaxPlayers-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add #setMaxPlayers API diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 8c1b6aa3957a988656eeb2ad6323fdbd2f67cd19..67c50a329e7bdf4056a1217963e29e8ceb99b20f 100644 +index 8fd4494fcd29e92856938792b922ee3ef0102604..ceb5e9540e54275e97f08533d16c820061e76c8f 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -147,7 +147,7 @@ public abstract class PlayerList { @@ -18,7 +18,7 @@ index 8c1b6aa3957a988656eeb2ad6323fdbd2f67cd19..67c50a329e7bdf4056a1217963e29e8c private int simulationDistance; private boolean allowCheatsForAllPlayers; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index c7a6143ebb2ed0a0977e1d38c8adcccf09800638..72e545e9aa01ad7ae4180d5421e16e330b4c9934 100644 +index 58f361ad664ba45c496ab0817c7ab5e1a017b807..f156620c14e28513fd0f825d5f34de5c5f831b75 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -674,6 +674,13 @@ public final class CraftServer implements Server { diff --git a/patches/server/0476-Add-playPickupItemAnimation-to-LivingEntity.patch b/patches/server/0479-Add-playPickupItemAnimation-to-LivingEntity.patch similarity index 100% rename from patches/server/0476-Add-playPickupItemAnimation-to-LivingEntity.patch rename to patches/server/0479-Add-playPickupItemAnimation-to-LivingEntity.patch diff --git a/patches/server/0477-Don-t-require-FACING-data.patch b/patches/server/0480-Don-t-require-FACING-data.patch similarity index 100% rename from patches/server/0477-Don-t-require-FACING-data.patch rename to patches/server/0480-Don-t-require-FACING-data.patch diff --git a/patches/server/0478-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch b/patches/server/0481-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch similarity index 87% rename from patches/server/0478-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch rename to patches/server/0481-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch index 2ee7bebf84..79f5aab58a 100644 --- a/patches/server/0478-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch +++ b/patches/server/0481-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix SpawnChangeEvent not firing for all use-cases diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 92603bc69e7782f252b2ad7b8c8a4546c9b23e12..0d51a518fa8b5d3ef5f6332c2b8f8796d62da658 100644 +index 8b5eac2ad96c0ebb6eae04585998cade578ff74b..2ba432f7be370ce1a5861e90de9541d76acdcfd2 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1853,6 +1853,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1855,6 +1855,7 @@ public class ServerLevel extends Level implements WorldGenLevel { //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c())); this.levelData.setSpawn(pos, angle); @@ -17,10 +17,10 @@ index 92603bc69e7782f252b2ad7b8c8a4546c9b23e12..0d51a518fa8b5d3ef5f6332c2b8f8796 // if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add this.removeTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange * 16, prevSpawn); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 566636192c8c5858999c80c31b068aeb5bace1e6..a04ae390f2d054b2ad9fb91eca04955471247b5a 100644 +index 04896192121039ef6a3be103d59a9d687d7f6c05..b95aed97b48bf31091ee2f44a21ad88071e97bf3 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -264,11 +264,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -263,11 +263,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { public boolean setSpawnLocation(int x, int y, int z, float angle) { try { Location previousLocation = this.getSpawnLocation(); diff --git a/patches/server/0479-Add-moon-phase-API.patch b/patches/server/0482-Add-moon-phase-API.patch similarity index 100% rename from patches/server/0479-Add-moon-phase-API.patch rename to patches/server/0482-Add-moon-phase-API.patch diff --git a/patches/server/0480-Improve-Chunk-Status-Transition-Speed.patch b/patches/server/0483-Improve-Chunk-Status-Transition-Speed.patch similarity index 91% rename from patches/server/0480-Improve-Chunk-Status-Transition-Speed.patch rename to patches/server/0483-Improve-Chunk-Status-Transition-Speed.patch index a4f7a9420d..352e70742e 100644 --- a/patches/server/0480-Improve-Chunk-Status-Transition-Speed.patch +++ b/patches/server/0483-Improve-Chunk-Status-Transition-Speed.patch @@ -36,10 +36,10 @@ scenario / path: Previously would have hopped to SERVER around 12+ times there extra. diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index ece4cd0de061969d4d2f07560e6cf38e631098b3..90f65fdcc4acf6762c67a5cb3023d2493f03144f 100644 +index ac42029596ae0c824bf33a4058ac1009740e29ea..a699107b1afea1c52e5a7e93af8f39ae9e1955b3 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -95,6 +95,13 @@ public class ChunkHolder { +@@ -101,6 +101,13 @@ public class ChunkHolder { // Paper end - optimise anyPlayerCloseEnoughForSpawning long lastAutoSaveTime; // Paper - incremental autosave long inactiveTimeStart; // Paper - incremental autosave @@ -54,10 +54,10 @@ index ece4cd0de061969d4d2f07560e6cf38e631098b3..90f65fdcc4acf6762c67a5cb3023d249 public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size()); diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 7b1781faed02a5b5fa37ca6f079d1fb620315c80..b659a058a0b6eb6b1827aacbd703e15fcbb1609c 100644 +index 7493da0f1c3f8ab0ebc517347ef23fbe2747a306..5a78ee69748b2b7b57a9adcff0a4718b1cc0c4ea 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -709,7 +709,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -726,7 +726,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return either.mapLeft((list) -> { return (LevelChunk) list.get(list.size() / 2); }); @@ -66,7 +66,7 @@ index 7b1781faed02a5b5fa37ca6f079d1fb620315c80..b659a058a0b6eb6b1827aacbd703e15f } @Nullable -@@ -1115,6 +1115,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1144,6 +1144,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return "chunkGenerate " + requiredStatus.getName(); }); Executor executor = (runnable) -> { diff --git a/patches/server/0481-Prevent-headless-pistons-from-being-created.patch b/patches/server/0484-Prevent-headless-pistons-from-being-created.patch similarity index 100% rename from patches/server/0481-Prevent-headless-pistons-from-being-created.patch rename to patches/server/0484-Prevent-headless-pistons-from-being-created.patch diff --git a/patches/server/0482-Add-BellRingEvent.patch b/patches/server/0485-Add-BellRingEvent.patch similarity index 100% rename from patches/server/0482-Add-BellRingEvent.patch rename to patches/server/0485-Add-BellRingEvent.patch diff --git a/patches/server/0483-Add-zombie-targets-turtle-egg-config.patch b/patches/server/0486-Add-zombie-targets-turtle-egg-config.patch similarity index 100% rename from patches/server/0483-Add-zombie-targets-turtle-egg-config.patch rename to patches/server/0486-Add-zombie-targets-turtle-egg-config.patch diff --git a/patches/server/0484-Buffer-joins-to-world.patch b/patches/server/0487-Buffer-joins-to-world.patch similarity index 100% rename from patches/server/0484-Buffer-joins-to-world.patch rename to patches/server/0487-Buffer-joins-to-world.patch diff --git a/patches/server/0485-Eigencraft-redstone-implementation.patch b/patches/server/0488-Eigencraft-redstone-implementation.patch similarity index 100% rename from patches/server/0485-Eigencraft-redstone-implementation.patch rename to patches/server/0488-Eigencraft-redstone-implementation.patch diff --git a/patches/server/0486-Fix-hex-colors-not-working-in-some-kick-messages.patch b/patches/server/0489-Fix-hex-colors-not-working-in-some-kick-messages.patch similarity index 100% rename from patches/server/0486-Fix-hex-colors-not-working-in-some-kick-messages.patch rename to patches/server/0489-Fix-hex-colors-not-working-in-some-kick-messages.patch diff --git a/patches/server/0487-PortalCreateEvent-needs-to-know-its-entity.patch b/patches/server/0490-PortalCreateEvent-needs-to-know-its-entity.patch similarity index 100% rename from patches/server/0487-PortalCreateEvent-needs-to-know-its-entity.patch rename to patches/server/0490-PortalCreateEvent-needs-to-know-its-entity.patch diff --git a/patches/server/0488-Fix-CraftTeam-null-check.patch b/patches/server/0491-Fix-CraftTeam-null-check.patch similarity index 100% rename from patches/server/0488-Fix-CraftTeam-null-check.patch rename to patches/server/0491-Fix-CraftTeam-null-check.patch diff --git a/patches/server/0489-Add-more-Evoker-API.patch b/patches/server/0492-Add-more-Evoker-API.patch similarity index 100% rename from patches/server/0489-Add-more-Evoker-API.patch rename to patches/server/0492-Add-more-Evoker-API.patch diff --git a/patches/server/0490-Add-methods-to-get-translation-keys.patch b/patches/server/0493-Add-methods-to-get-translation-keys.patch similarity index 100% rename from patches/server/0490-Add-methods-to-get-translation-keys.patch rename to patches/server/0493-Add-methods-to-get-translation-keys.patch diff --git a/patches/server/0491-Create-HoverEvent-from-ItemStack-Entity.patch b/patches/server/0494-Create-HoverEvent-from-ItemStack-Entity.patch similarity index 100% rename from patches/server/0491-Create-HoverEvent-from-ItemStack-Entity.patch rename to patches/server/0494-Create-HoverEvent-from-ItemStack-Entity.patch diff --git a/patches/server/0492-Cache-block-data-strings.patch b/patches/server/0495-Cache-block-data-strings.patch similarity index 100% rename from patches/server/0492-Cache-block-data-strings.patch rename to patches/server/0495-Cache-block-data-strings.patch diff --git a/patches/server/0493-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch b/patches/server/0496-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch similarity index 96% rename from patches/server/0493-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch rename to patches/server/0496-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch index efcb3aac9e..66b1d24e2d 100644 --- a/patches/server/0493-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch +++ b/patches/server/0496-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch @@ -69,10 +69,10 @@ index e3d8814cbad30da795632afddf8ebc87eff72106..ee619590aa49323059947fbaee9e88d6 if (entity instanceof Mob) { Mob entityinsentient = (Mob) entity; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index c0a2cffadb762240ef8fcdec1bd1e49edd3b5c61..148cd01c88600042c557f21558acace8bfdfa1cf 100644 +index 863cd2c84dd207f984ddad977e9fd23860247c68..ab270a14263d6a264bb74de3b924584ac41ed523 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -590,7 +590,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -559,7 +559,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } // entity.setLocation() throws no event, and so cannot be cancelled diff --git a/patches/server/0494-Add-additional-open-container-api-to-HumanEntity.patch b/patches/server/0497-Add-additional-open-container-api-to-HumanEntity.patch similarity index 100% rename from patches/server/0494-Add-additional-open-container-api-to-HumanEntity.patch rename to patches/server/0497-Add-additional-open-container-api-to-HumanEntity.patch diff --git a/patches/server/0495-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch b/patches/server/0498-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch similarity index 100% rename from patches/server/0495-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch rename to patches/server/0498-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch diff --git a/patches/server/0496-Extend-block-drop-capture-to-capture-all-items-added.patch b/patches/server/0499-Extend-block-drop-capture-to-capture-all-items-added.patch similarity index 94% rename from patches/server/0496-Extend-block-drop-capture-to-capture-all-items-added.patch rename to patches/server/0499-Extend-block-drop-capture-to-capture-all-items-added.patch index 0c2984a117..9009d631f8 100644 --- a/patches/server/0496-Extend-block-drop-capture-to-capture-all-items-added.patch +++ b/patches/server/0499-Extend-block-drop-capture-to-capture-all-items-added.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Extend block drop capture to capture all items added to the diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0d51a518fa8b5d3ef5f6332c2b8f8796d62da658..d78b75d00ff95eb0c9619420c2921881724d8561 100644 +index 2ba432f7be370ce1a5861e90de9541d76acdcfd2..85c0a80f00f5968b684b3609fbe56197e4aeb202 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1290,6 +1290,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1292,6 +1292,12 @@ public class ServerLevel extends Level implements WorldGenLevel { // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit return false; } else { diff --git a/patches/server/0497-Don-t-mark-dirty-in-invalid-locations-SPIGOT-6086.patch b/patches/server/0500-Don-t-mark-dirty-in-invalid-locations-SPIGOT-6086.patch similarity index 84% rename from patches/server/0497-Don-t-mark-dirty-in-invalid-locations-SPIGOT-6086.patch rename to patches/server/0500-Don-t-mark-dirty-in-invalid-locations-SPIGOT-6086.patch index e3de5bc8a4..89aadfda9c 100644 --- a/patches/server/0497-Don-t-mark-dirty-in-invalid-locations-SPIGOT-6086.patch +++ b/patches/server/0500-Don-t-mark-dirty-in-invalid-locations-SPIGOT-6086.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Don't mark dirty in invalid locations (SPIGOT-6086) diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 90f65fdcc4acf6762c67a5cb3023d2493f03144f..96fb6e6ba3d1f9d5bd412f4f2bfb9450efa17948 100644 +index a699107b1afea1c52e5a7e93af8f39ae9e1955b3..c4046b364d1896b781e23c92b241ec73c239d3a0 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -245,6 +245,7 @@ public class ChunkHolder { +@@ -250,6 +250,7 @@ public class ChunkHolder { } public void blockChanged(BlockPos pos) { diff --git a/patches/server/0498-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch b/patches/server/0501-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch similarity index 100% rename from patches/server/0498-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch rename to patches/server/0501-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch diff --git a/patches/server/0499-Lazily-track-plugin-scoreboards-by-default.patch b/patches/server/0502-Lazily-track-plugin-scoreboards-by-default.patch similarity index 100% rename from patches/server/0499-Lazily-track-plugin-scoreboards-by-default.patch rename to patches/server/0502-Lazily-track-plugin-scoreboards-by-default.patch diff --git a/patches/server/0500-Entity-isTicking.patch b/patches/server/0503-Entity-isTicking.patch similarity index 95% rename from patches/server/0500-Entity-isTicking.patch rename to patches/server/0503-Entity-isTicking.patch index c2e18c0dd7..86502ef7ae 100644 --- a/patches/server/0500-Entity-isTicking.patch +++ b/patches/server/0503-Entity-isTicking.patch @@ -27,7 +27,7 @@ index 511255467688d4c9397037753d2d4821af29bb79..532678194c2724e31a19f0e4d73d79d8 // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 148cd01c88600042c557f21558acace8bfdfa1cf..c39b683cbe83618daee0ca00d1107b115af6bf8f 100644 +index ab270a14263d6a264bb74de3b924584ac41ed523..fa1e996157fb3470c08669801e7482af70714b11 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -1278,5 +1278,9 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { diff --git a/patches/server/0501-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch b/patches/server/0504-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch similarity index 100% rename from patches/server/0501-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch rename to patches/server/0504-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch diff --git a/patches/server/0502-Fix-Concurrency-issue-in-ShufflingList.patch b/patches/server/0505-Fix-Concurrency-issue-in-ShufflingList.patch similarity index 100% rename from patches/server/0502-Fix-Concurrency-issue-in-ShufflingList.patch rename to patches/server/0505-Fix-Concurrency-issue-in-ShufflingList.patch diff --git a/patches/server/0503-Reset-Ender-Crystals-on-Dragon-Spawn.patch b/patches/server/0506-Reset-Ender-Crystals-on-Dragon-Spawn.patch similarity index 100% rename from patches/server/0503-Reset-Ender-Crystals-on-Dragon-Spawn.patch rename to patches/server/0506-Reset-Ender-Crystals-on-Dragon-Spawn.patch diff --git a/patches/server/0504-Fix-for-large-move-vectors-crashing-server.patch b/patches/server/0507-Fix-for-large-move-vectors-crashing-server.patch similarity index 100% rename from patches/server/0504-Fix-for-large-move-vectors-crashing-server.patch rename to patches/server/0507-Fix-for-large-move-vectors-crashing-server.patch diff --git a/patches/server/0505-Optimise-getType-calls.patch b/patches/server/0508-Optimise-getType-calls.patch similarity index 100% rename from patches/server/0505-Optimise-getType-calls.patch rename to patches/server/0508-Optimise-getType-calls.patch diff --git a/patches/server/0506-Villager-resetOffers.patch b/patches/server/0509-Villager-resetOffers.patch similarity index 100% rename from patches/server/0506-Villager-resetOffers.patch rename to patches/server/0509-Villager-resetOffers.patch diff --git a/patches/server/0507-Improve-inlinig-for-some-hot-IBlockData-methods.patch b/patches/server/0510-Improve-inlinig-for-some-hot-IBlockData-methods.patch similarity index 100% rename from patches/server/0507-Improve-inlinig-for-some-hot-IBlockData-methods.patch rename to patches/server/0510-Improve-inlinig-for-some-hot-IBlockData-methods.patch diff --git a/patches/server/0508-Retain-block-place-order-when-capturing-blockstates.patch b/patches/server/0511-Retain-block-place-order-when-capturing-blockstates.patch similarity index 100% rename from patches/server/0508-Retain-block-place-order-when-capturing-blockstates.patch rename to patches/server/0511-Retain-block-place-order-when-capturing-blockstates.patch diff --git a/patches/server/0509-Reduce-blockpos-allocation-from-pathfinding.patch b/patches/server/0512-Reduce-blockpos-allocation-from-pathfinding.patch similarity index 100% rename from patches/server/0509-Reduce-blockpos-allocation-from-pathfinding.patch rename to patches/server/0512-Reduce-blockpos-allocation-from-pathfinding.patch diff --git a/patches/server/0510-Fix-item-locations-dropped-from-campfires.patch b/patches/server/0513-Fix-item-locations-dropped-from-campfires.patch similarity index 100% rename from patches/server/0510-Fix-item-locations-dropped-from-campfires.patch rename to patches/server/0513-Fix-item-locations-dropped-from-campfires.patch diff --git a/patches/server/0511-Player-elytra-boost-API.patch b/patches/server/0514-Player-elytra-boost-API.patch similarity index 94% rename from patches/server/0511-Player-elytra-boost-API.patch rename to patches/server/0514-Player-elytra-boost-API.patch index 54561c48a1..1e60420c04 100644 --- a/patches/server/0511-Player-elytra-boost-API.patch +++ b/patches/server/0514-Player-elytra-boost-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Player elytra boost API diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 03d43fdc119dc526928abf7b0f1b38d35e985ffc..fb4f868457ebf06b26ddc60f5ffc5a1d5273a1bc 100644 +index 10e1be2349df779b911848f70e4b8f0e351b1de7..09f5a288cba1825fa0fff32f771f98675f473527 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -592,6 +592,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0512-Fixed-TileEntityBell-memory-leak.patch b/patches/server/0515-Fixed-TileEntityBell-memory-leak.patch similarity index 100% rename from patches/server/0512-Fixed-TileEntityBell-memory-leak.patch rename to patches/server/0515-Fixed-TileEntityBell-memory-leak.patch diff --git a/patches/server/0513-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch b/patches/server/0516-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch similarity index 100% rename from patches/server/0513-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch rename to patches/server/0516-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch diff --git a/patches/server/0514-Add-getOfflinePlayerIfCached-String.patch b/patches/server/0517-Add-getOfflinePlayerIfCached-String.patch similarity index 93% rename from patches/server/0514-Add-getOfflinePlayerIfCached-String.patch rename to patches/server/0517-Add-getOfflinePlayerIfCached-String.patch index 683ca40784..b453ab0746 100644 --- a/patches/server/0514-Add-getOfflinePlayerIfCached-String.patch +++ b/patches/server/0517-Add-getOfflinePlayerIfCached-String.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add getOfflinePlayerIfCached(String) diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 72e545e9aa01ad7ae4180d5421e16e330b4c9934..f5ed17af815f2e7da523e80319dc4021556376b2 100644 +index f156620c14e28513fd0f825d5f34de5c5f831b75..f5783a0df00c7c88c5d5d1c3b55ba671350cd0c6 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1803,6 +1803,28 @@ public final class CraftServer implements Server { diff --git a/patches/server/0515-Add-ignore-discounts-API.patch b/patches/server/0518-Add-ignore-discounts-API.patch similarity index 100% rename from patches/server/0515-Add-ignore-discounts-API.patch rename to patches/server/0518-Add-ignore-discounts-API.patch diff --git a/patches/server/0516-Toggle-for-removing-existing-dragon.patch b/patches/server/0519-Toggle-for-removing-existing-dragon.patch similarity index 100% rename from patches/server/0516-Toggle-for-removing-existing-dragon.patch rename to patches/server/0519-Toggle-for-removing-existing-dragon.patch diff --git a/patches/server/0517-Fix-client-lag-on-advancement-loading.patch b/patches/server/0520-Fix-client-lag-on-advancement-loading.patch similarity index 100% rename from patches/server/0517-Fix-client-lag-on-advancement-loading.patch rename to patches/server/0520-Fix-client-lag-on-advancement-loading.patch diff --git a/patches/server/0518-Item-no-age-no-player-pickup.patch b/patches/server/0521-Item-no-age-no-player-pickup.patch similarity index 100% rename from patches/server/0518-Item-no-age-no-player-pickup.patch rename to patches/server/0521-Item-no-age-no-player-pickup.patch diff --git a/patches/server/0519-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/patches/server/0522-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch similarity index 100% rename from patches/server/0519-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch rename to patches/server/0522-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch diff --git a/patches/server/0520-Beacon-API-custom-effect-ranges.patch b/patches/server/0523-Beacon-API-custom-effect-ranges.patch similarity index 100% rename from patches/server/0520-Beacon-API-custom-effect-ranges.patch rename to patches/server/0523-Beacon-API-custom-effect-ranges.patch diff --git a/patches/server/0521-Add-API-for-quit-reason.patch b/patches/server/0524-Add-API-for-quit-reason.patch similarity index 97% rename from patches/server/0521-Add-API-for-quit-reason.patch rename to patches/server/0524-Add-API-for-quit-reason.patch index a632927b3b..20ba1338d0 100644 --- a/patches/server/0521-Add-API-for-quit-reason.patch +++ b/patches/server/0524-Add-API-for-quit-reason.patch @@ -49,10 +49,10 @@ index 3b422cd28b3fb8a172a734e3d59636b293d4a5cb..a6820c2262dd2198b772eae491c40ee3 this.connection.disconnect(ichatbasecomponent); })); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index c00922556462a18543975f7f9c60ea6727e9b114..10acd0256cbe5393b3736be33a55285b7f214a5d 100644 +index ceb5e9540e54275e97f08533d16c820061e76c8f..1d7a7a2d11f0524ae7a81fc0e3bdddd72f5ef53c 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -610,7 +610,7 @@ public abstract class PlayerList { +@@ -607,7 +607,7 @@ public abstract class PlayerList { entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper } diff --git a/patches/server/0522-Add-Wandering-Trader-spawn-rate-config-options.patch b/patches/server/0525-Add-Wandering-Trader-spawn-rate-config-options.patch similarity index 100% rename from patches/server/0522-Add-Wandering-Trader-spawn-rate-config-options.patch rename to patches/server/0525-Add-Wandering-Trader-spawn-rate-config-options.patch diff --git a/patches/server/0523-Expose-world-spawn-angle.patch b/patches/server/0526-Expose-world-spawn-angle.patch similarity index 89% rename from patches/server/0523-Expose-world-spawn-angle.patch rename to patches/server/0526-Expose-world-spawn-angle.patch index 1626858a0e..5bf390c16c 100644 --- a/patches/server/0523-Expose-world-spawn-angle.patch +++ b/patches/server/0526-Expose-world-spawn-angle.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Expose world spawn angle diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 10acd0256cbe5393b3736be33a55285b7f214a5d..2fc183222e539e66c050e146c784a66222dee419 100644 +index 1d7a7a2d11f0524ae7a81fc0e3bdddd72f5ef53c..195fcf93c46967e14a3247768a575c7a73bf9e31 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -888,7 +888,7 @@ public abstract class PlayerList { +@@ -885,7 +885,7 @@ public abstract class PlayerList { if (location == null) { worldserver1 = this.server.getLevel(Level.OVERWORLD); blockposition = entityplayer1.getSpawnPoint(worldserver1); diff --git a/patches/server/0524-Add-Destroy-Speed-API.patch b/patches/server/0527-Add-Destroy-Speed-API.patch similarity index 100% rename from patches/server/0524-Add-Destroy-Speed-API.patch rename to patches/server/0527-Add-Destroy-Speed-API.patch diff --git a/patches/server/0525-Fix-Player-spawnParticle-x-y-z-precision-loss.patch b/patches/server/0528-Fix-Player-spawnParticle-x-y-z-precision-loss.patch similarity index 89% rename from patches/server/0525-Fix-Player-spawnParticle-x-y-z-precision-loss.patch rename to patches/server/0528-Fix-Player-spawnParticle-x-y-z-precision-loss.patch index f5ae3e4907..c8c87f141b 100644 --- a/patches/server/0525-Fix-Player-spawnParticle-x-y-z-precision-loss.patch +++ b/patches/server/0528-Fix-Player-spawnParticle-x-y-z-precision-loss.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix Player spawnParticle x/y/z precision loss diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index fb4f868457ebf06b26ddc60f5ffc5a1d5273a1bc..4c7d84a8f0f186dba18dba528ed324a0808605e3 100644 +index 09f5a288cba1825fa0fff32f771f98675f473527..21f413b1e75c15fae888a4e6dccefbe822ad1c40 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2273,7 +2273,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2263,7 +2263,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { if (data != null && !particle.getDataType().isInstance(data)) { throw new IllegalArgumentException("data should be " + particle.getDataType() + " got " + data.getClass()); } diff --git a/patches/server/0526-Add-LivingEntity-clearActiveItem.patch b/patches/server/0529-Add-LivingEntity-clearActiveItem.patch similarity index 100% rename from patches/server/0526-Add-LivingEntity-clearActiveItem.patch rename to patches/server/0529-Add-LivingEntity-clearActiveItem.patch diff --git a/patches/server/0527-Add-PlayerItemCooldownEvent.patch b/patches/server/0530-Add-PlayerItemCooldownEvent.patch similarity index 100% rename from patches/server/0527-Add-PlayerItemCooldownEvent.patch rename to patches/server/0530-Add-PlayerItemCooldownEvent.patch diff --git a/patches/server/0528-Significantly-improve-performance-of-the-end-generat.patch b/patches/server/0531-Significantly-improve-performance-of-the-end-generat.patch similarity index 100% rename from patches/server/0528-Significantly-improve-performance-of-the-end-generat.patch rename to patches/server/0531-Significantly-improve-performance-of-the-end-generat.patch diff --git a/patches/server/0529-More-lightning-API.patch b/patches/server/0532-More-lightning-API.patch similarity index 100% rename from patches/server/0529-More-lightning-API.patch rename to patches/server/0532-More-lightning-API.patch diff --git a/patches/server/0530-Climbing-should-not-bypass-cramming-gamerule.patch b/patches/server/0533-Climbing-should-not-bypass-cramming-gamerule.patch similarity index 100% rename from patches/server/0530-Climbing-should-not-bypass-cramming-gamerule.patch rename to patches/server/0533-Climbing-should-not-bypass-cramming-gamerule.patch diff --git a/patches/server/0531-Added-missing-default-perms-for-commands.patch b/patches/server/0534-Added-missing-default-perms-for-commands.patch similarity index 100% rename from patches/server/0531-Added-missing-default-perms-for-commands.patch rename to patches/server/0534-Added-missing-default-perms-for-commands.patch diff --git a/patches/server/0532-Add-PlayerShearBlockEvent.patch b/patches/server/0535-Add-PlayerShearBlockEvent.patch similarity index 100% rename from patches/server/0532-Add-PlayerShearBlockEvent.patch rename to patches/server/0535-Add-PlayerShearBlockEvent.patch diff --git a/patches/server/0533-Fix-curing-zombie-villager-discount-exploit.patch b/patches/server/0536-Fix-curing-zombie-villager-discount-exploit.patch similarity index 100% rename from patches/server/0533-Fix-curing-zombie-villager-discount-exploit.patch rename to patches/server/0536-Fix-curing-zombie-villager-discount-exploit.patch diff --git a/patches/server/0534-Limit-recipe-packets.patch b/patches/server/0537-Limit-recipe-packets.patch similarity index 100% rename from patches/server/0534-Limit-recipe-packets.patch rename to patches/server/0537-Limit-recipe-packets.patch diff --git a/patches/server/0535-Fix-CraftSound-backwards-compatibility.patch b/patches/server/0538-Fix-CraftSound-backwards-compatibility.patch similarity index 100% rename from patches/server/0535-Fix-CraftSound-backwards-compatibility.patch rename to patches/server/0538-Fix-CraftSound-backwards-compatibility.patch diff --git a/patches/server/0536-Player-Chunk-Load-Unload-Events.patch b/patches/server/0539-Player-Chunk-Load-Unload-Events.patch similarity index 100% rename from patches/server/0536-Player-Chunk-Load-Unload-Events.patch rename to patches/server/0539-Player-Chunk-Load-Unload-Events.patch diff --git a/patches/server/0537-Optimize-Dynamic-get-Missing-Keys.patch b/patches/server/0540-Optimize-Dynamic-get-Missing-Keys.patch similarity index 100% rename from patches/server/0537-Optimize-Dynamic-get-Missing-Keys.patch rename to patches/server/0540-Optimize-Dynamic-get-Missing-Keys.patch diff --git a/patches/server/0538-Expose-LivingEntity-hurt-direction.patch b/patches/server/0541-Expose-LivingEntity-hurt-direction.patch similarity index 100% rename from patches/server/0538-Expose-LivingEntity-hurt-direction.patch rename to patches/server/0541-Expose-LivingEntity-hurt-direction.patch diff --git a/patches/server/0539-Add-OBSTRUCTED-reason-to-BedEnterResult.patch b/patches/server/0542-Add-OBSTRUCTED-reason-to-BedEnterResult.patch similarity index 100% rename from patches/server/0539-Add-OBSTRUCTED-reason-to-BedEnterResult.patch rename to patches/server/0542-Add-OBSTRUCTED-reason-to-BedEnterResult.patch diff --git a/patches/server/0540-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch b/patches/server/0543-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch similarity index 100% rename from patches/server/0540-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch rename to patches/server/0543-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch diff --git a/patches/server/0541-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch b/patches/server/0544-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch similarity index 100% rename from patches/server/0541-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch rename to patches/server/0544-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch diff --git a/patches/server/0542-Implement-TargetHitEvent.patch b/patches/server/0545-Implement-TargetHitEvent.patch similarity index 100% rename from patches/server/0542-Implement-TargetHitEvent.patch rename to patches/server/0545-Implement-TargetHitEvent.patch diff --git a/patches/server/0543-MC-4-Fix-item-position-desync.patch b/patches/server/0546-MC-4-Fix-item-position-desync.patch similarity index 100% rename from patches/server/0543-MC-4-Fix-item-position-desync.patch rename to patches/server/0546-MC-4-Fix-item-position-desync.patch diff --git a/patches/server/0544-Additional-Block-Material-API-s.patch b/patches/server/0547-Additional-Block-Material-API-s.patch similarity index 100% rename from patches/server/0544-Additional-Block-Material-API-s.patch rename to patches/server/0547-Additional-Block-Material-API-s.patch diff --git a/patches/server/0545-Fix-harming-potion-dupe.patch b/patches/server/0548-Fix-harming-potion-dupe.patch similarity index 100% rename from patches/server/0545-Fix-harming-potion-dupe.patch rename to patches/server/0548-Fix-harming-potion-dupe.patch diff --git a/patches/server/0546-Implement-API-to-get-Material-from-Boats-and-Minecar.patch b/patches/server/0549-Implement-API-to-get-Material-from-Boats-and-Minecar.patch similarity index 100% rename from patches/server/0546-Implement-API-to-get-Material-from-Boats-and-Minecar.patch rename to patches/server/0549-Implement-API-to-get-Material-from-Boats-and-Minecar.patch diff --git a/patches/server/0547-Cache-burn-durations.patch b/patches/server/0550-Cache-burn-durations.patch similarity index 100% rename from patches/server/0547-Cache-burn-durations.patch rename to patches/server/0550-Cache-burn-durations.patch diff --git a/patches/server/0548-Allow-disabling-mob-spawner-spawn-egg-transformation.patch b/patches/server/0551-Allow-disabling-mob-spawner-spawn-egg-transformation.patch similarity index 100% rename from patches/server/0548-Allow-disabling-mob-spawner-spawn-egg-transformation.patch rename to patches/server/0551-Allow-disabling-mob-spawner-spawn-egg-transformation.patch diff --git a/patches/server/0549-Fix-Not-a-string-Map-Conversion-spam.patch b/patches/server/0552-Fix-Not-a-string-Map-Conversion-spam.patch similarity index 100% rename from patches/server/0549-Fix-Not-a-string-Map-Conversion-spam.patch rename to patches/server/0552-Fix-Not-a-string-Map-Conversion-spam.patch diff --git a/patches/server/0550-Implement-PlayerFlowerPotManipulateEvent.patch b/patches/server/0553-Implement-PlayerFlowerPotManipulateEvent.patch similarity index 100% rename from patches/server/0550-Implement-PlayerFlowerPotManipulateEvent.patch rename to patches/server/0553-Implement-PlayerFlowerPotManipulateEvent.patch diff --git a/patches/server/0551-Fix-interact-event-not-being-called-in-adventure.patch b/patches/server/0554-Fix-interact-event-not-being-called-in-adventure.patch similarity index 100% rename from patches/server/0551-Fix-interact-event-not-being-called-in-adventure.patch rename to patches/server/0554-Fix-interact-event-not-being-called-in-adventure.patch diff --git a/patches/server/0552-Zombie-API-breaking-doors.patch b/patches/server/0555-Zombie-API-breaking-doors.patch similarity index 100% rename from patches/server/0552-Zombie-API-breaking-doors.patch rename to patches/server/0555-Zombie-API-breaking-doors.patch diff --git a/patches/server/0553-Fix-nerfed-slime-when-splitting.patch b/patches/server/0556-Fix-nerfed-slime-when-splitting.patch similarity index 100% rename from patches/server/0553-Fix-nerfed-slime-when-splitting.patch rename to patches/server/0556-Fix-nerfed-slime-when-splitting.patch diff --git a/patches/server/0554-Add-EntityLoadCrossbowEvent.patch b/patches/server/0557-Add-EntityLoadCrossbowEvent.patch similarity index 100% rename from patches/server/0554-Add-EntityLoadCrossbowEvent.patch rename to patches/server/0557-Add-EntityLoadCrossbowEvent.patch diff --git a/patches/server/0555-Guardian-beam-workaround.patch b/patches/server/0558-Guardian-beam-workaround.patch similarity index 100% rename from patches/server/0555-Guardian-beam-workaround.patch rename to patches/server/0558-Guardian-beam-workaround.patch diff --git a/patches/server/0556-Added-WorldGameRuleChangeEvent.patch b/patches/server/0559-Added-WorldGameRuleChangeEvent.patch similarity index 96% rename from patches/server/0556-Added-WorldGameRuleChangeEvent.patch rename to patches/server/0559-Added-WorldGameRuleChangeEvent.patch index 34d10452cc..86de4a1af6 100644 --- a/patches/server/0556-Added-WorldGameRuleChangeEvent.patch +++ b/patches/server/0559-Added-WorldGameRuleChangeEvent.patch @@ -64,10 +64,10 @@ index 800325a544bb9f228ccbeb0a52d7f380a8c6083e..3c93bfeb94168f832904a8462ae23b06 public int get() { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index a04ae390f2d054b2ad9fb91eca04955471247b5a..da84c3106b9e6210e234585fdd9eb75e1db041f5 100644 +index b95aed97b48bf31091ee2f44a21ad88071e97bf3..42423b020f9c2ef2ba025b444be076c38314c721 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1804,8 +1804,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1803,8 +1803,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { if (!this.isGameRule(rule)) return false; @@ -82,7 +82,7 @@ index a04ae390f2d054b2ad9fb91eca04955471247b5a..da84c3106b9e6210e234585fdd9eb75e handle.onChanged(this.getHandle().getServer()); return true; } -@@ -1840,8 +1845,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1839,8 +1844,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { if (!this.isGameRule(rule.getName())) return false; diff --git a/patches/server/0557-Added-ServerResourcesReloadedEvent.patch b/patches/server/0560-Added-ServerResourcesReloadedEvent.patch similarity index 100% rename from patches/server/0557-Added-ServerResourcesReloadedEvent.patch rename to patches/server/0560-Added-ServerResourcesReloadedEvent.patch diff --git a/patches/server/0558-Added-world-settings-for-mobs-picking-up-loot.patch b/patches/server/0561-Added-world-settings-for-mobs-picking-up-loot.patch similarity index 100% rename from patches/server/0558-Added-world-settings-for-mobs-picking-up-loot.patch rename to patches/server/0561-Added-world-settings-for-mobs-picking-up-loot.patch diff --git a/patches/server/0559-Implemented-BlockFailedDispenseEvent.patch b/patches/server/0562-Implemented-BlockFailedDispenseEvent.patch similarity index 100% rename from patches/server/0559-Implemented-BlockFailedDispenseEvent.patch rename to patches/server/0562-Implemented-BlockFailedDispenseEvent.patch diff --git a/patches/server/0560-Added-PlayerLecternPageChangeEvent.patch b/patches/server/0563-Added-PlayerLecternPageChangeEvent.patch similarity index 100% rename from patches/server/0560-Added-PlayerLecternPageChangeEvent.patch rename to patches/server/0563-Added-PlayerLecternPageChangeEvent.patch diff --git a/patches/server/0561-Added-PlayerLoomPatternSelectEvent.patch b/patches/server/0564-Added-PlayerLoomPatternSelectEvent.patch similarity index 100% rename from patches/server/0561-Added-PlayerLoomPatternSelectEvent.patch rename to patches/server/0564-Added-PlayerLoomPatternSelectEvent.patch diff --git a/patches/server/0562-Configurable-door-breaking-difficulty.patch b/patches/server/0565-Configurable-door-breaking-difficulty.patch similarity index 100% rename from patches/server/0562-Configurable-door-breaking-difficulty.patch rename to patches/server/0565-Configurable-door-breaking-difficulty.patch diff --git a/patches/server/0563-Empty-commands-shall-not-be-dispatched.patch b/patches/server/0566-Empty-commands-shall-not-be-dispatched.patch similarity index 89% rename from patches/server/0563-Empty-commands-shall-not-be-dispatched.patch rename to patches/server/0566-Empty-commands-shall-not-be-dispatched.patch index e2a473d34d..1c382dc0f6 100644 --- a/patches/server/0563-Empty-commands-shall-not-be-dispatched.patch +++ b/patches/server/0566-Empty-commands-shall-not-be-dispatched.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Empty commands shall not be dispatched diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 0efb172c31a211e03d5fd922f65b6feff1317381..52d2c8d451dce33a5a62f3ec3c5add65a80ce9ca 100644 +index b141d251eedd31bd115342b878afd68dc51a8518..6ad3fe4718a0db17ad6115753e533bf069ce57c6 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -245,6 +245,7 @@ public class Commands { diff --git a/patches/server/0564-Implement-API-to-expose-exact-interaction-point.patch b/patches/server/0567-Implement-API-to-expose-exact-interaction-point.patch similarity index 100% rename from patches/server/0564-Implement-API-to-expose-exact-interaction-point.patch rename to patches/server/0567-Implement-API-to-expose-exact-interaction-point.patch diff --git a/patches/server/0565-Remove-stale-POIs.patch b/patches/server/0568-Remove-stale-POIs.patch similarity index 86% rename from patches/server/0565-Remove-stale-POIs.patch rename to patches/server/0568-Remove-stale-POIs.patch index 018ead4061..8627a969b7 100644 --- a/patches/server/0565-Remove-stale-POIs.patch +++ b/patches/server/0568-Remove-stale-POIs.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Remove stale POIs diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index d78b75d00ff95eb0c9619420c2921881724d8561..3016947fb05211ffa72eef027db92d02e2486150 100644 +index 85c0a80f00f5968b684b3609fbe56197e4aeb202..3f4e3e57999245a83263e88e221723e72a11b31e 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1918,6 +1918,11 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1920,6 +1920,11 @@ public class ServerLevel extends Level implements WorldGenLevel { }); optional1.ifPresent((holder) -> { this.getServer().execute(() -> { diff --git a/patches/server/0566-Fix-villager-boat-exploit.patch b/patches/server/0569-Fix-villager-boat-exploit.patch similarity index 88% rename from patches/server/0566-Fix-villager-boat-exploit.patch rename to patches/server/0569-Fix-villager-boat-exploit.patch index 0ad7ee193e..293797f2f9 100644 --- a/patches/server/0566-Fix-villager-boat-exploit.patch +++ b/patches/server/0569-Fix-villager-boat-exploit.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix villager boat exploit diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 2fc183222e539e66c050e146c784a66222dee419..02611a3929d5cc0904e938db1314567ef23fb041 100644 +index 195fcf93c46967e14a3247768a575c7a73bf9e31..54fff5ebefa04f64ed1abfd12ebf48762015fae3 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -635,6 +635,14 @@ public abstract class PlayerList { +@@ -632,6 +632,14 @@ public abstract class PlayerList { PlayerList.LOGGER.debug("Removing player mount"); entityplayer.stopRiding(); entity.getPassengersAndSelf().forEach((entity1) -> { diff --git a/patches/server/0567-Add-sendOpLevel-API.patch b/patches/server/0570-Add-sendOpLevel-API.patch similarity index 86% rename from patches/server/0567-Add-sendOpLevel-API.patch rename to patches/server/0570-Add-sendOpLevel-API.patch index d418dc9362..67a367d475 100644 --- a/patches/server/0567-Add-sendOpLevel-API.patch +++ b/patches/server/0570-Add-sendOpLevel-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add sendOpLevel API diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 02611a3929d5cc0904e938db1314567ef23fb041..5203bcb732c77b1c232ab262431914c53efd0ae9 100644 +index 54fff5ebefa04f64ed1abfd12ebf48762015fae3..c4f5a3bf60302743329b17f9b2dffcee9c1e5ab3 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1133,6 +1133,11 @@ public abstract class PlayerList { +@@ -1130,6 +1130,11 @@ public abstract class PlayerList { } private void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel) { @@ -20,7 +20,7 @@ index 02611a3929d5cc0904e938db1314567ef23fb041..5203bcb732c77b1c232ab262431914c5 if (player.connection != null) { byte b0; -@@ -1147,8 +1152,10 @@ public abstract class PlayerList { +@@ -1144,8 +1149,10 @@ public abstract class PlayerList { player.connection.send(new ClientboundEntityEventPacket(player, b0)); } @@ -32,7 +32,7 @@ index 02611a3929d5cc0904e938db1314567ef23fb041..5203bcb732c77b1c232ab262431914c5 public boolean isWhiteListed(GameProfile profile) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 99d6e2fcfb6605a712c48831a5b7bd22d123dee2..8608fbd5484498f0e478d857ea1dd548ad6a93e0 100644 +index 21f413b1e75c15fae888a4e6dccefbe822ad1c40..0528489348dc12c22bdb306a4b6c5c6a138f5347 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -606,6 +606,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0568-Add-PaperRegistry.patch b/patches/server/0571-Add-PaperRegistry.patch similarity index 100% rename from patches/server/0568-Add-PaperRegistry.patch rename to patches/server/0571-Add-PaperRegistry.patch diff --git a/patches/server/0569-Add-StructuresLocateEvent.patch b/patches/server/0572-Add-StructuresLocateEvent.patch similarity index 100% rename from patches/server/0569-Add-StructuresLocateEvent.patch rename to patches/server/0572-Add-StructuresLocateEvent.patch diff --git a/patches/server/0570-Collision-option-for-requiring-a-player-participant.patch b/patches/server/0573-Collision-option-for-requiring-a-player-participant.patch similarity index 100% rename from patches/server/0570-Collision-option-for-requiring-a-player-participant.patch rename to patches/server/0573-Collision-option-for-requiring-a-player-participant.patch diff --git a/patches/server/0571-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch b/patches/server/0574-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch similarity index 100% rename from patches/server/0571-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch rename to patches/server/0574-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch diff --git a/patches/server/0572-Return-chat-component-with-empty-text-instead-of-thr.patch b/patches/server/0575-Return-chat-component-with-empty-text-instead-of-thr.patch similarity index 100% rename from patches/server/0572-Return-chat-component-with-empty-text-instead-of-thr.patch rename to patches/server/0575-Return-chat-component-with-empty-text-instead-of-thr.patch diff --git a/patches/server/0573-Make-schedule-command-per-world.patch b/patches/server/0576-Make-schedule-command-per-world.patch similarity index 100% rename from patches/server/0573-Make-schedule-command-per-world.patch rename to patches/server/0576-Make-schedule-command-per-world.patch diff --git a/patches/server/0574-Configurable-max-leash-distance.patch b/patches/server/0577-Configurable-max-leash-distance.patch similarity index 100% rename from patches/server/0574-Configurable-max-leash-distance.patch rename to patches/server/0577-Configurable-max-leash-distance.patch diff --git a/patches/server/0575-Implement-BlockPreDispenseEvent.patch b/patches/server/0578-Implement-BlockPreDispenseEvent.patch similarity index 100% rename from patches/server/0575-Implement-BlockPreDispenseEvent.patch rename to patches/server/0578-Implement-BlockPreDispenseEvent.patch diff --git a/patches/server/0576-Added-firing-of-PlayerChangeBeaconEffectEvent.patch b/patches/server/0579-Added-firing-of-PlayerChangeBeaconEffectEvent.patch similarity index 100% rename from patches/server/0576-Added-firing-of-PlayerChangeBeaconEffectEvent.patch rename to patches/server/0579-Added-firing-of-PlayerChangeBeaconEffectEvent.patch diff --git a/patches/server/0577-Add-toggle-for-always-placing-the-dragon-egg.patch b/patches/server/0580-Add-toggle-for-always-placing-the-dragon-egg.patch similarity index 100% rename from patches/server/0577-Add-toggle-for-always-placing-the-dragon-egg.patch rename to patches/server/0580-Add-toggle-for-always-placing-the-dragon-egg.patch diff --git a/patches/server/0578-Added-PlayerStonecutterRecipeSelectEvent.patch b/patches/server/0581-Added-PlayerStonecutterRecipeSelectEvent.patch similarity index 100% rename from patches/server/0578-Added-PlayerStonecutterRecipeSelectEvent.patch rename to patches/server/0581-Added-PlayerStonecutterRecipeSelectEvent.patch diff --git a/patches/server/0579-Add-dropLeash-variable-to-EntityUnleashEvent.patch b/patches/server/0582-Add-dropLeash-variable-to-EntityUnleashEvent.patch similarity index 100% rename from patches/server/0579-Add-dropLeash-variable-to-EntityUnleashEvent.patch rename to patches/server/0582-Add-dropLeash-variable-to-EntityUnleashEvent.patch diff --git a/patches/server/0580-Reset-shield-blocking-on-dimension-change.patch b/patches/server/0583-Reset-shield-blocking-on-dimension-change.patch similarity index 100% rename from patches/server/0580-Reset-shield-blocking-on-dimension-change.patch rename to patches/server/0583-Reset-shield-blocking-on-dimension-change.patch diff --git a/patches/server/0581-add-DragonEggFormEvent.patch b/patches/server/0584-add-DragonEggFormEvent.patch similarity index 100% rename from patches/server/0581-add-DragonEggFormEvent.patch rename to patches/server/0584-add-DragonEggFormEvent.patch diff --git a/patches/server/0582-EntityMoveEvent.patch b/patches/server/0585-EntityMoveEvent.patch similarity index 97% rename from patches/server/0582-EntityMoveEvent.patch rename to patches/server/0585-EntityMoveEvent.patch index c8d45b7990..739f60de98 100644 --- a/patches/server/0582-EntityMoveEvent.patch +++ b/patches/server/0585-EntityMoveEvent.patch @@ -17,7 +17,7 @@ index d60439d49de781b12af6fbe4ff89b7270f57cbeb..abd1935ebc12f963b563023eb5279ad1 this.profiler.push(() -> { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 3016947fb05211ffa72eef027db92d02e2486150..675c8f6d856c6fa333887fd4079504713f3e861e 100644 +index 3f4e3e57999245a83263e88e221723e72a11b31e..a1b0256c8faceae89e1eaf5e26c8b588085fa760 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -217,6 +217,7 @@ public class ServerLevel extends Level implements WorldGenLevel { diff --git a/patches/server/0583-added-option-to-disable-pathfinding-updates-on-block.patch b/patches/server/0586-added-option-to-disable-pathfinding-updates-on-block.patch similarity index 80% rename from patches/server/0583-added-option-to-disable-pathfinding-updates-on-block.patch rename to patches/server/0586-added-option-to-disable-pathfinding-updates-on-block.patch index 988e34627b..24045de2fb 100644 --- a/patches/server/0583-added-option-to-disable-pathfinding-updates-on-block.patch +++ b/patches/server/0586-added-option-to-disable-pathfinding-updates-on-block.patch @@ -5,10 +5,10 @@ Subject: [PATCH] added option to disable pathfinding updates on block changes diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 675c8f6d856c6fa333887fd4079504713f3e861e..221612cddc9dd839c96d03325ee243721f7f5a9c 100644 +index a1b0256c8faceae89e1eaf5e26c8b588085fa760..7f121ce977fd5779032450443c94634bc919009d 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1492,6 +1492,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1494,6 +1494,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } this.getChunkSource().blockChanged(pos); @@ -16,7 +16,7 @@ index 675c8f6d856c6fa333887fd4079504713f3e861e..221612cddc9dd839c96d03325ee24372 VoxelShape voxelshape = oldState.getCollisionShape(this, pos); VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); -@@ -1533,6 +1534,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1535,6 +1536,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } } diff --git a/patches/server/0584-Inline-shift-direction-fields.patch b/patches/server/0587-Inline-shift-direction-fields.patch similarity index 100% rename from patches/server/0584-Inline-shift-direction-fields.patch rename to patches/server/0587-Inline-shift-direction-fields.patch diff --git a/patches/server/0585-Allow-adding-items-to-BlockDropItemEvent.patch b/patches/server/0588-Allow-adding-items-to-BlockDropItemEvent.patch similarity index 100% rename from patches/server/0585-Allow-adding-items-to-BlockDropItemEvent.patch rename to patches/server/0588-Allow-adding-items-to-BlockDropItemEvent.patch diff --git a/patches/server/0586-Add-getMainThreadExecutor-to-BukkitScheduler.patch b/patches/server/0589-Add-getMainThreadExecutor-to-BukkitScheduler.patch similarity index 100% rename from patches/server/0586-Add-getMainThreadExecutor-to-BukkitScheduler.patch rename to patches/server/0589-Add-getMainThreadExecutor-to-BukkitScheduler.patch diff --git a/patches/server/0587-living-entity-allow-attribute-registration.patch b/patches/server/0590-living-entity-allow-attribute-registration.patch similarity index 100% rename from patches/server/0587-living-entity-allow-attribute-registration.patch rename to patches/server/0590-living-entity-allow-attribute-registration.patch diff --git a/patches/server/0588-fix-dead-slime-setSize-invincibility.patch b/patches/server/0591-fix-dead-slime-setSize-invincibility.patch similarity index 100% rename from patches/server/0588-fix-dead-slime-setSize-invincibility.patch rename to patches/server/0591-fix-dead-slime-setSize-invincibility.patch diff --git a/patches/server/0589-Merchant-getRecipes-should-return-an-immutable-list.patch b/patches/server/0592-Merchant-getRecipes-should-return-an-immutable-list.patch similarity index 100% rename from patches/server/0589-Merchant-getRecipes-should-return-an-immutable-list.patch rename to patches/server/0592-Merchant-getRecipes-should-return-an-immutable-list.patch diff --git a/patches/server/0590-Add-support-for-hex-color-codes-in-console.patch b/patches/server/0593-Add-support-for-hex-color-codes-in-console.patch similarity index 100% rename from patches/server/0590-Add-support-for-hex-color-codes-in-console.patch rename to patches/server/0593-Add-support-for-hex-color-codes-in-console.patch diff --git a/patches/server/0591-Expose-Tracked-Players.patch b/patches/server/0594-Expose-Tracked-Players.patch similarity index 92% rename from patches/server/0591-Expose-Tracked-Players.patch rename to patches/server/0594-Expose-Tracked-Players.patch index 116eacbb27..2a57f6e90d 100644 --- a/patches/server/0591-Expose-Tracked-Players.patch +++ b/patches/server/0594-Expose-Tracked-Players.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Expose Tracked Players diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index c39b683cbe83618daee0ca00d1107b115af6bf8f..b8e5205c165bcba5b8383334f3d0d1daf9d0a8cd 100644 +index fa1e996157fb3470c08669801e7482af70714b11..e9828bab16ac05babccfb1fefad85860c1a4768c 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -1282,5 +1282,18 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { diff --git a/patches/server/0592-Remove-streams-from-SensorNearest.patch b/patches/server/0595-Remove-streams-from-SensorNearest.patch similarity index 100% rename from patches/server/0592-Remove-streams-from-SensorNearest.patch rename to patches/server/0595-Remove-streams-from-SensorNearest.patch diff --git a/patches/server/0593-Throw-proper-exception-on-empty-JsonList-file.patch b/patches/server/0596-Throw-proper-exception-on-empty-JsonList-file.patch similarity index 100% rename from patches/server/0593-Throw-proper-exception-on-empty-JsonList-file.patch rename to patches/server/0596-Throw-proper-exception-on-empty-JsonList-file.patch diff --git a/patches/server/0594-Improve-ServerGUI.patch b/patches/server/0597-Improve-ServerGUI.patch similarity index 100% rename from patches/server/0594-Improve-ServerGUI.patch rename to patches/server/0597-Improve-ServerGUI.patch diff --git a/patches/server/0595-stop-firing-pressure-plate-EntityInteractEvent-for-i.patch b/patches/server/0598-stop-firing-pressure-plate-EntityInteractEvent-for-i.patch similarity index 100% rename from patches/server/0595-stop-firing-pressure-plate-EntityInteractEvent-for-i.patch rename to patches/server/0598-stop-firing-pressure-plate-EntityInteractEvent-for-i.patch diff --git a/patches/server/0596-fix-converting-txt-to-json-file.patch b/patches/server/0599-fix-converting-txt-to-json-file.patch similarity index 97% rename from patches/server/0596-fix-converting-txt-to-json-file.patch rename to patches/server/0599-fix-converting-txt-to-json-file.patch index dfcc5eb724..a8f2f43419 100644 --- a/patches/server/0596-fix-converting-txt-to-json-file.patch +++ b/patches/server/0599-fix-converting-txt-to-json-file.patch @@ -48,7 +48,7 @@ index da83f111199a6b4c712a9bb8ab6f1d1b5c6ae77c..ef02ceba53943d34bd45070297c72bee if (!OldUsersConverter.serverReadyAfterUserconversion(this)) { return false; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 39ddb080e9a296fa499ea2959e22172500db6235..f7f0d7556d130197b8cb75841f1e326274eb59cd 100644 +index c4f5a3bf60302743329b17f9b2dffcee9c1e5ab3..a0b752e09f375fb72ff5ad7952b5ef6ebdb6c14b 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -177,6 +177,7 @@ public abstract class PlayerList { diff --git a/patches/server/0597-Add-worldborder-events.patch b/patches/server/0600-Add-worldborder-events.patch similarity index 100% rename from patches/server/0597-Add-worldborder-events.patch rename to patches/server/0600-Add-worldborder-events.patch diff --git a/patches/server/0598-added-PlayerNameEntityEvent.patch b/patches/server/0601-added-PlayerNameEntityEvent.patch similarity index 100% rename from patches/server/0598-added-PlayerNameEntityEvent.patch rename to patches/server/0601-added-PlayerNameEntityEvent.patch diff --git a/patches/server/0599-Prevent-grindstones-from-overstacking-items.patch b/patches/server/0602-Prevent-grindstones-from-overstacking-items.patch similarity index 100% rename from patches/server/0599-Prevent-grindstones-from-overstacking-items.patch rename to patches/server/0602-Prevent-grindstones-from-overstacking-items.patch diff --git a/patches/server/0600-Add-recipe-to-cook-events.patch b/patches/server/0603-Add-recipe-to-cook-events.patch similarity index 100% rename from patches/server/0600-Add-recipe-to-cook-events.patch rename to patches/server/0603-Add-recipe-to-cook-events.patch diff --git a/patches/server/0601-Add-Block-isValidTool.patch b/patches/server/0604-Add-Block-isValidTool.patch similarity index 100% rename from patches/server/0601-Add-Block-isValidTool.patch rename to patches/server/0604-Add-Block-isValidTool.patch diff --git a/patches/server/0602-Allow-using-signs-inside-spawn-protection.patch b/patches/server/0605-Allow-using-signs-inside-spawn-protection.patch similarity index 100% rename from patches/server/0602-Allow-using-signs-inside-spawn-protection.patch rename to patches/server/0605-Allow-using-signs-inside-spawn-protection.patch diff --git a/patches/server/0603-Expand-world-key-API.patch b/patches/server/0606-Expand-world-key-API.patch similarity index 97% rename from patches/server/0603-Expand-world-key-API.patch rename to patches/server/0606-Expand-world-key-API.patch index 3e4449fb6d..9d99a03dc8 100644 --- a/patches/server/0603-Expand-world-key-API.patch +++ b/patches/server/0606-Expand-world-key-API.patch @@ -20,7 +20,7 @@ index ee5e59c37301d9a806e2f696d52d9d217b232833..bb5d22125b6cd4e60d2b7e2e00af158c // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index f5ed17af815f2e7da523e80319dc4021556376b2..4a59e48f67a4ebd44562915ee866276c1270604b 100644 +index f5783a0df00c7c88c5d5d1c3b55ba671350cd0c6..cebc3c444681d6f422a8befff74476e7e0d8d22e 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1143,9 +1143,15 @@ public final class CraftServer implements Server { diff --git a/patches/server/0604-Add-fast-alternative-constructor-for-Rotations.patch b/patches/server/0607-Add-fast-alternative-constructor-for-Rotations.patch similarity index 100% rename from patches/server/0604-Add-fast-alternative-constructor-for-Rotations.patch rename to patches/server/0607-Add-fast-alternative-constructor-for-Rotations.patch diff --git a/patches/server/0605-Item-Rarity-API.patch b/patches/server/0608-Item-Rarity-API.patch similarity index 100% rename from patches/server/0605-Item-Rarity-API.patch rename to patches/server/0608-Item-Rarity-API.patch diff --git a/patches/server/0606-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch b/patches/server/0609-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch similarity index 100% rename from patches/server/0606-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch rename to patches/server/0609-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch diff --git a/patches/server/0607-copy-TESign-isEditable-from-snapshots.patch b/patches/server/0610-copy-TESign-isEditable-from-snapshots.patch similarity index 100% rename from patches/server/0607-copy-TESign-isEditable-from-snapshots.patch rename to patches/server/0610-copy-TESign-isEditable-from-snapshots.patch diff --git a/patches/server/0608-Drop-carried-item-when-player-has-disconnected.patch b/patches/server/0611-Drop-carried-item-when-player-has-disconnected.patch similarity index 88% rename from patches/server/0608-Drop-carried-item-when-player-has-disconnected.patch rename to patches/server/0611-Drop-carried-item-when-player-has-disconnected.patch index 6235dc89f7..8d562472bc 100644 --- a/patches/server/0608-Drop-carried-item-when-player-has-disconnected.patch +++ b/patches/server/0611-Drop-carried-item-when-player-has-disconnected.patch @@ -7,10 +7,10 @@ Fixes disappearance of held items, when a player gets disconnected and PlayerDro Closes #5036 diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 57e1fa9aa74b237763eb797a4fbe67b791666f84..b4a4fe2ba4cb00ed25fe5899723623f8e915d8d6 100644 +index a0b752e09f375fb72ff5ad7952b5ef6ebdb6c14b..8eae2de23226700b7186b5e673f7f776854a49bc 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -628,6 +628,14 @@ public abstract class PlayerList { +@@ -625,6 +625,14 @@ public abstract class PlayerList { } // Paper end diff --git a/patches/server/0609-forced-whitelist-use-configurable-kick-message.patch b/patches/server/0612-forced-whitelist-use-configurable-kick-message.patch similarity index 100% rename from patches/server/0609-forced-whitelist-use-configurable-kick-message.patch rename to patches/server/0612-forced-whitelist-use-configurable-kick-message.patch diff --git a/patches/server/0610-Don-t-ignore-result-of-PlayerEditBookEvent.patch b/patches/server/0613-Don-t-ignore-result-of-PlayerEditBookEvent.patch similarity index 100% rename from patches/server/0610-Don-t-ignore-result-of-PlayerEditBookEvent.patch rename to patches/server/0613-Don-t-ignore-result-of-PlayerEditBookEvent.patch diff --git a/patches/server/0611-Entity-load-save-limit-per-chunk.patch b/patches/server/0614-Entity-load-save-limit-per-chunk.patch similarity index 100% rename from patches/server/0611-Entity-load-save-limit-per-chunk.patch rename to patches/server/0614-Entity-load-save-limit-per-chunk.patch diff --git a/patches/server/0612-Expose-protocol-version.patch b/patches/server/0615-Expose-protocol-version.patch similarity index 100% rename from patches/server/0612-Expose-protocol-version.patch rename to patches/server/0615-Expose-protocol-version.patch diff --git a/patches/server/0613-Enhance-console-tab-completions-for-brigadier-comman.patch b/patches/server/0616-Enhance-console-tab-completions-for-brigadier-comman.patch similarity index 100% rename from patches/server/0613-Enhance-console-tab-completions-for-brigadier-comman.patch rename to patches/server/0616-Enhance-console-tab-completions-for-brigadier-comman.patch diff --git a/patches/server/0614-Fix-PlayerItemConsumeEvent-cancelling-properly.patch b/patches/server/0617-Fix-PlayerItemConsumeEvent-cancelling-properly.patch similarity index 100% rename from patches/server/0614-Fix-PlayerItemConsumeEvent-cancelling-properly.patch rename to patches/server/0617-Fix-PlayerItemConsumeEvent-cancelling-properly.patch diff --git a/patches/server/0615-Add-bypass-host-check.patch b/patches/server/0618-Add-bypass-host-check.patch similarity index 100% rename from patches/server/0615-Add-bypass-host-check.patch rename to patches/server/0618-Add-bypass-host-check.patch diff --git a/patches/server/0616-Set-area-affect-cloud-rotation.patch b/patches/server/0619-Set-area-affect-cloud-rotation.patch similarity index 100% rename from patches/server/0616-Set-area-affect-cloud-rotation.patch rename to patches/server/0619-Set-area-affect-cloud-rotation.patch diff --git a/patches/server/0617-add-isDeeplySleeping-to-HumanEntity.patch b/patches/server/0620-add-isDeeplySleeping-to-HumanEntity.patch similarity index 100% rename from patches/server/0617-add-isDeeplySleeping-to-HumanEntity.patch rename to patches/server/0620-add-isDeeplySleeping-to-HumanEntity.patch diff --git a/patches/server/0618-add-consumeFuel-to-FurnaceBurnEvent.patch b/patches/server/0621-add-consumeFuel-to-FurnaceBurnEvent.patch similarity index 100% rename from patches/server/0618-add-consumeFuel-to-FurnaceBurnEvent.patch rename to patches/server/0621-add-consumeFuel-to-FurnaceBurnEvent.patch diff --git a/patches/server/0619-add-get-set-drop-chance-to-EntityEquipment.patch b/patches/server/0622-add-get-set-drop-chance-to-EntityEquipment.patch similarity index 100% rename from patches/server/0619-add-get-set-drop-chance-to-EntityEquipment.patch rename to patches/server/0622-add-get-set-drop-chance-to-EntityEquipment.patch diff --git a/patches/server/0620-fix-PigZombieAngerEvent-cancellation.patch b/patches/server/0623-fix-PigZombieAngerEvent-cancellation.patch similarity index 100% rename from patches/server/0620-fix-PigZombieAngerEvent-cancellation.patch rename to patches/server/0623-fix-PigZombieAngerEvent-cancellation.patch diff --git a/patches/server/0621-Fix-checkReach-check-for-Shulker-boxes.patch b/patches/server/0624-Fix-checkReach-check-for-Shulker-boxes.patch similarity index 100% rename from patches/server/0621-Fix-checkReach-check-for-Shulker-boxes.patch rename to patches/server/0624-Fix-checkReach-check-for-Shulker-boxes.patch diff --git a/patches/server/0622-fix-PlayerItemHeldEvent-firing-twice.patch b/patches/server/0625-fix-PlayerItemHeldEvent-firing-twice.patch similarity index 100% rename from patches/server/0622-fix-PlayerItemHeldEvent-firing-twice.patch rename to patches/server/0625-fix-PlayerItemHeldEvent-firing-twice.patch diff --git a/patches/server/0623-Added-PlayerDeepSleepEvent.patch b/patches/server/0626-Added-PlayerDeepSleepEvent.patch similarity index 100% rename from patches/server/0623-Added-PlayerDeepSleepEvent.patch rename to patches/server/0626-Added-PlayerDeepSleepEvent.patch diff --git a/patches/server/0624-More-World-API.patch b/patches/server/0627-More-World-API.patch similarity index 96% rename from patches/server/0624-More-World-API.patch rename to patches/server/0627-More-World-API.patch index d6a3687642..fb9c49f999 100644 --- a/patches/server/0624-More-World-API.patch +++ b/patches/server/0627-More-World-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] More World API diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index da84c3106b9e6210e234585fdd9eb75e1db041f5..4e552504b207a91b9fbd7f2a7f6e96e1fe81cfe2 100644 +index 42423b020f9c2ef2ba025b444be076c38314c721..9ca188959484041f53a078963cb79d68fd2a4f48 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2046,6 +2046,65 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2045,6 +2045,65 @@ public class CraftWorld extends CraftRegionAccessor implements World { return new CraftStructureSearchResult(CraftStructure.minecraftToBukkit(found.getSecond().value(), this.getHandle().registryAccess()), new Location(this, found.getFirst().getX(), found.getFirst().getY(), found.getFirst().getZ())); } diff --git a/patches/server/0625-Added-PlayerBedFailEnterEvent.patch b/patches/server/0628-Added-PlayerBedFailEnterEvent.patch similarity index 100% rename from patches/server/0625-Added-PlayerBedFailEnterEvent.patch rename to patches/server/0628-Added-PlayerBedFailEnterEvent.patch diff --git a/patches/server/0626-Implement-methods-to-convert-between-Component-and-B.patch b/patches/server/0629-Implement-methods-to-convert-between-Component-and-B.patch similarity index 100% rename from patches/server/0626-Implement-methods-to-convert-between-Component-and-B.patch rename to patches/server/0629-Implement-methods-to-convert-between-Component-and-B.patch diff --git a/patches/server/0627-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch b/patches/server/0630-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch similarity index 86% rename from patches/server/0627-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch rename to patches/server/0630-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch index cfe54e00f8..e51b27c728 100644 --- a/patches/server/0627-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch +++ b/patches/server/0630-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Fix anchor respawn acting as a bed respawn from the end diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b4a4fe2ba4cb00ed25fe5899723623f8e915d8d6..b41b9d9ac1e28f44eed4b6c56d63cb5f249b9ea7 100644 +index 8eae2de23226700b7186b5e673f7f776854a49bc..6bdcfe46fd447cfdf2e57bb60250984f02c195da 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -861,6 +861,7 @@ public abstract class PlayerList { +@@ -858,6 +858,7 @@ public abstract class PlayerList { // Paper start boolean isBedSpawn = false; @@ -17,7 +17,7 @@ index b4a4fe2ba4cb00ed25fe5899723623f8e915d8d6..b41b9d9ac1e28f44eed4b6c56d63cb5f boolean isRespawn = false; boolean isLocAltered = false; // Paper - Fix SPIGOT-5989 // Paper end -@@ -881,6 +882,7 @@ public abstract class PlayerList { +@@ -878,6 +879,7 @@ public abstract class PlayerList { if (optional.isPresent()) { BlockState iblockdata = worldserver1.getBlockState(blockposition); boolean flag3 = iblockdata.is(Blocks.RESPAWN_ANCHOR); @@ -25,7 +25,7 @@ index b4a4fe2ba4cb00ed25fe5899723623f8e915d8d6..b41b9d9ac1e28f44eed4b6c56d63cb5f Vec3 vec3d = (Vec3) optional.get(); float f1; -@@ -909,7 +911,7 @@ public abstract class PlayerList { +@@ -906,7 +908,7 @@ public abstract class PlayerList { } Player respawnPlayer = entityplayer1.getBukkitEntity(); diff --git a/patches/server/0628-Introduce-beacon-activation-deactivation-events.patch b/patches/server/0631-Introduce-beacon-activation-deactivation-events.patch similarity index 100% rename from patches/server/0628-Introduce-beacon-activation-deactivation-events.patch rename to patches/server/0631-Introduce-beacon-activation-deactivation-events.patch diff --git a/patches/server/0629-add-RespawnFlags-to-PlayerRespawnEvent.patch b/patches/server/0632-add-RespawnFlags-to-PlayerRespawnEvent.patch similarity index 94% rename from patches/server/0629-add-RespawnFlags-to-PlayerRespawnEvent.patch rename to patches/server/0632-add-RespawnFlags-to-PlayerRespawnEvent.patch index 19655c9810..de0eea12c9 100644 --- a/patches/server/0629-add-RespawnFlags-to-PlayerRespawnEvent.patch +++ b/patches/server/0632-add-RespawnFlags-to-PlayerRespawnEvent.patch @@ -18,10 +18,10 @@ index 35b906d74a4cc03a5878cedff2ee9e694bb03ad4..1a987fe9bbfe4e59e6a10a0ef94e1b18 } else { if (this.player.getHealth() > 0.0F) { diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b41b9d9ac1e28f44eed4b6c56d63cb5f249b9ea7..4b00359d413058c49f79db8cdd81eaa1e729e3a7 100644 +index 6bdcfe46fd447cfdf2e57bb60250984f02c195da..977a23684b061d7390f70f8754a1d879d7d7075a 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -820,6 +820,12 @@ public abstract class PlayerList { +@@ -817,6 +817,12 @@ public abstract class PlayerList { } public ServerPlayer respawn(ServerPlayer entityplayer, ServerLevel worldserver, boolean flag, Location location, boolean avoidSuffocation) { @@ -34,7 +34,7 @@ index b41b9d9ac1e28f44eed4b6c56d63cb5f249b9ea7..4b00359d413058c49f79db8cdd81eaa1 entityplayer.stopRiding(); // CraftBukkit this.players.remove(entityplayer); this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot -@@ -911,7 +917,7 @@ public abstract class PlayerList { +@@ -908,7 +914,7 @@ public abstract class PlayerList { } Player respawnPlayer = entityplayer1.getBukkitEntity(); diff --git a/patches/server/0630-Add-Channel-initialization-listeners.patch b/patches/server/0633-Add-Channel-initialization-listeners.patch similarity index 100% rename from patches/server/0630-Add-Channel-initialization-listeners.patch rename to patches/server/0633-Add-Channel-initialization-listeners.patch diff --git a/patches/server/0631-Send-empty-commands-if-tab-completion-is-disabled.patch b/patches/server/0634-Send-empty-commands-if-tab-completion-is-disabled.patch similarity index 91% rename from patches/server/0631-Send-empty-commands-if-tab-completion-is-disabled.patch rename to patches/server/0634-Send-empty-commands-if-tab-completion-is-disabled.patch index c8fb05fbfb..e31efa98f9 100644 --- a/patches/server/0631-Send-empty-commands-if-tab-completion-is-disabled.patch +++ b/patches/server/0634-Send-empty-commands-if-tab-completion-is-disabled.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Send empty commands if tab completion is disabled diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 52d2c8d451dce33a5a62f3ec3c5add65a80ce9ca..884a7c3a082140d2e1d154851c534ab09f5da4ce 100644 +index 6ad3fe4718a0db17ad6115753e533bf069ce57c6..9c0b2679964f864671ff4041163d1065c8d9cf84 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -358,7 +358,12 @@ public class Commands { diff --git a/patches/server/0632-Add-more-WanderingTrader-API.patch b/patches/server/0635-Add-more-WanderingTrader-API.patch similarity index 100% rename from patches/server/0632-Add-more-WanderingTrader-API.patch rename to patches/server/0635-Add-more-WanderingTrader-API.patch diff --git a/patches/server/0633-Add-EntityBlockStorage-clearEntities.patch b/patches/server/0636-Add-EntityBlockStorage-clearEntities.patch similarity index 100% rename from patches/server/0633-Add-EntityBlockStorage-clearEntities.patch rename to patches/server/0636-Add-EntityBlockStorage-clearEntities.patch diff --git a/patches/server/0634-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch b/patches/server/0637-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch similarity index 100% rename from patches/server/0634-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch rename to patches/server/0637-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch diff --git a/patches/server/0635-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch b/patches/server/0638-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch similarity index 100% rename from patches/server/0635-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch rename to patches/server/0638-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch diff --git a/patches/server/0636-Inventory-close.patch b/patches/server/0639-Inventory-close.patch similarity index 100% rename from patches/server/0636-Inventory-close.patch rename to patches/server/0639-Inventory-close.patch diff --git a/patches/server/0637-call-PortalCreateEvent-players-and-end-platform.patch b/patches/server/0640-call-PortalCreateEvent-players-and-end-platform.patch similarity index 100% rename from patches/server/0637-call-PortalCreateEvent-players-and-end-platform.patch rename to patches/server/0640-call-PortalCreateEvent-players-and-end-platform.patch diff --git a/patches/server/0638-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/server/0641-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch similarity index 100% rename from patches/server/0638-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch rename to patches/server/0641-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch diff --git a/patches/server/0639-Fix-CraftPotionBrewer-cache.patch b/patches/server/0642-Fix-CraftPotionBrewer-cache.patch similarity index 100% rename from patches/server/0639-Fix-CraftPotionBrewer-cache.patch rename to patches/server/0642-Fix-CraftPotionBrewer-cache.patch diff --git a/patches/server/0640-Add-basic-Datapack-API.patch b/patches/server/0643-Add-basic-Datapack-API.patch similarity index 98% rename from patches/server/0640-Add-basic-Datapack-API.patch rename to patches/server/0643-Add-basic-Datapack-API.patch index 07268ceca0..1c6af9a618 100644 --- a/patches/server/0640-Add-basic-Datapack-API.patch +++ b/patches/server/0643-Add-basic-Datapack-API.patch @@ -92,7 +92,7 @@ index 0000000000000000000000000000000000000000..cf4374493c11057451a62a655514415c + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 4a59e48f67a4ebd44562915ee866276c1270604b..7490d6cd392defa93d64fd20cd47caf9b62ddd9b 100644 +index cebc3c444681d6f422a8befff74476e7e0d8d22e..9447b7cf08401608b2b79e8c68f58fd977cf0d42 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -282,6 +282,7 @@ public final class CraftServer implements Server { diff --git a/patches/server/0641-Add-environment-variable-to-disable-server-gui.patch b/patches/server/0644-Add-environment-variable-to-disable-server-gui.patch similarity index 100% rename from patches/server/0641-Add-environment-variable-to-disable-server-gui.patch rename to patches/server/0644-Add-environment-variable-to-disable-server-gui.patch diff --git a/patches/server/0642-additions-to-PlayerGameModeChangeEvent.patch b/patches/server/0645-additions-to-PlayerGameModeChangeEvent.patch similarity index 98% rename from patches/server/0642-additions-to-PlayerGameModeChangeEvent.patch rename to patches/server/0645-additions-to-PlayerGameModeChangeEvent.patch index 1236b864d5..51ec4454fc 100644 --- a/patches/server/0642-additions-to-PlayerGameModeChangeEvent.patch +++ b/patches/server/0645-additions-to-PlayerGameModeChangeEvent.patch @@ -139,10 +139,10 @@ index 1a987fe9bbfe4e59e6a10a0ef94e1b18ed874a9a..66d5b3d44fb56aa6142f730e4742bb8f } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 8608fbd5484498f0e478d857ea1dd548ad6a93e0..0004b78b63a2bf4b34467f9a550f6f0807e4dfb4 100644 +index 0528489348dc12c22bdb306a4b6c5c6a138f5347..ca8267966307ed5e0cb2fc5e4cf61868a77f50ed 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1396,7 +1396,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1386,7 +1386,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { throw new IllegalArgumentException("Mode cannot be null"); } diff --git a/patches/server/0643-ItemStack-repair-check-API.patch b/patches/server/0646-ItemStack-repair-check-API.patch similarity index 100% rename from patches/server/0643-ItemStack-repair-check-API.patch rename to patches/server/0646-ItemStack-repair-check-API.patch diff --git a/patches/server/0644-More-Enchantment-API.patch b/patches/server/0647-More-Enchantment-API.patch similarity index 100% rename from patches/server/0644-More-Enchantment-API.patch rename to patches/server/0647-More-Enchantment-API.patch diff --git a/patches/server/0645-Move-range-check-for-block-placing-up.patch b/patches/server/0648-Move-range-check-for-block-placing-up.patch similarity index 100% rename from patches/server/0645-Move-range-check-for-block-placing-up.patch rename to patches/server/0648-Move-range-check-for-block-placing-up.patch diff --git a/patches/server/0646-Fix-and-optimise-world-force-upgrading.patch b/patches/server/0649-Fix-and-optimise-world-force-upgrading.patch similarity index 98% rename from patches/server/0646-Fix-and-optimise-world-force-upgrading.patch rename to patches/server/0649-Fix-and-optimise-world-force-upgrading.patch index cb25250fdc..3ee5093552 100644 --- a/patches/server/0646-Fix-and-optimise-world-force-upgrading.patch +++ b/patches/server/0649-Fix-and-optimise-world-force-upgrading.patch @@ -272,7 +272,7 @@ index ce4aed84d751a48dcd2a8409190db4a22d78f77b..0a843e0afbcb1af8e2641515eb244b79 Main.LOGGER.info("Forcing world upgrade! {}", session.getLevelId()); // CraftBukkit WorldUpgrader worldupgrader = new WorldUpgrader(session, dataFixer, generatorOptions, eraseCache); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 486acce909cdd2cacc5f2bb9eab1a600152f9971..749421b638bbb5868a426888e42edc461ad0edf3 100644 +index 3c5b7f4b2db421d56e5832e283bd60702b2d67de..84e76fbe3eca77b112c9dff936e21cba1c83e5aa 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -545,11 +545,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop chunkDataPacket) { diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f239acbf6ad778b06bbaf3e03aef9963e5467d0b..66dcd4141ee3b650c4e7a6de2456eb3eb19ea287 100644 +index a34df8db7ae5a1e2fd304e006db7b4af609efb4d..5ee0c3bb27ffbadc1e088983e643eed974753b65 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -905,13 +905,13 @@ public abstract class PlayerList { +@@ -902,13 +902,13 @@ public abstract class PlayerList { f1 = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); } @@ -129,10 +129,10 @@ index c3e49a781f838e6a46cb89744f3f1846de182275..c2f3d3a09327e7cb7d3167609eb3ce68 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 4750ac09f2abfb712b042028a95d23121ffc049f..d309c994ffd72952cf9a8f2f4cc21231417bb9ed 100644 +index a7a0b892b50302ac7af4588bb65206834134dba2..5cdb599c6e460672ed0fe15d5c2a9d60ad22c2e3 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1216,9 +1216,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1206,9 +1206,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setBedSpawnLocation(Location location, boolean override) { if (location == null) { diff --git a/patches/server/0691-Make-hoppers-respect-inventory-max-stack-size.patch b/patches/server/0694-Make-hoppers-respect-inventory-max-stack-size.patch similarity index 100% rename from patches/server/0691-Make-hoppers-respect-inventory-max-stack-size.patch rename to patches/server/0694-Make-hoppers-respect-inventory-max-stack-size.patch diff --git a/patches/server/0692-Optimize-entity-tracker-passenger-checks.patch b/patches/server/0695-Optimize-entity-tracker-passenger-checks.patch similarity index 100% rename from patches/server/0692-Optimize-entity-tracker-passenger-checks.patch rename to patches/server/0695-Optimize-entity-tracker-passenger-checks.patch diff --git a/patches/server/0693-Config-option-for-Piglins-guarding-chests.patch b/patches/server/0696-Config-option-for-Piglins-guarding-chests.patch similarity index 100% rename from patches/server/0693-Config-option-for-Piglins-guarding-chests.patch rename to patches/server/0696-Config-option-for-Piglins-guarding-chests.patch diff --git a/patches/server/0694-Added-EntityDamageItemEvent.patch b/patches/server/0697-Added-EntityDamageItemEvent.patch similarity index 100% rename from patches/server/0694-Added-EntityDamageItemEvent.patch rename to patches/server/0697-Added-EntityDamageItemEvent.patch diff --git a/patches/server/0695-Optimize-indirect-passenger-iteration.patch b/patches/server/0698-Optimize-indirect-passenger-iteration.patch similarity index 100% rename from patches/server/0695-Optimize-indirect-passenger-iteration.patch rename to patches/server/0698-Optimize-indirect-passenger-iteration.patch diff --git a/patches/server/0696-Fix-block-drops-position-losing-precision-millions-o.patch b/patches/server/0699-Fix-block-drops-position-losing-precision-millions-o.patch similarity index 100% rename from patches/server/0696-Fix-block-drops-position-losing-precision-millions-o.patch rename to patches/server/0699-Fix-block-drops-position-losing-precision-millions-o.patch diff --git a/patches/server/0697-Configurable-item-frame-map-cursor-update-interval.patch b/patches/server/0700-Configurable-item-frame-map-cursor-update-interval.patch similarity index 100% rename from patches/server/0697-Configurable-item-frame-map-cursor-update-interval.patch rename to patches/server/0700-Configurable-item-frame-map-cursor-update-interval.patch diff --git a/patches/server/0698-Make-EntityUnleashEvent-cancellable.patch b/patches/server/0701-Make-EntityUnleashEvent-cancellable.patch similarity index 100% rename from patches/server/0698-Make-EntityUnleashEvent-cancellable.patch rename to patches/server/0701-Make-EntityUnleashEvent-cancellable.patch diff --git a/patches/server/0699-Clear-bucket-NBT-after-dispense.patch b/patches/server/0702-Clear-bucket-NBT-after-dispense.patch similarity index 100% rename from patches/server/0699-Clear-bucket-NBT-after-dispense.patch rename to patches/server/0702-Clear-bucket-NBT-after-dispense.patch diff --git a/patches/server/0700-Change-EnderEye-target-without-changing-other-things.patch b/patches/server/0703-Change-EnderEye-target-without-changing-other-things.patch similarity index 100% rename from patches/server/0700-Change-EnderEye-target-without-changing-other-things.patch rename to patches/server/0703-Change-EnderEye-target-without-changing-other-things.patch diff --git a/patches/server/0701-Add-BlockBreakBlockEvent.patch b/patches/server/0704-Add-BlockBreakBlockEvent.patch similarity index 100% rename from patches/server/0701-Add-BlockBreakBlockEvent.patch rename to patches/server/0704-Add-BlockBreakBlockEvent.patch diff --git a/patches/server/0702-Option-to-prevent-NBT-copy-in-smithing-recipes.patch b/patches/server/0705-Option-to-prevent-NBT-copy-in-smithing-recipes.patch similarity index 100% rename from patches/server/0702-Option-to-prevent-NBT-copy-in-smithing-recipes.patch rename to patches/server/0705-Option-to-prevent-NBT-copy-in-smithing-recipes.patch diff --git a/patches/server/0703-More-CommandBlock-API.patch b/patches/server/0706-More-CommandBlock-API.patch similarity index 100% rename from patches/server/0703-More-CommandBlock-API.patch rename to patches/server/0706-More-CommandBlock-API.patch diff --git a/patches/server/0704-Add-missing-team-sidebar-display-slots.patch b/patches/server/0707-Add-missing-team-sidebar-display-slots.patch similarity index 100% rename from patches/server/0704-Add-missing-team-sidebar-display-slots.patch rename to patches/server/0707-Add-missing-team-sidebar-display-slots.patch diff --git a/patches/server/0705-Add-back-EntityPortalExitEvent.patch b/patches/server/0708-Add-back-EntityPortalExitEvent.patch similarity index 100% rename from patches/server/0705-Add-back-EntityPortalExitEvent.patch rename to patches/server/0708-Add-back-EntityPortalExitEvent.patch diff --git a/patches/server/0706-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/server/0709-Add-methods-to-find-targets-for-lightning-strikes.patch similarity index 86% rename from patches/server/0706-Add-methods-to-find-targets-for-lightning-strikes.patch rename to patches/server/0709-Add-methods-to-find-targets-for-lightning-strikes.patch index f76a939dc1..6880c6cd68 100644 --- a/patches/server/0706-Add-methods-to-find-targets-for-lightning-strikes.patch +++ b/patches/server/0709-Add-methods-to-find-targets-for-lightning-strikes.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add methods to find targets for lightning strikes diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 388958c9cdd366f8a5cdf7653abdcc6cdf5433ce..290f7253e78bfd3acdffd2ca6368d80c8620eba5 100644 +index d0c4c9c172c8caa3eaf6c0bf56a8be9f16d8c4e7..10421fdac40c756c52abc9430f7149a9f58efbfb 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -778,6 +778,11 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -780,6 +780,11 @@ public class ServerLevel extends Level implements WorldGenLevel { } protected BlockPos findLightningTargetAround(BlockPos pos) { @@ -20,7 +20,7 @@ index 388958c9cdd366f8a5cdf7653abdcc6cdf5433ce..290f7253e78bfd3acdffd2ca6368d80c BlockPos blockposition1 = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); Optional optional = this.findLightningRod(blockposition1); -@@ -792,6 +797,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -794,6 +799,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (!list.isEmpty()) { return ((LivingEntity) list.get(this.random.nextInt(list.size()))).blockPosition(); } else { @@ -29,10 +29,10 @@ index 388958c9cdd366f8a5cdf7653abdcc6cdf5433ce..290f7253e78bfd3acdffd2ca6368d80c blockposition1 = blockposition1.above(2); } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 59bf99a51d386851501b0acf2f07679f497d3132..9d3f7f196c4331662c4c78cac0b047bcd2ff5e77 100644 +index 2bed5b4eaeac4e48df606b755489a3ca5ffc895e..38a74d683aec58a419af84111844a205596524b2 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -697,6 +697,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -696,6 +696,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { return (LightningStrike) lightning.getBukkitEntity(); } diff --git a/patches/server/0707-Get-entity-default-attributes.patch b/patches/server/0710-Get-entity-default-attributes.patch similarity index 100% rename from patches/server/0707-Get-entity-default-attributes.patch rename to patches/server/0710-Get-entity-default-attributes.patch diff --git a/patches/server/0708-Left-handed-API.patch b/patches/server/0711-Left-handed-API.patch similarity index 100% rename from patches/server/0708-Left-handed-API.patch rename to patches/server/0711-Left-handed-API.patch diff --git a/patches/server/0709-Add-advancement-display-API.patch b/patches/server/0712-Add-advancement-display-API.patch similarity index 100% rename from patches/server/0709-Add-advancement-display-API.patch rename to patches/server/0712-Add-advancement-display-API.patch diff --git a/patches/server/0710-Add-ItemFactory-getMonsterEgg-API.patch b/patches/server/0713-Add-ItemFactory-getMonsterEgg-API.patch similarity index 100% rename from patches/server/0710-Add-ItemFactory-getMonsterEgg-API.patch rename to patches/server/0713-Add-ItemFactory-getMonsterEgg-API.patch diff --git a/patches/server/0711-Add-critical-damage-API.patch b/patches/server/0714-Add-critical-damage-API.patch similarity index 100% rename from patches/server/0711-Add-critical-damage-API.patch rename to patches/server/0714-Add-critical-damage-API.patch diff --git a/patches/server/0712-Fix-issues-with-mob-conversion.patch b/patches/server/0715-Fix-issues-with-mob-conversion.patch similarity index 100% rename from patches/server/0712-Fix-issues-with-mob-conversion.patch rename to patches/server/0715-Fix-issues-with-mob-conversion.patch diff --git a/patches/server/0713-Add-isCollidable-methods-to-various-places.patch b/patches/server/0716-Add-isCollidable-methods-to-various-places.patch similarity index 100% rename from patches/server/0713-Add-isCollidable-methods-to-various-places.patch rename to patches/server/0716-Add-isCollidable-methods-to-various-places.patch diff --git a/patches/server/0714-Goat-ram-API.patch b/patches/server/0717-Goat-ram-API.patch similarity index 100% rename from patches/server/0714-Goat-ram-API.patch rename to patches/server/0717-Goat-ram-API.patch diff --git a/patches/server/0715-Add-API-for-resetting-a-single-score.patch b/patches/server/0718-Add-API-for-resetting-a-single-score.patch similarity index 100% rename from patches/server/0715-Add-API-for-resetting-a-single-score.patch rename to patches/server/0718-Add-API-for-resetting-a-single-score.patch diff --git a/patches/server/0716-Add-Raw-Byte-Entity-Serialization.patch b/patches/server/0719-Add-Raw-Byte-Entity-Serialization.patch similarity index 97% rename from patches/server/0716-Add-Raw-Byte-Entity-Serialization.patch rename to patches/server/0719-Add-Raw-Byte-Entity-Serialization.patch index 2f27482d7e..a4fbf9a562 100644 --- a/patches/server/0716-Add-Raw-Byte-Entity-Serialization.patch +++ b/patches/server/0719-Add-Raw-Byte-Entity-Serialization.patch @@ -25,7 +25,7 @@ index 3f4436a2257376f604926ff35c8589ba59c859e2..6f3147713b5bec3b2771e1ec52917fd4 return this.isPassenger() ? false : this.saveAsPassenger(nbt); } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index b8e5205c165bcba5b8383334f3d0d1daf9d0a8cd..ff8562821ebb363c755e9d316679226d9febe54f 100644 +index e9828bab16ac05babccfb1fefad85860c1a4768c..f04dcefde38c03403f05305ef044b0ee7608eaa3 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -1295,5 +1295,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { diff --git a/patches/server/0717-Vanilla-command-permission-fixes.patch b/patches/server/0720-Vanilla-command-permission-fixes.patch similarity index 97% rename from patches/server/0717-Vanilla-command-permission-fixes.patch rename to patches/server/0720-Vanilla-command-permission-fixes.patch index 8e3102cba2..603bc9d5f0 100644 --- a/patches/server/0717-Vanilla-command-permission-fixes.patch +++ b/patches/server/0720-Vanilla-command-permission-fixes.patch @@ -30,7 +30,7 @@ index 899008b2980d13f1be6280cd8cb959c53a29bebf..f875507241ac6769545e91cd3285232b private RedirectModifier modifier = null; private boolean forks; diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 884a7c3a082140d2e1d154851c534ab09f5da4ce..6d480d0332ee9348eacc3269890ee49206623c2a 100644 +index 9c0b2679964f864671ff4041163d1065c8d9cf84..27093aed1f4112a5414671fd5d9c4e683011506d 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -212,7 +212,13 @@ public class Commands { diff --git a/patches/server/0719-Do-not-allow-the-server-to-unload-chunks-at-request-.patch b/patches/server/0721-Do-not-allow-the-server-to-unload-chunks-at-request-.patch similarity index 87% rename from patches/server/0719-Do-not-allow-the-server-to-unload-chunks-at-request-.patch rename to patches/server/0721-Do-not-allow-the-server-to-unload-chunks-at-request-.patch index 169dae61cc..f8339eb67a 100644 --- a/patches/server/0719-Do-not-allow-the-server-to-unload-chunks-at-request-.patch +++ b/patches/server/0721-Do-not-allow-the-server-to-unload-chunks-at-request-.patch @@ -10,10 +10,10 @@ to be unloaded will simply be unloaded next tick, rather than immediately. diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 918fda0fbbafa39ce0f421dcaf10f8dcf1e5dabb..30347bba40c77c95933997800b9149fcd2326bb1 100644 +index 15b275ee91451478d1c55eae0d20e0e8f36f3a0f..dd4656f0b9d7740ab449ede2588df64e647fab40 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -873,6 +873,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -694,6 +694,7 @@ public class ServerChunkCache extends ChunkSource { // CraftBukkit start - modelled on below public void purgeUnload() { diff --git a/patches/server/0720-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch b/patches/server/0722-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch similarity index 96% rename from patches/server/0720-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch rename to patches/server/0722-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch index aae72845be..c4c28b34ad 100644 --- a/patches/server/0720-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch +++ b/patches/server/0722-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch @@ -9,10 +9,10 @@ chunk through it. This should also be OK from a leak prevention/ state desync POV because the TE is getting unloaded anyways. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 290f7253e78bfd3acdffd2ca6368d80c8620eba5..8234f7edb7668c9e9e742d703a3db315aa523fb4 100644 +index 10421fdac40c756c52abc9430f7149a9f58efbfb..39d96b4e3dce6d67b568b7b00456de164f6a7241 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1336,9 +1336,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1338,9 +1338,13 @@ public class ServerLevel extends Level implements WorldGenLevel { // Spigot Start for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) { if (tileentity instanceof net.minecraft.world.Container) { diff --git a/patches/server/0721-Correctly-handle-recursion-for-chunkholder-updates.patch b/patches/server/0723-Correctly-handle-recursion-for-chunkholder-updates.patch similarity index 90% rename from patches/server/0721-Correctly-handle-recursion-for-chunkholder-updates.patch rename to patches/server/0723-Correctly-handle-recursion-for-chunkholder-updates.patch index f152c64ae6..17b34c16ac 100644 --- a/patches/server/0721-Correctly-handle-recursion-for-chunkholder-updates.patch +++ b/patches/server/0723-Correctly-handle-recursion-for-chunkholder-updates.patch @@ -8,10 +8,10 @@ cause a recursive call which would handle the increase but then the caller would think the chunk would be unloaded. diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 96fb6e6ba3d1f9d5bd412f4f2bfb9450efa17948..eda3929ea7dee63c3598f676f719770637940f53 100644 +index c4046b364d1896b781e23c92b241ec73c239d3a0..9c0bf31c3c362632241c95338a3f8d67bbd4fdc5 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -467,8 +467,10 @@ public class ChunkHolder { +@@ -472,8 +472,10 @@ public class ChunkHolder { playerchunkmap.onFullChunkStatusChange(this.pos, playerchunk_state); } @@ -22,7 +22,7 @@ index 96fb6e6ba3d1f9d5bd412f4f2bfb9450efa17948..eda3929ea7dee63c3598f676f7197706 ChunkStatus chunkstatus = ChunkHolder.getStatus(this.oldTicketLevel); ChunkStatus chunkstatus1 = ChunkHolder.getStatus(this.ticketLevel); boolean flag = this.oldTicketLevel <= ChunkMap.MAX_CHUNK_DISTANCE; -@@ -510,6 +512,12 @@ public class ChunkHolder { +@@ -515,6 +517,12 @@ public class ChunkHolder { // Run callback right away if the future was already done chunkStorage.callbackExecutor.run(); diff --git a/patches/server/0722-Fix-GameProfileCache-concurrency.patch b/patches/server/0724-Fix-GameProfileCache-concurrency.patch similarity index 100% rename from patches/server/0722-Fix-GameProfileCache-concurrency.patch rename to patches/server/0724-Fix-GameProfileCache-concurrency.patch diff --git a/patches/server/0723-Fix-chunks-refusing-to-unload-at-low-TPS.patch b/patches/server/0725-Fix-chunks-refusing-to-unload-at-low-TPS.patch similarity index 88% rename from patches/server/0723-Fix-chunks-refusing-to-unload-at-low-TPS.patch rename to patches/server/0725-Fix-chunks-refusing-to-unload-at-low-TPS.patch index bbdf10fb3e..27155400d9 100644 --- a/patches/server/0723-Fix-chunks-refusing-to-unload-at-low-TPS.patch +++ b/patches/server/0725-Fix-chunks-refusing-to-unload-at-low-TPS.patch @@ -10,10 +10,10 @@ chunk future to complete. We can simply schedule to the immediate executor to get this effect, rather than the main mailbox. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 2418f1c0dc050d224bb866e62f414a55900d9652..f29d77572a3cd977fc492ada8ffc8b77467fabc5 100644 +index 5a78ee69748b2b7b57a9adcff0a4718b1cc0c4ea..a3fceb2608b3be80941dfe2570999b270429e0c6 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1328,9 +1328,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1352,9 +1352,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return chunk; }); diff --git a/patches/server/0724-Do-not-allow-ticket-level-changes-while-unloading-pl.patch b/patches/server/0726-Do-not-allow-ticket-level-changes-while-unloading-pl.patch similarity index 83% rename from patches/server/0724-Do-not-allow-ticket-level-changes-while-unloading-pl.patch rename to patches/server/0726-Do-not-allow-ticket-level-changes-while-unloading-pl.patch index 5a943a25f6..853e534c5c 100644 --- a/patches/server/0724-Do-not-allow-ticket-level-changes-while-unloading-pl.patch +++ b/patches/server/0726-Do-not-allow-ticket-level-changes-while-unloading-pl.patch @@ -8,18 +8,18 @@ Sync loading the chunk at this stage would cause it to load older data, as well as screwing our region state. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index f29d77572a3cd977fc492ada8ffc8b77467fabc5..ae0d7295c88005749f13dd230136f4a39d0a578e 100644 +index a3fceb2608b3be80941dfe2570999b270429e0c6..b34c90497a5492c289839ba74df9f2f27e29370e 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -314,6 +314,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -316,6 +316,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } // Paper end + boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); - this.visibleChunkMap = this.updatingChunkMap.clone(); -@@ -725,6 +726,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper - don't copy +@@ -731,6 +732,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Nullable ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k) { @@ -27,7 +27,7 @@ index f29d77572a3cd977fc492ada8ffc8b77467fabc5..ae0d7295c88005749f13dd230136f4a3 if (k > ChunkMap.MAX_CHUNK_DISTANCE && level > ChunkMap.MAX_CHUNK_DISTANCE) { return holder; } else { -@@ -928,6 +930,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -945,6 +947,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (completablefuture1 != completablefuture) { this.scheduleUnload(pos, holder); } else { @@ -40,19 +40,19 @@ index f29d77572a3cd977fc492ada8ffc8b77467fabc5..ae0d7295c88005749f13dd230136f4a3 // Paper start boolean removed; if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -@@ -965,6 +973,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); - } - } // Paper end +@@ -978,6 +986,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } else if (removed) { // Paper start + net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); + } // Paper end + } finally { this.unloadingPlayerChunk = unloadingBefore; } // Paper - do not allow ticket level changes while unloading chunks } }; diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 30347bba40c77c95933997800b9149fcd2326bb1..591c9577a66f5663f7728b70f44e33ca029af085 100644 +index dd4656f0b9d7740ab449ede2588df64e647fab40..3e45d0c1a95cf8124d15ff4851ea1dcf063f440d 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -809,6 +809,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -630,6 +630,7 @@ public class ServerChunkCache extends ChunkSource { public boolean runDistanceManagerUpdates() { if (distanceManager.delayDistanceManagerTick) return false; // Paper - Chunk priority diff --git a/patches/server/0725-Do-not-allow-ticket-level-changes-when-updating-chun.patch b/patches/server/0727-Do-not-allow-ticket-level-changes-when-updating-chun.patch similarity index 91% rename from patches/server/0725-Do-not-allow-ticket-level-changes-when-updating-chun.patch rename to patches/server/0727-Do-not-allow-ticket-level-changes-when-updating-chun.patch index c863630ea8..d3e3677642 100644 --- a/patches/server/0725-Do-not-allow-ticket-level-changes-when-updating-chun.patch +++ b/patches/server/0727-Do-not-allow-ticket-level-changes-when-updating-chun.patch @@ -8,10 +8,10 @@ This WILL cause state corruption if it happens. So, don't allow it. diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index eda3929ea7dee63c3598f676f719770637940f53..b75b3c4d274252a3a5c53059b9702728eeada389 100644 +index 9c0bf31c3c362632241c95338a3f8d67bbd4fdc5..a2b5f6457b08e4e02544dc71fbf383b5a67a2d69 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -447,7 +447,13 @@ public class ChunkHolder { +@@ -452,7 +452,13 @@ public class ChunkHolder { CompletableFuture completablefuture1 = new CompletableFuture(); completablefuture1.thenRunAsync(() -> { @@ -25,7 +25,7 @@ index eda3929ea7dee63c3598f676f719770637940f53..b75b3c4d274252a3a5c53059b9702728 }, executor); this.pendingFullStateConfirmation = completablefuture1; completablefuture.thenAccept((either) -> { -@@ -464,7 +470,12 @@ public class ChunkHolder { +@@ -469,7 +475,12 @@ public class ChunkHolder { private void demoteFullChunk(ChunkMap playerchunkmap, ChunkHolder.FullChunkStatus playerchunk_state) { this.pendingFullStateConfirmation.cancel(false); diff --git a/patches/server/0726-Log-when-the-async-catcher-is-tripped.patch b/patches/server/0728-Log-when-the-async-catcher-is-tripped.patch similarity index 100% rename from patches/server/0726-Log-when-the-async-catcher-is-tripped.patch rename to patches/server/0728-Log-when-the-async-catcher-is-tripped.patch diff --git a/patches/server/0727-Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/0729-Add-paper-mobcaps-and-paper-playermobcaps.patch similarity index 98% rename from patches/server/0727-Add-paper-mobcaps-and-paper-playermobcaps.patch rename to patches/server/0729-Add-paper-mobcaps-and-paper-playermobcaps.patch index 3e6c326057..07f2b36a13 100644 --- a/patches/server/0727-Add-paper-mobcaps-and-paper-playermobcaps.patch +++ b/patches/server/0729-Add-paper-mobcaps-and-paper-playermobcaps.patch @@ -286,7 +286,7 @@ index fa23e9c476d4edc6176d8b8a6cb13c52d2f66a87..4150e8cd7197eac53042d56f0a53a495 // Paper start - add parameters and int ret type spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 589ee4fd2a7f2c81ef0324662d8349cd3105373f..7f874c53cdb1815e3337c51ab564b7dafb20c939 100644 +index e7863390c8394a6afcfa25099b4ce49c5e010f13..4adacf6f849fe41918690fb8f195727a9c880b53 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2156,6 +2156,11 @@ public final class CraftServer implements Server { @@ -302,10 +302,10 @@ index 589ee4fd2a7f2c81ef0324662d8349cd3105373f..7f874c53cdb1815e3337c51ab564b7da } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 9d3f7f196c4331662c4c78cac0b047bcd2ff5e77..21bf39ef5b20ecc989881b07c4e6b90c68540afd 100644 +index 38a74d683aec58a419af84111844a205596524b2..5138182d8004aec69848d10b8cc63453c1e8808f 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1712,9 +1712,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1711,9 +1711,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { Validate.notNull(spawnCategory, "SpawnCategory cannot be null"); Validate.isTrue(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory." + spawnCategory + " are not supported."); diff --git a/patches/server/0728-Prevent-unload-calls-removing-tickets-for-sync-loads.patch b/patches/server/0730-Prevent-unload-calls-removing-tickets-for-sync-loads.patch similarity index 95% rename from patches/server/0728-Prevent-unload-calls-removing-tickets-for-sync-loads.patch rename to patches/server/0730-Prevent-unload-calls-removing-tickets-for-sync-loads.patch index a8485996ae..5c819b2c69 100644 --- a/patches/server/0728-Prevent-unload-calls-removing-tickets-for-sync-loads.patch +++ b/patches/server/0730-Prevent-unload-calls-removing-tickets-for-sync-loads.patch @@ -18,10 +18,10 @@ index b2df5e18ce5260a9781052db7afb0b9786fb887c..537d34a0325a985948c744929b90144a while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 591c9577a66f5663f7728b70f44e33ca029af085..ce88da358c8a89564a911e6c818e906e845006ff 100644 +index 3e45d0c1a95cf8124d15ff4851ea1dcf063f440d..9f7ec687e6cf971bb9699e9f4ad7ebe37a3ef882 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -714,6 +714,8 @@ public class ServerChunkCache extends ChunkSource { +@@ -535,6 +535,8 @@ public class ServerChunkCache extends ChunkSource { return completablefuture; } @@ -30,7 +30,7 @@ index 591c9577a66f5663f7728b70f44e33ca029af085..ce88da358c8a89564a911e6c818e906e private CompletableFuture> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { // Paper start - add isUrgent - old sig left in place for dirty nms plugins return getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create, false); -@@ -732,9 +734,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -553,9 +555,12 @@ public class ServerChunkCache extends ChunkSource { ChunkHolder.FullChunkStatus currentChunkState = ChunkHolder.getFullChunkStatus(playerchunk.getTicketLevel()); currentlyUnloading = (oldChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !currentChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)); } @@ -43,7 +43,7 @@ index 591c9577a66f5663f7728b70f44e33ca029af085..ce88da358c8a89564a911e6c818e906e if (isUrgent) this.distanceManager.markUrgent(chunkcoordintpair); // Paper - Chunk priority if (this.chunkAbsent(playerchunk, l)) { ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -@@ -745,13 +750,21 @@ public class ServerChunkCache extends ChunkSource { +@@ -566,13 +571,21 @@ public class ServerChunkCache extends ChunkSource { playerchunk = this.getVisibleChunkIfPresent(k); gameprofilerfiller.pop(); if (this.chunkAbsent(playerchunk, l)) { diff --git a/patches/server/0729-Sanitize-ResourceLocation-error-logging.patch b/patches/server/0731-Sanitize-ResourceLocation-error-logging.patch similarity index 100% rename from patches/server/0729-Sanitize-ResourceLocation-error-logging.patch rename to patches/server/0731-Sanitize-ResourceLocation-error-logging.patch diff --git a/patches/server/0730-Allow-controlled-flushing-for-network-manager.patch b/patches/server/0732-Allow-controlled-flushing-for-network-manager.patch similarity index 100% rename from patches/server/0730-Allow-controlled-flushing-for-network-manager.patch rename to patches/server/0732-Allow-controlled-flushing-for-network-manager.patch diff --git a/patches/server/0731-Optimise-general-POI-access.patch b/patches/server/0733-Optimise-general-POI-access.patch similarity index 100% rename from patches/server/0731-Optimise-general-POI-access.patch rename to patches/server/0733-Optimise-general-POI-access.patch diff --git a/patches/server/0732-Add-more-async-catchers.patch b/patches/server/0734-Add-more-async-catchers.patch similarity index 93% rename from patches/server/0732-Add-more-async-catchers.patch rename to patches/server/0734-Add-more-async-catchers.patch index 30eca154ba..c455647bca 100644 --- a/patches/server/0732-Add-more-async-catchers.patch +++ b/patches/server/0734-Add-more-async-catchers.patch @@ -31,10 +31,10 @@ index 2830d32bba3dc85847e3a5d9b4d98f822e34b606..a176a886235494fdc722030a93658d36 throw new UnsupportedOperationException("Only one concurrent iteration supported"); } else { 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 e53e912351a0753c429512f018281a656837bde2..fcf85047d89d5c55df78ab2a6d81cb6da254ecd7 100644 +index a5dc8e715c86c1e70a9cf3d99c9cd457a6666b70..a1a52669c19af22e3b5267d43584cb00d1646453 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -166,6 +166,7 @@ public class PersistentEntitySectionManager implements A +@@ -178,6 +178,7 @@ public class PersistentEntitySectionManager implements A } public void updateChunkStatus(ChunkPos chunkPos, ChunkHolder.FullChunkStatus levelType) { diff --git a/patches/server/0733-Rewrite-entity-bounding-box-lookup-calls.patch b/patches/server/0735-Rewrite-entity-bounding-box-lookup-calls.patch similarity index 99% rename from patches/server/0733-Rewrite-entity-bounding-box-lookup-calls.patch rename to patches/server/0735-Rewrite-entity-bounding-box-lookup-calls.patch index b9ac3b1401..7f57f555d0 100644 --- a/patches/server/0733-Rewrite-entity-bounding-box-lookup-calls.patch +++ b/patches/server/0735-Rewrite-entity-bounding-box-lookup-calls.patch @@ -914,10 +914,10 @@ index 0000000000000000000000000000000000000000..3ba094e640d7fe7803e2bbdab8ff3beb + } +} diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 8234f7edb7668c9e9e742d703a3db315aa523fb4..f3aa1276f0689996ce7827c9300c141dd95582cc 100644 +index 39d96b4e3dce6d67b568b7b00456de164f6a7241..29b80d074600fa7e20b05d1fe70ac12969b954a4 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -452,7 +452,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -454,7 +454,7 @@ public class ServerLevel extends Level implements WorldGenLevel { DataFixer datafixer = minecraftserver.getFixerUpper(); EntityPersistentStorage entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); @@ -1181,7 +1181,7 @@ index 2a4e6c6f732d9cd2567352b7fca2c284b0bb9c1b..4f484e71c93a5243d242e116e2f204ea + // Paper end } 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 fcf85047d89d5c55df78ab2a6d81cb6da254ecd7..8ad1c6f8147cfbd4677252a0d76f147786babe59 100644 +index a1a52669c19af22e3b5267d43584cb00d1646453..f635b610e68d129aa0ae60c54b83da6943946436 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -49,8 +49,10 @@ public class PersistentEntitySectionManager implements A @@ -1196,7 +1196,7 @@ index fcf85047d89d5c55df78ab2a6d81cb6da254ecd7..8ad1c6f8147cfbd4677252a0d76f1477 this.sectionStorage = new EntitySectionStorage<>(entityClass, this.chunkVisibility); this.chunkVisibility.defaultReturnValue(Visibility.HIDDEN); this.chunkLoadStatuses.defaultReturnValue(PersistentEntitySectionManager.ChunkLoadStatus.FRESH); -@@ -112,6 +114,7 @@ public class PersistentEntitySectionManager implements A +@@ -124,6 +126,7 @@ public class PersistentEntitySectionManager implements A EntitySection entitysection = this.sectionStorage.getOrCreateSection(i); entitysection.add(entity); @@ -1204,7 +1204,7 @@ index fcf85047d89d5c55df78ab2a6d81cb6da254ecd7..8ad1c6f8147cfbd4677252a0d76f1477 entity.setLevelCallback(new PersistentEntitySectionManager.Callback(entity, i, entitysection)); if (!existing) { this.callbacks.onCreated(entity); -@@ -169,6 +172,7 @@ public class PersistentEntitySectionManager implements A +@@ -181,6 +184,7 @@ public class PersistentEntitySectionManager implements A io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous chunk ticking status update"); // Paper Visibility visibility = Visibility.fromFullChunkStatus(levelType); @@ -1212,7 +1212,7 @@ index fcf85047d89d5c55df78ab2a6d81cb6da254ecd7..8ad1c6f8147cfbd4677252a0d76f1477 this.updateChunkStatus(chunkPos, visibility); } -@@ -455,6 +459,7 @@ public class PersistentEntitySectionManager implements A +@@ -467,6 +471,7 @@ public class PersistentEntitySectionManager implements A long i = SectionPos.asLong(blockposition); if (i != this.currentSectionKey) { @@ -1220,7 +1220,7 @@ index fcf85047d89d5c55df78ab2a6d81cb6da254ecd7..8ad1c6f8147cfbd4677252a0d76f1477 Visibility visibility = this.currentSection.getStatus(); if (!this.currentSection.remove(this.entity)) { -@@ -512,6 +517,7 @@ public class PersistentEntitySectionManager implements A +@@ -524,6 +529,7 @@ public class PersistentEntitySectionManager implements A if (!this.currentSection.remove(this.entity)) { PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), reason}); } diff --git a/patches/server/0736-Do-not-copy-visible-chunks.patch b/patches/server/0736-Do-not-copy-visible-chunks.patch deleted file mode 100644 index 1b2f6fcee8..0000000000 --- a/patches/server/0736-Do-not-copy-visible-chunks.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 21 Mar 2021 11:22:10 -0700 -Subject: [PATCH] Do not copy visible chunks - -For servers with a lot of chunk holders, copying for each -tickDistanceManager call can take up quite a bit in -the function. I saw approximately 1/3rd of the function -on the copy. - -diff --git a/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java -index 029ad37df71e74d9feb57e4b31b3602e55d49113..4b367982fae4662c326aa247824e9c4185896de1 100644 ---- a/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java -+++ b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java -@@ -90,7 +90,7 @@ public final class ChunkDebugCommand implements PaperSubcommand { - int ticking = 0; - int entityTicking = 0; - -- for (final ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunkMap.values()) { -+ for (final ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunks.getUpdatingMap().values()) { // Paper - change updating chunks map - if (chunk.getFullChunkNowUnchecked() == null) { - continue; - } -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index 613988c9ea892ab15516e1c8b4f376d52415ae34..1eb71004a19866590a3d27fa6e72842934989177 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -625,7 +625,7 @@ public final class MCUtil { - - ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle(); - ChunkMap chunkMap = world.getChunkSource().chunkMap; -- Long2ObjectLinkedOpenHashMap visibleChunks = chunkMap.visibleChunkMap; -+ Long2ObjectLinkedOpenHashMap visibleChunks = chunkMap.updatingChunks.getVisibleMap(); // Paper - DistanceManager chunkMapDistance = chunkMap.distanceManager; - List allChunks = new ArrayList<>(visibleChunks.values()); - List players = world.players; -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 1bbb15354e457a6056d380f9ef318a4661f460e3..b3dc2e71230304ab42b9dd935025f0bd3117bd01 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -123,9 +123,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - private static final int MIN_VIEW_DISTANCE = 3; - public static final int MAX_VIEW_DISTANCE = 33; - public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance(); -+ // Paper start - Don't copy -+ public final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object updatingChunks = new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(); -+ // Paper end - Don't copy - public static final int FORCED_TICKET_LEVEL = 31; -- public final Long2ObjectLinkedOpenHashMap updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); -- public volatile Long2ObjectLinkedOpenHashMap visibleChunkMap; -+ // Paper - Don't copy - private final Long2ObjectLinkedOpenHashMap pendingUnloads; - public final LongSet entitiesInLevel; - public final ServerLevel level; -@@ -318,7 +320,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks - public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { - super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); -- this.visibleChunkMap = this.updatingChunkMap.clone(); -+ // Paper - don't copy - this.pendingUnloads = new Long2ObjectLinkedOpenHashMap(); - this.entitiesInLevel = new LongOpenHashSet(); - this.toDrop = new LongOpenHashSet(); -@@ -559,12 +561,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - @Nullable - public ChunkHolder getUpdatingChunkIfPresent(long pos) { -- return (ChunkHolder) this.updatingChunkMap.get(pos); -+ return this.updatingChunks.getUpdating(pos); // Paper - Don't copy - } - - @Nullable - public ChunkHolder getVisibleChunkIfPresent(long pos) { -- return (ChunkHolder) this.visibleChunkMap.get(pos); -+ // Paper start - Don't copy -+ if (Thread.currentThread() == this.level.thread) { -+ return this.updatingChunks.getVisible(pos); -+ } -+ return this.updatingChunks.getVisibleAsync(pos); -+ // Paper end - Don't copy - } - - protected IntSupplier getChunkQueueLevel(long pos) { -@@ -704,9 +711,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - }; - - stringbuilder.append("Updating:").append(System.lineSeparator()); -- this.updatingChunkMap.values().forEach(consumer); -+ this.updatingChunks.getUpdatingValuesCopy().forEach(consumer); // Paper - stringbuilder.append("Visible:").append(System.lineSeparator()); -- this.visibleChunkMap.values().forEach(consumer); -+ this.updatingChunks.getVisibleValuesCopy().forEach(consumer); // Paper - CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading"); - CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading"); - -@@ -757,7 +764,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper end - } - -- this.updatingChunkMap.put(pos, holder); -+ this.updatingChunks.queueUpdate(pos, holder); // Paper - Don't copy - this.modified = true; - } - -@@ -837,7 +844,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - protected void saveAllChunks(boolean flush) { - if (flush) { -- List list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); -+ List list = (List) this.updatingChunks.getVisibleValuesCopy().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper - MutableBoolean mutableboolean = new MutableBoolean(); - - do { -@@ -868,7 +875,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - //this.flushWorker(); // Paper - nuke IOWorker - this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour - } else { -- this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded); -+ this.updatingChunks.getVisibleValuesCopy().forEach(this::saveChunkIfNeeded); // Paper - } - - } -@@ -891,14 +898,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public boolean hasWork() { -- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); -+ return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || !this.updatingChunks.getUpdatingValuesCopy().isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper - } - - private void processUnloads(BooleanSupplier shouldKeepTicking) { - LongIterator longiterator = this.toDrop.iterator(); - for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { - long j = longiterator.nextLong(); -- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); -+ ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy - - if (playerchunk != null) { - playerchunk.onChunkRemove(); // Paper -@@ -993,7 +1000,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - if (!this.modified) { - return false; - } else { -- this.visibleChunkMap = this.updatingChunkMap.clone(); -+ // Paper start - Don't copy -+ synchronized (this.updatingChunks) { -+ this.updatingChunks.performUpdates(); -+ } -+ // Paper end - Don't copy -+ - this.modified = false; - return true; - } -@@ -1493,7 +1505,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - this.viewDistance = j; - this.distanceManager.updatePlayerTickets(this.viewDistance + 1); -- ObjectIterator objectiterator = this.updatingChunkMap.values().iterator(); -+ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper - - while (objectiterator.hasNext()) { - ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); -@@ -1536,7 +1548,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public int size() { -- return this.visibleChunkMap.size(); -+ return this.updatingChunks.getVisibleMap().size(); // Paper - Don't copy - } - - public DistanceManager getDistanceManager() { -@@ -1544,13 +1556,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - protected Iterable getChunks() { -- return Iterables.unmodifiableIterable(this.visibleChunkMap.values()); -+ return Iterables.unmodifiableIterable(this.updatingChunks.getVisibleValuesCopy()); // Paper - } - - void dumpChunks(Writer writer) throws IOException { - CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); - TickingTracker tickingtracker = this.distanceManager.tickingTracker(); -- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator(); -+ ObjectBidirectionalIterator objectbidirectionaliterator = this.updatingChunks.getVisibleMap().clone().long2ObjectEntrySet().fastIterator(); // Paper - - while (objectbidirectionaliterator.hasNext()) { - Entry entry = (Entry) objectbidirectionaliterator.next(); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 21bf39ef5b20ecc989881b07c4e6b90c68540afd..beee040abf846492cefabe985c5286b00fc6bc63 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -167,7 +167,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - public int getTileEntityCount() { - // We don't use the full world tile entity list, so we must iterate chunks -- Long2ObjectLinkedOpenHashMap chunks = world.getChunkSource().chunkMap.visibleChunkMap; -+ Long2ObjectLinkedOpenHashMap chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Paper - change updating chunks map - int size = 0; - for (ChunkHolder playerchunk : chunks.values()) { - net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk(); -@@ -188,7 +188,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - public int getChunkCount() { - int ret = 0; - -- for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.visibleChunkMap.values()) { -+ for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().values()) { // Paper - change updating chunks map - if (chunkHolder.getTickingChunk() != null) { - ++ret; - } -@@ -345,7 +345,18 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public Chunk[] getLoadedChunks() { -- Long2ObjectLinkedOpenHashMap chunks = this.world.getChunkSource().chunkMap.visibleChunkMap; -+ // Paper start -+ if (Thread.currentThread() != world.getLevel().thread) { -+ // Paper start - change updating chunks map -+ Long2ObjectLinkedOpenHashMap chunks; -+ synchronized (world.getChunkSource().chunkMap.updatingChunks) { -+ chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().clone(); -+ } -+ return chunks.values().stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); -+ // Paper end - change updating chunks map -+ } -+ // Paper end -+ Long2ObjectLinkedOpenHashMap chunks = this.world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Paper - change updating chunks map - return chunks.values().stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); - } - -@@ -421,7 +432,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean refreshChunk(int x, int z) { -- ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.visibleChunkMap.get(ChunkPos.asLong(x, z)); -+ ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().get(ChunkPos.asLong(x, z)); - if (playerChunk == null) return false; - - playerChunk.getTickingChunkFuture().thenAccept(either -> { diff --git a/patches/server/0734-Optimise-chunk-tick-iteration.patch b/patches/server/0736-Optimise-chunk-tick-iteration.patch similarity index 91% rename from patches/server/0734-Optimise-chunk-tick-iteration.patch rename to patches/server/0736-Optimise-chunk-tick-iteration.patch index 3789453481..13c8c24128 100644 --- a/patches/server/0734-Optimise-chunk-tick-iteration.patch +++ b/patches/server/0736-Optimise-chunk-tick-iteration.patch @@ -6,13 +6,13 @@ Subject: [PATCH] Optimise chunk tick iteration Use a dedicated list of entity ticking chunks to reduce the cost diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index b75b3c4d274252a3a5c53059b9702728eeada389..8bea90cb57f38f33e8b3162e24e353993a98ebbf 100644 +index a2b5f6457b08e4e02544dc71fbf383b5a67a2d69..538f21e6bc29c0307441fe4899dc7f600d2d1a04 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -86,11 +86,21 @@ public class ChunkHolder { - long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos); +@@ -84,6 +84,11 @@ public class ChunkHolder { this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); + // Paper end - optimise anyPlayerCloseEnoughForSpawning + // Paper start - optimise chunk tick iteration + if (this.needsBroadcastChanges()) { + this.chunkMap.needsChangeBroadcasting.add(this); @@ -20,18 +20,20 @@ index b75b3c4d274252a3a5c53059b9702728eeada389..8bea90cb57f38f33e8b3162e24e35399 + // Paper end - optimise chunk tick iteration } - void onChunkRemove() { + public void onChunkRemove() { +@@ -91,6 +96,11 @@ public class ChunkHolder { this.playersInMobSpawnRange = null; this.playersInChunkTickRange = null; + // Paper end - optimise anyPlayerCloseEnoughForSpawning + // Paper start - optimise chunk tick iteration + if (this.needsBroadcastChanges()) { + this.chunkMap.needsChangeBroadcasting.remove(this); + } + // Paper end - optimise chunk tick iteration } - // Paper end - optimise anyPlayerCloseEnoughForSpawning - long lastAutoSaveTime; // Paper - incremental autosave -@@ -253,7 +263,7 @@ public class ChunkHolder { + // Paper end + +@@ -258,7 +268,7 @@ public class ChunkHolder { if (i < 0 || i >= this.changedBlocksPerSection.length) return; // CraftBukkit - SPIGOT-6086, SPIGOT-6296 if (this.changedBlocksPerSection[i] == null) { @@ -40,7 +42,7 @@ index b75b3c4d274252a3a5c53059b9702728eeada389..8bea90cb57f38f33e8b3162e24e35399 this.changedBlocksPerSection[i] = new ShortOpenHashSet(); } -@@ -276,6 +286,7 @@ public class ChunkHolder { +@@ -281,6 +291,7 @@ public class ChunkHolder { int k = this.lightEngine.getMaxLightSection(); if (y >= j && y <= k) { @@ -48,7 +50,7 @@ index b75b3c4d274252a3a5c53059b9702728eeada389..8bea90cb57f38f33e8b3162e24e35399 int l = y - j; if (lightType == LightLayer.SKY) { -@@ -290,8 +301,19 @@ public class ChunkHolder { +@@ -295,8 +306,19 @@ public class ChunkHolder { } } @@ -70,10 +72,10 @@ index b75b3c4d274252a3a5c53059b9702728eeada389..8bea90cb57f38f33e8b3162e24e35399 int i = 0; diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index ae0d7295c88005749f13dd230136f4a39d0a578e..1bbb15354e457a6056d380f9ef318a4661f460e3 100644 +index b34c90497a5492c289839ba74df9f2f27e29370e..e811c7d617b8c9cc684bc0a58a98d5ecfe11db02 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -160,6 +160,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -162,6 +162,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final Queue unloadQueue; int viewDistance; public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper @@ -82,7 +84,7 @@ index ae0d7295c88005749f13dd230136f4a39d0a578e..1bbb15354e457a6056d380f9ef318a46 // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() public final CallbackExecutor callbackExecutor = new CallbackExecutor(); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index ce88da358c8a89564a911e6c818e906e845006ff..438406936633b9c67d21b26527c3d1654118c744 100644 +index 9f7ec687e6cf971bb9699e9f4ad7ebe37a3ef882..e585d0047f1dbafeb2bcacf19bd38f3d4b9ab53e 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -47,6 +47,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp @@ -93,7 +95,7 @@ index ce88da358c8a89564a911e6c818e906e845006ff..438406936633b9c67d21b26527c3d165 public class ServerChunkCache extends ChunkSource { -@@ -987,34 +988,42 @@ public class ServerChunkCache extends ChunkSource { +@@ -808,34 +809,42 @@ public class ServerChunkCache extends ChunkSource { this.lastSpawnState = spawnercreature_d; gameprofilerfiller.popPush("filteringLoadedChunks"); @@ -152,24 +154,24 @@ index ce88da358c8a89564a911e6c818e906e845006ff..438406936633b9c67d21b26527c3d165 NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1); } -@@ -1022,7 +1031,16 @@ public class ServerChunkCache extends ChunkSource { +@@ -843,7 +852,16 @@ public class ServerChunkCache extends ChunkSource { this.level.tickChunk(chunk1, k); } } + // Paper start - optimise chunk tick iteration + } - } ++ } + + } finally { + if (iterator1 instanceof io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator safeIterator) { + safeIterator.finishedIterating(); + } -+ } + } + // Paper end - optimise chunk tick iteration this.level.timings.chunkTicks.stopTiming(); // Paper gameprofilerfiller.popPush("customSpawners"); if (flag2) { -@@ -1030,15 +1048,24 @@ public class ServerChunkCache extends ChunkSource { +@@ -851,15 +869,24 @@ public class ServerChunkCache extends ChunkSource { this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); } // Paper - timings } diff --git a/patches/server/0735-Execute-chunk-tasks-mid-tick.patch b/patches/server/0737-Execute-chunk-tasks-mid-tick.patch similarity index 94% rename from patches/server/0735-Execute-chunk-tasks-mid-tick.patch rename to patches/server/0737-Execute-chunk-tasks-mid-tick.patch index 7081da1b7a..90d5f94f2f 100644 --- a/patches/server/0735-Execute-chunk-tasks-mid-tick.patch +++ b/patches/server/0737-Execute-chunk-tasks-mid-tick.patch @@ -106,10 +106,10 @@ index 98fe4165d291b47a39ce741884353c87dd0a4789..99073ea2757cd1c15b098d7cfaf86817 + // Paper end - execute chunk tasks mid tick } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 438406936633b9c67d21b26527c3d1654118c744..2de322ffc2eedae9efe39f9b771c447dd76f26fb 100644 +index e585d0047f1dbafeb2bcacf19bd38f3d4b9ab53e..5ef0ddad4a129b53e3102f177f31f28d5f4cf455 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -1012,6 +1012,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -833,6 +833,7 @@ public class ServerChunkCache extends ChunkSource { iterator1 = shuffled.iterator(); } @@ -117,7 +117,7 @@ index 438406936633b9c67d21b26527c3d1654118c744..2de322ffc2eedae9efe39f9b771c447d try { while (iterator1.hasNext()) { LevelChunk chunk1 = iterator1.next(); -@@ -1029,6 +1030,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -850,6 +851,7 @@ public class ServerChunkCache extends ChunkSource { if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { this.level.tickChunk(chunk1, k); @@ -126,7 +126,7 @@ index 438406936633b9c67d21b26527c3d1654118c744..2de322ffc2eedae9efe39f9b771c447d } // Paper start - optimise chunk tick iteration diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index f3aa1276f0689996ce7827c9300c141dd95582cc..6eca2940cedc5c4fd73906cc4f5657c78d646a10 100644 +index 29b80d074600fa7e20b05d1fe70ac12969b954a4..7324f2ad437a15c42f84ba2deeb58861c0552209 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -212,6 +212,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -137,7 +137,7 @@ index f3aa1276f0689996ce7827c9300c141dd95582cc..6eca2940cedc5c4fd73906cc4f5657c7 // CraftBukkit start public final LevelStorageSource.LevelStorageAccess convertable; -@@ -989,6 +990,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -991,6 +992,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (fluid1.is(fluid)) { fluid1.tick(this, pos); } @@ -145,7 +145,7 @@ index f3aa1276f0689996ce7827c9300c141dd95582cc..6eca2940cedc5c4fd73906cc4f5657c7 } -@@ -998,6 +1000,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1000,6 +1002,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (iblockdata.is(block)) { iblockdata.tick(this, pos, this.random); } diff --git a/patches/server/0737-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/patches/server/0738-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch similarity index 99% rename from patches/server/0737-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch rename to patches/server/0738-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch index 06d2ade2a6..c448b0249c 100644 --- a/patches/server/0737-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch +++ b/patches/server/0738-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch @@ -685,7 +685,7 @@ index 861a25a15f1aab20e3245b6d5cdad5d23bdfd6d0..8ff8855c5267379b3a5f5d8baa4a275f return bytebuffer; } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 0d96d1c0b66c57c680759f3567ef1b0c326d8cfa..6986a170f37f70e8eb89d79d5d2615a06a5e0f0c 100644 +index 666286f94f09299f95538ef2f19b588eb74d9dda..f38ec8914e1953091ab65aa3aaefc886d3eede8a 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -26,7 +26,15 @@ public class RegionFileStorage implements AutoCloseable { diff --git a/patches/server/0738-Custom-table-implementation-for-blockstate-state-loo.patch b/patches/server/0739-Custom-table-implementation-for-blockstate-state-loo.patch similarity index 100% rename from patches/server/0738-Custom-table-implementation-for-blockstate-state-loo.patch rename to patches/server/0739-Custom-table-implementation-for-blockstate-state-loo.patch diff --git a/patches/server/0739-Detail-more-information-in-watchdog-dumps.patch b/patches/server/0740-Detail-more-information-in-watchdog-dumps.patch similarity index 98% rename from patches/server/0739-Detail-more-information-in-watchdog-dumps.patch rename to patches/server/0740-Detail-more-information-in-watchdog-dumps.patch index 73d66a556b..7b40f83dd9 100644 --- a/patches/server/0739-Detail-more-information-in-watchdog-dumps.patch +++ b/patches/server/0740-Detail-more-information-in-watchdog-dumps.patch @@ -78,10 +78,10 @@ index acfa1907bfc9c29d261cfccc00d65bad9ad1a002..d6f3869f5725c7f081efb7f486f74dbb }); throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 6eca2940cedc5c4fd73906cc4f5657c78d646a10..673da1feb2960a6d247265237eae480d34f58056 100644 +index 7324f2ad437a15c42f84ba2deeb58861c0552209..92aafd475d58d1ef2e2736d9363c4b1010724fd7 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1004,7 +1004,26 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1006,7 +1006,26 @@ public class ServerLevel extends Level implements WorldGenLevel { } @@ -108,7 +108,7 @@ index 6eca2940cedc5c4fd73906cc4f5657c78d646a10..673da1feb2960a6d247265237eae480d ++TimingHistory.entityTicks; // Paper - timings // Spigot start co.aikar.timings.Timing timer; // Paper -@@ -1044,7 +1063,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1046,7 +1065,13 @@ public class ServerLevel extends Level implements WorldGenLevel { this.tickPassenger(entity, entity1); } // } finally { timer.stopTiming(); } // Paper - timings - move up diff --git a/patches/server/0740-Manually-inline-methods-in-BlockPosition.patch b/patches/server/0741-Manually-inline-methods-in-BlockPosition.patch similarity index 100% rename from patches/server/0740-Manually-inline-methods-in-BlockPosition.patch rename to patches/server/0741-Manually-inline-methods-in-BlockPosition.patch diff --git a/patches/server/0741-Distance-manager-tick-timings.patch b/patches/server/0742-Distance-manager-tick-timings.patch similarity index 91% rename from patches/server/0741-Distance-manager-tick-timings.patch rename to patches/server/0742-Distance-manager-tick-timings.patch index 98a316c64e..411ac81671 100644 --- a/patches/server/0741-Distance-manager-tick-timings.patch +++ b/patches/server/0742-Distance-manager-tick-timings.patch @@ -19,10 +19,10 @@ index 5ec241d49ff5e3a161a39006f05823a5de847c5e..435b3b6d05e00803386d123c66f961c9 public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks"); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 2de322ffc2eedae9efe39f9b771c447dd76f26fb..7524d9cf7184b345cbd7f0bd1d85601b75c29087 100644 +index 5ef0ddad4a129b53e3102f177f31f28d5f4cf455..5aa5e951f7827e81d370825f0ac8afd78f482955 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -824,6 +824,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -645,6 +645,7 @@ public class ServerChunkCache extends ChunkSource { public boolean runDistanceManagerUpdates() { if (distanceManager.delayDistanceManagerTick) return false; // Paper - Chunk priority if (this.chunkMap.unloadingPlayerChunk) { LOGGER.error("Cannot tick distance manager while unloading playerchunks", new Throwable()); throw new IllegalStateException("Cannot tick distance manager while unloading playerchunks"); } // Paper @@ -30,7 +30,7 @@ index 2de322ffc2eedae9efe39f9b771c447dd76f26fb..7524d9cf7184b345cbd7f0bd1d85601b boolean flag = this.distanceManager.runAllUpdates(this.chunkMap); boolean flag1 = this.chunkMap.promoteChunkMap(); -@@ -833,6 +834,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -654,6 +655,7 @@ public class ServerChunkCache extends ChunkSource { this.clearCache(); return true; } diff --git a/patches/server/0742-Name-craft-scheduler-threads-according-to-the-plugin.patch b/patches/server/0743-Name-craft-scheduler-threads-according-to-the-plugin.patch similarity index 100% rename from patches/server/0742-Name-craft-scheduler-threads-according-to-the-plugin.patch rename to patches/server/0743-Name-craft-scheduler-threads-according-to-the-plugin.patch diff --git a/patches/server/0743-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch b/patches/server/0744-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch similarity index 100% rename from patches/server/0743-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch rename to patches/server/0744-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch diff --git a/patches/server/0744-Add-packet-limiter-config.patch b/patches/server/0745-Add-packet-limiter-config.patch similarity index 100% rename from patches/server/0744-Add-packet-limiter-config.patch rename to patches/server/0745-Add-packet-limiter-config.patch diff --git a/patches/server/0745-Use-correct-LevelStem-registry-when-loading-default-.patch b/patches/server/0746-Use-correct-LevelStem-registry-when-loading-default-.patch similarity index 96% rename from patches/server/0745-Use-correct-LevelStem-registry-when-loading-default-.patch rename to patches/server/0746-Use-correct-LevelStem-registry-when-loading-default-.patch index 82aca1adfa..acaf871233 100644 --- a/patches/server/0745-Use-correct-LevelStem-registry-when-loading-default-.patch +++ b/patches/server/0746-Use-correct-LevelStem-registry-when-loading-default-.patch @@ -24,7 +24,7 @@ index 8da1226a6c293abb038d10c7921a77ed71ad06cc..f958f0ae738a6fb26400e17e54c8d69e } else { Holder holder = registry.getOrCreateHolderOrThrow(entryKey); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 2d94390e3b9fa3afd2471cc691d59de0f470b46c..68c0bb1d493b3de3c3e80018a1655ec968b0316a 100644 +index 99073ea2757cd1c15b098d7cfaf8681702f04a19..857af8ed37c10723d6cd81d7f3c2ba6169021050 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -553,7 +553,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop pendingLogin = new ReferenceOpenHashSet<>(); // Paper @@ -193,7 +193,7 @@ index 82e6a535ff86df7c5fa076d64f09aba4a9231fe6..b0c95b0af6d24b9566b82b2df54eae51 // Add env and gen to constructor, IWorldDataServer -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { // Holder holder = worlddimension.typeHolder(); // CraftBukkit - decompile error -@@ -511,6 +589,14 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -513,6 +591,14 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void tick(BooleanSupplier shouldKeepTicking) { diff --git a/patches/server/0758-Optimise-WorldServer-notify.patch b/patches/server/0759-Optimise-WorldServer-notify.patch similarity index 96% rename from patches/server/0758-Optimise-WorldServer-notify.patch rename to patches/server/0759-Optimise-WorldServer-notify.patch index 745e6af137..0e414d0146 100644 --- a/patches/server/0758-Optimise-WorldServer-notify.patch +++ b/patches/server/0759-Optimise-WorldServer-notify.patch @@ -8,7 +8,7 @@ Instead, only iterate over navigators in the current region that are eligible for repathing. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 97ec72dc383a2637c60cfc988bca2a8a86954ffb..236ba4c1950a3cced590f520b5349eede75fd59b 100644 +index 95c49072e4e90a44873c96af8173d364a5614dff..b98a918ed6d2fabda5bb596dcd13e52033473ebe 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -302,15 +302,81 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -110,10 +110,10 @@ index 97ec72dc383a2637c60cfc988bca2a8a86954ffb..236ba4c1950a3cced590f520b5349eed } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index b0c95b0af6d24b9566b82b2df54eae5108b9b48b..bd64c6d0930565785deb999f43cfaa4eaea53195 100644 +index 25149dde919738859f6fb6b2d0405e90d1732f2b..a7a403d34551453a1e0502fe1f7bc139f645d917 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1120,6 +1120,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1122,6 +1122,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public void tickNonPassenger(Entity entity) { // Paper start - log detailed entity tick information io.papermc.paper.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); @@ -121,7 +121,7 @@ index b0c95b0af6d24b9566b82b2df54eae5108b9b48b..bd64c6d0930565785deb999f43cfaa4e try { if (currentlyTickingEntity.get() == null) { currentlyTickingEntity.lazySet(entity); -@@ -1637,9 +1638,18 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1639,9 +1640,18 @@ public class ServerLevel extends Level implements WorldGenLevel { if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) { List list = new ObjectArrayList(); @@ -142,7 +142,7 @@ index b0c95b0af6d24b9566b82b2df54eae5108b9b48b..bd64c6d0930565785deb999f43cfaa4e // CraftBukkit start - fix SPIGOT-6362 Mob entityinsentient; try { -@@ -1661,16 +1671,23 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1663,16 +1673,23 @@ public class ServerLevel extends Level implements WorldGenLevel { try { this.isUpdatingNavigations = true; @@ -169,7 +169,7 @@ index b0c95b0af6d24b9566b82b2df54eae5108b9b48b..bd64c6d0930565785deb999f43cfaa4e } } // Paper -@@ -2468,10 +2485,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2470,10 +2487,12 @@ public class ServerLevel extends Level implements WorldGenLevel { public void onTickingStart(Entity entity) { ServerLevel.this.entityTickList.add(entity); @@ -226,7 +226,7 @@ index af53372391d05dd6aa3757556418e8723b8b6d80..3f672d7c2377fca16a6d8d31cf7aaae4 + // Paper end } 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 8ad1c6f8147cfbd4677252a0d76f147786babe59..af37b1fcf8459af41482713a9e977599ae6da556 100644 +index f635b610e68d129aa0ae60c54b83da6943946436..1f0eddb0f3ded42bf312f8933def2f5c9a964651 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -71,6 +71,65 @@ public class PersistentEntitySectionManager implements A @@ -295,7 +295,7 @@ index 8ad1c6f8147cfbd4677252a0d76f147786babe59..af37b1fcf8459af41482713a9e977599 void removeSectionIfEmpty(long sectionPos, EntitySection section) { if (section.isEmpty()) { this.sectionStorage.remove(sectionPos); -@@ -456,11 +515,25 @@ public class PersistentEntitySectionManager implements A +@@ -468,11 +527,25 @@ public class PersistentEntitySectionManager implements A @Override public void onMove() { BlockPos blockposition = this.entity.blockPosition(); @@ -323,7 +323,7 @@ index 8ad1c6f8147cfbd4677252a0d76f147786babe59..af37b1fcf8459af41482713a9e977599 if (!this.currentSection.remove(this.entity)) { PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (moving to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), i}); -@@ -472,6 +545,11 @@ public class PersistentEntitySectionManager implements A +@@ -484,6 +557,11 @@ public class PersistentEntitySectionManager implements A entitysection.add(this.entity); this.currentSection = entitysection; this.currentSectionKey = i; diff --git a/patches/server/0759-Remove-streams-for-villager-AI.patch b/patches/server/0760-Remove-streams-for-villager-AI.patch similarity index 100% rename from patches/server/0759-Remove-streams-for-villager-AI.patch rename to patches/server/0760-Remove-streams-for-villager-AI.patch diff --git a/patches/server/0760-Rewrite-dataconverter-system.patch b/patches/server/0761-Rewrite-dataconverter-system.patch similarity index 100% rename from patches/server/0760-Rewrite-dataconverter-system.patch rename to patches/server/0761-Rewrite-dataconverter-system.patch diff --git a/patches/server/0761-Use-Velocity-compression-and-cipher-natives.patch b/patches/server/0762-Use-Velocity-compression-and-cipher-natives.patch similarity index 100% rename from patches/server/0761-Use-Velocity-compression-and-cipher-natives.patch rename to patches/server/0762-Use-Velocity-compression-and-cipher-natives.patch diff --git a/patches/server/0762-Reduce-worldgen-thread-worker-count-for-low-core-cou.patch b/patches/server/0763-Reduce-worldgen-thread-worker-count-for-low-core-cou.patch similarity index 100% rename from patches/server/0762-Reduce-worldgen-thread-worker-count-for-low-core-cou.patch rename to patches/server/0763-Reduce-worldgen-thread-worker-count-for-low-core-cou.patch diff --git a/patches/server/0763-Do-not-process-entity-loads-in-CraftChunk-getEntitie.patch b/patches/server/0764-Do-not-process-entity-loads-in-CraftChunk-getEntitie.patch similarity index 100% rename from patches/server/0763-Do-not-process-entity-loads-in-CraftChunk-getEntitie.patch rename to patches/server/0764-Do-not-process-entity-loads-in-CraftChunk-getEntitie.patch diff --git a/patches/server/0764-Async-catch-modifications-to-critical-entity-state.patch b/patches/server/0765-Async-catch-modifications-to-critical-entity-state.patch similarity index 86% rename from patches/server/0764-Async-catch-modifications-to-critical-entity-state.patch rename to patches/server/0765-Async-catch-modifications-to-critical-entity-state.patch index 3b0091079e..3e8995df49 100644 --- a/patches/server/0764-Async-catch-modifications-to-critical-entity-state.patch +++ b/patches/server/0765-Async-catch-modifications-to-critical-entity-state.patch @@ -8,7 +8,7 @@ Now in 1.17, this state is _even more_ critical than it was before, so these must exist to catch stupid plugins. 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 af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c782659def3ba6 100644 +index 1f0eddb0f3ded42bf312f8933def2f5c9a964651..2d3aacdae95963385ea228e73a2073a6fd96e640 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -138,6 +138,7 @@ public class PersistentEntitySectionManager implements A @@ -24,10 +24,10 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 private boolean addEntity(T entity, boolean existing) { + org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper - if (!this.addEntityUuid(entity)) { - return false; - } else { -@@ -210,19 +212,23 @@ public class PersistentEntitySectionManager implements A + // Paper start - chunk system hooks + if (existing) { + // I don't want to know why this is a generic type. +@@ -222,19 +224,23 @@ public class PersistentEntitySectionManager implements A } void startTicking(T entity) { @@ -51,7 +51,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 this.callbacks.onTrackingEnd(entity); this.visibleEntityStorage.remove(entity); } -@@ -236,6 +242,7 @@ public class PersistentEntitySectionManager implements A +@@ -248,6 +254,7 @@ public class PersistentEntitySectionManager implements A } public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) { @@ -59,7 +59,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 long i = chunkPos.toLong(); if (trackingStatus == Visibility.HIDDEN) { -@@ -280,6 +287,7 @@ public class PersistentEntitySectionManager implements A +@@ -292,6 +299,7 @@ public class PersistentEntitySectionManager implements A } public void ensureChunkQueuedForLoad(long chunkPos) { @@ -67,7 +67,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos); if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { -@@ -324,6 +332,7 @@ public class PersistentEntitySectionManager implements A +@@ -336,6 +344,7 @@ public class PersistentEntitySectionManager implements A } private void requestChunkLoad(long chunkPos) { @@ -75,7 +75,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 this.chunkLoadStatuses.put(chunkPos, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); ChunkPos chunkcoordintpair = new ChunkPos(chunkPos); CompletableFuture completablefuture = this.permanentStorage.loadEntities(chunkcoordintpair); -@@ -337,6 +346,7 @@ public class PersistentEntitySectionManager implements A +@@ -349,6 +358,7 @@ public class PersistentEntitySectionManager implements A } private boolean processChunkUnload(long chunkPos) { @@ -83,7 +83,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> { entityaccess.getPassengersAndSelf().forEach(this::unloadEntity); }, true); // CraftBukkit - add boolean for event call -@@ -361,6 +371,7 @@ public class PersistentEntitySectionManager implements A +@@ -373,6 +383,7 @@ public class PersistentEntitySectionManager implements A } private void processPendingLoads() { @@ -91,7 +91,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 ChunkEntities chunkentities; // CraftBukkit - decompile error while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) { -@@ -377,6 +388,7 @@ public class PersistentEntitySectionManager implements A +@@ -389,6 +400,7 @@ public class PersistentEntitySectionManager implements A } public void tick() { @@ -99,7 +99,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 this.processPendingLoads(); this.processUnloads(); } -@@ -397,6 +409,7 @@ public class PersistentEntitySectionManager implements A +@@ -409,6 +421,7 @@ public class PersistentEntitySectionManager implements A } public void autoSave() { @@ -107,7 +107,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 this.getAllChunksToSave().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN; -@@ -411,6 +424,7 @@ public class PersistentEntitySectionManager implements A +@@ -423,6 +436,7 @@ public class PersistentEntitySectionManager implements A } public void saveAll() { @@ -115,7 +115,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 LongSet longset = this.getAllChunksToSave(); while (!longset.isEmpty()) { -@@ -518,6 +532,7 @@ public class PersistentEntitySectionManager implements A +@@ -530,6 +544,7 @@ public class PersistentEntitySectionManager implements A long i = SectionPos.asLong(blockposition); final long newSectionPos = i; // Paper - diff on change, new position section if (i != this.currentSectionKey) { @@ -123,7 +123,7 @@ index af37b1fcf8459af41482713a9e977599ae6da556..30c4974b4019d67cffabd3e686c78265 PersistentEntitySectionManager.this.entitySliceManager.moveEntity((Entity)this.entity); // Paper Visibility visibility = this.currentSection.getStatus(); final Visibility oldVisibility = visibility; // Paper - diff on change - this should be OLD section visibility // Paper start -@@ -592,6 +607,7 @@ public class PersistentEntitySectionManager implements A +@@ -604,6 +619,7 @@ public class PersistentEntitySectionManager implements A @Override public void onRemove(Entity.RemovalReason reason) { diff --git a/patches/server/0765-Fix-Bukkit-NamespacedKey-shenanigans.patch b/patches/server/0766-Fix-Bukkit-NamespacedKey-shenanigans.patch similarity index 100% rename from patches/server/0765-Fix-Bukkit-NamespacedKey-shenanigans.patch rename to patches/server/0766-Fix-Bukkit-NamespacedKey-shenanigans.patch diff --git a/patches/server/0766-Fix-merchant-inventory-not-closing-on-entity-removal.patch b/patches/server/0767-Fix-merchant-inventory-not-closing-on-entity-removal.patch similarity index 90% rename from patches/server/0766-Fix-merchant-inventory-not-closing-on-entity-removal.patch rename to patches/server/0767-Fix-merchant-inventory-not-closing-on-entity-removal.patch index 2ebc3b0fb5..85602ad6d7 100644 --- a/patches/server/0766-Fix-merchant-inventory-not-closing-on-entity-removal.patch +++ b/patches/server/0767-Fix-merchant-inventory-not-closing-on-entity-removal.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix merchant inventory not closing on entity removal diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index bd64c6d0930565785deb999f43cfaa4eaea53195..502a11fbef542891358589f00cf4a267dca9bc9a 100644 +index a7a403d34551453a1e0502fe1f7bc139f645d917..3bb6dbdd05ed981f70556c8f905d1eeeeade30b8 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2576,6 +2576,11 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2578,6 +2578,11 @@ public class ServerLevel extends Level implements WorldGenLevel { // Spigot end // Spigot Start if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message diff --git a/patches/server/0767-Check-requirement-before-suggesting-root-nodes.patch b/patches/server/0768-Check-requirement-before-suggesting-root-nodes.patch similarity index 100% rename from patches/server/0767-Check-requirement-before-suggesting-root-nodes.patch rename to patches/server/0768-Check-requirement-before-suggesting-root-nodes.patch diff --git a/patches/server/0768-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch b/patches/server/0769-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch similarity index 100% rename from patches/server/0768-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch rename to patches/server/0769-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch diff --git a/patches/server/0769-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch b/patches/server/0770-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch similarity index 100% rename from patches/server/0769-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch rename to patches/server/0770-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch diff --git a/patches/server/0770-Ensure-valid-vehicle-status.patch b/patches/server/0771-Ensure-valid-vehicle-status.patch similarity index 100% rename from patches/server/0770-Ensure-valid-vehicle-status.patch rename to patches/server/0771-Ensure-valid-vehicle-status.patch diff --git a/patches/server/0771-Prevent-softlocked-end-exit-portal-generation.patch b/patches/server/0772-Prevent-softlocked-end-exit-portal-generation.patch similarity index 100% rename from patches/server/0771-Prevent-softlocked-end-exit-portal-generation.patch rename to patches/server/0772-Prevent-softlocked-end-exit-portal-generation.patch diff --git a/patches/server/0772-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch b/patches/server/0773-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch similarity index 100% rename from patches/server/0772-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch rename to patches/server/0773-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch diff --git a/patches/server/0773-Don-t-log-debug-logging-being-disabled.patch b/patches/server/0774-Don-t-log-debug-logging-being-disabled.patch similarity index 100% rename from patches/server/0773-Don-t-log-debug-logging-being-disabled.patch rename to patches/server/0774-Don-t-log-debug-logging-being-disabled.patch diff --git a/patches/server/0775-Do-not-overload-I-O-threads-with-chunk-data-while-fl.patch b/patches/server/0775-Do-not-overload-I-O-threads-with-chunk-data-while-fl.patch deleted file mode 100644 index c0add08508..0000000000 --- a/patches/server/0775-Do-not-overload-I-O-threads-with-chunk-data-while-fl.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 16 Oct 2021 01:36:00 -0700 -Subject: [PATCH] Do not overload I/O threads with chunk data while flush - saving - -If the chunk count is high, then the memory used by the -chunks adds up and could cause problems. By flushing -every so many chunks, the server will not become -stressed for memory. It will also not increase the total -time to save, as flush saving performs a full flush at -the end anyways. - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 236ba4c1950a3cced590f520b5349eede75fd59b..adce96d372e0f9b6c3813b2153a5dcbb32a4e75c 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -946,6 +946,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper end - - protected void saveAllChunks(boolean flush) { -+ // Paper start - do not overload I/O threads with too much work when saving -+ int[] saved = new int[1]; -+ int maxAsyncSaves = 50; -+ Runnable onChunkSave = () -> { -+ if (++saved[0] >= maxAsyncSaves) { -+ saved[0] = 0; -+ com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.flush(); -+ } -+ }; -+ // Paper end - do not overload I/O threads with too much work when saving - if (flush) { - List list = (List) this.updatingChunks.getVisibleValuesCopy().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper - MutableBoolean mutableboolean = new MutableBoolean(); -@@ -968,6 +978,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - }).filter((ichunkaccess) -> { - return ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk; - }).filter(this::save).forEach((ichunkaccess) -> { -+ onChunkSave.run(); // Paper - do not overload I/O threads with too much work when saving - mutableboolean.setTrue(); - }); - } while (mutableboolean.isTrue()); diff --git a/patches/server/0774-fix-various-menus-with-empty-level-accesses.patch b/patches/server/0775-fix-various-menus-with-empty-level-accesses.patch similarity index 100% rename from patches/server/0774-fix-various-menus-with-empty-level-accesses.patch rename to patches/server/0775-fix-various-menus-with-empty-level-accesses.patch diff --git a/patches/server/0781-Add-config-option-for-logging-player-ip-addresses.patch b/patches/server/0781-Add-config-option-for-logging-player-ip-addresses.patch index f72d88e116..4e93cf35ca 100644 --- a/patches/server/0781-Add-config-option-for-logging-player-ip-addresses.patch +++ b/patches/server/0781-Add-config-option-for-logging-player-ip-addresses.patch @@ -65,10 +65,10 @@ index 77cb18da4f89bb89aea7d1ef5ebe3dd7acfe000d..acd581d14e0ef1fe5a6545ee67be00de @Nullable diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 03c413dfd16f415377749baa4fdd41949c6a12b9..d3c6c1b9ac00df265507db61301cae397214dca7 100644 +index 5ee0c3bb27ffbadc1e088983e643eed974753b65..fc14fc8017d89c27b0aeb10a5f38dafde5c15f53 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -241,7 +241,7 @@ public abstract class PlayerList { +@@ -243,7 +243,7 @@ public abstract class PlayerList { final String s1; if (connection.getRemoteAddress() != null) { diff --git a/patches/server/0797-Add-player-health-update-API.patch b/patches/server/0797-Add-player-health-update-API.patch index da94ae0e7a..96480e59ca 100644 --- a/patches/server/0797-Add-player-health-update-API.patch +++ b/patches/server/0797-Add-player-health-update-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add player health update API diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 55f4a09bc27c30936e29fa2a2fe2ef0a67b8876d..67833efdd2c4babe20a01691a44ec6f153656729 100644 +index 5cdb599c6e460672ed0fe15d5c2a9d60ad22c2e3..8882651847fc9a8d2e4222f10eb389b553da48ca 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2152,9 +2152,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2142,9 +2142,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.getHandle().maxHealthCache = getMaxHealth(); } @@ -22,7 +22,7 @@ index 55f4a09bc27c30936e29fa2a2fe2ef0a67b8876d..67833efdd2c4babe20a01691a44ec6f1 if (this.getHandle().queueHealthUpdatePacket) { this.getHandle().queuedHealthUpdatePacket = packet; } else { -@@ -2162,7 +2164,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2152,7 +2154,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } // Paper end } diff --git a/patches/server/0800-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch b/patches/server/0800-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch index 74fdb0cea4..ded6d6290a 100644 --- a/patches/server/0800-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch +++ b/patches/server/0800-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch @@ -1202,10 +1202,10 @@ index 97de35c614e1e9b0e825f9914173a3e1e0e53221..b35b36527294dd697d146d2ad817d791 } } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index fa7885b5ecde24e0d6bd3e8aa49668859ce275ed..0c8e0ce1e02c5865bef855ca8f68c6dfb06eca82 100644 +index fc14fc8017d89c27b0aeb10a5f38dafde5c15f53..70d648bc5e795355d28579cc2fda43c3c9eb255d 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -946,7 +946,7 @@ public abstract class PlayerList { +@@ -943,7 +943,7 @@ public abstract class PlayerList { // CraftBukkit end worldserver1.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper diff --git a/patches/server/0802-Actually-unload-POI-data.patch b/patches/server/0802-Actually-unload-POI-data.patch index 0d8ec84d4e..009a863557 100644 --- a/patches/server/0802-Actually-unload-POI-data.patch +++ b/patches/server/0802-Actually-unload-POI-data.patch @@ -9,19 +9,31 @@ sometimes it is. This patch also prevents the saving/unloading of POI data when world saving is disabled. +diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java +index 2a099fe0d514f181bf2b452d5333bc29b0d29e43..81ea64443a843736f9ada97900d173c302e39ba0 100644 +--- a/src/main/java/net/minecraft/server/ChunkSystem.java ++++ b/src/main/java/net/minecraft/server/ChunkSystem.java +@@ -270,6 +270,7 @@ public final class ChunkSystem { + for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { + chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); + } ++ chunkMap.getPoiManager().dequeueUnload(holder.pos.longKey); // Paper - unload POI data + } + + public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { +@@ -277,6 +278,7 @@ public final class ChunkSystem { + for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { + chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); + } ++ chunkMap.getPoiManager().queueUnload(holder.pos.longKey, MinecraftServer.currentTickLong + 1); // Paper - unload POI data + } + + public static void onChunkBorder(LevelChunk chunk, ChunkHolder holder) { diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index dc8d915956c04b3e9b596e3cb62f1a0498ef1787..39915f1c71fae142725ae2977a4eb0c483b4967a 100644 +index fe10c770b511fa8a38ece2bf9679492a85b28eff..a5e74d30045a171f5ed66a115fbd429e9ab412af 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -866,6 +866,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - // Paper end - } -+ this.getPoiManager().dequeueUnload(holder.pos.longKey); // Paper - unload POI data - - this.updatingChunks.queueUpdate(pos, holder); // Paper - Don't copy - this.modified = true; -@@ -1017,7 +1018,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1016,7 +1016,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private void processUnloads(BooleanSupplier shouldKeepTicking) { LongIterator longiterator = this.toDrop.iterator(); @@ -30,23 +42,7 @@ index dc8d915956c04b3e9b596e3cb62f1a0498ef1787..39915f1c71fae142725ae2977a4eb0c4 long j = longiterator.nextLong(); ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy -@@ -1065,6 +1066,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); - } - // Paper end -+ this.getPoiManager().queueUnload(holder.pos.longKey, MinecraftServer.currentTickLong + 1); // Paper - unload POI data - if (ichunkaccess instanceof LevelChunk) { - ((LevelChunk) ichunkaccess).setLoaded(false); - } -@@ -1094,6 +1096,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - for (int index = 0, len = this.regionManagers.size(); index < len; ++index) { - this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); - } -+ this.getPoiManager().queueUnload(holder.pos.longKey, MinecraftServer.currentTickLong + 1); // Paper - unload POI data - } // Paper end - } finally { this.unloadingPlayerChunk = unloadingBefore; } // Paper - do not allow ticket level changes while unloading chunks - -@@ -1169,6 +1172,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1164,6 +1164,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } this.poiManager.loadInData(pos, chunkHolder.poiData); chunkHolder.tasks.forEach(Runnable::run); diff --git a/patches/server/0806-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch b/patches/server/0806-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch index 8596aa0004..fca5a00257 100644 --- a/patches/server/0806-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch +++ b/patches/server/0806-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch @@ -47,7 +47,7 @@ index 8ff8855c5267379b3a5f5d8baa4a275ffee2c4bf..fc3442b4c7e1f22080fe6bf36d4fade1 ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 6986a170f37f70e8eb89d79d5d2615a06a5e0f0c..c31b9a6b1d4548d507ecb60d42ca9f96f49f6c4b 100644 +index f38ec8914e1953091ab65aa3aaefc886d3eede8a..c2356ed1a00fd8087cca285be5e7f6a5442e73fb 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -298,10 +298,17 @@ public class RegionFileStorage implements AutoCloseable { @@ -79,9 +79,9 @@ index 6986a170f37f70e8eb89d79d5d2615a06a5e0f0c..c31b9a6b1d4548d507ecb60d42ca9f96 - } + // Paper - move into try block to only write if successfully serialized } - - // Paper start -@@ -359,4 +363,13 @@ public class RegionFileStorage implements AutoCloseable { + // Paper start + return; +@@ -358,4 +362,13 @@ public class RegionFileStorage implements AutoCloseable { } } diff --git a/patches/server/0821-Validate-usernames.patch b/patches/server/0821-Validate-usernames.patch index 8422e53312..c032b67744 100644 --- a/patches/server/0821-Validate-usernames.patch +++ b/patches/server/0821-Validate-usernames.patch @@ -56,10 +56,10 @@ index acd581d14e0ef1fe5a6545ee67be00deff589879..553eb8e437b07376dbfc54b0018bcc3f GameProfile gameprofile = this.server.getSingleplayerProfile(); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 0c8e0ce1e02c5865bef855ca8f68c6dfb06eca82..04d2f469dc045152c4fad0427d4d16d80d508f3f 100644 +index 70d648bc5e795355d28579cc2fda43c3c9eb255d..67f90c75aa4858bf1575bf7b0a62b8113de7c2ea 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -717,7 +717,7 @@ public abstract class PlayerList { +@@ -714,7 +714,7 @@ public abstract class PlayerList { for (int i = 0; i < this.players.size(); ++i) { entityplayer = (ServerPlayer) this.players.get(i); diff --git a/patches/server/0824-Expose-vanilla-BiomeProvider-from-WorldInfo.patch b/patches/server/0824-Expose-vanilla-BiomeProvider-from-WorldInfo.patch index c07b3000af..7a4e27a8cd 100644 --- a/patches/server/0824-Expose-vanilla-BiomeProvider-from-WorldInfo.patch +++ b/patches/server/0824-Expose-vanilla-BiomeProvider-from-WorldInfo.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Expose vanilla BiomeProvider from WorldInfo diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 68c0bb1d493b3de3c3e80018a1655ec968b0316a..a4433426efd0823cd8145a50b38127f63e90adc9 100644 +index 857af8ed37c10723d6cd81d7f3c2ba6169021050..28e2f22cc2e5b6dd47705cdd5095ff2394979c8f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -562,7 +562,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index f68a1d5adac4d88c462371c484464bbea22d3147..1bbc73dcdf890a9383795ffeb0d368293f7146a5 100644 +index 7916426a9d7953c2cc15a319adea8d982b63b773..73e7181655b78f5bff90d07edfe6c5408cc08235 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -139,6 +139,7 @@ import org.bukkit.util.Vector; @@ -17,7 +17,7 @@ index f68a1d5adac4d88c462371c484464bbea22d3147..1bbc73dcdf890a9383795ffeb0d36829 private final ServerLevel world; private WorldBorder worldBorder; -@@ -431,27 +432,62 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -419,27 +420,62 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean regenerateChunk(int x, int z) { org.spigotmc.AsyncCatcher.catchOp("chunk regenerate"); // Spigot diff --git a/patches/server/0854-Replace-player-chunk-loader-system.patch b/patches/server/0854-Replace-player-chunk-loader-system.patch index cb165d3086..c06805bfb0 100644 --- a/patches/server/0854-Replace-player-chunk-loader-system.patch +++ b/patches/server/0854-Replace-player-chunk-loader-system.patch @@ -1272,10 +1272,10 @@ index 66afd752fd7d327e141d49b477f07e1ff3645d02..2a26d03fba2f3b37f176be9e47954ef9 // Paper end diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index 1eb71004a19866590a3d27fa6e72842934989177..7034af8ad42940c5af6b9032b9873ce36c55a2a7 100644 +index b575d73ae0ff2e4f09a6a1f6fb061ca3da2cedf1..6939ef9b1fe782980e77c351d8a385a573d6a8e6 100644 --- a/src/main/java/net/minecraft/server/MCUtil.java +++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -647,7 +647,8 @@ public final class MCUtil { +@@ -636,7 +636,8 @@ public final class MCUtil { }); worldData.addProperty("name", world.getWorld().getName()); @@ -1284,9 +1284,9 @@ index 1eb71004a19866590a3d27fa6e72842934989177..7034af8ad42940c5af6b9032b9873ce3 + worldData.addProperty("tick-view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()); // Paper - replace chunk loader system worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); - worldData.addProperty("visible-chunk-count", visibleChunks.size()); + worldData.addProperty("visible-chunk-count", allChunks.size()); diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 5482be03a667939ff009b6810d5cc90c8601e983..11cd31691307749e925930c4b6e10e3f3b4fad25 100644 +index 73712d6b9c828427d4c066c6d8672534575f3793..a041161dee9a857d43c83fb677dba7e90a6a5d24 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -76,6 +76,17 @@ public class ChunkHolder { @@ -1305,9 +1305,9 @@ index 5482be03a667939ff009b6810d5cc90c8601e983..11cd31691307749e925930c4b6e10e3f + } + // Paper end - no-tick view distance - // Paper start - optimise anyPlayerCloseEnoughForSpawning - // cached here to avoid a map lookup -@@ -268,7 +279,7 @@ public class ChunkHolder { + // Paper start + public void onChunkAdd() { +@@ -273,7 +284,7 @@ public class ChunkHolder { public void blockChanged(BlockPos pos) { if (!pos.isInsideBuildHeightAndWorldBoundsHorizontal(levelHeightAccessor)) return; // Paper - SPIGOT-6086 for all invalid locations; avoid acquiring locks @@ -1316,7 +1316,7 @@ index 5482be03a667939ff009b6810d5cc90c8601e983..11cd31691307749e925930c4b6e10e3f if (chunk != null) { int i = this.levelHeightAccessor.getSectionIndex(pos.getY()); -@@ -284,14 +295,15 @@ public class ChunkHolder { +@@ -289,14 +300,15 @@ public class ChunkHolder { } public void sectionLightChanged(LightLayer lightType, int y) { @@ -1336,7 +1336,7 @@ index 5482be03a667939ff009b6810d5cc90c8601e983..11cd31691307749e925930c4b6e10e3f if (chunk != null) { int j = this.lightEngine.getMinLightSection(); -@@ -394,9 +406,28 @@ public class ChunkHolder { +@@ -399,9 +411,28 @@ public class ChunkHolder { } public void broadcast(Packet packet, boolean onlyOnWatchDistanceEdge) { @@ -1369,7 +1369,7 @@ index 5482be03a667939ff009b6810d5cc90c8601e983..11cd31691307749e925930c4b6e10e3f public CompletableFuture> getOrScheduleFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) { diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8d9a4340b 100644 +index a5e74d30045a171f5ed66a115fbd429e9ab412af..47657f20652a80f50a2e46207c9c05d1a12111b4 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -218,6 +218,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -1422,7 +1422,7 @@ index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8 } // Paper end // Paper start -@@ -1449,11 +1453,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1447,11 +1451,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider completablefuture1.thenAcceptAsync((either) -> { either.ifLeft((chunk) -> { this.tickingGenerated.getAndIncrement(); @@ -1435,12 +1435,12 @@ index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8 }); }, (runnable) -> { this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); -@@ -1622,33 +1622,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1620,33 +1620,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int k = this.viewDistance; this.viewDistance = j; - this.distanceManager.updatePlayerTickets(this.viewDistance + 1); -- Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper +- Iterator objectiterator = net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper - - while (objectiterator.hasNext()) { - ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); @@ -1478,16 +1478,16 @@ index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8 if (chunk != null) { this.playerLoadedChunk(player, packet, chunk); -@@ -1679,7 +1670,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1677,7 +1668,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider void dumpChunks(Writer writer) throws IOException { CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); - TickingTracker tickingtracker = this.distanceManager.tickingTracker(); + // Paper - replace loader system - ObjectBidirectionalIterator objectbidirectionaliterator = this.updatingChunks.getVisibleMap().clone().long2ObjectEntrySet().fastIterator(); // Paper + Iterator objectbidirectionaliterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper while (objectbidirectionaliterator.hasNext()) { -@@ -1695,7 +1686,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1693,7 +1684,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // CraftBukkit - decompile error csvwriter.writeRow(chunkcoordintpair.x, chunkcoordintpair.z, playerchunk.getTicketLevel(), optional.isPresent(), optional.map(ChunkAccess::getStatus).orElse(null), optional1.map(LevelChunk::getFullStatus).orElse(null), ChunkMap.printFuture(playerchunk.getFullChunkFuture()), ChunkMap.printFuture(playerchunk.getTickingChunkFuture()), ChunkMap.printFuture(playerchunk.getEntityTickingChunkFuture()), this.distanceManager.getTicketDebugString(i), this.anyPlayerCloseEnoughForSpawning(chunkcoordintpair), optional1.map((chunk) -> { return chunk.getBlockEntities().size(); @@ -1496,7 +1496,7 @@ index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8 return chunk.getBlockTicks().count(); }).orElse(0), optional1.map((chunk) -> { return chunk.getFluidTicks().count(); -@@ -1929,15 +1920,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1927,15 +1918,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.removePlayerFromDistanceMaps(player); // Paper - distance maps } @@ -1513,7 +1513,7 @@ index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8 } -@@ -1945,7 +1928,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1943,7 +1926,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider SectionPos sectionposition = SectionPos.of((EntityAccess) player); player.setLastSectionPos(sectionposition); @@ -1522,7 +1522,7 @@ index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8 return sectionposition; } -@@ -1990,65 +1973,40 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1988,65 +1971,40 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int k1; int l1; @@ -1610,7 +1610,7 @@ index 39915f1c71fae142725ae2977a4eb0c483b4967a..77c89376495d90d0e7cbf6cd02c9a1c8 } public void addEntity(Entity entity) { -@@ -2417,7 +2375,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -2415,7 +2373,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider double vec3d_dx = player.getX() - this.entity.getX(); double vec3d_dz = player.getZ() - this.entity.getZ(); // Paper end - remove allocation of Vec3D here @@ -1797,10 +1797,10 @@ index f581a9f79b2357118d912a15344ff94df3b0c50e..d1b5c25b7455174e908cd6ed66789fa7 + */ // Paper - replace old loader system } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 96a232f22b1c270b91635ce9c7c6cacc63b026cc..59acbf6249f8f5285504c0ddea448a3433d1d68d 100644 +index 3b549ac6d07484a09dc6521cb4f3ab3b3cc979e9..ea1b8f4fd49678f39b1036ae6be880bacc6997f8 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -844,17 +844,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -665,17 +665,10 @@ public class ServerChunkCache extends ChunkSource { // Paper end public boolean isPositionTicking(long pos) { @@ -1822,7 +1822,7 @@ index 96a232f22b1c270b91635ce9c7c6cacc63b026cc..59acbf6249f8f5285504c0ddea448a34 } public void save(boolean flush) { -@@ -911,6 +904,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -732,6 +725,7 @@ public class ServerChunkCache extends ChunkSource { this.level.getProfiler().popPush("chunks"); if (tickChunks) { this.level.timings.chunks.startTiming(); // Paper - timings @@ -1830,7 +1830,7 @@ index 96a232f22b1c270b91635ce9c7c6cacc63b026cc..59acbf6249f8f5285504c0ddea448a34 this.tickChunks(); this.level.timings.chunks.stopTiming(); // Paper - timings } -@@ -1024,13 +1018,13 @@ public class ServerChunkCache extends ChunkSource { +@@ -845,13 +839,13 @@ public class ServerChunkCache extends ChunkSource { // Paper end - optimise chunk tick iteration ChunkPos chunkcoordintpair = chunk1.getPos(); @@ -1846,7 +1846,7 @@ index 96a232f22b1c270b91635ce9c7c6cacc63b026cc..59acbf6249f8f5285504c0ddea448a34 this.level.tickChunk(chunk1, k); if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper } -@@ -1259,6 +1253,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -1080,6 +1074,7 @@ public class ServerChunkCache extends ChunkSource { public boolean pollTask() { try { boolean execChunkTask = com.destroystokyo.paper.io.chunk.ChunkTaskManager.pollChunkWaitQueue() || ServerChunkCache.this.level.asyncChunkTaskManager.pollNextChunkTask(); // Paper @@ -1855,10 +1855,10 @@ index 96a232f22b1c270b91635ce9c7c6cacc63b026cc..59acbf6249f8f5285504c0ddea448a34 return true; } else { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 502a11fbef542891358589f00cf4a267dca9bc9a..9dc4a1d9082a0cb3ab6848698c3fc41a5f57e380 100644 +index 3bb6dbdd05ed981f70556c8f905d1eeeeade30b8..e71ae32d9827d8a6fb8543abdba7627897ac9f2e 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -680,7 +680,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -682,7 +682,7 @@ public class ServerLevel extends Level implements WorldGenLevel { gameprofilerfiller.push("checkDespawn"); entity.checkDespawn(); gameprofilerfiller.pop(); @@ -1867,7 +1867,7 @@ index 502a11fbef542891358589f00cf4a267dca9bc9a..9dc4a1d9082a0cb3ab6848698c3fc41a Entity entity1 = entity.getVehicle(); if (entity1 != null) { -@@ -713,7 +713,10 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -715,7 +715,10 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public boolean shouldTickBlocksAt(long chunkPos) { @@ -1879,7 +1879,7 @@ index 502a11fbef542891358589f00cf4a267dca9bc9a..9dc4a1d9082a0cb3ab6848698c3fc41a } protected void tickTime() { -@@ -2457,7 +2460,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2459,7 +2462,7 @@ public class ServerLevel extends Level implements WorldGenLevel { private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) { // Paper start - optimize is ticking ready type functions ChunkHolder chunkHolder = this.chunkSource.chunkMap.getVisibleChunkIfPresent(chunkPos); @@ -1900,10 +1900,10 @@ index b35b36527294dd697d146d2ad817d7911145ae8c..18c3d4aecf498f78040c27336d2ea56f + public final int getViewDistance() { throw new UnsupportedOperationException("Use PlayerChunkLoader"); } // Paper - placeholder } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 04d2f469dc045152c4fad0427d4d16d80d508f3f..525b385cfd216f8ff2de02439c5cd0f8d77c5d42 100644 +index 67f90c75aa4858bf1575bf7b0a62b8113de7c2ea..b588e14b2826bda5b03b4fc497efcb96b566541a 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -274,7 +274,7 @@ public abstract class PlayerList { +@@ -276,7 +276,7 @@ public abstract class PlayerList { boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO); // Spigot - view distance @@ -1912,7 +1912,7 @@ index 04d2f469dc045152c4fad0427d4d16d80d508f3f..525b385cfd216f8ff2de02439c5cd0f8 player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf(this.getServer().getServerModName()))); playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); -@@ -952,8 +952,8 @@ public abstract class PlayerList { +@@ -949,8 +949,8 @@ public abstract class PlayerList { // CraftBukkit start LevelData worlddata = worldserver1.getLevelData(); entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), flag, entityplayer1.getLastDeathLocation())); @@ -1923,7 +1923,7 @@ index 04d2f469dc045152c4fad0427d4d16d80d508f3f..525b385cfd216f8ff2de02439c5cd0f8 entityplayer1.spawnIn(worldserver1); entityplayer1.unsetRemoved(); entityplayer1.connection.teleport(new Location(worldserver1.getWorld(), entityplayer1.getX(), entityplayer1.getY(), entityplayer1.getZ(), entityplayer1.getYRot(), entityplayer1.getXRot())); -@@ -1522,7 +1522,7 @@ public abstract class PlayerList { +@@ -1519,7 +1519,7 @@ public abstract class PlayerList { public void setViewDistance(int viewDistance) { this.viewDistance = viewDistance; @@ -1932,7 +1932,7 @@ index 04d2f469dc045152c4fad0427d4d16d80d508f3f..525b385cfd216f8ff2de02439c5cd0f8 Iterator iterator = this.server.getAllLevels().iterator(); while (iterator.hasNext()) { -@@ -1537,7 +1537,7 @@ public abstract class PlayerList { +@@ -1534,7 +1534,7 @@ public abstract class PlayerList { public void setSimulationDistance(int simulationDistance) { this.simulationDistance = simulationDistance; @@ -2079,10 +2079,10 @@ index d870cefbe5b7485f423817f4f639e3e2a304640c..2292cb0e0c1a3e0ed34b941f028136bf @Nullable diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 1bbc73dcdf890a9383795ffeb0d368293f7146a5..c4f7aa9ffb72d2bc555ace64bb8cedc5c2545d8b 100644 +index 73e7181655b78f5bff90d07edfe6c5408cc08235..1e179d8ff339c6647fed1a3d2a1c010737d37dc6 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2281,43 +2281,56 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2234,43 +2234,56 @@ public class CraftWorld extends CraftRegionAccessor implements World { // Spigot start @Override public int getViewDistance() { @@ -2148,7 +2148,7 @@ index 1bbc73dcdf890a9383795ffeb0d368293f7146a5..c4f7aa9ffb72d2bc555ace64bb8cedc5 // Paper end - view distance api diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index dc5ef870e23ba9497fcb9c2961334d928213f4c2..77339926519057b1c878761780ff2d6621f5ccb7 100644 +index 86d9250ce0a49635362a2710bf3c064936d1c77f..16fa7bdb8cc4bcad01ed33455cf1e51b69e2f720 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -541,45 +541,80 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0856-Force-close-world-loading-screen.patch b/patches/server/0856-Force-close-world-loading-screen.patch index e55a25678b..1f75753d30 100644 --- a/patches/server/0856-Force-close-world-loading-screen.patch +++ b/patches/server/0856-Force-close-world-loading-screen.patch @@ -10,10 +10,10 @@ so we do not need that. The client only needs the chunk it is currently in to be loaded to close the loading screen, so we just send an empty one. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 525b385cfd216f8ff2de02439c5cd0f8d77c5d42..26345ddd671175b9dfd457750ae0da7042ec649f 100644 +index b588e14b2826bda5b03b4fc497efcb96b566541a..5a5ea1f9d6e978916d32b170ecf7f848d2524303 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -432,6 +432,16 @@ public abstract class PlayerList { +@@ -429,6 +429,16 @@ public abstract class PlayerList { // Paper start - move vehicle into method so it can be called above - short circuit around that code onPlayerJoinFinish(player, worldserver1, s1); diff --git a/patches/server/0857-Fix-falling-block-spawn-methods.patch b/patches/server/0857-Fix-falling-block-spawn-methods.patch index 3c1270d7c9..f72c2de50f 100644 --- a/patches/server/0857-Fix-falling-block-spawn-methods.patch +++ b/patches/server/0857-Fix-falling-block-spawn-methods.patch @@ -21,10 +21,10 @@ index d1fca0e3227b5f37c11367548be362f5a49b6a71..5628940cd3c3566c5db2beda506d4f20 if (Snowball.class.isAssignableFrom(clazz)) { entity = new net.minecraft.world.entity.projectile.Snowball(world, x, y, z); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index c4f7aa9ffb72d2bc555ace64bb8cedc5c2545d8b..3aa4363793ea0b2de4224010b51e9798bc77ec2c 100644 +index 1e179d8ff339c6647fed1a3d2a1c010737d37dc6..ea26283265902cf05151283c4abc7db9e30f2559 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1417,7 +1417,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1405,7 +1405,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { Validate.notNull(material, "Material cannot be null"); Validate.isTrue(material.isBlock(), "Material must be a block"); @@ -38,7 +38,7 @@ index c4f7aa9ffb72d2bc555ace64bb8cedc5c2545d8b..3aa4363793ea0b2de4224010b51e9798 return (FallingBlock) entity.getBukkitEntity(); } -@@ -1426,7 +1431,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1414,7 +1419,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { Validate.notNull(location, "Location cannot be null"); Validate.notNull(data, "BlockData cannot be null"); diff --git a/patches/server/0860-Fix-save-problems-on-shutdown.patch b/patches/server/0860-Fix-save-problems-on-shutdown.patch index 4ae525c1f1..b07c4721de 100644 --- a/patches/server/0860-Fix-save-problems-on-shutdown.patch +++ b/patches/server/0860-Fix-save-problems-on-shutdown.patch @@ -55,10 +55,10 @@ index df08b7afcf19ce694a87c25e8589c0c72521c5db..4d920031300a9801debc2eb39a4d3cb9 if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken return this.forceTicks || this.runningTask() || Util.getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 9dc4a1d9082a0cb3ab6848698c3fc41a5f57e380..95c2f8d70eff220dd53a6779e105a9bb67e47b6a 100644 +index e71ae32d9827d8a6fb8543abdba7627897ac9f2e..eceaa1f2ede1c068f9090d13bf9d3b3afaa08cc3 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1282,7 +1282,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1284,7 +1284,13 @@ public class ServerLevel extends Level implements WorldGenLevel { } } diff --git a/patches/server/0880-Use-username-instead-of-display-name-in-PlayerList-g.patch b/patches/server/0880-Use-username-instead-of-display-name-in-PlayerList-g.patch index 0c9a4f6f91..2accf61444 100644 --- a/patches/server/0880-Use-username-instead-of-display-name-in-PlayerList-g.patch +++ b/patches/server/0880-Use-username-instead-of-display-name-in-PlayerList-g.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Use username instead of display name in diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 26345ddd671175b9dfd457750ae0da7042ec649f..e1b6017953edffcea0be81b70cf7b22ce8c0570d 100644 +index 5a5ea1f9d6e978916d32b170ecf7f848d2524303..5999d85e38951503fc83b40cfe39671921ae5088 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1486,7 +1486,7 @@ public abstract class PlayerList { +@@ -1483,7 +1483,7 @@ public abstract class PlayerList { // CraftBukkit start public ServerStatsCounter getPlayerStats(ServerPlayer entityhuman) { ServerStatsCounter serverstatisticmanager = entityhuman.getStats(); diff --git a/patches/server/0882-Pass-ServerLevel-for-gamerule-callbacks.patch b/patches/server/0882-Pass-ServerLevel-for-gamerule-callbacks.patch index 649425acbe..cb27fe4e42 100644 --- a/patches/server/0882-Pass-ServerLevel-for-gamerule-callbacks.patch +++ b/patches/server/0882-Pass-ServerLevel-for-gamerule-callbacks.patch @@ -158,10 +158,10 @@ index 3c93bfeb94168f832904a8462ae23b06e81e080d..468c635d31cfa8051666bbefce8df4b4 this.onChanged(server); } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 3aa4363793ea0b2de4224010b51e9798bc77ec2c..a5d8dfc77475845be7c6d37eed04fb19eeef1c0c 100644 +index ea26283265902cf05151283c4abc7db9e30f2559..d5f2a83296ae25e41629f3ab114c067dda1c7f33 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1921,7 +1921,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1909,7 +1909,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { // Paper end GameRules.Value handle = this.getHandle().getGameRules().getRule(CraftWorld.getGameRulesNMS().get(rule)); handle.deserialize(event.getValue()); // Paper @@ -170,7 +170,7 @@ index 3aa4363793ea0b2de4224010b51e9798bc77ec2c..a5d8dfc77475845be7c6d37eed04fb19 return true; } -@@ -1961,7 +1961,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1949,7 +1949,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { // Paper end GameRules.Value handle = this.getHandle().getGameRules().getRule(CraftWorld.getGameRulesNMS().get(rule.getName())); handle.deserialize(event.getValue()); // Paper diff --git a/patches/server/0892-Don-t-tick-markers.patch b/patches/server/0892-Don-t-tick-markers.patch index eaf0d00d81..d21ff9fe5a 100644 --- a/patches/server/0892-Don-t-tick-markers.patch +++ b/patches/server/0892-Don-t-tick-markers.patch @@ -22,10 +22,10 @@ index 68f99e93ed3e843b4001a7a27620f88a48b85e67..0dc96c39151ec4dbeec3947cb17606f5 } }); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 95c2f8d70eff220dd53a6779e105a9bb67e47b6a..43df2ed0f464a0e7be188b7efea723215dbaf527 100644 +index eceaa1f2ede1c068f9090d13bf9d3b3afaa08cc3..e5a64e70020487b15825a865623afa45b0ae59d4 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2493,6 +2493,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2495,6 +2495,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void onTickingStart(Entity entity) { diff --git a/patches/server/0901-Add-Alternate-Current-redstone-implementation.patch b/patches/server/0901-Add-Alternate-Current-redstone-implementation.patch index e155fcdd0a..f0b286c6c2 100644 --- a/patches/server/0901-Add-Alternate-Current-redstone-implementation.patch +++ b/patches/server/0901-Add-Alternate-Current-redstone-implementation.patch @@ -2008,7 +2008,7 @@ index 0000000000000000000000000000000000000000..33cd90c30c22200a4e1ae64f40a0bf78 + } +} diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 43df2ed0f464a0e7be188b7efea723215dbaf527..43aa4eee00502d1f05acc5f7e4e92db98063accd 100644 +index e5a64e70020487b15825a865623afa45b0ae59d4..684063b8433f78ef0adf0de1057ea24720b32181 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -219,6 +219,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -2019,7 +2019,7 @@ index 43df2ed0f464a0e7be188b7efea723215dbaf527..43aa4eee00502d1f05acc5f7e4e92db9 public static Throwable getAddToWorldStackTrace(Entity entity) { return new Throwable(entity + " Added to world at " + new java.util.Date()); } -@@ -2482,6 +2483,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2484,6 +2485,13 @@ public class ServerLevel extends Level implements WorldGenLevel { return this.entityManager.canPositionTick(pos.toLong()); // Paper } diff --git a/patches/server/0909-Prevent-empty-items-from-being-added-to-world.patch b/patches/server/0909-Prevent-empty-items-from-being-added-to-world.patch index 286893bc24..2e13972f86 100644 --- a/patches/server/0909-Prevent-empty-items-from-being-added-to-world.patch +++ b/patches/server/0909-Prevent-empty-items-from-being-added-to-world.patch @@ -7,10 +7,10 @@ The previous solution caused a bunch of bandaid fixes inorder to resolve edge ca Just simply prevent them from being added to the world instead. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 43aa4eee00502d1f05acc5f7e4e92db98063accd..3d986805c89d22330d6ad1e09760940b2f399214 100644 +index 684063b8433f78ef0adf0de1057ea24720b32181..96bb0e56f12437037b598cd7baabf369e5994517 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1437,6 +1437,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1439,6 +1439,7 @@ public class ServerLevel extends Level implements WorldGenLevel { // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit return false; } else { diff --git a/patches/server/0919-More-Teleport-API.patch b/patches/server/0919-More-Teleport-API.patch index 735a1effb8..e133efa140 100644 --- a/patches/server/0919-More-Teleport-API.patch +++ b/patches/server/0919-More-Teleport-API.patch @@ -29,10 +29,10 @@ index 13c253b1d7f6d4713135baba2bc2ad9cd84224f8..0e365529695321ab2b164c75d4c67bdd d0 = to.getX(); d1 = to.getY(); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 2a6c67634c31c332102d24bef293da1bacd0c000..b80cc0938b2b3928f4450f1314a9fbd7ea9c116b 100644 +index 0bae967bb9830784d98c2a1cccca512660c6324a..cc7b76a66d87ffa30c4bf6e3c1123df86d73b571 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -571,15 +571,33 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -540,15 +540,33 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @Override public boolean teleport(Location location, TeleportCause cause) { @@ -69,10 +69,10 @@ index 2a6c67634c31c332102d24bef293da1bacd0c000..b80cc0938b2b3928f4450f1314a9fbd7 // Let the server handle cross world teleports if (location.getWorld() != null && !location.getWorld().equals(this.getWorld())) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 77339926519057b1c878761780ff2d6621f5ccb7..6f0ffd1895a9c392b643f3595e709ec3706c39b4 100644 +index 16fa7bdb8cc4bcad01ed33455cf1e51b69e2f720..a8e63a417ab4971ce35569dbb0b792635e8366ae 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1135,7 +1135,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1135,13 +1135,92 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setRotation(float yaw, float pitch) { @@ -88,9 +88,6 @@ index 77339926519057b1c878761780ff2d6621f5ccb7..6f0ffd1895a9c392b643f3595e709ec3 + // Paper end } - // Paper start - Chunk priority -@@ -1150,8 +1158,79 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - @Override public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) { + // Paper start - Teleport API @@ -169,7 +166,7 @@ index 77339926519057b1c878761780ff2d6621f5ccb7..6f0ffd1895a9c392b643f3595e709ec3 location.checkFinite(); ServerPlayer entity = this.getHandle(); -@@ -1164,7 +1243,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1154,7 +1233,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return false; } @@ -178,7 +175,7 @@ index 77339926519057b1c878761780ff2d6621f5ccb7..6f0ffd1895a9c392b643f3595e709ec3 return false; } -@@ -1182,7 +1261,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1172,7 +1251,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } // If this player is riding another entity, we must dismount before teleporting. @@ -187,7 +184,7 @@ index 77339926519057b1c878761780ff2d6621f5ccb7..6f0ffd1895a9c392b643f3595e709ec3 // SPIGOT-5509: Wakeup, similar to riding if (this.isSleeping()) { -@@ -1204,7 +1283,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1194,7 +1273,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { // Check if the fromWorld and toWorld are the same. if (fromWorld == toWorld) { diff --git a/patches/server/0923-Warn-on-plugins-accessing-faraway-chunks.patch b/patches/server/0923-Warn-on-plugins-accessing-faraway-chunks.patch index 069ec6a90b..6b7a35a426 100644 --- a/patches/server/0923-Warn-on-plugins-accessing-faraway-chunks.patch +++ b/patches/server/0923-Warn-on-plugins-accessing-faraway-chunks.patch @@ -18,10 +18,10 @@ index 9467ccaa1d73e1913495a46919aee530e749977d..5a2a1d394852d39ea576624586f7fa73 private static boolean isOutsideSpawnableHeight(int y) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index a5d8dfc77475845be7c6d37eed04fb19eeef1c0c..f0b14914438840bd819fa7da8b76f4fcc13704d0 100644 +index d5f2a83296ae25e41629f3ab114c067dda1c7f33..4c5145ed32a22080a88d25e2dbb7cfde2f6bbc4f 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -314,9 +314,24 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -313,9 +313,24 @@ public class CraftWorld extends CraftRegionAccessor implements World { public boolean setSpawnLocation(int x, int y, int z) { return this.setSpawnLocation(x, y, z, 0.0F); } @@ -46,7 +46,7 @@ index a5d8dfc77475845be7c6d37eed04fb19eeef1c0c..f0b14914438840bd819fa7da8b76f4fc // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it net.minecraft.world.level.chunk.LevelChunk chunk = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); if (chunk == null) { -@@ -432,6 +447,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -420,6 +435,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean regenerateChunk(int x, int z) { org.spigotmc.AsyncCatcher.catchOp("chunk regenerate"); // Spigot @@ -54,7 +54,7 @@ index a5d8dfc77475845be7c6d37eed04fb19eeef1c0c..f0b14914438840bd819fa7da8b76f4fc // Paper start - implement regenerateChunk method final ServerLevel serverLevel = this.world; final net.minecraft.server.level.ServerChunkCache serverChunkCache = serverLevel.getChunkSource(); -@@ -525,6 +541,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -513,6 +529,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean loadChunk(int x, int z, boolean generate) { org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot @@ -62,7 +62,7 @@ index a5d8dfc77475845be7c6d37eed04fb19eeef1c0c..f0b14914438840bd819fa7da8b76f4fc // Paper start - Optimize this method ChunkPos chunkPos = new ChunkPos(x, z); ChunkAccess immediate = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); // Paper -@@ -589,6 +606,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -577,6 +594,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean addPluginChunkTicket(int x, int z, Plugin plugin) { @@ -70,7 +70,7 @@ index a5d8dfc77475845be7c6d37eed04fb19eeef1c0c..f0b14914438840bd819fa7da8b76f4fc Preconditions.checkArgument(plugin != null, "null plugin"); Preconditions.checkArgument(plugin.isEnabled(), "plugin is not enabled"); -@@ -670,6 +688,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -658,6 +676,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setChunkForceLoaded(int x, int z, boolean forced) { @@ -78,7 +78,7 @@ index a5d8dfc77475845be7c6d37eed04fb19eeef1c0c..f0b14914438840bd819fa7da8b76f4fc this.getHandle().setChunkForced(x, z, forced); } -@@ -981,6 +1000,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -969,6 +988,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) { @@ -86,9 +86,9 @@ index a5d8dfc77475845be7c6d37eed04fb19eeef1c0c..f0b14914438840bd819fa7da8b76f4fc // Transient load for this tick return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z); } -@@ -2238,6 +2258,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2330,6 +2350,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + // Spigot end // Paper start - @Override public java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { + warnUnsafeChunk("getting a faraway chunk async", x, z); // Paper if (Bukkit.isPrimaryThread()) { diff --git a/patches/server/0936-Workaround-for-client-lag-spikes-MC-162253.patch b/patches/server/0936-Workaround-for-client-lag-spikes-MC-162253.patch index 4e963d9792..7da4def3c8 100644 --- a/patches/server/0936-Workaround-for-client-lag-spikes-MC-162253.patch +++ b/patches/server/0936-Workaround-for-client-lag-spikes-MC-162253.patch @@ -16,10 +16,10 @@ Co-authored-by: =?UTF-8?q?Dani=C3=ABl=20Goossens?= Co-authored-by: Nassim Jahnke diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 77c89376495d90d0e7cbf6cd02c9a1c8d9a4340b..649355158ed435e242a48f4aaa4578bcc2a808dd 100644 +index 47657f20652a80f50a2e46207c9c05d1a12111b4..c2c01988bf3b6fbb0a7a4716373c2ff0cffce27d 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -2171,6 +2171,46 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -2169,6 +2169,46 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -66,7 +66,7 @@ index 77c89376495d90d0e7cbf6cd02c9a1c8d9a4340b..649355158ed435e242a48f4aaa4578bc // Paper start - Anti-Xray - Bypass private void playerLoadedChunk(ServerPlayer player, MutableObject> cachedDataPackets, LevelChunk chunk) { if (cachedDataPackets.getValue() == null) { -@@ -2179,6 +2219,45 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -2177,6 +2217,45 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider Boolean shouldModify = chunk.getLevel().chunkPacketBlockController.shouldModify(player, chunk); player.trackChunk(chunk.getPos(), (Packet) cachedDataPackets.getValue().computeIfAbsent(shouldModify, (s) -> {