tryParse(String value) {
+ Matcher matcher = PARSE.matcher(value);
+ if (!matcher.find()) {
+ return Optional.empty();
}
- return true;
- }
-
- private static boolean isValidKey(String key) {
- int len = key.length();
- if (len == 0) {
- return false;
- }
+ String namespace = matcher.group("namespace");
+ String key = matcher.group("key");
- for (int i = 0; i < len; i++) {
- if (!isValidKeyChar(key.charAt(i))) {
- return false;
- }
+ if ("..".equals(namespace)) {
+ return Optional.empty();
}
- return true;
+ return Optional.of(new NamespacedKey(namespace == null ? DEFAULT_NAMESPACE : namespace, key));
}
- /**
- * Create a key in a specific namespace.
- *
- * @param namespace namespace
- * @param key key
- * @deprecated should never be used by plugins, for internal use only!!
- */
- @Deprecated
- public NamespacedKey(String namespace, String key) {
- if (namespace == null || !isValidNamespace(namespace)) {
- throw new IllegalArgumentException(String.format("Invalid namespace. Must be [a-z0-9._-]: %s", namespace));
- } else if (key == null || !isValidKey(key)) {
- throw new IllegalArgumentException(String.format("Invalid key. Must be [a-z0-9/._-]: %s", key));
+ @SuppressWarnings("ConstantConditions")
+ public NamespacedKey {
+ if (namespace == null || namespace.equals("..") || !VALID_NAMESPACE.test(namespace)) {
+ throw new IllegalArgumentException("Invalid namespace. Must be [a-z0-9._-]: %s".formatted(namespace));
}
-
- this.namespace = namespace;
- this.key = key;
-
- String string = toString();
- if (string.length() >= 256) {
- throw new IllegalArgumentException(String.format("NamespacedKey must be less than 256 characters (%s)", string));
+ if (key == null || !VALID_KEY.test(key)) {
+ throw new IllegalArgumentException("Invalid key. Must be [a-z0-9/._-]: %s".formatted(key));
}
}
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final NamespacedKey other = (NamespacedKey) obj;
- return this.namespace.equals(other.namespace) && this.key.equals(other.key);
- }
-
@Override
public String toString() {
return this.namespace + ":" + this.key;
}
-
- /**
- * Get a key in the Minecraft namespace.
- *
- * @param key the key to use
- * @return new key in the Minecraft namespace
- */
- public static NamespacedKey minecraft(String key) {
- return new NamespacedKey(MINECRAFT, key);
- }
-
-
- /**
- * Get a NamespacedKey from the supplied string.
- *
- * The default namespace will be Minecraft's (i.e. {@link #minecraft(String)}).
- *
- * @return the created NamespacedKey. null if invalid
- */
- public static NamespacedKey fromString(@NotNull String string) {
- if (string == null || string.isEmpty()) {
- throw new IllegalArgumentException("Input string must not be empty or null");
- }
-
- String[] components = string.split(":", 3);
- if (components.length > 2) {
- return null;
- }
-
- String key = (components.length == 2) ? components[1] : "";
- if (components.length == 1) {
- String value = components[0];
- if (value.isEmpty() || !isValidKey(value)) {
- return null;
- }
-
- return minecraft(value);
- } else if (components.length == 2 && !isValidKey(key)) {
- return null;
- }
-
- String namespace = components[0];
- if (namespace.isEmpty()) {
- return minecraft(key);
- }
-
- if (!isValidNamespace(namespace)) {
- return null;
- }
-
- return new NamespacedKey(namespace, key);
- }
}
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/MathUtil.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/QuickMaths.java
similarity index 81%
rename from orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/MathUtil.java
rename to orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/QuickMaths.java
index 095a8fa8..d285f348 100644
--- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/MathUtil.java
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/QuickMaths.java
@@ -1,6 +1,6 @@
package dev.imprex.orebfuscator.util;
-public class MathUtil {
+public class QuickMaths {
public static int ceilToPowerOfTwo(int value) {
value--;
@@ -13,6 +13,11 @@ public static int ceilToPowerOfTwo(int value) {
return value;
}
+ public static int floor(double value) {
+ int i = (int) value;
+ return value < (double) i ? i - 1 : i;
+ }
+
public static int clamp(int value, int min, int max) {
return Math.max(min, Math.min(max, value));
}
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingAverage.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingAverage.java
new file mode 100644
index 00000000..a5486fa2
--- /dev/null
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingAverage.java
@@ -0,0 +1,102 @@
+package dev.imprex.orebfuscator.util;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.DoubleFunction;
+import java.util.function.LongFunction;
+import org.jspecify.annotations.NullMarked;
+import com.google.common.util.concurrent.AtomicDouble;
+
+@NullMarked
+public class RollingAverage {
+
+ private static final VarHandle BUFFER_HANDLE = MethodHandles.arrayElementVarHandle(double[].class);
+
+ private final double[] buffer;
+
+ private final AtomicInteger head = new AtomicInteger(0);
+ private final AtomicInteger size = new AtomicInteger(0);
+
+ private final AtomicDouble min = new AtomicDouble(Long.MAX_VALUE);
+ private final AtomicDouble max = new AtomicDouble(Long.MIN_VALUE);
+
+ public RollingAverage(int capacity) {
+ this.buffer = new double[capacity];
+ }
+
+ public void add(double value) {
+ int index = head.getAndUpdate(h -> (h + 1) % buffer.length);
+ BUFFER_HANDLE.setRelease(buffer, index, value);
+
+ if (size.get() < buffer.length) {
+ size.updateAndGet(s -> s < buffer.length ? s + 1 : s);
+ }
+
+ if (size.get() >= buffer.length) {
+ min.getAndUpdate(prev -> Math.min(prev, value));
+ max.getAndUpdate(prev -> Math.max(prev, value));
+ }
+ }
+
+ public double average() {
+ int size = this.size.get();
+ if (size == 0) {
+ return 0;
+ }
+
+ double sum = 0;
+ for (int i = 0; i < size; i++) {
+ sum += (double) BUFFER_HANDLE.getAcquire(buffer, i);
+ }
+
+ return sum / size;
+ }
+
+ private double percentile(double p) {
+ int size = this.size.get();
+ if (size == 0) {
+ return 0;
+ }
+
+ double[] copy = new double[size];
+ for (int i = 0; i < size; i++) {
+ copy[i] = (double) BUFFER_HANDLE.getAcquire(buffer, i);
+ }
+
+ Arrays.sort(copy);
+ double rank = p * (size - 1);
+ int lower = (int) Math.floor(rank);
+ int upper = (int) Math.ceil(rank);
+ if (lower == upper) {
+ return copy[lower];
+ }
+ // Linear interpolation
+ return copy[lower] + (copy[upper] - copy[lower]) * (rank - lower);
+ }
+
+ public String debugLong(LongFunction formatter) {
+ var n = size.get();
+ var avg = formatter.apply((long) average());
+ var p95 = formatter.apply((long) percentile(0.95));
+ var p99 = formatter.apply((long) percentile(0.99));
+ var min = formatter.apply((long) this.min.get());
+ var max = formatter.apply((long) this.max.get());
+
+ return String.format("{size=%d, avg=%s, p95=%s, p99=%s, min=%s, max=%s}", n, avg, p95,
+ p99, min, max);
+ }
+
+ public String debugDouble(DoubleFunction formatter) {
+ var n = size.get();
+ var avg = formatter.apply(average());
+ var p95 = formatter.apply(percentile(0.95));
+ var p99 = formatter.apply(percentile(0.99));
+ var min = formatter.apply(this.min.get());
+ var max = formatter.apply(this.max.get());
+
+ return String.format("{size=%d, avg=%s, p95=%s, p99=%s, min=%s, max=%s}", n, avg, p95,
+ p99, min, max);
+ }
+}
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java
new file mode 100644
index 00000000..e4406d39
--- /dev/null
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java
@@ -0,0 +1,36 @@
+package dev.imprex.orebfuscator.util;
+
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class RollingTimer extends RollingAverage {
+
+ public RollingTimer(int capacity) {
+ super(capacity);
+ }
+
+ public Instance start() {
+ return new Instance();
+ }
+
+ public class Instance {
+
+ private final long time = System.nanoTime();
+ private final AtomicBoolean running = new AtomicBoolean(true);
+
+ private Instance() {
+ }
+
+ public CompletionStage wrap(CompletionStage completionStage) {
+ return completionStage.whenComplete((a, b) -> stop());
+ }
+
+ public void stop() {
+ if (this.running.compareAndSet(true, false)) {
+ add(System.nanoTime() - time);
+ }
+ }
+ }
+}
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/SimpleCache.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/SimpleCache.java
index d5122138..d8ec4bdd 100644
--- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/SimpleCache.java
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/SimpleCache.java
@@ -3,14 +3,14 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
+import org.jspecify.annotations.NullMarked;
/**
* Simple cache implementation that removes the oldest element once a certain size is reached
*/
+@NullMarked
public class SimpleCache extends LinkedHashMap {
- private static final long serialVersionUID = -2732738355560313649L;
-
private final int maximumSize;
private final Consumer> remove;
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/Version.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/Version.java
index 6a0b4b88..8dc5056f 100644
--- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/Version.java
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/Version.java
@@ -1,6 +1,7 @@
package dev.imprex.orebfuscator.util;
import java.io.IOException;
+import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
@@ -8,11 +9,14 @@
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
-public record Version(int major, int minor, int patch) implements Comparable {
+@NullMarked
+public record Version(int major, int minor, int patch, @Nullable String suffix) implements Comparable {
private static final Pattern VERSION_PATTERN =
- Pattern.compile("(?\\d+)(?:\\.(?\\d+))?(?:\\.(?\\d+))?");
+ Pattern.compile("^(?\\d+)(?:\\.(?\\d+))?(?:\\.(?\\d+))?(?.+)?$");
public static Version parse(String version) {
return tryParse(version)
@@ -20,7 +24,7 @@ public static Version parse(String version) {
}
public static Optional tryParse(String version) {
- Matcher matcher = VERSION_PATTERN.matcher(version);
+ Matcher matcher = VERSION_PATTERN.matcher(version.trim());
if (!matcher.find()) {
return Optional.empty();
@@ -34,7 +38,9 @@ public static Optional tryParse(String version) {
String patchGroup = matcher.group("patch");
int patch = patchGroup != null ? Integer.parseInt(patchGroup) : 0;
- return Optional.of(new Version(major, minor, patch));
+ String suffix = matcher.group("suffix");
+
+ return Optional.of(new Version(major, minor, patch, suffix));
}
public boolean isAbove(String version) {
@@ -81,12 +87,17 @@ public int compareTo(Version other) {
return minor;
}
- return Integer.compare(this.patch, other.patch);
+ int patch = Integer.compare(this.patch, other.patch);
+ if (patch != 0) {
+ return patch;
+ }
+
+ return Objects.compare(this.suffix, other.suffix, Comparator.nullsLast(Comparator.naturalOrder()));
}
@Override
public int hashCode() {
- return Objects.hash(major, minor, patch);
+ return Objects.hash(major, minor, patch, suffix);
}
@Override
@@ -97,12 +108,12 @@ public boolean equals(Object obj) {
if (!(obj instanceof Version other)) {
return false;
}
- return major == other.major && minor == other.minor && patch == other.patch;
+ return major == other.major && minor == other.minor && patch == other.patch && Objects.equals(suffix, other.suffix);
}
@Override
public String toString() {
- return String.format("%s.%s.%s", this.major, this.minor, this.patch);
+ return String.format("%s.%s.%s%s", this.major, this.minor, this.patch, Objects.toString(this.suffix, ""));
}
public static final class Json extends TypeAdapter {
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/WeightedRandom.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/WeightedRandom.java
index ac40fd34..68dd6a75 100644
--- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/WeightedRandom.java
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/WeightedRandom.java
@@ -7,7 +7,7 @@
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import java.util.random.RandomGenerator;
-import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
/**
* Weighted random integer sampler using the
@@ -35,6 +35,7 @@
* This implementation is immutable and thread-safe for concurrent calls to
* {@link #next()} after construction.
*/
+@NullMarked
public final class WeightedRandom {
/**
@@ -59,7 +60,7 @@ public static Builder builder() {
*
* @param builder the builder containing values and weights
*/
- private WeightedRandom(@NotNull Builder builder) {
+ private WeightedRandom(Builder builder) {
double minWeight = Double.POSITIVE_INFINITY;
double maxWeight = Double.NEGATIVE_INFINITY;
double totalWeight = 0d;
@@ -142,22 +143,48 @@ public int next() {
return next(ThreadLocalRandom.current());
}
+ private static double boundedNextDouble(long seed, double bound) {
+ // Specialize boundedNextDouble for origin == 0, bound > 0
+ double r = (seed >>> 11) * 0x1.0p-53;
+ r = r * bound;
+ if (r >= bound) // may need to correct a rounding problem
+ {
+ r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+ }
+ return r;
+ }
+
+ private static int boundedNextInt(long seed, int n) {
+ return ((n & (n - 1)) == 0)
+ ? (int) (seed & (n - 1))
+ : (int) (((seed & 0xFFFF_FFFFL) * (long) n) >>> 32);
+ }
+
/**
* Samples a random value using the given random generator.
*
* @param random a {@link RandomGenerator} to use for randomness
* @return a sampled integer according to the configured weights
*/
- public int next(@NotNull RandomGenerator random) {
+ public int next(RandomGenerator random) {
Objects.requireNonNull(random);
- int i = random.nextInt(this.n);
+ long seed = random.nextLong();
+
+ int i = boundedNextInt(seed, this.n);
if (this.allWeightsEqual) {
return values[i];
}
- int pick = random.nextDouble(totalWeight) < probabilities[i] ? i : alias[i];
+ int pick = boundedNextDouble(seed, totalWeight) < probabilities[i] ? i : alias[i];
return values[pick];
+// int i = random.nextInt(this.n);
+// if (this.allWeightsEqual) {
+// return values[i];
+// }
+//
+// int pick = random.nextDouble(totalWeight) < probabilities[i] ? i : alias[i];
+// return values[pick];
}
/**
@@ -187,7 +214,7 @@ public Builder add(int value, double weight) {
throw new IllegalArgumentException("Weight has to be greater zero and finite!");
}
- this.entries.merge(value, weight, (a, b) -> a + b);
+ this.entries.merge(value, weight, Double::sum);
return this;
}
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorExecutor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorExecutor.java
new file mode 100644
index 00000000..d09fa587
--- /dev/null
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorExecutor.java
@@ -0,0 +1,108 @@
+package dev.imprex.orebfuscator.util.concurrent;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.LongAdder;
+import org.jspecify.annotations.NullMarked;
+import dev.imprex.orebfuscator.interop.OrebfuscatorCore;
+import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics;
+
+@NullMarked
+public class OrebfuscatorExecutor implements Executor {
+
+ private final ScheduledExecutorService scheduledExecutorService = Executors
+ .newSingleThreadScheduledExecutor(r -> new Thread(OrebfuscatorCore.THREAD_GROUP, r, "orebfuscator-scheduler"));
+
+ private final int poolSize;
+ private final ExecutorService executorService;
+
+ private final LongAdder run = new LongAdder();
+ private long updateTime = System.nanoTime();
+
+ private final OrebfuscatorStatistics statistics;
+
+ public OrebfuscatorExecutor(OrebfuscatorCore orebfuscator) {
+ this.statistics = orebfuscator.statistics();
+
+ this.poolSize = orebfuscator.config().advanced().threads();
+ this.executorService = Executors.newFixedThreadPool(this.poolSize, OrebfuscatorThread::new);
+
+ this.scheduledExecutorService.scheduleAtFixedRate(this::updateStatistics, 1L, 1L, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ Objects.requireNonNull(command);
+
+ if (Thread.currentThread() instanceof OrebfuscatorThread) {
+ // don't time runnables if we're already on one of our threads as we can only enter
+ // our thread through a timed runnable
+ command.run();
+ } else {
+ executorService.execute(new TimedRunnable(command));
+ }
+ }
+
+ public ScheduledFuture> schedule(Runnable command, long delay, TimeUnit unit) {
+ return scheduledExecutorService.schedule(command, delay, unit);
+ }
+
+ public ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+ return scheduledExecutorService.scheduleAtFixedRate(command, initialDelay, period, unit);
+ }
+
+ public boolean isShutdown() {
+ return this.scheduledExecutorService.isShutdown() || this.executorService.isShutdown();
+ }
+
+ public void shutdown() {
+ this.scheduledExecutorService.shutdownNow();
+ this.executorService.shutdownNow();
+ }
+
+ private void updateStatistics() {
+ long time = System.nanoTime();
+ try {
+ long run = this.run.sumThenReset();
+ long available = this.poolSize * (time - this.updateTime);
+
+ // invalid value don't know how to interpret it
+ if (run < 0 || run > available) {
+ return;
+ }
+
+ double utilization = available == 0 ? 0.0 : (double) run / available;
+ statistics.obfuscation.executorUtilization.add(utilization);
+ } finally {
+ this.updateTime = time;
+ }
+ }
+
+ private class TimedRunnable implements Runnable {
+
+ private final long enqueuedAt = System.nanoTime();
+
+ private final Runnable delegate;
+
+ public TimedRunnable(Runnable delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void run() {
+ long start = System.nanoTime();
+ statistics.obfuscation.executorWaitTime.add(start - this.enqueuedAt);
+
+ try {
+ delegate.run();
+ } finally {
+ run.add(System.nanoTime() - start);
+ }
+ }
+ }
+}
diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorThread.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorThread.java
new file mode 100644
index 00000000..f334185b
--- /dev/null
+++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorThread.java
@@ -0,0 +1,32 @@
+package dev.imprex.orebfuscator.util.concurrent;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.random.RandomGenerator;
+import java.util.random.RandomGenerator.SplittableGenerator;
+import org.jspecify.annotations.NullMarked;
+import dev.imprex.orebfuscator.interop.OrebfuscatorCore;
+import dev.imprex.orebfuscator.logging.OfcLogger;
+
+@NullMarked
+public class OrebfuscatorThread extends Thread implements UncaughtExceptionHandler {
+
+ private static final SplittableGenerator ROOT_GENERATOR = SplittableGenerator.of("L64X128StarStarRandom");
+ private static final AtomicInteger THREAD_ID = new AtomicInteger();
+
+ private final RandomGenerator randomGenerator = ROOT_GENERATOR.split();
+
+ public OrebfuscatorThread(Runnable target) {
+ super(OrebfuscatorCore.THREAD_GROUP, target, "orebfuscator-thread-" + THREAD_ID.getAndIncrement());
+ this.setUncaughtExceptionHandler(this);
+ }
+
+ public RandomGenerator random() {
+ return this.randomGenerator;
+ }
+
+ @Override
+ public void uncaughtException(Thread thread, Throwable throwable) {
+ OfcLogger.error(String.format("Uncaught exception in: %s%n", thread.getName()), throwable);
+ }
+}
diff --git a/orebfuscator-core/src/main/resources/config/config-1.16.0.yml b/orebfuscator-core/src/main/resources/config/config-1.16.0.yml
index 648d6ef6..0bdebb84 100644
--- a/orebfuscator-core/src/main/resources/config/config-1.16.0.yml
+++ b/orebfuscator-core/src/main/resources/config/config-1.16.0.yml
@@ -1,4 +1,4 @@
-version: 5
+version: 6
general:
checkForUpdates: true
updateOnBlockDamage: true
@@ -7,12 +7,10 @@ general:
updateRadius: 2
advanced:
verbose: false
+ threads: -1
obfuscation:
- threads: -1
timeout: 10000
- maxMillisecondsPerTick: 10
proximity:
- threads: -1
defaultBucketSize: 50
threadCheckInterval: 50
playerCheckInterval: 5000
diff --git a/orebfuscator-core/src/main/resources/config/config-1.17.0.yml b/orebfuscator-core/src/main/resources/config/config-1.17.0.yml
index 913da549..2626d3e8 100644
--- a/orebfuscator-core/src/main/resources/config/config-1.17.0.yml
+++ b/orebfuscator-core/src/main/resources/config/config-1.17.0.yml
@@ -1,4 +1,4 @@
-version: 5
+version: 6
general:
checkForUpdates: true
updateOnBlockDamage: true
@@ -7,12 +7,10 @@ general:
updateRadius: 2
advanced:
verbose: false
+ threads: -1
obfuscation:
- threads: -1
timeout: 10000
- maxMillisecondsPerTick: 10
proximity:
- threads: -1
defaultBucketSize: 50
threadCheckInterval: 50
playerCheckInterval: 5000
diff --git a/orebfuscator-core/src/main/resources/config/config-1.18.0.yml b/orebfuscator-core/src/main/resources/config/config-1.18.0.yml
index 221c5b5f..c006d5b6 100644
--- a/orebfuscator-core/src/main/resources/config/config-1.18.0.yml
+++ b/orebfuscator-core/src/main/resources/config/config-1.18.0.yml
@@ -1,4 +1,4 @@
-version: 5
+version: 6
general:
checkForUpdates: true
updateOnBlockDamage: true
@@ -7,12 +7,10 @@ general:
updateRadius: 2
advanced:
verbose: false
+ threads: -1
obfuscation:
- threads: -1
timeout: 10000
- maxMillisecondsPerTick: 10
proximity:
- threads: -1
defaultBucketSize: 50
threadCheckInterval: 50
playerCheckInterval: 5000
diff --git a/orebfuscator-core/src/main/resources/config/config-1.20.3.yml b/orebfuscator-core/src/main/resources/config/config-1.20.3.yml
index b00acd8a..7638d9a7 100644
--- a/orebfuscator-core/src/main/resources/config/config-1.20.3.yml
+++ b/orebfuscator-core/src/main/resources/config/config-1.20.3.yml
@@ -1,4 +1,4 @@
-version: 5
+version: 6
general:
checkForUpdates: true
updateOnBlockDamage: true
@@ -7,12 +7,10 @@ general:
updateRadius: 2
advanced:
verbose: false
+ threads: -1
obfuscation:
- threads: -1
timeout: 10000
- maxMillisecondsPerTick: 10
proximity:
- threads: -1
defaultBucketSize: 50
threadCheckInterval: 50
playerCheckInterval: 5000
diff --git a/orebfuscator-core/src/main/resources/config/config-1.21.9.yml b/orebfuscator-core/src/main/resources/config/config-1.21.9.yml
index de013be6..2460e868 100644
--- a/orebfuscator-core/src/main/resources/config/config-1.21.9.yml
+++ b/orebfuscator-core/src/main/resources/config/config-1.21.9.yml
@@ -1,4 +1,4 @@
-version: 5
+version: 6
general:
checkForUpdates: true
updateOnBlockDamage: true
@@ -7,12 +7,10 @@ general:
updateRadius: 2
advanced:
verbose: false
+ threads: -1
obfuscation:
- threads: -1
timeout: 10000
- maxMillisecondsPerTick: 10
proximity:
- threads: -1
defaultBucketSize: 50
threadCheckInterval: 50
playerCheckInterval: 5000
diff --git a/orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/VersionTest.java b/orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/VersionTest.java
new file mode 100644
index 00000000..a8018693
--- /dev/null
+++ b/orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/VersionTest.java
@@ -0,0 +1,131 @@
+package dev.imprex.orebfuscator.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public class VersionTest {
+
+ @Test
+ public void testParse() {
+ assertEquals(new Version(1, 0, 0, null), Version.parse("1"));
+ assertEquals(new Version(1, 2, 0, null), Version.parse("1.2"));
+ assertEquals(new Version(1, 2, 3, null), Version.parse("1.2.3"));
+ assertEquals(new Version(1, 2, 3, "-b0"), Version.parse("1.2.3-b0"));
+
+ assertThrows(IllegalArgumentException.class, () -> Version.parse("a.1.c"));
+ assertThrows(IllegalArgumentException.class, () -> Version.parse("a.b.c"));
+ assertThrows(IllegalArgumentException.class, () -> Version.parse("fooBar"));
+ }
+
+ @Test
+ public void testCompareTo() {
+ Version a = new Version(1, 0, 0, null);
+ Version b = new Version(1, 0, 0, null);
+ Version c = new Version(1, 2, 0, null);
+ Version d = new Version(1, 2, 3, null);
+ Version e = new Version(2, 0, 0, "-b0");
+ Version f = new Version(2, 0, 0, "-b1");
+ Version g = new Version(2, 0, 0, null);
+
+ assertFalse(a.isAbove(b));
+ assertTrue(a.isAtOrAbove(b));
+ assertTrue(a.isAtOrBelow(b));
+ assertFalse(a.isBelow(b));
+
+ assertFalse(a.isAbove(c));
+ assertFalse(a.isAtOrAbove(c));
+ assertTrue(a.isAtOrBelow(c));
+ assertTrue(a.isBelow(c));
+
+ assertTrue(c.isAbove(a));
+ assertTrue(c.isAtOrAbove(a));
+ assertFalse(c.isAtOrBelow(a));
+ assertFalse(c.isBelow(a));
+
+ assertFalse(c.isAbove(d));
+ assertFalse(c.isAtOrAbove(d));
+ assertTrue(c.isAtOrBelow(d));
+ assertTrue(c.isBelow(d));
+
+ assertFalse(d.isAbove(e));
+ assertFalse(d.isAtOrAbove(e));
+ assertTrue(d.isAtOrBelow(e));
+ assertTrue(d.isBelow(e));
+
+ assertFalse(e.isAbove(f));
+ assertFalse(e.isAtOrAbove(f));
+ assertTrue(e.isAtOrBelow(f));
+ assertTrue(e.isBelow(f));
+
+ assertFalse(f.isAbove(g));
+ assertFalse(f.isAtOrAbove(g));
+ assertTrue(f.isAtOrBelow(g));
+ assertTrue(f.isBelow(g));
+
+ List versions = new ArrayList<>(List.of(a, b, c, d, e, f, g));
+ Collections.shuffle(versions);
+
+ versions.sort(Comparator.naturalOrder());
+ assertEquals(List.of(a, b, c, d, e, f, g), versions);
+
+ versions.sort(Comparator.reverseOrder());
+ assertEquals(List.of(g, f, e, d, c, b, a), versions);
+ }
+
+ @Test
+ public void testHashCode() {
+ Version a = new Version(1, 2, 3, "-b0");
+ Version b = new Version(1, 2, 3, "-b0");
+
+ assertEquals(a.hashCode(), b.hashCode());
+ }
+
+ @Test
+ public void testEquals() {
+ Version a = new Version(1, 2, 3, "-b0");
+ Version b = new Version(1, 2, 3, "-b0");
+ Version c = new Version(1, 2, 3, "-b1");
+
+ assertEquals(a, a);
+ assertEquals(a, b);
+
+ assertNotEquals(a, c);
+ assertNotEquals(b, c);
+
+ assertNotEquals(a, new Object());
+ }
+
+ @Test
+ public void testToString() {
+ assertEquals("1.0.0", new Version(1, 0, 0, null).toString());
+ assertEquals("1.2.0", new Version(1, 2, 0, null).toString());
+ assertEquals("1.2.3", new Version(1, 2, 3, null).toString());
+ assertEquals("1.2.3-b0", new Version(1, 2, 3, "-b0").toString());
+ }
+
+ @Test
+ public void testJson() {
+ DummyClass dummy = new DummyClass(
+ new Version(1, 0, 0, null),
+ new Version(2, 3, 4, "-alpha"));
+
+ JsonElement json = AbstractHttpService.GSON.toJsonTree(dummy);
+ DummyClass other = AbstractHttpService.GSON.fromJson(json, DummyClass.class);
+
+ assertEquals(dummy, other);
+ }
+
+ private record DummyClass(Version fieldA, Version fieldB) {
+ }
+}
diff --git a/orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/WeightedRandomTest.java b/orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/WeightedRandomTest.java
index 7dd6e5d0..1396e2c9 100644
--- a/orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/WeightedRandomTest.java
+++ b/orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/WeightedRandomTest.java
@@ -14,7 +14,7 @@
public class WeightedRandomTest {
private static final long SEED = 1337;
- private static final int SAMPLES = 250_000;
+ private static final int SAMPLES = 1_000_000;
private static final double SIGMA = 2.0;
private WeightedRandom createWeightedRandom(Map weights) {
diff --git a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java
index 89fd71d1..95422e69 100644
--- a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java
+++ b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java
@@ -1,17 +1,19 @@
package net.imprex.orebfuscator;
-import java.lang.reflect.Constructor;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
import dev.imprex.orebfuscator.config.api.Config;
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
import dev.imprex.orebfuscator.interop.RegistryAccessor;
import dev.imprex.orebfuscator.logging.OfcLogger;
import dev.imprex.orebfuscator.util.BlockPos;
+import java.lang.reflect.Constructor;
+import java.util.concurrent.CompletableFuture;
import net.imprex.orebfuscator.nms.NmsManager;
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
import net.imprex.orebfuscator.util.MinecraftVersion;
import net.imprex.orebfuscator.util.ServerVersion;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.jspecify.annotations.Nullable;
public class OrebfuscatorNms {
@@ -51,36 +53,12 @@ public static AbstractRegionFileCache> createRegionFileCache(Config config) {
return instance.createRegionFileCache(config);
}
- public static int getUniqueBlockStateCount() {
- return instance.getUniqueBlockStateCount();
- }
-
- public static int getMaxBitsPerBlockState() {
- return instance.getMaxBitsPerBlockState();
- }
-
- public static boolean isAir(int blockId) {
- return instance.isAir(blockId);
- }
-
- public static boolean isOccluding(int blockId) {
- return instance.isOccluding(blockId);
- }
-
- public static boolean isBlockEntity(int blockId) {
- return instance.isBlockEntity(blockId);
- }
-
- public static ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) {
- return instance.getReadOnlyChunk(world, chunkX, chunkZ);
- }
-
- public static int getBlockState(World world, BlockPos position) {
- return getBlockState(world, position.x(), position.y(), position.z());
+ public static CompletableFuture<@Nullable ChunkAccessor> getChunkFuture(World world, int chunkX, int chunkZ) {
+ return instance.getChunkFuture(world, chunkX, chunkZ);
}
- public static int getBlockState(World world, int x, int y, int z) {
- return instance.getBlockState(world, x, y, z);
+ public static @Nullable ChunkAccessor getChunkNow(World world, int chunkX, int chunkZ) {
+ return instance.getChunkNow(world, chunkX, chunkZ);
}
public static void sendBlockUpdates(World world, Iterable iterable) {
diff --git a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/AbstractNmsManager.java b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/AbstractNmsManager.java
index a1b3e411..59f36ea7 100644
--- a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/AbstractNmsManager.java
+++ b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/AbstractNmsManager.java
@@ -1,23 +1,24 @@
package net.imprex.orebfuscator.nms;
-import java.util.HashMap;
-import java.util.Map;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import dev.imprex.orebfuscator.reflect.Reflector;
import dev.imprex.orebfuscator.reflect.accessor.MethodAccessor;
import dev.imprex.orebfuscator.util.BlockProperties;
import dev.imprex.orebfuscator.util.BlockStateProperties;
import dev.imprex.orebfuscator.util.BlockTag;
-import dev.imprex.orebfuscator.util.MathUtil;
import dev.imprex.orebfuscator.util.NamespacedKey;
+import dev.imprex.orebfuscator.util.QuickMaths;
+import java.util.HashMap;
+import java.util.Map;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
public abstract class AbstractNmsManager implements NmsManager {
- private static MethodAccessor worldGetHandle;
- private static MethodAccessor playerGetHandle;
+ private static @Nullable MethodAccessor worldGetHandle;
+ private static @Nullable MethodAccessor playerGetHandle;
protected static T worldHandle(World world, Class targetClass) {
if (worldGetHandle == null) {
@@ -52,7 +53,7 @@ protected static T playerHandle(Player player, Class targetClass) {
public AbstractNmsManager(int uniqueBlockStateCount) {
this.uniqueBlockStateCount = uniqueBlockStateCount;
- this.maxBitsPerBlockState = MathUtil.ceilLog2(uniqueBlockStateCount);
+ this.maxBitsPerBlockState = QuickMaths.ceilLog2(uniqueBlockStateCount);
this.blockStates = new BlockStateProperties[uniqueBlockStateCount];
}
@@ -80,13 +81,13 @@ public final int getMaxBitsPerBlockState() {
}
@Override
- public final @Nullable BlockProperties getBlockByName(@NotNull String name) {
- return this.blocks.get(NamespacedKey.fromString(name));
+ public final @Nullable BlockProperties getBlockByName(String name) {
+ return NamespacedKey.tryParse(name).map(this.blocks::get).orElse(null);
}
@Override
- public final @Nullable BlockTag getBlockTagByName(@NotNull String name) {
- return this.tags.get(NamespacedKey.fromString(name));
+ public final @Nullable BlockTag getBlockTagByName(String name) {
+ return NamespacedKey.tryParse(name).map(this.tags::get).orElse(null);
}
@Override
@@ -94,6 +95,11 @@ public final boolean isAir(int id) {
return this.blockStates[id].isAir();
}
+ @Override
+ public final boolean isLava(int id) {
+ return this.blockStates[id].isLava();
+ }
+
@Override
public final boolean isOccluding(int id) {
return this.blockStates[id].isOccluding();
diff --git a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/NmsManager.java
index b61e354d..b1a98af7 100644
--- a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/NmsManager.java
+++ b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/NmsManager.java
@@ -1,20 +1,24 @@
package net.imprex.orebfuscator.nms;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
-
import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
import dev.imprex.orebfuscator.config.api.Config;
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
import dev.imprex.orebfuscator.interop.RegistryAccessor;
import dev.imprex.orebfuscator.util.BlockPos;
+import java.util.concurrent.CompletableFuture;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
public interface NmsManager extends RegistryAccessor {
AbstractRegionFileCache> createRegionFileCache(Config config);
- ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ);
+ CompletableFuture<@Nullable ChunkAccessor> getChunkFuture(World world, int chunkX, int chunkZ);
- int getBlockState(World world, int x, int y, int z);
+ @Nullable ChunkAccessor getChunkNow(World world, int chunkX, int chunkZ);
void sendBlockUpdates(World world, Iterable iterable);
diff --git a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/ReadOnlyChunk.java b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/ReadOnlyChunk.java
deleted file mode 100644
index ad28dbe3..00000000
--- a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/ReadOnlyChunk.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package net.imprex.orebfuscator.nms;
-
-public interface ReadOnlyChunk {
-
- int getBlockState(int x, int y, int z);
-}
diff --git a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java
index 25dcbf1e..c1151084 100644
--- a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java
+++ b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java
@@ -1,18 +1,16 @@
package net.imprex.orebfuscator.util;
+import dev.imprex.orebfuscator.logging.OfcLogger;
+import dev.imprex.orebfuscator.util.Version;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import org.bukkit.Bukkit;
-import dev.imprex.orebfuscator.logging.OfcLogger;
-import dev.imprex.orebfuscator.util.Version;
-
public final class MinecraftVersion {
- private static final class NmsMapping {
+ private record NmsMapping(Version version, String nmsVersion) {
private static final List MAPPINGS = new ArrayList<>();
@@ -42,19 +40,15 @@ public static String get(Version version) {
throw new RuntimeException("Can't get nms package version for minecraft version: " + version);
}
- private final Version version;
- private final String nmsVersion;
-
- public NmsMapping(String version, String nmsVersion) {
- this.version = Version.parse(version);
- this.nmsVersion = nmsVersion;
+ private NmsMapping(String version, String nmsVersion) {
+ this(Version.parse(version), nmsVersion);
}
}
private static final Pattern PACKAGE_PATTERN = Pattern.compile("org\\.bukkit\\.craftbukkit\\.(v\\d+_\\d+_R\\d+)");
private static final Version CURRENT_VERSION = Version.parse(Bukkit.getBukkitVersion());
- private static String NMS_VERSION;
+ private static final String NMS_VERSION;
static {
String craftBukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/pom.xml b/orebfuscator-nms/orebfuscator-nms-v1_16_R1/pom.xml
deleted file mode 100644
index adf33b2a..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/pom.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
- 4.0.0
-
-
- net.imprex
- orebfuscator-nms
- ${revision}
-
-
- orebfuscator-nms-v1_16_R1
- jar
-
-
-
- net.imprex
- orebfuscator-nms-api
- ${revision}
- provided
-
-
- net.dmulloy2
- ProtocolLib
- ${dependency.protocollib.version}
- provided
-
-
- org.spigotmc
- spigot
- 1.16.1-R0.1-SNAPSHOT
- provided
-
-
-
\ No newline at end of file
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/NmsManager.java
deleted file mode 100644
index 3e97717b..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/NmsManager.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package net.imprex.orebfuscator.nms.v1_16_R1;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.events.PacketContainer;
-import com.comphenix.protocol.wrappers.ChunkCoordIntPair;
-import com.comphenix.protocol.wrappers.MultiBlockChangeInfo;
-import com.comphenix.protocol.wrappers.WrappedBlockData;
-import com.google.common.collect.ImmutableList;
-import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
-import dev.imprex.orebfuscator.config.api.Config;
-import dev.imprex.orebfuscator.util.BlockPos;
-import dev.imprex.orebfuscator.util.BlockProperties;
-import dev.imprex.orebfuscator.util.BlockStateProperties;
-import dev.imprex.orebfuscator.util.BlockTag;
-import dev.imprex.orebfuscator.util.NamespacedKey;
-import net.imprex.orebfuscator.nms.AbstractNmsManager;
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
-import net.minecraft.server.v1_16_R1.Block;
-import net.minecraft.server.v1_16_R1.BlockAccessAir;
-import net.minecraft.server.v1_16_R1.BlockPosition;
-import net.minecraft.server.v1_16_R1.Blocks;
-import net.minecraft.server.v1_16_R1.Chunk;
-import net.minecraft.server.v1_16_R1.ChunkProviderServer;
-import net.minecraft.server.v1_16_R1.ChunkSection;
-import net.minecraft.server.v1_16_R1.EntityPlayer;
-import net.minecraft.server.v1_16_R1.IBlockData;
-import net.minecraft.server.v1_16_R1.IRegistry;
-import net.minecraft.server.v1_16_R1.MinecraftKey;
-import net.minecraft.server.v1_16_R1.Packet;
-import net.minecraft.server.v1_16_R1.PacketListenerPlayOut;
-import net.minecraft.server.v1_16_R1.ResourceKey;
-import net.minecraft.server.v1_16_R1.Tag;
-import net.minecraft.server.v1_16_R1.TagsBlock;
-import net.minecraft.server.v1_16_R1.TileEntity;
-import net.minecraft.server.v1_16_R1.WorldServer;
-
-public class NmsManager extends AbstractNmsManager {
-
- private static final int BLOCK_ID_AIR = Block.getCombinedId(Blocks.AIR.getBlockData());
-
- static int getBlockState(Chunk chunk, int x, int y, int z) {
- ChunkSection[] sections = chunk.getSections();
-
- int sectionIndex = y >> 4;
- if (sectionIndex >= 0 && sectionIndex < sections.length) {
- ChunkSection section = sections[sectionIndex];
- if (section != null && !ChunkSection.a(section)) {
- return Block.getCombinedId(section.getType(x & 0xF, y & 0xF, z & 0xF));
- }
- }
-
- return BLOCK_ID_AIR;
- }
-
- private static WorldServer level(World world) {
- return worldHandle(world, WorldServer.class);
- }
-
- private static EntityPlayer player(Player player) {
- return playerHandle(player, EntityPlayer.class);
- }
-
- public NmsManager() {
- super(Block.REGISTRY_ID.a());
-
- for (Map.Entry, Block> entry : IRegistry.BLOCK.c()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().a().toString());
- Block block = entry.getValue();
-
- ImmutableList possibleBlockStates = block.getStates().a();
- BlockProperties.Builder builder = BlockProperties.builder(namespacedKey);
-
- for (IBlockData blockState : possibleBlockStates) {
- BlockStateProperties properties = BlockStateProperties.builder(Block.getCombinedId(blockState))
- .withIsAir(blockState.isAir())
- .withIsOccluding(blockState.i(BlockAccessAir.INSTANCE, BlockPosition.ZERO)/*isSolidRender*/)
- .withIsBlockEntity(block.isTileEntity())
- .withIsDefaultState(Objects.equals(block.getBlockData(), blockState))
- .build();
-
- builder.withBlockState(properties);
- }
-
- registerBlockProperties(builder.build());
- }
-
- for (Entry> entry : TagsBlock.b().b().entrySet()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().toString());
-
- Set blocks = new HashSet<>();
- for (Block block : entry.getValue().getTagged()) {
- BlockProperties properties = getBlockByName(IRegistry.BLOCK.getKey(block).toString());
- if (properties != null) {
- blocks.add(properties);
- }
- }
-
- registerBlockTag(new BlockTag(namespacedKey, blocks));
- }
- }
-
- @Override
- public AbstractRegionFileCache> createRegionFileCache(Config config) {
- return new RegionFileCache(config.cache());
- }
-
- @Override
- public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) {
- ChunkProviderServer chunkProviderServer = level(world).getChunkProvider();
- Chunk chunk = chunkProviderServer.getChunkAt(chunkX, chunkZ, true);
- return new ReadOnlyChunkWrapper(chunk);
- }
-
- @Override
- public int getBlockState(World world, int x, int y, int z) {
- ChunkProviderServer serverChunkCache = level(world).getChunkProvider();
- if (!serverChunkCache.isChunkLoaded(x >> 4, z >> 4)) {
- return BLOCK_ID_AIR;
- }
-
- Chunk chunk = serverChunkCache.getChunkAt(x >> 4, z >> 4, true);
- if (chunk == null) {
- return BLOCK_ID_AIR;
- }
-
- return getBlockState(chunk, x, y, z);
- }
-
- @Override
- public void sendBlockUpdates(World world, Iterable iterable) {
- ChunkProviderServer serverChunkCache = level(world).getChunkProvider();
- BlockPosition.MutableBlockPosition position = new BlockPosition.MutableBlockPosition();
-
- for (dev.imprex.orebfuscator.util.BlockPos pos : iterable) {
- position.c(pos.x(), pos.y(), pos.z());
- serverChunkCache.flagDirty(position);
- }
- }
-
- @Override
- public void sendBlockUpdates(Player player, Iterable iterable) {
- EntityPlayer serverPlayer = player(player);
- WorldServer level = serverPlayer.getWorldServer();
- ChunkProviderServer serverChunkCache = level.getChunkProvider();
-
- BlockPosition.MutableBlockPosition position = new BlockPosition.MutableBlockPosition();
- Map> sectionPackets = new HashMap<>();
- List> blockEntityPackets = new ArrayList<>();
-
- for (dev.imprex.orebfuscator.util.BlockPos pos : iterable) {
- if (!serverChunkCache.isChunkLoaded(pos.x() >> 4, pos.z() >> 4)) {
- continue;
- }
-
- position.c(pos.x(), pos.y(), pos.z());
- IBlockData blockState = level.getType(position);
-
- ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(pos.x() >> 4, pos.z() >> 4);
- short location = (short) ((pos.x() & 0xF) << 12 | (pos.z() & 0xF) << 8 | pos.y());
-
- sectionPackets.computeIfAbsent(chunkCoord, key -> new ArrayList<>())
- .add(new MultiBlockChangeInfo(location, WrappedBlockData.fromHandle(blockState), chunkCoord));
-
- if (blockState.getBlock().isTileEntity()) {
- TileEntity blockEntity = level.getTileEntity(position);
- if (blockEntity != null) {
- blockEntityPackets.add(blockEntity.getUpdatePacket());
- }
- }
- }
-
- for (Map.Entry> entry : sectionPackets.entrySet()) {
- List blockStates = entry.getValue();
- if (blockStates.size() == 1) {
- MultiBlockChangeInfo blockEntry = blockStates.get(0);
- var blockPosition = new com.comphenix.protocol.wrappers.BlockPosition(
- blockEntry.getAbsoluteX(), blockEntry.getY(), blockEntry.getAbsoluteZ());
-
- PacketContainer packet = new PacketContainer(PacketType.Play.Server.BLOCK_CHANGE);
- packet.getBlockPositionModifier().write(0, blockPosition);
- packet.getBlockData().write(0, blockEntry.getData());
- serverPlayer.playerConnection.sendPacket((Packet>) packet.getHandle());
- } else {
- PacketContainer packet = new PacketContainer(PacketType.Play.Server.MULTI_BLOCK_CHANGE);
- packet.getChunkCoordIntPairs().write(0, entry.getKey());
- packet.getMultiBlockChangeInfoArrays().write(0, blockStates.toArray(MultiBlockChangeInfo[]::new));
- serverPlayer.playerConnection.sendPacket((Packet>) packet.getHandle());
- }
- }
-
- for (Packet packet : blockEntityPackets) {
- serverPlayer.playerConnection.sendPacket(packet);
- }
- }
-}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/ReadOnlyChunkWrapper.java
deleted file mode 100644
index ff4a535f..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/ReadOnlyChunkWrapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.imprex.orebfuscator.nms.v1_16_R1;
-
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
-import net.minecraft.server.v1_16_R1.Chunk;
-
-public class ReadOnlyChunkWrapper implements ReadOnlyChunk {
-
- private final Chunk chunk;
-
- ReadOnlyChunkWrapper(Chunk chunk) {
- this.chunk = chunk;
- }
-
- @Override
- public int getBlockState(int x, int y, int z) {
- return NmsManager.getBlockState(chunk, x, y, z);
- }
-}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/RegionFileCache.java
deleted file mode 100644
index b9b1c1c3..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/RegionFileCache.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.imprex.orebfuscator.nms.v1_16_R1;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.file.Path;
-
-import org.bukkit.Bukkit;
-
-import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
-import dev.imprex.orebfuscator.config.api.CacheConfig;
-import dev.imprex.orebfuscator.util.ChunkCacheKey;
-import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
-import net.minecraft.server.v1_16_R1.DedicatedServer;
-import net.minecraft.server.v1_16_R1.RegionFile;
-import net.minecraft.server.v1_16_R1.RegionFileCompression;
-
-public class RegionFileCache extends AbstractRegionFileCache {
-
- RegionFileCache(CacheConfig cacheConfig) {
- super(cacheConfig);
- }
-
- @Override
- protected RegionFile createRegionFile(Path path) throws IOException {
- boolean isSyncChunkWrites = serverHandle(Bukkit.getServer(), DedicatedServer.class).isSyncChunkWrites();
- return new RegionFile(path, path.getParent(), RegionFileCompression.c, isSyncChunkWrites);
- }
-
- @Override
- protected void closeRegionFile(RegionFile t) throws IOException {
- t.close();
- }
-
- @Override
- protected DataInputStream createInputStream(RegionFile t, ChunkCacheKey key) throws IOException {
- return t.a(new ChunkCoordIntPair(key.x(), key.z()));
- }
-
- @Override
- protected DataOutputStream createOutputStream(RegionFile t, ChunkCacheKey key) throws IOException {
- return t.c(new ChunkCoordIntPair(key.x(), key.z()));
- }
-}
\ No newline at end of file
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/pom.xml b/orebfuscator-nms/orebfuscator-nms-v1_16_R2/pom.xml
deleted file mode 100644
index 7765f476..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/pom.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
- 4.0.0
-
-
- net.imprex
- orebfuscator-nms
- ${revision}
-
-
- orebfuscator-nms-v1_16_R2
- jar
-
-
-
- net.imprex
- orebfuscator-nms-api
- ${revision}
- provided
-
-
- net.dmulloy2
- ProtocolLib
- ${dependency.protocollib.version}
- provided
-
-
- org.spigotmc
- spigot
- 1.16.3-R0.1-SNAPSHOT
- provided
-
-
-
\ No newline at end of file
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/NmsManager.java
deleted file mode 100644
index 497cd2f1..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/NmsManager.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package net.imprex.orebfuscator.nms.v1_16_R2;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
-import com.comphenix.protocol.events.PacketContainer;
-import com.google.common.collect.ImmutableList;
-import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
-import dev.imprex.orebfuscator.config.api.Config;
-import dev.imprex.orebfuscator.util.BlockPos;
-import dev.imprex.orebfuscator.util.BlockProperties;
-import dev.imprex.orebfuscator.util.BlockStateProperties;
-import dev.imprex.orebfuscator.util.BlockTag;
-import dev.imprex.orebfuscator.util.NamespacedKey;
-import net.imprex.orebfuscator.nms.AbstractNmsManager;
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
-import net.minecraft.server.v1_16_R2.Block;
-import net.minecraft.server.v1_16_R2.BlockAccessAir;
-import net.minecraft.server.v1_16_R2.BlockPosition;
-import net.minecraft.server.v1_16_R2.Blocks;
-import net.minecraft.server.v1_16_R2.Chunk;
-import net.minecraft.server.v1_16_R2.ChunkProviderServer;
-import net.minecraft.server.v1_16_R2.ChunkSection;
-import net.minecraft.server.v1_16_R2.EntityPlayer;
-import net.minecraft.server.v1_16_R2.IBlockData;
-import net.minecraft.server.v1_16_R2.IRegistry;
-import net.minecraft.server.v1_16_R2.MinecraftKey;
-import net.minecraft.server.v1_16_R2.Packet;
-import net.minecraft.server.v1_16_R2.PacketListenerPlayOut;
-import net.minecraft.server.v1_16_R2.PacketPlayOutBlockChange;
-import net.minecraft.server.v1_16_R2.PacketPlayOutMultiBlockChange;
-import net.minecraft.server.v1_16_R2.ResourceKey;
-import net.minecraft.server.v1_16_R2.SectionPosition;
-import net.minecraft.server.v1_16_R2.Tag;
-import net.minecraft.server.v1_16_R2.TagsBlock;
-import net.minecraft.server.v1_16_R2.TileEntity;
-import net.minecraft.server.v1_16_R2.WorldServer;
-
-public class NmsManager extends AbstractNmsManager {
-
- private static final int BLOCK_ID_AIR = Block.getCombinedId(Blocks.AIR.getBlockData());
-
- static int getBlockState(Chunk chunk, int x, int y, int z) {
- ChunkSection[] sections = chunk.getSections();
-
- int sectionIndex = y >> 4;
- if (sectionIndex >= 0 && sectionIndex < sections.length) {
- ChunkSection section = sections[sectionIndex];
- if (section != null && !ChunkSection.a(section)) {
- return Block.getCombinedId(section.getType(x & 0xF, y & 0xF, z & 0xF));
- }
- }
-
- return BLOCK_ID_AIR;
- }
-
- private static WorldServer level(World world) {
- return worldHandle(world, WorldServer.class);
- }
-
- private static EntityPlayer player(Player player) {
- return playerHandle(player, EntityPlayer.class);
- }
-
- public NmsManager() {
- super(Block.REGISTRY_ID.a());
-
- for (Map.Entry, Block> entry : IRegistry.BLOCK.d()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().a().toString());
- Block block = entry.getValue();
-
- ImmutableList possibleBlockStates = block.getStates().a();
- BlockProperties.Builder builder = BlockProperties.builder(namespacedKey);
-
- for (IBlockData blockState : possibleBlockStates) {
- BlockStateProperties properties = BlockStateProperties.builder(Block.getCombinedId(blockState))
- .withIsAir(blockState.isAir())
- .withIsOccluding(blockState.i(BlockAccessAir.INSTANCE, BlockPosition.ZERO)/*isSolidRender*/)
- .withIsBlockEntity(block.isTileEntity())
- .withIsDefaultState(Objects.equals(block.getBlockData(), blockState))
- .build();
-
- builder.withBlockState(properties);
- }
-
- registerBlockProperties(builder.build());
- }
-
- for (Entry> entry : TagsBlock.a().a().entrySet()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().toString());
-
- Set blocks = new HashSet<>();
- for (Block block : entry.getValue().getTagged()) {
- BlockProperties properties = getBlockByName(IRegistry.BLOCK.getKey(block).toString());
- if (properties != null) {
- blocks.add(properties);
- }
- }
-
- registerBlockTag(new BlockTag(namespacedKey, blocks));
- }
- }
-
- @Override
- public AbstractRegionFileCache> createRegionFileCache(Config config) {
- return new RegionFileCache(config.cache());
- }
-
- @Override
- public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) {
- ChunkProviderServer chunkProviderServer = level(world).getChunkProvider();
- Chunk chunk = chunkProviderServer.getChunkAt(chunkX, chunkZ, true);
- return new ReadOnlyChunkWrapper(chunk);
- }
-
- @Override
- public int getBlockState(World world, int x, int y, int z) {
- ChunkProviderServer serverChunkCache = level(world).getChunkProvider();
- if (!serverChunkCache.isChunkLoaded(x >> 4, z >> 4)) {
- return BLOCK_ID_AIR;
- }
-
- Chunk chunk = serverChunkCache.getChunkAt(x >> 4, z >> 4, true);
- if (chunk == null) {
- return BLOCK_ID_AIR;
- }
-
- return getBlockState(chunk, x, y, z);
- }
-
- @Override
- public void sendBlockUpdates(World world, Iterable iterable) {
- ChunkProviderServer serverChunkCache = level(world).getChunkProvider();
- BlockPosition.MutableBlockPosition position = new BlockPosition.MutableBlockPosition();
-
- for (dev.imprex.orebfuscator.util.BlockPos pos : iterable) {
- position.c(pos.x(), pos.y(), pos.z());
- serverChunkCache.flagDirty(position);
- }
- }
-
- @Override
- public void sendBlockUpdates(Player player, Iterable iterable) {
- EntityPlayer serverPlayer = player(player);
- WorldServer level = serverPlayer.getWorldServer();
- ChunkProviderServer serverChunkCache = level.getChunkProvider();
-
- BlockPosition.MutableBlockPosition position = new BlockPosition.MutableBlockPosition();
- Map> sectionPackets = new HashMap<>();
- List> blockEntityPackets = new ArrayList<>();
-
- for (dev.imprex.orebfuscator.util.BlockPos pos : iterable) {
- if (!serverChunkCache.isChunkLoaded(pos.x() >> 4, pos.z() >> 4)) {
- continue;
- }
-
- position.c(pos.x(), pos.y(), pos.z());
- IBlockData blockState = level.getType(position);
-
- sectionPackets.computeIfAbsent(SectionPosition.a(position), key -> new HashMap<>())
- .put(SectionPosition.b(position), blockState);
-
- if (blockState.getBlock().isTileEntity()) {
- TileEntity blockEntity = level.getTileEntity(position);
- if (blockEntity != null) {
- blockEntityPackets.add(blockEntity.getUpdatePacket());
- }
- }
- }
-
- for (Map.Entry> entry : sectionPackets.entrySet()) {
- Map blockStates = entry.getValue();
- if (blockStates.size() == 1) {
- Map.Entry blockEntry = blockStates.entrySet().iterator().next();
- BlockPosition blockPosition = entry.getKey().g(blockEntry.getKey());
- serverPlayer.playerConnection.sendPacket(new PacketPlayOutBlockChange(blockPosition, blockEntry.getValue()));
- } else {
- // fix #324: use empty constructor cause ChunkSection can only be null for spigot forks
- PacketContainer packet = PacketContainer.fromPacket(new PacketPlayOutMultiBlockChange());
- packet.getSpecificModifier(SectionPosition.class).write(0, entry.getKey());
- packet.getSpecificModifier(short[].class).write(0, toShortArray(blockStates.keySet()));
- packet.getSpecificModifier(IBlockData[].class).write(0, blockStates.values().toArray(IBlockData[]::new));
- serverPlayer.playerConnection.sendPacket((Packet>) packet.getHandle());
- }
- }
-
- for (Packet packet : blockEntityPackets) {
- serverPlayer.playerConnection.sendPacket(packet);
- }
- }
-
- private static short[] toShortArray(Set set) {
- short[] array = new short[set.size()];
-
- int i = 0;
- for (Short value : set) {
- array[i++] = value;
- }
-
- return array;
- }
-}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/ReadOnlyChunkWrapper.java
deleted file mode 100644
index ce66968f..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/ReadOnlyChunkWrapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.imprex.orebfuscator.nms.v1_16_R2;
-
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
-import net.minecraft.server.v1_16_R2.Chunk;
-
-public class ReadOnlyChunkWrapper implements ReadOnlyChunk {
-
- private final Chunk chunk;
-
- ReadOnlyChunkWrapper(Chunk chunk) {
- this.chunk = chunk;
- }
-
- @Override
- public int getBlockState(int x, int y, int z) {
- return NmsManager.getBlockState(chunk, x, y, z);
- }
-}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/RegionFileCache.java
deleted file mode 100644
index 72800adf..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/RegionFileCache.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.imprex.orebfuscator.nms.v1_16_R2;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.file.Path;
-
-import org.bukkit.Bukkit;
-
-import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
-import dev.imprex.orebfuscator.config.api.CacheConfig;
-import dev.imprex.orebfuscator.util.ChunkCacheKey;
-import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
-import net.minecraft.server.v1_16_R2.DedicatedServer;
-import net.minecraft.server.v1_16_R2.RegionFile;
-import net.minecraft.server.v1_16_R2.RegionFileCompression;
-
-public class RegionFileCache extends AbstractRegionFileCache {
-
- RegionFileCache(CacheConfig cacheConfig) {
- super(cacheConfig);
- }
-
- @Override
- protected RegionFile createRegionFile(Path path) throws IOException {
- boolean isSyncChunkWrites = serverHandle(Bukkit.getServer(), DedicatedServer.class).isSyncChunkWrites();
- return new RegionFile(path, path.getParent(), RegionFileCompression.c, isSyncChunkWrites);
- }
-
- @Override
- protected void closeRegionFile(RegionFile t) throws IOException {
- t.close();
- }
-
- @Override
- protected DataInputStream createInputStream(RegionFile t, ChunkCacheKey key) throws IOException {
- return t.a(new ChunkCoordIntPair(key.x(), key.z()));
- }
-
- @Override
- protected DataOutputStream createOutputStream(RegionFile t, ChunkCacheKey key) throws IOException {
- return t.c(new ChunkCoordIntPair(key.x(), key.z()));
- }
-}
\ No newline at end of file
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/DefaultChunkAccessor.java
similarity index 50%
rename from orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/ReadOnlyChunkWrapper.java
rename to orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/DefaultChunkAccessor.java
index 1fb7a511..caffc3eb 100644
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/ReadOnlyChunkWrapper.java
+++ b/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/DefaultChunkAccessor.java
@@ -1,15 +1,9 @@
package net.imprex.orebfuscator.nms.v1_16_R3;
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
import net.minecraft.server.v1_16_R3.Chunk;
-public class ReadOnlyChunkWrapper implements ReadOnlyChunk {
-
- private final Chunk chunk;
-
- ReadOnlyChunkWrapper(Chunk chunk) {
- this.chunk = chunk;
- }
+public record DefaultChunkAccessor(Chunk chunk) implements ChunkAccessor {
@Override
public int getBlockState(int x, int y, int z) {
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/NmsManager.java
index 3fd5f17f..8269e67d 100644
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/NmsManager.java
+++ b/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/NmsManager.java
@@ -1,26 +1,25 @@
package net.imprex.orebfuscator.nms.v1_16_R3;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.collect.ImmutableList;
import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
import dev.imprex.orebfuscator.config.api.Config;
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
import dev.imprex.orebfuscator.util.BlockPos;
import dev.imprex.orebfuscator.util.BlockProperties;
import dev.imprex.orebfuscator.util.BlockStateProperties;
import dev.imprex.orebfuscator.util.BlockTag;
import dev.imprex.orebfuscator.util.NamespacedKey;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import net.imprex.orebfuscator.nms.AbstractNmsManager;
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
import net.minecraft.server.v1_16_R3.Block;
import net.minecraft.server.v1_16_R3.BlockAccessAir;
import net.minecraft.server.v1_16_R3.BlockPosition;
@@ -42,13 +41,18 @@
import net.minecraft.server.v1_16_R3.TagsBlock;
import net.minecraft.server.v1_16_R3.TileEntity;
import net.minecraft.server.v1_16_R3.WorldServer;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
public class NmsManager extends AbstractNmsManager {
private static final int BLOCK_ID_AIR = Block.getCombinedId(Blocks.AIR.getBlockData());
static int getBlockState(Chunk chunk, int x, int y, int z) {
- ChunkSection[] sections = chunk.getSections();
+ @Nullable ChunkSection[] sections = chunk.getSections();
int sectionIndex = y >> 4;
if (sectionIndex >= 0 && sectionIndex < sections.length) {
@@ -72,8 +76,8 @@ private static EntityPlayer player(Player player) {
public NmsManager() {
super(Block.REGISTRY_ID.a());
- for (Map.Entry, Block> entry : IRegistry.BLOCK.d()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().a().toString());
+ for (Entry, Block> entry : IRegistry.BLOCK.d()) {
+ NamespacedKey namespacedKey = NamespacedKey.parse(entry.getKey().a().toString());
Block block = entry.getValue();
ImmutableList possibleBlockStates = block.getStates().a();
@@ -82,6 +86,7 @@ public NmsManager() {
for (IBlockData blockState : possibleBlockStates) {
BlockStateProperties properties = BlockStateProperties.builder(Block.getCombinedId(blockState))
.withIsAir(blockState.isAir())
+ .withIsLava(block == Blocks.LAVA)
.withIsOccluding(blockState.i(BlockAccessAir.INSTANCE, BlockPosition.ZERO)/*isSolidRender*/)
.withIsBlockEntity(block.isTileEntity())
.withIsDefaultState(Objects.equals(block.getBlockData(), blockState))
@@ -94,7 +99,7 @@ public NmsManager() {
}
for (Entry> entry : TagsBlock.a().a().entrySet()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().toString());
+ NamespacedKey namespacedKey = NamespacedKey.parse(entry.getKey().toString());
Set blocks = new HashSet<>();
for (Block block : entry.getValue().getTagged()) {
@@ -114,33 +119,29 @@ public AbstractRegionFileCache> createRegionFileCache(Config config) {
}
@Override
- public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) {
- ChunkProviderServer chunkProviderServer = level(world).getChunkProvider();
- Chunk chunk = chunkProviderServer.getChunkAt(chunkX, chunkZ, true);
- return new ReadOnlyChunkWrapper(chunk);
+ public CompletableFuture<@Nullable ChunkAccessor> getChunkFuture(World world, int chunkX, int chunkZ) {
+ Chunk chunk = level(world).getChunkProvider().getChunkAt(chunkX, chunkZ, true);
+ return CompletableFuture.completedFuture(chunk != null ? new DefaultChunkAccessor(chunk) : null);
}
@Override
- public int getBlockState(World world, int x, int y, int z) {
+ public @Nullable ChunkAccessor getChunkNow(World world, int chunkX, int chunkZ) {
ChunkProviderServer serverChunkCache = level(world).getChunkProvider();
- if (!serverChunkCache.isChunkLoaded(x >> 4, z >> 4)) {
- return BLOCK_ID_AIR;
- }
- Chunk chunk = serverChunkCache.getChunkAt(x >> 4, z >> 4, true);
- if (chunk == null) {
- return BLOCK_ID_AIR;
+ Chunk chunk = serverChunkCache.a(chunkX, chunkZ);
+ if (chunk == null && serverChunkCache.isChunkLoaded(chunkX, chunkZ)) {
+ chunk = serverChunkCache.getChunkAt(chunkX, chunkZ, false);
}
- return getBlockState(chunk, x, y, z);
+ return chunk != null ? new DefaultChunkAccessor(chunk) : null;
}
@Override
- public void sendBlockUpdates(World world, Iterable iterable) {
+ public void sendBlockUpdates(World world, Iterable iterable) {
ChunkProviderServer serverChunkCache = level(world).getChunkProvider();
BlockPosition.MutableBlockPosition position = new BlockPosition.MutableBlockPosition();
- for (dev.imprex.orebfuscator.util.BlockPos pos : iterable) {
+ for (BlockPos pos : iterable) {
position.c(pos.x(), pos.y(), pos.z());
serverChunkCache.flagDirty(position);
}
@@ -156,7 +157,7 @@ public void sendBlockUpdates(Player player, Iterable iterable) {
Map> sectionPackets = new HashMap<>();
List> blockEntityPackets = new ArrayList<>();
- for (dev.imprex.orebfuscator.util.BlockPos pos : iterable) {
+ for (BlockPos pos : iterable) {
if (!serverChunkCache.isChunkLoaded(pos.x() >> 4, pos.z() >> 4)) {
continue;
}
@@ -170,15 +171,18 @@ public void sendBlockUpdates(Player player, Iterable iterable) {
if (blockState.getBlock().isTileEntity()) {
TileEntity blockEntity = level.getTileEntity(position);
if (blockEntity != null) {
- blockEntityPackets.add(blockEntity.getUpdatePacket());
+ Packet packet = blockEntity.getUpdatePacket();
+ if (packet != null) {
+ blockEntityPackets.add(packet);
+ }
}
}
}
- for (Map.Entry> entry : sectionPackets.entrySet()) {
+ for (Entry> entry : sectionPackets.entrySet()) {
Map blockStates = entry.getValue();
if (blockStates.size() == 1) {
- Map.Entry blockEntry = blockStates.entrySet().iterator().next();
+ Entry blockEntry = blockStates.entrySet().iterator().next();
BlockPosition blockPosition = entry.getKey().g(blockEntry.getKey());
serverPlayer.playerConnection.sendPacket(new PacketPlayOutBlockChange(blockPosition, blockEntry.getValue()));
} else {
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/RegionFileCache.java
index 2791a238..4a081cf9 100644
--- a/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/RegionFileCache.java
+++ b/orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/RegionFileCache.java
@@ -1,20 +1,21 @@
package net.imprex.orebfuscator.nms.v1_16_R3;
+import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
+import dev.imprex.orebfuscator.config.api.CacheConfig;
+import dev.imprex.orebfuscator.util.ChunkCacheKey;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.file.Path;
-
-import org.bukkit.Bukkit;
-
-import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
-import dev.imprex.orebfuscator.config.api.CacheConfig;
-import dev.imprex.orebfuscator.util.ChunkCacheKey;
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
import net.minecraft.server.v1_16_R3.DedicatedServer;
import net.minecraft.server.v1_16_R3.RegionFile;
import net.minecraft.server.v1_16_R3.RegionFileCompression;
+import org.bukkit.Bukkit;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
public class RegionFileCache extends AbstractRegionFileCache {
RegionFileCache(CacheConfig cacheConfig) {
@@ -33,7 +34,7 @@ protected void closeRegionFile(RegionFile t) throws IOException {
}
@Override
- protected DataInputStream createInputStream(RegionFile t, ChunkCacheKey key) throws IOException {
+ protected @Nullable DataInputStream createInputStream(RegionFile t, ChunkCacheKey key) throws IOException {
return t.a(new ChunkCoordIntPair(key.x(), key.z()));
}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/DefaultChunkAccessor.java b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/DefaultChunkAccessor.java
new file mode 100644
index 00000000..8ed70d1d
--- /dev/null
+++ b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/DefaultChunkAccessor.java
@@ -0,0 +1,12 @@
+package net.imprex.orebfuscator.nms.v1_17_R1;
+
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
+import net.minecraft.world.level.chunk.ChunkAccess;
+
+public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor {
+
+ @Override
+ public int getBlockState(int x, int y, int z) {
+ return NmsManager.getBlockState(chunk, x, y, z);
+ }
+}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/NmsManager.java
index 22fb66ee..d80997f8 100644
--- a/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/NmsManager.java
+++ b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/NmsManager.java
@@ -1,25 +1,24 @@
package net.imprex.orebfuscator.nms.v1_17_R1;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.collect.ImmutableList;
import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
import dev.imprex.orebfuscator.config.api.Config;
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
import dev.imprex.orebfuscator.util.BlockProperties;
import dev.imprex.orebfuscator.util.BlockStateProperties;
import dev.imprex.orebfuscator.util.BlockTag;
import dev.imprex.orebfuscator.util.NamespacedKey;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import net.imprex.orebfuscator.nms.AbstractNmsManager;
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
@@ -38,15 +37,22 @@
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
public class NmsManager extends AbstractNmsManager {
private static final int BLOCK_ID_AIR = Block.getId(Blocks.AIR.defaultBlockState());
- static int getBlockState(LevelChunk chunk, int x, int y, int z) {
- LevelChunkSection[] sections = chunk.getSections();
+ static int getBlockState(ChunkAccess chunk, int x, int y, int z) {
+ @Nullable LevelChunkSection[] sections = chunk.getSections();
int sectionIndex = chunk.getSectionIndex(y);
if (sectionIndex >= 0 && sectionIndex < sections.length) {
@@ -71,7 +77,7 @@ public NmsManager() {
super(Block.BLOCK_STATE_REGISTRY.size());
for (Map.Entry, Block> entry : Registry.BLOCK.entrySet()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().location().toString());
+ NamespacedKey namespacedKey = NamespacedKey.parse(entry.getKey().location().toString());
Block block = entry.getValue();
ImmutableList possibleBlockStates = block.getStateDefinition().getPossibleStates();
@@ -80,6 +86,7 @@ public NmsManager() {
for (BlockState blockState : possibleBlockStates) {
BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState))
.withIsAir(blockState.isAir())
+ .withIsLava(block == Blocks.LAVA)
.withIsOccluding(blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO))
.withIsBlockEntity(blockState.hasBlockEntity())
.withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState))
@@ -92,7 +99,7 @@ public NmsManager() {
}
for (Map.Entry> entry : BlockTags.getAllTags().getAllTags().entrySet()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().toString());
+ NamespacedKey namespacedKey = NamespacedKey.parse(entry.getKey().toString());
Set blocks = new HashSet<>();
for (Block block : entry.getValue().getValues()) {
@@ -112,25 +119,25 @@ public AbstractRegionFileCache> createRegionFileCache(Config config) {
}
@Override
- public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) {
- ServerChunkCache serverChunkCache = level(world).getChunkProvider();
- LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true);
- return new ReadOnlyChunkWrapper(chunk);
+ public CompletableFuture<@Nullable ChunkAccessor> getChunkFuture(World world, int chunkX, int chunkZ) {
+ return level(world).getChunkProvider()
+ .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true)
+ .thenApply(result -> {
+ var chunk = result.left().orElse(null);
+ return chunk != null ? new DefaultChunkAccessor(chunk) : null;
+ });
}
@Override
- public int getBlockState(World world, int x, int y, int z) {
+ public @Nullable ChunkAccessor getChunkNow(World world, int chunkX, int chunkZ) {
ServerChunkCache serverChunkCache = level(world).getChunkProvider();
- if (!serverChunkCache.isChunkLoaded(x >> 4, z >> 4)) {
- return BLOCK_ID_AIR;
- }
- LevelChunk chunk = serverChunkCache.getChunk(x >> 4, z >> 4, true);
- if (chunk == null) {
- return BLOCK_ID_AIR;
+ LevelChunk chunk = serverChunkCache.getChunkNow(chunkX, chunkZ);
+ if (chunk == null && serverChunkCache.isChunkLoaded(chunkX, chunkZ)) {
+ chunk = serverChunkCache.getChunk(chunkX, chunkZ, false);
}
- return getBlockState(chunk, x, y, z);
+ return chunk != null ? new DefaultChunkAccessor(chunk) : null;
}
@Override
@@ -169,7 +176,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket();
+ if (packet != null) {
+ blockEntityPackets.add(packet);
+ }
}
}
}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/ReadOnlyChunkWrapper.java
deleted file mode 100644
index 290da572..00000000
--- a/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/ReadOnlyChunkWrapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.imprex.orebfuscator.nms.v1_17_R1;
-
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
-import net.minecraft.world.level.chunk.LevelChunk;
-
-public class ReadOnlyChunkWrapper implements ReadOnlyChunk {
-
- private final LevelChunk chunk;
-
- ReadOnlyChunkWrapper(LevelChunk chunk) {
- this.chunk = chunk;
- }
-
- @Override
- public int getBlockState(int x, int y, int z) {
- return NmsManager.getBlockState(chunk, x, y, z);
- }
-}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/RegionFileCache.java
index 7e2724c9..e084291e 100644
--- a/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/RegionFileCache.java
+++ b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/RegionFileCache.java
@@ -1,20 +1,21 @@
package net.imprex.orebfuscator.nms.v1_17_R1;
+import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
+import dev.imprex.orebfuscator.config.api.CacheConfig;
+import dev.imprex.orebfuscator.util.ChunkCacheKey;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.file.Path;
-
-import org.bukkit.Bukkit;
-
-import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
-import dev.imprex.orebfuscator.config.api.CacheConfig;
-import dev.imprex.orebfuscator.util.ChunkCacheKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFile;
import net.minecraft.world.level.chunk.storage.RegionFileVersion;
+import org.bukkit.Bukkit;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
public class RegionFileCache extends AbstractRegionFileCache {
RegionFileCache(CacheConfig cacheConfig) {
@@ -33,7 +34,7 @@ protected void closeRegionFile(RegionFile t) throws IOException {
}
@Override
- protected DataInputStream createInputStream(RegionFile t, ChunkCacheKey key) throws IOException {
+ protected @Nullable DataInputStream createInputStream(RegionFile t, ChunkCacheKey key) throws IOException {
return t.getChunkDataInputStream(new ChunkPos(key.x(), key.z()));
}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/DefaultChunkAccessor.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/DefaultChunkAccessor.java
new file mode 100644
index 00000000..c5866dd2
--- /dev/null
+++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/DefaultChunkAccessor.java
@@ -0,0 +1,12 @@
+package net.imprex.orebfuscator.nms.v1_18_R1;
+
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
+import net.minecraft.world.level.chunk.ChunkAccess;
+
+public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor {
+
+ @Override
+ public int getBlockState(int x, int y, int z) {
+ return NmsManager.getBlockState(chunk, x, y, z);
+ }
+}
diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/NmsManager.java
index a37c2c4f..1008fe47 100644
--- a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/NmsManager.java
+++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/NmsManager.java
@@ -1,26 +1,25 @@
package net.imprex.orebfuscator.nms.v1_18_R1;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import org.bukkit.World;
-import org.bukkit.entity.Player;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.collect.ImmutableList;
import dev.imprex.orebfuscator.cache.AbstractRegionFileCache;
import dev.imprex.orebfuscator.config.api.Config;
+import dev.imprex.orebfuscator.interop.ChunkAccessor;
import dev.imprex.orebfuscator.util.BlockProperties;
import dev.imprex.orebfuscator.util.BlockStateProperties;
import dev.imprex.orebfuscator.util.BlockTag;
import dev.imprex.orebfuscator.util.NamespacedKey;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import net.imprex.orebfuscator.nms.AbstractNmsManager;
-import net.imprex.orebfuscator.nms.ReadOnlyChunk;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
@@ -40,15 +39,22 @@
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
public class NmsManager extends AbstractNmsManager {
private static final int BLOCK_ID_AIR = Block.getId(Blocks.AIR.defaultBlockState());
- static int getBlockState(LevelChunk chunk, int x, int y, int z) {
- LevelChunkSection[] sections = chunk.getSections();
+ static int getBlockState(ChunkAccess chunk, int x, int y, int z) {
+ @Nullable LevelChunkSection[] sections = chunk.getSections();
int sectionIndex = chunk.getSectionIndex(y);
if (sectionIndex >= 0 && sectionIndex < sections.length) {
@@ -73,7 +79,7 @@ public NmsManager() {
super(Block.BLOCK_STATE_REGISTRY.size());
for (Map.Entry, Block> entry : Registry.BLOCK.entrySet()) {
- NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().location().toString());
+ NamespacedKey namespacedKey = NamespacedKey.parse(entry.getKey().location().toString());
Block block = entry.getValue();
ImmutableList