From 0763e306cf2a564d4f82ee03671f928c8bc769f2 Mon Sep 17 00:00:00 2001 From: Elier <71361901+Elierrr@users.noreply.github.com> Date: Wed, 19 Jan 2022 18:07:05 -0500 Subject: [PATCH] Update Guava and GSON (#323) * Update Guava and gson * Update CraftServer.java * Update EntitySlice.java * Update BlockState.java * Update BaseBlockPosition.java * Update BlockStateList.java * Update PacketPlayOutPlayerInfo.java * Fix compile errors * Some fixes * Add old Objects * Finally get WorldGuard working * Fix Java 9-15 * Add tests * Use Java 17 for workflows * Revert "Add tests" This reverts commit 0c0461f76cad0a25c4ee34a3ddeb6b11473c9f51. * Reverting everything * Overwrite Guava classes instead of modifing them at runtime --- .github/workflows/build-nachospigot.yml | 4 +- .github/workflows/test-pr.yml | 4 +- NachoSpigot-API/pom.xml | 16 +- .../java/com/google/common/base/Objects.java | 451 +++++++ .../common/util/concurrent/MoreExecutors.java | 1172 +++++++++++++++++ NachoSpigot-Server/pom.xml | 4 +- .../minecraft/server/BaseBlockPosition.java | 4 +- .../java/net/minecraft/server/BlockState.java | 4 +- .../net/minecraft/server/BlockStateList.java | 4 +- .../minecraft/server/BlockTripwireHook.java | 4 +- .../net/minecraft/server/EntitySlice.java | 4 +- .../net/minecraft/server/MinecraftServer.java | 2 +- .../server/PacketPlayOutPlayerInfo.java | 6 +- .../net/minecraft/server/ShapeDetector.java | 164 +++ .../server/StructureBoundingBox.java | 153 +++ .../net/minecraft/server/WorldGenCaves.java | 274 ++++ .../org/bukkit/craftbukkit/CraftServer.java | 2 +- pom.xml | 1 - 18 files changed, 2239 insertions(+), 34 deletions(-) create mode 100644 NachoSpigot-API/src/main/java/com/google/common/base/Objects.java create mode 100644 NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java create mode 100644 NachoSpigot-Server/src/main/java/net/minecraft/server/ShapeDetector.java create mode 100644 NachoSpigot-Server/src/main/java/net/minecraft/server/StructureBoundingBox.java create mode 100644 NachoSpigot-Server/src/main/java/net/minecraft/server/WorldGenCaves.java diff --git a/.github/workflows/build-nachospigot.yml b/.github/workflows/build-nachospigot.yml index ad215daca..52451ed0d 100644 --- a/.github/workflows/build-nachospigot.yml +++ b/.github/workflows/build-nachospigot.yml @@ -8,10 +8,10 @@ jobs: if: "!contains(github.event.head_commit.message, '[skip]')" steps: - uses: actions/checkout@v2 - - name: Set up JDK 15 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 15 + java-version: 17 server-id: github settings-path: ${{ github.workspace }} diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 36e3241d0..55ff3948d 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -9,10 +9,10 @@ jobs: if: ${{ !contains(github.event.head_commit.message, '[skip]') || github.repository != github.event.pull_request.head.repo.full_name}} steps: - uses: actions/checkout@v2 - - name: Set up JDK 15 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 15 + java-version: 17 server-id: github settings-path: ${{ github.workspace }} - name: Install minecraft-server to local repo diff --git a/NachoSpigot-API/pom.xml b/NachoSpigot-API/pom.xml index 7f3934285..3f8face3b 100644 --- a/NachoSpigot-API/pom.xml +++ b/NachoSpigot-API/pom.xml @@ -1,4 +1,3 @@ - 4.0.0 @@ -7,6 +6,7 @@ dev.cobblesword.nachospigot parent dev-SNAPSHOT + ../pom.xml api @@ -44,25 +44,17 @@ jar compile - com.google.guava guava - 17.0 + + 31.0.1-jre compile - - - - - - - - com.google.code.gson gson - 2.2.4 + 2.8.9 org.avaje diff --git a/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java b/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java new file mode 100644 index 000000000..0101907a6 --- /dev/null +++ b/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +import javax.annotation.CheckReturnValue; +import javax.annotation.Nullable; +import java.util.Arrays; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helper functions that can operate on any {@code Object}. + * + *

See the Guava User Guide on writing + * {@code Object} methods with {@code Objects}. + * + * @author Laurence Gonsalves + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public final class Objects { + private Objects() {} + + /** + * Determines whether two possibly-null objects are equal. Returns: + * + *

+ * + *

This assumes that any non-null objects passed to this function conform + * to the {@code equals()} contract. + */ + @CheckReturnValue + public static boolean equal(@Nullable Object a, @Nullable Object b) { + return java.util.Objects.equals(a, b); // Nacho + } + + /** + * Generates a hash code for multiple values. The hash code is generated by + * calling {@link Arrays#hashCode(Object[])}. Note that array arguments to + * this method, with the exception of a single Object array, do not get any + * special handling; their hash codes are based on identity and not contents. + * + *

This is useful for implementing {@link Object#hashCode()}. For example, + * in an object that has three properties, {@code x}, {@code y}, and + * {@code z}, one could write: + *

   {@code
+     *   public int hashCode() {
+     *     return Objects.hashCode(getX(), getY(), getZ());
+     *   }}
+ * + *

Warning: When a single object is supplied, the returned hash code + * does not equal the hash code of that object. + */ + public static int hashCode(@Nullable Object... objects) { + return Arrays.hashCode(objects); + } + + // Nacho start + /** + * Creates an instance of {@link ToStringHelper}. + * + *

This is helpful for implementing {@link Object#toString()}. + * Specification by example:

   {@code
+     *   // Returns "ClassName{}"
+     *   Objects.toStringHelper(this)
+     *       .toString();
+     *
+     *   // Returns "ClassName{x=1}"
+     *   Objects.toStringHelper(this)
+     *       .add("x", 1)
+     *       .toString();
+     *
+     *   // Returns "MyObject{x=1}"
+     *   Objects.toStringHelper("MyObject")
+     *       .add("x", 1)
+     *       .toString();
+     *
+     *   // Returns "ClassName{x=1, y=foo}"
+     *   Objects.toStringHelper(this)
+     *       .add("x", 1)
+     *       .add("y", "foo")
+     *       .toString();
+     *
+     *   // Returns "ClassName{x=1}"
+     *   Objects.toStringHelper(this)
+     *       .omitNullValues()
+     *       .add("x", 1)
+     *       .add("y", null)
+     *       .toString();
+     *   }}
+ * + *

Note that in GWT, class names are often obfuscated. + * + * @param self the object to generate the string for (typically {@code this}), + * used only for its class name + * @since 2.0 + * @deprecated replaced by {@link MoreObjects#toStringHelper(Object)} + * @see MoreObjects#toStringHelper(Object) + */ + @Deprecated + public static ToStringHelper toStringHelper(Object self) { + return new ToStringHelper(simpleName(self.getClass())); + } + + /** + * Creates an instance of {@link ToStringHelper} in the same manner as + * {@link Objects#toStringHelper(Object)}, but using the name of {@code clazz} + * instead of using an instance's {@link Object#getClass()}. + * + *

Note that in GWT, class names are often obfuscated. + * + * @param clazz the {@link Class} of the instance + * @since 7.0 (source-compatible since 2.0) + * @deprecated replaced by {@link MoreObjects#toStringHelper(Class)} + * @see MoreObjects#toStringHelper(Class) + */ + @Deprecated + public static ToStringHelper toStringHelper(Class clazz) { + return new ToStringHelper(simpleName(clazz)); + } + + /** + * Creates an instance of {@link ToStringHelper} in the same manner as + * {@link Objects#toStringHelper(Object)}, but using {@code className} instead + * of using an instance's {@link Object#getClass()}. + * + * @param className the name of the instance type + * @since 7.0 (source-compatible since 2.0) + * @deprecated replaced by {@link MoreObjects#toStringHelper(String)} + * @see MoreObjects#toStringHelper(String) + */ + @Deprecated + public static ToStringHelper toStringHelper(String className) { + return new ToStringHelper(className); + } + + /** + * {@link Class#getSimpleName()} is not GWT compatible yet, so we + * provide our own implementation. + * @deprecated {@link Class#getSimpleName()} is now GWT compatible, use it instead + * @see Class#getSimpleName() + */ + @Deprecated + private static String simpleName(Class clazz) { + String name = clazz.getName(); + + // the nth anonymous class has a class name ending in "Outer$n" + // and local inner classes have names ending in "Outer.$1Inner" + name = name.replaceAll("\\$[0-9]+", "\\$"); + + // we want the name of the inner class all by its lonesome + int start = name.lastIndexOf('$'); + + // if this isn't an inner class, just find the start of the + // top level class name. + if (start == -1) { + start = name.lastIndexOf('.'); + } + return name.substring(start + 1); + } + + /** + * Returns the first of two given parameters that is not {@code null}, if + * either is, or otherwise throws a {@link NullPointerException}. + * + *

Note: if {@code first} is represented as an {@link Optional}, + * this can be accomplished with + * {@linkplain Optional#or(Object) first.or(second)}. + * That approach also allows for lazy evaluation of the fallback instance, + * using {@linkplain Optional#or(Supplier) first.or(Supplier)}. + * + * @return {@code first} if {@code first} is not {@code null}, or + * {@code second} if {@code first} is {@code null} and {@code second} is + * not {@code null} + * @throws NullPointerException if both {@code first} and {@code second} were + * {@code null} + * @since 3.0 + * @deprecated replaced by {@link MoreObjects#firstNonNull(Object, Object)} + * @see MoreObjects#firstNonNull(Object, Object) + */ + @Deprecated + public static T firstNonNull(@Nullable T first, @Nullable T second) { + return first != null ? first : checkNotNull(second); + } + + /** + * Support class for {@link Objects#toStringHelper}. + * + * @author Jason Lee + * @since 2.0 + * @deprecated replaced by {@link MoreObjects.ToStringHelper} + * @see MoreObjects.ToStringHelper + */ + @Deprecated + public static final class ToStringHelper { + private final String className; + private ValueHolder holderHead = new ValueHolder(); + private ValueHolder holderTail = holderHead; + private boolean omitNullValues = false; + + /** + * Use {@link Objects#toStringHelper(Object)} to create an instance. + */ + private ToStringHelper(String className) { + this.className = checkNotNull(className); + } + + /** + * Configures the {@link ToStringHelper} so {@link #toString()} will ignore + * properties with null value. The order of calling this method, relative + * to the {@code add()}/{@code addValue()} methods, is not significant. + * + * @since 12.0 + */ + public ToStringHelper omitNullValues() { + omitNullValues = true; + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. If {@code value} is {@code null}, the string {@code "null"} + * is used, unless {@link #omitNullValues()} is called, in which case this + * name/value pair will not be added. + */ + public ToStringHelper add(String name, @Nullable Object value) { + return addHolder(name, value); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, boolean value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, char value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, double value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, float value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, int value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, long value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, Object)} instead + * and give value a readable name. + */ + public ToStringHelper addValue(@Nullable Object value) { + return addHolder(value); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, boolean)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(boolean value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, char)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(char value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, double)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(double value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, float)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(float value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, int)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(int value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, long)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(long value) { + return addHolder(String.valueOf(value)); + } + + /** + * Returns a string in the format specified by {@link + * Objects#toStringHelper(Object)}. + * + *

After calling this method, you can keep adding more properties to later + * call toString() again and get a more complete representation of the + * same object; but properties cannot be removed, so this only allows + * limited reuse of the helper instance. The helper allows duplication of + * properties (multiple name/value pairs with the same name can be added). + */ + @Override public String toString() { + // create a copy to keep it consistent in case value changes + boolean omitNullValuesSnapshot = omitNullValues; + String nextSeparator = ""; + StringBuilder builder = new StringBuilder(32).append(className) + .append('{'); + for (ValueHolder valueHolder = holderHead.next; valueHolder != null; + valueHolder = valueHolder.next) { + if (!omitNullValuesSnapshot || valueHolder.value != null) { + builder.append(nextSeparator); + nextSeparator = ", "; + + if (valueHolder.name != null) { + builder.append(valueHolder.name).append('='); + } + builder.append(valueHolder.value); + } + } + return builder.append('}').toString(); + } + + private ValueHolder addHolder() { + ValueHolder valueHolder = new ValueHolder(); + holderTail = holderTail.next = valueHolder; + return valueHolder; + } + + private ToStringHelper addHolder(@Nullable Object value) { + ValueHolder valueHolder = addHolder(); + valueHolder.value = value; + return this; + } + + private ToStringHelper addHolder(String name, @Nullable Object value) { + ValueHolder valueHolder = addHolder(); + valueHolder.value = value; + valueHolder.name = checkNotNull(name); + return this; + } + + private static final class ValueHolder { + String name; + Object value; + ValueHolder next; + } + } + // Nacho end +} \ No newline at end of file diff --git a/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java new file mode 100644 index 000000000..24b84d3c7 --- /dev/null +++ b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java @@ -0,0 +1,1172 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.common.util.concurrent; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.util.concurrent.Internal.toNanosSaturated; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.google.common.collect.Queues; +import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.concurrent.GuardedBy; +import java.lang.reflect.InvocationTargetException; +import java.time.Duration; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.Delayed; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Factory and utility methods for {@link java.util.concurrent.Executor}, {@link ExecutorService}, + * and {@link java.util.concurrent.ThreadFactory}. + * + * @author Eric Fellheimer + * @author Kyle Littlefield + * @author Justin Mahoney + * @since 3.0 + */ +@GwtCompatible(emulated = true) +@ElementTypesAreNonnullByDefault +public final class MoreExecutors { + private MoreExecutors() {} + + /** + * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application + * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their + * completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @return an unmodifiable version of the input which will not hang the JVM + * @since 28.0 + */ + @Beta + @GwtIncompatible // TODO + public static ExecutorService getExitingExecutorService( + ThreadPoolExecutor executor, Duration terminationTimeout) { + return getExitingExecutorService( + executor, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); + } + + /** + * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application + * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their + * completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @param timeUnit unit of time for the time parameter + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // TODO + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static ExecutorService getExitingExecutorService( + ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + return new Application().getExitingExecutorService(executor, terminationTimeout, timeUnit); + } + + /** + * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application + * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their + * completion. + * + *

This method waits 120 seconds before continuing with JVM termination, even if the executor + * has not finished its work. + * + *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // concurrency + public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { + return new Application().getExitingExecutorService(executor); + } + + /** + * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when + * the application is complete. It does so by using daemon threads and adding a shutdown hook to + * wait for their completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @return an unmodifiable version of the input which will not hang the JVM + * @since 28.0 + */ + @Beta + @GwtIncompatible // java.time.Duration + public static ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor, Duration terminationTimeout) { + return getExitingScheduledExecutorService( + executor, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); + } + + /** + * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when + * the application is complete. It does so by using daemon threads and adding a shutdown hook to + * wait for their completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @param timeUnit unit of time for the time parameter + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // TODO + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + return new Application() + .getExitingScheduledExecutorService(executor, terminationTimeout, timeUnit); + } + + /** + * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when + * the application is complete. It does so by using daemon threads and adding a shutdown hook to + * wait for their completion. + * + *

This method waits 120 seconds before continuing with JVM termination, even if the executor + * has not finished its work. + * + *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // TODO + public static ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor) { + return new Application().getExitingScheduledExecutorService(executor); + } + + /** + * Add a shutdown hook to wait for thread completion in the given {@link ExecutorService service}. + * This is useful if the given service uses daemon threads, and we want to keep the JVM from + * exiting immediately on shutdown, instead giving these daemon threads a chance to terminate + * normally. + * + * @param service ExecutorService which uses daemon threads + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @since 28.0 + */ + @Beta + @GwtIncompatible // java.time.Duration + public static void addDelayedShutdownHook(ExecutorService service, Duration terminationTimeout) { + addDelayedShutdownHook(service, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); + } + + /** + * Add a shutdown hook to wait for thread completion in the given {@link ExecutorService service}. + * This is useful if the given service uses daemon threads, and we want to keep the JVM from + * exiting immediately on shutdown, instead giving these daemon threads a chance to terminate + * normally. + * + * @param service ExecutorService which uses daemon threads + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @param timeUnit unit of time for the time parameter + */ + @Beta + @GwtIncompatible // TODO + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static void addDelayedShutdownHook( + ExecutorService service, long terminationTimeout, TimeUnit timeUnit) { + new Application().addDelayedShutdownHook(service, terminationTimeout, timeUnit); + } + + /** Represents the current application to register shutdown hooks. */ + @GwtIncompatible // TODO + @VisibleForTesting + static class Application { + + final ExecutorService getExitingExecutorService( + ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + useDaemonThreadFactory(executor); + ExecutorService service = Executors.unconfigurableExecutorService(executor); + addDelayedShutdownHook(executor, terminationTimeout, timeUnit); + return service; + } + + final ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { + return getExitingExecutorService(executor, 120, TimeUnit.SECONDS); + } + + final ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + useDaemonThreadFactory(executor); + ScheduledExecutorService service = Executors.unconfigurableScheduledExecutorService(executor); + addDelayedShutdownHook(executor, terminationTimeout, timeUnit); + return service; + } + + final ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor) { + return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS); + } + + final void addDelayedShutdownHook( + final ExecutorService service, final long terminationTimeout, final TimeUnit timeUnit) { + checkNotNull(service); + checkNotNull(timeUnit); + addShutdownHook( + MoreExecutors.newThread( + "DelayedShutdownHook-for-" + service, + new Runnable() { + @Override + public void run() { + try { + // We'd like to log progress and failures that may arise in the + // following code, but unfortunately the behavior of logging + // is undefined in shutdown hooks. + // This is because the logging code installs a shutdown hook of its + // own. See Cleaner class inside {@link LogManager}. + service.shutdown(); + service.awaitTermination(terminationTimeout, timeUnit); + } catch (InterruptedException ignored) { + // We're shutting down anyway, so just ignore. + } + } + })); + } + + @VisibleForTesting + void addShutdownHook(Thread hook) { + Runtime.getRuntime().addShutdownHook(hook); + } + } + + @GwtIncompatible // TODO + private static void useDaemonThreadFactory(ThreadPoolExecutor executor) { + executor.setThreadFactory( + new ThreadFactoryBuilder() + .setDaemon(true) + .setThreadFactory(executor.getThreadFactory()) + .build()); + } + + // See newDirectExecutorService javadoc for behavioral notes. + @GwtIncompatible // TODO + private static final class DirectExecutorService extends AbstractListeningExecutorService { + /** Lock used whenever accessing the state variables (runningTasks, shutdown) of the executor */ + private final Object lock = new Object(); + + /* + * Conceptually, these two variables describe the executor being in + * one of three states: + * - Active: shutdown == false + * - Shutdown: runningTasks > 0 and shutdown == true + * - Terminated: runningTasks == 0 and shutdown == true + */ + @GuardedBy("lock") + private int runningTasks = 0; + + @GuardedBy("lock") + private boolean shutdown = false; + + @Override + public void execute(Runnable command) { + startTask(); + try { + command.run(); + } finally { + endTask(); + } + } + + @Override + public boolean isShutdown() { + synchronized (lock) { + return shutdown; + } + } + + @Override + public void shutdown() { + synchronized (lock) { + shutdown = true; + if (runningTasks == 0) { + lock.notifyAll(); + } + } + } + + // See newDirectExecutorService javadoc for unusual behavior of this method. + @Override + public List shutdownNow() { + shutdown(); + return Collections.emptyList(); + } + + @Override + public boolean isTerminated() { + synchronized (lock) { + return shutdown && runningTasks == 0; + } + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + synchronized (lock) { + while (true) { + if (shutdown && runningTasks == 0) { + return true; + } else if (nanos <= 0) { + return false; + } else { + long now = System.nanoTime(); + TimeUnit.NANOSECONDS.timedWait(lock, nanos); + nanos -= System.nanoTime() - now; // subtract the actual time we waited + } + } + } + } + + /** + * Checks if the executor has been shut down and increments the running task count. + * + * @throws RejectedExecutionException if the executor has been previously shutdown + */ + private void startTask() { + synchronized (lock) { + if (shutdown) { + throw new RejectedExecutionException("Executor already shutdown"); + } + runningTasks++; + } + } + + /** Decrements the running task count. */ + private void endTask() { + synchronized (lock) { + int numRunning = --runningTasks; + if (numRunning == 0) { + lock.notifyAll(); + } + } + } + } + + /** + * Creates an executor service that runs each task in the thread that invokes {@code + * execute/submit}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. This applies both to + * individually submitted tasks and to collections of tasks submitted via {@code invokeAll} or + * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are + * run to completion before a {@code Future} is returned to the caller (unless the executor has + * been shutdown). + * + *

Although all tasks are immediately executed in the thread that submitted the task, this + * {@code ExecutorService} imposes a small locking overhead on each task submission in order to + * implement shutdown and termination behavior. + * + *

The implementation deviates from the {@code ExecutorService} specification with regards to + * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is + * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing + * tasks. Second, the returned list will always be empty, as any submitted task is considered to + * have started execution. This applies also to tasks given to {@code invokeAll} or {@code + * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet + * started execution. It is unclear from the {@code ExecutorService} specification if these should + * be included, and it's much easier to implement the interpretation that they not be. Finally, a + * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code + * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may + * already have been executed. + * + * @since 18.0 (present as MoreExecutors.sameThreadExecutor() since 10.0) + */ + @GwtIncompatible // TODO + public static ListeningExecutorService newDirectExecutorService() { + return new DirectExecutorService(); + } + + /** + * Returns an {@link Executor} that runs each task in the thread that invokes {@link + * Executor#execute execute}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. + * + *

This executor is appropriate for tasks that are lightweight and not deeply chained. + * Inappropriate {@code directExecutor} usage can cause problems, and these problems can be + * difficult to reproduce because they depend on timing. For example: + * + *

+ * + * Additionally, beware of executing tasks with {@code directExecutor} while holding a lock. Since + * the task you submit to the executor (or any other arbitrary work the executor does) may do slow + * work or acquire other locks, you risk deadlocks. + * + *

This instance is equivalent to: + * + *

{@code
+     * final class DirectExecutor implements Executor {
+     *   public void execute(Runnable r) {
+     *     r.run();
+     *   }
+     * }
+     * }
+ * + *

This should be preferred to {@link #newDirectExecutorService()} because implementing the + * {@link ExecutorService} subinterface necessitates significant performance overhead. + * + * @since 18.0 + */ + public static Executor directExecutor() { + return DirectExecutor.INSTANCE; + } + + /** + * Returns an {@link Executor} that runs each task executed sequentially, such that no two tasks + * are running concurrently. Submitted tasks have a happens-before order as defined in the Java + * Language Specification. + * + *

The executor uses {@code delegate} in order to {@link Executor#execute execute} each task in + * turn, and does not create any threads of its own. + * + *

After execution begins on a thread from the {@code delegate} {@link Executor}, tasks are + * polled and executed from a task queue until there are no more tasks. The thread will not be + * released until there are no more tasks to run. + * + *

If a task is submitted while a thread is executing tasks from the task queue, the thread + * will not be released until that submitted task is also complete. + * + *

If a task is {@linkplain Thread#interrupt interrupted} while a task is running: + * + *

    + *
  1. execution will not stop until the task queue is empty. + *
  2. tasks will begin execution with the thread marked as not interrupted - any interruption + * applies only to the task that was running at the point of interruption. + *
  3. if the thread was interrupted before the SequentialExecutor's worker begins execution, + * the interrupt will be restored to the thread after it completes so that its {@code + * delegate} Executor may process the interrupt. + *
  4. subtasks are run with the thread uninterrupted and interrupts received during execution + * of a task are ignored. + *
+ * + *

{@code RuntimeException}s thrown by tasks are simply logged and the executor keeps trucking. + * If an {@code Error} is thrown, the error will propagate and execution will stop until the next + * time a task is submitted. + * + *

When an {@code Error} is thrown by an executed task, previously submitted tasks may never + * run. An attempt will be made to restart execution on the next call to {@code execute}. If the + * {@code delegate} has begun to reject execution, the previously submitted tasks may never run, + * despite not throwing a RejectedExecutionException synchronously with the call to {@code + * execute}. If this behaviour is problematic, use an Executor with a single thread (e.g. {@link + * Executors#newSingleThreadExecutor}). + * + * @since 23.3 (since 23.1 as {@code sequentialExecutor}) + */ + @Beta + @GwtIncompatible + public static Executor newSequentialExecutor(Executor delegate) { + return new SequentialExecutor(delegate); + } + + /** + * Creates an {@link ExecutorService} whose {@code submit} and {@code invokeAll} methods submit + * {@link ListenableFutureTask} instances to the given delegate executor. Those methods, as well + * as {@code execute} and {@code invokeAny}, are implemented in terms of calls to {@code + * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that + * the returned {@code ListeningExecutorService} never calls the delegate's {@code submit}, {@code + * invokeAll}, and {@code invokeAny} methods, so any special handling of tasks must be implemented + * in the delegate's {@code execute} method or by wrapping the returned {@code + * ListeningExecutorService}. + * + *

If the delegate executor was already an instance of {@code ListeningExecutorService}, it is + * returned untouched, and the rest of this documentation does not apply. + * + * @since 10.0 + */ + @GwtIncompatible // TODO + public static ListeningExecutorService listeningDecorator(ExecutorService delegate) { + return (delegate instanceof ListeningExecutorService) + ? (ListeningExecutorService) delegate + : (delegate instanceof ScheduledExecutorService) + ? new ScheduledListeningDecorator((ScheduledExecutorService) delegate) + : new ListeningDecorator(delegate); + } + + /** + * Creates a {@link ScheduledExecutorService} whose {@code submit} and {@code invokeAll} methods + * submit {@link ListenableFutureTask} instances to the given delegate executor. Those methods, as + * well as {@code execute} and {@code invokeAny}, are implemented in terms of calls to {@code + * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that + * the returned {@code ListeningScheduledExecutorService} never calls the delegate's {@code + * submit}, {@code invokeAll}, and {@code invokeAny} methods, so any special handling of tasks + * must be implemented in the delegate's {@code execute} method or by wrapping the returned {@code + * ListeningScheduledExecutorService}. + * + *

If the delegate executor was already an instance of {@code + * ListeningScheduledExecutorService}, it is returned untouched, and the rest of this + * documentation does not apply. + * + * @since 10.0 + */ + @GwtIncompatible // TODO + public static ListeningScheduledExecutorService listeningDecorator( + ScheduledExecutorService delegate) { + return (delegate instanceof ListeningScheduledExecutorService) + ? (ListeningScheduledExecutorService) delegate + : new ScheduledListeningDecorator(delegate); + } + + @GwtIncompatible // TODO + private static class ListeningDecorator extends AbstractListeningExecutorService { + private final ExecutorService delegate; + + ListeningDecorator(ExecutorService delegate) { + this.delegate = checkNotNull(delegate); + } + + @Override + public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return delegate.awaitTermination(timeout, unit); + } + + @Override + public final boolean isShutdown() { + return delegate.isShutdown(); + } + + @Override + public final boolean isTerminated() { + return delegate.isTerminated(); + } + + @Override + public final void shutdown() { + delegate.shutdown(); + } + + @Override + public final List shutdownNow() { + return delegate.shutdownNow(); + } + + @Override + public final void execute(Runnable command) { + delegate.execute(command); + } + + @Override + public final String toString() { + return super.toString() + "[" + delegate + "]"; + } + } + + @GwtIncompatible // TODO + private static final class ScheduledListeningDecorator extends ListeningDecorator + implements ListeningScheduledExecutorService { + @SuppressWarnings("hiding") + final ScheduledExecutorService delegate; + + ScheduledListeningDecorator(ScheduledExecutorService delegate) { + super(delegate); + this.delegate = checkNotNull(delegate); + } + + @Override + public ListenableScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + TrustedListenableFutureTask<@Nullable Void> task = + TrustedListenableFutureTask.create(command, null); + ScheduledFuture scheduled = delegate.schedule(task, delay, unit); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); + } + + @Override + public ListenableScheduledFuture schedule( + Callable callable, long delay, TimeUnit unit) { + TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); + ScheduledFuture scheduled = delegate.schedule(task, delay, unit); + return new ListenableScheduledTask(task, scheduled); + } + + @Override + public ListenableScheduledFuture scheduleAtFixedRate( + Runnable command, long initialDelay, long period, TimeUnit unit) { + NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); + ScheduledFuture scheduled = delegate.scheduleAtFixedRate(task, initialDelay, period, unit); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); + } + + @Override + public ListenableScheduledFuture scheduleWithFixedDelay( + Runnable command, long initialDelay, long delay, TimeUnit unit) { + NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); + ScheduledFuture scheduled = + delegate.scheduleWithFixedDelay(task, initialDelay, delay, unit); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); + } + + private static final class ListenableScheduledTask + extends SimpleForwardingListenableFuture implements ListenableScheduledFuture { + + private final ScheduledFuture scheduledDelegate; + + public ListenableScheduledTask( + ListenableFuture listenableDelegate, ScheduledFuture scheduledDelegate) { + super(listenableDelegate); + this.scheduledDelegate = scheduledDelegate; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + boolean cancelled = super.cancel(mayInterruptIfRunning); + if (cancelled) { + // Unless it is cancelled, the delegate may continue being scheduled + scheduledDelegate.cancel(mayInterruptIfRunning); + + // TODO(user): Cancel "this" if "scheduledDelegate" is cancelled. + } + return cancelled; + } + + @Override + public long getDelay(TimeUnit unit) { + return scheduledDelegate.getDelay(unit); + } + + @Override + public int compareTo(Delayed other) { + return scheduledDelegate.compareTo(other); + } + } + + @GwtIncompatible // TODO + private static final class NeverSuccessfulListenableFutureTask + extends AbstractFuture.TrustedFuture<@Nullable Void> implements Runnable { + private final Runnable delegate; + + public NeverSuccessfulListenableFutureTask(Runnable delegate) { + this.delegate = checkNotNull(delegate); + } + + @Override + public void run() { + try { + delegate.run(); + } catch (Throwable t) { + setException(t); + throw Throwables.propagate(t); + } + } + + @Override + protected String pendingToString() { + return "task=[" + delegate + "]"; + } + } + } + + /* + * This following method is a modified version of one found in + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck/AbstractExecutorServiceTest.java?revision=1.30 + * which contained the following notice: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to + * the public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/ + * + * Other contributors include Andrew Wright, Jeffrey Hayes, Pat Fisher, Mike Judd. + */ + + /** + * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService} + * implementations. + */ + @GwtIncompatible + @ParametricNullness + static T invokeAnyImpl( + ListeningExecutorService executorService, + Collection> tasks, + boolean timed, + Duration timeout) + throws InterruptedException, ExecutionException, TimeoutException { + return invokeAnyImpl( + executorService, tasks, timed, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); + } + + /** + * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService} + * implementations. + */ + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + @GwtIncompatible + @ParametricNullness + static T invokeAnyImpl( + ListeningExecutorService executorService, + Collection> tasks, + boolean timed, + long timeout, + TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + checkNotNull(executorService); + checkNotNull(unit); + int ntasks = tasks.size(); + checkArgument(ntasks > 0); + List> futures = Lists.newArrayListWithCapacity(ntasks); + BlockingQueue> futureQueue = Queues.newLinkedBlockingQueue(); + long timeoutNanos = unit.toNanos(timeout); + + // For efficiency, especially in executors with limited + // parallelism, check to see if previously submitted tasks are + // done before submitting more of them. This interleaving + // plus the exception mechanics account for messiness of main + // loop. + + try { + // Record exceptions so that if we fail to obtain any + // result, we can throw the last exception we got. + ExecutionException ee = null; + long lastTime = timed ? System.nanoTime() : 0; + Iterator> it = tasks.iterator(); + + futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue)); + --ntasks; + int active = 1; + + while (true) { + Future f = futureQueue.poll(); + if (f == null) { + if (ntasks > 0) { + --ntasks; + futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue)); + ++active; + } else if (active == 0) { + break; + } else if (timed) { + f = futureQueue.poll(timeoutNanos, TimeUnit.NANOSECONDS); + if (f == null) { + throw new TimeoutException(); + } + long now = System.nanoTime(); + timeoutNanos -= now - lastTime; + lastTime = now; + } else { + f = futureQueue.take(); + } + } + if (f != null) { + --active; + try { + return f.get(); + } catch (ExecutionException eex) { + ee = eex; + } catch (RuntimeException rex) { + ee = new ExecutionException(rex); + } + } + } + + if (ee == null) { + ee = new ExecutionException(null); + } + throw ee; + } finally { + for (Future f : futures) { + f.cancel(true); + } + } + } + + /** + * Submits the task and adds a listener that adds the future to {@code queue} when it completes. + */ + @GwtIncompatible // TODO + private static ListenableFuture submitAndAddQueueListener( + ListeningExecutorService executorService, + Callable task, + final BlockingQueue> queue) { + final ListenableFuture future = executorService.submit(task); + future.addListener( + new Runnable() { + @Override + public void run() { + queue.add(future); + } + }, + directExecutor()); + return future; + } + + /** + * Returns a default thread factory used to create new threads. + * + *

When running on AppEngine with access to AppEngine legacy + * APIs, this method returns {@code ThreadManager.currentRequestThreadFactory()}. Otherwise, + * it returns {@link Executors#defaultThreadFactory()}. + * + * @since 14.0 + */ + @Beta + @GwtIncompatible // concurrency + public static ThreadFactory platformThreadFactory() { + if (!isAppEngineWithApiClasses()) { + return Executors.defaultThreadFactory(); + } + try { + return (ThreadFactory) + Class.forName("com.google.appengine.api.ThreadManager") + .getMethod("currentRequestThreadFactory") + .invoke(null); + /* + * Do not merge the 3 catch blocks below. javac would infer a type of + * ReflectiveOperationException, which Animal Sniffer would reject. (Old versions of Android + * don't *seem* to mind, but there might be edge cases of which we're unaware.) + */ + } catch (IllegalAccessException e) { + throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); + } catch (InvocationTargetException e) { + throw Throwables.propagate(e.getCause()); + } + } + + @GwtIncompatible // TODO + private static boolean isAppEngineWithApiClasses() { + if (System.getProperty("com.google.appengine.runtime.environment") == null) { + return false; + } + try { + Class.forName("com.google.appengine.api.utils.SystemProperty"); + } catch (ClassNotFoundException e) { + return false; + } + try { + // If the current environment is null, we're not inside AppEngine. + return Class.forName("com.google.apphosting.api.ApiProxy") + .getMethod("getCurrentEnvironment") + .invoke(null) + != null; + } catch (ClassNotFoundException e) { + // If ApiProxy doesn't exist, we're not on AppEngine at all. + return false; + } catch (InvocationTargetException e) { + // If ApiProxy throws an exception, we're not in a proper AppEngine environment. + return false; + } catch (IllegalAccessException e) { + // If the method isn't accessible, we're not on a supported version of AppEngine; + return false; + } catch (NoSuchMethodException e) { + // If the method doesn't exist, we're not on a supported version of AppEngine; + return false; + } + } + + /** + * Creates a thread using {@link #platformThreadFactory}, and sets its name to {@code name} unless + * changing the name is forbidden by the security manager. + */ + @GwtIncompatible // concurrency + static Thread newThread(String name, Runnable runnable) { + checkNotNull(name); + checkNotNull(runnable); + Thread result = platformThreadFactory().newThread(runnable); + try { + result.setName(name); + } catch (SecurityException e) { + // OK if we can't set the name in this environment. + } + return result; + } + + // TODO(lukes): provide overloads for ListeningExecutorService? ListeningScheduledExecutorService? + // TODO(lukes): provide overloads that take constant strings? Functions to + // calculate names? + + /** + * Creates an {@link Executor} that renames the {@link Thread threads} that its tasks run in. + * + *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed + * right before each task is run. The renaming is best effort, if a {@link SecurityManager} + * prevents the renaming then it will be skipped but the tasks will still execute. + * + * @param executor The executor to decorate + * @param nameSupplier The source of names for each task + */ + @GwtIncompatible // concurrency + static Executor renamingDecorator(final Executor executor, final Supplier nameSupplier) { + checkNotNull(executor); + checkNotNull(nameSupplier); + return new Executor() { + @Override + public void execute(Runnable command) { + executor.execute(Callables.threadRenaming(command, nameSupplier)); + } + }; + } + + /** + * Creates an {@link ExecutorService} that renames the {@link Thread threads} that its tasks run + * in. + * + *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed + * right before each task is run. The renaming is best effort, if a {@link SecurityManager} + * prevents the renaming then it will be skipped but the tasks will still execute. + * + * @param service The executor to decorate + * @param nameSupplier The source of names for each task + */ + @GwtIncompatible // concurrency + static ExecutorService renamingDecorator( + final ExecutorService service, final Supplier nameSupplier) { + checkNotNull(service); + checkNotNull(nameSupplier); + return new WrappingExecutorService(service) { + @Override + protected Callable wrapTask(Callable callable) { + return Callables.threadRenaming(callable, nameSupplier); + } + + @Override + protected Runnable wrapTask(Runnable command) { + return Callables.threadRenaming(command, nameSupplier); + } + }; + } + + /** + * Creates a {@link ScheduledExecutorService} that renames the {@link Thread threads} that its + * tasks run in. + * + *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed + * right before each task is run. The renaming is best effort, if a {@link SecurityManager} + * prevents the renaming then it will be skipped but the tasks will still execute. + * + * @param service The executor to decorate + * @param nameSupplier The source of names for each task + */ + @GwtIncompatible // concurrency + static ScheduledExecutorService renamingDecorator( + final ScheduledExecutorService service, final Supplier nameSupplier) { + checkNotNull(service); + checkNotNull(nameSupplier); + return new WrappingScheduledExecutorService(service) { + @Override + protected Callable wrapTask(Callable callable) { + return Callables.threadRenaming(callable, nameSupplier); + } + + @Override + protected Runnable wrapTask(Runnable command) { + return Callables.threadRenaming(command, nameSupplier); + } + }; + } + + /** + * Shuts down the given executor service gradually, first disabling new submissions and later, if + * necessary, cancelling remaining tasks. + * + *

The method takes the following steps: + * + *

    + *
  1. calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. + *
  2. awaits executor service termination for half of the specified timeout. + *
  3. if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling + * pending tasks and interrupting running tasks. + *
  4. awaits executor service termination for the other half of the specified timeout. + *
+ * + *

If, at any step of the process, the calling thread is interrupted, the method calls {@link + * ExecutorService#shutdownNow()} and returns. + * + * @param service the {@code ExecutorService} to shut down + * @param timeout the maximum time to wait for the {@code ExecutorService} to terminate + * @return {@code true} if the {@code ExecutorService} was terminated successfully, {@code false} + * if the call timed out or was interrupted + * @since 28.0 + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // java.time.Duration + public static boolean shutdownAndAwaitTermination(ExecutorService service, Duration timeout) { + return shutdownAndAwaitTermination(service, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); + } + + /** + * Shuts down the given executor service gradually, first disabling new submissions and later, if + * necessary, cancelling remaining tasks. + * + *

The method takes the following steps: + * + *

    + *
  1. calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. + *
  2. awaits executor service termination for half of the specified timeout. + *
  3. if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling + * pending tasks and interrupting running tasks. + *
  4. awaits executor service termination for the other half of the specified timeout. + *
+ * + *

If, at any step of the process, the calling thread is interrupted, the method calls {@link + * ExecutorService#shutdownNow()} and returns. + * + * @param service the {@code ExecutorService} to shut down + * @param timeout the maximum time to wait for the {@code ExecutorService} to terminate + * @param unit the time unit of the timeout argument + * @return {@code true} if the {@code ExecutorService} was terminated successfully, {@code false} + * if the call timed out or was interrupted + * @since 17.0 + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // concurrency + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static boolean shutdownAndAwaitTermination( + ExecutorService service, long timeout, TimeUnit unit) { + long halfTimeoutNanos = unit.toNanos(timeout) / 2; + // Disable new tasks from being submitted + service.shutdown(); + try { + // Wait for half the duration of the timeout for existing tasks to terminate + if (!service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS)) { + // Cancel currently executing tasks + service.shutdownNow(); + // Wait the other half of the timeout for tasks to respond to being cancelled + service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS); + } + } catch (InterruptedException ie) { + // Preserve interrupt status + Thread.currentThread().interrupt(); + // (Re-)Cancel if current thread also interrupted + service.shutdownNow(); + } + return service.isTerminated(); + } + + /** + * Returns an Executor that will propagate {@link RejectedExecutionException} from the delegate + * executor to the given {@code future}. + * + *

Note, the returned executor can only be used once. + */ + static Executor rejectionPropagatingExecutor( + final Executor delegate, final AbstractFuture future) { + checkNotNull(delegate); + checkNotNull(future); + if (delegate == directExecutor()) { + // directExecutor() cannot throw RejectedExecutionException + return delegate; + } + return new Executor() { + @Override + public void execute(Runnable command) { + try { + delegate.execute(command); + } catch (RejectedExecutionException e) { + future.setException(e); + } + } + }; + } + + // Nacho start + /** + * Creates an executor service that runs each task in the thread that invokes {@code + * execute/submit}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. This applies both to + * individually submitted tasks and to collections of tasks submitted via {@code invokeAll} or + * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are + * run to completion before a {@code Future} is returned to the caller (unless the executor has + * been shutdown). + * + *

Although all tasks are immediately executed in the thread that submitted the task, this + * {@code ExecutorService} imposes a small locking overhead on each task submission in order to + * implement shutdown and termination behavior. + * + *

The implementation deviates from the {@code ExecutorService} specification with regards to + * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is + * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing + * tasks. Second, the returned list will always be empty, as any submitted task is considered to + * have started execution. This applies also to tasks given to {@code invokeAll} or {@code + * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet + * started execution. It is unclear from the {@code ExecutorService} specification if these should + * be included, and it's much easier to implement the interpretation that they not be. Finally, a + * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code + * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may + * already have been executed. + * + * @since 10.0 + * @deprecated replaced by {@link MoreExecutors#sameThreadExecutor()} + * @see MoreExecutors#sameThreadExecutor() + */ + @Deprecated + @GwtIncompatible + public static ListeningExecutorService sameThreadExecutor() { + return newDirectExecutorService(); + } + // Nacho end +} \ No newline at end of file diff --git a/NachoSpigot-Server/pom.xml b/NachoSpigot-Server/pom.xml index d78e03fef..4e5161035 100644 --- a/NachoSpigot-Server/pom.xml +++ b/NachoSpigot-Server/pom.xml @@ -101,7 +101,7 @@ 2.17.1 compile - + org.apache.logging.log4j log4j-api 2.17.1 @@ -207,10 +207,10 @@ org.bukkit.craftbukkit.Main CraftBukkit + ${describe} ${maven.build.timestamp} Bukkit - ${api.version} Bukkit Team true diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/BaseBlockPosition.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/BaseBlockPosition.java index 39ac17623..24efd8eb2 100644 --- a/NachoSpigot-Server/src/main/java/net/minecraft/server/BaseBlockPosition.java +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/BaseBlockPosition.java @@ -1,6 +1,6 @@ package net.minecraft.server; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; public class BaseBlockPosition implements Comparable { @@ -80,7 +80,7 @@ public double i(BaseBlockPosition baseblockposition) { } public String toString() { - return Objects.toStringHelper(this).add("x", this.getX()).add("y", this.getY()).add("z", this.getZ()).toString(); + return MoreObjects.toStringHelper(this).add("x", this.getX()).add("y", this.getY()).add("z", this.getZ()).toString(); } // Paperspigot - Signature change, Object -> BaseBlockPosition diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockState.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockState.java index 17a16170c..cd4c3753d 100644 --- a/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockState.java +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockState.java @@ -1,6 +1,6 @@ package net.minecraft.server; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; // TacoSpigot start import com.google.common.base.Preconditions; @@ -42,7 +42,7 @@ public Class b() { } public String toString() { - return Objects.toStringHelper(this).add("name", this.b).add("clazz", this.a).add("values", this.c()).toString(); + return MoreObjects.toStringHelper(this).add("name", this.b).add("clazz", this.a).add("values", this.c()).toString(); } public boolean equals(Object object) { diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockStateList.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockStateList.java index 2369efba0..b8d3bc622 100644 --- a/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockStateList.java +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockStateList.java @@ -2,7 +2,7 @@ import com.google.common.base.Function; import com.google.common.base.Joiner; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -111,7 +111,7 @@ public Collection d() { } public String toString() { - return Objects.toStringHelper(this).add("block", Block.REGISTRY.c(this.c)).add("properties", Iterables.transform(this.d, BlockStateList.b)).toString(); + return MoreObjects.toStringHelper(this).add("block", Block.REGISTRY.c(this.c)).add("properties", Iterables.transform(this.d, BlockStateList.b)).toString(); } static class BlockData extends BlockDataAbstract { diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockTripwireHook.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockTripwireHook.java index 0ad4a20f3..355d1a6b1 100644 --- a/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockTripwireHook.java +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/BlockTripwireHook.java @@ -1,6 +1,6 @@ package net.minecraft.server; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.common.base.Predicate; import java.util.Iterator; import java.util.Random; @@ -113,7 +113,7 @@ public void a(World world, BlockPosition blockposition, IBlockData iblockdata, b flag5 = false; } else { if (k == i) { - iblockdata2 = (IBlockData) Objects.firstNonNull(iblockdata1, iblockdata2); + iblockdata2 = (IBlockData) MoreObjects.firstNonNull(iblockdata1, iblockdata2); } boolean flag7 = !((Boolean) iblockdata2.get(BlockTripwire.DISARMED)).booleanValue(); diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/EntitySlice.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/EntitySlice.java index ae6c52f2c..bddaa43da 100644 --- a/NachoSpigot-Server/src/main/java/net/minecraft/server/EntitySlice.java +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/EntitySlice.java @@ -114,7 +114,7 @@ public Iterator iterator() { List list = (List) EntitySlice.this.b.get(EntitySlice.this.b(oclass)); if (list == null) { - return Iterators.emptyIterator(); + return java.util.Collections.emptyIterator(); } else { Iterator iterator = list.iterator(); @@ -125,7 +125,7 @@ public Iterator iterator() { } public Iterator iterator() { - return this.e.isEmpty() ? Iterators.emptyIterator() : Iterators.unmodifiableIterator(this.e.iterator()); + return this.e.isEmpty() ? java.util.Collections.emptyIterator() : Iterators.unmodifiableIterator(this.e.iterator()); } public int size() { diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java index cfcab7362..9f8f3038d 100644 --- a/NachoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1593,7 +1593,7 @@ public ListenableFuture a(Callable callable) { try { return Futures.immediateFuture(callable.call()); } catch (Exception exception) { - return Futures.immediateFailedCheckedFuture(exception); + return Futures.immediateFailedFuture(exception); } } } diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutPlayerInfo.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutPlayerInfo.java index 251137dc3..3b062bd12 100644 --- a/NachoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutPlayerInfo.java +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutPlayerInfo.java @@ -1,6 +1,6 @@ package net.minecraft.server; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; @@ -176,7 +176,7 @@ public void a(PacketListenerPlayOut var1) { } public String toString() { - return Objects.toStringHelper(this).add("action", this.a).add("entries", this.b).toString(); + return MoreObjects.toStringHelper(this).add("action", this.a).add("entries", this.b).toString(); } public class PlayerInfoData { @@ -209,7 +209,7 @@ public IChatBaseComponent d() { } public String toString() { - return Objects.toStringHelper(this).add("latency", this.b).add("gameMode", this.c).add("profile", this.d).add("displayName", this.e == null ? null : ChatSerializer.a(this.e)).toString(); + return MoreObjects.toStringHelper(this).add("latency", this.b).add("gameMode", this.c).add("profile", this.d).add("displayName", this.e == null ? null : ChatSerializer.a(this.e)).toString(); } } diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/ShapeDetector.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/ShapeDetector.java new file mode 100644 index 000000000..2bbce1171 --- /dev/null +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/ShapeDetector.java @@ -0,0 +1,164 @@ +package net.minecraft.server; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Predicate; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import org.jetbrains.annotations.NotNull; + +public class ShapeDetector { + private final Predicate[][][] a; + private final int b; + private final int c; + private final int d; + + public ShapeDetector(Predicate[][][] var1) { + this.a = var1; + this.b = var1.length; + if (this.b > 0) { + this.c = var1[0].length; + if (this.c > 0) { + this.d = var1[0][0].length; + } else { + this.d = 0; + } + } else { + this.c = 0; + this.d = 0; + } + + } + + public int b() { + return this.c; + } + + public int c() { + return this.d; + } + + private ShapeDetector.ShapeDetectorCollection a( + BlockPosition var1, EnumDirection var2, EnumDirection var3, LoadingCache var4 + ) { + for(int var5 = 0; var5 < this.d; ++var5) { + for(int var6 = 0; var6 < this.c; ++var6) { + for(int var7 = 0; var7 < this.b; ++var7) { + if (!this.a[var7][var6][var5].apply(var4.getUnchecked(a(var1, var2, var3, var5, var6, var7)))) { + return null; + } + } + } + } + + return new ShapeDetector.ShapeDetectorCollection(var1, var2, var3, var4, this.d, this.c, this.b); + } + + public ShapeDetector.ShapeDetectorCollection a(World var1, BlockPosition var2) { + LoadingCache var3 = a(var1, false); + int var4 = Math.max(Math.max(this.d, this.c), this.b); + + for(Object var6 : BlockPosition.a(var2, var2.a(var4 - 1, var4 - 1, var4 - 1))) { + for(Object var10 : EnumDirection.values()) { + for(Object var14 : EnumDirection.values()) { + if (var14 != var10 && var14 != ((EnumDirection)var10).opposite()) { + ShapeDetector.ShapeDetectorCollection var15 = this.a((BlockPosition)var6, (EnumDirection)var10, (EnumDirection)var14, var3); + if (var15 != null) { + return var15; + } + } + } + } + } + + return null; + } + + public static LoadingCache a(World var0, boolean var1) { + return CacheBuilder.newBuilder().build(new ShapeDetector.BlockLoader(var0, var1)); + } + + protected static BlockPosition a(BlockPosition var0, EnumDirection var1, EnumDirection var2, int var3, int var4, int var5) { + if (var1 != var2 && var1 != var2.opposite()) { + BaseBlockPosition var6 = new BaseBlockPosition(var1.getAdjacentX(), var1.getAdjacentY(), var1.getAdjacentZ()); + BaseBlockPosition var7 = new BaseBlockPosition(var2.getAdjacentX(), var2.getAdjacentY(), var2.getAdjacentZ()); + BaseBlockPosition var8 = var6.d(var7); + return var0.a( + var7.getX() * -var4 + var8.getX() * var3 + var6.getX() * var5, + var7.getY() * -var4 + var8.getY() * var3 + var6.getY() * var5, + var7.getZ() * -var4 + var8.getZ() * var3 + var6.getZ() * var5 + ); + } else { + throw new IllegalArgumentException("Invalid forwards & up combination"); + } + } + + static class BlockLoader extends CacheLoader { + private final World a; + private final boolean b; + + public BlockLoader(World var1, boolean var2) { + this.a = var1; + this.b = var2; + } + + public ShapeDetectorBlock a(BlockPosition var1) throws Exception { + return new ShapeDetectorBlock(this.a, var1, this.b); + } + + @Override + public ShapeDetectorBlock load(BlockPosition var1) throws Exception { + return this.a(var1); + } + } + + public static class ShapeDetectorCollection { + private final BlockPosition a; + private final EnumDirection b; + private final EnumDirection c; + private final LoadingCache d; + private final int e; + private final int f; + private final int g; + + public ShapeDetectorCollection( + BlockPosition var1, EnumDirection var2, EnumDirection var3, LoadingCache var4, int var5, int var6, int var7 + ) { + this.a = var1; + this.b = var2; + this.c = var3; + this.d = var4; + this.e = var5; + this.f = var6; + this.g = var7; + } + + public BlockPosition a() { + return this.a; + } + + public EnumDirection b() { + return this.b; + } + + public EnumDirection c() { + return this.c; + } + + public int d() { + return this.e; + } + + public int e() { + return this.f; + } + + public ShapeDetectorBlock a(int var1, int var2, int var3) { + return (ShapeDetectorBlock)this.d.getUnchecked(ShapeDetector.a(this.a, this.b(), this.c(), var1, var2, var3)); + } + + public String toString() { + return MoreObjects.toStringHelper(this).add("up", this.c).add("forwards", this.b).add("frontTopLeft", this.a).toString(); + } + } +} diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/StructureBoundingBox.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/StructureBoundingBox.java new file mode 100644 index 000000000..17c5b7425 --- /dev/null +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/StructureBoundingBox.java @@ -0,0 +1,153 @@ +package net.minecraft.server; + +import com.google.common.base.MoreObjects; + +public class StructureBoundingBox { + public int a; + public int b; + public int c; + public int d; + public int e; + public int f; + + public StructureBoundingBox() { + } + + public StructureBoundingBox(int[] var1) { + if (var1.length == 6) { + this.a = var1[0]; + this.b = var1[1]; + this.c = var1[2]; + this.d = var1[3]; + this.e = var1[4]; + this.f = var1[5]; + } + + } + + public static StructureBoundingBox a() { + return new StructureBoundingBox(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + } + + public static StructureBoundingBox a(int var0, int var1, int var2, int var3, int var4, int var5, int var6, int var7, int var8, EnumDirection var9) { + switch(var9) { + case NORTH: + return new StructureBoundingBox(var0 + var3, var1 + var4, var2 - var8 + 1 + var5, var0 + var6 - 1 + var3, var1 + var7 - 1 + var4, var2 + var5); + case SOUTH: + return new StructureBoundingBox(var0 + var3, var1 + var4, var2 + var5, var0 + var6 - 1 + var3, var1 + var7 - 1 + var4, var2 + var8 - 1 + var5); + case WEST: + return new StructureBoundingBox(var0 - var8 + 1 + var5, var1 + var4, var2 + var3, var0 + var5, var1 + var7 - 1 + var4, var2 + var6 - 1 + var3); + case EAST: + return new StructureBoundingBox(var0 + var5, var1 + var4, var2 + var3, var0 + var8 - 1 + var5, var1 + var7 - 1 + var4, var2 + var6 - 1 + var3); + default: + return new StructureBoundingBox(var0 + var3, var1 + var4, var2 + var5, var0 + var6 - 1 + var3, var1 + var7 - 1 + var4, var2 + var8 - 1 + var5); + } + } + + public static StructureBoundingBox a(int var0, int var1, int var2, int var3, int var4, int var5) { + return new StructureBoundingBox( + Math.min(var0, var3), Math.min(var1, var4), Math.min(var2, var5), Math.max(var0, var3), Math.max(var1, var4), Math.max(var2, var5) + ); + } + + public StructureBoundingBox(StructureBoundingBox var1) { + this.a = var1.a; + this.b = var1.b; + this.c = var1.c; + this.d = var1.d; + this.e = var1.e; + this.f = var1.f; + } + + public StructureBoundingBox(int var1, int var2, int var3, int var4, int var5, int var6) { + this.a = var1; + this.b = var2; + this.c = var3; + this.d = var4; + this.e = var5; + this.f = var6; + } + + public StructureBoundingBox(BaseBlockPosition var1, BaseBlockPosition var2) { + this.a = Math.min(var1.getX(), var2.getX()); + this.b = Math.min(var1.getY(), var2.getY()); + this.c = Math.min(var1.getZ(), var2.getZ()); + this.d = Math.max(var1.getX(), var2.getX()); + this.e = Math.max(var1.getY(), var2.getY()); + this.f = Math.max(var1.getZ(), var2.getZ()); + } + + public StructureBoundingBox(int var1, int var2, int var3, int var4) { + this.a = var1; + this.c = var2; + this.d = var3; + this.f = var4; + this.b = 1; + this.e = 512; + } + + public boolean a(StructureBoundingBox var1) { + return this.d >= var1.a && this.a <= var1.d && this.f >= var1.c && this.c <= var1.f && this.e >= var1.b && this.b <= var1.e; + } + + public boolean a(int var1, int var2, int var3, int var4) { + return this.d >= var1 && this.a <= var3 && this.f >= var2 && this.c <= var4; + } + + public void b(StructureBoundingBox var1) { + this.a = Math.min(this.a, var1.a); + this.b = Math.min(this.b, var1.b); + this.c = Math.min(this.c, var1.c); + this.d = Math.max(this.d, var1.d); + this.e = Math.max(this.e, var1.e); + this.f = Math.max(this.f, var1.f); + } + + public void a(int var1, int var2, int var3) { + this.a += var1; + this.b += var2; + this.c += var3; + this.d += var1; + this.e += var2; + this.f += var3; + } + + public boolean b(BaseBlockPosition var1) { + return var1.getX() >= this.a && var1.getX() <= this.d && var1.getZ() >= this.c && var1.getZ() <= this.f && var1.getY() >= this.b && var1.getY() <= this.e; + } + + public BaseBlockPosition b() { + return new BaseBlockPosition(this.d - this.a, this.e - this.b, this.f - this.c); + } + + public int c() { + return this.d - this.a + 1; + } + + public int d() { + return this.e - this.b + 1; + } + + public int e() { + return this.f - this.c + 1; + } + + public BaseBlockPosition f() { + return new BlockPosition(this.a + (this.d - this.a + 1) / 2, this.b + (this.e - this.b + 1) / 2, this.c + (this.f - this.c + 1) / 2); + } + + public String toString() { + return MoreObjects.toStringHelper(this) + .add("x0", this.a) + .add("y0", this.b) + .add("z0", this.c) + .add("x1", this.d) + .add("y1", this.e) + .add("z1", this.f) + .toString(); + } + + public NBTTagIntArray g() { + return new NBTTagIntArray(new int[]{this.a, this.b, this.c, this.d, this.e, this.f}); + } +} diff --git a/NachoSpigot-Server/src/main/java/net/minecraft/server/WorldGenCaves.java b/NachoSpigot-Server/src/main/java/net/minecraft/server/WorldGenCaves.java new file mode 100644 index 000000000..91fef9d9e --- /dev/null +++ b/NachoSpigot-Server/src/main/java/net/minecraft/server/WorldGenCaves.java @@ -0,0 +1,274 @@ +package net.minecraft.server; + +import com.google.common.base.MoreObjects; +import java.util.Random; + +public class WorldGenCaves extends WorldGenBase { + public WorldGenCaves() { + } + + protected void a(long var1, int var3, int var4, ChunkSnapshot var5, double var6, double var8, double var10) { + this.a(var1, var3, var4, var5, var6, var8, var10, 1.0F + this.b.nextFloat() * 6.0F, 0.0F, 0.0F, -1, -1, 0.5); + } + + protected void a( + long var1, + int var3, + int var4, + ChunkSnapshot var5, + double var6, + double var8, + double var10, + float var12, + float var13, + float var14, + int var15, + int var16, + double var17 + ) { + double var19 = (double)(var3 * 16 + 8); + double var21 = (double)(var4 * 16 + 8); + float var23 = 0.0F; + float var24 = 0.0F; + Random var25 = new Random(var1); + if (var16 <= 0) { + int var26 = this.a * 16 - 16; + var16 = var26 - var25.nextInt(var26 / 4); + } + + boolean var58 = false; + if (var15 == -1) { + var15 = var16 / 2; + var58 = true; + } + + int var27 = var25.nextInt(var16 / 2) + var16 / 4; + + for(boolean var28 = var25.nextInt(6) == 0; var15 < var16; ++var15) { + double var29 = 1.5 + (double)(MathHelper.sin((float)var15 * (float) Math.PI / (float)var16) * var12 * 1.0F); + double var31 = var29 * var17; + float var33 = MathHelper.cos(var14); + float var34 = MathHelper.sin(var14); + var6 += (double)(MathHelper.cos(var13) * var33); + var8 += (double)var34; + var10 += (double)(MathHelper.sin(var13) * var33); + if (var28) { + var14 *= 0.92F; + } else { + var14 *= 0.7F; + } + + var14 += var24 * 0.1F; + var13 += var23 * 0.1F; + var24 *= 0.9F; + var23 *= 0.75F; + var24 += (var25.nextFloat() - var25.nextFloat()) * var25.nextFloat() * 2.0F; + var23 += (var25.nextFloat() - var25.nextFloat()) * var25.nextFloat() * 4.0F; + if (!var58 && var15 == var27 && var12 > 1.0F && var16 > 0) { + this.a( + var25.nextLong(), + var3, + var4, + var5, + var6, + var8, + var10, + var25.nextFloat() * 0.5F + 0.5F, + var13 - (float) (Math.PI / 2), + var14 / 3.0F, + var15, + var16, + 1.0 + ); + this.a( + var25.nextLong(), + var3, + var4, + var5, + var6, + var8, + var10, + var25.nextFloat() * 0.5F + 0.5F, + var13 + (float) (Math.PI / 2), + var14 / 3.0F, + var15, + var16, + 1.0 + ); + return; + } + + if (var58 || var25.nextInt(4) != 0) { + double var35 = var6 - var19; + double var37 = var10 - var21; + double var39 = (double)(var16 - var15); + double var41 = (double)(var12 + 2.0F + 16.0F); + if (var35 * var35 + var37 * var37 - var39 * var39 > var41 * var41) { + return; + } + + if (!(var6 < var19 - 16.0 - var29 * 2.0) + && !(var10 < var21 - 16.0 - var29 * 2.0) + && !(var6 > var19 + 16.0 + var29 * 2.0) + && !(var10 > var21 + 16.0 + var29 * 2.0)) { + int var59 = MathHelper.floor(var6 - var29) - var3 * 16 - 1; + int var36 = MathHelper.floor(var6 + var29) - var3 * 16 + 1; + int var60 = MathHelper.floor(var8 - var31) - 1; + int var38 = MathHelper.floor(var8 + var31) + 1; + int var61 = MathHelper.floor(var10 - var29) - var4 * 16 - 1; + int var40 = MathHelper.floor(var10 + var29) - var4 * 16 + 1; + if (var59 < 0) { + var59 = 0; + } + + if (var36 > 16) { + var36 = 16; + } + + if (var60 < 1) { + var60 = 1; + } + + if (var38 > 248) { + var38 = 248; + } + + if (var61 < 0) { + var61 = 0; + } + + if (var40 > 16) { + var40 = 16; + } + + boolean var62 = false; + + for(int var42 = var59; !var62 && var42 < var36; ++var42) { + for(int var43 = var61; !var62 && var43 < var40; ++var43) { + for(int var44 = var38 + 1; !var62 && var44 >= var60 - 1; --var44) { + if (var44 >= 0 && var44 < 256) { + IBlockData var45 = var5.a(var42, var44, var43); + if (var45.getBlock() == Blocks.FLOWING_WATER || var45.getBlock() == Blocks.WATER) { + var62 = true; + } + + if (var44 != var60 - 1 && var42 != var59 && var42 != var36 - 1 && var43 != var61 && var43 != var40 - 1) { + var44 = var60; + } + } + } + } + } + + if (!var62) { + BlockPosition.MutableBlockPosition var63 = new BlockPosition.MutableBlockPosition(); + + for(int var64 = var59; var64 < var36; ++var64) { + double var65 = ((double)(var64 + var3 * 16) + 0.5 - var6) / var29; + + for(int var46 = var61; var46 < var40; ++var46) { + double var47 = ((double)(var46 + var4 * 16) + 0.5 - var10) / var29; + boolean var49 = false; + if (var65 * var65 + var47 * var47 < 1.0) { + for(int var50 = var38; var50 > var60; --var50) { + double var51 = ((double)(var50 - 1) + 0.5 - var8) / var31; + if (var51 > -0.7 && var65 * var65 + var51 * var51 + var47 * var47 < 1.0) { + IBlockData var53 = var5.a(var64, var50, var46); + IBlockData var54 = (IBlockData)MoreObjects.firstNonNull(var5.a(var64, var50 + 1, var46), Blocks.AIR.getBlockData()); + if (var53.getBlock() == Blocks.GRASS || var53.getBlock() == Blocks.MYCELIUM) { + var49 = true; + } + + if (this.a(var53, var54)) { + if (var50 - 1 < 10) { + var5.a(var64, var50, var46, Blocks.LAVA.getBlockData()); + } else { + var5.a(var64, var50, var46, Blocks.AIR.getBlockData()); + if (var54.getBlock() == Blocks.SAND) { + var5.a( + var64, + var50 + 1, + var46, + var54.get(BlockSand.VARIANT) == BlockSand.EnumSandVariant.RED_SAND + ? Blocks.RED_SANDSTONE.getBlockData() + : Blocks.SANDSTONE.getBlockData() + ); + } + + if (var49 && var5.a(var64, var50 - 1, var46).getBlock() == Blocks.DIRT) { + var63.setValues(var64 + var3 * 16, 0, var46 + var4 * 16); + var5.a(var64, var50 - 1, var46, this.c.getBiome(var63).ak.getBlock().getBlockData()); + } + } + } + } + } + } + } + } + + if (var58) { + break; + } + } + } + } + } + + } + + protected boolean a(IBlockData var1, IBlockData var2) { + if (var1.getBlock() == Blocks.STONE) { + return true; + } else if (var1.getBlock() == Blocks.DIRT) { + return true; + } else if (var1.getBlock() == Blocks.GRASS) { + return true; + } else if (var1.getBlock() == Blocks.HARDENED_CLAY) { + return true; + } else if (var1.getBlock() == Blocks.STAINED_HARDENED_CLAY) { + return true; + } else if (var1.getBlock() == Blocks.SANDSTONE) { + return true; + } else if (var1.getBlock() == Blocks.RED_SANDSTONE) { + return true; + } else if (var1.getBlock() == Blocks.MYCELIUM) { + return true; + } else if (var1.getBlock() == Blocks.SNOW_LAYER) { + return true; + } else { + return (var1.getBlock() == Blocks.SAND || var1.getBlock() == Blocks.GRAVEL) && var2.getBlock().getMaterial() != Material.WATER; + } + } + + @Override + protected void a(World var1, int var2, int var3, int var4, int var5, ChunkSnapshot var6) { + int var7 = this.b.nextInt(this.b.nextInt(this.b.nextInt(15) + 1) + 1); + if (this.b.nextInt(7) != 0) { + var7 = 0; + } + + for(int var8 = 0; var8 < var7; ++var8) { + double var9 = (double)(var2 * 16 + this.b.nextInt(16)); + double var11 = (double)this.b.nextInt(this.b.nextInt(120) + 8); + double var13 = (double)(var3 * 16 + this.b.nextInt(16)); + int var15 = 1; + if (this.b.nextInt(4) == 0) { + this.a(this.b.nextLong(), var4, var5, var6, var9, var11, var13); + var15 += this.b.nextInt(4); + } + + for(int var16 = 0; var16 < var15; ++var16) { + float var17 = this.b.nextFloat() * (float) Math.PI * 2.0F; + float var18 = (this.b.nextFloat() - 0.5F) * 2.0F / 8.0F; + float var19 = this.b.nextFloat() * 2.0F + this.b.nextFloat(); + if (this.b.nextInt(10) == 0) { + var19 *= this.b.nextFloat() * this.b.nextFloat() * 3.0F + 1.0F; + } + + this.a(this.b.nextLong(), var4, var5, var6, var9, var11, var13, var19, var17, var18, 0, 0, 1.0); + } + } + + } +} diff --git a/NachoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/NachoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index c797874e3..9266a3b3c 100644 --- a/NachoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/NachoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -141,7 +141,7 @@ public final class CraftServer implements Server { private YamlConfiguration configuration; private YamlConfiguration commandsConfiguration; private final Yaml yaml = new Yaml(new SafeConstructor()); - private final Map offlinePlayers = new MapMaker().softValues().makeMap(); + private final Map offlinePlayers = new MapMaker().weakValues().makeMap(); private final EntityMetadataStore entityMetadata = new EntityMetadataStore(); private final PlayerMetadataStore playerMetadata = new PlayerMetadataStore(); private final WorldMetadataStore worldMetadata = new WorldMetadataStore(); diff --git a/pom.xml b/pom.xml index 01b636e0c..84f6e9492 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,3 @@ - 4.0.0