From 11ab36a8bd2cc0e196f8f51dad5352f8785c08ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sun, 14 Dec 2025 04:08:54 +0100 Subject: [PATCH 01/14] chore: replace org.jetbrains.annotations with org.jspecify.annotations --- .../cache/AbstractRegionFileCache.java | 24 ++--- .../config/AbstractWorldConfig.java | 9 +- .../orebfuscator/config/ConfigLookup.java | 39 ++++++--- .../config/OrebfuscatorAdvancedConfig.java | 2 + .../config/OrebfuscatorBlockFlags.java | 16 ++-- .../config/OrebfuscatorCacheConfig.java | 4 +- .../config/OrebfuscatorConfig.java | 50 ++++++----- .../config/OrebfuscatorGeneralConfig.java | 2 + .../config/OrebfuscatorObfuscationConfig.java | 2 + .../config/OrebfuscatorProximityConfig.java | 2 + .../config/api/AdvancedConfig.java | 3 + .../orebfuscator/config/api/BlockFlags.java | 3 + .../orebfuscator/config/api/CacheConfig.java | 2 + .../orebfuscator/config/api/Config.java | 5 +- .../config/api/GeneralConfig.java | 3 + .../config/api/ObfuscationConfig.java | 2 + .../config/api/ProximityConfig.java | 2 + .../orebfuscator/config/api/WorldConfig.java | 3 + .../config/api/WorldConfigBundle.java | 8 +- .../config/components/BlockParser.java | 22 ++--- .../config/components/ConfigBlockValue.java | 19 ++-- .../components/ConfigFunctionValue.java | 10 +-- .../config/components/WeightedBlockList.java | 5 +- .../config/components/WorldMatcher.java | 6 +- .../config/context/ConfigMessage.java | 14 +-- .../config/context/ConfigParsingContext.java | 23 +++-- .../context/DefaultConfigParsingContext.java | 24 +++-- .../config/migrations/ConfigMigration.java | 9 +- .../config/migrations/ConfigMigrationV1.java | 5 +- .../config/migrations/ConfigMigrationV2.java | 8 +- .../config/migrations/ConfigMigrationV3.java | 5 +- .../config/migrations/ConfigMigrationV4.java | 8 +- .../config/migrations/ConfigMigrator.java | 2 + .../config/yaml/ConfigurationSection.java | 82 +++++++---------- .../yaml/InvalidConfigurationException.java | 4 +- .../config/yaml/NodeCommentData.java | 22 ++--- .../config/yaml/YamlConfiguration.java | 25 +++--- .../interop/RegistryAccessor.java | 9 +- .../orebfuscator/logging/LoggerAccessor.java | 7 +- .../orebfuscator/logging/OfcLogger.java | 23 +++-- .../orebfuscator/logging/SystemLogger.java | 8 +- .../orebfuscator/reflect/Reflector.java | 18 ++-- .../reflect/accessor/Accessors.java | 15 ++-- .../accessor/DefaultConstrutorAccessor.java | 6 +- .../accessor/DefaultFieldAccessor.java | 8 +- .../accessor/DefaultMethodAccessor.java | 7 +- .../reflect/accessor/MemberAccessor.java | 4 +- .../reflect/accessor/MethodAccessor.java | 1 - .../AbstractExecutablePredicate.java | 49 ++++++----- .../predicate/AbstractMemberPredicate.java | 71 ++++++++------- .../reflect/predicate/ClassPredicate.java | 87 +++++++------------ .../predicate/ConstructorPredicate.java | 9 +- .../reflect/predicate/FieldPredicate.java | 19 ++-- .../reflect/predicate/MethodPredicate.java | 19 ++-- .../predicate/RequirementCollector.java | 12 ++- .../imprex/orebfuscator/util/BlockPos.java | 12 +-- .../orebfuscator/util/BlockProperties.java | 12 ++- .../util/BlockStateProperties.java | 3 + .../imprex/orebfuscator/util/BlockTag.java | 7 +- .../orebfuscator/util/ChunkCacheKey.java | 14 ++- .../orebfuscator/util/ChunkDirection.java | 3 + .../orebfuscator/util/NamespacedKey.java | 43 +++++---- .../imprex/orebfuscator/util/SimpleCache.java | 2 - .../dev/imprex/orebfuscator/util/Version.java | 2 + .../orebfuscator/util/WeightedRandom.java | 9 +- .../orebfuscator/nms/AbstractNmsManager.java | 13 +-- .../cache/AsyncChunkSerializer.java | 12 +-- .../orebfuscator/cache/ChunkSerializer.java | 25 ++---- .../orebfuscator/cache/ObfuscationCache.java | 35 ++++---- .../iterop/BukkitLoggerAccessor.java | 22 ++--- 70 files changed, 552 insertions(+), 508 deletions(-) diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java index 46609b35..4edf76c5 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.cache; +import dev.imprex.orebfuscator.logging.OfcLogger; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -14,10 +15,13 @@ import dev.imprex.orebfuscator.reflect.accessor.MethodAccessor; import dev.imprex.orebfuscator.util.ChunkCacheKey; import dev.imprex.orebfuscator.util.SimpleCache; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public abstract class AbstractRegionFileCache { - private static MethodAccessor serverGetServer; + private static @Nullable MethodAccessor serverGetServer; protected static T serverHandle(Object server, Class targetClass) { if (serverGetServer == null) { @@ -46,25 +50,25 @@ public AbstractRegionFileCache(CacheConfig cacheConfig) { protected abstract void closeRegionFile(T t) throws IOException; - protected abstract DataInputStream createInputStream(T t, ChunkCacheKey key) throws IOException; + protected abstract @Nullable DataInputStream createInputStream(T t, ChunkCacheKey key) throws IOException; protected abstract DataOutputStream createOutputStream(T t, ChunkCacheKey key) throws IOException; - public final DataInputStream createInputStream(ChunkCacheKey key) throws IOException { + public final @Nullable DataInputStream createInputStream(ChunkCacheKey key) throws IOException { T t = this.get(this.cacheConfig.regionFile(key)); - return t != null ? this.createInputStream(t, key) : null; + return this.createInputStream(t, key); } public final DataOutputStream createOutputStream(ChunkCacheKey key) throws IOException { T t = this.get(this.cacheConfig.regionFile(key)); - return t != null ? this.createOutputStream(t, key) : null; + return this.createOutputStream(t, key); } - private final void remove(Map.Entry entry) { + private void remove(Map.Entry entry) { try { this.closeRegionFile(entry.getValue()); } catch (IOException e) { - e.printStackTrace(); + OfcLogger.error(e); } } @@ -123,11 +127,9 @@ public final void clear() { try { for (T t : this.regionFiles.values()) { try { - if (t != null) { - this.closeRegionFile(t); - } + this.closeRegionFile(t); } catch (IOException e) { - e.printStackTrace(); + OfcLogger.error(e); } } this.regionFiles.clear(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java index 175fd921..37492f96 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java @@ -1,8 +1,5 @@ package dev.imprex.orebfuscator.config; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; import com.google.gson.JsonObject; import dev.imprex.orebfuscator.config.api.WorldConfig; import dev.imprex.orebfuscator.config.components.BlockParser; @@ -17,7 +14,12 @@ import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.MathUtil; import dev.imprex.orebfuscator.util.WeightedRandom; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.jspecify.annotations.NullMarked; +@NullMarked public abstract class AbstractWorldConfig implements WorldConfig { private final String name; @@ -138,7 +140,6 @@ public boolean shouldObfuscate(int y) { return y >= this.minY && y <= this.maxY; } - WeightedRandom[] createWeightedRandoms(WorldAccessor world) { OfcLogger.debug(String.format("Creating weighted randoms for %s for world %s:", name, world)); return WeightedBlockList.create(world, this.weightedBlockLists); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/ConfigLookup.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/ConfigLookup.java index 3af7a23f..a344ac43 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/ConfigLookup.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/ConfigLookup.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.net.URI; import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -16,12 +17,15 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import dev.imprex.orebfuscator.util.Version; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class ConfigLookup { private static final Pattern FILENAME_PATTERN = Pattern.compile("config-(?.*)\\.yml"); - public static Version getConfigVersion(Version version) throws IOException { + public static @Nullable Version getConfigVersion(Version version) throws IOException { List versions = discoverConfigs().stream() .map(FILENAME_PATTERN::matcher) .filter(Matcher::find) @@ -41,7 +45,7 @@ public static Version getConfigVersion(Version version) throws IOException { return null; } - public static InputStream loadConfig(Version version) { + public static @Nullable InputStream loadConfig(Version version) { String path = String.format("/config/config-%s.yml", version); return ConfigLookup.class.getResourceAsStream(path); } @@ -61,17 +65,12 @@ private static List discoverConfigs() throws IOException { if (location.getPath().endsWith(".jar")) { URI jar = URI.create("jar:" + location); - try (FileSystem fileSystem = FileSystems.newFileSystem(jar, Map.of())) { - Path configDir = fileSystem.getPath("/config/"); - if (!Files.isDirectory(configDir)) { - return Collections.emptyList(); - } - - try (var stream = Files.list(configDir)) { - return stream - .map(configDir::relativize) - .map(Path::toString) - .toList(); + try { + FileSystem fileSystem = FileSystems.getFileSystem(jar); + return discoverConfigs(fileSystem); + } catch (FileSystemNotFoundException e) { + try (var fs = FileSystems.newFileSystem(jar, Map.of())) { + return discoverConfigs(fs); } } } @@ -97,4 +96,18 @@ private static List discoverConfigs() throws IOException { .toList(); } } + + private static List discoverConfigs(FileSystem fileSystem) throws IOException { + Path configDir = fileSystem.getPath("/config/"); + if (!Files.isDirectory(configDir)) { + return Collections.emptyList(); + } + + try (var stream = Files.list(configDir)) { + return stream + .map(configDir::relativize) + .map(Path::toString) + .toList(); + } + } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java index a10a236b..e5f03eaa 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java @@ -5,7 +5,9 @@ import dev.imprex.orebfuscator.config.context.ConfigParsingContext; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; import dev.imprex.orebfuscator.logging.OfcLogger; +import org.jspecify.annotations.NullMarked; +@NullMarked public class OrebfuscatorAdvancedConfig implements AdvancedConfig { private boolean verbose = false; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorBlockFlags.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorBlockFlags.java index 81832563..12375797 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorBlockFlags.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorBlockFlags.java @@ -6,15 +6,18 @@ import dev.imprex.orebfuscator.interop.RegistryAccessor; import dev.imprex.orebfuscator.util.BlockProperties; import dev.imprex.orebfuscator.util.BlockStateProperties; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class OrebfuscatorBlockFlags implements BlockFlags { private static final BlockFlags EMPTY_FLAGS = new EmptyBlockFlags(); - static BlockFlags create(RegistryAccessor registry, OrebfuscatorObfuscationConfig worldConfig, - OrebfuscatorProximityConfig proximityConfig) { - if ((worldConfig != null && worldConfig.isEnabled()) || (proximityConfig != null - && proximityConfig.isEnabled())) { + static BlockFlags create(RegistryAccessor registry, + @Nullable OrebfuscatorObfuscationConfig worldConfig, + @Nullable OrebfuscatorProximityConfig proximityConfig) { + if ((worldConfig != null && worldConfig.isEnabled()) || (proximityConfig != null && proximityConfig.isEnabled())) { return new OrebfuscatorBlockFlags(registry, worldConfig, proximityConfig); } return EMPTY_FLAGS; @@ -22,8 +25,9 @@ static BlockFlags create(RegistryAccessor registry, OrebfuscatorObfuscationConfi private final int[] blockFlags; - private OrebfuscatorBlockFlags(RegistryAccessor registry, OrebfuscatorObfuscationConfig worldConfig, - OrebfuscatorProximityConfig proximityConfig) { + private OrebfuscatorBlockFlags(RegistryAccessor registry, + @Nullable OrebfuscatorObfuscationConfig worldConfig, + @Nullable OrebfuscatorProximityConfig proximityConfig) { this.blockFlags = new int[registry.getUniqueBlockStateCount()]; if (worldConfig != null && worldConfig.isEnabled()) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java index f4b83243..427f9d96 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java @@ -13,7 +13,9 @@ import dev.imprex.orebfuscator.interop.ServerAccessor; import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.util.ChunkCacheKey; +import org.jspecify.annotations.NullMarked; +@NullMarked public class OrebfuscatorCacheConfig implements CacheConfig { private final Path worldDirectory; @@ -145,7 +147,7 @@ public Path baseDirectory() { @Override public Path regionFile(ChunkCacheKey key) { - return this.baseDirectory.resolve(key.world()) + return this.baseDirectory.resolve(key.world().replace(":", "_")) .resolve("r." + (key.x() >> 5) + "." + (key.z() >> 5) + ".mca"); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java index 6c2ca44b..a44aad63 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java @@ -13,6 +13,9 @@ import java.util.WeakHashMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.random.RandomGenerator; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import com.google.common.hash.Hashing; import com.google.gson.JsonObject; import dev.imprex.orebfuscator.config.api.AdvancedConfig; @@ -38,6 +41,7 @@ import dev.imprex.orebfuscator.util.Version; import dev.imprex.orebfuscator.util.WeightedRandom; +@NullMarked public class OrebfuscatorConfig implements Config { private static final int CONFIG_VERSION = 5; @@ -49,15 +53,15 @@ public class OrebfuscatorConfig implements Config { private final List obfuscationConfigs = new ArrayList<>(); private final List proximityConfigs = new ArrayList<>(); - private final Map worldConfigBundles = new WeakHashMap<>(); + private final Map worldConfigBundles = new WeakHashMap<>(); private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final ServerAccessor server; private final Path path; private final YamlConfiguration configuration; - private byte[] systemHash; - private String configReport; + private byte[] systemHash = new byte[0]; + private @Nullable String configReport; public OrebfuscatorConfig(ServerAccessor server) { this.server = server; @@ -75,6 +79,10 @@ public YamlConfiguration loadConfiguration() { Version version = this.server.getMinecraftVersion(); Version configVersion = ConfigLookup.getConfigVersion(version); + if (configVersion == null) { + throw new InvalidConfigurationException( + "No config found and can't find default config for your version"); + } OfcLogger.info( String.format("No config found, creating default config for version %s and above", configVersion)); @@ -91,12 +99,14 @@ public YamlConfiguration loadConfiguration() { this.deserialize(configuration, context); this.configReport = context.report(); - if (context.hasErrors()) { - OfcLogger.error(this.configReport, null); - throw new IllegalArgumentException( - "Can't parse config due to errors, Orebfuscator will now disable itself!"); - } else if (this.configReport != null) { - OfcLogger.warn(this.configReport); + if (this.configReport != null) { + if (context.hasErrors()) { + OfcLogger.error(this.configReport, null); + throw new InvalidConfigurationException( + "Can't parse config due to errors, Orebfuscator will now disable itself!"); + } else { + OfcLogger.warn(this.configReport); + } } this.systemHash = this.calculateSystemHash(configuration); @@ -120,7 +130,7 @@ public void store() { private byte[] calculateSystemHash(YamlConfiguration configuration) throws IOException { return Hashing.murmur3_128().newHasher() - .putBytes(this.server.getOrebfuscatorVersion().getBytes(StandardCharsets.UTF_8)) + .putBytes(this.server.getOrebfuscatorVersion().toString().getBytes(StandardCharsets.UTF_8)) .putBytes(this.server.getMinecraftVersion().toString().getBytes(StandardCharsets.UTF_8)) .putBytes(configuration.withoutComments().getBytes(StandardCharsets.UTF_8)) .hash().asBytes(); @@ -246,7 +256,7 @@ public byte[] systemHash() { } @Override - public String report() { + public @Nullable String report() { return configReport; } @@ -330,8 +340,8 @@ private OrebfuscatorWorldConfigBundle getWorldConfigBundle(WorldAccessor world) private class OrebfuscatorWorldConfigBundle implements WorldConfigBundle { - private final OrebfuscatorObfuscationConfig obfuscationConfig; - private final OrebfuscatorProximityConfig proximityConfig; + private final @Nullable OrebfuscatorObfuscationConfig obfuscationConfig; + private final @Nullable OrebfuscatorProximityConfig proximityConfig; private final BlockFlags blockFlags; private final boolean needsObfuscation; @@ -343,8 +353,8 @@ private class OrebfuscatorWorldConfigBundle implements WorldConfigBundle { private final int maxSectionIndex; private final WorldAccessor world; - private final WeightedRandom[] obfuscationRandoms; - private final WeightedRandom[] proximityRandoms; + private final WeightedRandom @Nullable [] obfuscationRandoms; + private final WeightedRandom @Nullable [] proximityRandoms; public OrebfuscatorWorldConfigBundle(WorldAccessor world) { String worldName = world.getName(); @@ -367,13 +377,13 @@ public OrebfuscatorWorldConfigBundle(WorldAccessor world) { this.minSectionIndex = world.getSectionIndex(this.minY); this.maxSectionIndex = world.getSectionIndex(this.maxY - 1) + 1; - this.obfuscationRandoms = this.obfuscationConfig != null + this.obfuscationRandoms = obfuscationConfig != null && obfuscationConfig.isEnabled() ? this.obfuscationConfig.createWeightedRandoms(world) : null; - this.proximityRandoms = this.proximityConfig != null + this.proximityRandoms = proximityConfig != null && proximityConfig.isEnabled() ? this.proximityConfig.createWeightedRandoms(world) : null; } - private T findConfig(Collection configs, String worldName, + private @Nullable T findConfig(Collection configs, String worldName, String configType) { List matchingConfigs = configs.stream() .filter(config -> config.matchesWorldName(worldName)) @@ -398,12 +408,12 @@ public BlockFlags blockFlags() { } @Override - public ObfuscationConfig obfuscation() { + public @Nullable ObfuscationConfig obfuscation() { return this.obfuscationConfig; } @Override - public ProximityConfig proximity() { + public @Nullable ProximityConfig proximity() { return this.proximityConfig; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorGeneralConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorGeneralConfig.java index 4dea6850..647a950d 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorGeneralConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorGeneralConfig.java @@ -3,7 +3,9 @@ import dev.imprex.orebfuscator.config.api.GeneralConfig; import dev.imprex.orebfuscator.config.context.ConfigParsingContext; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; +import org.jspecify.annotations.NullMarked; +@NullMarked public class OrebfuscatorGeneralConfig implements GeneralConfig { private boolean checkForUpdates = true; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java index e1dc29b1..3ac4996a 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java @@ -11,7 +11,9 @@ import dev.imprex.orebfuscator.config.context.ConfigMessage; import dev.imprex.orebfuscator.config.context.ConfigParsingContext; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; +import org.jspecify.annotations.NullMarked; +@NullMarked public class OrebfuscatorObfuscationConfig extends AbstractWorldConfig implements ObfuscationConfig { private boolean layerObfuscation = false; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java index 509c8b7a..0ebab9bc 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java @@ -15,7 +15,9 @@ import dev.imprex.orebfuscator.config.context.ConfigParsingContext; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; import dev.imprex.orebfuscator.util.BlockProperties; +import org.jspecify.annotations.NullMarked; +@NullMarked public class OrebfuscatorProximityConfig extends AbstractWorldConfig implements ProximityConfig { private int distance = 24; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java index 93427ce5..83035c4b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.config.api; +import org.jspecify.annotations.NullMarked; + +@NullMarked public interface AdvancedConfig { int obfuscationThreads(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/BlockFlags.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/BlockFlags.java index 98e36a54..76db1352 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/BlockFlags.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/BlockFlags.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.config.api; +import org.jspecify.annotations.NullMarked; + +@NullMarked public interface BlockFlags { int FLAG_OBFUSCATE = 1; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/CacheConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/CacheConfig.java index ae4569e7..b3c7ee57 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/CacheConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/CacheConfig.java @@ -2,7 +2,9 @@ import java.nio.file.Path; import dev.imprex.orebfuscator.util.ChunkCacheKey; +import org.jspecify.annotations.NullMarked; +@NullMarked public interface CacheConfig { boolean enabled(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/Config.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/Config.java index 5cd05f26..e3544330 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/Config.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/Config.java @@ -1,12 +1,15 @@ package dev.imprex.orebfuscator.config.api; import dev.imprex.orebfuscator.interop.WorldAccessor; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public interface Config { byte[] systemHash(); - String report(); + @Nullable String report(); GeneralConfig general(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/GeneralConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/GeneralConfig.java index 96a5972c..7f50c251 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/GeneralConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/GeneralConfig.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.config.api; +import org.jspecify.annotations.NullMarked; + +@NullMarked public interface GeneralConfig { boolean checkForUpdates(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ObfuscationConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ObfuscationConfig.java index ddb22cff..a8dd2a62 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ObfuscationConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ObfuscationConfig.java @@ -1,7 +1,9 @@ package dev.imprex.orebfuscator.config.api; import dev.imprex.orebfuscator.config.components.ConfigBlockValue; +import org.jspecify.annotations.NullMarked; +@NullMarked public interface ObfuscationConfig extends WorldConfig { boolean layerObfuscation(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ProximityConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ProximityConfig.java index b529f4e0..ec31fa0e 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ProximityConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/ProximityConfig.java @@ -5,7 +5,9 @@ import org.joml.Matrix4f; import dev.imprex.orebfuscator.config.components.ConfigBlockValue; +import org.jspecify.annotations.NullMarked; +@NullMarked public interface ProximityConfig extends WorldConfig { int distance(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfig.java index 8b19b235..f0b3e2a0 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfig.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.config.api; +import org.jspecify.annotations.NullMarked; + +@NullMarked public interface WorldConfig { boolean isEnabled(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java index ba33f936..85603f68 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java @@ -1,12 +1,16 @@ package dev.imprex.orebfuscator.config.api; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked public interface WorldConfigBundle { BlockFlags blockFlags(); - ObfuscationConfig obfuscation(); + @Nullable ObfuscationConfig obfuscation(); - ProximityConfig proximity(); + @Nullable ProximityConfig proximity(); boolean needsObfuscation(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java index 92743c63..355082c8 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java @@ -3,29 +3,29 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.config.context.ConfigMessage; import dev.imprex.orebfuscator.config.context.ConfigParsingContext; import dev.imprex.orebfuscator.interop.RegistryAccessor; import dev.imprex.orebfuscator.util.BlockProperties; import dev.imprex.orebfuscator.util.BlockTag; +import org.jspecify.annotations.NullMarked; +@NullMarked public class BlockParser { public static BlockParser.Factory factory(RegistryAccessor registryAccessor) { return new Factory(registryAccessor); } - private final @NotNull RegistryAccessor registry; + private final RegistryAccessor registry; private final boolean excludeAir; - private BlockParser(@NotNull RegistryAccessor registry, boolean excludeAir) { + private BlockParser(RegistryAccessor registry, boolean excludeAir) { this.registry = Objects.requireNonNull(registry); this.excludeAir = excludeAir; } - @NotNull - public ConfigBlockValue parse(@NotNull ConfigParsingContext context, @NotNull String value) { + public ConfigBlockValue parse(ConfigParsingContext context, String value) { var parsed = ConfigFunctionValue.parse(value); if (parsed != null) { return switch (parsed.function()) { @@ -40,8 +40,7 @@ public ConfigBlockValue parse(@NotNull ConfigParsingContext context, @NotNull St } } - @NotNull - private ConfigBlockValue parseBlockTag(@NotNull ConfigParsingContext context, @NotNull String value) { + private ConfigBlockValue parseBlockTag(ConfigParsingContext context, String value) { BlockTag tag = registry.getBlockTagByName(value); if (tag == null) { context.warn(ConfigMessage.BLOCK_TAG_UNKNOWN, value); @@ -76,8 +75,7 @@ private ConfigBlockValue parseBlockTag(@NotNull ConfigParsingContext context, @N return ConfigBlockValue.tag(tag, blocks); } - @NotNull - private ConfigBlockValue parseBlock(@NotNull ConfigParsingContext context, @NotNull String value) { + private ConfigBlockValue parseBlock(ConfigParsingContext context, String value) { BlockProperties block = registry.getBlockByName(value); if (block == null) { context.warn(ConfigMessage.BLOCK_UNKNOWN, value); @@ -92,14 +90,10 @@ private ConfigBlockValue parseBlock(@NotNull ConfigParsingContext context, @NotN public static class Factory { - private final @NotNull RegistryAccessor registry; - private final BlockParser excludeAir; private final BlockParser includeAir; - public Factory(@NotNull RegistryAccessor registry) { - this.registry = Objects.requireNonNull(registry); - + public Factory(RegistryAccessor registry) { this.excludeAir = new BlockParser(registry, true); this.includeAir = new BlockParser(registry, false); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java index 4bee4daf..ef90cdbb 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java @@ -4,15 +4,16 @@ import java.util.Collections; import java.util.Objects; import java.util.Set; -import org.jetbrains.annotations.NotNull; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import dev.imprex.orebfuscator.util.BlockProperties; import dev.imprex.orebfuscator.util.BlockTag; +import org.jspecify.annotations.NullMarked; -public record ConfigBlockValue(@NotNull String value, @NotNull Set blocks) implements +@NullMarked +public record ConfigBlockValue(String value, Set blocks) implements Comparable { private static final JsonElement INVALID = new JsonPrimitive("invalid"); @@ -30,7 +31,7 @@ public static JsonObject toJson(Collection values) { array.add(block.getKey().toString()); } object.add(entry.value(), array); - } else if (entry.blocks().size() > 0) { + } else if (!entry.blocks().isEmpty()) { object.add(entry.value(), VALID); } else { object.add(entry.value(), INVALID); @@ -40,23 +41,19 @@ public static JsonObject toJson(Collection values) { return object; } - @NotNull - public static ConfigBlockValue invalid(@NotNull String value) { + public static ConfigBlockValue invalid(String value) { return new ConfigBlockValue(value, Collections.emptySet()); } - @NotNull - public static ConfigBlockValue block(@NotNull BlockProperties block) { + public static ConfigBlockValue block(BlockProperties block) { return new ConfigBlockValue(block.getKey().toString(), Set.of(block)); } - @NotNull - public static ConfigBlockValue invalidTag(@NotNull String value) { + public static ConfigBlockValue invalidTag(String value) { return new ConfigBlockValue(String.format("tag(%s)", value), Collections.emptySet()); } - @NotNull - public static ConfigBlockValue tag(@NotNull BlockTag tag, @NotNull Set blocks) { + public static ConfigBlockValue tag(BlockTag tag, Set blocks) { return new ConfigBlockValue(String.format("tag(%s)", tag.key()), Collections.unmodifiableSet(blocks)); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigFunctionValue.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigFunctionValue.java index 9f456bf7..dde3c4fc 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigFunctionValue.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigFunctionValue.java @@ -2,15 +2,15 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; -public record ConfigFunctionValue(@NotNull String function, @NotNull String argument) { +@NullMarked +public record ConfigFunctionValue(String function, String argument) { private static final Pattern CONFIG_FUNCTION_PATTERN = Pattern.compile("^(?\\w+)\\((?.+)\\)$"); - @Nullable - public static ConfigFunctionValue parse(@NotNull String value) { + public static @Nullable ConfigFunctionValue parse(String value) { Matcher matcher = CONFIG_FUNCTION_PATTERN.matcher(value); if (matcher.find()) { String function = matcher.group("function"); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java index 8973f914..6fec6405 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.config.components; +import dev.imprex.orebfuscator.util.BlockProperties; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -16,7 +17,9 @@ import dev.imprex.orebfuscator.util.BlockStateProperties; import dev.imprex.orebfuscator.util.MathUtil; import dev.imprex.orebfuscator.util.WeightedRandom; +import org.jspecify.annotations.NullMarked; +@NullMarked public class WeightedBlockList { public static WeightedRandom[] create(WorldAccessor world, List lists) { @@ -45,7 +48,7 @@ public static WeightedRandom[] create(WorldAccessor world, List entry : list.blocks.entrySet()) { // TODO: add support for other block states in future var blockStates = entry.getKey().blocks().stream() - .map(block -> block.getDefaultBlockState()) + .map(BlockProperties::getDefaultBlockState) .collect(Collectors.toSet()); double weight = (double) entry.getValue() / (double) blockStates.size(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WorldMatcher.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WorldMatcher.java index 40beacd3..be3b4dd4 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WorldMatcher.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WorldMatcher.java @@ -2,12 +2,12 @@ import java.util.function.Predicate; import java.util.regex.Pattern; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; +@NullMarked public class WorldMatcher implements Predicate { - @NotNull - public static WorldMatcher parseMatcher(@NotNull String value) { + public static WorldMatcher parseMatcher(String value) { var parsed = ConfigFunctionValue.parse(value); if (parsed != null && parsed.function().equals("regex")) { return new WorldMatcher(parseRegexMatcher(parsed.argument()), Type.REGEX); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigMessage.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigMessage.java index 2aa95355..8dcc4a71 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigMessage.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigMessage.java @@ -1,9 +1,10 @@ package dev.imprex.orebfuscator.config.context; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class ConfigMessage { public static final ConfigMessage MISSING_OR_EMPTY = fixed("is missing or empty"); @@ -30,25 +31,24 @@ public class ConfigMessage { public static final ConfigMessage BLOCK_UNKNOWN = dynamic("skipping unknown block '%s'"); public static final ConfigMessage BLOCK_AIR = dynamic("skipping air block '%s'"); - private static ConfigMessage fixed(@NotNull String message) { + private static ConfigMessage fixed(String message) { return new ConfigMessage(message, true); } - private static ConfigMessage dynamic(@NotNull String message) { + private static ConfigMessage dynamic(String message) { return new ConfigMessage(message, false); } private final String message; private final boolean fixed; - private ConfigMessage(@NotNull String message, boolean fixed) { + private ConfigMessage(String message, boolean fixed) { this.message = message; this.fixed = fixed; } - @NotNull @Contract(pure = true) - public String format(@Nullable Object... arguments) { + public String format(Object @Nullable ... arguments) { return this.fixed ? this.message : String.format(this.message, arguments); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigParsingContext.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigParsingContext.java index 74f8a8cb..30164ec4 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigParsingContext.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/ConfigParsingContext.java @@ -1,8 +1,8 @@ package dev.imprex.orebfuscator.config.context; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * Represents a context used during configuration parsing to track and collect warnings and errors. @@ -16,6 +16,7 @@ * individually without affecting the entire configuration. *

*/ +@NullMarked public interface ConfigParsingContext { /** @@ -25,8 +26,7 @@ public interface ConfigParsingContext { * @param isolateErrors Whether errors in this child context should be isolated from the parent. * @return An existing or newly created {@code ConfigParsingContext} instance for the given path. */ - @NotNull - ConfigParsingContext section(@NotNull String path, boolean isolateErrors); + ConfigParsingContext section(String path, boolean isolateErrors); /** * Creates or retrieves an existing child context for the specified path without isolating errors. @@ -34,8 +34,7 @@ public interface ConfigParsingContext { * @param path The relative path of the child context. * @return An existing or newly created {@code ConfigParsingContext} instance for the given path. */ - @NotNull - default ConfigParsingContext section(@NotNull String path) { + default ConfigParsingContext section(String path) { return section(path, false); } @@ -45,7 +44,7 @@ default ConfigParsingContext section(@NotNull String path) { * @param message The warning message to be logged. * @param arguments Optional arguments used to format the message. */ - void warn(@NotNull ConfigMessage message, @Nullable Object... arguments); + void warn(ConfigMessage message, Object @Nullable ... arguments); /** * Adds a warning message to the context of the specified path. @@ -54,7 +53,7 @@ default ConfigParsingContext section(@NotNull String path) { * @param message The warning message to be logged. * @param arguments Optional arguments used to format the message. */ - void warn(@NotNull String path, @NotNull ConfigMessage message, @Nullable Object... arguments); + void warn(String path, ConfigMessage message, Object @Nullable ... arguments); /** * Determines whether a subsystem should remain enabled based on the presence of errors. @@ -82,7 +81,7 @@ default boolean disableIfError(boolean enabled) { * @param message The error message to be logged. * @param arguments Optional arguments used to format the message. */ - void error(@NotNull ConfigMessage message, @Nullable Object... arguments); + void error(ConfigMessage message, Object @Nullable ... arguments); /** * Adds an error message to the context of the specified path. @@ -91,7 +90,7 @@ default boolean disableIfError(boolean enabled) { * @param message The error message to be logged. * @param arguments Optional arguments used to format the message. */ - void error(@NotNull String path, @NotNull ConfigMessage message, @Nullable Object... arguments); + void error(String path, ConfigMessage message, Object @Nullable ... arguments); /** * Adds an error if the specified value is below the minimum allowed value. @@ -100,7 +99,7 @@ default boolean disableIfError(boolean enabled) { * @param min The minimum allowed value. * @param value The actual value to be checked. */ - default void errorMinValue(@NotNull String path, long min, long value) { + default void errorMinValue(String path, long min, long value) { if (value < min) { error(path, ConfigMessage.VALUE_MIN, value, min); } @@ -114,7 +113,7 @@ default void errorMinValue(@NotNull String path, long min, long value) { * @param max The maximum allowed value. * @param value The actual value to be checked. */ - default void errorMinMaxValue(@NotNull String path, long min, long max, long value) { + default void errorMinMaxValue(String path, long min, long max, long value) { if (value < min || value > max) { error(path, ConfigMessage.VALUE_MIN_MAX, value, min, max); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/DefaultConfigParsingContext.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/DefaultConfigParsingContext.java index b8404140..2ef1573a 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/DefaultConfigParsingContext.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/context/DefaultConfigParsingContext.java @@ -6,11 +6,11 @@ import java.util.List; import java.util.Map; import java.util.Objects; - import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +@NullMarked public class DefaultConfigParsingContext implements ConfigParsingContext { private static final String ANSI_RESET = "\u001B[m"; @@ -34,34 +34,33 @@ private DefaultConfigParsingContext(@Nullable DefaultConfigParsingContext parent } @Override - @NotNull - public DefaultConfigParsingContext section(@NotNull String path, boolean isolateErrors) { + public DefaultConfigParsingContext section(String path, boolean isolateErrors) { DefaultConfigParsingContext context = getContext(path); context.isolateErrors = isolateErrors; return context; } @Override - public void warn(@NotNull ConfigMessage message, @Nullable Object... arguments) { + public void warn(ConfigMessage message, Object @Nullable ... arguments) { Objects.requireNonNull(message, "message can't be null"); this.messages.add(new Message(false, message.format(arguments))); } @Override - public void warn(@NotNull String path, @NotNull ConfigMessage message, @Nullable Object... arguments) { + public void warn(String path, ConfigMessage message, Object @Nullable ... arguments) { getContext(path).warn(message, arguments); } @Override - public void error(@NotNull ConfigMessage message, @Nullable Object... arguments) { + public void error(ConfigMessage message, Object @Nullable ... arguments) { Objects.requireNonNull(message, "message can't be null"); this.messages.add(new Message(true, message.format(arguments))); } @Override - public void error(@NotNull String path, @NotNull ConfigMessage message, @Nullable Object... arguments) { + public void error(String path, ConfigMessage message, Object @Nullable ... arguments) { getContext(path).error(message, arguments); } @@ -83,7 +82,7 @@ public boolean hasErrors() { return false; } - private DefaultConfigParsingContext getContext(@NotNull String path) { + private DefaultConfigParsingContext getContext(String path) { Objects.requireNonNull(path, "context path can't be null"); DefaultConfigParsingContext context = this; @@ -136,8 +135,7 @@ private StringBuilder buildReport(final StringBuilder builder) { return builder; } - @Nullable - public String report() { + public @Nullable String report() { int messageCount = this.getMessageCount(); if (messageCount == 0) { return null; @@ -153,7 +151,7 @@ public String report() { .toString(); } - private record Message(boolean isError, @NotNull String content) implements Comparable { + private record Message(boolean isError, String content) implements Comparable { @Override public int compareTo(Message o) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigration.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigration.java index d455e41b..3c02c110 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigration.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigration.java @@ -4,18 +4,19 @@ import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked interface ConfigMigration { int sourceVersion(); - @NotNull ConfigurationSection migrate(@NotNull ConfigurationSection root); + ConfigurationSection migrate(ConfigurationSection root); - static void migrateNames(@Nullable ConfigurationSection section, @NotNull List> mapping) { + static void migrateNames(@Nullable ConfigurationSection section, List> mapping) { Objects.requireNonNull(mapping, "mappings can't be null"); if (section == null) { return; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV1.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV1.java index e752b16f..f8565d91 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV1.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV1.java @@ -5,10 +5,11 @@ import java.util.List; import java.util.Map; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; +import org.jspecify.annotations.NullMarked; +@NullMarked class ConfigMigrationV1 implements ConfigMigration { @Override @@ -17,7 +18,7 @@ public int sourceVersion() { } @Override - public @NotNull ConfigurationSection migrate(@NotNull ConfigurationSection root) { + public ConfigurationSection migrate(ConfigurationSection root) { // check if config is still using old path String obfuscationConfigPath = root.contains("world") ? "world" : "obfuscation"; convertSectionListToSection(root, obfuscationConfigPath); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV2.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV2.java index 4ceb1b3a..89e1ccb9 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV2.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV2.java @@ -1,9 +1,11 @@ package dev.imprex.orebfuscator.config.migrations; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; import dev.imprex.orebfuscator.util.BlockPos; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked class ConfigMigrationV2 implements ConfigMigration { @Override @@ -12,13 +14,13 @@ public int sourceVersion() { } @Override - public @NotNull ConfigurationSection migrate(@NotNull ConfigurationSection root) { + public ConfigurationSection migrate(ConfigurationSection root) { convertRandomBlocksToSections(root.getSection("obfuscation")); convertRandomBlocksToSections(root.getSection("proximity")); return root; } - private static void convertRandomBlocksToSections(ConfigurationSection configContainer) { + private static void convertRandomBlocksToSections(@Nullable ConfigurationSection configContainer) { if (configContainer == null) { return; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV3.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV3.java index 460dab21..ec5c8b93 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV3.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV3.java @@ -2,10 +2,11 @@ import java.util.List; import java.util.Map; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; import dev.imprex.orebfuscator.util.BlockPos; +import org.jspecify.annotations.NullMarked; +@NullMarked class ConfigMigrationV3 implements ConfigMigration { @Override @@ -14,7 +15,7 @@ public int sourceVersion() { } @Override - public @NotNull ConfigurationSection migrate(@NotNull ConfigurationSection root) { + public ConfigurationSection migrate(ConfigurationSection root) { migrateAdvancedConfig(root); migrateCacheConfig(root); migrateProximityConfigs(root); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV4.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV4.java index c72a40df..1f9882cd 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV4.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV4.java @@ -1,8 +1,10 @@ package dev.imprex.orebfuscator.config.migrations; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked class ConfigMigrationV4 implements ConfigMigration { @Override @@ -11,13 +13,13 @@ public int sourceVersion() { } @Override - public @NotNull ConfigurationSection migrate(@NotNull ConfigurationSection root) { + public ConfigurationSection migrate(ConfigurationSection root) { migrateWorlds(root.getSection("obfuscation")); migrateWorlds(root.getSection("proximity")); return root; } - private static void migrateWorlds(ConfigurationSection configContainer) { + private static void migrateWorlds(@Nullable ConfigurationSection configContainer) { if (configContainer == null) { return; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java index a43ca11e..7474b6ca 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java @@ -5,7 +5,9 @@ import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; import dev.imprex.orebfuscator.logging.OfcLogger; +import org.jspecify.annotations.NullMarked; +@NullMarked public class ConfigMigrator { private static final Map MIGRATIONS = new HashMap<>(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/ConfigurationSection.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/ConfigurationSection.java index 966c6a5b..dac9fc34 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/ConfigurationSection.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/ConfigurationSection.java @@ -15,9 +15,10 @@ import java.util.Set; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class ConfigurationSection { static final char PATH_SEPARATOR = '.'; @@ -25,27 +26,25 @@ public class ConfigurationSection { protected final Map map = new LinkedHashMap<>(); private final String path; - protected ConfigurationSection(@NotNull String path) { + protected ConfigurationSection(String path) { Objects.requireNonNull(path, "Path cannot be null"); this.path = path; } - @NotNull public String getName() { return path; } - @NotNull public Set getKeys() { return this.map.keySet(); } - public boolean contains(@NotNull String path) { + public boolean contains(String path) { return get(path, null) != null; } - public void set(@NotNull String path, @Nullable Object value) { + public void set(String path, @Nullable Object value) { Objects.requireNonNull(path, "Path cannot be null"); int end = -1, start; @@ -76,14 +75,13 @@ public void set(@NotNull String path, @Nullable Object value) { } } - @Nullable - public Object get(@NotNull String path) { + public @Nullable Object get(String path) { return get(path, null); } - @Nullable + @Contract("_, !null -> !null") - public Object get(@NotNull String path, @Nullable Object defaultValue) { + public @Nullable Object get(String path, @Nullable Object defaultValue) { Objects.requireNonNull(path, "Path cannot be null"); if (path.isBlank()) { @@ -107,8 +105,7 @@ public Object get(@NotNull String path, @Nullable Object defaultValue) { return section.get(segment, defaultValue); } - @NotNull - public ConfigurationSection createSection(@NotNull String path) { + public ConfigurationSection createSection(String path) { Objects.requireNonNull(path, "Cannot create section at empty path"); if (path.isBlank()) { @@ -136,108 +133,95 @@ public ConfigurationSection createSection(@NotNull String path) { return section.createSection(segment); } - public boolean isBoolean(@NotNull String path) { + public boolean isBoolean(String path) { return get(path) instanceof Boolean; } - @Nullable - public Boolean getBoolean(@NotNull String path) { + public @Nullable Boolean getBoolean(String path) { return getBoolean(path, null); } - @Nullable @Contract("_, !null -> !null") - public Boolean getBoolean(@NotNull String path, @Nullable Boolean defaultValue) { + public @Nullable Boolean getBoolean(String path, @Nullable Boolean defaultValue) { return get(path, defaultValue) instanceof Boolean value ? value : defaultValue; } - public boolean isInt(@NotNull String path) { + public boolean isInt(String path) { return get(path) instanceof Integer; } - @Nullable - public Integer getInt(@NotNull String path) { + public @Nullable Integer getInt(String path) { return getInt(path, null); } - @Nullable @Contract("_, !null -> !null") - public Integer getInt(@NotNull String path, @Nullable Integer defaultValue) { + public @Nullable Integer getInt(String path, @Nullable Integer defaultValue) { return get(path, defaultValue) instanceof Number value ? Integer.valueOf(value.intValue()) : defaultValue; } - public boolean isLong(@NotNull String path) { + public boolean isLong(String path) { return get(path) instanceof Long; } - @Nullable - public Long getLong(@NotNull String path) { + public @Nullable Long getLong(String path) { return getLong(path, null); } - @Nullable @Contract("_, !null -> !null") - public Long getLong(@NotNull String path, @Nullable Long defaultValue) { + public @Nullable Long getLong(String path, @Nullable Long defaultValue) { return get(path, defaultValue) instanceof Number value ? Long.valueOf(value.longValue()) : defaultValue; } - public boolean isDouble(@NotNull String path) { + public boolean isDouble(String path) { return get(path) instanceof Double; } - @Nullable - public Double getDouble(@NotNull String path) { + public @Nullable Double getDouble(String path) { return getDouble(path, null); } - @Nullable @Contract("_, !null -> !null") - public Double getDouble(@NotNull String path, @Nullable Double defaultValue) { + public @Nullable Double getDouble(String path, @Nullable Double defaultValue) { return get(path, defaultValue) instanceof Number value ? Double.valueOf(value.doubleValue()) : defaultValue; } - public boolean isNumber(@NotNull String path) { + public boolean isNumber(String path) { return get(path) instanceof Number; } - public boolean isString(@NotNull String path) { + public boolean isString(String path) { return get(path) instanceof String; } - @Nullable - public String getString(@NotNull String path) { + public @Nullable String getString(String path) { return getString(path, null); } - @Nullable @Contract("_, !null -> !null") - public String getString(@NotNull String path, @Nullable String defaultValue) { + public @Nullable String getString(String path, @Nullable String defaultValue) { return get(path, defaultValue) instanceof String value ? value : defaultValue; } - public boolean isList(@NotNull String path) { + public boolean isList(String path) { return get(path) instanceof List; } - @Nullable - public List getList(@NotNull String path) { + public @Nullable List getList(String path) { return getList(path, null); } - @Nullable @Contract("_, !null -> !null") - public List getList(@NotNull String path, List defaultValue) { + public @Nullable List getList(String path, @Nullable List defaultValue) { return get(path, defaultValue) instanceof List value ? value : defaultValue; } - @NotNull - public List getStringList(@NotNull String path) { + public List getStringList(String path) { List list = getList(path); if (list == null) { return Collections.emptyList(); @@ -254,17 +238,15 @@ public List getStringList(@NotNull String path) { return result; } - public boolean isSection(@NotNull String path) { + public boolean isSection(String path) { return get(path) instanceof ConfigurationSection; } - @Nullable - public ConfigurationSection getSection(@NotNull String path) { + public @Nullable ConfigurationSection getSection(String path) { return get(path) instanceof ConfigurationSection value ? value : null; } - @NotNull public List getSubSections() { List result = new ArrayList<>(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/InvalidConfigurationException.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/InvalidConfigurationException.java index 7cb14620..2c1f827f 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/InvalidConfigurationException.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/InvalidConfigurationException.java @@ -6,7 +6,9 @@ */ package dev.imprex.orebfuscator.config.yaml; -@SuppressWarnings("serial") +import org.jspecify.annotations.NullMarked; + +@NullMarked public class InvalidConfigurationException extends Exception { public InvalidConfigurationException(String message) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/NodeCommentData.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/NodeCommentData.java index 94822213..af3dac94 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/NodeCommentData.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/NodeCommentData.java @@ -4,9 +4,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.yaml.snakeyaml.comments.CommentLine; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.Node; @@ -14,14 +13,15 @@ import org.yaml.snakeyaml.nodes.ScalarNode; import org.yaml.snakeyaml.nodes.SequenceNode; +@NullMarked class NodeCommentData { private final List blockComments; private final List inLineComments; - private final List endComments; + private final @Nullable List endComments; private final Map children = new HashMap<>(); - private final Map> sequenceValueComments; + private final @Nullable Map> sequenceValueComments; public NodeCommentData() { this.blockComments = Collections.emptyList(); @@ -30,7 +30,7 @@ public NodeCommentData() { this.sequenceValueComments = null; } - public NodeCommentData(@NotNull NodeTuple nodeTuple) { + public NodeCommentData(NodeTuple nodeTuple) { Node keyNode = nodeTuple.getKeyNode(); Node valueNode = nodeTuple.getValueNode(); @@ -60,23 +60,23 @@ public NodeCommentData(@NotNull NodeTuple nodeTuple) { } } - public NodeCommentData(@NotNull MappingNode node) { + public NodeCommentData(MappingNode node) { this.blockComments = node.getBlockComments(); this.inLineComments = node.getInLineComments(); this.endComments = node.getEndComments(); this.sequenceValueComments = null; } - public void addChild(@NotNull String key, @NotNull NodeCommentData commentData) { + public void addChild(String key, NodeCommentData commentData) { this.children.put(key, commentData); } @Nullable - public NodeCommentData getChild(@NotNull String key) { + public NodeCommentData getChild(String key) { return this.children.get(key); } - public void apply(@NotNull NodeTuple nodeTuple) { + public void apply(NodeTuple nodeTuple) { Node keyNode = nodeTuple.getKeyNode(); Node valueNode = nodeTuple.getValueNode(); @@ -103,7 +103,7 @@ public void apply(@NotNull NodeTuple nodeTuple) { } } - public void apply(@NotNull MappingNode node) { + public void apply(MappingNode node) { node.setBlockComments(this.blockComments); node.setInLineComments(this.inLineComments); node.setEndComments(this.endComments); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/YamlConfiguration.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/YamlConfiguration.java index b517c396..89cfd990 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/YamlConfiguration.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/yaml/YamlConfiguration.java @@ -18,8 +18,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; @@ -32,10 +32,10 @@ import org.yaml.snakeyaml.reader.UnicodeReader; import org.yaml.snakeyaml.representer.Representer; +@NullMarked public class YamlConfiguration extends ConfigurationSection { - @NotNull - public static YamlConfiguration loadConfig(@NotNull Path path) throws IOException, InvalidConfigurationException { + public static YamlConfiguration loadConfig(Path path) throws IOException, InvalidConfigurationException { Objects.requireNonNull(path, "Path cannot be null"); try (InputStream inputStream = Files.newInputStream(path)) { @@ -43,8 +43,7 @@ public static YamlConfiguration loadConfig(@NotNull Path path) throws IOExceptio } } - @NotNull - public static YamlConfiguration loadConfig(@NotNull InputStream inputStream) + public static YamlConfiguration loadConfig(InputStream inputStream) throws IOException, InvalidConfigurationException { Objects.requireNonNull(inputStream, "InputStream cannot be null"); @@ -82,7 +81,7 @@ public void clear() { this.map.clear(); } - public void save(@NotNull Path path) throws IOException { + public void save(Path path) throws IOException { Objects.requireNonNull(path, "Path cannot be null"); Files.createDirectories(path.getParent()); @@ -101,7 +100,7 @@ public String withoutComments() throws IOException { } } - private void save(@NotNull Writer writer) throws IOException { + private void save(Writer writer) throws IOException { Objects.requireNonNull(writer, "Writer cannot be null"); MappingNode node = toNodeTree(this.commentData, this); @@ -117,7 +116,7 @@ private void save(@NotNull Writer writer) throws IOException { } } - private void load(@NotNull Reader reader) throws YAMLException, InvalidConfigurationException { + private void load(Reader reader) throws YAMLException, InvalidConfigurationException { Objects.requireNonNull(reader, "Reader cannot be null"); Node rawNode = yaml.compose(reader); @@ -134,7 +133,7 @@ private void load(@NotNull Reader reader) throws YAMLException, InvalidConfigura } } - private MappingNode toNodeTree(@Nullable NodeCommentData commentData, @NotNull ConfigurationSection section) { + private MappingNode toNodeTree(@Nullable NodeCommentData commentData, ConfigurationSection section) { List nodeTuples = new ArrayList<>(); for (Map.Entry entry : section.map.entrySet()) { @@ -163,8 +162,8 @@ private MappingNode toNodeTree(@Nullable NodeCommentData commentData, @NotNull C return new MappingNode(Tag.MAP, nodeTuples, DumperOptions.FlowStyle.BLOCK); } - private void fromNodeTree(@NotNull MappingNode input, @NotNull NodeCommentData commentData, - @NotNull ConfigurationSection section) throws InvalidConfigurationException { + private void fromNodeTree(MappingNode input, NodeCommentData commentData, ConfigurationSection section) + throws InvalidConfigurationException { constructor.flattenMapping(input); for (NodeTuple nodeTuple : input.getValue()) { @@ -191,7 +190,7 @@ private void fromNodeTree(@NotNull MappingNode input, @NotNull NodeCommentData c } } - private boolean isNullOrEmpty(Collection collection) { + private boolean isNullOrEmpty(@Nullable Collection collection) { return collection == null || collection.isEmpty(); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java index 3f316c2b..2353cefd 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java @@ -1,10 +1,11 @@ package dev.imprex.orebfuscator.interop; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import dev.imprex.orebfuscator.util.BlockProperties; import dev.imprex.orebfuscator.util.BlockTag; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public interface RegistryAccessor { int getUniqueBlockStateCount(); @@ -17,8 +18,8 @@ public interface RegistryAccessor { boolean isBlockEntity(int blockId); - @Nullable BlockProperties getBlockByName(@NotNull String name); + @Nullable BlockProperties getBlockByName(String name); - @Nullable BlockTag getBlockTagByName(@NotNull String name); + @Nullable BlockTag getBlockTagByName(String name); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/LoggerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/LoggerAccessor.java index 22bade65..c1159095 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/LoggerAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/LoggerAccessor.java @@ -1,10 +1,11 @@ package dev.imprex.orebfuscator.logging; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public interface LoggerAccessor { - void log(@NotNull LogLevel level, @NotNull String message, @Nullable Throwable throwable); + void log(LogLevel level, String message, @Nullable Throwable throwable); } \ No newline at end of file diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/OfcLogger.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/OfcLogger.java index 00b16f33..a0b5ad32 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/OfcLogger.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/OfcLogger.java @@ -3,10 +3,10 @@ import java.util.Objects; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - +@NullMarked public class OfcLogger { private static LoggerAccessor logger = new SystemLogger(); @@ -14,7 +14,7 @@ public class OfcLogger { private static final Queue VERBOSE_LOG = new ConcurrentLinkedQueue<>(); private static boolean verbose; - public static void setLogger(@NotNull LoggerAccessor logger) { + public static void setLogger(LoggerAccessor logger) { if (OfcLogger.logger instanceof SystemLogger) { OfcLogger.logger = Objects.requireNonNull(logger); } @@ -29,36 +29,35 @@ public static void setVerboseLogging(boolean enabled) { } } - @NotNull public static String getLatestVerboseLog() { return String.join("\n", VERBOSE_LOG); } - public static void debug(@NotNull String message) { + public static void debug(String message) { log(LogLevel.DEBUG, message); } - public static void info(@NotNull String message) { + public static void info(String message) { log(LogLevel.INFO, message); } - public static void warn(@NotNull String message) { + public static void warn(String message) { log(LogLevel.WARN, message); } - public static void error(@NotNull Throwable throwable) { + public static void error(Throwable throwable) { log(LogLevel.ERROR, "An error occurred:", throwable); } - public static void error(@NotNull String message, @Nullable Throwable throwable) { + public static void error(String message, @Nullable Throwable throwable) { log(LogLevel.ERROR, message, throwable); } - public static void log(@NotNull LogLevel level, @NotNull String message) { + public static void log(LogLevel level, String message) { log(level, message, null); } - public static void log(@NotNull LogLevel level, @NotNull String message, @Nullable Throwable throwable) { + public static void log(LogLevel level, String message, @Nullable Throwable throwable) { Objects.requireNonNull(level); Objects.requireNonNull(message); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/SystemLogger.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/SystemLogger.java index 921a2f07..51c17f55 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/SystemLogger.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/logging/SystemLogger.java @@ -1,14 +1,14 @@ package dev.imprex.orebfuscator.logging; import java.io.PrintStream; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - +@NullMarked public class SystemLogger implements LoggerAccessor { @Override - public void log(@NotNull LogLevel level, @NotNull String message, @Nullable Throwable throwable) { + public void log(LogLevel level, String message, @Nullable Throwable throwable) { PrintStream stream = level == LogLevel.ERROR ? System.err : System.out; stream.printf("[Orebfuscator - %s] %s%n", level, message); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/Reflector.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/Reflector.java index 6e823248..4036d84a 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/Reflector.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/Reflector.java @@ -8,7 +8,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.reflect.accessor.Accessors; import dev.imprex.orebfuscator.reflect.accessor.ConstructorAccessor; import dev.imprex.orebfuscator.reflect.accessor.FieldAccessor; @@ -16,17 +15,20 @@ import dev.imprex.orebfuscator.reflect.predicate.ConstructorPredicate; import dev.imprex.orebfuscator.reflect.predicate.FieldPredicate; import dev.imprex.orebfuscator.reflect.predicate.MethodPredicate; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class Reflector { public static Reflector of(Class target) { return new Reflector(target); } - private final @NotNull Class target; - private @NotNull Class recursiveUntil; + private final Class target; + private Class recursiveUntil; - private Reflector(@NotNull Class target) { + private Reflector(Class target) { this.target = Objects.requireNonNull(target); this.recursiveUntil = target; } @@ -35,7 +37,7 @@ public Reflector recursive() { return this.recursiveUntil(Object.class); } - public Reflector recursiveUntil(Class recursiveUntil) { + public Reflector recursiveUntil(@Nullable Class recursiveUntil) { this.recursiveUntil = recursiveUntil != null ? recursiveUntil : this.target; @@ -68,35 +70,29 @@ private Stream get(Function, T[]> getter) { return stream; } - @NotNull public Stream constructor(Predicate> predicate) { Stream> stream = get(Class::getDeclaredConstructors); return stream.filter(predicate).map(Accessors::wrap); } - @NotNull public ConstructorPredicate constructor() { return new ConstructorPredicate(this::constructor, this::className); } - @NotNull public Stream field(Predicate predicate) { Stream stream = get(Class::getDeclaredFields); return stream.filter(predicate).map(Accessors::wrap); } - @NotNull public FieldPredicate field() { return new FieldPredicate(this::field, this::className); } - @NotNull public Stream method(Predicate predicate) { Stream stream = get(Class::getDeclaredMethods); return stream.filter(predicate).map(Accessors::wrap); } - @NotNull public MethodPredicate method() { return new MethodPredicate(this::method, this::className); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/Accessors.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/Accessors.java index 2fc4b450..3bee61e4 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/Accessors.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/Accessors.java @@ -11,8 +11,9 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Objects; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; +@NullMarked public final class Accessors { private static final Lookup LOOKUP = MethodHandles.lookup(); @@ -23,7 +24,7 @@ public final class Accessors { private Accessors() { } - public static @NotNull ConstructorAccessor wrap(@NotNull Constructor constructor) { + public static ConstructorAccessor wrap(Constructor constructor) { return create(constructor, () -> { MethodHandle methodHandle = LOOKUP.unreflectConstructor(constructor); methodHandle = generifyExecutable(methodHandle, false, true); @@ -32,14 +33,14 @@ private Accessors() { }); } - public static @NotNull FieldAccessor wrap(@NotNull Field field) { + public static FieldAccessor wrap(Field field) { return create(field, () -> { MethodHandle getter = LOOKUP.unreflectGetter(field); MethodHandle setter = null; try { setter = LOOKUP.unreflectSetter(field); - } catch (IllegalAccessException e) { + } catch (IllegalAccessException ignored) { } if (Modifier.isStatic(field.getModifiers())) { @@ -54,7 +55,7 @@ private Accessors() { }); } - public static @NotNull MethodAccessor wrap(@NotNull Method method) { + public static MethodAccessor wrap(Method method) { return create(method, () -> { MethodHandle methodHandle = LOOKUP.unreflect(method); methodHandle = generifyExecutable(methodHandle, Modifier.isStatic(method.getModifiers()), false); @@ -63,8 +64,8 @@ private Accessors() { }); } - private static @NotNull TAccessor create( - @NotNull TMember member, @NotNull AccessorFactory factory) { + private static TAccessor create( + TMember member, AccessorFactory factory) { Objects.requireNonNull(member); @SuppressWarnings("deprecation") diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultConstrutorAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultConstrutorAccessor.java index 58b41fb7..532895fd 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultConstrutorAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultConstrutorAccessor.java @@ -1,11 +1,11 @@ package dev.imprex.orebfuscator.reflect.accessor; -import org.jetbrains.annotations.NotNull; import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; +import org.jspecify.annotations.NonNull; -record DefaultConstructorAccessor(@NotNull Constructor member, @NotNull MethodHandle methodHandle) implements +record DefaultConstructorAccessor(@NonNull Constructor member, @NonNull MethodHandle methodHandle) implements ConstructorAccessor { @Override @@ -18,7 +18,7 @@ public Object invoke(Object... args) { } @Override - public @NotNull Constructor member() { + public @NonNull Constructor member() { return member; } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultFieldAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultFieldAccessor.java index c91dab56..60c8838a 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultFieldAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultFieldAccessor.java @@ -2,10 +2,10 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; -record DefaultFieldAccessor(@NotNull Field member, @NotNull MethodHandle getterHandle, +record DefaultFieldAccessor(@NonNull Field member, @NonNull MethodHandle getterHandle, @Nullable MethodHandle setterHandle) implements FieldAccessor { @Override @@ -36,7 +36,7 @@ public void set(Object instance, Object value) { } @Override - public @NotNull Field member() { + public @NonNull Field member() { return this.member; } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java index 940bb2f5..e041c337 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java @@ -2,9 +2,10 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Method; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; -record DefaultMethodAccessor(@NotNull Method member, @NotNull MethodHandle methodHandle) implements +record DefaultMethodAccessor(@NonNull Method member, @NonNull MethodHandle methodHandle) implements MethodAccessor { @Override @@ -17,7 +18,7 @@ public Object invoke(Object instance, Object... args) { } @Override - public @NotNull Method member() { + public @NonNull Method member() { return member; } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MemberAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MemberAccessor.java index ce43b857..ac61b941 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MemberAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MemberAccessor.java @@ -1,10 +1,10 @@ package dev.imprex.orebfuscator.reflect.accessor; -import org.jetbrains.annotations.NotNull; import java.lang.reflect.Member; +import org.jspecify.annotations.NonNull; public interface MemberAccessor { - @NotNull TMember member(); + @NonNull TMember member(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MethodAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MethodAccessor.java index 11198eb8..1b07f00f 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MethodAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/MethodAccessor.java @@ -5,5 +5,4 @@ public interface MethodAccessor extends MemberAccessor { Object invoke(Object target, Object... args); - } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java index d3c6722a..2e221be7 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java @@ -9,29 +9,30 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import dev.imprex.orebfuscator.reflect.accessor.MemberAccessor; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked abstract sealed class AbstractExecutablePredicate< TThis extends AbstractExecutablePredicate, TAccessor extends MemberAccessor, TExecutable extends Executable > extends AbstractMemberPredicate permits ConstructorPredicate, MethodPredicate { - private final @NotNull List exceptionClass = new ArrayList<>(); - private final @NotNull List parameterClass = new ArrayList<>(); + private final List exceptionClass = new ArrayList<>(); + private final List parameterClass = new ArrayList<>(); private int parameterCount = -1; public AbstractExecutablePredicate( - @NotNull Function> producer, - @NotNull Supplier error) { + Function> producer, + Supplier error) { super(producer, error); } @Override - public boolean test(@NotNull TExecutable executable) { + public boolean test(TExecutable executable) { return super.test(executable) && IndexedClassMatcher.all(executable.getExceptionTypes(), exceptionClass) && IndexedClassMatcher.all(executable.getParameterTypes(), parameterClass) @@ -39,7 +40,7 @@ public boolean test(@NotNull TExecutable executable) { } @Override - void requirements(@NotNull RequirementCollector collector) { + void requirements(RequirementCollector collector) { super.requirements(collector); if (!exceptionClass.isEmpty()) { @@ -53,66 +54,66 @@ void requirements(@NotNull RequirementCollector collector) { } } - public @NotNull TThis exception(@NotNull ClassPredicate matcher) { + public TThis exception(ClassPredicate matcher) { this.exceptionClass.add(new IndexedClassMatcher(Objects.requireNonNull(matcher))); return instance(); } - public @NotNull TThis exception(@NotNull ClassPredicate matcher, int index) { + public TThis exception(ClassPredicate matcher, int index) { this.exceptionClass.add(new IndexedClassMatcher(Objects.requireNonNull(matcher), index)); return instance(); } - public @NotNull ClassPredicate.Builder exception() { + public ClassPredicate.Builder exception() { return new ClassPredicate.Builder<>(this::exception); } - public @NotNull ClassPredicate.Builder exception(int index) { + public ClassPredicate.Builder exception(int index) { return new ClassPredicate.Builder<>(m -> this.exception(m, index)); } - public @NotNull TThis parameter(@NotNull ClassPredicate matcher) { + public TThis parameter(ClassPredicate matcher) { this.parameterClass.add(new IndexedClassMatcher(Objects.requireNonNull(matcher))); return instance(); } - public @NotNull TThis parameter(@NotNull ClassPredicate matcher, int index) { + public TThis parameter(ClassPredicate matcher, int index) { this.parameterClass.add(new IndexedClassMatcher(Objects.requireNonNull(matcher), index)); return instance(); } - public @NotNull ClassPredicate.Builder parameter() { + public ClassPredicate.Builder parameter() { return new ClassPredicate.Builder<>(this::parameter); } - public @NotNull ClassPredicate.Builder parameter(int index) { + public ClassPredicate.Builder parameter(int index) { return new ClassPredicate.Builder<>(m -> this.parameter(m, index)); } - public @NotNull TThis parameterCount(int parameterCount) { + public TThis parameterCount(int parameterCount) { this.parameterCount = parameterCount; return instance(); } - private record IndexedClassMatcher(@NotNull ClassPredicate matcher, @Nullable Integer index) implements + private record IndexedClassMatcher(ClassPredicate matcher, @Nullable Integer index) implements Comparable { - private static boolean all(@NotNull Class[] classArray, @NotNull List classMatchers) { + private static boolean all(Class[] classArray, List classMatchers) { return classMatchers.stream().allMatch(matcher -> matcher.matches(classArray)); } - private static String toString(@NotNull List classMatchers) { + private static String toString(List classMatchers) { return classMatchers.stream() .sorted() .map(IndexedClassMatcher::toString) .collect(Collectors.joining(",\n ", "{\n ", "\n }")); } - public IndexedClassMatcher(@NotNull ClassPredicate matcher) { + public IndexedClassMatcher(ClassPredicate matcher) { this(matcher, null); } - public boolean matches(@NotNull Class[] classArray) { + public boolean matches(Class[] classArray) { if (index() == null) { for (Class entry : classArray) { if (matcher().test(entry)) { @@ -126,7 +127,7 @@ public boolean matches(@NotNull Class[] classArray) { } @Override - public int compareTo(@NotNull IndexedClassMatcher other) { + public int compareTo(IndexedClassMatcher other) { if (this.index == null && other.index == null) { return 0; } @@ -140,7 +141,7 @@ public int compareTo(@NotNull IndexedClassMatcher other) { } @Override - public @NotNull String toString() { + public String toString() { String key = index() == null ? "" : index().toString(); return String.format("%s=%s", key, matcher().requirement()); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractMemberPredicate.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractMemberPredicate.java index 5cff71ac..9565c622 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractMemberPredicate.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractMemberPredicate.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.reflect.predicate; +import dev.imprex.orebfuscator.reflect.accessor.MemberAccessor; import java.lang.reflect.Member; import java.lang.reflect.Modifier; import java.util.Objects; @@ -8,22 +9,20 @@ import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.stream.Stream; - import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import dev.imprex.orebfuscator.reflect.accessor.MemberAccessor; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked abstract sealed class AbstractMemberPredicate< TThis extends AbstractMemberPredicate, TAccessor extends MemberAccessor, TMember extends Member > implements Predicate permits AbstractExecutablePredicate, FieldPredicate { - private final @NotNull Function> producer; - private final @NotNull Supplier error; + private final Function> producer; + private final Supplier error; private int requiredModifiers; private int bannedModifiers; @@ -32,14 +31,14 @@ abstract sealed class AbstractMemberPredicate< private @Nullable ClassPredicate declaringClass; public AbstractMemberPredicate( - @NotNull Function> producer, - @NotNull Supplier error) { + Function> producer, + Supplier error) { this.producer = producer; this.error = error; } @Override - public boolean test(@NotNull TMember member) { + public boolean test(TMember member) { int modifiers = member.getModifiers(); return (modifiers & requiredModifiers) == requiredModifiers && (modifiers & bannedModifiers) == 0 @@ -48,7 +47,7 @@ public boolean test(@NotNull TMember member) { && (declaringClass == null || declaringClass.test(member.getDeclaringClass())); } - void requirements(@NotNull RequirementCollector collector) { + void requirements(RequirementCollector collector) { if (requiredModifiers != 0) { collector.collect("requiredModifiers", Modifier.toString(requiredModifiers)); } @@ -66,95 +65,95 @@ void requirements(@NotNull RequirementCollector collector) { } } - private @NotNull IllegalArgumentException requirementException() { + private IllegalArgumentException requirementException() { var collector = new RequirementCollector(error.get()); requirements(collector); return new IllegalArgumentException(collector.get()); } - protected abstract @NotNull TThis instance(); + protected abstract TThis instance(); - public @NotNull TThis requireModifier(@MagicConstant(flagsFromClass = Modifier.class) int modifiers) { + public TThis requireModifier(@MagicConstant(flagsFromClass = Modifier.class) int modifiers) { this.requiredModifiers |= modifiers; return instance(); } - public @NotNull TThis requirePublic() { + public TThis requirePublic() { return requireModifier(Modifier.PUBLIC); } - public @NotNull TThis requireProtected() { + public TThis requireProtected() { return requireModifier(Modifier.PROTECTED); } - public @NotNull TThis requirePrivate() { + public TThis requirePrivate() { return requireModifier(Modifier.PRIVATE); } - public @NotNull TThis requireStatic() { + public TThis requireStatic() { return requireModifier(Modifier.STATIC); } - public @NotNull TThis requireFinal() { + public TThis requireFinal() { return requireModifier(Modifier.FINAL); } - public @NotNull TThis banModifier(@MagicConstant(flagsFromClass = Modifier.class) int modifiers) { + public TThis banModifier(@MagicConstant(flagsFromClass = Modifier.class) int modifiers) { this.bannedModifiers |= modifiers; return instance(); } - public @NotNull TThis banPublic() { + public TThis banPublic() { return banModifier(Modifier.PUBLIC); } - public @NotNull TThis banProtected() { + public TThis banProtected() { return banModifier(Modifier.PROTECTED); } - public @NotNull TThis banPrivate() { + public TThis banPrivate() { return banModifier(Modifier.PRIVATE); } - public @NotNull TThis banStatic() { + public TThis banStatic() { return banModifier(Modifier.STATIC); } - public @NotNull TThis banFinal() { + public TThis banFinal() { return banModifier(Modifier.FINAL); } - public @NotNull TThis includeSynthetic() { + public TThis includeSynthetic() { this.includeSynthetic = true; return instance(); } - public @NotNull TThis nameRegex(@NotNull Pattern pattern) { + public TThis nameRegex(Pattern pattern) { this.name = Objects.requireNonNull(pattern); return instance(); } - public @NotNull TThis nameIs(@NotNull String name) { + public TThis nameIs(String name) { String pattern = Pattern.quote(Objects.requireNonNull(name)); return nameRegex(Pattern.compile(pattern)); } - public @NotNull TThis nameIsIgnoreCase(@NotNull String name) { + public TThis nameIsIgnoreCase(String name) { String pattern = Pattern.quote(Objects.requireNonNull(name)); return nameRegex(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE)); } - public @NotNull TThis declaringClass(@NotNull ClassPredicate matcher) { + public TThis declaringClass(ClassPredicate matcher) { this.declaringClass = Objects.requireNonNull(matcher); return instance(); } - public @NotNull ClassPredicate.Builder declaringClass() { + public ClassPredicate.Builder declaringClass() { return new ClassPredicate.Builder<>(this::declaringClass); } @Contract(pure = true) - public @NotNull Stream stream() { + public Stream stream() { return producer.apply(instance()); } @@ -164,7 +163,7 @@ void requirements(@NotNull RequirementCollector collector) { } @Contract(pure = true) - public @NotNull TAccessor getOrThrow(int index) { + public TAccessor getOrThrow(int index) { return stream().skip(index).findFirst().orElseThrow(this::requirementException); } @@ -174,18 +173,18 @@ void requirements(@NotNull RequirementCollector collector) { } @Contract(pure = true) - public @NotNull TAccessor firstOrThrow() { + public TAccessor firstOrThrow() { return stream().findFirst().orElseThrow(this::requirementException); } @Contract(pure = true) - public @Nullable TAccessor find(@NotNull Predicate predicate) { + public @Nullable TAccessor find(Predicate predicate) { return stream().filter(accessor -> predicate.test(accessor.member())) .findFirst().orElse(null); } @Contract(pure = true) - public @NotNull TAccessor findOrThrow(@NotNull Predicate predicate) { + public TAccessor findOrThrow(Predicate predicate) { return stream().filter(accessor -> predicate.test(accessor.member())) .findFirst().orElseThrow(this::requirementException); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ClassPredicate.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ClassPredicate.java index 09e22367..601c80fc 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ClassPredicate.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ClassPredicate.java @@ -6,70 +6,55 @@ import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; +@NullMarked public interface ClassPredicate extends Predicate> { - boolean test(@NotNull Class type); + boolean test(Class type); - @NotNull String requirement(); - class Builder { + record Builder(Function returnFunction) { - private final Function returnFunction; - - public Builder(Function returnFunction) { - this.returnFunction = returnFunction; - } - - @NotNull - public TParent is(@NotNull Class type) { + public TParent is(Class type) { return returnFunction.apply(new IsClassPredicate(type)); } - @NotNull - public TParent superOf(@NotNull Class type) { + public TParent superOf(Class type) { return returnFunction.apply(new SuperClassPredicate(type)); } - @NotNull - public TParent subOf(@NotNull Class type) { + public TParent subOf(Class type) { return returnFunction.apply(new SubClassPredicate(type)); } - @NotNull - public TParent any(@NotNull Set> types) { + public TParent any(Set> types) { return returnFunction.apply(new AnyClassPredicate(types)); } - @NotNull - public TParent any(@NotNull Class... types) { + public TParent any(Class... types) { return any(Set.of(types)); } - @NotNull - public TParent regex(@NotNull Pattern pattern) { + public TParent regex(Pattern pattern) { return returnFunction.apply(new RegexClassPredicate(pattern)); } } - class IsClassPredicate implements ClassPredicate { - - private final @NotNull Class expected; + record IsClassPredicate(Class expected) implements ClassPredicate { - public IsClassPredicate(@NotNull Class expected) { - this.expected = Objects.requireNonNull(expected); + public IsClassPredicate { + Objects.requireNonNull(expected); } @Override - public boolean test(@NotNull Class type) { + public boolean test(Class type) { Objects.requireNonNull(type); return this.expected.equals(type); } - @NotNull @Override public String requirement() { return String.format("{is %s}", this.expected.getTypeName()); @@ -81,22 +66,19 @@ public boolean equals(Object obj) { } } - class SuperClassPredicate implements ClassPredicate { + record SuperClassPredicate(Class expected) implements ClassPredicate { - private final @NotNull Class expected; - - public SuperClassPredicate(@NotNull Class expected) { - this.expected = Objects.requireNonNull(expected); + public SuperClassPredicate { + Objects.requireNonNull(expected); } @Override - public boolean test(@NotNull Class type) { + public boolean test(Class type) { Objects.requireNonNull(type); return type.isAssignableFrom(this.expected); } - @NotNull @Override public String requirement() { return String.format("{super-class-of %s}", this.expected.getTypeName()); @@ -108,22 +90,19 @@ public boolean equals(Object obj) { } } - class SubClassPredicate implements ClassPredicate { - - private final @NotNull Class expected; + record SubClassPredicate(Class expected) implements ClassPredicate { - public SubClassPredicate(@NotNull Class expected) { - this.expected = Objects.requireNonNull(expected); + public SubClassPredicate { + Objects.requireNonNull(expected); } @Override - public boolean test(@NotNull Class type) { + public boolean test(Class type) { Objects.requireNonNull(type); return this.expected.isAssignableFrom(type); } - @NotNull @Override public String requirement() { return String.format("{sub-class-of %s}", this.expected.getTypeName()); @@ -135,22 +114,19 @@ public boolean equals(Object obj) { } } - class AnyClassPredicate implements ClassPredicate { + record AnyClassPredicate(Set> expected) implements ClassPredicate { - private final @NotNull Set> expected; - - public AnyClassPredicate(@NotNull Set> expected) { - this.expected = Objects.requireNonNull(expected); + public AnyClassPredicate { + Objects.requireNonNull(expected); } @Override - public boolean test(@NotNull Class type) { + public boolean test(Class type) { Objects.requireNonNull(type); return this.expected.contains(type); } - @NotNull @Override public String requirement() { return String.format("{any %s}", @@ -163,22 +139,19 @@ public boolean equals(Object obj) { } } - class RegexClassPredicate implements ClassPredicate { - - private final @NotNull Pattern expected; + record RegexClassPredicate(Pattern expected) implements ClassPredicate { - public RegexClassPredicate(@NotNull Pattern expected) { - this.expected = Objects.requireNonNull(expected); + public RegexClassPredicate { + Objects.requireNonNull(expected); } @Override - public boolean test(@NotNull Class type) { + public boolean test(Class type) { Objects.requireNonNull(type); return this.expected.matcher(type.getTypeName()).matches(); } - @NotNull @Override public String requirement() { return String.format("{regex %s}", this.expected); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ConstructorPredicate.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ConstructorPredicate.java index d1e89d3a..7b35cbe1 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ConstructorPredicate.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/ConstructorPredicate.java @@ -5,21 +5,22 @@ import java.util.function.Supplier; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.reflect.accessor.ConstructorAccessor; +import org.jspecify.annotations.NullMarked; +@NullMarked public final class ConstructorPredicate extends AbstractExecutablePredicate> { public ConstructorPredicate( - @NotNull Function> producer, - @NotNull Supplier className) { + Function> producer, + Supplier className) { super(producer, () -> String.format("Can't find constructor in class %s matching: ", className.get())); } @Override - protected @NotNull ConstructorPredicate instance() { + protected ConstructorPredicate instance() { return this; } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/FieldPredicate.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/FieldPredicate.java index 6af1db37..80e877ee 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/FieldPredicate.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/FieldPredicate.java @@ -6,27 +6,28 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public final class FieldPredicate extends AbstractMemberPredicate { private @Nullable ClassPredicate type; public FieldPredicate( - @NotNull Function> producer, - @NotNull Supplier className) { + Function> producer, + Supplier className) { super(producer, () -> String.format("Can't find field in class %s matching: ", className.get())); } @Override - public boolean test(@NotNull Field field) { + public boolean test(Field field) { return super.test(field) && (type == null || type.test(field.getType())); } @Override - void requirements(@NotNull RequirementCollector collector) { + void requirements(RequirementCollector collector) { super.requirements(collector); if (type != null) { @@ -34,17 +35,17 @@ void requirements(@NotNull RequirementCollector collector) { } } - public @NotNull FieldPredicate type(@NotNull ClassPredicate matcher) { + public FieldPredicate type(ClassPredicate matcher) { this.type = Objects.requireNonNull(matcher); return this; } - public @NotNull ClassPredicate.Builder type() { + public ClassPredicate.Builder type() { return new ClassPredicate.Builder<>(this::type); } @Override - protected @NotNull FieldPredicate instance() { + protected FieldPredicate instance() { return this; } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/MethodPredicate.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/MethodPredicate.java index 462d6e83..06d9d606 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/MethodPredicate.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/MethodPredicate.java @@ -6,27 +6,28 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public final class MethodPredicate extends AbstractExecutablePredicate { private @Nullable ClassPredicate returnType; public MethodPredicate( - @NotNull Function> producer, - @NotNull Supplier className) { + Function> producer, + Supplier className) { super(producer, () -> String.format("Can't find constructor in class %s matching: ", className.get())); } @Override - public boolean test(@NotNull Method method) { + public boolean test(Method method) { return super.test(method) && (returnType == null || returnType.test(method.getReturnType())); } @Override - void requirements(@NotNull RequirementCollector collector) { + void requirements(RequirementCollector collector) { super.requirements(collector); if (returnType != null) { @@ -34,17 +35,17 @@ void requirements(@NotNull RequirementCollector collector) { } } - public @NotNull MethodPredicate returnType(@NotNull ClassPredicate matcher) { + public MethodPredicate returnType(ClassPredicate matcher) { this.returnType = Objects.requireNonNull(matcher); return this; } - public @NotNull ClassPredicate.Builder returnType() { + public ClassPredicate.Builder returnType() { return new ClassPredicate.Builder<>(this::returnType); } @Override - protected @NotNull MethodPredicate instance() { + protected MethodPredicate instance() { return this; } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/RequirementCollector.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/RequirementCollector.java index d1a91e77..1384360e 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/RequirementCollector.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/RequirementCollector.java @@ -2,26 +2,25 @@ import java.util.Objects; import java.util.StringJoiner; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; +@NullMarked class RequirementCollector { private final StringJoiner entries; - public RequirementCollector(@NotNull String prefix) { + public RequirementCollector(String prefix) { this.entries = new StringJoiner(",\n", prefix + "{\n", "\n}"); } - @NotNull - public RequirementCollector collect(@NotNull String name) { + public RequirementCollector collect(String name) { Objects.requireNonNull(name); entries.add(" " + name); return this; } - @NotNull - public RequirementCollector collect(@NotNull String name, @NotNull Object value) { + public RequirementCollector collect(String name, Object value) { Objects.requireNonNull(name); Objects.requireNonNull(value); @@ -29,7 +28,6 @@ public RequirementCollector collect(@NotNull String name, @NotNull Object value) return this; } - @NotNull public String get() { return entries.toString(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java index 8e46b483..63ff370b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.util; +import org.jspecify.annotations.NullMarked; + +@NullMarked public record BlockPos(int x, int y, int z) implements Comparable { // from net.minecraft.core.BlockPos @@ -24,6 +27,10 @@ public BlockPos add(int x, int y, int z) { return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.x + x, this.y + y, this.z + z); } + public BlockPos add(BlockPos other) { + return this.add(other.x(), other.y(), other.z()); + } + public double distanceSquared(double x, double y, double z) { double dx = this.x - x; double dy = this.y - y; @@ -63,9 +70,4 @@ public int compareTo(BlockPos other) { } return this.y - other.y; } - - @Override - public String toString() { - return "BlockPos [x=" + x + ", y=" + y + ", z=" + z + "]"; - } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java index 30a0561c..a6a72da1 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java @@ -4,7 +4,10 @@ import java.util.Objects; import java.util.Set; import com.google.common.collect.ImmutableList; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class BlockProperties { public static Builder builder(NamespacedKey key) { @@ -17,6 +20,7 @@ public static Builder builder(NamespacedKey key) { private BlockProperties(Builder builder) { this.key = builder.key; + assert builder.defaultBlockState != null; this.defaultBlockState = builder.defaultBlockState; this.blockStates = ImmutableList.copyOf(builder.blockStates); } @@ -59,11 +63,11 @@ public static class Builder { private final NamespacedKey key; - private BlockStateProperties defaultBlockState; + private @Nullable BlockStateProperties defaultBlockState; private final Set blockStates = new HashSet<>(); private Builder(NamespacedKey key) { - this.key = key; + this.key = Objects.requireNonNull(key); } public Builder withBlockState(BlockStateProperties blockState) { @@ -76,7 +80,7 @@ public Builder withBlockState(BlockStateProperties blockState) { // check for multiple default blocks if (this.defaultBlockState != null) { throw new IllegalStateException( - String.format("multiple default block states for block: %s", blockState.getId(), key)); + String.format("multiple default block states for block: %s", key)); } this.defaultBlockState = blockState; @@ -88,7 +92,7 @@ public Builder withBlockState(BlockStateProperties blockState) { public BlockProperties build() { Objects.requireNonNull(this.defaultBlockState, "missing default block state for block: " + this.key); - if (this.blockStates.size() == 0) { + if (this.blockStates.isEmpty()) { throw new IllegalStateException("missing block states for block: " + this.key); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java index 9c53c5f3..f1201bcd 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.util; +import org.jspecify.annotations.NullMarked; + +@NullMarked public class BlockStateProperties { public static Builder builder(int id) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java index 5769bda4..35cdfa77 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java @@ -3,11 +3,12 @@ import java.util.Collections; import java.util.Objects; import java.util.Set; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; -public record BlockTag(@NotNull NamespacedKey key, @NotNull Set blocks) { +@NullMarked +public record BlockTag(NamespacedKey key, Set blocks) { - public BlockTag(@NotNull NamespacedKey key, @NotNull Set blocks) { + public BlockTag(NamespacedKey key, Set blocks) { this.key = key; this.blocks = Collections.unmodifiableSet(blocks); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java index 2de79156..02873514 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java @@ -1,15 +1,21 @@ package dev.imprex.orebfuscator.util; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.interop.WorldAccessor; +import org.jspecify.annotations.NullMarked; -public record ChunkCacheKey(@NotNull String world, int x, int z) { +@NullMarked +public record ChunkCacheKey(String world, int x, int z) { - public ChunkCacheKey(@NotNull WorldAccessor world, BlockPos position) { + public ChunkCacheKey(WorldAccessor world, BlockPos position) { this(world.getName(), position.x() >> 4, position.z() >> 4); } - public ChunkCacheKey(@NotNull WorldAccessor world, int x, int z) { + public ChunkCacheKey(WorldAccessor world, int x, int z) { this(world.getName(), x, z); } + + @Override + public String toString() { + return "[%s, (%s, %s)]".formatted(world, x, z); + } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java index a9f65cb3..1bac2629 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.util; +import org.jspecify.annotations.NullMarked; + +@NullMarked public enum ChunkDirection { NORTH(1, 0), EAST(0, 1), SOUTH(-1, 0), WEST(0, -1); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java index 3a029d3b..094b9f1c 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java @@ -1,6 +1,7 @@ package dev.imprex.orebfuscator.util; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * Represents a String based key which consists of two components - a namespace and a key. @@ -12,6 +13,8 @@ * @author org.bukkit.NamespacedKey from 1.19.4 * */ + +@NullMarked public record NamespacedKey(String namespace, String key) { /** @@ -27,34 +30,42 @@ private static boolean isValidKeyChar(char c) { return isValidNamespaceChar(c) || c == '/'; } - private static boolean isValidNamespace(String namespace) { + private static boolean isInvalidNamespace(@Nullable String namespace) { + if (namespace == null) { + return true; + } + int len = namespace.length(); if (len == 0) { - return false; + return true; } for (int i = 0; i < len; i++) { if (!isValidNamespaceChar(namespace.charAt(i))) { - return false; + return true; } } - return true; + return false; } - private static boolean isValidKey(String key) { + private static boolean isInvalidKey(@Nullable String key) { + if (key == null) { + return true; + } + int len = key.length(); if (len == 0) { - return false; + return true; } for (int i = 0; i < len; i++) { if (!isValidKeyChar(key.charAt(i))) { - return false; + return true; } } - return true; + return false; } /** @@ -66,9 +77,9 @@ private static boolean isValidKey(String key) { */ @Deprecated public NamespacedKey(String namespace, String key) { - if (namespace == null || !isValidNamespace(namespace)) { + if (isInvalidNamespace(namespace)) { throw new IllegalArgumentException(String.format("Invalid namespace. Must be [a-z0-9._-]: %s", namespace)); - } else if (key == null || !isValidKey(key)) { + } else if (isInvalidKey(key)) { throw new IllegalArgumentException(String.format("Invalid key. Must be [a-z0-9/._-]: %s", key)); } @@ -116,8 +127,8 @@ public static NamespacedKey minecraft(String key) { * * @return the created NamespacedKey. null if invalid */ - public static NamespacedKey fromString(@NotNull String string) { - if (string == null || string.isEmpty()) { + public static @Nullable NamespacedKey fromString(String string) { + if (string.isEmpty()) { throw new IllegalArgumentException("Input string must not be empty or null"); } @@ -129,12 +140,12 @@ public static NamespacedKey fromString(@NotNull String string) { String key = (components.length == 2) ? components[1] : ""; if (components.length == 1) { String value = components[0]; - if (value.isEmpty() || !isValidKey(value)) { + if (value.isEmpty() || isInvalidKey(value)) { return null; } return minecraft(value); - } else if (components.length == 2 && !isValidKey(key)) { + } else if (components.length == 2 && isInvalidKey(key)) { return null; } @@ -143,7 +154,7 @@ public static NamespacedKey fromString(@NotNull String string) { return minecraft(key); } - if (!isValidNamespace(namespace)) { + if (isInvalidNamespace(namespace)) { return null; } 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..e0c301a9 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 @@ -9,8 +9,6 @@ */ 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..419690a2 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 @@ -8,7 +8,9 @@ import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; +import org.jspecify.annotations.NullMarked; +@NullMarked public record Version(int major, int minor, int patch) implements Comparable { private static final Pattern VERSION_PATTERN = 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..98c1c9e3 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; @@ -148,7 +149,7 @@ public int next() { * @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); @@ -187,7 +188,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-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..c9dd0963 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 @@ -4,8 +4,6 @@ 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; @@ -13,11 +11,14 @@ import dev.imprex.orebfuscator.util.BlockTag; import dev.imprex.orebfuscator.util.MathUtil; import dev.imprex.orebfuscator.util.NamespacedKey; +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) { @@ -80,12 +81,12 @@ public final int getMaxBitsPerBlockState() { } @Override - public final @Nullable BlockProperties getBlockByName(@NotNull String name) { + public final @Nullable BlockProperties getBlockByName(String name) { return this.blocks.get(NamespacedKey.fromString(name)); } @Override - public final @Nullable BlockTag getBlockTagByName(@NotNull String name) { + public final @Nullable BlockTag getBlockTagByName(String name) { return this.tags.get(NamespacedKey.fromString(name)); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java index d99a6758..598d16c6 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java @@ -10,12 +10,13 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import org.jetbrains.annotations.NotNull; import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.util.ChunkCacheKey; import net.imprex.orebfuscator.Orebfuscator; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * This class works similar to a bounded buffer for cache read and write requests but also functions as the only @@ -26,6 +27,7 @@ * @see Bound buffer * @see Memory ordering */ +@NullMarked public class AsyncChunkSerializer implements Runnable { private final Lock lock = new ReentrantLock(true); @@ -52,8 +54,7 @@ public AsyncChunkSerializer(Orebfuscator orebfuscator, AbstractRegionFileCache read(@NotNull ChunkCacheKey key) { + public CompletableFuture read(ChunkCacheKey key) { this.lock.lock(); try { Runnable task = this.tasks.get(key); @@ -71,7 +72,7 @@ public CompletableFuture read(@NotNull ChunkCacheKey key) { } } - public void write(@NotNull ChunkCacheKey key, @NotNull CacheChunkEntry chunk) { + public void write(ChunkCacheKey key, CacheChunkEntry chunk) { this.lock.lock(); try { Runnable prevTask = this.queueTask(key, new WriteTask(key, chunk)); @@ -83,8 +84,7 @@ public void write(@NotNull ChunkCacheKey key, @NotNull CacheChunkEntry chunk) { } } - @NotNull - private Runnable queueTask(@NotNull ChunkCacheKey key, @NotNull Runnable nextTask) { + private @Nullable Runnable queueTask(ChunkCacheKey key, Runnable nextTask) { while (this.positions.size() >= this.maxTaskQueueSize) { this.notFull.awaitUninterruptibly(); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java index 3e8c77ff..872c675a 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java @@ -1,27 +1,19 @@ package net.imprex.orebfuscator.cache; +import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; +import dev.imprex.orebfuscator.util.ChunkCacheKey; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; -import dev.imprex.orebfuscator.util.ChunkCacheKey; - -public class ChunkSerializer { +@NullMarked +public record ChunkSerializer(AbstractRegionFileCache regionFileCache) { private static final int CACHE_VERSION = 2; - private final AbstractRegionFileCache regionFileCache; - - public ChunkSerializer(AbstractRegionFileCache regionFileCache) { - this.regionFileCache = regionFileCache; - } - - @Nullable - public CacheChunkEntry read(@NotNull ChunkCacheKey key) throws IOException { + public @Nullable CacheChunkEntry read(ChunkCacheKey key) throws IOException { try (DataInputStream dataInputStream = this.regionFileCache.createInputStream(key)) { if (dataInputStream != null) { // check if cache entry has right version and if chunk is present @@ -41,7 +33,7 @@ public CacheChunkEntry read(@NotNull ChunkCacheKey key) throws IOException { return null; } - public void write(@NotNull ChunkCacheKey key, @Nullable CacheChunkEntry value) throws IOException { + public void write(ChunkCacheKey key, @Nullable CacheChunkEntry value) throws IOException { try (DataOutputStream dataOutputStream = this.regionFileCache.createOutputStream(key)) { dataOutputStream.writeInt(CACHE_VERSION); @@ -58,5 +50,4 @@ public void write(@NotNull ChunkCacheKey key, @Nullable CacheChunkEntry value) t throw new IOException("Unable to write chunk: " + key, e); } } - } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java index c88d9a2e..1ca233a3 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.cache; +import dev.imprex.orebfuscator.logging.OfcLogger; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import org.jetbrains.annotations.NotNull; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; @@ -18,51 +18,53 @@ import net.imprex.orebfuscator.OrebfuscatorStatistics; import net.imprex.orebfuscator.obfuscation.ObfuscationRequest; import net.imprex.orebfuscator.obfuscation.ObfuscationResult; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class ObfuscationCache { - private final CacheConfig cacheConfig; private final OrebfuscatorStatistics statistics; private final AbstractRegionFileCache regionFileCache; private final Cache cache; - private final AsyncChunkSerializer serializer; + private final @Nullable AsyncChunkSerializer serializer; public ObfuscationCache(Orebfuscator orebfuscator) { - this.cacheConfig = orebfuscator.getOrebfuscatorConfig().cache(); + CacheConfig cacheConfig = orebfuscator.getOrebfuscatorConfig().cache(); this.statistics = orebfuscator.getStatistics(); this.cache = CacheBuilder.newBuilder() - .maximumSize(this.cacheConfig.maximumSize()) - .expireAfterAccess(this.cacheConfig.expireAfterAccess(), TimeUnit.MILLISECONDS) + .maximumSize(cacheConfig.maximumSize()) + .expireAfterAccess(cacheConfig.expireAfterAccess(), TimeUnit.MILLISECONDS) .removalListener(this::onRemoval) .build(); - this.statistics.setMemoryCacheSizeSupplier(() -> this.cache.size()); + this.statistics.setMemoryCacheSizeSupplier(this.cache::size); this.regionFileCache = OrebfuscatorNms.createRegionFileCache(orebfuscator.getOrebfuscatorConfig()); - if (this.cacheConfig.enableDiskCache()) { + if (cacheConfig.enableDiskCache()) { this.serializer = new AsyncChunkSerializer(orebfuscator, regionFileCache); } else { this.serializer = null; } - if (this.cacheConfig.enabled() && this.cacheConfig.deleteRegionFilesAfterAccess() > 0) { + if (cacheConfig.enabled() && cacheConfig.deleteRegionFilesAfterAccess() > 0) { OrebfuscatorCompatibility.runAsyncAtFixedRate(new CacheFileCleanupTask(orebfuscator, regionFileCache), 0, 72000L); } } - private void onRemoval(@NotNull RemovalNotification notification) { + private void onRemoval(RemovalNotification notification) { this.statistics.onCacheSizeChange(-notification.getValue().estimatedSize()); // don't serialize invalidated chunks since this would require locking the main // thread and wouldn't bring a huge improvement - if (this.cacheConfig.enableDiskCache() && notification.wasEvicted() && !OrebfuscatorCompatibility.isGameThread()) { + if (this.serializer != null && notification.wasEvicted() && !OrebfuscatorCompatibility.isGameThread()) { this.serializer.write(notification.getKey(), notification.getValue()); } } - private void requestObfuscation(@NotNull ObfuscationRequest request) { + private void requestObfuscation(ObfuscationRequest request) { request.submitForObfuscation().thenAccept(chunk -> { var compressedChunk = CacheChunkEntry.create(chunk); if (compressedChunk != null) { @@ -72,8 +74,7 @@ private void requestObfuscation(@NotNull ObfuscationRequest request) { }); } - @NotNull - public CompletableFuture get(@NotNull ObfuscationRequest request) { + public CompletableFuture get(ObfuscationRequest request) { ChunkCacheKey key = request.getCacheKey(); CacheChunkEntry cacheChunk = this.cache.getIfPresent(key); @@ -86,7 +87,7 @@ public CompletableFuture get(@NotNull ObfuscationRequest requ () -> this.requestObfuscation(request)); } // only access disk cache if we couldn't find the chunk in memory cache - else if (cacheChunk == null && this.cacheConfig.enableDiskCache()) { + else if (cacheChunk == null && this.serializer != null) { this.serializer.read(key).whenComplete((diskChunk, throwable) -> { if (diskChunk != null && diskChunk.isValid(request)) { this.statistics.onCacheHitDisk(); @@ -106,10 +107,10 @@ else if (cacheChunk == null && this.cacheConfig.enableDiskCache()) { this.requestObfuscation(request); } - // request future doesn't care about serialzer failure because + // request future doesn't care about serializer failure because // we simply request obfuscation on failure if (throwable != null) { - throwable.printStackTrace(); + OfcLogger.error(throwable); } }); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java index 872cf1c0..af1f972e 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java @@ -1,28 +1,28 @@ package net.imprex.orebfuscator.iterop; import java.util.Objects; +import java.util.logging.Level; import java.util.logging.Logger; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import dev.imprex.orebfuscator.logging.LogLevel; import dev.imprex.orebfuscator.logging.LoggerAccessor; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; -public class BukkitLoggerAccessor implements LoggerAccessor { +@NullMarked +public record BukkitLoggerAccessor(Logger logger) implements LoggerAccessor { - private final Logger logger; - - public BukkitLoggerAccessor(@NotNull Logger logger) { - this.logger = Objects.requireNonNull(logger, "Plugin logger can't be null"); + public BukkitLoggerAccessor { + Objects.requireNonNull(logger, "Plugin logger can't be null"); } @Override - public void log(@NotNull LogLevel level, @NotNull String message, @Nullable Throwable throwable) { + public void log(LogLevel level, String message, @Nullable Throwable throwable) { var mappedLevel = switch (level) { - case DEBUG, INFO -> java.util.logging.Level.INFO; - case WARN -> java.util.logging.Level.WARNING; - case ERROR -> java.util.logging.Level.SEVERE; + case DEBUG, INFO -> Level.INFO; + case WARN -> Level.WARNING; + case ERROR -> Level.SEVERE; }; if (level == LogLevel.DEBUG) { From 0bda60926911b1d2e52d07175fa729b5f80514bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Mon, 15 Dec 2025 17:56:03 +0100 Subject: [PATCH 02/14] feat: wip - migrate obfuscation/cache/proximity to core --- orebfuscator-core/pom.xml | 6 +- .../cache/AsyncChunkSerializer.java | 180 +++++++++++++++ .../cache/CacheFileCleanupTask.java | 61 +++++ .../orebfuscator/cache/CacheRequest.java | 24 ++ .../orebfuscator/cache/CacheResponse.java | 22 ++ .../orebfuscator/cache/ChunkCacheEntry.java | 93 ++++++++ .../cache/ChunkCacheException.java | 12 + .../orebfuscator/cache/ChunkSerializer.java | 56 +++++ .../orebfuscator/cache/ObfuscationCache.java | 160 +++++++++++++ .../dev/imprex/orebfuscator/chunk/Chunk.java | 8 +- .../orebfuscator/chunk/ChunkFactory.java | 6 +- .../config/OrebfuscatorConfig.java | 8 +- .../config/api/WorldConfigBundle.java | 5 +- .../orebfuscator/interop/ChunkAccessor.java | 12 + .../interop/ChunkPacketAccessor.java | 9 +- .../interop/OrebfuscatorCore.java | 30 +++ .../orebfuscator/interop/PlayerAccessor.java | 29 +++ .../interop/RegistryAccessor.java | 6 +- .../orebfuscator/interop/ServerAccessor.java | 9 +- .../orebfuscator/interop/WorldAccessor.java | 17 ++ .../obfuscation/DeobfuscationWorker.java | 140 +++++++++++ .../obfuscation/ObfuscationPipeline.java | 156 +++++++++++++ .../obfuscation/ObfuscationProcessor.java | 217 ++++++++++++++++++ .../obfuscation/ObfuscationRequest.java | 41 ++++ .../obfuscation/ObfuscationResponse.java | 18 ++ .../player/OrebfuscatorPlayer.java | 124 ++++++++++ .../player/OrebfuscatorPlayerChunk.java | 114 +++++++++ .../orebfuscator/player/ProximityBlock.java | 7 + .../orebfuscator/proximity/FastGazeUtil.java | 95 ++++++++ .../proximity/ProximityDirectorThread.java | 170 ++++++++++++++ .../proximity/ProximityWorker.java | 173 ++++++++++++++ .../proximity/ProximityWorkerThread.java | 40 ++++ .../statistics/CacheStatistics.java | 90 ++++++++ .../statistics/InjectorStatistics.java | 58 +++++ .../statistics/ObfuscationStatistics.java | 81 +++++++ .../statistics/OrebfuscatorStatistics.java | 19 ++ .../statistics/StatisticsRegistry.java | 64 ++++++ .../statistics/StatisticsSource.java | 42 ++++ .../util/BlockStateProperties.java | 12 + .../orebfuscator/util/ChunkCacheKey.java | 7 +- .../orebfuscator/util/ChunkDirection.java | 23 ++ .../imprex/orebfuscator/util/EntityPose.java | 29 +++ .../imprex/orebfuscator/util/MathUtil.java | 5 + .../orebfuscator/util/RollingAverage.java | 101 ++++++++ .../orebfuscator/util/RollingTimer.java | 35 +++ .../imprex/orebfuscator/util/SimpleCache.java | 1 + .../orebfuscator/util/WeightedRandom.java | 30 ++- .../util/concurrent/OrebfuscatorExecutor.java | 89 +++++++ .../util/concurrent/OrebfuscatorThread.java | 31 +++ .../orebfuscator/util/WeightedRandomTest.java | 2 +- pom.xml | 4 + 51 files changed, 2743 insertions(+), 28 deletions(-) create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheRequest.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheException.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationResponse.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingAverage.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorExecutor.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorThread.java diff --git a/orebfuscator-core/pom.xml b/orebfuscator-core/pom.xml index 9afa7bfa..2701bc00 100644 --- a/orebfuscator-core/pom.xml +++ b/orebfuscator-core/pom.xml @@ -53,12 +53,12 @@ ${dependency.joml.version} provided - + provided + diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java new file mode 100644 index 00000000..e4d04360 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java @@ -0,0 +1,180 @@ +package dev.imprex.orebfuscator.cache; + +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.util.ChunkCacheKey; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * This class works similar to a bounded buffer for cache read and write requests but also functions as the only + * consumer of said buffer. All requests can get reorder similar to modern memory access reordering in CPUs. If for + * example a write request is already in the buffer and a new read request for the same position is created then the + * read request doesn't get put in the buffer and gets completed with the content of the write request. + * + * @see Bound buffer + * @see Memory ordering + */ +// TODO: add statistice for read/write times and ratio of read/write as well as average throughput for read/write +@NullMarked +public class AsyncChunkSerializer implements Runnable { + + private final Lock lock = new ReentrantLock(true); + private final Condition notFull = lock.newCondition(); + private final Condition notEmpty = lock.newCondition(); + + private final Map tasks = new HashMap<>(); + private final Queue positions = new LinkedList<>(); + + private final int maxTaskQueueSize; + private final ChunkSerializer serializer; + + private final Thread thread; + private volatile boolean running = true; + + public AsyncChunkSerializer(OrebfuscatorCore orebfuscator, AbstractRegionFileCache regionFileCache) { + this.maxTaskQueueSize = orebfuscator.config().cache().maximumTaskQueueSize(); + this.serializer = new ChunkSerializer(regionFileCache); + + this.thread = new Thread(OrebfuscatorCore.THREAD_GROUP, this, "ofc-chunk-serializer"); + this.thread.setDaemon(true); + this.thread.start(); + + orebfuscator.statistics().cache.setDiskCacheQueueLength(this.tasks::size); + } + + public CompletableFuture<@Nullable ChunkCacheEntry> read(ChunkCacheKey key) { + this.lock.lock(); + try { + Runnable task = this.tasks.get(key); + if (task instanceof WriteTask) { + return CompletableFuture.completedFuture(((WriteTask) task).chunk); + } else if (task instanceof ReadTask) { + return ((ReadTask) task).future; + } else { + CompletableFuture future = new CompletableFuture<>(); + this.queueTask(key, new ReadTask(key, future)); + return future; + } + } finally { + this.lock.unlock(); + } + } + + public void write(ChunkCacheKey key, ChunkCacheEntry chunk) { + this.lock.lock(); + try { + Runnable prevTask = this.queueTask(key, new WriteTask(key, chunk)); + if (prevTask instanceof ReadTask) { + ((ReadTask) prevTask).future.complete(chunk); + } + } finally { + this.lock.unlock(); + } + } + + @Nullable + private Runnable queueTask(ChunkCacheKey key, Runnable nextTask) { + while (this.positions.size() >= this.maxTaskQueueSize) { + this.notFull.awaitUninterruptibly(); + } + + if (!this.running) { + throw new IllegalStateException("AsyncChunkSerializer already closed"); + } + + Runnable prevTask = this.tasks.put(key, nextTask); + if (prevTask == null) { + this.positions.offer(key); + } + + this.notEmpty.signal(); + return prevTask; + } + + @Override + public void run() { + while (this.running) { + this.lock.lock(); + try { + while (this.positions.isEmpty()) { + this.notEmpty.await(); + } + + this.tasks.remove(this.positions.poll()).run(); + + this.notFull.signal(); + } catch (InterruptedException e) { + break; + } finally { + this.lock.unlock(); + } + } + } + + public void close() { + this.lock.lock(); + try { + this.running = false; + this.thread.interrupt(); + + while (!this.positions.isEmpty()) { + Runnable task = this.tasks.remove(this.positions.poll()); + if (task instanceof WriteTask) { + task.run(); + } + } + } finally { + this.lock.unlock(); + } + } + + private class WriteTask implements Runnable { + + private final ChunkCacheKey key; + private final ChunkCacheEntry chunk; + + public WriteTask(ChunkCacheKey key, ChunkCacheEntry chunk) { + this.key = key; + this.chunk = chunk; + } + + @Override + public void run() { + try { + serializer.write(key, chunk); + } catch (IOException e) { + OfcLogger.error(e); + } + } + } + + private class ReadTask implements Runnable { + + private final ChunkCacheKey key; + private final CompletableFuture<@Nullable ChunkCacheEntry> future; + + public ReadTask(ChunkCacheKey key, CompletableFuture<@Nullable ChunkCacheEntry> future) { + this.key = key; + this.future = future; + } + + @Override + public void run() { + try { + future.complete(serializer.read(key)); + } catch (Exception e) { + future.completeExceptionally(e); + } + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java new file mode 100644 index 00000000..e61324ec --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java @@ -0,0 +1,61 @@ +package dev.imprex.orebfuscator.cache; + +import dev.imprex.orebfuscator.config.api.CacheConfig; +import dev.imprex.orebfuscator.config.api.Config; +import dev.imprex.orebfuscator.logging.OfcLogger; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class CacheFileCleanupTask implements Runnable { + + private final CacheConfig cacheConfig; + private final AbstractRegionFileCache regionFileCache; + + private int deleteCount = 0; + + public CacheFileCleanupTask(Config config, AbstractRegionFileCache regionFileCache) { + this.cacheConfig = config.cache(); + this.regionFileCache = regionFileCache; + } + + @Override + public void run() { + if (Files.notExists(this.cacheConfig.baseDirectory())) { + OfcLogger.debug("Skipping CacheFileCleanupTask as the cache directory doesn't exist."); + return; + } + + long deleteAfterMillis = this.cacheConfig.deleteRegionFilesAfterAccess(); + + this.deleteCount = 0; + + try { + Files.walkFileTree(this.cacheConfig.baseDirectory(), new SimpleFileVisitor<>() { + + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) throws IOException { + if (System.currentTimeMillis() - attributes.lastAccessTime().toMillis() > deleteAfterMillis) { + regionFileCache.close(path); + Files.delete(path); + + CacheFileCleanupTask.this.deleteCount++; + OfcLogger.debug("deleted cache file: " + path); + } + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + OfcLogger.error(e); + } + + if (this.deleteCount > 0) { + OfcLogger.info(String.format("CacheFileCleanupTask successfully deleted %d cache file(s)", this.deleteCount)); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheRequest.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheRequest.java new file mode 100644 index 00000000..bbaf234e --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheRequest.java @@ -0,0 +1,24 @@ +package dev.imprex.orebfuscator.cache; + +import java.util.Objects; +import org.jspecify.annotations.NullMarked; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; +import dev.imprex.orebfuscator.util.ChunkCacheKey; + +@NullMarked +public record CacheRequest(ChunkCacheKey cacheKey, byte[] hash) { + + public static final HashFunction HASH_FUNCTION = Hashing.murmur3_128(); + public static final int HASH_LENGTH = HASH_FUNCTION.bits() / Byte.SIZE; + + public CacheRequest { + Objects.requireNonNull(cacheKey); + Objects.requireNonNull(hash); + } + + @Override + public String toString() { + return "CacheRequest [cacheKey=" + cacheKey + "]"; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java new file mode 100644 index 00000000..42b76b3c --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java @@ -0,0 +1,22 @@ +package dev.imprex.orebfuscator.cache; + +import java.util.Objects; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public sealed interface CacheResponse permits CacheResponse.Success, CacheResponse.Failure { + + public static CacheResponse success(ChunkCacheEntry entry) { + return new Success(entry); + } + + record Success(ChunkCacheEntry entry) implements CacheResponse { + public Success { + Objects.requireNonNull(entry, "entry"); + } + } + + enum Failure implements CacheResponse { + NOT_FOUND, MEMORY_INVALID, DISK_INVALID; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java new file mode 100644 index 00000000..aff14940 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java @@ -0,0 +1,93 @@ +package dev.imprex.orebfuscator.cache; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import org.jspecify.annotations.NullMarked; +import dev.imprex.orebfuscator.obfuscation.ObfuscationResponse; +import dev.imprex.orebfuscator.player.ProximityBlock; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.ChunkCacheKey; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; + +@NullMarked +public record ChunkCacheEntry(ChunkCacheKey key, byte[] compressedData) { + + public static ChunkCacheEntry create(CacheRequest request, ObfuscationResponse response) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + // TODO: move BAOS and return into try block + + try (LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(byteArrayOutputStream); + DataOutputStream dataOutputStream = new DataOutputStream(lz4BlockOutputStream)) { + + byteArrayOutputStream.write(request.hash()); + + byte[] data = response.data(); + dataOutputStream.writeInt(data.length); + dataOutputStream.write(data, 0, data.length); + + Collection proximityBlocks = response.proximityBlocks(); + dataOutputStream.writeInt(proximityBlocks.size()); + for (ProximityBlock blockPosition : proximityBlocks) { + dataOutputStream.writeInt(blockPosition.blockPos().toSectionPos()); + // TODO save as byte: flags + dataOutputStream.writeBoolean(blockPosition.lavaObfuscated()); + } + + Collection blockEntities = response.blockEntities(); + dataOutputStream.writeInt(blockEntities.size()); + for (BlockPos blockPosition : blockEntities) { + dataOutputStream.writeInt(blockPosition.toSectionPos()); + } + } catch (Exception e) { + throw new ChunkCacheException("Unable to compress chunk: " + request.cacheKey(), e); + } + + return new ChunkCacheEntry(request.cacheKey(), byteArrayOutputStream.toByteArray()); + } + + public int estimatedSize() { + return 64 + key.world().length() + compressedData.length; + } + + public boolean isValid(CacheRequest request) { + return Arrays.equals(compressedData, 0, CacheRequest.HASH_LENGTH, request.hash(), 0, CacheRequest.HASH_LENGTH); + } + + public ObfuscationResponse toResult() { + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(compressedData); + LZ4BlockInputStream lz4BlockInputStream = new LZ4BlockInputStream(byteArrayInputStream); + DataInputStream dataInputStream = new DataInputStream(lz4BlockInputStream)) { + + byteArrayInputStream.skip(CacheRequest.HASH_LENGTH); + + byte[] data = new byte[dataInputStream.readInt()]; + dataInputStream.readFully(data); + + int x = key.x() << 4; + int z = key.z() << 4; + + var proximityBlocks = new ArrayList(); + for (int i = dataInputStream.readInt(); i > 0; i--) { + var blockPos = BlockPos.fromSectionPos(x, z, dataInputStream.readInt()); + var lavaObfuscated = dataInputStream.readBoolean(); + proximityBlocks.add(new ProximityBlock(blockPos, lavaObfuscated)); + } + + var blockEntities = new HashSet(); + for (int i = dataInputStream.readInt(); i > 0; i--) { + blockEntities.add(BlockPos.fromSectionPos(x, z, dataInputStream.readInt())); + } + + return new ObfuscationResponse(data, blockEntities, proximityBlocks); + } catch (Exception e) { + throw new ChunkCacheException("Unable to decompress chunk: " + key, e); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheException.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheException.java new file mode 100644 index 00000000..ba67bb4c --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheException.java @@ -0,0 +1,12 @@ +package dev.imprex.orebfuscator.cache; + +public class ChunkCacheException extends RuntimeException { + + public ChunkCacheException(String message) { + super(message); + } + + public ChunkCacheException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java new file mode 100644 index 00000000..602ab6c4 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java @@ -0,0 +1,56 @@ +package dev.imprex.orebfuscator.cache; + +import dev.imprex.orebfuscator.util.ChunkCacheKey; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +public class ChunkSerializer { + + private static final int CACHE_VERSION = 3; + + private final AbstractRegionFileCache regionFileCache; + + public ChunkSerializer(AbstractRegionFileCache regionFileCache) { + this.regionFileCache = regionFileCache; + } + + @Nullable + public ChunkCacheEntry read(ChunkCacheKey key) throws IOException { + try (DataInputStream dataInputStream = this.regionFileCache.createInputStream(key)) { + // check if cache entry has right version and if chunk is present + if (dataInputStream == null || dataInputStream.readInt() != CACHE_VERSION || !dataInputStream.readBoolean()) { + return null; + } + + byte[] compressedData = new byte[dataInputStream.readInt()]; + dataInputStream.readFully(compressedData); + + return new ChunkCacheEntry(key, compressedData); + } catch (IOException e) { + throw new IOException("Unable to read chunk: " + key, e); + } + } + + public void write(ChunkCacheKey key, @Nullable ChunkCacheEntry value) throws IOException { + try (DataOutputStream dataOutputStream = this.regionFileCache.createOutputStream(key)) { + dataOutputStream.writeInt(CACHE_VERSION); + // TODO: merge present boolean (and future flags) into the int32 version field wher int16 for version and int16 for flags + + if (value != null) { + dataOutputStream.writeBoolean(true); + + byte[] compressedData = value.compressedData(); + dataOutputStream.writeInt(compressedData.length); + dataOutputStream.write(compressedData); + } else { + dataOutputStream.writeBoolean(false); + } + } catch (IOException e) { + throw new IOException("Unable to write chunk: " + key, e); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java new file mode 100644 index 00000000..187a57dc --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java @@ -0,0 +1,160 @@ +package dev.imprex.orebfuscator.cache; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalNotification; +import dev.imprex.orebfuscator.config.api.CacheConfig; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.obfuscation.ObfuscationResponse; +import dev.imprex.orebfuscator.statistics.CacheStatistics; +import dev.imprex.orebfuscator.util.ChunkCacheKey; +import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorExecutor; + +@NullMarked +public class ObfuscationCache { + + private final OrebfuscatorCore orebfuscator; + private final CacheConfig cacheConfig; + private final CacheStatistics statistics; + private final OrebfuscatorExecutor executor; + + private final AbstractRegionFileCache regionFileCache; + private final Cache cache; + private final @Nullable AsyncChunkSerializer serializer; + + public ObfuscationCache(OrebfuscatorCore orebfuscator) { + this.orebfuscator = orebfuscator; + this.cacheConfig = orebfuscator.config().cache(); + this.statistics = orebfuscator.statistics().cache; + this.executor = orebfuscator.executor(); + + this.cache = CacheBuilder.newBuilder() + .maximumSize(this.cacheConfig.maximumSize()) + .expireAfterAccess(this.cacheConfig.expireAfterAccess(), TimeUnit.MILLISECONDS) + .removalListener(this::onRemoval) + .build(); + this.statistics.setMemoryCacheEntryCount(this.cache::size); + + this.regionFileCache = orebfuscator.createRegionFileCache(); + + if (this.cacheConfig.enableDiskCache()) { + this.serializer = new AsyncChunkSerializer(orebfuscator, regionFileCache); + } else { + this.serializer = null; + } + + if (this.cacheConfig.enabled() && this.cacheConfig.deleteRegionFilesAfterAccess() > 0) { + // TODO: OrebfuscatorCompatibility.runAsyncAtFixedRate(new CacheFileCleanupTask(orebfuscator, + // regionFileCache), 0, 72000L); + } + } + + private void onRemoval(RemovalNotification notification) { + assert notification.getValue() != null; + this.statistics.onCacheSizeChange(-notification.getValue().estimatedSize()); + + // don't serialize invalidated chunks since this would require locking the main + // thread and wouldn't bring a huge improvement + if (this.serializer != null && notification.wasEvicted() && !orebfuscator.isGameThread()) { + assert notification.getKey() != null; + this.serializer.write(notification.getKey(), notification.getValue()); + } + } + + public CompletionStage> get(CacheRequest request) { + return probeCaches(request).thenApplyAsync(response -> { + if (response instanceof CacheResponse.Success success) { + return Optional.of(success.entry().toResult()); + } else { + this.statistics.onCacheMiss(); + return Optional.empty(); + } + }, this.executor).exceptionallyAsync(throwable -> { + OfcLogger.error("An error occurred while trying to get cache entry for request: %s".formatted(request), + throwable); + return Optional.empty(); + }, this.executor); + } + + private CompletionStage probeCaches(CacheRequest request) { + var future = CompletableFuture.supplyAsync(() -> probeMemory(request), this.executor); + + if (this.serializer != null) { + future = future.thenComposeAsync(response -> + // only access disk cache if we couldn't find an entry in memory cache + response == CacheResponse.Failure.NOT_FOUND + ? this.probeDisk(request) + : CompletableFuture.completedStage(response) + , this.executor); + } + + return future; + } + + private CacheResponse probeMemory(CacheRequest request) { + ChunkCacheEntry cacheEntry = this.cache.getIfPresent(request.cacheKey()); + + if (cacheEntry == null) { + return CacheResponse.Failure.NOT_FOUND; + } else if (!cacheEntry.isValid(request)) { + // invalidate invalid in-memory cache entries + this.cache.invalidate(request.cacheKey()); + return CacheResponse.Failure.MEMORY_INVALID; + } + + this.statistics.onCacheHitMemory(); + return CacheResponse.success(cacheEntry); + } + + private CompletionStage probeDisk(CacheRequest request) { + return this.serializer.read(request.cacheKey()).thenApplyAsync(cacheEntry -> { + if (cacheEntry == null) { + return CacheResponse.Failure.NOT_FOUND; + } else if (!cacheEntry.isValid(request)) { + return CacheResponse.Failure.DISK_INVALID; + } + + // add valid disk cache entry to in-memory cache + this.cache.put(request.cacheKey(), cacheEntry); + this.statistics.onCacheSizeChange(cacheEntry.estimatedSize()); + + this.statistics.onCacheHitDisk(); + return CacheResponse.success(cacheEntry); + }, this.executor); + } + + public void add(CacheRequest request, ObfuscationResponse response) { + try { + var entry = ChunkCacheEntry.create(request, response); + this.cache.put(request.cacheKey(), entry); + this.statistics.onCacheSizeChange(entry.estimatedSize()); + } catch (Exception e) { + OfcLogger.error("An error occurred while trying to cache entry for request: %s".formatted(request), e); + } + } + + public void invalidate(ChunkCacheKey key) { + this.cache.invalidate(key); + } + + public void close() { + if (this.serializer != null) { + // flush memory cache to disk on shutdown + this.cache.asMap().entrySet().removeIf(entry -> { + this.serializer.write(entry.getKey(), entry.getValue()); + return true; + }); + + this.serializer.close(); + } + + this.regionFileCache.clear(); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java index 3c908454..8467422e 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.chunk; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import java.util.Arrays; import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; import dev.imprex.orebfuscator.interop.WorldAccessor; @@ -20,13 +21,14 @@ public class Chunk implements AutoCloseable { private final ByteBuf inputBuffer; private final ByteBuf outputBuffer; - Chunk(ChunkFactory factory, ChunkPacketAccessor packet) { + Chunk(ChunkFactory factory, ObfuscationRequest request) { this.factory = factory; + final var packet = request.packet(); this.chunkX = packet.chunkX(); this.chunkZ = packet.chunkZ(); - this.worldAccessor = packet.world(); + this.worldAccessor = request.world(); this.sections = new ChunkSectionHolder[this.worldAccessor.getSectionCount()]; byte[] data = packet.data(); @@ -83,7 +85,7 @@ public byte[] finalizeOutput() { } @Override - public void close() throws Exception { + public void close() { this.inputBuffer.release(); this.outputBuffer.release(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java index 8581780b..c0fd0300 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java @@ -1,8 +1,8 @@ package dev.imprex.orebfuscator.chunk; -import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; import dev.imprex.orebfuscator.interop.RegistryAccessor; import dev.imprex.orebfuscator.interop.ServerAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; public class ChunkFactory { @@ -22,7 +22,7 @@ ChunkVersionFlags versionFlags() { return versionFlags; } - public Chunk fromPacket(ChunkPacketAccessor packet) { - return new Chunk(this, packet); + public Chunk fromPacket(ObfuscationRequest request) { + return new Chunk(this, request); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java index a44aad63..45fff1a0 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java @@ -438,15 +438,15 @@ public boolean shouldObfuscate(int y) { } @Override - public int nextRandomObfuscationBlock(int y) { + public int nextRandomObfuscationBlock(RandomGenerator random, int y) { return this.obfuscationRandoms != null - ? this.obfuscationRandoms[y - this.world.getMinBuildHeight()].next() : 0; + ? this.obfuscationRandoms[y - this.world.getMinBuildHeight()].next(random) : 0; } @Override - public int nextRandomProximityBlock(int y) { + public int nextRandomProximityBlock(RandomGenerator random, int y) { return this.proximityRandoms != null - ? this.proximityRandoms[y - this.world.getMinBuildHeight()].next() : 0; + ? this.proximityRandoms[y - this.world.getMinBuildHeight()].next(random) : 0; } } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java index 85603f68..48340427 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/WorldConfigBundle.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.config.api; +import java.util.random.RandomGenerator; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -20,7 +21,7 @@ public interface WorldConfigBundle { boolean shouldObfuscate(int y); - int nextRandomObfuscationBlock(int y); + int nextRandomObfuscationBlock(RandomGenerator random, int y); - int nextRandomProximityBlock(int y); + int nextRandomProximityBlock(RandomGenerator random, int y); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java new file mode 100644 index 00000000..730260ec --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java @@ -0,0 +1,12 @@ +package dev.imprex.orebfuscator.interop; + +public interface ChunkAccessor { + + ChunkAccessor EMPTY = (x, y, z) -> 0; + + static long chunkCoordsToLong(int chunkX, int chunkZ) { + return (chunkZ & 0xffffffffL) << 32 | chunkX & 0xffffffffL; + } + + int getBlockState(int x, int y, int z); +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java index e77b8533..8a43447d 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java @@ -1,12 +1,10 @@ package dev.imprex.orebfuscator.interop; -import java.util.function.Predicate; -import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.obfuscation.ObfuscationResponse; +// TODO: nullability public interface ChunkPacketAccessor { - WorldAccessor world(); - int chunkX(); int chunkZ(); @@ -15,7 +13,6 @@ public interface ChunkPacketAccessor { byte[] data(); - void setData(byte[] data); + void update(ObfuscationResponse response); - void filterBlockEntities(Predicate predicate); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java new file mode 100644 index 00000000..4895ec84 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java @@ -0,0 +1,30 @@ +package dev.imprex.orebfuscator.interop; + +import dev.imprex.orebfuscator.cache.ObfuscationCache; +import dev.imprex.orebfuscator.chunk.ChunkFactory; +import dev.imprex.orebfuscator.config.OrebfuscatorConfig; +import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; +import dev.imprex.orebfuscator.obfuscation.ObfuscationProcessor; +import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics; +import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorExecutor; + +// TODO: nullability +public interface OrebfuscatorCore extends ServerAccessor { + + ThreadGroup THREAD_GROUP = new ThreadGroup("orebfuscator"); + + OrebfuscatorExecutor executor(); + + OrebfuscatorStatistics statistics(); + + OrebfuscatorConfig config(); + + ChunkFactory chunkFactory(); + + ObfuscationCache cache(); + + ObfuscationPipeline obfuscationPipeline(); + + ObfuscationProcessor obfuscationProcessor(); + +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java new file mode 100644 index 00000000..a97e0bcd --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java @@ -0,0 +1,29 @@ +package dev.imprex.orebfuscator.interop; + +import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.EntityPose; + +// TODO: nullability +public interface PlayerAccessor { + + OrebfuscatorPlayer orebfuscatorPlayer(); + + EntityPose pose(); + + EntityPose eyePose(); + + WorldAccessor world(); + + boolean isAlive(); + + boolean isSpectator(); + + double lavaFogDistance(); + + boolean hasPermission(String permission); + + void runForPlayer(Runnable runnable); + + void sendBlockUpdates(Iterable iterable); +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java index 2353cefd..54275308 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java @@ -1,9 +1,9 @@ package dev.imprex.orebfuscator.interop; -import dev.imprex.orebfuscator.util.BlockProperties; -import dev.imprex.orebfuscator.util.BlockTag; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.util.BlockProperties; +import dev.imprex.orebfuscator.util.BlockTag; @NullMarked public interface RegistryAccessor { @@ -14,6 +14,8 @@ public interface RegistryAccessor { boolean isAir(int blockId); + boolean isLava(int blockId); + boolean isOccluding(int blockId); boolean isBlockEntity(int blockId); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java index c10e72b4..b244b9b8 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java @@ -2,20 +2,27 @@ import java.nio.file.Path; import java.util.List; +import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; import dev.imprex.orebfuscator.util.Version; +// TODO: nullability public interface ServerAccessor { + boolean isGameThread(); + Path getConfigDirectory(); Path getWorldDirectory(); - String getOrebfuscatorVersion(); + Version getOrebfuscatorVersion(); Version getMinecraftVersion(); RegistryAccessor getRegistry(); + AbstractRegionFileCache createRegionFileCache(); + List getWorlds(); + List getPlayers(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java index 9661af57..a7f2adbd 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java @@ -1,5 +1,11 @@ package dev.imprex.orebfuscator.interop; +import java.util.concurrent.CompletableFuture; +import dev.imprex.orebfuscator.config.api.WorldConfigBundle; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; +import dev.imprex.orebfuscator.util.BlockPos; + +// TODO: nullability public interface WorldAccessor { String getName(); @@ -17,4 +23,15 @@ public interface WorldAccessor { int getMaxSection(); int getSectionIndex(int y); + + WorldConfigBundle config(); + + CompletableFuture getNeighboringChunks(ObfuscationRequest request); + + ChunkAccessor getChunk(int chunkX, int chunkZ); + + @Deprecated + int getBlockState(int x, int y, int z); + + void sendBlockUpdates(Iterable iterable); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java new file mode 100644 index 00000000..32ecdd4b --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java @@ -0,0 +1,140 @@ +package dev.imprex.orebfuscator.obfuscation; + +import java.util.ArrayList; +import java.util.Comparator; +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.jspecify.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import dev.imprex.orebfuscator.cache.ObfuscationCache; +import dev.imprex.orebfuscator.config.OrebfuscatorConfig; +import dev.imprex.orebfuscator.config.api.BlockFlags; +import dev.imprex.orebfuscator.config.api.ObfuscationConfig; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.statistics.ObfuscationStatistics; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.ChunkCacheKey; + +@NullMarked +public class DeobfuscationWorker { + + private static List precomputeOffsets(int radius) { + List> offset = new ArrayList<>(); + + for (int dx = -radius; dx <= radius; dx++) { + for (int dy = -radius; dy <= radius; dy++) { + for (int dz = -radius; dz <= radius; dz++) { + int distance = Math.abs(dx) + Math.abs(dy) + Math.abs(dz); + if (distance <= radius) { + offset.add(Map.entry(new BlockPos(dx, dy, dz), distance)); + } + } + } + } + + offset + .sort(Comparator.comparingInt((Map.Entry e) -> e.getValue()).thenComparing(Entry::getKey)); + + return offset.stream().map(Map.Entry::getKey).toList(); + } + + private final OrebfuscatorConfig config; + private final ObfuscationCache cache; + private final ObfuscationStatistics statistics; + + private final List offsets; + + public DeobfuscationWorker(OrebfuscatorCore orebfuscator) { + this.config = orebfuscator.config(); + this.cache = orebfuscator.cache(); + this.statistics = orebfuscator.statistics().obfuscation; + + this.offsets = precomputeOffsets(orebfuscator.config().general().updateRadius()); + } + + public void deobfuscate(WorldAccessor world, @Nullable BlockPos block) { + Objects.requireNonNull(world); + if (block == null) { + return; + } + + deobfuscate(world, List.of(block)); + } + + public void deobfuscate(WorldAccessor world, @Nullable List blocks) { + Objects.requireNonNull(world); + if (blocks == null || blocks.isEmpty()) { + return; + } + + ObfuscationConfig obfuscationConfig = world.config().obfuscation(); + if (obfuscationConfig == null || !obfuscationConfig.isEnabled()) { + return; + } + + var timer = statistics.debofuscation.start(); + try (var processor = new RecursiveProcessor(world)) { + for (BlockPos position : blocks) { + processor.processPosition(position); + } + } finally { + timer.stop(); + } + } + + // TODO: there is nothing recusive about this, maybe even remove class and do a single method + private class RecursiveProcessor implements AutoCloseable { + + private final Set updatedBlocks = new HashSet<>(); + private final Set invalidChunks = new HashSet<>(); + private final Map chunks = new HashMap<>(); + + private final WorldAccessor world; + private final BlockFlags blockFlags; + + public RecursiveProcessor(WorldAccessor world) { + this.world = world; + this.blockFlags = world.config().blockFlags(); + } + + public void processPosition(BlockPos position) { + Objects.requireNonNull(position); + + for (var offset : offsets) { + updateBlock(position.add(offset)); + } + } + + private void updateBlock(BlockPos position) { + int chunkX = position.x() >> 4; + int chunkZ = position.z() >> 4; + long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); + var chunk = chunks.computeIfAbsent(key, k -> world.getChunk(chunkX, chunkZ)); + if (chunk != null) { + int blockState = chunk.getBlockState(position.x(), position.y(), position.z()); + if (BlockFlags.isObfuscateBitSet(blockFlags.flags(blockState)) && updatedBlocks.add(position)) { + + // invalidate cache if enabled + if (config.cache().enabled()) { + ChunkCacheKey chunkPosition = new ChunkCacheKey(world, position); + if (this.invalidChunks.add(chunkPosition)) { + cache.invalidate(chunkPosition); + } + } + } + } + } + + @Override + public void close() { + world.sendBlockUpdates(this.updatedBlocks); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java new file mode 100644 index 00000000..5abc2872 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java @@ -0,0 +1,156 @@ +package dev.imprex.orebfuscator.obfuscation; + +import java.util.Arrays; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.cache.CacheRequest; +import dev.imprex.orebfuscator.cache.ObfuscationCache; +import dev.imprex.orebfuscator.config.api.AdvancedConfig; +import dev.imprex.orebfuscator.config.api.Config; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics; +import dev.imprex.orebfuscator.util.ChunkCacheKey; +import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorExecutor; + +@NullMarked +public class ObfuscationPipeline { + + private final Config config; + private final ObfuscationCache cache; + private final ObfuscationProcessor processor; + private final OrebfuscatorStatistics statistics; + private final OrebfuscatorExecutor executor; + + public ObfuscationPipeline(OrebfuscatorCore orebfuscator) { + this.config = orebfuscator.config(); + this.cache = orebfuscator.cache(); + this.processor = orebfuscator.obfuscationProcessor(); + this.statistics = orebfuscator.statistics(); + this.executor = orebfuscator.executor(); + } + + public CompletionStage request( + WorldAccessor world, + PlayerAccessor player, + ChunkPacketAccessor packet, + @Nullable ChunkAccessor @Nullable[] neighborChunks) { + var timer = statistics.injector.pipelineDelayTotal.start(); + return timer.wrap(requestInternal(world, player, packet, neighborChunks)); + } + + private CompletionStage requestInternal( + WorldAccessor world, + PlayerAccessor player, + ChunkPacketAccessor packet, + @Nullable ChunkAccessor @Nullable[] neighborChunks) { + + final var request = new ObfuscationRequest(world, player, packet, neighborChunks); + + final var neighborTimer = statistics.injector.pipelineDelayNeighbors.start(); +// final var neighborFuture = neighborTimer.wrap(world.getNeighboringChunks(request)); + + final CacheRequest cacheRequest; + final CompletionStage> cacheFuture; + + if (config.cache().enabled()) { + ChunkCacheKey cacheKey = new ChunkCacheKey(request); + + byte[] hash = CacheRequest.HASH_FUNCTION.newHasher() + .putBytes(config.systemHash()) + .putBytes(request.packet().data()) + .hash() + .asBytes(); + + cacheRequest = new CacheRequest(cacheKey, hash); + + var cacheTimer = statistics.injector.pipelineDelayCache.start(); + cacheFuture = cacheTimer.wrap(this.cache.get(cacheRequest)); + } else { + cacheRequest = null; + cacheFuture = CompletableFuture.completedStage(Optional.empty()); + } + + var future = cacheFuture.thenComposeAsync(optional -> { + if (optional.isPresent()) { + return CompletableFuture.completedStage(optional.get()); + } else { + return neighborTimer.wrap(world.getNeighboringChunks(request)) + .handleAsync((neighbors, throwable) -> { + if (throwable != null) { + OfcLogger.error("Can't get neighboring chunks for (%d, %d)".formatted(packet.chunkX(), packet.chunkZ()), + throwable); + return request; + } else if (neighbors == null) { + return request; + } + + long missingChunks = Arrays.stream(neighbors).filter(n -> n == ChunkAccessor.EMPTY).count(); + statistics.obfuscation.missingNeighboringChunks.add(missingChunks); + + return request.withNeighbors(neighbors); + }, this.executor) + .thenApply(this.processor::process) + .thenApply(response -> { + if (config.cache().enabled() && cacheRequest != null) { + cache.add(cacheRequest, response); + } + return response; + }); + } + }, this.executor); + + AdvancedConfig advancedConfig = config.advanced(); + if (advancedConfig.hasObfuscationTimeout()) { + future = future + .toCompletableFuture() + .orTimeout(advancedConfig.obfuscationTimeout(), TimeUnit.MILLISECONDS); + } + + return future.thenApplyAsync(response -> { + this.postProcess(request, response); + return null; + }, this.executor).exceptionallyAsync(throwable -> { + this.handleExceptions(request, throwable); + return null; + }, this.executor); + } + + private void postProcess(ObfuscationRequest request, ObfuscationResponse response) { + var packet = request.packet(); + + statistics.obfuscation.originalChunkSize.add(packet.data().length); + statistics.obfuscation.obfuscatedChunkSize.add(response.data().length); + + packet.update(response); + + var player = request.player().orebfuscatorPlayer(); + player.addChunk(request.world(), packet.chunkX(), packet.chunkZ(), response.proximityBlocks()); + } + + private void handleExceptions(ObfuscationRequest request, Throwable throwable) { + var packet = request.packet(); + + if (throwable instanceof CompletionException && throwable.getCause() != null) { + throwable = throwable.getCause(); + } + + if (throwable instanceof TimeoutException) { + OfcLogger.warn("Obfuscation for chunk[world=%s, x=%d, z=%d] timed out".formatted(request.world().getName(), + packet.chunkX(), packet.chunkZ())); + } else { + OfcLogger.error("An error occurred while obfuscating chunk[world=%s, x=%d, z=%d]" + .formatted(request.world().getName(), packet.chunkX(), packet.chunkZ()), throwable); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java new file mode 100644 index 00000000..ac7884e2 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java @@ -0,0 +1,217 @@ +package dev.imprex.orebfuscator.obfuscation; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.random.RandomGenerator; +import org.jspecify.annotations.NullMarked; +import dev.imprex.orebfuscator.chunk.Chunk; +import dev.imprex.orebfuscator.chunk.ChunkFactory; +import dev.imprex.orebfuscator.chunk.ChunkSection; +import dev.imprex.orebfuscator.config.ProximityHeightCondition; +import dev.imprex.orebfuscator.config.api.BlockFlags; +import dev.imprex.orebfuscator.config.api.ObfuscationConfig; +import dev.imprex.orebfuscator.config.api.ProximityConfig; +import dev.imprex.orebfuscator.config.api.WorldConfigBundle; +import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.RegistryAccessor; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.player.ProximityBlock; +import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorThread; + +@NullMarked +public class ObfuscationProcessor { + + private static final ThreadLocal STATE = ThreadLocal.withInitial(() -> new State()); + + private final ChunkFactory chunkFactory; + private final RegistryAccessor registryAccessor; + private final OrebfuscatorStatistics statistics; + + public ObfuscationProcessor(OrebfuscatorCore orebfuscator) { + this.chunkFactory = orebfuscator.chunkFactory(); + this.registryAccessor = orebfuscator.getRegistry(); + this.statistics = orebfuscator.statistics(); + } + + public ObfuscationResponse process(ObfuscationRequest request) { + var timer = statistics.injector.pipelineDelayProcessor.start(); + try { + return processInternal(request); + } finally { + timer.stop(); + } + } + + private ObfuscationResponse processInternal(ObfuscationRequest request) { + ChunkPacketAccessor packet = request.packet(); + WorldAccessor worldAccessor = request.world(); + + WorldConfigBundle bundle = worldAccessor.config(); + BlockFlags blockFlags = bundle.blockFlags(); + ObfuscationConfig obfuscationConfig = bundle.obfuscation(); + ProximityConfig proximityConfig = bundle.proximity(); + + var state = STATE.get(); + + Set blockEntities = new HashSet<>(); + List proximityBlocks = new ArrayList<>(); + + RandomGenerator random = ThreadLocalRandom.current(); + if (Thread.currentThread() instanceof OrebfuscatorThread obfuscationThread) { + random = obfuscationThread.random(); + } + + int baseX = packet.chunkX() << 4; + int baseZ = packet.chunkZ() << 4; + + int layerY = Integer.MIN_VALUE; + int layerYBlockState = -1; + + try (Chunk chunk = this.chunkFactory.fromPacket(request)) { + for (int sectionIndex = Math.max(0, bundle.minSectionIndex()); sectionIndex <= Math + .min(chunk.getSectionCount() - 1, bundle.maxSectionIndex()); sectionIndex++) { + ChunkSection chunkSection = chunk.getSection(sectionIndex); + if (chunkSection == null || chunkSection.isEmpty()) { + continue; + } + + final int baseY = worldAccessor.getMinBuildHeight() + (sectionIndex << 4); + for (int index = 0; index < 4096; index++) { + int y = baseY + (index >> 8 & 15); + if (!bundle.shouldObfuscate(y)) { + continue; + } + + int blockState = chunkSection.getBlockState(index); + + int obfuscateBits = blockFlags.flags(blockState, y); + if (BlockFlags.isEmpty(obfuscateBits)) { + continue; + } + + int x = baseX + (index & 15); + int z = baseZ + (index >> 4 & 15); + + boolean isObfuscateBitSet = BlockFlags.isObfuscateBitSet(obfuscateBits); + boolean obfuscated = false; + + // should current block be obfuscated + if (isObfuscateBitSet && obfuscationConfig != null && obfuscationConfig.shouldObfuscate(y) + && shouldObfuscate(request, chunk, state, x, y, z)) { + if (state.isLava) { + proximityBlocks.add(new ProximityBlock(new BlockPos(x, y, z), true)); + } + if (obfuscationConfig.layerObfuscation()) { + if (layerY != y) { + layerY = y; + layerYBlockState = bundle.nextRandomObfuscationBlock(random, y); + } + blockState = layerYBlockState; + } else { + blockState = bundle.nextRandomObfuscationBlock(random, y); + } + obfuscated = true; + } + + // should current block be proximity hidden + if (!obfuscated && BlockFlags.isProximityBitSet(obfuscateBits) && proximityConfig != null + && proximityConfig.shouldObfuscate(y)) { + proximityBlocks.add(new ProximityBlock(new BlockPos(x, y, z), false)); + if (BlockFlags.isUseBlockBelowBitSet(obfuscateBits)) { + boolean allowNonOcclude = !isObfuscateBitSet || !ProximityHeightCondition.isPresent(obfuscateBits); + blockState = getBlockStateBelow(random, bundle, chunk, x, y, z, allowNonOcclude); + } else { + blockState = bundle.nextRandomProximityBlock(random, y); + } + obfuscated = true; + } + + // update block state if needed + if (obfuscated) { + chunkSection.setBlockState(index, blockState); + if (BlockFlags.isBlockEntityBitSet(obfuscateBits)) { + blockEntities.add(new BlockPos(x, y, z)); + } + } + + state.reset(); + } + } + + return new ObfuscationResponse(chunk.finalizeOutput(), blockEntities, proximityBlocks); + } + } + + // returns first block below given position that wouldn't be obfuscated in any + // way at given position + private int getBlockStateBelow(RandomGenerator random, WorldConfigBundle bundle, Chunk chunk, int x, int y, int z, + boolean allowNonOcclude) { + BlockFlags blockFlags = bundle.blockFlags(); + + for (int targetY = y - 1; targetY > chunk.world().getMinBuildHeight(); targetY--) { + int blockData = chunk.getBlockState(x, targetY, z); + if (blockData != -1 && (allowNonOcclude || registryAccessor.isOccluding(blockData))) { + int mask = blockFlags.flags(blockData, y); + if (BlockFlags.isEmpty(mask) || BlockFlags.isAllowForUseBlockBelowBitSet(mask)) { + return blockData; + } + } + } + + return bundle.nextRandomProximityBlock(random, y); + } + + private boolean shouldObfuscate(ObfuscationRequest request, Chunk chunk, State state, int x, int y, int z) { + return isAdjacentBlockOccluding(request, chunk, state, x, y + 1, z) + && isAdjacentBlockOccluding(request, chunk, state, x, y - 1, z) + && isAdjacentBlockOccluding(request, chunk, state, x + 1, y, z) + && isAdjacentBlockOccluding(request, chunk, state, x - 1, y, z) + && isAdjacentBlockOccluding(request, chunk, state, x, y, z + 1) + && isAdjacentBlockOccluding(request, chunk, state, x, y, z - 1); + } + + private boolean isAdjacentBlockOccluding(ObfuscationRequest request, Chunk chunk, State state, int x, int y, int z) { + int blockId = getBlockId(request, chunk, x, y, z); + if (blockId < 0) { + return false; + } + + if (registryAccessor.isOccluding(blockId)) { + return true; + } else if (registryAccessor.isLava(blockId)) { + int aboveBlockId = getBlockId(request, chunk, x, y + 1, z); + state.isLava = aboveBlockId >= 0 && registryAccessor.isLava(aboveBlockId); + return state.isLava; + } + + return false; + } + + private int getBlockId(ObfuscationRequest request, Chunk chunk, int x, int y, int z) { + if (y >= chunk.world().getMaxBuildHeight() || y < chunk.world().getMinBuildHeight()) { + return -1; + } + + int blockId = chunk.getBlockState(x, y, z); + if (blockId == -1) { + blockId = request.getBlockState(x, y, z); + } + + return blockId; + } + + private static class State { + + public boolean isLava = false; + + public void reset() { + this.isLava = false; + } + } +} \ No newline at end of file diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java new file mode 100644 index 00000000..8a8dcd73 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java @@ -0,0 +1,41 @@ +package dev.imprex.orebfuscator.obfuscation; + +import java.util.Objects; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.util.ChunkDirection; + +@NullMarked +public record ObfuscationRequest( + WorldAccessor world, + PlayerAccessor player, + ChunkPacketAccessor packet, + @Nullable ChunkAccessor @Nullable[] neighborChunks) { + + public ObfuscationRequest { + Objects.requireNonNull(world); + Objects.requireNonNull(player); + Objects.requireNonNull(packet); + + if (neighborChunks != null && neighborChunks.length != 4) { + throw new IllegalArgumentException("Expected 4 neighboring chunks but got " + neighborChunks.length); + } + } + + public ObfuscationRequest withNeighbors(ChunkAccessor[] neighborChunks) { + return new ObfuscationRequest(world, player, packet, Objects.requireNonNull(neighborChunks)); + } + + public int getBlockState(int x, int y, int z) { + if (neighborChunks != null) { + ChunkDirection direction = ChunkDirection.fromPosition(packet, x, z); + return neighborChunks[direction.ordinal()].getBlockState(x, y, z); + } + + return 0; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationResponse.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationResponse.java new file mode 100644 index 00000000..d16f7acc --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationResponse.java @@ -0,0 +1,18 @@ +package dev.imprex.orebfuscator.obfuscation; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import org.jspecify.annotations.NullMarked; +import dev.imprex.orebfuscator.player.ProximityBlock; +import dev.imprex.orebfuscator.util.BlockPos; + +@NullMarked +public record ObfuscationResponse(byte[] data, Set blockEntities, List proximityBlocks) { + + public ObfuscationResponse { + Objects.requireNonNull(data); + Objects.requireNonNull(blockEntities); + Objects.requireNonNull(proximityBlocks); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java new file mode 100644 index 00000000..6c14d6bd --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java @@ -0,0 +1,124 @@ +package dev.imprex.orebfuscator.player; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; +import dev.imprex.orebfuscator.config.api.AdvancedConfig; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.util.EntityPose; + +public class OrebfuscatorPlayer { + + private final AdvancedConfig config; + private final PlayerAccessor player; + + private final AtomicReference world = new AtomicReference<>(); + private final Map chunks = new ConcurrentHashMap<>(); + + private volatile long latestUpdateTimestamp = System.currentTimeMillis(); + private volatile EntityPose location = EntityPose.ZERO; + + public OrebfuscatorPlayer(OrebfuscatorCore orebfuscator, PlayerAccessor player) { + this.config = orebfuscator.config().advanced(); + this.player = player; + } + + /** + * Returns true if the last proximity update is longer ago then the configured proximity player interval (default 5s) + * or if the players location since the last update change according to the given rotation boolean and the + * {@link OrebfuscatorPlayer#isLocationSimilar isLocationSimilar} method. + * + * @param rotation passed to the isLocationSimilar method + * @return true if a proximity update is needed + */ + public boolean needsProximityUpdate(boolean rotation) { + if (!player.isAlive()) { + return false; + } + + long timestamp = System.currentTimeMillis(); + if (this.config.hasProximityPlayerCheckInterval() + && timestamp - this.latestUpdateTimestamp > this.config.proximityPlayerCheckInterval()) { + + // always update location + latestUpdateTimestamp on update + this.location = player.pose(); + this.latestUpdateTimestamp = timestamp; + + return true; + } + + EntityPose location = player.pose(); + if (isLocationSimilar(rotation, this.location, location)) { + return false; + } + + // always update location + latestUpdateTimestamp on update + this.location = location; + this.latestUpdateTimestamp = timestamp; + + return true; + } + + /** + * Returns true if the worlds are the same and the distance between the locations is less then 0.5. If the rotation + * boolean is set this method also check if the yaw changed less then 5deg and the pitch less then 2.5deg. + * + * @param rotation should rotation be checked + * @param a the first location + * @param b the second location + * @return if the locations are similar + */ + private static boolean isLocationSimilar(boolean rotation, EntityPose a, EntityPose b) { + // check if world changed + if (!Objects.equals(a.world(), b.world())) { + return false; + } + + // check if len(xyz) changed less then 0.5 blocks + if (a.distanceSquared(b) > 0.25) { + return false; + } + + // check if rotation changed less then 5deg yaw or 2.5deg pitch + if (rotation && (Math.abs(a.rotY() - b.rotY()) > 5 || Math.abs(a.rotX() - b.rotX()) > 2.5)) { + return false; + } + + return true; + } + + public void clearChunks() { + WorldAccessor world = player.world(); + if (!Objects.equals(this.world.getAndSet(world), world)) { + this.chunks.clear(); + } + } + + public void addChunk(WorldAccessor world, int chunkX, int chunkZ, List blocks) { + if (Objects.equals(this.world.getAcquire(), world)) { + long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); + this.chunks.put(key, new OrebfuscatorPlayerChunk(chunkX, chunkZ, blocks)); + } + } + + public OrebfuscatorPlayerChunk getChunk(WorldAccessor world, int chunkX, int chunkZ) { + if (Objects.equals(this.world.getAcquire(), world)) { + long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); + return this.chunks.get(key); + } else { + return null; + } + } + + public void removeChunk(WorldAccessor world, int chunkX, int chunkZ) { + if (Objects.equals(this.world.getAcquire(), world)) { + long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); + this.chunks.remove(key); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java new file mode 100644 index 00000000..3a4f9876 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java @@ -0,0 +1,114 @@ +package dev.imprex.orebfuscator.player; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import dev.imprex.orebfuscator.util.BlockPos; + +public class OrebfuscatorPlayerChunk { + + private static final int FLAG_DELETED = 0x80; + private static final int FLAG_LAVA_OBFUSCATED = 0x01; + + private final int chunkX; + private final int chunkZ; + + private int proximitySize; + private int[] proximityBlocks; + private byte[] proximityFlags; + + public OrebfuscatorPlayerChunk(int chunkX, int chunkZ, List proximityBlocks) { + this.chunkX = chunkX; + this.chunkZ = chunkZ; + + this.proximitySize = proximityBlocks.size(); + this.proximityBlocks = new int[proximityBlocks.size()]; + this.proximityFlags = new byte[proximityBlocks.size()]; + + for (int i = 0; i < proximityBlocks.size(); i++) { + var block = proximityBlocks.get(i); + this.proximityBlocks[i] = block.blockPos().toSectionPos(); + this.proximityFlags[i] = (byte) (block.lavaObfuscated() ? FLAG_LAVA_OBFUSCATED : 0x00); + } + } + + public boolean isEmpty() { + return this.proximitySize <= 0; + } + + public ProximityIterator proximityIterator() { + return new ProximityItr(); + } + + public interface ProximityIterator extends Iterator, AutoCloseable { + void close(); + } + + private class ProximityItr implements ProximityIterator { + + private final int x = chunkX << 4; + private final int z = chunkZ << 4; + + private int cursor; + private int removeCursor = -1; + private int deleteCount; + + @Override + public boolean hasNext() { + return cursor < proximitySize; + } + + @Override + public ProximityBlock next() { + if (cursor >= proximitySize) { + throw new NoSuchElementException(); + } + + int sectionPos = proximityBlocks[removeCursor = cursor]; + int flags = proximityFlags[cursor++]; + + var blockPos = BlockPos.fromSectionPos(x, z, sectionPos); + return new ProximityBlock(blockPos, (flags & FLAG_LAVA_OBFUSCATED) != 0); + } + + @Override + public void remove() { + if (removeCursor < 0) { + throw new IllegalStateException(); + } + + // remove entry + final int index = removeCursor; + int flags = proximityFlags[index]; + if ((flags & FLAG_DELETED) != 0) + throw new IllegalStateException("Already deleted!"); + + // update cursor positions + removeCursor = -1; + + proximityFlags[index] |= FLAG_DELETED; + deleteCount++; + } + + @Override + public void close() { + if (deleteCount > 0) { + int newSize = Math.max(0, proximitySize - deleteCount); + int[] newProximityBlocks = new int[newSize]; + byte[] newProximityFlags = new byte[newSize]; + + int newIndex = 0; + for (int oldIndex = 0; newIndex < newSize && oldIndex < proximitySize; oldIndex++) { + if ((proximityFlags[oldIndex] & FLAG_DELETED) == 0) { + newProximityBlocks[newIndex] = proximityBlocks[oldIndex]; + newProximityFlags[newIndex++] = proximityFlags[oldIndex]; + } + } + + proximitySize = newSize; + proximityBlocks = newProximityBlocks; + proximityFlags = newProximityFlags; + } + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java new file mode 100644 index 00000000..ceca4d1e --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java @@ -0,0 +1,7 @@ +package dev.imprex.orebfuscator.player; + +import dev.imprex.orebfuscator.util.BlockPos; + +public record ProximityBlock(BlockPos blockPos, boolean lavaObfuscated) { + +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java new file mode 100644 index 00000000..394c7ec9 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java @@ -0,0 +1,95 @@ +package dev.imprex.orebfuscator.proximity; + +import dev.imprex.orebfuscator.interop.RegistryAccessor; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.EntityPose; + +// TODO: convert to instance class ProximityRayCaster with instance variables, etc. +public class FastGazeUtil { + + /** + * Basic idea here is to take some rays from the considered block to the + * level's eyes, and decide if any of those rays can reach the eyes unimpeded. + * + * @param pos the starting block position + * @param eyes the destination eyes + * @param level the level world we are testing for + * @param onlyCheckCenter only check block center if true + * @return true if unimpeded path, false otherwise + */ + public static boolean doFastCheck( + BlockPos pos, EntityPose eyes, + WorldAccessor level, RegistryAccessor registry, + boolean onlyCheckCenter) { + double ex = eyes.x(); + double ey = eyes.y(); + double ez = eyes.z(); + double x = pos.x(); + double y = pos.y(); + double z = pos.z(); + if (onlyCheckCenter) { + return // center + FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z + 0.5, ex, ey, ez, level, registry); + } else { + return // midfaces + FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 0.5, z + 0.5, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y, z + 0.5, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 1.0, z + 0.5, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z + 1.0, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1.0, y + 0.5, z + 0.5, ex, ey, ez, level, registry) || + // corners + FastGazeUtil.fastAABBRayCheck(x, y, z, x, y, z, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y, z, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 1, z, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y + 1, z, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y, z + 1, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y, z + 1, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 1, z + 1, ex, ey, ez, level, registry) + || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y + 1, z + 1, ex, ey, ez, level, registry); + } + } + + public static boolean fastAABBRayCheck( + double bx, double by, double bz, + double x, double y, double z, + double ex, double ey, double ez, + WorldAccessor level, RegistryAccessor registry) { + double fx = ex - x; + double fy = ey - y; + double fz = ez - z; + double absFx = Math.abs(fx); + double absFy = Math.abs(fy); + double absFz = Math.abs(fz); + double s = Math.max(absFx, Math.max(absFy, absFz)); + + if (s < 1) { + return true; // on top / inside + } + + double lx, ly, lz; + + fx = fx / s; // units of change along vector + fy = fy / s; + fz = fz / s; + + while (s > 0) { + ex = ex - fx; // move along vector, we start _at_ the eye and move towards b + ey = ey - fy; + ez = ez - fz; + lx = Math.floor(ex); + ly = Math.floor(ey); + lz = Math.floor(ez); + if (lx == bx && ly == by && lz == bz) { + return true; // we've reached our starting block, don't test it. + } + int blockId = level.getBlockState((int) lx, (int) ly, (int) lz); + if (blockId != 0 && registry.isOccluding(blockId)) { + return false; // fail on first hit, this ray is "blocked" + } + s--; // we stop + } + return true; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java new file mode 100644 index 00000000..133c7e5a --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java @@ -0,0 +1,170 @@ +package dev.imprex.orebfuscator.proximity; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; +import dev.imprex.orebfuscator.config.api.AdvancedConfig; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.statistics.ObfuscationStatistics; + +// TODO: rewrite to use new OrebfuscatorExecutor +public class ProximityDirectorThread extends Thread { + + private final OrebfuscatorCore orebfuscator; + private final ObfuscationStatistics statistics; + + private final int workerCount; + private final int defaultBucketSize; + private final long checkInterval; + + private final Phaser phaser = new Phaser(1); + private volatile boolean running = true; + + private final ProximityWorker worker; + private final ProximityWorkerThread[] workerThreads; + + private final BlockingQueue> bucketQueue = new LinkedBlockingQueue<>(); + + public ProximityDirectorThread(OrebfuscatorCore orebfuscator) { + super(OrebfuscatorCore.THREAD_GROUP, "orebfuscator-proximity-director"); + this.setDaemon(true); + + this.orebfuscator = orebfuscator; + this.statistics = orebfuscator.statistics().obfuscation; + + AdvancedConfig advancedConfig = orebfuscator.config().advanced(); + this.workerCount = advancedConfig.proximityThreads(); + this.defaultBucketSize = advancedConfig.proximityDefaultBucketSize(); + this.checkInterval = TimeUnit.MILLISECONDS.toNanos(advancedConfig.proximityThreadCheckInterval()); + + this.worker = new ProximityWorker(orebfuscator); + this.workerThreads = new ProximityWorkerThread[workerCount - 1]; + } + + @Override + public void start() { + super.start(); + + for (int i = 0; i < workerCount - 1; i++) { + this.workerThreads[i] = new ProximityWorkerThread(this, this.worker); + this.workerThreads[i].start(); + } + } + + public void close() { + this.running = false; + + this.interrupt(); + + for (int i = 0; i < workerCount - 1; i++) { + this.workerThreads[i].interrupt(); + } + + // technically not need but better be safe + this.phaser.forceTermination(); + } + + boolean isRunning() { + return this.running && !this.phaser.isTerminated(); + } + + List nextBucket() throws InterruptedException { + return this.bucketQueue.take(); + } + + void finishBucketProcessing() { + this.phaser.arriveAndDeregister(); + } + + @Override + public void run() { + while (this.isRunning()) { + try { + long processStart = System.nanoTime(); + List players = this.orebfuscator.getPlayers(); + + // park thread if no players are online + if (players.isEmpty()) { + // park for 1sec and retry + LockSupport.parkNanos(this, 1000000000L); + // reset interrupt flag + Thread.interrupted(); + continue; + } + + // get player count and derive max bucket size for each thread + int playerCount = players.size(); + int maxBucketSize = Math.max(this.defaultBucketSize, (int) Math.ceil((float) playerCount / this.workerCount)); + + // calculate bucket + int bucketCount = (int) Math.ceil((float) playerCount / maxBucketSize); + int bucketSize = (int) Math.ceil((float) playerCount / (float) bucketCount); + + // register extra worker threads in phaser + if (bucketCount > 1) { + this.phaser.bulkRegister(bucketCount - 1); + } + + // this threads local bucket + List localBucket = null; + + Iterator iterator = players.iterator(); + + // create buckets and fill queue + for (int index = 0; index < bucketCount; index++) { + List bucket = new ArrayList<>(); + + // fill bucket until bucket full or no players remain + for (int size = 0; size < bucketSize && iterator.hasNext(); size++) { + bucket.add(iterator.next()); + } + + // assign first bucket to current thread + if (index == 0) { + localBucket = bucket; + } else { + this.bucketQueue.offer(bucket); + } + } + + // process local bucket + if (localBucket != null) { + this.worker.process(localBucket); + } + + // wait for all threads to finish and reset phaser + this.phaser.awaitAdvanceInterruptibly(this.phaser.arrive()); + + long processTime = System.nanoTime() - processStart; + this.statistics.proximityProcess.add(processTime); + + // check if we have enough time to sleep + long waitTime = Math.max(0, this.checkInterval - processTime); + long waitMillis = TimeUnit.NANOSECONDS.toMillis(waitTime); + + if (waitMillis > 0) { + // measure wait time + this.statistics.proximityWait.add(TimeUnit.MILLISECONDS.toNanos(waitMillis)); + + Thread.sleep(waitMillis); + } + } catch (InterruptedException e) { + continue; + } catch (Exception e) { + OfcLogger.error(e); + } + } + + if (this.phaser.isTerminated() && this.running) { + OfcLogger.error("Looks like we encountered an invalid state, please report this:", + new IllegalStateException("Proximity Phaser terminated!")); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java new file mode 100644 index 00000000..363c820a --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java @@ -0,0 +1,173 @@ +package dev.imprex.orebfuscator.proximity; + +import java.util.ArrayList; +import java.util.List; +import org.joml.FrustumIntersection; +import org.joml.Quaternionf; +import dev.imprex.orebfuscator.config.OrebfuscatorConfig; +import dev.imprex.orebfuscator.config.api.ProximityConfig; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.interop.RegistryAccessor; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; +import dev.imprex.orebfuscator.player.OrebfuscatorPlayerChunk; +import dev.imprex.orebfuscator.player.ProximityBlock; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.EntityPose; + +public class ProximityWorker { + + private final OrebfuscatorCore orebfuscator; + private final OrebfuscatorConfig config; + private final RegistryAccessor registry; + + public ProximityWorker(OrebfuscatorCore orebfuscator) { + this.orebfuscator = orebfuscator; + this.config = orebfuscator.config(); + this.registry = orebfuscator.getRegistry(); + } + + private boolean shouldIgnorePlayer(PlayerAccessor player) { + if (player.hasPermission("orebfuscator.bypass")) { + return true; + } + + return player.isSpectator() && this.config.general().ignoreSpectator(); + } + + protected void process(List players) { + for (PlayerAccessor player : players) { + try { + this.process(player); + } catch (Exception e) { + OfcLogger.error(e); + } + } + } + + private void process(PlayerAccessor player) { + if (this.shouldIgnorePlayer(player)) { + return; + } + + var world = player.world(); + + // check if level has enabled proximity config + ProximityConfig proximityConfig = world.config().proximity(); + if (proximityConfig == null || !proximityConfig.isEnabled()) { + return; + } + + // frustum culling and ray casting both need rotation changes + boolean needsRotation = proximityConfig.frustumCullingEnabled() || proximityConfig.rayCastCheckEnabled(); + + // check if player changed location since last time + OrebfuscatorPlayer orebfuscatorPlayer = player.orebfuscatorPlayer(); + if (!orebfuscatorPlayer.needsProximityUpdate(needsRotation)) { + return; + } + + int distance = proximityConfig.distance(); + int distanceSquared = distance * distance; + + List updateBlocks = new ArrayList<>(); + EntityPose eyeLocation = player.eyePose(); + + // create frustum planes if culling is enabled + FrustumIntersection frustum = + proximityConfig.frustumCullingEnabled() + ? new FrustumIntersection(proximityConfig.frustumCullingProjectionMatrix() + .rotate(new Quaternionf() + .rotateX((float) Math.toRadians(eyeLocation.rotX())) + .rotateY((float) Math.toRadians(eyeLocation.rotY() + 180))) + .translate((float) -eyeLocation.x(), (float) -eyeLocation.y(), (float) -eyeLocation.z()), false) + : null; + + EntityPose location = player.pose(); + int minChunkX = (location.blockX() - distance) >> 4; + int maxChunkX = (location.blockX() + distance) >> 4; + int minChunkZ = (location.blockZ() - distance) >> 4; + int maxChunkZ = (location.blockZ() + distance) >> 4; + + ChunkAccessor playerChunk = world.getChunk(location.blockX() >> 4, location.blockZ() >> 4); + int eyeBlockId = playerChunk.getBlockState(location.blockX(), eyeLocation.blockY(), location.blockZ()); + boolean isInLava = eyeBlockId >= 0 && this.registry.isLava(eyeBlockId); + + double lavaDistance = player.lavaFogDistance(); + double lavaDistanceSquared = lavaDistance * lavaDistance; + + for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) { + for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) { + + OrebfuscatorPlayerChunk chunk = orebfuscatorPlayer.getChunk(world, chunkX, chunkZ); + if (chunk == null) { + continue; + } + + try (var iterator = chunk.proximityIterator()) { + while (iterator.hasNext()) { + ProximityBlock proximityBlock = iterator.next(); + BlockPos blockPos = proximityBlock.blockPos(); + + // skip lava obfuscated if not in lava + // TODO: the current deobfuscation would only deobfuscate lava if the neighoring block is a hiddenBlock + if (proximityBlock.lavaObfuscated() && !isInLava) { + continue; + } + + double compareDistanceSquared; + double blockDistanceSquared; + if (proximityBlock.lavaObfuscated()) { + blockDistanceSquared = blockPos.distanceSquared(eyeLocation.x(), eyeLocation.y(), eyeLocation.z()); + compareDistanceSquared = lavaDistanceSquared; + } else { + blockDistanceSquared = blockPos.distanceSquared(location.x(), location.y(), location.z()); + compareDistanceSquared = distanceSquared; + } + + // check if block is in range + if (blockDistanceSquared > compareDistanceSquared) { + continue; + } + + // do frustum culling check + if (proximityConfig.frustumCullingEnabled() + && blockDistanceSquared > proximityConfig.frustumCullingMinDistanceSquared()) { + + // check if block AABB is inside frustum + int result = frustum.intersectAab(blockPos.x(), blockPos.y(), blockPos.z(), blockPos.x() + 1, + blockPos.y() + 1, blockPos.z() + 1); + + // block is outside + if (result != FrustumIntersection.INSIDE && result != FrustumIntersection.INTERSECT) { + continue; + } + } + + // do ray cast check + if (proximityConfig.rayCastCheckEnabled() && !FastGazeUtil.doFastCheck(blockPos, eyeLocation, world, + orebfuscator.getRegistry(), proximityConfig.rayCastCheckOnlyCheckCenter())) { + continue; + } + + // block is visible and needs update + iterator.remove(); + updateBlocks.add(blockPos); + } + } + + if (chunk.isEmpty()) { + orebfuscatorPlayer.removeChunk(world, chunkX, chunkZ); + } + } + } + + player.runForPlayer(() -> { + if (player.isAlive() && player.world().equals(world)) { + player.sendBlockUpdates(updateBlocks); + } + }); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java new file mode 100644 index 00000000..584319ec --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java @@ -0,0 +1,40 @@ +package dev.imprex.orebfuscator.proximity; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.logging.OfcLogger; + +public class ProximityWorkerThread extends Thread { + + private static final AtomicInteger NEXT_ID = new AtomicInteger(); + + private final ProximityDirectorThread directorThread; + private final ProximityWorker worker; + + public ProximityWorkerThread(ProximityDirectorThread directorThread, ProximityWorker worker) { + super(OrebfuscatorCore.THREAD_GROUP, "orebfuscator-proximity-worker-" + NEXT_ID.getAndIncrement()); + this.setDaemon(true); + + this.directorThread = directorThread; + this.worker = worker; + } + + @Override + public void run() { + while (this.directorThread.isRunning()) { + try { + List bucket = this.directorThread.nextBucket(); + + this.worker.process(bucket); + + this.directorThread.finishBucketProcessing(); + } catch (InterruptedException e) { + continue; + } catch (Exception e) { + OfcLogger.error(e); + } + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java new file mode 100644 index 00000000..c91d1b51 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java @@ -0,0 +1,90 @@ +package dev.imprex.orebfuscator.statistics; + +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; +import java.util.function.LongSupplier; + +public class CacheStatistics implements StatisticsSource { + + private final AtomicLong cacheHitCountMemory = new AtomicLong(0); + private final AtomicLong cacheHitCountDisk = new AtomicLong(0); + private final AtomicLong cacheMissCount = new AtomicLong(0); + + private final AtomicLong memoryCacheByteSize = new AtomicLong(0); + private LongSupplier memoryCacheEntryCount = () -> 0; + + private LongSupplier diskCacheQueueLength = () -> 0; + + public void onCacheHitMemory() { + this.cacheHitCountMemory.incrementAndGet(); + } + + public void onCacheHitDisk() { + this.cacheHitCountDisk.incrementAndGet(); + } + + public void onCacheMiss() { + this.cacheMissCount.incrementAndGet(); + } + + public void onCacheSizeChange(int delta) { + this.memoryCacheByteSize.addAndGet(delta); + } + + public void setMemoryCacheEntryCount(LongSupplier supplier) { + this.memoryCacheEntryCount = Objects.requireNonNull(supplier); + } + + public void setDiskCacheQueueLength(LongSupplier supplier) { + this.diskCacheQueueLength = Objects.requireNonNull(supplier); + } + + public void add(StringJoiner joiner) { + long cacheHitCountMemory = this.cacheHitCountMemory.get(); + long cacheHitCountDisk = this.cacheHitCountDisk.get(); + long cacheMissCount = this.cacheMissCount.get(); + long totalCount = cacheHitCountMemory + cacheHitCountDisk + cacheMissCount; + + double memoryHitRate = 0.0d; + double diskHitRate = 0.0d; + double missRate = 1.0d; + if (totalCount > 0) { + memoryHitRate = (double) cacheHitCountMemory / totalCount; + diskHitRate = (double) cacheHitCountDisk / totalCount; + missRate = 1d - (memoryHitRate + diskHitRate); + } + + joiner.add(String.format(" - cacheHitRate (memory/disk/miss): %s / %s / %s", + percent(memoryHitRate), percent(diskHitRate), percent(missRate))); + + long memoryCacheByteSize = this.memoryCacheByteSize.get(); + long memoryCacheEntryCount = this.memoryCacheEntryCount.getAsLong(); + + long memoryCacheBytesPerEntry = 0; + if (memoryCacheByteSize > 0) { + memoryCacheBytesPerEntry = memoryCacheByteSize / memoryCacheEntryCount; + } + + joiner.add(String.format(" - memoryCache (count/bytesPerEntry): %s / %s ", + memoryCacheEntryCount, bytes(memoryCacheBytesPerEntry))); + + long diskCacheQueueLength = this.diskCacheQueueLength.getAsLong(); + + joiner.add(String.format(" - diskCache (queue): %s ", diskCacheQueueLength)); + } + + @Override + public void debug(Consumer> consumer) { + consumer.accept(Map.entry("cacheHitCountMemory", Long.toString(cacheHitCountMemory.get()))); + consumer.accept(Map.entry("cacheHitCountDisk", Long.toString(cacheHitCountDisk.get()))); + consumer.accept(Map.entry("cacheMissCount", Long.toString(cacheMissCount.get()))); + + consumer.accept(Map.entry("memoryCacheByteSize", Long.toString(memoryCacheByteSize.get()))); + consumer.accept(Map.entry("memoryCacheEntryCount", Long.toString(memoryCacheEntryCount.getAsLong()))); + + consumer.accept(Map.entry("diskCacheQueueLength", Long.toString(diskCacheQueueLength.getAsLong()))); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java new file mode 100644 index 00000000..ca6fde6c --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java @@ -0,0 +1,58 @@ +package dev.imprex.orebfuscator.statistics; + +import java.util.Map; +import java.util.StringJoiner; +import java.util.function.Consumer; +import dev.imprex.orebfuscator.util.RollingAverage; +import dev.imprex.orebfuscator.util.RollingTimer; + +public class InjectorStatistics implements StatisticsSource { + + public final RollingTimer pipelineDelayTotal = new RollingTimer(4096); + public final RollingTimer pipelineDelayCache = new RollingTimer(4096); + public final RollingTimer pipelineDelayNeighbors = new RollingTimer(4096); + public final RollingTimer pipelineDelayProcessor = new RollingTimer(4096); + + public final RollingTimer injectorDelaySync = new RollingTimer(4096); + public final RollingAverage injectorBatchSize = new RollingAverage(4096); + + public final RollingTimer packetDelayAny = new RollingTimer(4096); + public final RollingTimer packetDelayChunk = new RollingTimer(4096); + + @Override + public void add(StringJoiner joiner) { + long pipeline = (long) this.pipelineDelayTotal.average(); + long cache = (long) this.pipelineDelayCache.average(); + long neighbors = (long) this.pipelineDelayNeighbors.average(); + long processor = (long) this.pipelineDelayProcessor.average(); + + joiner.add(String.format(" - pipelineDelay (t/c/n/p): %s / %s / %s / %s", + time(pipeline), time(cache), time(neighbors), time(processor))); + + long sync = (long) this.injectorDelaySync.average(); + double batchSize = this.injectorBatchSize.average(); + + joiner.add(String.format(" - injector (syncDelay/batchSize): %s / %.2f", + time(sync), batchSize)); + + long any = (long) this.packetDelayAny.average(); + long chunk = (long) this.packetDelayChunk.average(); + + joiner.add(String.format(" - packetDelay (any/chunk): %s / %s", + time(any), time(chunk))); + } + + @Override + public void debug(Consumer> consumer) { + consumer.accept(Map.entry("pipelineDelayTotal", this.pipelineDelayTotal.debugLong(this::time))); + consumer.accept(Map.entry("pipelineDelayCache", this.pipelineDelayCache.debugLong(this::time))); + consumer.accept(Map.entry("pipelineDelayNeighbors", this.pipelineDelayNeighbors.debugLong(this::time))); + consumer.accept(Map.entry("pipelineDelayProcessor", this.pipelineDelayProcessor.debugLong(this::time))); + + consumer.accept(Map.entry("injectorDelaySync", this.injectorDelaySync.debugLong(this::time))); + consumer.accept(Map.entry("injectorBatchSize", this.injectorBatchSize.debugLong(this::time))); + + consumer.accept(Map.entry("packetDelayAny", this.packetDelayAny.debugLong(this::time))); + consumer.accept(Map.entry("packetDelayChunk", this.packetDelayChunk.debugLong(this::time))); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java new file mode 100644 index 00000000..4288440a --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java @@ -0,0 +1,81 @@ +package dev.imprex.orebfuscator.statistics; + +import java.util.Map; +import java.util.StringJoiner; +import java.util.function.Consumer; +import dev.imprex.orebfuscator.util.RollingAverage; +import dev.imprex.orebfuscator.util.RollingTimer; + +public class ObfuscationStatistics implements StatisticsSource { + + public final RollingTimer debofuscation = new RollingTimer(8192); + + public final RollingTimer executorWaitTime = new RollingTimer(8192); + public final RollingTimer executorUtilization = new RollingTimer(4096); + + public final RollingTimer proximityWait = new RollingTimer(4096); + public final RollingTimer proximityProcess = new RollingTimer(4096); + + public final RollingAverage missingNeighboringChunks = new RollingAverage(4096); + + public final RollingAverage originalChunkSize = new RollingAverage(4096); + public final RollingAverage obfuscatedChunkSize = new RollingAverage(4096); + + @Override + public void add(StringJoiner joiner) { + long debofuscation = (long) this.debofuscation.average(); + + joiner.add(String.format(" - debofuscation: %s", + time(debofuscation))); + + long executorWaitTime = (long) this.executorWaitTime.average(); + double executorUtilization = this.executorUtilization.average(); + + joiner.add(String.format(" - executor (wait/utilization): %s / %s", + time(executorWaitTime), percent(executorUtilization))); + + double proximityWait = this.proximityWait.average(); + double proximityProcess = this.proximityProcess.average(); + double proximityTotalTime = proximityWait + proximityProcess; + + double proximityUtilization = 0; + if (proximityTotalTime > 0) { + proximityUtilization = (double) proximityProcess / proximityTotalTime; + } + + joiner.add(String.format(" - proximity utilization: %s", + percent(proximityUtilization))); + + double missingNeighboringChunks = this.missingNeighboringChunks.average(); + + joiner.add(String.format(" - missingNeighbors: %s", + faction(missingNeighboringChunks))); + + long originalChunkSize = (long) this.originalChunkSize.average(); + long obfuscatedChunkSize = (long) this.obfuscatedChunkSize.average(); + + double chunkSizeRatio = 1; + if (originalChunkSize > 0) { + chunkSizeRatio = (double) obfuscatedChunkSize / originalChunkSize; + } + + joiner.add(String.format(" - chunk size (org/obf/rat): %s / %s / %s ", + bytes(originalChunkSize), bytes(obfuscatedChunkSize), percent(chunkSizeRatio))); + } + + @Override + public void debug(Consumer> consumer) { + consumer.accept(Map.entry("debofuscation", this.debofuscation.debugLong(this::time))); + + consumer.accept(Map.entry("executorWaitTime", this.executorWaitTime.debugLong(this::time))); + consumer.accept(Map.entry("executorUtilization", this.executorUtilization.debugDouble(this::percent))); + + consumer.accept(Map.entry("proximityWait", this.proximityWait.debugLong(this::time))); + consumer.accept(Map.entry("proximityProcess", this.proximityProcess.debugDouble(this::percent))); + + consumer.accept(Map.entry("missingNeighboringChunks", this.missingNeighboringChunks.debugDouble(this::faction))); + + consumer.accept(Map.entry("originalChunkSize", this.originalChunkSize.debugLong(this::bytes))); + consumer.accept(Map.entry("obfuscatedChunkSize", this.obfuscatedChunkSize.debugLong(this::bytes))); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java new file mode 100644 index 00000000..c9dbb7e7 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java @@ -0,0 +1,19 @@ +package dev.imprex.orebfuscator.statistics; + +import dev.imprex.orebfuscator.config.api.Config; + +public class OrebfuscatorStatistics { + + public final CacheStatistics cache = new CacheStatistics(); + public final InjectorStatistics injector = new InjectorStatistics(); + public final ObfuscationStatistics obfuscation = new ObfuscationStatistics(); + + public OrebfuscatorStatistics(Config config, StatisticsRegistry registry) { + if (config.cache().enabled()) { + registry.register("cache", this.cache); + } + + registry.register("injector", this.injector); + registry.register("obfuscation", this.obfuscation); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java new file mode 100644 index 00000000..772200c7 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java @@ -0,0 +1,64 @@ +package dev.imprex.orebfuscator.statistics; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; +import java.util.stream.Collectors; +import com.google.gson.JsonObject; + +public class StatisticsRegistry { + + private final Map sources = new HashMap<>(); + + public void register(String name, StatisticsSource source) { + if (sources.containsKey(name)) { + throw new IllegalArgumentException("Duplicate statistics name: " + name); + } + + this.sources.put(name, source); + } + + public String format() { + var joiner = new StringJoiner("\n", "Here are some useful statistics:\n", ""); + + for (var source : sources.values()) { + source.add(joiner); + } + + return joiner.toString(); + } + + public String debug() { + return entries().stream() + .sorted(Comparator.comparing(Map.Entry::getKey)) + .map(entry -> String.format(" - %s: %s", entry.getKey(), entry.getValue())) + .collect(Collectors.joining("\n")); + } + + public JsonObject json() { + JsonObject object = new JsonObject(); + + var entries = entries().stream() + .sorted(Comparator.comparing(Map.Entry::getKey)) + .toList(); + + for (var entry : entries) { + object.addProperty(entry.getKey(), entry.getValue()); + } + + return object; + } + + private List> entries() { + var entries = new ArrayList>(); + + for (var source : sources.values()) { + source.debug(entries::add); + } + + return entries; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java new file mode 100644 index 00000000..e29b703d --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java @@ -0,0 +1,42 @@ +package dev.imprex.orebfuscator.statistics; + +import java.util.Map; +import java.util.StringJoiner; +import java.util.function.Consumer; + +public interface StatisticsSource { + + default String faction(double value) { + return String.format("%.3f", value); + } + + default String percent(double value) { + return String.format("%.2f%%", value * 100); + } + + default String time(long time) { + if (time > 1000_000L) { + return String.format("%.1fms", time / 1000_000d); + } else if (time > 1000L) { + return String.format("%.1fµs", time / 1000d); + } else { + return String.format("%dns", time); + } + } + + default String bytes(long bytes) { + if (bytes > 1073741824L) { + return String.format("%.1f GiB", bytes / 1073741824d); + } else if (bytes > 1048576L) { + return String.format("%.1f MiB", bytes / 1048576d); + } else if (bytes > 1024L) { + return String.format("%.1f KiB", bytes / 1024d); + } else { + return String.format("%d B", bytes); + } + } + + void add(StringJoiner joiner); + + void debug(Consumer> consumer); +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java index f1201bcd..490252d1 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockStateProperties.java @@ -12,6 +12,7 @@ public static Builder builder(int id) { private final int id; private final boolean isAir; + private final boolean isLava; private final boolean isOccluding; private final boolean isBlockEntity; private final boolean isDefaultState; @@ -19,6 +20,7 @@ public static Builder builder(int id) { private BlockStateProperties(Builder builder) { this.id = builder.id; this.isAir = builder.isAir; + this.isLava = builder.isLava; this.isOccluding = builder.isOccluding; this.isBlockEntity = builder.isBlockEntity; this.isDefaultState = builder.isDefaultState; @@ -32,6 +34,10 @@ public boolean isAir() { return isAir; } + public boolean isLava() { + return isLava; + } + public boolean isOccluding() { return isOccluding; } @@ -71,6 +77,7 @@ public static class Builder { private final int id; private boolean isAir; + private boolean isLava; private boolean isOccluding; private boolean isBlockEntity; private boolean isDefaultState; @@ -84,6 +91,11 @@ public Builder withIsAir(boolean isAir) { return this; } + public Builder withIsLava(boolean isLava) { + this.isLava = isLava; + return this; + } + public Builder withIsOccluding(boolean isOccluding) { this.isOccluding = isOccluding; return this; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java index 02873514..94f2b725 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java @@ -1,11 +1,16 @@ package dev.imprex.orebfuscator.util; -import dev.imprex.orebfuscator.interop.WorldAccessor; import org.jspecify.annotations.NullMarked; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; @NullMarked public record ChunkCacheKey(String world, int x, int z) { + public ChunkCacheKey(ObfuscationRequest request) { + this(request.world(), request.packet().chunkX(), request.packet().chunkZ()); + } + public ChunkCacheKey(WorldAccessor world, BlockPos position) { this(world.getName(), position.x() >> 4, position.z() >> 4); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java index 1bac2629..0a109a87 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java @@ -1,5 +1,7 @@ package dev.imprex.orebfuscator.util; +import java.util.Objects; +import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; import org.jspecify.annotations.NullMarked; @NullMarked @@ -23,6 +25,27 @@ public int getOffsetZ() { return offsetZ; } + public static ChunkDirection fromPosition(ChunkPacketAccessor packetAccessor, int targetX, int targetZ) { + Objects.requireNonNull(packetAccessor); + + int offsetX = (targetX >> 4) - packetAccessor.chunkX(); + int offsetZ = (targetZ >> 4) - packetAccessor.chunkZ(); + + if (offsetX == 1 && offsetZ == 0) { + return NORTH; + } else if (offsetX == 0 && offsetZ == 1) { + return EAST; + } else if (offsetX == -1 && offsetZ == 0) { + return SOUTH; + } else if (offsetX == 0 && offsetZ == -1) { + return WEST; + } + + throw new IllegalArgumentException(String.format("invalid offset (chunkX: %d, chunkZ: %d, x: %d, z: %d)", + packetAccessor.chunkX(), packetAccessor.chunkZ(), targetX, targetZ)); + } + + @Deprecated public static ChunkDirection fromPosition(ChunkCacheKey key, int targetX, int targetZ) { int offsetX = (targetX >> 4) - key.x(); int offsetZ = (targetZ >> 4) - key.z(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java new file mode 100644 index 00000000..83628514 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java @@ -0,0 +1,29 @@ +package dev.imprex.orebfuscator.util; + +import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.interop.WorldAccessor; + +// TODO: nullability +public record EntityPose(@Nullable WorldAccessor world, double x, double y, double z, float rotX, float rotY) { + + public static final EntityPose ZERO = new EntityPose(null, 0, 0, 0, 0, 0); + + public int blockX() { + return MathUtil.floor(this.x); + } + + public int blockY() { + return MathUtil.floor(this.y); + } + + public int blockZ() { + return MathUtil.floor(this.z); + } + + public double distanceSquared(EntityPose other) { + double dx = this.x - other.x; + double dy = this.y - other.y; + double dz = this.z - other.z; + return dx * dx + dy * dy + dz * dz; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/MathUtil.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/MathUtil.java index 095a8fa8..476c2e79 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/MathUtil.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/MathUtil.java @@ -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..3280e9e9 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingAverage.java @@ -0,0 +1,101 @@ +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 com.google.common.util.concurrent.AtomicDouble; + +// TODO: nullability +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..b040f9a3 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java @@ -0,0 +1,35 @@ +package dev.imprex.orebfuscator.util; + +import java.util.concurrent.CompletionStage; + +// TODO: nullability +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 boolean running = true; + + private Instance() { + } + + public CompletionStage wrap(CompletionStage completionStage) { + return completionStage.whenComplete((a, b) -> stop()); + } + + public void stop() { + if (running) { + add(System.nanoTime() - time); + running = false; + } + } + } +} 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 e0c301a9..05fd845e 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 @@ -7,6 +7,7 @@ /** * Simple cache implementation that removes the oldest element once a certain size is reached */ +// TODO: nullability public class SimpleCache extends LinkedHashMap { private final int maximumSize; 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 98c1c9e3..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 @@ -143,6 +143,23 @@ 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. * @@ -152,13 +169,22 @@ public int next() { 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]; } /** 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..b52f4853 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorExecutor.java @@ -0,0 +1,89 @@ +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.TimeUnit; +import java.util.concurrent.atomic.LongAdder; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics; + +// TODO: nullability, public schedule method +public class OrebfuscatorExecutor implements Executor { + + private final ScheduledExecutorService scheduledExecutorService = + Executors.newScheduledThreadPool(1, 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().obfuscationThreads(); + 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)); + } + } + + 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..5c4c3fea --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/concurrent/OrebfuscatorThread.java @@ -0,0 +1,31 @@ +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 dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.logging.OfcLogger; + +// TODO: nullability +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/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/pom.xml b/pom.xml index 4879ef82..388a2727 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,10 @@ papermc https://repo.papermc.io/repository/maven-public/ + + codemc-releases + https://repo.codemc.io/repository/maven-releases/ + From e592c475ac6cb8033b41ce2572039dc08276fbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sun, 18 Jan 2026 02:30:36 +0100 Subject: [PATCH 03/14] feat: migrate bukkit plugin to entirely to core --- .../OrebfuscatorCompatibility.java | 4 +- .../compatibility/CompatibilityLayer.java | 4 +- .../bukkit/BukkitChunkLoader.java | 10 +- .../bukkit/BukkitCompatibilityLayer.java | 4 +- .../AbstractPaperCompatibilityLayer.java | 8 +- orebfuscator-core/pom.xml | 2 +- .../orebfuscator/cache/ChunkCacheEntry.java | 19 +- .../dev/imprex/orebfuscator/chunk/Chunk.java | 3 +- .../config/AbstractWorldConfig.java | 6 +- .../config/components/WeightedBlockList.java | 6 +- .../orebfuscator/interop/ChunkAccessor.java | 3 + .../interop/ChunkPacketAccessor.java | 3 +- .../interop/OrebfuscatorCore.java | 3 +- .../orebfuscator/interop/PlayerAccessor.java | 3 +- .../orebfuscator/interop/ServerAccessor.java | 3 +- .../orebfuscator/interop/WorldAccessor.java | 3 +- .../player/OrebfuscatorPlayer.java | 5 +- .../player/OrebfuscatorPlayerChunk.java | 2 + .../orebfuscator/player/ProximityBlock.java | 11 + .../orebfuscator/proximity/FastGazeUtil.java | 95 --------- .../proximity/ProximityRayCaster.java | 97 +++++++++ .../proximity/ProximityWorker.java | 8 +- .../accessor/DefaultMethodAccessor.java | 1 - .../imprex/orebfuscator/util/EntityPose.java | 9 +- .../util/{MathUtil.java => QuickMaths.java} | 2 +- .../orebfuscator/util/RollingAverage.java | 3 +- .../orebfuscator/util/RollingTimer.java | 3 +- .../imprex/orebfuscator/util/SimpleCache.java | 3 +- .../dev/imprex/orebfuscator/util/Version.java | 2 +- .../util/concurrent/OrebfuscatorExecutor.java | 4 +- .../util/concurrent/OrebfuscatorThread.java | 3 +- .../imprex/orebfuscator/OrebfuscatorNms.java | 15 +- .../orebfuscator/nms/AbstractNmsManager.java | 19 +- .../imprex/orebfuscator/nms/NmsManager.java | 7 +- .../orebfuscator/nms/ReadOnlyChunk.java | 6 - .../orebfuscator/nms/v1_16_R1/NmsManager.java | 5 +- .../nms/v1_16_R1/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_16_R2/NmsManager.java | 5 +- .../nms/v1_16_R2/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_16_R3/NmsManager.java | 5 +- .../nms/v1_16_R3/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_17_R1/NmsManager.java | 5 +- .../nms/v1_17_R1/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_18_R1/NmsManager.java | 5 +- .../nms/v1_18_R1/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_18_R2/NmsManager.java | 5 +- .../nms/v1_18_R2/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_19_R1/NmsManager.java | 5 +- .../nms/v1_19_R1/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_19_R2/NmsManager.java | 5 +- .../nms/v1_19_R2/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_19_R3/NmsManager.java | 5 +- .../nms/v1_19_R3/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_20_R1/NmsManager.java | 5 +- .../nms/v1_20_R1/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_20_R2/NmsManager.java | 5 +- .../nms/v1_20_R2/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_20_R3/NmsManager.java | 5 +- .../nms/v1_20_R3/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_20_R4/NmsManager.java | 5 +- .../nms/v1_20_R4/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_21_R1/NmsManager.java | 5 +- .../nms/v1_21_R1/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_21_R2/NmsManager.java | 5 +- .../nms/v1_21_R2/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_21_R3/NmsManager.java | 5 +- .../nms/v1_21_R3/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_21_R4/NmsManager.java | 5 +- .../nms/v1_21_R4/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_21_R5/NmsManager.java | 5 +- .../nms/v1_21_R5/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_21_R6/NmsManager.java | 5 +- .../nms/v1_21_R6/ReadOnlyChunkWrapper.java | 4 +- .../orebfuscator/nms/v1_21_R7/NmsManager.java | 15 +- .../nms/v1_21_R7/ReadOnlyChunkWrapper.java | 4 +- orebfuscator-plugin/pom.xml | 4 +- .../DefaultOrebfuscatorService.java | 2 - .../imprex/orebfuscator/MetricsSystem.java | 8 +- .../net/imprex/orebfuscator/Orebfuscator.java | 135 +++++++----- .../orebfuscator/OrebfuscatorCommand.java | 8 +- .../orebfuscator/OrebfuscatorStatistics.java | 200 ------------------ .../net/imprex/orebfuscator/UpdateSystem.java | 2 +- .../cache/AsyncChunkSerializer.java | 181 ---------------- .../orebfuscator/cache/CacheChunkEntry.java | 110 ---------- .../cache/CacheFileCleanupTask.java | 61 ------ .../orebfuscator/cache/ChunkSerializer.java | 53 ----- .../orebfuscator/cache/ObfuscationCache.java | 143 ------------- .../iterop/BukkitChunkPacketAccessor.java | 35 +-- .../iterop/BukkitLoggerAccessor.java | 6 +- .../iterop/BukkitPlayerAccessor.java | 147 +++++++++++++ .../iterop/BukkitWorldAccessor.java | 79 +++++-- .../obfuscation/DeobfuscationListener.java | 33 ++- .../obfuscation/DeobfuscationWorker.java | 110 ---------- .../obfuscation/ObfuscationListener.java | 129 +++-------- .../obfuscation/ObfuscationProcessor.java | 161 -------------- .../obfuscation/ObfuscationRequest.java | 82 ------- .../obfuscation/ObfuscationResult.java | 53 ----- .../obfuscation/ObfuscationSystem.java | 48 ++--- .../obfuscation/ObfuscationTask.java | 54 ----- .../ObfuscationTaskDispatcher.java | 78 ------- .../obfuscation/ObfuscationTaskWorker.java | 67 ------ .../player/OrebfuscatorPlayer.java | 126 ----------- .../player/OrebfuscatorPlayerChunk.java | 81 ------- .../player/OrebfuscatorPlayerMap.java | 53 ----- .../proximity/ProximityDirectorThread.java | 187 ---------------- .../proximity/ProximityPacketListener.java | 43 ++-- .../proximity/ProximityWorker.java | 161 -------------- .../proximity/ProximityWorkerThread.java | 41 ---- .../orebfuscator/util/FastGazeUtil.java | 89 -------- .../imprex/orebfuscator/util/RingTimer.java | 53 ----- .../orebfuscator/util/RollingAverage.java | 42 ---- pom.xml | 15 +- 112 files changed, 736 insertions(+), 2713 deletions(-) delete mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java rename orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/{MathUtil.java => QuickMaths.java} (96%) delete mode 100644 orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/nms/ReadOnlyChunk.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheChunkEntry.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheFileCleanupTask.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java create mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationRequest.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationResult.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTask.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskDispatcher.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskWorker.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayer.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerMap.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityDirectorThread.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorker.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorkerThread.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/FastGazeUtil.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RingTimer.java delete mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RollingAverage.java diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java index 36257427..71b94d0e 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java @@ -11,7 +11,7 @@ import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.util.ChunkCacheKey; import net.imprex.orebfuscator.compatibility.CompatibilityLayer; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.imprex.orebfuscator.util.ServerVersion; public class OrebfuscatorCompatibility { @@ -64,7 +64,7 @@ public static void cancelTasks() { instance.getScheduler().cancelTasks(); } - public static CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { + public static CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { return instance.getNeighboringChunks(world, key); } diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java index 6a039e64..79fb1b8b 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java @@ -5,7 +5,7 @@ import org.bukkit.World; import dev.imprex.orebfuscator.util.ChunkCacheKey; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; public interface CompatibilityLayer { @@ -13,5 +13,5 @@ public interface CompatibilityLayer { CompatibilityScheduler getScheduler(); - CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key); + CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key); } diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java index f8dd4c3d..6267ac9b 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java @@ -13,7 +13,7 @@ import dev.imprex.orebfuscator.util.ChunkCacheKey; import dev.imprex.orebfuscator.util.ChunkDirection; import net.imprex.orebfuscator.OrebfuscatorNms; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; public class BukkitChunkLoader implements Runnable { @@ -27,7 +27,7 @@ public BukkitChunkLoader(Plugin plugin, Config config) { Bukkit.getScheduler().runTaskTimer(plugin, this, 0, 1); } - public CompletableFuture submitRequest(World world, ChunkCacheKey key) { + public CompletableFuture submitRequest(World world, ChunkCacheKey key) { Request request = new Request(world, key); this.requests.offer(request); return request.future; @@ -48,7 +48,7 @@ private class Request implements Runnable { private final World world; private final ChunkCacheKey key; - private final CompletableFuture future = new CompletableFuture<>(); + private final CompletableFuture future = new CompletableFuture<>(); public Request(World world, ChunkCacheKey key) { this.world = world; @@ -57,13 +57,13 @@ public Request(World world, ChunkCacheKey key) { @Override public void run() { - final ReadOnlyChunk[] neighboringChunks = new ReadOnlyChunk[4]; + final ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; for (ChunkDirection direction : ChunkDirection.values()) { int chunkX = key.x() + direction.getOffsetX(); int chunkZ = key.z() + direction.getOffsetZ(); - neighboringChunks[direction.ordinal()] = OrebfuscatorNms.getReadOnlyChunk(world, chunkX, chunkZ); + neighboringChunks[direction.ordinal()] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); } future.complete(neighboringChunks); diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java index 637ca123..62a0c59c 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java @@ -9,7 +9,7 @@ import dev.imprex.orebfuscator.util.ChunkCacheKey; import net.imprex.orebfuscator.compatibility.CompatibilityLayer; import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; public class BukkitCompatibilityLayer implements CompatibilityLayer { @@ -34,7 +34,7 @@ public CompatibilityScheduler getScheduler() { } @Override - public CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { + public CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { return this.chunkLoader.submitRequest(world, key); } } diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java index 3f5efe34..c63218e0 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java @@ -8,14 +8,14 @@ import dev.imprex.orebfuscator.util.ChunkDirection; import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.compatibility.CompatibilityLayer; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; public abstract class AbstractPaperCompatibilityLayer implements CompatibilityLayer { @Override - public CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { + public CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { CompletableFuture[] futures = new CompletableFuture[4]; - ReadOnlyChunk[] neighboringChunks = new ReadOnlyChunk[4]; + ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; for (ChunkDirection direction : ChunkDirection.values()) { int chunkX = key.x() + direction.getOffsetX(); @@ -23,7 +23,7 @@ public CompletableFuture getNeighboringChunks(World world, Chun int index = direction.ordinal(); futures[index] = world.getChunkAtAsync(chunkX, chunkZ).thenAccept(chunk -> { - neighboringChunks[index] = OrebfuscatorNms.getReadOnlyChunk(world, chunkX, chunkZ); + neighboringChunks[index] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); }); } diff --git a/orebfuscator-core/pom.xml b/orebfuscator-core/pom.xml index 2701bc00..6a6918a0 100644 --- a/orebfuscator-core/pom.xml +++ b/orebfuscator-core/pom.xml @@ -54,7 +54,7 @@ provided - org.lz4 + at.yawk.lz4 lz4-java ${dependency.lz4.version} provided diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java index aff14940..0bddb96b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java @@ -20,10 +20,8 @@ public record ChunkCacheEntry(ChunkCacheKey key, byte[] compressedData) { public static ChunkCacheEntry create(CacheRequest request, ObfuscationResponse response) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - // TODO: move BAOS and return into try block - - try (LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(byteArrayOutputStream); + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(byteArrayOutputStream); DataOutputStream dataOutputStream = new DataOutputStream(lz4BlockOutputStream)) { byteArrayOutputStream.write(request.hash()); @@ -36,8 +34,7 @@ public static ChunkCacheEntry create(CacheRequest request, ObfuscationResponse r dataOutputStream.writeInt(proximityBlocks.size()); for (ProximityBlock blockPosition : proximityBlocks) { dataOutputStream.writeInt(blockPosition.blockPos().toSectionPos()); - // TODO save as byte: flags - dataOutputStream.writeBoolean(blockPosition.lavaObfuscated()); + dataOutputStream.writeByte(blockPosition.flags()); } Collection blockEntities = response.blockEntities(); @@ -45,11 +42,11 @@ public static ChunkCacheEntry create(CacheRequest request, ObfuscationResponse r for (BlockPos blockPosition : blockEntities) { dataOutputStream.writeInt(blockPosition.toSectionPos()); } + + return new ChunkCacheEntry(request.cacheKey(), byteArrayOutputStream.toByteArray()); } catch (Exception e) { throw new ChunkCacheException("Unable to compress chunk: " + request.cacheKey(), e); } - - return new ChunkCacheEntry(request.cacheKey(), byteArrayOutputStream.toByteArray()); } public int estimatedSize() { @@ -62,7 +59,7 @@ public boolean isValid(CacheRequest request) { public ObfuscationResponse toResult() { try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(compressedData); - LZ4BlockInputStream lz4BlockInputStream = new LZ4BlockInputStream(byteArrayInputStream); + LZ4BlockInputStream lz4BlockInputStream = LZ4BlockInputStream.newBuilder().build(byteArrayInputStream); DataInputStream dataInputStream = new DataInputStream(lz4BlockInputStream)) { byteArrayInputStream.skip(CacheRequest.HASH_LENGTH); @@ -76,8 +73,8 @@ public ObfuscationResponse toResult() { var proximityBlocks = new ArrayList(); for (int i = dataInputStream.readInt(); i > 0; i--) { var blockPos = BlockPos.fromSectionPos(x, z, dataInputStream.readInt()); - var lavaObfuscated = dataInputStream.readBoolean(); - proximityBlocks.add(new ProximityBlock(blockPos, lavaObfuscated)); + var flags = dataInputStream.readByte(); + proximityBlocks.add(new ProximityBlock(blockPos, flags)); } var blockEntities = new HashSet(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java index 8467422e..7d737e98 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java @@ -1,9 +1,8 @@ package dev.imprex.orebfuscator.chunk; -import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import java.util.Arrays; -import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import io.netty.buffer.ByteBuf; import io.netty.buffer.PooledByteBufAllocator; import io.netty.buffer.Unpooled; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java index 37492f96..8a06bed0 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java @@ -12,7 +12,7 @@ import dev.imprex.orebfuscator.interop.WorldAccessor; import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.MathUtil; +import dev.imprex.orebfuscator.util.QuickMaths; import dev.imprex.orebfuscator.util.WeightedRandom; import java.util.ArrayList; import java.util.List; @@ -40,8 +40,8 @@ public AbstractWorldConfig(String name) { protected void deserializeBase(ConfigurationSection section, ConfigParsingContext context) { this.enabledValue = section.getBoolean("enabled", true); - int minY = MathUtil.clamp(section.getInt("minY", BlockPos.MIN_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); - int maxY = MathUtil.clamp(section.getInt("maxY", BlockPos.MAX_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); + int minY = QuickMaths.clamp(section.getInt("minY", BlockPos.MIN_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); + int maxY = QuickMaths.clamp(section.getInt("maxY", BlockPos.MAX_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); this.minY = Math.min(minY, maxY); this.maxY = Math.max(minY, maxY); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java index 6fec6405..91191969 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java @@ -15,7 +15,7 @@ import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.BlockStateProperties; -import dev.imprex.orebfuscator.util.MathUtil; +import dev.imprex.orebfuscator.util.QuickMaths; import dev.imprex.orebfuscator.util.WeightedRandom; import org.jspecify.annotations.NullMarked; @@ -85,8 +85,8 @@ public WeightedBlockList(BlockParser.Factory blockParserFactory, ConfigurationSe ConfigParsingContext context) { this.name = section.getName(); - int minY = MathUtil.clamp(section.getInt("minY", BlockPos.MIN_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); - int maxY = MathUtil.clamp(section.getInt("maxY", BlockPos.MAX_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); + int minY = QuickMaths.clamp(section.getInt("minY", BlockPos.MIN_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); + int maxY = QuickMaths.clamp(section.getInt("maxY", BlockPos.MAX_Y), BlockPos.MIN_Y, BlockPos.MAX_Y); this.minY = Math.min(minY, maxY); this.maxY = Math.max(minY, maxY); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java index 730260ec..758e5ac8 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java @@ -1,5 +1,8 @@ package dev.imprex.orebfuscator.interop; +import org.jspecify.annotations.NullMarked; + +@NullMarked public interface ChunkAccessor { ChunkAccessor EMPTY = (x, y, z) -> 0; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java index 8a43447d..09e42b4b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkPacketAccessor.java @@ -1,8 +1,9 @@ package dev.imprex.orebfuscator.interop; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.obfuscation.ObfuscationResponse; -// TODO: nullability +@NullMarked public interface ChunkPacketAccessor { int chunkX(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java index 4895ec84..4534921d 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.interop; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.cache.ObfuscationCache; import dev.imprex.orebfuscator.chunk.ChunkFactory; import dev.imprex.orebfuscator.config.OrebfuscatorConfig; @@ -8,7 +9,7 @@ import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics; import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorExecutor; -// TODO: nullability +@NullMarked public interface OrebfuscatorCore extends ServerAccessor { ThreadGroup THREAD_GROUP = new ThreadGroup("orebfuscator"); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java index a97e0bcd..efdda0f0 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java @@ -1,10 +1,11 @@ package dev.imprex.orebfuscator.interop; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.EntityPose; -// TODO: nullability +@NullMarked public interface PlayerAccessor { OrebfuscatorPlayer orebfuscatorPlayer(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java index b244b9b8..7dac1448 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java @@ -2,10 +2,11 @@ import java.nio.file.Path; import java.util.List; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; import dev.imprex.orebfuscator.util.Version; -// TODO: nullability +@NullMarked public interface ServerAccessor { boolean isGameThread(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java index a7f2adbd..c82a3407 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java @@ -1,11 +1,12 @@ package dev.imprex.orebfuscator.interop; import java.util.concurrent.CompletableFuture; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.config.api.WorldConfigBundle; import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import dev.imprex.orebfuscator.util.BlockPos; -// TODO: nullability +@NullMarked public interface WorldAccessor { String getName(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java index 6c14d6bd..8d3c804d 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java @@ -5,6 +5,8 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import dev.imprex.orebfuscator.config.api.AdvancedConfig; import dev.imprex.orebfuscator.interop.ChunkAccessor; import dev.imprex.orebfuscator.interop.OrebfuscatorCore; @@ -12,12 +14,13 @@ import dev.imprex.orebfuscator.interop.WorldAccessor; import dev.imprex.orebfuscator.util.EntityPose; +@NullMarked public class OrebfuscatorPlayer { private final AdvancedConfig config; private final PlayerAccessor player; - private final AtomicReference world = new AtomicReference<>(); + private final AtomicReference<@Nullable WorldAccessor> world = new AtomicReference<>(); private final Map chunks = new ConcurrentHashMap<>(); private volatile long latestUpdateTimestamp = System.currentTimeMillis(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java index 3a4f9876..58cace67 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java @@ -3,8 +3,10 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.util.BlockPos; +@NullMarked public class OrebfuscatorPlayerChunk { private static final int FLAG_DELETED = 0x80; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java index ceca4d1e..40b2d075 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java @@ -1,7 +1,18 @@ package dev.imprex.orebfuscator.player; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.util.BlockPos; +@NullMarked public record ProximityBlock(BlockPos blockPos, boolean lavaObfuscated) { + private static final byte FLAG_LAVA_OBFUSCATED = 0x01; + + public ProximityBlock(BlockPos blockPos, byte flags) { + this(blockPos, (flags & FLAG_LAVA_OBFUSCATED) == FLAG_LAVA_OBFUSCATED); + } + + public byte flags() { + return lavaObfuscated ? FLAG_LAVA_OBFUSCATED : 0x00; + } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java deleted file mode 100644 index 394c7ec9..00000000 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/FastGazeUtil.java +++ /dev/null @@ -1,95 +0,0 @@ -package dev.imprex.orebfuscator.proximity; - -import dev.imprex.orebfuscator.interop.RegistryAccessor; -import dev.imprex.orebfuscator.interop.WorldAccessor; -import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.EntityPose; - -// TODO: convert to instance class ProximityRayCaster with instance variables, etc. -public class FastGazeUtil { - - /** - * Basic idea here is to take some rays from the considered block to the - * level's eyes, and decide if any of those rays can reach the eyes unimpeded. - * - * @param pos the starting block position - * @param eyes the destination eyes - * @param level the level world we are testing for - * @param onlyCheckCenter only check block center if true - * @return true if unimpeded path, false otherwise - */ - public static boolean doFastCheck( - BlockPos pos, EntityPose eyes, - WorldAccessor level, RegistryAccessor registry, - boolean onlyCheckCenter) { - double ex = eyes.x(); - double ey = eyes.y(); - double ez = eyes.z(); - double x = pos.x(); - double y = pos.y(); - double z = pos.z(); - if (onlyCheckCenter) { - return // center - FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z + 0.5, ex, ey, ez, level, registry); - } else { - return // midfaces - FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 0.5, z + 0.5, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y, z + 0.5, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 1.0, z + 0.5, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z + 1.0, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1.0, y + 0.5, z + 0.5, ex, ey, ez, level, registry) || - // corners - FastGazeUtil.fastAABBRayCheck(x, y, z, x, y, z, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y, z, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 1, z, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y + 1, z, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y, z + 1, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y, z + 1, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 1, z + 1, ex, ey, ez, level, registry) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y + 1, z + 1, ex, ey, ez, level, registry); - } - } - - public static boolean fastAABBRayCheck( - double bx, double by, double bz, - double x, double y, double z, - double ex, double ey, double ez, - WorldAccessor level, RegistryAccessor registry) { - double fx = ex - x; - double fy = ey - y; - double fz = ez - z; - double absFx = Math.abs(fx); - double absFy = Math.abs(fy); - double absFz = Math.abs(fz); - double s = Math.max(absFx, Math.max(absFy, absFz)); - - if (s < 1) { - return true; // on top / inside - } - - double lx, ly, lz; - - fx = fx / s; // units of change along vector - fy = fy / s; - fz = fz / s; - - while (s > 0) { - ex = ex - fx; // move along vector, we start _at_ the eye and move towards b - ey = ey - fy; - ez = ez - fz; - lx = Math.floor(ex); - ly = Math.floor(ey); - lz = Math.floor(ez); - if (lx == bx && ly == by && lz == bz) { - return true; // we've reached our starting block, don't test it. - } - int blockId = level.getBlockState((int) lx, (int) ly, (int) lz); - if (blockId != 0 && registry.isOccluding(blockId)) { - return false; // fail on first hit, this ray is "blocked" - } - s--; // we stop - } - return true; - } -} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java new file mode 100644 index 00000000..3be65a69 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java @@ -0,0 +1,97 @@ +package dev.imprex.orebfuscator.proximity; + +import dev.imprex.orebfuscator.interop.RegistryAccessor; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.EntityPose; +import dev.imprex.orebfuscator.util.QuickMaths; + +public class ProximityRayCaster { + + private final RegistryAccessor registry; + private final WorldAccessor level; + private final boolean onlyCheckCenter; + + public ProximityRayCaster(RegistryAccessor registry, WorldAccessor level) { + this.registry = registry; + this.level = level; + this.onlyCheckCenter = level.config().proximity().rayCastCheckOnlyCheckCenter(); + } + + public boolean isVisible(EntityPose origin, BlockPos target) { + if (this.onlyCheckCenter) { + return canRayPass(origin, target, 0.5, 0.5, 0.5); + } + + // midfaces (6) + return canRayPass(origin, target, 0.0, 0.5, 0.5) + || canRayPass(origin, target, 0.5, 0.0, 0.5) + || canRayPass(origin, target, 0.5, 0.5, 0.0) + || canRayPass(origin, target, 0.5, 1.0, 0.5) + || canRayPass(origin, target, 0.5, 0.5, 1.0) + || canRayPass(origin, target, 1.0, 0.5, 0.5) + + // corners (8) + || canRayPass(origin, target, 0.0, 0.0, 0.0) + || canRayPass(origin, target, 1.0, 0.0, 0.0) + || canRayPass(origin, target, 0.0, 1.0, 0.0) + || canRayPass(origin, target, 1.0, 1.0, 0.0) + || canRayPass(origin, target, 0.0, 0.0, 1.0) + || canRayPass(origin, target, 1.0, 0.0, 1.0) + || canRayPass(origin, target, 0.0, 1.0, 1.0) + || canRayPass(origin, target, 1.0, 1.0, 1.0); + } + + private boolean canRayPass(EntityPose origin, BlockPos target, double offsetX, double offsetY, double offsetZ) { + double tx = target.x() + offsetX; + double ty = target.y() + offsetY; + double tz = target.z() + offsetZ; + + double dx = origin.x() - tx; + double dy = origin.y() - ty; + double dz = origin.z() - tz; + + double maxAbs = Math.max(Math.abs(dx), Math.max(Math.abs(dy), Math.abs(dz))); + // on top / inside + if (maxAbs < 1) { + return true; + } + + // step in "dominant-axis" units + dx /= maxAbs; + dy /= maxAbs; + dz /= maxAbs; + + // our current position + double cx = origin.x(); + double cy = origin.y(); + double cz = origin.z(); + + // position of current block + int x, y, z; + + for (int steps = (int) Math.ceil(maxAbs); steps > 0; steps--) { + // move from origin toward target + cx -= dx; + cy -= dy; + cz -= dz; + + x = (int) QuickMaths.floor(cx); + y = (int) QuickMaths.floor(cy); + z = (int) QuickMaths.floor(cz); + + // check if we reached our target block + if (x == target.x() && y == target.y() && z == target.z()) { + return true; + } + + int blockId = level.getBlockState(x, y, z); + // fail on first hit, this ray is "blocked" + if (registry.isOccluding(blockId)) { + return false; + } + } + + return true; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java index 363c820a..f8e8f403 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java @@ -19,12 +19,10 @@ public class ProximityWorker { - private final OrebfuscatorCore orebfuscator; private final OrebfuscatorConfig config; private final RegistryAccessor registry; public ProximityWorker(OrebfuscatorCore orebfuscator) { - this.orebfuscator = orebfuscator; this.config = orebfuscator.config(); this.registry = orebfuscator.getRegistry(); } @@ -97,6 +95,9 @@ private void process(PlayerAccessor player) { double lavaDistance = player.lavaFogDistance(); double lavaDistanceSquared = lavaDistance * lavaDistance; + + ProximityRayCaster rayCaster = proximityConfig.rayCastCheckEnabled() + ? new ProximityRayCaster(registry, world) : null; for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) { for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) { @@ -147,8 +148,7 @@ private void process(PlayerAccessor player) { } // do ray cast check - if (proximityConfig.rayCastCheckEnabled() && !FastGazeUtil.doFastCheck(blockPos, eyeLocation, world, - orebfuscator.getRegistry(), proximityConfig.rayCastCheckOnlyCheckCenter())) { + if (rayCaster != null && !rayCaster.isVisible(eyeLocation, blockPos)) { continue; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java index e041c337..1faff2db 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/accessor/DefaultMethodAccessor.java @@ -3,7 +3,6 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Method; import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.NullMarked; record DefaultMethodAccessor(@NonNull Method member, @NonNull MethodHandle methodHandle) implements MethodAccessor { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java index 83628514..ecca6930 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/EntityPose.java @@ -1,23 +1,24 @@ package dev.imprex.orebfuscator.util; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import dev.imprex.orebfuscator.interop.WorldAccessor; -// TODO: nullability +@NullMarked public record EntityPose(@Nullable WorldAccessor world, double x, double y, double z, float rotX, float rotY) { public static final EntityPose ZERO = new EntityPose(null, 0, 0, 0, 0, 0); public int blockX() { - return MathUtil.floor(this.x); + return QuickMaths.floor(this.x); } public int blockY() { - return MathUtil.floor(this.y); + return QuickMaths.floor(this.y); } public int blockZ() { - return MathUtil.floor(this.z); + return QuickMaths.floor(this.z); } public double distanceSquared(EntityPose other) { 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 96% 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 476c2e79..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--; 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 index 3280e9e9..a5486fa2 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingAverage.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingAverage.java @@ -6,9 +6,10 @@ 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; -// TODO: nullability +@NullMarked public class RollingAverage { private static final VarHandle BUFFER_HANDLE = MethodHandles.arrayElementVarHandle(double[].class); 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 index b040f9a3..7771caa5 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java @@ -1,8 +1,9 @@ package dev.imprex.orebfuscator.util; import java.util.concurrent.CompletionStage; +import org.jspecify.annotations.NullMarked; -// TODO: nullability +@NullMarked public class RollingTimer extends RollingAverage { public RollingTimer(int capacity) { 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 05fd845e..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,11 +3,12 @@ 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 */ -// TODO: nullability +@NullMarked public class SimpleCache extends LinkedHashMap { private final int maximumSize; 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 419690a2..d1530283 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 @@ -14,7 +14,7 @@ public record Version(int major, int minor, int patch) 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) 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 index b52f4853..20c9e13b 100644 --- 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 @@ -7,10 +7,12 @@ import java.util.concurrent.ScheduledExecutorService; 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; -// TODO: nullability, public schedule method +// TODO: public schedule method +@NullMarked public class OrebfuscatorExecutor implements Executor { private final ScheduledExecutorService scheduledExecutorService = 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 index 5c4c3fea..f334185b 100644 --- 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 @@ -4,10 +4,11 @@ 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; -// TODO: nullability +@NullMarked public class OrebfuscatorThread extends Thread implements UncaughtExceptionHandler { private static final SplittableGenerator ROOT_GENERATOR = SplittableGenerator.of("L64X128StarStarRandom"); 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..cde371db 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 @@ -3,13 +3,14 @@ import java.lang.reflect.Constructor; import org.bukkit.World; import org.bukkit.entity.Player; +import org.jspecify.annotations.Nullable; 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 net.imprex.orebfuscator.nms.NmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; import net.imprex.orebfuscator.util.MinecraftVersion; import net.imprex.orebfuscator.util.ServerVersion; @@ -63,6 +64,10 @@ public static boolean isAir(int blockId) { return instance.isAir(blockId); } + public static boolean isLava(int blockId) { + return instance.isLava(blockId); + } + public static boolean isOccluding(int blockId) { return instance.isOccluding(blockId); } @@ -71,8 +76,12 @@ 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 ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { + return instance.getChunkAccessor(world, chunkX, chunkZ); + } + + public static @Nullable ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ) { + return instance.tryGetChunkAccessor(world, chunkX, chunkZ); } public static int getBlockState(World world, BlockPos position) { 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 c9dd0963..38758611 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 @@ -4,15 +4,16 @@ import java.util.Map; import org.bukkit.World; import org.bukkit.entity.Player; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.interop.ChunkAccessor; 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 org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.util.QuickMaths; @NullMarked public abstract class AbstractNmsManager implements NmsManager { @@ -53,7 +54,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]; } @@ -95,6 +96,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(); @@ -104,4 +110,9 @@ public final boolean isOccluding(int id) { public final boolean isBlockEntity(int id) { return this.blockStates[id].isBlockEntity(); } + + @Override + public @Nullable ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ) { + throw new UnsupportedOperationException(); + } } 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..ed18fc61 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 @@ -2,9 +2,10 @@ import org.bukkit.World; import org.bukkit.entity.Player; - +import org.jspecify.annotations.Nullable; 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; @@ -12,7 +13,9 @@ public interface NmsManager extends RegistryAccessor { AbstractRegionFileCache createRegionFileCache(Config config); - ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ); + ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ); + + @Nullable ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ); int getBlockState(World world, int x, int y, int z); 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-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 index 3e97717b..fd075f5c 100644 --- 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 @@ -18,13 +18,13 @@ 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 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; @@ -83,6 +83,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)) @@ -115,7 +116,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ChunkProviderServer chunkProviderServer = level(world).getChunkProvider(); Chunk chunk = chunkProviderServer.getChunkAt(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); 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 index ff4a535f..68664ff6 100644 --- 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 @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_16_R1; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.server.v1_16_R1.Chunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final Chunk chunk; 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 index 497cd2f1..e7cc4f1f 100644 --- 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 @@ -20,7 +20,7 @@ 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 dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.server.v1_16_R2.Block; import net.minecraft.server.v1_16_R2.BlockAccessAir; import net.minecraft.server.v1_16_R2.BlockPosition; @@ -82,6 +82,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)) @@ -114,7 +115,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ChunkProviderServer chunkProviderServer = level(world).getChunkProvider(); Chunk chunk = chunkProviderServer.getChunkAt(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); 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 index ce66968f..d34605b8 100644 --- 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 @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_16_R2; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.server.v1_16_R2.Chunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final Chunk chunk; 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..4862bd91 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 @@ -20,7 +20,7 @@ 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 dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockAccessAir; import net.minecraft.server.v1_16_R3.BlockPosition; @@ -82,6 +82,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)) @@ -114,7 +115,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ChunkProviderServer chunkProviderServer = level(world).getChunkProvider(); Chunk chunk = chunkProviderServer.getChunkAt(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); 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/ReadOnlyChunkWrapper.java index 1fb7a511..e9a3fbf8 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/ReadOnlyChunkWrapper.java @@ -1,9 +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 { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final Chunk chunk; 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..ea496330 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 @@ -19,7 +19,7 @@ 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 dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; @@ -80,6 +80,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)) @@ -112,7 +113,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkProvider(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); 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 index 290da572..69e73457 100644 --- 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 @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_17_R1; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; 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..cabfb642 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 @@ -20,7 +20,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; @@ -82,6 +82,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)) @@ -114,7 +115,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/ReadOnlyChunkWrapper.java index 67796e6c..38519080 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_18_R1; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java index fb33df14..3951a3a4 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java @@ -22,7 +22,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; @@ -81,6 +81,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)) @@ -111,7 +112,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/ReadOnlyChunkWrapper.java index 6fd0ed7f..8948f582 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_18_R2; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java index c662f8c3..f1438133 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/ReadOnlyChunkWrapper.java index 669bdedf..37529a31 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_19_R1; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java index 7b808b80..e5fc5798 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/ReadOnlyChunkWrapper.java index 88f7fe04..a6f0f650 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_19_R2; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java index 275f4e2c..94dcf144 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/ReadOnlyChunkWrapper.java index 129b5aa0..dd41aca6 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_19_R3; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java index 2232640f..479c3e7b 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/ReadOnlyChunkWrapper.java index 906c43cc..bd3d6d99 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R1; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java index 3a112683..987bf567 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/ReadOnlyChunkWrapper.java index 739b574e..cd66cd63 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R2; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java index 92c99455..3381cc75 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/ReadOnlyChunkWrapper.java index 2288e982..f747824a 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R3; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java index 18d807d5..aa34a0a6 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java index 09bb28f3..af640a51 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R4; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java index 7535db94..5b0235d1 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -80,6 +80,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)) @@ -110,7 +111,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/ReadOnlyChunkWrapper.java index cbab6e42..7613e16a 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R1; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java index 231f7482..780212aa 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java @@ -20,7 +20,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -78,6 +78,7 @@ public NmsManager() { for (BlockState blockState : possibleBlockStates) { BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState)) .withIsAir(blockState.isAir()) + .withIsLava(block == Blocks.LAVA) .withIsOccluding(blockState.isSolidRender()) .withIsBlockEntity(blockState.hasBlockEntity()) .withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState)) @@ -108,7 +109,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java index 7da016f6..59de9739 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R2; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java index 0ee52c66..62930138 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java @@ -20,7 +20,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -78,6 +78,7 @@ public NmsManager() { for (BlockState blockState : possibleBlockStates) { BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState)) .withIsAir(blockState.isAir()) + .withIsLava(block == Blocks.LAVA) .withIsOccluding(blockState.isSolidRender()) .withIsBlockEntity(blockState.hasBlockEntity()) .withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState)) @@ -108,7 +109,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/ReadOnlyChunkWrapper.java index 09a4e436..7c096175 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R3; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java index 3845684e..2625c0ac 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java @@ -20,7 +20,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -78,6 +78,7 @@ public NmsManager() { for (BlockState blockState : possibleBlockStates) { BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState)) .withIsAir(blockState.isAir()) + .withIsLava(block == Blocks.LAVA) .withIsOccluding(blockState.isSolidRender()) .withIsBlockEntity(blockState.hasBlockEntity()) .withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState)) @@ -108,7 +109,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/ReadOnlyChunkWrapper.java index 62ded1a9..47de6fee 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R4; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java index ba4cdedd..aad87cb2 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java @@ -20,7 +20,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -78,6 +78,7 @@ public NmsManager() { for (BlockState blockState : possibleBlockStates) { BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState)) .withIsAir(blockState.isAir()) + .withIsLava(block == Blocks.LAVA) .withIsOccluding(blockState.isSolidRender()) .withIsBlockEntity(blockState.hasBlockEntity()) .withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState)) @@ -108,7 +109,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/ReadOnlyChunkWrapper.java index 3d2e02f2..29751811 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R5; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java index ea8f01ec..f94eec73 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java @@ -20,7 +20,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -78,6 +78,7 @@ public NmsManager() { for (BlockState blockState : possibleBlockStates) { BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState)) .withIsAir(blockState.isAir()) + .withIsLava(block == Blocks.LAVA) .withIsOccluding(blockState.isSolidRender()) .withIsBlockEntity(blockState.hasBlockEntity()) .withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState)) @@ -108,7 +109,7 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/ReadOnlyChunkWrapper.java index be1e2d6b..52a3fa3b 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R6; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java index 4eceab57..fb90ae6b 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java @@ -8,12 +8,9 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - import org.bukkit.World; import org.bukkit.entity.Player; - import com.google.common.collect.ImmutableList; - import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; import dev.imprex.orebfuscator.config.api.Config; import dev.imprex.orebfuscator.util.BlockProperties; @@ -23,7 +20,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -81,6 +78,7 @@ public NmsManager() { for (BlockState blockState : possibleBlockStates) { BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState)) .withIsAir(blockState.isAir()) + .withIsLava(block == Blocks.LAVA) .withIsOccluding(blockState.isSolidRender()) .withIsBlockEntity(blockState.hasBlockEntity()) .withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState)) @@ -111,12 +109,19 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); return new ReadOnlyChunkWrapper(chunk); } + @Override + public ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ) { + ServerChunkCache serverChunkCache = level(world).getChunkSource(); + LevelChunk chunk = serverChunkCache.getChunkNow(chunkX, chunkZ); + return chunk != null ? new ReadOnlyChunkWrapper(chunk) : null; + } + @Override public int getBlockState(World world, int x, int y, int z) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/ReadOnlyChunkWrapper.java index 9df0f7c8..ac486727 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/ReadOnlyChunkWrapper.java @@ -1,9 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R7; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.world.level.chunk.LevelChunk; -public class ReadOnlyChunkWrapper implements ReadOnlyChunk { +public class ReadOnlyChunkWrapper implements ChunkAccessor { private final LevelChunk chunk; diff --git a/orebfuscator-plugin/pom.xml b/orebfuscator-plugin/pom.xml index 31b7f455..faf9de80 100644 --- a/orebfuscator-plugin/pom.xml +++ b/orebfuscator-plugin/pom.xml @@ -98,7 +98,7 @@ compile - org.lz4 + at.yawk.lz4 lz4-java ${dependency.lz4.version} compile @@ -136,7 +136,7 @@ joml - org.lz4 + at.yawk.lz4 lz4-java diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/DefaultOrebfuscatorService.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/DefaultOrebfuscatorService.java index 1aec2fd7..ac9ae59b 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/DefaultOrebfuscatorService.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/DefaultOrebfuscatorService.java @@ -2,10 +2,8 @@ import java.util.Collection; import java.util.Iterator; - import org.bukkit.World; import org.bukkit.block.Block; - import net.imprex.orebfuscator.api.OrebfuscatorService; import net.imprex.orebfuscator.obfuscation.ObfuscationSystem; diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java index 86d0ccd3..200177c2 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java @@ -11,7 +11,7 @@ import org.bukkit.Bukkit; import dev.imprex.orebfuscator.config.OrebfuscatorConfig; -import dev.imprex.orebfuscator.util.MathUtil; +import dev.imprex.orebfuscator.util.QuickMaths; public class MetricsSystem { @@ -32,8 +32,8 @@ public MetricsSystem(Orebfuscator orebfuscator) { this.metrics = new Metrics(orebfuscator, 8942); this.addMemoryChart(); this.addPlayerCountChart(); - this.addConfigCharts(orebfuscator.getOrebfuscatorConfig()); - this.addUsageCharts(orebfuscator.getOrebfuscatorConfig()); + this.addConfigCharts(orebfuscator.config()); + this.addUsageCharts(orebfuscator.config()); } public void addMemoryChart() { @@ -47,7 +47,7 @@ public void addMemoryChart() { } else { float gibiByte = Math.round(memory / 1073741824f * 100f) / 100f; exact.put(gibiByte + "GiB", 1); - result.put(MathUtil.ceilToPowerOfTwo((int) gibiByte) + "GiB", exact); + result.put(QuickMaths.ceilToPowerOfTwo((int) gibiByte) + "GiB", exact); } return result; diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index 32831d6c..4dc61791 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -2,7 +2,6 @@ import java.nio.file.Path; import java.util.List; - import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; @@ -12,37 +11,49 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; - +import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; +import dev.imprex.orebfuscator.cache.ObfuscationCache; import dev.imprex.orebfuscator.chunk.ChunkFactory; import dev.imprex.orebfuscator.config.OrebfuscatorConfig; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; import dev.imprex.orebfuscator.interop.RegistryAccessor; -import dev.imprex.orebfuscator.interop.ServerAccessor; import dev.imprex.orebfuscator.interop.WorldAccessor; import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; +import dev.imprex.orebfuscator.obfuscation.ObfuscationProcessor; +import dev.imprex.orebfuscator.proximity.ProximityDirectorThread; +import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics; +import dev.imprex.orebfuscator.statistics.StatisticsRegistry; import dev.imprex.orebfuscator.util.Version; +import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorExecutor; import net.imprex.orebfuscator.api.OrebfuscatorService; -import net.imprex.orebfuscator.cache.ObfuscationCache; import net.imprex.orebfuscator.iterop.BukkitLoggerAccessor; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.obfuscation.ObfuscationSystem; -import net.imprex.orebfuscator.player.OrebfuscatorPlayerMap; -import net.imprex.orebfuscator.proximity.ProximityDirectorThread; import net.imprex.orebfuscator.proximity.ProximityPacketListener; import net.imprex.orebfuscator.util.MinecraftVersion; -public class Orebfuscator extends JavaPlugin implements Listener, ServerAccessor { +public class Orebfuscator extends JavaPlugin implements Listener, OrebfuscatorCore { public static final ThreadGroup THREAD_GROUP = new ThreadGroup("orebfuscator"); - private OrebfuscatorStatistics statistics; + private StatisticsRegistry statisticsRegistry; private OrebfuscatorConfig config; - private OrebfuscatorPlayerMap playerMap; - private UpdateSystem updateSystem; + private OrebfuscatorStatistics statistics; + private OrebfuscatorExecutor executor; + + private ChunkFactory chunkFactory; + private ObfuscationProcessor obfuscationProcessor; private ObfuscationCache obfuscationCache; + private ObfuscationPipeline obfuscationPipeline; private ObfuscationSystem obfuscationSystem; + private ProximityDirectorThread proximityThread; private ProximityPacketListener proximityPacketListener; - private ChunkFactory chunkFactory; + + private UpdateSystem updateSystem; @Override public void onLoad() { @@ -52,53 +63,43 @@ public void onLoad() { @Override public void onEnable() { try { - // Check for valid minecraft version if (MinecraftVersion.isBelow("1.16")) { throw new RuntimeException("Orebfuscator only supports minecraft 1.16 and above"); } - // Check if protocolLib is enabled Plugin protocolLib = getServer().getPluginManager().getPlugin("ProtocolLib"); if (protocolLib == null || !protocolLib.isEnabled()) { throw new RuntimeException("ProtocolLib can't be found or is disabled! Orebfuscator can't be enabled."); } - BukkitWorldAccessor.registerListener(this); - - this.statistics = new OrebfuscatorStatistics(); + this.statisticsRegistry = new StatisticsRegistry(); - // Load configurations + BukkitWorldAccessor.registerListener(this); OrebfuscatorNms.initialize(); this.config = new OrebfuscatorConfig(this); OrebfuscatorCompatibility.initialize(this, config); + BukkitPlayerAccessor.registerListener(this); - this.playerMap = new OrebfuscatorPlayerMap(this); - - // Initialize metrics new MetricsSystem(this); - - // initialize update system and check for updates this.updateSystem = new UpdateSystem(this); - // Load chunk cache - this.obfuscationCache = new ObfuscationCache(this); - - // Load obfuscater + this.statistics = new OrebfuscatorStatistics(this.config, this.statisticsRegistry); + this.executor = new OrebfuscatorExecutor(this); + this.chunkFactory = new ChunkFactory(this); + this.obfuscationProcessor = new ObfuscationProcessor(this); + this.obfuscationCache = new ObfuscationCache(this); + this.obfuscationPipeline = new ObfuscationPipeline(this); this.obfuscationSystem = new ObfuscationSystem(this); - // Load proximity hider this.proximityThread = new ProximityDirectorThread(this); if (this.config.proximityEnabled()) { this.proximityThread.start(); - this.proximityPacketListener = new ProximityPacketListener(this); } // Load packet listener this.obfuscationSystem.registerChunkListener(); - - // Store formatted config this.config.store(); // initialize service @@ -147,36 +148,56 @@ public void onEnableFailed(Listener listener, Event event) { } } - public OrebfuscatorStatistics getStatistics() { - return statistics; + public UpdateSystem updateSystem() { + return updateSystem; } - public OrebfuscatorConfig getOrebfuscatorConfig() { - return this.config; + public ObfuscationSystem getObfuscationSystem() { + return obfuscationSystem; } - public OrebfuscatorPlayerMap getPlayerMap() { - return playerMap; + public StatisticsRegistry statisticsRegistry() { + return statisticsRegistry; } - public UpdateSystem getUpdateSystem() { - return updateSystem; + @Override + public OrebfuscatorExecutor executor() { + return executor; } - public ObfuscationCache getObfuscationCache() { - return this.obfuscationCache; + @Override + public OrebfuscatorStatistics statistics() { + return statistics; } - public ObfuscationSystem getObfuscationSystem() { - return obfuscationSystem; + @Override + public OrebfuscatorConfig config() { + return config; } - public ProximityPacketListener getProximityPacketListener() { - return this.proximityPacketListener; + @Override + public ChunkFactory chunkFactory() { + return chunkFactory; } - public ChunkFactory getChunkFactory() { - return chunkFactory; + @Override + public ObfuscationCache cache() { + return obfuscationCache; + } + + @Override + public ObfuscationPipeline obfuscationPipeline() { + return obfuscationPipeline; + } + + @Override + public ObfuscationProcessor obfuscationProcessor() { + return obfuscationProcessor; + } + + @Override + public boolean isGameThread() { + return OrebfuscatorCompatibility.isGameThread(); } @Override @@ -190,8 +211,8 @@ public Path getWorldDirectory() { } @Override - public String getOrebfuscatorVersion() { - return getDescription().getVersion(); + public Version getOrebfuscatorVersion() { + return Version.parse(getDescription().getVersion()); } @Override @@ -204,10 +225,28 @@ public RegistryAccessor getRegistry() { return OrebfuscatorNms.registry(); } + @Override + public AbstractRegionFileCache createRegionFileCache() { + return OrebfuscatorNms.createRegionFileCache(config); + } + @Override public List getWorlds() { return BukkitWorldAccessor.getWorlds().stream() .map(WorldAccessor.class::cast) .toList(); } + + @Override + public List getPlayers() { + return BukkitPlayerAccessor.getAll().stream() + .map(PlayerAccessor.class::cast) + .toList(); + } + + @Override + public String toString() { + var meta = getDescription(); + return String.format("%s %s", meta.getName(), meta.getVersion()); + } } \ No newline at end of file diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java index 6797f618..313d9248 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java @@ -62,7 +62,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St if (args.length == 0) { sender.sendMessage("You are using " + this.orebfuscator.toString()); - sender.sendMessage(this.orebfuscator.getStatistics().toString()); + sender.sendMessage(this.orebfuscator.statisticsRegistry().format()); } else if (args[0].equalsIgnoreCase("dump")) { TemporalAccessor now = OffsetDateTime.now(ZoneOffset.UTC); @@ -78,7 +78,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St versions.addProperty("orebfuscator", orebfuscator.toString()); root.add("versions", versions); - root.add("statistics", orebfuscator.getStatistics().toJson()); + root.add("statistics", orebfuscator.statisticsRegistry().json()); JsonObject plugins = new JsonObject(); for (Plugin bukkitPlugin : Bukkit.getPluginManager().getPlugins()) { @@ -110,7 +110,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } root.add("listeners", listeners); - root.add("blocks", orebfuscator.getOrebfuscatorConfig().toJson()); + root.add("blocks", orebfuscator.config().toJson()); Base64.Encoder encoder = Base64.getUrlEncoder(); @@ -125,7 +125,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St e.printStackTrace(); } - String configReport = orebfuscator.getOrebfuscatorConfig().report(); + String configReport = orebfuscator.config().report(); configReport = configReport != null ? configReport : ""; root.addProperty("configReport", encoder.encodeToString(configReport.getBytes(StandardCharsets.UTF_8))); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java deleted file mode 100644 index 849eda64..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java +++ /dev/null @@ -1,200 +0,0 @@ -package net.imprex.orebfuscator; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.LongSupplier; - -import com.google.gson.JsonObject; - -public class OrebfuscatorStatistics { - - private static String formatPrecent(double percent) { - return String.format("%.2f%%", percent * 100); - } - - private static String formatNanos(long time) { - if (time > 1000_000L) { - return String.format("%.1fms", time / 1000_000d); - } else if (time > 1000L) { - return String.format("%.1fµs", time / 1000d); - } else { - return String.format("%dns", time); - } - } - - private static String formatBytes(long bytes) { - if (bytes > 1073741824L) { - return String.format("%.1f GiB", bytes / 1073741824d); - } else if (bytes > 1048576L) { - return String.format("%.1f MiB", bytes / 1048576d); - } else if (bytes > 1024L) { - return String.format("%.1f KiB", bytes / 1024d); - } else { - return String.format("%d B", bytes); - } - } - - private final AtomicLong cacheHitCountMemory = new AtomicLong(0); - private final AtomicLong cacheHitCountDisk = new AtomicLong(0); - private final AtomicLong cacheMissCount = new AtomicLong(0); - private final AtomicLong cacheEstimatedSize = new AtomicLong(0); - private LongSupplier memoryCacheSize = () -> 0; - private LongSupplier diskCacheQueueLength = () -> 0; - private LongSupplier obfuscationQueueLength = () -> 0; - private LongSupplier obfuscationWaitTime = () -> 0; - private LongSupplier obfuscationProcessTime = () -> 0; - private LongSupplier proximityWaitTime = () -> 0; - private LongSupplier proximityProcessTime = () -> 0; - private LongSupplier originalChunkSize = () -> 0; - private LongSupplier obfuscatedChunkSize = () -> 0; - - public void onCacheHitMemory() { - this.cacheHitCountMemory.incrementAndGet(); - } - - public void onCacheHitDisk() { - this.cacheHitCountDisk.incrementAndGet(); - } - - public void onCacheMiss() { - this.cacheMissCount.incrementAndGet(); - } - - public void onCacheSizeChange(int delta) { - this.cacheEstimatedSize.addAndGet(delta); - } - - public void setMemoryCacheSizeSupplier(LongSupplier supplier) { - this.memoryCacheSize = Objects.requireNonNull(supplier); - } - - public void setDiskCacheQueueLengthSupplier(LongSupplier supplier) { - this.diskCacheQueueLength = Objects.requireNonNull(supplier); - } - - public void setObfuscationQueueLengthSupplier(LongSupplier supplier) { - this.obfuscationQueueLength = Objects.requireNonNull(supplier); - } - - public void setObfuscationWaitTime(LongSupplier supplier) { - this.obfuscationWaitTime = Objects.requireNonNull(supplier); - } - - public void setObfuscationProcessTime(LongSupplier supplier) { - this.obfuscationProcessTime = Objects.requireNonNull(supplier); - } - - public void setProximityWaitTime(LongSupplier supplier) { - this.proximityWaitTime = Objects.requireNonNull(supplier); - } - - public void setProximityProcessTime(LongSupplier supplier) { - this.proximityProcessTime = Objects.requireNonNull(supplier); - } - - public void setOriginalChunkSize(LongSupplier supplier) { - this.originalChunkSize = Objects.requireNonNull(supplier); - } - - public void setObfuscatedChunkSize(LongSupplier supplier) { - this.obfuscatedChunkSize = Objects.requireNonNull(supplier); - } - - @Override - public String toString() { - long cacheHitCountMemory = this.cacheHitCountMemory.get(); - long cacheHitCountDisk = this.cacheHitCountDisk.get(); - long cacheMissCount = this.cacheMissCount.get(); - long cacheEstimatedSize = this.cacheEstimatedSize.get(); - long memoryCacheSize = this.memoryCacheSize.getAsLong(); - long diskCacheQueueLength = this.diskCacheQueueLength.getAsLong(); - long obfuscationQueueLength = this.obfuscationQueueLength.getAsLong(); - - double totalCacheRequest = (double) (cacheHitCountMemory + cacheHitCountDisk + cacheMissCount); - - double memoryCacheHitRate = 0.0d; - double diskCacheHitRate = 0.0d; - if (totalCacheRequest > 0) { - memoryCacheHitRate = (double) cacheHitCountMemory / totalCacheRequest; - diskCacheHitRate = (double) cacheHitCountDisk / totalCacheRequest; - } - - long memoryCacheBytesPerEntry = 0; - if (memoryCacheSize > 0) { - memoryCacheBytesPerEntry = cacheEstimatedSize / memoryCacheSize; - } - - StringBuilder builder = new StringBuilder("Here are some useful statistics:\n"); - - builder.append(" - memoryCacheHitRate: ").append(formatPrecent(memoryCacheHitRate)).append('\n'); - builder.append(" - diskCacheHitRate: ").append(formatPrecent(diskCacheHitRate)).append('\n'); - builder.append(" - memoryCacheEstimatedSize: ").append(formatBytes(cacheEstimatedSize)).append('\n'); - builder.append(" - memoryCacheBytesPerEntry: ").append(formatBytes(memoryCacheBytesPerEntry)).append('\n'); - builder.append(" - memoryCacheEntries: ").append(memoryCacheSize).append('\n'); - builder.append(" - diskCacheQueueLength: ").append(diskCacheQueueLength).append('\n'); - builder.append(" - obfuscationQueueLength: ").append(obfuscationQueueLength).append('\n'); - - long obfuscationWaitTime = this.obfuscationWaitTime.getAsLong(); - long obfuscationProcessTime = this.obfuscationProcessTime.getAsLong(); - long obfuscationTotalTime = obfuscationWaitTime + obfuscationProcessTime; - - double obfuscationUtilization = 0; - if (obfuscationTotalTime > 0) { - obfuscationUtilization = (double) obfuscationProcessTime / obfuscationTotalTime; - } - - builder.append(" - obfuscation (wait/process/utilization): ") - .append(formatNanos(obfuscationWaitTime)).append(" | ") - .append(formatNanos(obfuscationProcessTime)).append(" | ") - .append(formatPrecent(obfuscationUtilization)).append('\n'); - - long proximityWaitTime = this.proximityWaitTime.getAsLong(); - long proximityProcessTime = this.proximityProcessTime.getAsLong(); - long proximityTotalTime = proximityWaitTime + proximityProcessTime; - - double proximityUtilization = 0; - if (proximityTotalTime > 0) { - proximityUtilization = (double) proximityProcessTime / proximityTotalTime; - } - - builder.append(" - proximity (wait/process/utilization): ") - .append(formatNanos(proximityWaitTime)).append(" | ") - .append(formatNanos(proximityProcessTime)).append(" | ") - .append(formatPrecent(proximityUtilization)).append('\n'); - - long originalChunkSize = this.originalChunkSize.getAsLong(); - long obfuscatedChunkSize = this.obfuscatedChunkSize.getAsLong(); - - double ratio = 1; - if (originalChunkSize > 0) { - ratio = (double) obfuscatedChunkSize / originalChunkSize; - } - - builder.append(" - chunk size (original/obfuscated/ratio): ") - .append(formatBytes(originalChunkSize)).append(" | ") - .append(formatBytes(obfuscatedChunkSize)).append(" | ") - .append(formatPrecent(ratio)).append('\n'); - - return builder.toString(); - } - - public JsonObject toJson() { - JsonObject object = new JsonObject(); - - object.addProperty("cacheHitCountMemory", this.cacheHitCountMemory.get()); - object.addProperty("cacheHitCountDisk", this.cacheHitCountDisk.get()); - object.addProperty("cacheMissCount", this.cacheMissCount.get()); - object.addProperty("cacheEstimatedSize", this.cacheEstimatedSize.get()); - object.addProperty("memoryCacheSize", this.memoryCacheSize.getAsLong()); - object.addProperty("diskCacheQueueLength", this.diskCacheQueueLength.getAsLong()); - object.addProperty("obfuscationQueueLength", this.obfuscationQueueLength.getAsLong()); - object.addProperty("obfuscationWaitTime", this.obfuscationWaitTime.getAsLong()); - object.addProperty("obfuscationProcessTime", this.obfuscationProcessTime.getAsLong()); - object.addProperty("proximityWaitTime", this.proximityWaitTime.getAsLong()); - object.addProperty("proximityProcessTime", this.proximityProcessTime.getAsLong()); - object.addProperty("originalChunkSize", this.originalChunkSize.getAsLong()); - object.addProperty("obfuscatedChunkSize", this.obfuscatedChunkSize.getAsLong()); - - return object; - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java index 957983ca..603b3b03 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java @@ -54,7 +54,7 @@ public UpdateSystem(Orebfuscator orebfuscator) { super(orebfuscator); this.orebfuscator = orebfuscator; - this.generalConfig = orebfuscator.getOrebfuscatorConfig().general(); + this.generalConfig = orebfuscator.config().general(); this.checkForUpdates(); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java deleted file mode 100644 index 598d16c6..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/AsyncChunkSerializer.java +++ /dev/null @@ -1,181 +0,0 @@ -package net.imprex.orebfuscator.cache; - -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - - -import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; -import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.util.ChunkCacheKey; -import net.imprex.orebfuscator.Orebfuscator; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * This class works similar to a bounded buffer for cache read and write requests but also functions as the only - * consumer of said buffer. All requests can get reorder similar to modern memory access reordering in CPUs. If for - * example a write request is already in the buffer and a new read request for the same position is created then the - * read request doesn't get put in the buffer and gets completed with the content of the write request. - * - * @see Bound buffer - * @see Memory ordering - */ -@NullMarked -public class AsyncChunkSerializer implements Runnable { - - private final Lock lock = new ReentrantLock(true); - private final Condition notFull = lock.newCondition(); - private final Condition notEmpty = lock.newCondition(); - - private final Map tasks = new HashMap<>(); - private final Queue positions = new LinkedList<>(); - - private final int maxTaskQueueSize; - private final ChunkSerializer serializer; - - private final Thread thread; - private volatile boolean running = true; - - public AsyncChunkSerializer(Orebfuscator orebfuscator, AbstractRegionFileCache regionFileCache) { - this.maxTaskQueueSize = orebfuscator.getOrebfuscatorConfig().cache().maximumTaskQueueSize(); - this.serializer = new ChunkSerializer(regionFileCache); - - this.thread = new Thread(Orebfuscator.THREAD_GROUP, this, "ofc-chunk-serializer"); - this.thread.setDaemon(true); - this.thread.start(); - - orebfuscator.getStatistics().setDiskCacheQueueLengthSupplier(this.tasks::size); - } - - public CompletableFuture read(ChunkCacheKey key) { - this.lock.lock(); - try { - Runnable task = this.tasks.get(key); - if (task instanceof WriteTask) { - return CompletableFuture.completedFuture(((WriteTask) task).chunk); - } else if (task instanceof ReadTask) { - return ((ReadTask) task).future; - } else { - CompletableFuture future = new CompletableFuture<>(); - this.queueTask(key, new ReadTask(key, future)); - return future; - } - } finally { - this.lock.unlock(); - } - } - - public void write(ChunkCacheKey key, CacheChunkEntry chunk) { - this.lock.lock(); - try { - Runnable prevTask = this.queueTask(key, new WriteTask(key, chunk)); - if (prevTask instanceof ReadTask) { - ((ReadTask) prevTask).future.complete(chunk); - } - } finally { - this.lock.unlock(); - } - } - - private @Nullable Runnable queueTask(ChunkCacheKey key, Runnable nextTask) { - while (this.positions.size() >= this.maxTaskQueueSize) { - this.notFull.awaitUninterruptibly(); - } - - if (!this.running) { - throw new IllegalStateException("AsyncChunkSerializer already closed"); - } - - Runnable prevTask = this.tasks.put(key, nextTask); - if (prevTask == null) { - this.positions.offer(key); - } - - this.notEmpty.signal(); - return prevTask; - } - - @Override - public void run() { - while (this.running) { - this.lock.lock(); - try { - while (this.positions.isEmpty()) { - this.notEmpty.await(); - } - - this.tasks.remove(this.positions.poll()).run(); - - this.notFull.signal(); - } catch (InterruptedException e) { - break; - } finally { - this.lock.unlock(); - } - } - } - - public void close() { - this.lock.lock(); - try { - this.running = false; - this.thread.interrupt(); - - while (!this.positions.isEmpty()) { - Runnable task = this.tasks.remove(this.positions.poll()); - if (task instanceof WriteTask) { - task.run(); - } - } - } finally { - this.lock.unlock(); - } - } - - private class WriteTask implements Runnable { - - private final ChunkCacheKey key; - private final CacheChunkEntry chunk; - - public WriteTask(ChunkCacheKey key, CacheChunkEntry chunk) { - this.key = key; - this.chunk = chunk; - } - - @Override - public void run() { - try { - serializer.write(key, chunk); - } catch (IOException e) { - OfcLogger.error(e); - } - } - } - - private class ReadTask implements Runnable { - - private final ChunkCacheKey key; - private final CompletableFuture future; - - public ReadTask(ChunkCacheKey key, CompletableFuture future) { - this.key = key; - this.future = future; - } - - @Override - public void run() { - try { - future.complete(serializer.read(key)); - } catch (IOException e) { - future.completeExceptionally(e); - } - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheChunkEntry.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheChunkEntry.java deleted file mode 100644 index 7458ad49..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheChunkEntry.java +++ /dev/null @@ -1,110 +0,0 @@ -package net.imprex.orebfuscator.cache; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Optional; - -import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.ChunkCacheKey; -import net.imprex.orebfuscator.obfuscation.ObfuscationRequest; -import net.imprex.orebfuscator.obfuscation.ObfuscationResult; -import net.jpountz.lz4.LZ4BlockInputStream; -import net.jpountz.lz4.LZ4BlockOutputStream; - -public class CacheChunkEntry { - - public static CacheChunkEntry create(ObfuscationResult result) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - - try ( - LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(byteArrayOutputStream); - DataOutputStream dataOutputStream = new DataOutputStream(lz4BlockOutputStream)) { - - byteArrayOutputStream.write(result.getHash()); - - byte[] data = result.getData(); - dataOutputStream.writeInt(data.length); - dataOutputStream.write(data, 0, data.length); - - Collection proximityBlocks = result.getProximityBlocks(); - dataOutputStream.writeInt(proximityBlocks.size()); - for (BlockPos blockPosition : proximityBlocks) { - dataOutputStream.writeInt(blockPosition.toSectionPos()); - } - - Collection removedEntities = result.getBlockEntities(); - dataOutputStream.writeInt(removedEntities.size()); - for (BlockPos blockPosition : removedEntities) { - dataOutputStream.writeInt(blockPosition.toSectionPos()); - } - } catch (Exception e) { - new IOException("Unable to compress chunk: " + result.getCacheKey(), e).printStackTrace(); - return null; - } - - return new CacheChunkEntry(result.getCacheKey(), byteArrayOutputStream.toByteArray()); - } - - private final ChunkCacheKey key; - private final byte[] compressedData; - - public CacheChunkEntry(ChunkCacheKey key, byte[] data) { - this.key = key; - this.compressedData = data; - } - - public byte[] compressedData() { - return compressedData; - } - - public int estimatedSize() { - return 128 + this.compressedData.length; - } - - public boolean isValid(ObfuscationRequest request) { - try { - return request != null && Arrays.equals(this.compressedData, 0, ObfuscationRequest.HASH_LENGTH, - request.getChunkHash(), 0, ObfuscationRequest.HASH_LENGTH); - } catch (Exception e) { - throw new RuntimeException("unable to validate", e); - } - } - - public Optional toResult() { - try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.compressedData); - LZ4BlockInputStream lz4BlockInputStream = new LZ4BlockInputStream(byteArrayInputStream); - DataInputStream dataInputStream = new DataInputStream(lz4BlockInputStream)) { - - byte[] hash = Arrays.copyOf(this.compressedData, ObfuscationRequest.HASH_LENGTH); - byteArrayInputStream.skip(ObfuscationRequest.HASH_LENGTH); - - byte[] data = new byte[dataInputStream.readInt()]; - dataInputStream.readFully(data); - - ObfuscationResult result = new ObfuscationResult(this.key, hash, data); - - int x = this.key.x() << 4; - int z = this.key.z() << 4; - - Collection proximityBlocks = result.getProximityBlocks(); - for (int i = dataInputStream.readInt(); i > 0; i--) { - proximityBlocks.add(BlockPos.fromSectionPos(x, z, dataInputStream.readInt())); - } - - Collection removedEntities = result.getBlockEntities(); - for (int i = dataInputStream.readInt(); i > 0; i--) { - removedEntities.add(BlockPos.fromSectionPos(x, z, dataInputStream.readInt())); - } - - return Optional.of(result); - } catch (Exception e) { - new IOException("Unable to decompress chunk: " + this.key, e).printStackTrace(); - return Optional.empty(); - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheFileCleanupTask.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheFileCleanupTask.java deleted file mode 100644 index 2f68c385..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/CacheFileCleanupTask.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.imprex.orebfuscator.cache; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; - -import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; -import dev.imprex.orebfuscator.config.api.CacheConfig; -import dev.imprex.orebfuscator.logging.OfcLogger; -import net.imprex.orebfuscator.Orebfuscator; - -public class CacheFileCleanupTask implements Runnable { - - private final CacheConfig cacheConfig; - private final AbstractRegionFileCache regionFileCache; - - private int deleteCount = 0; - - public CacheFileCleanupTask(Orebfuscator orebfuscator, AbstractRegionFileCache regionFileCache) { - this.cacheConfig = orebfuscator.getOrebfuscatorConfig().cache(); - this.regionFileCache = regionFileCache; - } - - @Override - public void run() { - if (Files.notExists(this.cacheConfig.baseDirectory())) { - OfcLogger.debug("Skipping CacheFileCleanupTask as the cache directory doesn't exist."); - return; - } - - long deleteAfterMillis = this.cacheConfig.deleteRegionFilesAfterAccess(); - - this.deleteCount = 0; - - try { - Files.walkFileTree(this.cacheConfig.baseDirectory(), new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) throws IOException { - if (System.currentTimeMillis() - attributes.lastAccessTime().toMillis() > deleteAfterMillis) { - regionFileCache.close(path); - Files.delete(path); - - CacheFileCleanupTask.this.deleteCount++; - OfcLogger.debug("deleted cache file: " + path); - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - e.printStackTrace(); - } - - if (this.deleteCount > 0) { - OfcLogger.info(String.format("CacheFileCleanupTask successfully deleted %d cache file(s)", this.deleteCount)); - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java deleted file mode 100644 index 872c675a..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ChunkSerializer.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.imprex.orebfuscator.cache; - -import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; -import dev.imprex.orebfuscator.util.ChunkCacheKey; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -@NullMarked -public record ChunkSerializer(AbstractRegionFileCache regionFileCache) { - - private static final int CACHE_VERSION = 2; - - public @Nullable CacheChunkEntry read(ChunkCacheKey key) throws IOException { - try (DataInputStream dataInputStream = this.regionFileCache.createInputStream(key)) { - if (dataInputStream != null) { - // check if cache entry has right version and if chunk is present - if (dataInputStream.readInt() != CACHE_VERSION || !dataInputStream.readBoolean()) { - return null; - } - - byte[] compressedData = new byte[dataInputStream.readInt()]; - dataInputStream.readFully(compressedData); - - return new CacheChunkEntry(key, compressedData); - } - } catch (IOException e) { - throw new IOException("Unable to read chunk: " + key, e); - } - - return null; - } - - public void write(ChunkCacheKey key, @Nullable CacheChunkEntry value) throws IOException { - try (DataOutputStream dataOutputStream = this.regionFileCache.createOutputStream(key)) { - dataOutputStream.writeInt(CACHE_VERSION); - - if (value != null) { - dataOutputStream.writeBoolean(true); - - byte[] compressedData = value.compressedData(); - dataOutputStream.writeInt(compressedData.length); - dataOutputStream.write(compressedData); - } else { - dataOutputStream.writeBoolean(false); - } - } catch (IOException e) { - throw new IOException("Unable to write chunk: " + key, e); - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java deleted file mode 100644 index 1ca233a3..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/cache/ObfuscationCache.java +++ /dev/null @@ -1,143 +0,0 @@ -package net.imprex.orebfuscator.cache; - -import dev.imprex.orebfuscator.logging.OfcLogger; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalNotification; - -import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; -import dev.imprex.orebfuscator.config.api.CacheConfig; -import dev.imprex.orebfuscator.util.ChunkCacheKey; -import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.OrebfuscatorCompatibility; -import net.imprex.orebfuscator.OrebfuscatorNms; -import net.imprex.orebfuscator.OrebfuscatorStatistics; -import net.imprex.orebfuscator.obfuscation.ObfuscationRequest; -import net.imprex.orebfuscator.obfuscation.ObfuscationResult; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -@NullMarked -public class ObfuscationCache { - - private final OrebfuscatorStatistics statistics; - - private final AbstractRegionFileCache regionFileCache; - private final Cache cache; - private final @Nullable AsyncChunkSerializer serializer; - - public ObfuscationCache(Orebfuscator orebfuscator) { - CacheConfig cacheConfig = orebfuscator.getOrebfuscatorConfig().cache(); - this.statistics = orebfuscator.getStatistics(); - - this.cache = CacheBuilder.newBuilder() - .maximumSize(cacheConfig.maximumSize()) - .expireAfterAccess(cacheConfig.expireAfterAccess(), TimeUnit.MILLISECONDS) - .removalListener(this::onRemoval) - .build(); - this.statistics.setMemoryCacheSizeSupplier(this.cache::size); - - this.regionFileCache = OrebfuscatorNms.createRegionFileCache(orebfuscator.getOrebfuscatorConfig()); - - if (cacheConfig.enableDiskCache()) { - this.serializer = new AsyncChunkSerializer(orebfuscator, regionFileCache); - } else { - this.serializer = null; - } - - if (cacheConfig.enabled() && cacheConfig.deleteRegionFilesAfterAccess() > 0) { - OrebfuscatorCompatibility.runAsyncAtFixedRate(new CacheFileCleanupTask(orebfuscator, regionFileCache), 0, 72000L); - } - } - - private void onRemoval(RemovalNotification notification) { - this.statistics.onCacheSizeChange(-notification.getValue().estimatedSize()); - - // don't serialize invalidated chunks since this would require locking the main - // thread and wouldn't bring a huge improvement - if (this.serializer != null && notification.wasEvicted() && !OrebfuscatorCompatibility.isGameThread()) { - this.serializer.write(notification.getKey(), notification.getValue()); - } - } - - private void requestObfuscation(ObfuscationRequest request) { - request.submitForObfuscation().thenAccept(chunk -> { - var compressedChunk = CacheChunkEntry.create(chunk); - if (compressedChunk != null) { - this.cache.put(request.getCacheKey(), compressedChunk); - this.statistics.onCacheSizeChange(compressedChunk.estimatedSize()); - } - }); - } - - public CompletableFuture get(ObfuscationRequest request) { - ChunkCacheKey key = request.getCacheKey(); - - CacheChunkEntry cacheChunk = this.cache.getIfPresent(key); - if (cacheChunk != null && cacheChunk.isValid(request)) { - this.statistics.onCacheHitMemory(); - - // complete request - cacheChunk.toResult().ifPresentOrElse(request::complete, - // request obfuscation if decoding failed - () -> this.requestObfuscation(request)); - } - // only access disk cache if we couldn't find the chunk in memory cache - else if (cacheChunk == null && this.serializer != null) { - this.serializer.read(key).whenComplete((diskChunk, throwable) -> { - if (diskChunk != null && diskChunk.isValid(request)) { - this.statistics.onCacheHitDisk(); - - // add valid disk cache entry to in-memory cache - this.cache.put(key, diskChunk); - this.statistics.onCacheSizeChange(diskChunk.estimatedSize()); - - // complete request - diskChunk.toResult().ifPresentOrElse(request::complete, - // request obfuscation if decoding failed - () -> this.requestObfuscation(request)); - } else { - this.statistics.onCacheMiss(); - - // request obfuscation if disk cache missing - this.requestObfuscation(request); - } - - // request future doesn't care about serializer failure because - // we simply request obfuscation on failure - if (throwable != null) { - OfcLogger.error(throwable); - } - }); - } - // request obfuscation if cache missed - else { - this.statistics.onCacheMiss(); - this.requestObfuscation(request); - } - - return request.getFuture(); - } - - public void invalidate(ChunkCacheKey key) { - this.cache.invalidate(key); - } - - public void close() { - if (this.serializer != null) { - // flush memory cache to disk on shutdown - this.cache.asMap().entrySet().removeIf(entry -> { - this.serializer.write(entry.getKey(), entry.getValue()); - return true; - }); - - this.serializer.close(); - } - - this.regionFileCache.clear(); - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java index 7607703e..7dd35b79 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java @@ -4,14 +4,12 @@ import java.util.Iterator; import java.util.List; import java.util.function.Predicate; - import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.nbt.NbtBase; import com.comphenix.protocol.wrappers.nbt.NbtCompound; - import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; -import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationResponse; import dev.imprex.orebfuscator.util.BlockPos; import net.imprex.orebfuscator.util.MinecraftVersion; import net.imprex.orebfuscator.util.WrappedClientboundLevelChunkPacketData; @@ -22,8 +20,6 @@ public class BukkitChunkPacketAccessor implements ChunkPacketAccessor { private static final boolean HAS_HEIGHT_BITMASK = MinecraftVersion.isBelow("1.18"); private static final boolean HAS_VARINT_BITMASK = MinecraftVersion.isBelow("1.17"); - public final BukkitWorldAccessor worldAccessor; - private final int chunkX; private final int chunkZ; @@ -35,7 +31,6 @@ public class BukkitChunkPacketAccessor implements ChunkPacketAccessor { public BukkitChunkPacketAccessor(PacketContainer packet, BukkitWorldAccessor worldAccessor) { this.packet = packet; - this.worldAccessor = worldAccessor; StructureModifier packetInteger = packet.getIntegers(); this.chunkX = packetInteger.read(0); @@ -61,11 +56,6 @@ public BukkitChunkPacketAccessor(PacketContainer packet, BukkitWorldAccessor wor } } - @Override - public WorldAccessor world() { - return this.worldAccessor; - } - @Override public int chunkX() { return this.chunkX; @@ -87,26 +77,21 @@ public byte[] data() { } @Override - public void setData(byte[] data) { - if (this.packetData != null) { - this.packetData.setBuffer(data); - } else { - this.packet.getByteArrays().write(0, data); - } - } + public void update(ObfuscationResponse response) { + Predicate blockEntityPredicate = relativePostion -> + response.blockEntities().contains(relativePostion.add(chunkX << 4, 0, chunkZ << 4)); - @Override - public void filterBlockEntities(Predicate predicate) { if (this.packetData != null) { - this.packetData.removeBlockEntityIf(relativePostion -> - predicate.test(relativePostion.add(chunkX << 4, 0, chunkZ << 4))); + this.packetData.setBuffer(response.data()); + this.packetData.removeBlockEntityIf(blockEntityPredicate); } else { - removeTileEntitiesFromPacket(this.packet, predicate); + this.packet.getByteArrays().write(0, response.data()); + removeTileEntitiesFromPacket(blockEntityPredicate); } } - private void removeTileEntitiesFromPacket(PacketContainer packet, Predicate predicate) { - StructureModifier>> packetNbtList = packet.getListNbtModifier(); + private void removeTileEntitiesFromPacket(Predicate predicate) { + StructureModifier>> packetNbtList = this.packet.getListNbtModifier(); List> tileEntities = packetNbtList.read(0); this.removeTileEntities(tileEntities, predicate); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java index af1f972e..25a15f3f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java @@ -3,12 +3,10 @@ import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; - - -import dev.imprex.orebfuscator.logging.LogLevel; -import dev.imprex.orebfuscator.logging.LoggerAccessor; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.logging.LogLevel; +import dev.imprex.orebfuscator.logging.LoggerAccessor; @NullMarked public record BukkitLoggerAccessor(Logger logger) implements LoggerAccessor { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java new file mode 100644 index 00000000..fbd903f2 --- /dev/null +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java @@ -0,0 +1,147 @@ +package net.imprex.orebfuscator.iterop; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.potion.PotionEffectType; +import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.EntityPose; +import net.imprex.orebfuscator.Orebfuscator; +import net.imprex.orebfuscator.OrebfuscatorCompatibility; +import net.imprex.orebfuscator.OrebfuscatorNms; + +public class BukkitPlayerAccessor implements PlayerAccessor { + + private static final Map PLAYERS = new HashMap<>(); + + public static void registerListener(Orebfuscator orebfuscator) { + Bukkit.getPluginManager().registerEvents(new Listener() { + @EventHandler + public void onJoin(PlayerJoinEvent event) { + var player = event.getPlayer(); + var bukkitPlayer = PLAYERS.computeIfAbsent(player.getUniqueId(), + key -> new BukkitPlayerAccessor(orebfuscator, player)); + bukkitPlayer.orebfuscatorPlayer.clearChunks(); + } + + @EventHandler + public void onChangedWorld(PlayerChangedWorldEvent event) { + var player = event.getPlayer(); + var bukkitPlayer = PLAYERS.get(player.getUniqueId()); + if (bukkitPlayer != null) { + bukkitPlayer.world = BukkitWorldAccessor.get(player.getWorld()); + bukkitPlayer.orebfuscatorPlayer.clearChunks(); + } + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + PLAYERS.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler + public void onDisable(PluginDisableEvent event) { + if (event.getPlugin() == orebfuscator) { + PLAYERS.clear(); + } + } + }, orebfuscator); + + for (Player player : Bukkit.getOnlinePlayers()) { + var bukkitPlayer = PLAYERS.computeIfAbsent(player.getUniqueId(), + key -> new BukkitPlayerAccessor(orebfuscator, player)); + bukkitPlayer.orebfuscatorPlayer.clearChunks(); + } + } + + @Nullable + public static BukkitPlayerAccessor tryGet(Player player) { + try { + return PLAYERS.get(player.getUniqueId()); + } catch (UnsupportedOperationException e) { + // catch TemporaryPlayer not implementing getUniqueId + return null; + } + } + + public static List getAll() { + return PLAYERS.values().stream().toList(); + } + + private final Player player; + private BukkitWorldAccessor world; + + private final OrebfuscatorPlayer orebfuscatorPlayer; + + public BukkitPlayerAccessor(OrebfuscatorCore orebfuscator, Player player) { + this.player = player; + this.world = BukkitWorldAccessor.get(player.getWorld()); + this.orebfuscatorPlayer = new OrebfuscatorPlayer(orebfuscator, this); + } + + @Override + public OrebfuscatorPlayer orebfuscatorPlayer() { + return this.orebfuscatorPlayer; + } + + @Override + public EntityPose pose() { + var location = player.getLocation(); + return new EntityPose(world, location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw()); + } + + @Override + public EntityPose eyePose() { + var location = player.getEyeLocation(); + return new EntityPose(world, location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw()); + } + + @Override + public BukkitWorldAccessor world() { + return world; + } + + @Override + public boolean isAlive() { + return !player.isDead(); + } + + @Override + public boolean isSpectator() { + return player.getGameMode() == GameMode.SPECTATOR; + } + + @Override + public double lavaFogDistance() { + return player.hasPotionEffect(PotionEffectType.FIRE_RESISTANCE) ? 7 : 2; + } + + @Override + public boolean hasPermission(String permission) { + return player.hasPermission(permission); + } + + @Override + public void runForPlayer(Runnable runnable) { + OrebfuscatorCompatibility.runForPlayer(player, runnable); + } + + @Override + public void sendBlockUpdates(Iterable iterable) { + OrebfuscatorNms.sendBlockUpdates(player, iterable); + } +} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java index d89fce1e..b529503e 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java @@ -3,21 +3,27 @@ import java.util.Collection; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; - import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; -import org.bukkit.plugin.Plugin; - import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.MethodAccessor; - +import dev.imprex.orebfuscator.config.api.WorldConfigBundle; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import dev.imprex.orebfuscator.interop.WorldAccessor; import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; +import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.util.ChunkCacheKey; +import dev.imprex.orebfuscator.util.ChunkDirection; +import net.imprex.orebfuscator.Orebfuscator; +import net.imprex.orebfuscator.OrebfuscatorCompatibility; +import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.util.MinecraftVersion; public class BukkitWorldAccessor implements WorldAccessor { @@ -28,8 +34,7 @@ public class BukkitWorldAccessor implements WorldAccessor { public static BukkitWorldAccessor get(World world) { return ACCESSOR_LOOKUP.computeIfAbsent(world, key -> { - OfcLogger.warn("Created world accessor outside of event!"); - return new BukkitWorldAccessor(key); + throw new IllegalStateException("Created world accessor outside of event!"); }); } @@ -70,32 +75,36 @@ public static Collection getWorlds() { return ACCESSOR_LOOKUP.values(); } - public static void registerListener(Plugin plugin) { - for (World world : Bukkit.getWorlds()) { - ACCESSOR_LOOKUP.put(world, new BukkitWorldAccessor(world)); - } - + public static void registerListener(Orebfuscator orebfuscator) { Bukkit.getPluginManager().registerEvents(new Listener() { @EventHandler public void onWorldUnload(WorldLoadEvent event) { World world = event.getWorld(); - ACCESSOR_LOOKUP.put(world, new BukkitWorldAccessor(world)); + ACCESSOR_LOOKUP.put(world, new BukkitWorldAccessor(world, orebfuscator)); } @EventHandler public void onWorldUnload(WorldUnloadEvent event) { ACCESSOR_LOOKUP.remove(event.getWorld()); } - }, plugin); + }, orebfuscator); + + for (World world : Bukkit.getWorlds()) { + ACCESSOR_LOOKUP.put(world, new BukkitWorldAccessor(world, orebfuscator)); + } } public final World world; + private final Orebfuscator orebfuscator; private final int maxHeight; private final int minHeight; - private BukkitWorldAccessor(World world) { + private WorldConfigBundle worldConfigBundle; + + private BukkitWorldAccessor(World world, Orebfuscator orebfuscator) { this.world = Objects.requireNonNull(world); + this.orebfuscator = Objects.requireNonNull(orebfuscator); if (HAS_DYNAMIC_HEIGHT) { this.maxHeight = (int) WORLD_GET_MAX_HEIGHT.invoke(world); @@ -106,6 +115,14 @@ private BukkitWorldAccessor(World world) { } } + @Override + public WorldConfigBundle config() { + if (this.worldConfigBundle == null) { + this.worldConfigBundle = this.orebfuscator.config().world(this); + } + return this.worldConfigBundle; + } + @Override public String getName() { return this.world.getName(); @@ -146,6 +163,40 @@ public int getSectionIndex(int y) { return blockToSectionCoord(y) - getMinSection(); } + public ChunkAccessor[] getNeighboringChunks(int chunkX, int chunkZ) { + ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; + + for (ChunkDirection direction : ChunkDirection.values()) { + int x = chunkX + direction.getOffsetX(); + int z = chunkZ + direction.getOffsetZ(); + int index = direction.ordinal(); + + neighboringChunks[index] = OrebfuscatorNms.tryGetChunkAccessor(world, x, z); + } + + return neighboringChunks; + } + + @Override + public CompletableFuture getNeighboringChunks(ObfuscationRequest request) { + return OrebfuscatorCompatibility.getNeighboringChunks(world, new ChunkCacheKey(request)); + } + + @Override + public ChunkAccessor getChunk(int chunkX, int chunkZ) { + return OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); + } + + @Override + public int getBlockState(int x, int y, int z) { + return OrebfuscatorNms.getBlockState(world, x, y, z); + } + + @Override + public void sendBlockUpdates(Iterable iterable) { + OrebfuscatorNms.sendBlockUpdates(world, iterable); + } + @Override public int hashCode() { return this.world.hashCode(); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java index c8a0f08b..eeaaacae 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java @@ -18,7 +18,6 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; - import dev.imprex.orebfuscator.config.OrebfuscatorConfig; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.UpdateSystem; @@ -27,61 +26,61 @@ public class DeobfuscationListener implements Listener { - public static void createAndRegister(Orebfuscator orebfuscator, DeobfuscationWorker deobfuscationWorker) { - Listener listener = new DeobfuscationListener(orebfuscator, deobfuscationWorker); + public static void createAndRegister(Orebfuscator orebfuscator, ObfuscationSystem obfuscationSystem) { + Listener listener = new DeobfuscationListener(orebfuscator, obfuscationSystem); Bukkit.getPluginManager().registerEvents(listener, orebfuscator); } private final UpdateSystem updateSystem; private final OrebfuscatorConfig config; - private final DeobfuscationWorker deobfuscationWorker; + private final ObfuscationSystem obfuscationSystem; - private DeobfuscationListener(Orebfuscator orebfuscator, DeobfuscationWorker deobfuscationWorker) { - this.updateSystem = orebfuscator.getUpdateSystem(); - this.config = orebfuscator.getOrebfuscatorConfig(); - this.deobfuscationWorker = deobfuscationWorker; + private DeobfuscationListener(Orebfuscator orebfuscator, ObfuscationSystem obfuscationSystem) { + this.updateSystem = orebfuscator.updateSystem(); + this.config = orebfuscator.config(); + this.obfuscationSystem = obfuscationSystem; } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockDamage(BlockDamageEvent event) { if (this.config.general().updateOnBlockDamage()) { - this.deobfuscationWorker.deobfuscate(event.getBlock()); + this.obfuscationSystem.deobfuscate(event.getBlock()); } } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { - this.deobfuscationWorker.deobfuscate(event.getBlock()); + this.obfuscationSystem.deobfuscate(event.getBlock()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockBurn(BlockBurnEvent event) { - this.deobfuscationWorker.deobfuscate(event.getBlock()); + this.obfuscationSystem.deobfuscate(event.getBlock()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockExplode(BlockExplodeEvent event) { - this.deobfuscationWorker.deobfuscate(event.blockList(), true); + this.obfuscationSystem.deobfuscate(event.blockList()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockPistonExtend(BlockPistonExtendEvent event) { - this.deobfuscationWorker.deobfuscate(event.getBlocks(), true); + this.obfuscationSystem.deobfuscate(event.getBlocks()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockPistonRetract(BlockPistonRetractEvent event) { - this.deobfuscationWorker.deobfuscate(event.getBlocks(), true); + this.obfuscationSystem.deobfuscate(event.getBlocks()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onEntityExplode(EntityExplodeEvent event) { - this.deobfuscationWorker.deobfuscate(event.blockList(), true); + this.obfuscationSystem.deobfuscate(event.blockList()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onEntityChangeBlock(EntityChangeBlockEvent event) { - this.deobfuscationWorker.deobfuscate(event.getBlock()); + this.obfuscationSystem.deobfuscate(event.getBlock()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) @@ -90,7 +89,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { && event.getItem() != null && event.getItem().getType() != null) { Material material = event.getItem().getType(); if (material.name().endsWith("_HOE")) { - this.deobfuscationWorker.deobfuscate(event.getClickedBlock()); + this.obfuscationSystem.deobfuscate(event.getClickedBlock()); } } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java deleted file mode 100644 index 143333ce..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java +++ /dev/null @@ -1,110 +0,0 @@ -package net.imprex.orebfuscator.obfuscation; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import org.bukkit.World; -import org.bukkit.block.Block; - -import com.google.common.collect.Iterables; - -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; -import dev.imprex.orebfuscator.config.api.BlockFlags; -import dev.imprex.orebfuscator.config.api.ObfuscationConfig; -import dev.imprex.orebfuscator.config.api.WorldConfigBundle; -import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.ChunkCacheKey; -import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.OrebfuscatorNms; -import net.imprex.orebfuscator.cache.ObfuscationCache; -import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; - -public class DeobfuscationWorker { - - private final OrebfuscatorConfig config; - private final ObfuscationCache cache; - - public DeobfuscationWorker(Orebfuscator orebfuscator) { - this.config = orebfuscator.getOrebfuscatorConfig(); - this.cache = orebfuscator.getObfuscationCache(); - } - - void deobfuscate(Block block) { - if (block == null || !block.getType().isOccluding()) { - return; - } - - deobfuscate(Arrays.asList(block), true); - } - - public void deobfuscate(Collection blocks, boolean occluding) { - if (blocks.isEmpty()) { - return; - } - - World world = Iterables.get(blocks, 0).getWorld(); - BukkitWorldAccessor worldAccessor = BukkitWorldAccessor.get(world); - WorldConfigBundle bundle = this.config.world(worldAccessor); - - ObfuscationConfig obfuscationConfig = bundle.obfuscation(); - if (obfuscationConfig == null || !obfuscationConfig.isEnabled()) { - return; - } - - int updateRadius = this.config.general().updateRadius(); - BlockFlags blockFlags = bundle.blockFlags(); - - try (Processor processor = new Processor(worldAccessor, blockFlags)) { - for (Block block : blocks) { - if (!occluding || block.getType().isOccluding()) { - BlockPos position = new BlockPos(block.getX(), block.getY(), block.getZ()); - processor.processPosition(position, updateRadius); - } - } - } - } - - public class Processor implements AutoCloseable { - - private final Set updatedBlocks = new HashSet<>(); - private final Set invalidChunks = new HashSet<>(); - - private final BukkitWorldAccessor worldAccessor; - private final BlockFlags blockFlags; - - public Processor(BukkitWorldAccessor worldAccessor, BlockFlags blockFlags) { - this.worldAccessor = worldAccessor; - this.blockFlags = blockFlags; - } - - public void processPosition(BlockPos position, int depth) { - int blockId = OrebfuscatorNms.getBlockState(worldAccessor.world, position); - if (BlockFlags.isObfuscateBitSet(blockFlags.flags(blockId)) && updatedBlocks.add(position)) { - - // invalidate cache if enabled - if (config.cache().enabled()) { - ChunkCacheKey chunkPosition = new ChunkCacheKey(worldAccessor, position); - if (this.invalidChunks.add(chunkPosition)) { - cache.invalidate(chunkPosition); - } - } - } - - if (depth-- > 0) { - processPosition(position.add(1, 0, 0), depth); - processPosition(position.add(-1, 0, 0), depth); - processPosition(position.add(0, 1, 0), depth); - processPosition(position.add(0, -1, 0), depth); - processPosition(position.add(0, 0, 1), depth); - processPosition(position.add(0, 0, -1), depth); - } - } - - @Override - public void close() { - OrebfuscatorNms.sendBlockUpdates(worldAccessor.world, this.updatedBlocks); - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java index 959c41ba..c8b49f9d 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java @@ -3,34 +3,19 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; - -import org.bukkit.entity.Player; - import com.comphenix.protocol.AsynchronousManager; import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketTypeEnum; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.async.AsyncListenerHandler; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketEvent; - -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; -import dev.imprex.orebfuscator.config.api.AdvancedConfig; -import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.util.BlockPos; +import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; -import net.imprex.orebfuscator.player.OrebfuscatorPlayer; -import net.imprex.orebfuscator.player.OrebfuscatorPlayerMap; -import net.imprex.orebfuscator.util.PermissionUtil; -import net.imprex.orebfuscator.util.RollingAverage; import net.imprex.orebfuscator.util.ServerVersion; public class ObfuscationListener extends PacketAdapter { @@ -38,37 +23,34 @@ public class ObfuscationListener extends PacketAdapter { private static final List PACKET_TYPES = Arrays.asList( PacketType.Play.Server.MAP_CHUNK, PacketType.Play.Server.UNLOAD_CHUNK, + PacketType.Play.Server.CHUNKS_BIOMES, PacketType.Play.Server.LIGHT_UPDATE, PacketType.Play.Server.TILE_ENTITY_DATA, - tryGetPacketType(PacketType.Play.Client.getInstance(), "CHUNK_BATCH_RECEIVED") + PacketType.Play.Server.RESPAWN, + // PlayerList::sendLevelInfo + PacketType.Play.Server.INITIALIZE_BORDER, + PacketType.Play.Server.UPDATE_TIME, + PacketType.Play.Server.SPAWN_POSITION, + PacketType.Play.Server.GAME_STATE_CHANGE, + // Proximity hider updates + PacketType.Play.Server.BLOCK_CHANGE, + PacketType.Play.Server.MULTI_BLOCK_CHANGE, + // Clientbound packet + PacketType.Play.Client.CHUNK_BATCH_RECEIVED ); - private static PacketType tryGetPacketType(PacketTypeEnum packetTypeEnum, String name) { - return packetTypeEnum.values().stream() - .filter(packetType -> packetType.name().equals(name)) - .findAny() - .orElse(null); - } - - private final OrebfuscatorConfig config; - private final OrebfuscatorPlayerMap playerMap; - private final ObfuscationSystem obfuscationSystem; + private final ObfuscationPipeline pipeline; private final AsynchronousManager asynchronousManager; private final AsyncListenerHandler asyncListenerHandler; - private final RollingAverage originalSize = new RollingAverage(2048); - private final RollingAverage obfuscatedSize = new RollingAverage(2048); - public ObfuscationListener(Orebfuscator orebfuscator) { super(orebfuscator, PACKET_TYPES.stream() .filter(Objects::nonNull) .filter(PacketType::isSupported) .collect(Collectors.toList())); - this.config = orebfuscator.getOrebfuscatorConfig(); - this.playerMap = orebfuscator.getPlayerMap(); - this.obfuscationSystem = orebfuscator.getObfuscationSystem(); + this.pipeline = orebfuscator.obfuscationPipeline(); this.asynchronousManager = ProtocolLibrary.getProtocolManager().getAsynchronousManager(); this.asyncListenerHandler = this.asynchronousManager.registerAsyncHandler(this); @@ -78,10 +60,6 @@ public ObfuscationListener(Orebfuscator orebfuscator) { } else { this.asyncListenerHandler.start(); } - - var statistics = orebfuscator.getStatistics(); - statistics.setOriginalChunkSize(() -> (long) originalSize.average()); - statistics.setObfuscatedChunkSize(() -> (long) obfuscatedSize.average()); } public void unregister() { @@ -99,72 +77,31 @@ public void onPacketSending(PacketEvent event) { return; } - Player player = event.getPlayer(); - BukkitWorldAccessor worldAccessor = BukkitWorldAccessor.get(player.getWorld()); - if (this.shouldNotObfuscate(player, worldAccessor)) { + BukkitPlayerAccessor player = BukkitPlayerAccessor.tryGet(event.getPlayer()); + if (player == null || !player.isAlive()) { return; } - - var packet = new BukkitChunkPacketAccessor(event.getPacket(), worldAccessor); - if (packet.isEmpty()) { + + BukkitWorldAccessor world = player.world(); + if (player.hasPermission("orebfuscator.bypass") || !world.config().needsObfuscation()) { return; } - // delay packet - event.getAsyncMarker().incrementProcessingDelay(); - - CompletableFuture future = this.obfuscationSystem.obfuscate(packet); - - AdvancedConfig advancedConfig = this.config.advanced(); - if (advancedConfig.hasObfuscationTimeout()) { - future = future.orTimeout(advancedConfig.obfuscationTimeout(), TimeUnit.MILLISECONDS); + var packet = new BukkitChunkPacketAccessor(event.getPacket(), world); + if (packet.isEmpty()) { + return; } - future.whenComplete((chunk, throwable) -> { - if (throwable != null) { - this.completeExceptionally(event, packet, throwable); - } else if (chunk != null) { - this.complete(event, packet, chunk); - } else { - OfcLogger.warn(String.format("skipping chunk[world=%s, x=%d, z=%d] because obfuscation result is missing", - packet.worldAccessor.getName(), packet.chunkX(), packet.chunkZ())); + var neighboringChunks = world + .getNeighboringChunks(packet.chunkX(), packet.chunkZ()); + var future = pipeline.request(world, player, packet, neighboringChunks) + .toCompletableFuture(); + + if (!future.isDone()) { + event.getAsyncMarker().incrementProcessingDelay(); + future.whenComplete((result, throwable) -> { this.asynchronousManager.signalPacketTransmission(event); - } - }); - } - - private boolean shouldNotObfuscate(Player player, BukkitWorldAccessor worldAccessor) { - return PermissionUtil.canBypassObfuscate(player) || !config.world(worldAccessor).needsObfuscation(); - } - - private void completeExceptionally(PacketEvent event, BukkitChunkPacketAccessor packet, Throwable throwable) { - if (throwable instanceof TimeoutException) { - OfcLogger.warn(String.format("Obfuscation for chunk[world=%s, x=%d, z=%d] timed out", - packet.worldAccessor.getName(), packet.chunkX(), packet.chunkZ())); - } else { - OfcLogger.error(String.format("An error occurred while obfuscating chunk[world=%s, x=%d, z=%d]", - packet.worldAccessor.getName(), packet.chunkX(), packet.chunkZ()), throwable); + }); } - - this.asynchronousManager.signalPacketTransmission(event); - } - - private void complete(PacketEvent event, BukkitChunkPacketAccessor packet, ObfuscationResult chunk) { - originalSize.add(packet.data().length); - obfuscatedSize.add(chunk.getData().length); - - packet.setData(chunk.getData()); - - Set blockEntities = chunk.getBlockEntities(); - if (!blockEntities.isEmpty()) { - packet.filterBlockEntities(blockEntities::contains); - } - - final OrebfuscatorPlayer player = this.playerMap.get(event.getPlayer()); - if (player != null) { - player.addChunk(packet.chunkX(), packet.chunkZ(), chunk.getProximityBlocks()); - } - - this.asynchronousManager.signalPacketTransmission(event); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java deleted file mode 100644 index 5e38d2ed..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java +++ /dev/null @@ -1,161 +0,0 @@ -package net.imprex.orebfuscator.obfuscation; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import dev.imprex.orebfuscator.chunk.Chunk; -import dev.imprex.orebfuscator.chunk.ChunkFactory; -import dev.imprex.orebfuscator.chunk.ChunkSection; -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; -import dev.imprex.orebfuscator.config.ProximityHeightCondition; -import dev.imprex.orebfuscator.config.api.BlockFlags; -import dev.imprex.orebfuscator.config.api.ObfuscationConfig; -import dev.imprex.orebfuscator.config.api.ProximityConfig; -import dev.imprex.orebfuscator.config.api.WorldConfigBundle; -import dev.imprex.orebfuscator.interop.WorldAccessor; -import dev.imprex.orebfuscator.util.BlockPos; -import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.OrebfuscatorNms; -import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; - -public class ObfuscationProcessor { - - private final OrebfuscatorConfig config; - private final ChunkFactory chunkFactory; - - public ObfuscationProcessor(Orebfuscator orebfuscator) { - this.config = orebfuscator.getOrebfuscatorConfig(); - this.chunkFactory = orebfuscator.getChunkFactory(); - } - - public void process(ObfuscationTask task) { - BukkitChunkPacketAccessor packet = task.getPacket(); - - WorldAccessor worldAccessor = packet.worldAccessor; - - WorldConfigBundle bundle = this.config.world(worldAccessor); - BlockFlags blockFlags = bundle.blockFlags(); - ObfuscationConfig obfuscationConfig = bundle.obfuscation(); - ProximityConfig proximityConfig = bundle.proximity(); - - Set blockEntities = new HashSet<>(); - List proximityBlocks = new ArrayList<>(); - - int baseX = packet.chunkX() << 4; - int baseZ = packet.chunkZ() << 4; - - int layerY = Integer.MIN_VALUE; - int layerYBlockState = -1; - - try (Chunk chunk = this.chunkFactory.fromPacket(packet)) { - for (int sectionIndex = Math.max(0, bundle.minSectionIndex()); sectionIndex <= Math - .min(chunk.getSectionCount() - 1, bundle.maxSectionIndex()); sectionIndex++) { - ChunkSection chunkSection = chunk.getSection(sectionIndex); - if (chunkSection == null || chunkSection.isEmpty()) { - continue; - } - - final int baseY = worldAccessor.getMinBuildHeight() + (sectionIndex << 4); - for (int index = 0; index < 4096; index++) { - int y = baseY + (index >> 8 & 15); - if (!bundle.shouldObfuscate(y)) { - continue; - } - - int blockState = chunkSection.getBlockState(index); - - int obfuscateBits = blockFlags.flags(blockState, y); - if (BlockFlags.isEmpty(obfuscateBits)) { - continue; - } - - int x = baseX + (index & 15); - int z = baseZ + (index >> 4 & 15); - - boolean isObfuscateBitSet = BlockFlags.isObfuscateBitSet(obfuscateBits); - boolean obfuscated = false; - - // should current block be obfuscated - if (isObfuscateBitSet && obfuscationConfig.shouldObfuscate(y) && shouldObfuscate(task, chunk, x, y, z)) { - if (obfuscationConfig.layerObfuscation()) { - if (layerY != y) { - layerY = y; - layerYBlockState = bundle.nextRandomObfuscationBlock(y); - } - blockState = layerYBlockState; - } else { - blockState = bundle.nextRandomObfuscationBlock(y); - } - obfuscated = true; - } - - // should current block be proximity hidden - if (!obfuscated && BlockFlags.isProximityBitSet(obfuscateBits) && proximityConfig.shouldObfuscate(y)) { - proximityBlocks.add(new BlockPos(x, y, z)); - if (BlockFlags.isUseBlockBelowBitSet(obfuscateBits)) { - boolean allowNonOcclude = !isObfuscateBitSet || !ProximityHeightCondition.isPresent(obfuscateBits); - blockState = getBlockStateBelow(bundle, chunk, x, y, z, allowNonOcclude); - } else { - blockState = bundle.nextRandomProximityBlock(y); - } - obfuscated = true; - } - - // update block state if needed - if (obfuscated) { - chunkSection.setBlockState(index, blockState); - if (BlockFlags.isBlockEntityBitSet(obfuscateBits)) { - blockEntities.add(new BlockPos(x, y, z)); - } - } - } - } - - task.complete(chunk.finalizeOutput(), blockEntities, proximityBlocks); - } catch (Exception e) { - task.completeExceptionally(e); - } - } - - // returns first block below given position that wouldn't be obfuscated in any - // way at given position - private int getBlockStateBelow(WorldConfigBundle bundle, Chunk chunk, int x, int y, int z, boolean allowNonOcclude) { - BlockFlags blockFlags = bundle.blockFlags(); - - for (int targetY = y - 1; targetY > chunk.world().getMinBuildHeight(); targetY--) { - int blockData = chunk.getBlockState(x, targetY, z); - if (blockData != -1 && (allowNonOcclude || OrebfuscatorNms.isOccluding(blockData))) { - int mask = blockFlags.flags(blockData, y); - if (BlockFlags.isEmpty(mask) || BlockFlags.isAllowForUseBlockBelowBitSet(mask)) { - return blockData; - } - } - } - - return bundle.nextRandomProximityBlock(y); - } - - private boolean shouldObfuscate(ObfuscationTask task, Chunk chunk, int x, int y, int z) { - return isAdjacentBlockOccluding(task, chunk, x, y + 1, z) - && isAdjacentBlockOccluding(task, chunk, x, y - 1, z) - && isAdjacentBlockOccluding(task, chunk, x + 1, y, z) - && isAdjacentBlockOccluding(task, chunk, x - 1, y, z) - && isAdjacentBlockOccluding(task, chunk, x, y, z + 1) - && isAdjacentBlockOccluding(task, chunk, x, y, z - 1); - } - - private boolean isAdjacentBlockOccluding(ObfuscationTask task, Chunk chunk, int x, int y, int z) { - if (y >= chunk.world().getMaxBuildHeight() || y < chunk.world().getMinBuildHeight()) { - return false; - } - - int blockId = chunk.getBlockState(x, y, z); - if (blockId == -1) { - blockId = task.getBlockState(x, y, z); - } - - return blockId >= 0 && OrebfuscatorNms.isOccluding(blockId); - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationRequest.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationRequest.java deleted file mode 100644 index 644127f7..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationRequest.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.imprex.orebfuscator.obfuscation; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -import com.google.common.hash.HashFunction; -import com.google.common.hash.Hashing; - -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; -import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.ChunkCacheKey; -import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; - -public class ObfuscationRequest { - - private static final HashFunction HASH_FUNCTION = Hashing.murmur3_128(); - private static final byte[] EMPTY_HASH = new byte[0]; - - public static final int HASH_LENGTH = HASH_FUNCTION.bits() / Byte.SIZE; - - private static final byte[] hash(byte[] systemHash, byte[] data) { - return HASH_FUNCTION.newHasher().putBytes(systemHash).putBytes(data).hash().asBytes(); - } - - public static ObfuscationRequest fromChunk(BukkitChunkPacketAccessor packet, OrebfuscatorConfig config, - ObfuscationTaskDispatcher dispatcher) { - byte[] hash = config.cache().enabled() ? hash(config.systemHash(), packet.data()) : EMPTY_HASH; - return new ObfuscationRequest(dispatcher, packet, hash); - } - - private final CompletableFuture future = new CompletableFuture<>(); - - private final ObfuscationTaskDispatcher dispatcher; - private final BukkitChunkPacketAccessor packet; - - private final ChunkCacheKey chunkCacheKey; - private final byte[] chunkHash; - - private ObfuscationRequest(ObfuscationTaskDispatcher dispatcher, BukkitChunkPacketAccessor packet, byte[] chunkHash) { - this.dispatcher = dispatcher; - this.packet = packet; - - this.chunkCacheKey = new ChunkCacheKey(packet.world().getName(), packet.chunkX(), packet.chunkZ()); - this.chunkHash = chunkHash; - } - - public CompletableFuture getFuture() { - return future; - } - - public ChunkCacheKey getCacheKey() { - return chunkCacheKey; - } - - public byte[] getChunkHash() { - return chunkHash; - } - - public BukkitChunkPacketAccessor getPacket() { - return packet; - } - - public CompletableFuture submitForObfuscation() { - this.dispatcher.submitRequest(this); - return this.future; - } - - public ObfuscationResult createResult(byte[] data, Set blockEntities, List proximityBlocks) { - return new ObfuscationResult(this.chunkCacheKey, this.chunkHash, data, blockEntities, proximityBlocks); - } - - public CompletableFuture complete(ObfuscationResult result) { - this.future.complete(result); - return this.future; - } - - public CompletableFuture completeExceptionally(Throwable throwable) { - this.future.completeExceptionally(throwable); - return this.future; - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationResult.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationResult.java deleted file mode 100644 index 587ec42b..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationResult.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.imprex.orebfuscator.obfuscation; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.ChunkCacheKey; - -public class ObfuscationResult { - - private final ChunkCacheKey key; - - private final byte[] hash; - private final byte[] data; - - private final Set blockEntities; - private final List proximityBlocks; - - public ObfuscationResult(ChunkCacheKey key, byte[] hash, byte[] data) { - this(key, hash, data, new HashSet<>(), new ArrayList<>()); - } - - public ObfuscationResult(ChunkCacheKey key, byte[] hash, byte[] data, - Set blockEntities, List proximityBlocks) { - this.key = key; - this.hash = hash; - this.data = data; - this.blockEntities = blockEntities; - this.proximityBlocks = proximityBlocks; - } - - public ChunkCacheKey getCacheKey() { - return key; - } - - public byte[] getHash() { - return hash; - } - - public byte[] getData() { - return data; - } - - public Set getBlockEntities() { - return blockEntities; - } - - public List getProximityBlocks() { - return proximityBlocks; - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java index 66e2344d..2680dbac 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java @@ -1,58 +1,50 @@ package net.imprex.orebfuscator.obfuscation; import java.util.Collection; -import java.util.concurrent.CompletableFuture; - import org.bukkit.block.Block; - -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; +import dev.imprex.orebfuscator.obfuscation.DeobfuscationWorker; +import dev.imprex.orebfuscator.util.BlockPos; import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.cache.ObfuscationCache; -import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; +import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; public class ObfuscationSystem { private final Orebfuscator orebfuscator; - private final OrebfuscatorConfig config; - private final ObfuscationCache cache; - - private final ObfuscationProcessor processor; - private final ObfuscationTaskDispatcher dispatcher; private ObfuscationListener listener; private final DeobfuscationWorker deobfuscationWorker; public ObfuscationSystem(Orebfuscator orebfuscator) { this.orebfuscator = orebfuscator; - this.config = orebfuscator.getOrebfuscatorConfig(); - this.cache = orebfuscator.getObfuscationCache(); - - this.processor = new ObfuscationProcessor(orebfuscator); - this.dispatcher = new ObfuscationTaskDispatcher(orebfuscator, this.processor); this.deobfuscationWorker = new DeobfuscationWorker(orebfuscator); - DeobfuscationListener.createAndRegister(orebfuscator, this.deobfuscationWorker); + DeobfuscationListener.createAndRegister(orebfuscator, this); } public void registerChunkListener() { this.listener = new ObfuscationListener(orebfuscator); } - - public CompletableFuture obfuscate(BukkitChunkPacketAccessor packet) { - ObfuscationRequest request = ObfuscationRequest.fromChunk(packet, this.config, this.dispatcher); - if (this.config.cache().enabled()) { - return this.cache.get(request); - } else { - return request.submitForObfuscation(); - } + + public void deobfuscate(Block block) { + var world = BukkitWorldAccessor.get(block.getWorld()); + var blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); + this.deobfuscationWorker.deobfuscate(world, blockPos); } - + public void deobfuscate(Collection blocks) { - this.deobfuscationWorker.deobfuscate(blocks, false); + if (blocks.isEmpty()) { + return; + } + + var world = BukkitWorldAccessor.get(blocks.stream().findFirst().get().getWorld()); + var blockPos = blocks.stream() + .map(block -> new BlockPos(block.getX(), block.getY(), block.getZ())) + .toList(); + + this.deobfuscationWorker.deobfuscate(world, blockPos); } public void shutdown() { this.listener.unregister(); - this.dispatcher.shutdown(); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTask.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTask.java deleted file mode 100644 index 9d6423d2..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTask.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.imprex.orebfuscator.obfuscation; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -import org.bukkit.World; - -import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.ChunkCacheKey; -import dev.imprex.orebfuscator.util.ChunkDirection; -import net.imprex.orebfuscator.OrebfuscatorCompatibility; -import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; -import net.imprex.orebfuscator.nms.ReadOnlyChunk; - -public class ObfuscationTask { - - public static CompletableFuture fromRequest(ObfuscationRequest request) { - World world = request.getPacket().worldAccessor.world; - ChunkCacheKey key = request.getCacheKey(); - - return OrebfuscatorCompatibility.getNeighboringChunks(world, key) - .thenApply(chunks -> new ObfuscationTask(request, chunks)); - } - - private final ObfuscationRequest request; - private final ReadOnlyChunk[] neighboringChunks; - - private ObfuscationTask(ObfuscationRequest request, ReadOnlyChunk[] neighboringChunks) { - if (neighboringChunks == null || neighboringChunks.length != 4) { - throw new IllegalArgumentException("neighboringChunks missing or invalid length"); - } - - this.request = request; - this.neighboringChunks = neighboringChunks; - } - - public BukkitChunkPacketAccessor getPacket() { - return this.request.getPacket(); - } - - public void complete(byte[] data, Set blockEntities, List proximityBlocks) { - this.request.complete(this.request.createResult(data, blockEntities, proximityBlocks)); - } - - public void completeExceptionally(Throwable throwable) { - this.request.completeExceptionally(throwable); - } - - public int getBlockState(int x, int y, int z) { - ChunkDirection direction = ChunkDirection.fromPosition(request.getCacheKey(), x, z); - return this.neighboringChunks[direction.ordinal()].getBlockState(x, y, z); - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskDispatcher.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskDispatcher.java deleted file mode 100644 index 9bb68bff..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskDispatcher.java +++ /dev/null @@ -1,78 +0,0 @@ -package net.imprex.orebfuscator.obfuscation; - -import java.util.Arrays; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; - -import dev.imprex.orebfuscator.config.api.AdvancedConfig; -import net.imprex.orebfuscator.Orebfuscator; - -class ObfuscationTaskDispatcher { - - private static final long DEFAULT_PARK_DURATION = TimeUnit.MILLISECONDS.toNanos(1); - private static final long MAX_PARK_DURATION = TimeUnit.MILLISECONDS.toNanos(16); - - private final Queue tasks = new ConcurrentLinkedQueue<>(); - - private final ObfuscationProcessor processor; - private final ObfuscationTaskWorker[] worker; - - public ObfuscationTaskDispatcher(Orebfuscator orebfuscator, ObfuscationProcessor processor) { - this.processor = processor; - - AdvancedConfig config = orebfuscator.getOrebfuscatorConfig().advanced(); - this.worker = new ObfuscationTaskWorker[config.obfuscationThreads()]; - for (int i = 0; i < this.worker.length; i++) { - this.worker[i] = new ObfuscationTaskWorker(this, this.processor); - } - - var statistics = orebfuscator.getStatistics(); - statistics.setObfuscationQueueLengthSupplier(() -> this.tasks.size()); - statistics.setObfuscationWaitTime(() -> (long) Arrays.stream(this.worker) - .mapToDouble(ObfuscationTaskWorker::waitTime).average().orElse(0d)); - statistics.setObfuscationProcessTime(() -> (long) Arrays.stream(this.worker) - .mapToDouble(ObfuscationTaskWorker::processTime).average().orElse(0d)); - } - - public void submitRequest(ObfuscationRequest request) { - ObfuscationTask.fromRequest(request).whenComplete((task, throwable) -> { - if (throwable != null) { - request.completeExceptionally(throwable); - } else { - this.tasks.offer(task); - } - }); - } - - public ObfuscationTask retrieveTask() throws InterruptedException { - ObfuscationTask task; - - long parkDuration = DEFAULT_PARK_DURATION; - for (int i = 0; (task = this.tasks.poll()) == null; i++) { - if (i < 8192) { - Thread.onSpinWait(); - } else { - LockSupport.parkNanos(this, parkDuration); - - // exponential backoff - if (parkDuration < MAX_PARK_DURATION) { - parkDuration *= 2; - } - } - - if (Thread.interrupted()) { - throw new InterruptedException(); - } - } - - return task; - } - - public void shutdown() { - for (ObfuscationTaskWorker worker : this.worker) { - worker.shutdown(); - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskWorker.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskWorker.java deleted file mode 100644 index 61fbcbf2..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationTaskWorker.java +++ /dev/null @@ -1,67 +0,0 @@ -package net.imprex.orebfuscator.obfuscation; - -import java.util.concurrent.atomic.AtomicInteger; - -import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.util.RingTimer; - -class ObfuscationTaskWorker implements Runnable { - - private static final AtomicInteger WORKER_ID = new AtomicInteger(); - - private final ObfuscationTaskDispatcher dispatcher; - private final ObfuscationProcessor processor; - - private final Thread thread; - private volatile boolean running = true; - - private final RingTimer waitTimer = new RingTimer(100); - private final RingTimer processTimer = new RingTimer(100); - - public ObfuscationTaskWorker(ObfuscationTaskDispatcher dispatcher, ObfuscationProcessor processor) { - this.dispatcher = dispatcher; - this.processor = processor; - - this.thread = new Thread(Orebfuscator.THREAD_GROUP, this, "ofc-task-worker-" + WORKER_ID.getAndIncrement()); - this.thread.setDaemon(true); - this.thread.start(); - } - - public double waitTime() { - return waitTimer.average(); - } - - public double processTime() { - return processTimer.average(); - } - - @Override - public void run() { - while (this.running) { - try { - ObfuscationTask task; - - waitTimer.start(); - try { - task = dispatcher.retrieveTask(); - } finally { - waitTimer.stop(); - } - - processTimer.start(); - try { - processor.process(task); - } finally { - processTimer.stop(); - } - } catch (InterruptedException e) { - break; - } - } - } - - public void shutdown() { - this.running = false; - this.thread.interrupt(); - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayer.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayer.java deleted file mode 100644 index 4d343f31..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayer.java +++ /dev/null @@ -1,126 +0,0 @@ -package net.imprex.orebfuscator.player; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicReference; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import com.google.common.base.Objects; - -import dev.imprex.orebfuscator.config.api.AdvancedConfig; -import dev.imprex.orebfuscator.util.BlockPos; -import net.imprex.orebfuscator.Orebfuscator; - -public class OrebfuscatorPlayer { - - private static long chunkCoordsToLong(int chunkX, int chunkZ) { - return (chunkZ & 0xffffffffL) << 32 | chunkX & 0xffffffffL; - } - - private final Player player; - private final AdvancedConfig config; - - private final AtomicReference world = new AtomicReference<>(); - private final Map chunks = new ConcurrentHashMap<>(); - - private volatile long latestUpdateTimestamp = System.currentTimeMillis(); - private volatile Location location = new Location(null, 0, 0, 0); - - public OrebfuscatorPlayer(Orebfuscator orebfuscator, Player player) { - this.player = player; - this.config = orebfuscator.getOrebfuscatorConfig().advanced(); - this.location = player.getLocation(); - } - - /** - * Returns true if the last proximity update is longer ago then the configured proximity player interval (default 5s) - * or if the players location since the last update change according to the given rotation boolean and the - * {@link OrebfuscatorPlayer#isLocationSimilar isLocationSimilar} method. - * - * @param rotation passed to the isLocationSimilar method - * @return true if a proximity update is needed - */ - public boolean needsProximityUpdate(boolean rotation) { - if (!this.player.isOnline()) { - return false; - } - - long timestamp = System.currentTimeMillis(); - if (this.config.hasProximityPlayerCheckInterval() && - timestamp - this.latestUpdateTimestamp > this.config.proximityPlayerCheckInterval()) { - - // always update location + latestUpdateTimestamp on update - this.location = location; - this.latestUpdateTimestamp = timestamp; - - return true; - } - - Location location = this.player.getLocation(); - if (isLocationSimilar(rotation, this.location, location)) { - return false; - } - - // always update location + latestUpdateTimestamp on update - this.location = location; - this.latestUpdateTimestamp = timestamp; - - return true; - } - - /** - * Returns true if the worlds are the same and the distance between the locations is less then 0.5. If the rotation - * boolean is set this method also check if the yaw changed less then 10deg and the pitch less then 5deg. - * - * @param rotation should rotation be checked - * @param a the first location - * @param b the second location - * @return if the locations are similar - */ - private static boolean isLocationSimilar(boolean rotation, Location a, Location b) { - // check if world changed - if (!Objects.equal(a.getWorld(), b.getWorld())) { - return false; - } - - // check if len(xyz) changed less then 0.5 blocks - if (a.distanceSquared(b) > 0.25) { - return false; - } - - // check if rotation changed less then 5deg yaw or 2.5deg pitch - if (rotation && (Math.abs(a.getYaw() - b.getYaw()) > 5 || Math.abs(a.getPitch() - b.getPitch()) > 2.5)) { - return false; - } - - return true; - } - - void updateWorld() { - if (!this.player.isOnline()) { - return; - } - - World world = this.player.getWorld(); - if (!Objects.equal(this.world.getAndSet(world), world)) { - this.chunks.clear(); - } - } - - public void addChunk(int chunkX, int chunkZ, List blocks) { - this.chunks.put(chunkCoordsToLong(chunkX, chunkZ), - new OrebfuscatorPlayerChunk(chunkX, chunkZ, blocks)); - } - - public OrebfuscatorPlayerChunk getChunk(int chunkX, int chunkZ) { - return this.chunks.get(chunkCoordsToLong(chunkX, chunkZ)); - } - - public void removeChunk(int chunkX, int chunkZ) { - this.chunks.remove(chunkCoordsToLong(chunkX, chunkZ)); - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java deleted file mode 100644 index acff2eb1..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java +++ /dev/null @@ -1,81 +0,0 @@ -package net.imprex.orebfuscator.player; - -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import dev.imprex.orebfuscator.util.BlockPos; - -public class OrebfuscatorPlayerChunk { - - private final int chunkX; - private final int chunkZ; - - private int proximitySize; - private final int[] proximityBlocks; - - public OrebfuscatorPlayerChunk(int chunkX, int chunkZ, List proximityBlocks) { - this.chunkX = chunkX; - this.chunkZ = chunkZ; - - this.proximitySize = proximityBlocks.size(); - this.proximityBlocks = new int[proximityBlocks.size()]; - - for (int i = 0; i < proximityBlocks.size(); i++) { - this.proximityBlocks[i] = proximityBlocks.get(i).toSectionPos(); - } - } - - public boolean isEmpty() { - return proximitySize <= 0; - } - - public Iterator proximityIterator() { - return new ProximityItr(); - } - - private class ProximityItr implements Iterator { - - private final int x = chunkX << 4; - private final int z = chunkZ << 4; - - private int cursor; - private int returnCursor = -1; - - @Override - public boolean hasNext() { - return cursor < proximitySize; - } - - @Override - public BlockPos next() { - if (cursor >= proximitySize) { - throw new NoSuchElementException(); - } - - int sectionPos = proximityBlocks[returnCursor = cursor]; - cursor++; - - return BlockPos.fromSectionPos(x, z, sectionPos); - } - - @Override - public void remove() { - if (returnCursor < 0) { - throw new IllegalStateException(); - } - - // remove entry - final int index = returnCursor; - final int newSize; - if ((newSize = proximitySize - 1) > index) { - System.arraycopy(proximityBlocks, index + 1, proximityBlocks, index, newSize - index); - } - proximityBlocks[proximitySize = newSize] = 0xFFFFFFFF; - - // update cursor positions - cursor = returnCursor; - returnCursor = -1; - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerMap.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerMap.java deleted file mode 100644 index 2025bcf0..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/player/OrebfuscatorPlayerMap.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.imprex.orebfuscator.player; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import net.imprex.orebfuscator.Orebfuscator; - -public class OrebfuscatorPlayerMap implements Listener { - - private final Orebfuscator orebfuscator; - - private final ConcurrentMap internalMap = new ConcurrentHashMap<>(); - - public OrebfuscatorPlayerMap(Orebfuscator orebfuscator) { - this.orebfuscator = orebfuscator; - if (orebfuscator.getOrebfuscatorConfig().proximityEnabled()) { - Bukkit.getPluginManager().registerEvents(this, orebfuscator); - - for (Player player : Bukkit.getOnlinePlayers()) { - this.addPlayer(player); - } - } - } - - private void addPlayer(Player player) { - this.internalMap.put(player, new OrebfuscatorPlayer(orebfuscator, player)); - } - - @EventHandler - public void onJoin(PlayerJoinEvent event) { - this.addPlayer(event.getPlayer()); - } - - @EventHandler - public void onQuit(PlayerQuitEvent event) { - this.internalMap.remove(event.getPlayer()); - } - - public OrebfuscatorPlayer get(Player player) { - OrebfuscatorPlayer orebfuscatorPlayer = this.internalMap.get(player); - if (orebfuscatorPlayer != null) { - orebfuscatorPlayer.updateWorld(); - } - return orebfuscatorPlayer; - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityDirectorThread.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityDirectorThread.java deleted file mode 100644 index 0261e720..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityDirectorThread.java +++ /dev/null @@ -1,187 +0,0 @@ -package net.imprex.orebfuscator.proximity; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.Phaser; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; - -import dev.imprex.orebfuscator.config.api.AdvancedConfig; -import net.imprex.orebfuscator.Orebfuscator; -import dev.imprex.orebfuscator.logging.OfcLogger; -import net.imprex.orebfuscator.util.RingTimer; - -public class ProximityDirectorThread extends Thread implements Listener { - - private final Orebfuscator orebfuscator; - private final int workerCount; - private final int defaultBucketSize; - private final long checkInterval; - - private final Phaser phaser = new Phaser(1); - private volatile boolean running = true; - - private final ProximityWorker worker; - private final ProximityWorkerThread[] workerThreads; - - private final BlockingQueue> bucketQueue = new LinkedBlockingQueue<>(); - - private final RingTimer waitTimer = new RingTimer(100); - private final RingTimer processTimer = new RingTimer(100); - - public ProximityDirectorThread(Orebfuscator orebfuscator) { - super(Orebfuscator.THREAD_GROUP, "ofc-proximity-director"); - this.setDaemon(true); - - this.orebfuscator = orebfuscator; - - AdvancedConfig advancedConfig = orebfuscator.getOrebfuscatorConfig().advanced(); - this.workerCount = advancedConfig.proximityThreads(); - this.defaultBucketSize = advancedConfig.proximityDefaultBucketSize(); - this.checkInterval = TimeUnit.MILLISECONDS.toNanos(advancedConfig.proximityThreadCheckInterval()); - - this.worker = new ProximityWorker(orebfuscator); - this.workerThreads = new ProximityWorkerThread[workerCount - 1]; - - var statistics = this.orebfuscator.getStatistics(); - statistics.setProximityWaitTime(() -> (long) waitTimer.average()); - statistics.setProximityProcessTime(() -> (long) processTimer.average()); - } - - @EventHandler - public void onJoin(PlayerJoinEvent event) { - if (LockSupport.getBlocker(this) == this) { - LockSupport.unpark(this); - } - } - - @Override - public void start() { - Bukkit.getPluginManager().registerEvents(this, this.orebfuscator); - - super.start(); - - for (int i = 0; i < workerCount - 1; i++) { - this.workerThreads[i] = new ProximityWorkerThread(this, this.worker); - this.workerThreads[i].start(); - } - } - - public void close() { - this.running = false; - - this.interrupt(); - - for (int i = 0; i < workerCount - 1; i++) { - this.workerThreads[i].interrupt(); - } - - // technically not need but better be safe - this.phaser.forceTermination(); - } - - boolean isRunning() { - return this.running && !this.phaser.isTerminated(); - } - - List nextBucket() throws InterruptedException { - return this.bucketQueue.take(); - } - - void finishBucketProcessing() { - this.phaser.arriveAndDeregister(); - } - - @Override - public void run() { - while (this.isRunning()) { - try { - long processStart = System.nanoTime(); - Collection players = Bukkit.getOnlinePlayers(); - - // park thread if no players are online - if (players.isEmpty()) { - // park for 1sec and retry - LockSupport.parkNanos(this, 1000000000L); - // reset interrupt flag - Thread.interrupted(); - continue; - } - - // get player count and derive max bucket size for each thread - int playerCount = players.size(); - int maxBucketSize = Math.max(this.defaultBucketSize, (int) Math.ceil((float) playerCount / this.workerCount)); - - // calculate bucket - int bucketCount = (int) Math.ceil((float) playerCount / maxBucketSize); - int bucketSize = (int) Math.ceil((float) playerCount / (float) bucketCount); - - // register extra worker threads in phaser - if (bucketCount > 1) { - this.phaser.bulkRegister(bucketCount - 1); - } - - // this threads local bucket - List localBucket = null; - - Iterator iterator = players.iterator(); - - // create buckets and fill queue - for (int index = 0; index < bucketCount; index++) { - List bucket = new ArrayList<>(); - - // fill bucket until bucket full or no players remain - for (int size = 0; size < bucketSize && iterator.hasNext(); size++) { - bucket.add(iterator.next()); - } - - // assign first bucket to current thread - if (index == 0) { - localBucket = bucket; - } else { - this.bucketQueue.offer(bucket); - } - } - - // process local bucket - this.worker.process(localBucket); - - // wait for all threads to finish and reset phaser - this.phaser.awaitAdvanceInterruptibly(this.phaser.arrive()); - - long processTime = System.nanoTime() - processStart; - processTimer.add(processTime); - - // check if we have enough time to sleep - long waitTime = Math.max(0, this.checkInterval - processTime); - long waitMillis = TimeUnit.NANOSECONDS.toMillis(waitTime); - - if (waitMillis > 0) { - // measure wait time - waitTimer.add(TimeUnit.MILLISECONDS.toNanos(waitMillis)); - - Thread.sleep(waitMillis); - } - } catch (InterruptedException e) { - continue; - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (this.phaser.isTerminated() && this.running) { - OfcLogger.error("Looks like we encountered an invalid state, please report this:", - new IllegalStateException("Proximity Phaser terminated!")); - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java index 07378f47..ec16158e 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java @@ -1,7 +1,5 @@ package net.imprex.orebfuscator.proximity; -import org.bukkit.entity.Player; - import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; @@ -10,16 +8,12 @@ import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.ChunkCoordIntPair; - -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; import dev.imprex.orebfuscator.config.api.ProximityConfig; -import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; import net.imprex.orebfuscator.Orebfuscator; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; -import net.imprex.orebfuscator.player.OrebfuscatorPlayer; -import net.imprex.orebfuscator.player.OrebfuscatorPlayerMap; import net.imprex.orebfuscator.util.MinecraftVersion; -import net.imprex.orebfuscator.util.PermissionUtil; public class ProximityPacketListener extends PacketAdapter { @@ -27,17 +21,11 @@ public class ProximityPacketListener extends PacketAdapter { private final ProtocolManager protocolManager; - private final OrebfuscatorConfig config; - private final OrebfuscatorPlayerMap playerMap; - public ProximityPacketListener(Orebfuscator orebfuscator) { super(orebfuscator, PacketType.Play.Server.UNLOAD_CHUNK); this.protocolManager = ProtocolLibrary.getProtocolManager(); this.protocolManager.addPacketListener(this); - - this.config = orebfuscator.getOrebfuscatorConfig(); - this.playerMap = orebfuscator.getPlayerMap(); } public void unregister() { @@ -46,27 +34,26 @@ public void unregister() { @Override public void onPacketSending(PacketEvent event) { - Player player = event.getPlayer(); - if (PermissionUtil.canBypassObfuscate(player)) { + BukkitPlayerAccessor player = BukkitPlayerAccessor.tryGet(event.getPlayer()); + if (player == null || player.hasPermission("orebfuscator.bypass")) { return; } - WorldAccessor worldAccessor = BukkitWorldAccessor.get(player.getWorld()); - ProximityConfig proximityConfig = config.world(worldAccessor).proximity(); + BukkitWorldAccessor world = player.world(); + ProximityConfig proximityConfig = world.config().proximity(); if (proximityConfig == null || !proximityConfig.isEnabled()) { return; } - OrebfuscatorPlayer orebfuscatorPlayer = this.playerMap.get(player); - if (orebfuscatorPlayer != null) { - PacketContainer packet = event.getPacket(); - if (HAS_CHUNK_POS_FIELD) { - ChunkCoordIntPair chunkPos = packet.getChunkCoordIntPairs().read(0); - orebfuscatorPlayer.removeChunk(chunkPos.getChunkX(), chunkPos.getChunkZ()); - } else { - StructureModifier ints = packet.getIntegers(); - orebfuscatorPlayer.removeChunk(ints.read(0), ints.read(1)); - } + PacketContainer packet = event.getPacket(); + OrebfuscatorPlayer orebfuscatorPlayer = player.orebfuscatorPlayer(); + + if (HAS_CHUNK_POS_FIELD) { + ChunkCoordIntPair chunkPos = packet.getChunkCoordIntPairs().read(0); + orebfuscatorPlayer.removeChunk(world, chunkPos.getChunkX(), chunkPos.getChunkZ()); + } else { + StructureModifier ints = packet.getIntegers(); + orebfuscatorPlayer.removeChunk(world, ints.read(0), ints.read(1)); } } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorker.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorker.java deleted file mode 100644 index 2fd3db41..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorker.java +++ /dev/null @@ -1,161 +0,0 @@ -package net.imprex.orebfuscator.proximity; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.joml.FrustumIntersection; -import org.joml.Quaternionf; - -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; -import dev.imprex.orebfuscator.config.api.ProximityConfig; -import dev.imprex.orebfuscator.interop.WorldAccessor; -import dev.imprex.orebfuscator.util.BlockPos; -import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.OrebfuscatorCompatibility; -import net.imprex.orebfuscator.OrebfuscatorNms; -import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; -import net.imprex.orebfuscator.player.OrebfuscatorPlayer; -import net.imprex.orebfuscator.player.OrebfuscatorPlayerChunk; -import net.imprex.orebfuscator.player.OrebfuscatorPlayerMap; -import net.imprex.orebfuscator.util.FastGazeUtil; -import net.imprex.orebfuscator.util.PermissionUtil; - -public class ProximityWorker { - - private final OrebfuscatorConfig config; - private final OrebfuscatorPlayerMap playerMap; - - public ProximityWorker(Orebfuscator orebfuscator) { - this.config = orebfuscator.getOrebfuscatorConfig(); - this.playerMap = orebfuscator.getPlayerMap(); - } - - private boolean shouldIgnorePlayer(Player player) { - if (PermissionUtil.canBypassObfuscate(player)) { - return true; - } - - return player.getGameMode() == GameMode.SPECTATOR && this.config.general().ignoreSpectator(); - } - - protected void process(List players) { - for (Player player : players) { - try { - this.process(player); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - private void process(Player player) { - if (this.shouldIgnorePlayer(player)) { - return; - } - - World world = player.getWorld(); - WorldAccessor worldAccessor = BukkitWorldAccessor.get(world); - - // check if world has enabled proximity config - ProximityConfig proximityConfig = this.config.world(worldAccessor).proximity(); - if (proximityConfig == null || !proximityConfig.isEnabled()) { - return; - } - - // frustum culling and ray casting both need rotation changes - boolean needsRotation = proximityConfig.frustumCullingEnabled() || proximityConfig.rayCastCheckEnabled(); - - // check if player changed location since last time - OrebfuscatorPlayer orebfuscatorPlayer = this.playerMap.get(player); - if (orebfuscatorPlayer == null || !orebfuscatorPlayer.needsProximityUpdate(needsRotation)) { - return; - } - - int distance = proximityConfig.distance(); - int distanceSquared = distance * distance; - - List updateBlocks = new ArrayList<>(); - Location eyeLocation = needsRotation - ? player.getEyeLocation() - : null; - - // create frustum planes if culling is enabled - FrustumIntersection frustum = proximityConfig.frustumCullingEnabled() - ? new FrustumIntersection(proximityConfig.frustumCullingProjectionMatrix() - .rotate(new Quaternionf() - .rotateX((float) Math.toRadians(eyeLocation.getPitch())) - .rotateY((float) Math.toRadians(eyeLocation.getYaw() + 180))) - .translate( - (float) -eyeLocation.getX(), - (float) -eyeLocation.getY(), - (float) -eyeLocation.getZ() - ), false) - : null; - - Location location = player.getLocation(); - int minChunkX = (location.getBlockX() - distance) >> 4; - int maxChunkX = (location.getBlockX() + distance) >> 4; - int minChunkZ = (location.getBlockZ() - distance) >> 4; - int maxChunkZ = (location.getBlockZ() + distance) >> 4; - - for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) { - for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) { - - OrebfuscatorPlayerChunk chunk = orebfuscatorPlayer.getChunk(chunkX, chunkZ); - if (chunk == null) { - continue; - } - - for (Iterator iterator = chunk.proximityIterator(); iterator.hasNext(); ) { - BlockPos blockPos = iterator.next(); - - // check if block is in range - double blockDistanceSquared = blockPos.distanceSquared(location.getX(), location.getY(), location.getZ()); - if (blockDistanceSquared > distanceSquared) { - continue; - } - - // do frustum culling check - if (proximityConfig.frustumCullingEnabled() - && blockDistanceSquared > proximityConfig.frustumCullingMinDistanceSquared()) { - - // check if block AABB is inside frustum - int result = frustum.intersectAab( - blockPos.x(), blockPos.y(), blockPos.z(), - blockPos.x() + 1, blockPos.y() + 1, blockPos.z() + 1); - - // block is outside - if (result != FrustumIntersection.INSIDE && result != FrustumIntersection.INTERSECT) { - continue; - } - } - - // do ray cast check - if (proximityConfig.rayCastCheckEnabled() && !FastGazeUtil.doFastCheck(blockPos, eyeLocation, world, - proximityConfig.rayCastCheckOnlyCheckCenter())) { - continue; - } - - // block is visible and needs update - iterator.remove(); - updateBlocks.add(blockPos); - } - - if (chunk.isEmpty()) { - orebfuscatorPlayer.removeChunk(chunkX, chunkZ); - } - } - } - - OrebfuscatorCompatibility.runForPlayer(player, () -> { - if (player.isOnline() && player.getWorld().equals(world)) { - OrebfuscatorNms.sendBlockUpdates(player, updateBlocks); - } - }); - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorkerThread.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorkerThread.java deleted file mode 100644 index 2bb2949b..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityWorkerThread.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.imprex.orebfuscator.proximity; - -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import org.bukkit.entity.Player; - -import net.imprex.orebfuscator.Orebfuscator; - -public class ProximityWorkerThread extends Thread { - - private static final AtomicInteger NEXT_ID = new AtomicInteger(); - - private final ProximityDirectorThread directorThread; - private final ProximityWorker worker; - - public ProximityWorkerThread(ProximityDirectorThread directorThread, ProximityWorker worker) { - super(Orebfuscator.THREAD_GROUP, "ofc-proximity-worker-" + NEXT_ID.getAndIncrement()); - this.setDaemon(true); - - this.directorThread = directorThread; - this.worker = worker; - } - - @Override - public void run() { - while (this.directorThread.isRunning()) { - try { - List bucket = this.directorThread.nextBucket(); - - this.worker.process(bucket); - - this.directorThread.finishBucketProcessing(); - } catch (InterruptedException e) { - continue; - } catch (Exception e) { - e.printStackTrace(); - } - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/FastGazeUtil.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/FastGazeUtil.java deleted file mode 100644 index efdfca14..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/FastGazeUtil.java +++ /dev/null @@ -1,89 +0,0 @@ -package net.imprex.orebfuscator.util; - -import org.bukkit.Location; -import org.bukkit.World; - -import dev.imprex.orebfuscator.util.BlockPos; -import net.imprex.orebfuscator.OrebfuscatorNms; - -public class FastGazeUtil { - - /** - * Basic idea here is to take some rays from the considered block to the player's eyes, and decide if any of those - * rays can reach the eyes unimpeded. - * - * @param pos the starting block position - * @param eyes the destination eyes - * @param player the player world we are testing for - * @param onlyCheckCenter only check block center if true - * @return true if unimpeded path, false otherwise - */ - public static boolean doFastCheck(BlockPos pos, Location eyes, World player, boolean onlyCheckCenter) { - double ex = eyes.getX(); - double ey = eyes.getY(); - double ez = eyes.getZ(); - double x = pos.x(); - double y = pos.y(); - double z = pos.z(); - if (onlyCheckCenter) { - return // center - FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z + 0.5, ex, ey, ez, player); - } else { - return // midfaces - FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 0.5, z + 0.5, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y, z + 0.5, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 1.0, z + 0.5, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 0.5, y + 0.5, z + 1.0, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1.0, y + 0.5, z + 0.5, ex, ey, ez, player) || - // corners - FastGazeUtil.fastAABBRayCheck(x, y, z, x, y, z, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y, z, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 1, z, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y + 1, z, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y, z + 1, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y, z + 1, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x, y + 1, z + 1, ex, ey, ez, player) - || FastGazeUtil.fastAABBRayCheck(x, y, z, x + 1, y + 1, z + 1, ex, ey, ez, player); - } - } - - public static boolean fastAABBRayCheck(double bx, double by, double bz, double x, double y, double z, double ex, - double ey, double ez, World world) { - double fx = ex - x; - double fy = ey - y; - double fz = ez - z; - double absFx = Math.abs(fx); - double absFy = Math.abs(fy); - double absFz = Math.abs(fz); - double s = Math.max(absFx, Math.max(absFy, absFz)); - - if (s < 1) { - return true; // on top / inside - } - - double lx, ly, lz; - - fx = fx / s; // units of change along vector - fy = fy / s; - fz = fz / s; - - while (s > 0) { - ex = ex - fx; // move along vector, we start _at_ the eye and move towards b - ey = ey - fy; - ez = ez - fz; - lx = Math.floor(ex); - ly = Math.floor(ey); - lz = Math.floor(ez); - if (lx == bx && ly == by && lz == bz) { - return true; // we've reached our starting block, don't test it. - } - int blockId = OrebfuscatorNms.getBlockState(world, (int) lx, (int) ly, (int) lz); - if (blockId != 0 && OrebfuscatorNms.isOccluding(blockId)) { - return false; // fail on first hit, this ray is "blocked" - } - s--; // we stop - } - return true; - } -} \ No newline at end of file diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RingTimer.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RingTimer.java deleted file mode 100644 index c3b4e345..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RingTimer.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.imprex.orebfuscator.util; - -public class RingTimer { - - private final long[] buffer; - - private int size; - private int head; - - private Long time; - - public RingTimer(int size) { - this.buffer = new long[size]; - } - - public double average() { - if (size == 0) { - return 0; - } - - double sum = 0; - for (int i = 0; i < size; i++) { - sum += buffer[i]; - } - - return sum / size; - } - - public void start() { - if (time == null) { - time = System.nanoTime(); - } - } - - public void stop() { - if (time != null) { - add(System.nanoTime() - time); - time = null; - } - } - - public void add(long time) { - buffer[head++] = time; - - if (head >= buffer.length) { - head = 0; - } - - if (size < buffer.length) { - size++; - } - } -} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RollingAverage.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RollingAverage.java deleted file mode 100644 index 50afcfab..00000000 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/RollingAverage.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.imprex.orebfuscator.util; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.util.concurrent.atomic.AtomicInteger; - -public class RollingAverage { - - private static final VarHandle BUFFER_HANDLE = MethodHandles.arrayElementVarHandle(long[].class); - - private final long[] buffer; - - private final AtomicInteger head = new AtomicInteger(0); - private final AtomicInteger size = new AtomicInteger(0); - - public RollingAverage(int capacity) { - this.buffer = new long[capacity]; - } - - public void add(long 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); - } - } - - public double average() { - int size = this.size.get(); - if (size == 0) { - return 0; - } - - double sum = 0; - for (int i = 0; i < size; i++) { - sum += (long) BUFFER_HANDLE.getAcquire(buffer, i); - } - - return sum / size; - } -} diff --git a/pom.xml b/pom.xml index 388a2727..5713c175 100644 --- a/pom.xml +++ b/pom.xml @@ -29,16 +29,17 @@ 4.1.90.Final - 33.4.8-jre - 2.13.1 - 2.4 + 33.5.0-jre + 2.13.2 + 2.5 1.10.8 - 1.8.0 + 1.10.2 5.13.4 5.19.0 26.0.2 + 1.0.0 3.14.0 3.6.0 @@ -225,5 +226,11 @@ ${dependency.jetannotations.version} provided + + org.jspecify + jspecify + ${dependency.jspecify.version} + compile + From 61387abba790ced23f484f92f07394fc27eeefd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sun, 18 Jan 2026 15:45:18 +0100 Subject: [PATCH 04/14] feat: move more classes from plugin to core --- .../orebfuscator/PermissionRequirements.java | 16 ++ .../imprex/orebfuscator/UpdateSystem.java | 46 ++--- .../cache/AsyncChunkSerializer.java | 48 ++++- .../orebfuscator/cache/ChunkCacheEntry.java | 9 +- .../orebfuscator/cache/ChunkSerializer.java | 12 +- .../orebfuscator/cache/ObfuscationCache.java | 4 +- .../orebfuscator/chunk/ChunkFactory.java | 2 +- .../orebfuscator/chunk/ChunkVersionFlags.java | 2 +- .../config/OrebfuscatorCacheConfig.java | 2 +- .../config/OrebfuscatorConfig.java | 16 +- .../interop/OrebfuscatorCore.java | 2 + .../orebfuscator/interop/PlayerAccessor.java | 3 +- .../orebfuscator/interop/ServerAccessor.java | 14 +- .../obfuscation/DeobfuscationWorker.java | 69 +++---- .../obfuscation/ObfuscationProcessor.java | 2 +- .../proximity/ProximityDirectorThread.java | 170 ------------------ .../proximity/ProximitySystem.java | 104 +++++++++++ .../proximity/ProximityWorker.java | 5 +- .../proximity/ProximityWorkerThread.java | 40 ----- .../statistics/CacheStatistics.java | 65 ++++++- .../statistics/ObfuscationStatistics.java | 4 +- .../statistics/OrebfuscatorStatistics.java | 4 +- .../util/AbstractHttpService.java | 17 +- .../imprex/orebfuscator/util/ConsoleUtil.java | 11 +- .../dev/imprex/orebfuscator/util/Version.java | 9 +- .../util/concurrent/OrebfuscatorExecutor.java | 23 ++- .../net/imprex/orebfuscator/Orebfuscator.java | 38 ++-- .../orebfuscator/OrebfuscatorCommand.java | 6 +- .../iterop/BukkitPlayerAccessor.java | 6 +- .../obfuscation/DeobfuscationListener.java | 27 ++- .../obfuscation/ObfuscationListener.java | 3 +- .../proximity/ProximityPacketListener.java | 3 +- .../orebfuscator/util/PermissionUtil.java | 15 +- 33 files changed, 410 insertions(+), 387 deletions(-) create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java rename {orebfuscator-plugin/src/main/java/net => orebfuscator-core/src/main/java/dev}/imprex/orebfuscator/UpdateSystem.java (80%) delete mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java delete mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java rename {orebfuscator-plugin/src/main/java/net => orebfuscator-core/src/main/java/dev}/imprex/orebfuscator/util/AbstractHttpService.java (75%) rename {orebfuscator-plugin/src/main/java/net => orebfuscator-core/src/main/java/dev}/imprex/orebfuscator/util/ConsoleUtil.java (90%) diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java new file mode 100644 index 00000000..62598b4f --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java @@ -0,0 +1,16 @@ +package dev.imprex.orebfuscator; + +import java.util.Optional; +import java.util.OptionalInt; + +public record PermissionRequirements(OptionalInt operatorLevel, Optional permission) { + + public static final PermissionRequirements BYPASS = new PermissionRequirements(OptionalInt.empty(), Optional.of("orebfuscator.bypass")); + public static final PermissionRequirements ADMIN = new PermissionRequirements(OptionalInt.of(4), Optional.of("orebfuscator.admin")); + + public PermissionRequirements { + if (operatorLevel.isEmpty() && permission.isEmpty()) { + throw new IllegalArgumentException("Either an operator level, permission or both have to defined"); + } + } +} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java similarity index 80% rename from orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java rename to orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java index 603b3b03..14f2902f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java @@ -1,4 +1,4 @@ -package net.imprex.orebfuscator; +package dev.imprex.orebfuscator; import java.time.Duration; import java.time.Instant; @@ -12,24 +12,17 @@ import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; - -import org.bukkit.entity.Player; - +import org.jspecify.annotations.NullMarked; import com.google.gson.annotations.SerializedName; - import dev.imprex.orebfuscator.config.api.GeneralConfig; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; import dev.imprex.orebfuscator.logging.LogLevel; import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.util.AbstractHttpService; +import dev.imprex.orebfuscator.util.ConsoleUtil; import dev.imprex.orebfuscator.util.Version; -import net.imprex.orebfuscator.util.AbstractHttpService; -import net.imprex.orebfuscator.util.ConsoleUtil; -import net.imprex.orebfuscator.util.MinecraftVersion; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.ComponentBuilder; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.hover.content.Text; +@NullMarked public class UpdateSystem extends AbstractHttpService { private static final Pattern DEV_VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:-b(?\\d+))?"); @@ -44,14 +37,18 @@ private static boolean isDevVersion(String version) { private static final Duration CACHE_DURATION = Duration.ofMinutes(10L); - private final Orebfuscator orebfuscator; + private final String loader; + + private final OrebfuscatorCore orebfuscator; private final GeneralConfig generalConfig; private final AtomicReference validUntil = new AtomicReference<>(); private final AtomicReference>> latestVersion = new AtomicReference<>(); - public UpdateSystem(Orebfuscator orebfuscator) { + public UpdateSystem(OrebfuscatorCore orebfuscator, String loader) { super(orebfuscator); + + this.loader = loader; this.orebfuscator = orebfuscator; this.generalConfig = orebfuscator.config().general(); @@ -60,13 +57,13 @@ public UpdateSystem(Orebfuscator orebfuscator) { } private CompletableFuture> requestLatestVersion() { - String installedVersion = this.orebfuscator.getDescription().getVersion(); + String installedVersion = this.orebfuscator.orebfuscatorVersion().toString(); if (!this.generalConfig.checkForUpdates() || isDevVersion(installedVersion)) { OfcLogger.debug("UpdateSystem - Update check disabled or dev version detected; skipping"); return CompletableFuture.completedFuture(Optional.empty()); } - var uri = String.format(API_URI, "bukkit", MinecraftVersion.current()); + var uri = String.format(API_URI, this.loader, this.orebfuscator.minecraftVersion().toString()); return HTTP.sendAsync(request(uri).build(), optionalJson(ModrinthVersion[].class)).thenApply(response -> response.body().flatMap(body -> { var version = Version.parse(installedVersion); @@ -118,24 +115,17 @@ private void ifNewerVersionAvailable(Consumer consumer) { this.getLatestVersion().thenAccept(o -> o.ifPresent(consumer)); } - private void checkForUpdates() { + public void ifNewerDownloadAvailable(Consumer consumer) { this.ifNewerVersionAvailable(version -> { String downloadUri = String.format(DOWNLOAD_URI, version.version); - ConsoleUtil.printBox(LogLevel.WARN, "UPDATE AVAILABLE", "", downloadUri); + consumer.accept(downloadUri); }); } - public void checkForUpdates(Player player) { + private void checkForUpdates() { this.ifNewerVersionAvailable(version -> { String downloadUri = String.format(DOWNLOAD_URI, version.version); - BaseComponent[] components = new ComponentBuilder("[§bOrebfuscator§f]§7 A new release is available ") - .append("§f§l[CLICK HERE]") - .event(new ClickEvent(ClickEvent.Action.OPEN_URL, downloadUri)) - .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new Text(new ComponentBuilder("§7Click here to see the latest release").create()))).create(); - OrebfuscatorCompatibility.runForPlayer(player, () -> { - player.spigot().sendMessage(components); - }); + ConsoleUtil.printBox(LogLevel.WARN, "UPDATE AVAILABLE", "", downloadUri); }); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java index e4d04360..1e3590b3 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java @@ -9,11 +9,13 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import dev.imprex.orebfuscator.interop.OrebfuscatorCore; import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.statistics.CacheStatistics; import dev.imprex.orebfuscator.util.ChunkCacheKey; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.util.RollingTimer; /** * This class works similar to a bounded buffer for cache read and write requests but also functions as the only @@ -24,10 +26,11 @@ * @see Bound buffer * @see Memory ordering */ -// TODO: add statistice for read/write times and ratio of read/write as well as average throughput for read/write @NullMarked public class AsyncChunkSerializer implements Runnable { + private final CacheStatistics statistics; + private final Lock lock = new ReentrantLock(true); private final Condition notFull = lock.newCondition(); private final Condition notEmpty = lock.newCondition(); @@ -42,14 +45,15 @@ public class AsyncChunkSerializer implements Runnable { private volatile boolean running = true; public AsyncChunkSerializer(OrebfuscatorCore orebfuscator, AbstractRegionFileCache regionFileCache) { + this.statistics = orebfuscator.statistics().cache; this.maxTaskQueueSize = orebfuscator.config().cache().maximumTaskQueueSize(); - this.serializer = new ChunkSerializer(regionFileCache); + this.serializer = new ChunkSerializer(regionFileCache, this.statistics); this.thread = new Thread(OrebfuscatorCore.THREAD_GROUP, this, "ofc-chunk-serializer"); this.thread.setDaemon(true); this.thread.start(); - orebfuscator.statistics().cache.setDiskCacheQueueLength(this.tasks::size); + this.statistics.setDiskCacheQueueLength(this.tasks::size); } public CompletableFuture<@Nullable ChunkCacheEntry> read(ChunkCacheKey key) { @@ -137,19 +141,44 @@ public void close() { this.lock.unlock(); } } + + private abstract class TimedTask implements Runnable { + + private final RollingTimer.Instance waitTimer = statistics.diskCacheWaitTime.start(); + private final RollingTimer runTimer; + + public TimedTask(RollingTimer runTimer) { + this.runTimer = runTimer; + } + + @Override + public final void run() { + waitTimer.stop(); + + var timer = runTimer.start(); + try { + execute(); + } finally { + timer.stop(); + } + } + + protected abstract void execute(); + } - private class WriteTask implements Runnable { + private class WriteTask extends TimedTask { private final ChunkCacheKey key; private final ChunkCacheEntry chunk; public WriteTask(ChunkCacheKey key, ChunkCacheEntry chunk) { + super(statistics.diskCacheWriteTime); this.key = key; this.chunk = chunk; } @Override - public void run() { + public void execute() { try { serializer.write(key, chunk); } catch (IOException e) { @@ -158,18 +187,19 @@ public void run() { } } - private class ReadTask implements Runnable { + private class ReadTask extends TimedTask { private final ChunkCacheKey key; private final CompletableFuture<@Nullable ChunkCacheEntry> future; public ReadTask(ChunkCacheKey key, CompletableFuture<@Nullable ChunkCacheEntry> future) { + super(statistics.diskCacheReadTime); this.key = key; this.future = future; } @Override - public void run() { + public void execute() { try { future.complete(serializer.read(key)); } catch (Exception e) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java index 0bddb96b..5eeb99b2 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkCacheEntry.java @@ -20,8 +20,9 @@ public record ChunkCacheEntry(ChunkCacheKey key, byte[] compressedData) { public static ChunkCacheEntry create(CacheRequest request, ObfuscationResponse response) { - try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(byteArrayOutputStream); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + try (LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(byteArrayOutputStream); DataOutputStream dataOutputStream = new DataOutputStream(lz4BlockOutputStream)) { byteArrayOutputStream.write(request.hash()); @@ -42,11 +43,11 @@ public static ChunkCacheEntry create(CacheRequest request, ObfuscationResponse r for (BlockPos blockPosition : blockEntities) { dataOutputStream.writeInt(blockPosition.toSectionPos()); } - - return new ChunkCacheEntry(request.cacheKey(), byteArrayOutputStream.toByteArray()); } catch (Exception e) { throw new ChunkCacheException("Unable to compress chunk: " + request.cacheKey(), e); } + + return new ChunkCacheEntry(request.cacheKey(), byteArrayOutputStream.toByteArray()); } public int estimatedSize() { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java index 602ab6c4..6cd0253e 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java @@ -1,11 +1,12 @@ package dev.imprex.orebfuscator.cache; -import dev.imprex.orebfuscator.util.ChunkCacheKey; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.statistics.CacheStatistics; +import dev.imprex.orebfuscator.util.ChunkCacheKey; @NullMarked public class ChunkSerializer { @@ -13,9 +14,11 @@ public class ChunkSerializer { private static final int CACHE_VERSION = 3; private final AbstractRegionFileCache regionFileCache; + private final CacheStatistics statistics; - public ChunkSerializer(AbstractRegionFileCache regionFileCache) { + public ChunkSerializer(AbstractRegionFileCache regionFileCache, CacheStatistics statistics) { this.regionFileCache = regionFileCache; + this.statistics = statistics; } @Nullable @@ -23,11 +26,14 @@ public ChunkCacheEntry read(ChunkCacheKey key) throws IOException { try (DataInputStream dataInputStream = this.regionFileCache.createInputStream(key)) { // check if cache entry has right version and if chunk is present if (dataInputStream == null || dataInputStream.readInt() != CACHE_VERSION || !dataInputStream.readBoolean()) { + statistics.onDiskCacheRead(5); return null; } byte[] compressedData = new byte[dataInputStream.readInt()]; dataInputStream.readFully(compressedData); + + statistics.onDiskCacheRead(9 + compressedData.length); return new ChunkCacheEntry(key, compressedData); } catch (IOException e) { @@ -46,8 +52,10 @@ public void write(ChunkCacheKey key, @Nullable ChunkCacheEntry value) throws IOE byte[] compressedData = value.compressedData(); dataOutputStream.writeInt(compressedData.length); dataOutputStream.write(compressedData); + statistics.onDiskCacheWrite(9 + compressedData.length); } else { dataOutputStream.writeBoolean(false); + statistics.onDiskCacheWrite(5); } } catch (IOException e) { throw new IOException("Unable to write chunk: " + key, e); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java index 187a57dc..fc5c8609 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java @@ -51,8 +51,8 @@ public ObfuscationCache(OrebfuscatorCore orebfuscator) { } if (this.cacheConfig.enabled() && this.cacheConfig.deleteRegionFilesAfterAccess() > 0) { - // TODO: OrebfuscatorCompatibility.runAsyncAtFixedRate(new CacheFileCleanupTask(orebfuscator, - // regionFileCache), 0, 72000L); + var task = new CacheFileCleanupTask(orebfuscator.config(), regionFileCache); + this.executor.scheduleAtFixedRate(task, 0, 1, TimeUnit.HOURS); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java index c0fd0300..9e718d77 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkFactory.java @@ -10,7 +10,7 @@ public class ChunkFactory { private final ChunkVersionFlags versionFlags; public ChunkFactory(ServerAccessor serverAccessor) { - this.registryAccessor = serverAccessor.getRegistry(); + this.registryAccessor = serverAccessor.registry(); this.versionFlags = new ChunkVersionFlags(serverAccessor); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkVersionFlags.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkVersionFlags.java index 14f9cae3..da68a131 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkVersionFlags.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/ChunkVersionFlags.java @@ -13,7 +13,7 @@ public final class ChunkVersionFlags { private final boolean hasSingleValuePalette; public ChunkVersionFlags(ServerAccessor serverAccessor) { - var version = serverAccessor.getMinecraftVersion(); + var version = serverAccessor.minecraftVersion(); hasLongArrayLengthField = version.isBelow("1.21.5"); hasBiomePalettedContainer = version.isAtOrAbove("1.18"); hasSingleValuePalette = version.isAtOrAbove("1.18"); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java index 427f9d96..37f2033b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java @@ -35,7 +35,7 @@ public class OrebfuscatorCacheConfig implements CacheConfig { private boolean enableDiskCache = false; public OrebfuscatorCacheConfig(ServerAccessor server) { - this.worldDirectory = server.getWorldDirectory().normalize(); + this.worldDirectory = server.worldDirectory().normalize(); this.baseDirectory = this.worldDirectory.resolve("orebfuscator_cache/"); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java index 45fff1a0..3889b6ea 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java @@ -65,7 +65,7 @@ public class OrebfuscatorConfig implements Config { public OrebfuscatorConfig(ServerAccessor server) { this.server = server; - this.path = server.getConfigDirectory().resolve("config.yml"); + this.path = server.configDirectory().resolve("config.yml"); this.cacheConfig = new OrebfuscatorCacheConfig(this.server); this.configuration = this.loadConfiguration(); @@ -77,7 +77,7 @@ public YamlConfiguration loadConfiguration() { if (Files.notExists(this.path)) { Files.createDirectories(this.path.getParent()); - Version version = this.server.getMinecraftVersion(); + Version version = this.server.minecraftVersion(); Version configVersion = ConfigLookup.getConfigVersion(version); if (configVersion == null) { throw new InvalidConfigurationException( @@ -130,8 +130,8 @@ public void store() { private byte[] calculateSystemHash(YamlConfiguration configuration) throws IOException { return Hashing.murmur3_128().newHasher() - .putBytes(this.server.getOrebfuscatorVersion().toString().getBytes(StandardCharsets.UTF_8)) - .putBytes(this.server.getMinecraftVersion().toString().getBytes(StandardCharsets.UTF_8)) + .putBytes(this.server.orebfuscatorVersion().toString().getBytes(StandardCharsets.UTF_8)) + .putBytes(this.server.minecraftVersion().toString().getBytes(StandardCharsets.UTF_8)) .putBytes(configuration.withoutComments().getBytes(StandardCharsets.UTF_8)) .hash().asBytes(); } @@ -139,7 +139,7 @@ private byte[] calculateSystemHash(YamlConfiguration configuration) throws IOExc private void deserialize(YamlConfiguration configuration, ConfigParsingContext context) { if (ConfigMigrator.willMigrate(configuration)) { try { - configuration.save(server.getConfigDirectory().resolve("config-old.yml")); + configuration.save(server.configDirectory().resolve("config-old.yml")); } catch (IOException e) { OfcLogger.error("Can't save original config before migration", e); } @@ -184,7 +184,7 @@ private void deserialize(YamlConfiguration configuration, ConfigParsingContext c cacheContext.warn(ConfigMessage.MISSING_USING_DEFAULTS); } - final BlockParser.Factory blockParserFactory = BlockParser.factory(server.getRegistry()); + final BlockParser.Factory blockParserFactory = BlockParser.factory(server.registry()); // parse obfuscation sections ConfigParsingContext obfuscationContext = context.section("obfuscation"); @@ -213,7 +213,7 @@ private void deserialize(YamlConfiguration configuration, ConfigParsingContext c proximityContext.warn(ConfigMessage.MISSING_OR_EMPTY); } - for (WorldAccessor world : this.server.getWorlds()) { + for (WorldAccessor world : this.server.worlds()) { this.worldConfigBundles.put(world, new OrebfuscatorWorldConfigBundle(world)); } } @@ -363,7 +363,7 @@ public OrebfuscatorWorldConfigBundle(WorldAccessor world) { this.obfuscationConfig = findConfig(obfuscationConfigs, worldName, "obfuscation"); this.proximityConfig = findConfig(proximityConfigs, worldName, "proximity"); - this.blockFlags = OrebfuscatorBlockFlags.create(server.getRegistry(), obfuscationConfig, proximityConfig); + this.blockFlags = OrebfuscatorBlockFlags.create(server.registry(), obfuscationConfig, proximityConfig); this.needsObfuscation = obfuscationConfig != null && obfuscationConfig.isEnabled() || proximityConfig != null && proximityConfig.isEnabled(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java index 4534921d..3f6ca88b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java @@ -13,6 +13,8 @@ public interface OrebfuscatorCore extends ServerAccessor { ThreadGroup THREAD_GROUP = new ThreadGroup("orebfuscator"); + + String name(); OrebfuscatorExecutor executor(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java index efdda0f0..d1f35ee4 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java @@ -1,6 +1,7 @@ package dev.imprex.orebfuscator.interop; import org.jspecify.annotations.NullMarked; +import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.EntityPose; @@ -22,7 +23,7 @@ public interface PlayerAccessor { double lavaFogDistance(); - boolean hasPermission(String permission); + boolean hasPermission(PermissionRequirements permission); void runForPlayer(Runnable runnable); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java index 7dac1448..71091895 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ServerAccessor.java @@ -11,19 +11,19 @@ public interface ServerAccessor { boolean isGameThread(); - Path getConfigDirectory(); + Path configDirectory(); - Path getWorldDirectory(); + Path worldDirectory(); - Version getOrebfuscatorVersion(); + Version orebfuscatorVersion(); - Version getMinecraftVersion(); + Version minecraftVersion(); - RegistryAccessor getRegistry(); + RegistryAccessor registry(); AbstractRegionFileCache createRegionFileCache(); - List getWorlds(); + List worlds(); - List getPlayers(); + List players(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java index 32ecdd4b..b7b9228b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java @@ -80,61 +80,48 @@ public void deobfuscate(WorldAccessor world, @Nullable List blocks) { } var timer = statistics.debofuscation.start(); - try (var processor = new RecursiveProcessor(world)) { - for (BlockPos position : blocks) { - processor.processPosition(position); - } + try { + this.deobfuscateNow(world, blocks); } finally { timer.stop(); } } + + private void deobfuscateNow(WorldAccessor world, List blocks) { + final BlockFlags blockFlags = world.config().blockFlags(); - // TODO: there is nothing recusive about this, maybe even remove class and do a single method - private class RecursiveProcessor implements AutoCloseable { - - private final Set updatedBlocks = new HashSet<>(); - private final Set invalidChunks = new HashSet<>(); - private final Map chunks = new HashMap<>(); - - private final WorldAccessor world; - private final BlockFlags blockFlags; + final Map chunks = new HashMap<>(); + final Set updatedBlocks = new HashSet<>(); + final Set invalidChunks = new HashSet<>(); - public RecursiveProcessor(WorldAccessor world) { - this.world = world; - this.blockFlags = world.config().blockFlags(); - } + for (BlockPos block : blocks) { + for (var offset : offsets) { + BlockPos position = block.add(offset); - public void processPosition(BlockPos position) { - Objects.requireNonNull(position); + int chunkX = position.x() >> 4; + int chunkZ = position.z() >> 4; - for (var offset : offsets) { - updateBlock(position.add(offset)); - } - } + long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); + // TODO: use getChunkNow instead of getChunk with force load? + var chunk = chunks.computeIfAbsent(key, k -> world.getChunk(chunkX, chunkZ)); + if (chunk == null) { + continue; + } - private void updateBlock(BlockPos position) { - int chunkX = position.x() >> 4; - int chunkZ = position.z() >> 4; - long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); - var chunk = chunks.computeIfAbsent(key, k -> world.getChunk(chunkX, chunkZ)); - if (chunk != null) { int blockState = chunk.getBlockState(position.x(), position.y(), position.z()); - if (BlockFlags.isObfuscateBitSet(blockFlags.flags(blockState)) && updatedBlocks.add(position)) { - - // invalidate cache if enabled - if (config.cache().enabled()) { - ChunkCacheKey chunkPosition = new ChunkCacheKey(world, position); - if (this.invalidChunks.add(chunkPosition)) { - cache.invalidate(chunkPosition); - } + if (!(BlockFlags.isObfuscateBitSet(blockFlags.flags(blockState)) && updatedBlocks.add(position))) { + continue; + } + + if (config.cache().enabled()) { + ChunkCacheKey chunkPosition = new ChunkCacheKey(world, position); + if (invalidChunks.add(chunkPosition)) { + cache.invalidate(chunkPosition); } } } } - @Override - public void close() { - world.sendBlockUpdates(this.updatedBlocks); - } + world.sendBlockUpdates(updatedBlocks); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java index ac7884e2..c8db662c 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java @@ -35,7 +35,7 @@ public class ObfuscationProcessor { public ObfuscationProcessor(OrebfuscatorCore orebfuscator) { this.chunkFactory = orebfuscator.chunkFactory(); - this.registryAccessor = orebfuscator.getRegistry(); + this.registryAccessor = orebfuscator.registry(); this.statistics = orebfuscator.statistics(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java deleted file mode 100644 index 133c7e5a..00000000 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityDirectorThread.java +++ /dev/null @@ -1,170 +0,0 @@ -package dev.imprex.orebfuscator.proximity; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.Phaser; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; -import dev.imprex.orebfuscator.config.api.AdvancedConfig; -import dev.imprex.orebfuscator.interop.OrebfuscatorCore; -import dev.imprex.orebfuscator.interop.PlayerAccessor; -import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.statistics.ObfuscationStatistics; - -// TODO: rewrite to use new OrebfuscatorExecutor -public class ProximityDirectorThread extends Thread { - - private final OrebfuscatorCore orebfuscator; - private final ObfuscationStatistics statistics; - - private final int workerCount; - private final int defaultBucketSize; - private final long checkInterval; - - private final Phaser phaser = new Phaser(1); - private volatile boolean running = true; - - private final ProximityWorker worker; - private final ProximityWorkerThread[] workerThreads; - - private final BlockingQueue> bucketQueue = new LinkedBlockingQueue<>(); - - public ProximityDirectorThread(OrebfuscatorCore orebfuscator) { - super(OrebfuscatorCore.THREAD_GROUP, "orebfuscator-proximity-director"); - this.setDaemon(true); - - this.orebfuscator = orebfuscator; - this.statistics = orebfuscator.statistics().obfuscation; - - AdvancedConfig advancedConfig = orebfuscator.config().advanced(); - this.workerCount = advancedConfig.proximityThreads(); - this.defaultBucketSize = advancedConfig.proximityDefaultBucketSize(); - this.checkInterval = TimeUnit.MILLISECONDS.toNanos(advancedConfig.proximityThreadCheckInterval()); - - this.worker = new ProximityWorker(orebfuscator); - this.workerThreads = new ProximityWorkerThread[workerCount - 1]; - } - - @Override - public void start() { - super.start(); - - for (int i = 0; i < workerCount - 1; i++) { - this.workerThreads[i] = new ProximityWorkerThread(this, this.worker); - this.workerThreads[i].start(); - } - } - - public void close() { - this.running = false; - - this.interrupt(); - - for (int i = 0; i < workerCount - 1; i++) { - this.workerThreads[i].interrupt(); - } - - // technically not need but better be safe - this.phaser.forceTermination(); - } - - boolean isRunning() { - return this.running && !this.phaser.isTerminated(); - } - - List nextBucket() throws InterruptedException { - return this.bucketQueue.take(); - } - - void finishBucketProcessing() { - this.phaser.arriveAndDeregister(); - } - - @Override - public void run() { - while (this.isRunning()) { - try { - long processStart = System.nanoTime(); - List players = this.orebfuscator.getPlayers(); - - // park thread if no players are online - if (players.isEmpty()) { - // park for 1sec and retry - LockSupport.parkNanos(this, 1000000000L); - // reset interrupt flag - Thread.interrupted(); - continue; - } - - // get player count and derive max bucket size for each thread - int playerCount = players.size(); - int maxBucketSize = Math.max(this.defaultBucketSize, (int) Math.ceil((float) playerCount / this.workerCount)); - - // calculate bucket - int bucketCount = (int) Math.ceil((float) playerCount / maxBucketSize); - int bucketSize = (int) Math.ceil((float) playerCount / (float) bucketCount); - - // register extra worker threads in phaser - if (bucketCount > 1) { - this.phaser.bulkRegister(bucketCount - 1); - } - - // this threads local bucket - List localBucket = null; - - Iterator iterator = players.iterator(); - - // create buckets and fill queue - for (int index = 0; index < bucketCount; index++) { - List bucket = new ArrayList<>(); - - // fill bucket until bucket full or no players remain - for (int size = 0; size < bucketSize && iterator.hasNext(); size++) { - bucket.add(iterator.next()); - } - - // assign first bucket to current thread - if (index == 0) { - localBucket = bucket; - } else { - this.bucketQueue.offer(bucket); - } - } - - // process local bucket - if (localBucket != null) { - this.worker.process(localBucket); - } - - // wait for all threads to finish and reset phaser - this.phaser.awaitAdvanceInterruptibly(this.phaser.arrive()); - - long processTime = System.nanoTime() - processStart; - this.statistics.proximityProcess.add(processTime); - - // check if we have enough time to sleep - long waitTime = Math.max(0, this.checkInterval - processTime); - long waitMillis = TimeUnit.NANOSECONDS.toMillis(waitTime); - - if (waitMillis > 0) { - // measure wait time - this.statistics.proximityWait.add(TimeUnit.MILLISECONDS.toNanos(waitMillis)); - - Thread.sleep(waitMillis); - } - } catch (InterruptedException e) { - continue; - } catch (Exception e) { - OfcLogger.error(e); - } - } - - if (this.phaser.isTerminated() && this.running) { - OfcLogger.error("Looks like we encountered an invalid state, please report this:", - new IllegalStateException("Proximity Phaser terminated!")); - } - } -} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java new file mode 100644 index 00000000..ad74f8ac --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java @@ -0,0 +1,104 @@ +package dev.imprex.orebfuscator.proximity; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import dev.imprex.orebfuscator.config.api.AdvancedConfig; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.statistics.ObfuscationStatistics; +import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorExecutor; + +public class ProximitySystem implements Runnable { + + private final OrebfuscatorCore orebfuscator; + private final ObfuscationStatistics statistics; + private final OrebfuscatorExecutor executor; + + private final int workerCount; + private final int defaultBucketSize; + private final long checkInterval; + + private final ProximityWorker worker; + + public ProximitySystem(OrebfuscatorCore orebfuscator) { + this.orebfuscator = orebfuscator; + this.statistics = orebfuscator.statistics().obfuscation; + this.executor = orebfuscator.executor(); + + AdvancedConfig advancedConfig = orebfuscator.config().advanced(); + this.workerCount = advancedConfig.proximityThreads(); + this.defaultBucketSize = advancedConfig.proximityDefaultBucketSize(); + this.checkInterval = TimeUnit.MILLISECONDS.toNanos(advancedConfig.proximityThreadCheckInterval()); + + this.worker = new ProximityWorker(orebfuscator); + } + + public void start() { + this.executor.schedule(this, this.checkInterval, TimeUnit.NANOSECONDS); + } + + @Override + public void run() { + long processStart = System.nanoTime(); + process().whenComplete((v, throwable) -> { + if (throwable != null) { + OfcLogger.error("An error occurred while running proximity worker", throwable); + } + + if (this.executor.isShutdown()) { + return; + } + + long processTime = System.nanoTime() - processStart; + this.statistics.proximityProcess.add(processTime); + + // check if we have enough time to sleep + long waitTime = Math.max(0, this.checkInterval - processTime); + long waitMillis = TimeUnit.NANOSECONDS.toMillis(waitTime); + + if (waitMillis > 0) { + // measure wait time + this.statistics.proximityWait.add(TimeUnit.MILLISECONDS.toNanos(waitMillis)); + this.executor.schedule(this, waitMillis, TimeUnit.MILLISECONDS); + } else { + this.executor.execute(this); + } + }); + } + + private CompletableFuture process() { + var players = this.orebfuscator.players(); + if (players.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + + // get player count and derive max bucket size for each thread + int playerCount = players.size(); + int maxBucketSize = Math.max(this.defaultBucketSize, (int) Math.ceil((float) playerCount / this.workerCount)); + + // calculate bucket + int bucketCount = (int) Math.ceil((float) playerCount / maxBucketSize); + int bucketSize = (int) Math.ceil((float) playerCount / (float) bucketCount); + + var pendingFutures = new CompletableFuture[bucketCount]; + Iterator iterator = players.iterator(); + + // create buckets and fill queue + for (int index = 0; index < bucketCount; index++) { + List bucket = new ArrayList<>(); + + // fill bucket until bucket full or no players remain + for (int size = 0; size < bucketSize && iterator.hasNext(); size++) { + bucket.add(iterator.next()); + } + + pendingFutures[index] = CompletableFuture.runAsync(() -> this.worker.process(bucket), this.executor); + } + + return CompletableFuture.allOf(pendingFutures); + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java index f8e8f403..01783626 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java @@ -4,6 +4,7 @@ import java.util.List; import org.joml.FrustumIntersection; import org.joml.Quaternionf; +import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.config.OrebfuscatorConfig; import dev.imprex.orebfuscator.config.api.ProximityConfig; import dev.imprex.orebfuscator.interop.ChunkAccessor; @@ -24,11 +25,11 @@ public class ProximityWorker { public ProximityWorker(OrebfuscatorCore orebfuscator) { this.config = orebfuscator.config(); - this.registry = orebfuscator.getRegistry(); + this.registry = orebfuscator.registry(); } private boolean shouldIgnorePlayer(PlayerAccessor player) { - if (player.hasPermission("orebfuscator.bypass")) { + if (player.hasPermission(PermissionRequirements.BYPASS)) { return true; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java deleted file mode 100644 index 584319ec..00000000 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorkerThread.java +++ /dev/null @@ -1,40 +0,0 @@ -package dev.imprex.orebfuscator.proximity; - -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import dev.imprex.orebfuscator.interop.OrebfuscatorCore; -import dev.imprex.orebfuscator.interop.PlayerAccessor; -import dev.imprex.orebfuscator.logging.OfcLogger; - -public class ProximityWorkerThread extends Thread { - - private static final AtomicInteger NEXT_ID = new AtomicInteger(); - - private final ProximityDirectorThread directorThread; - private final ProximityWorker worker; - - public ProximityWorkerThread(ProximityDirectorThread directorThread, ProximityWorker worker) { - super(OrebfuscatorCore.THREAD_GROUP, "orebfuscator-proximity-worker-" + NEXT_ID.getAndIncrement()); - this.setDaemon(true); - - this.directorThread = directorThread; - this.worker = worker; - } - - @Override - public void run() { - while (this.directorThread.isRunning()) { - try { - List bucket = this.directorThread.nextBucket(); - - this.worker.process(bucket); - - this.directorThread.finishBucketProcessing(); - } catch (InterruptedException e) { - continue; - } catch (Exception e) { - OfcLogger.error(e); - } - } - } -} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java index c91d1b51..e613d030 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java @@ -3,11 +3,18 @@ import java.util.Map; import java.util.Objects; import java.util.StringJoiner; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.LongSupplier; +import dev.imprex.orebfuscator.config.api.CacheConfig; +import dev.imprex.orebfuscator.config.api.Config; +import dev.imprex.orebfuscator.util.RollingAverage; +import dev.imprex.orebfuscator.util.RollingTimer; public class CacheStatistics implements StatisticsSource { + + private final CacheConfig config; private final AtomicLong cacheHitCountMemory = new AtomicLong(0); private final AtomicLong cacheHitCountDisk = new AtomicLong(0); @@ -17,6 +24,15 @@ public class CacheStatistics implements StatisticsSource { private LongSupplier memoryCacheEntryCount = () -> 0; private LongSupplier diskCacheQueueLength = () -> 0; + private final RollingAverage diskCacheReadBytes = new RollingAverage(4096); + private final RollingAverage diskCacheWriteBytes = new RollingAverage(4096); + public final RollingTimer diskCacheWaitTime = new RollingTimer(4096); + public final RollingTimer diskCacheReadTime = new RollingTimer(4096); + public final RollingTimer diskCacheWriteTime = new RollingTimer(4096); + + public CacheStatistics(Config config) { + this.config = config.cache(); + } public void onCacheHitMemory() { this.cacheHitCountMemory.incrementAndGet(); @@ -41,6 +57,14 @@ public void setMemoryCacheEntryCount(LongSupplier supplier) { public void setDiskCacheQueueLength(LongSupplier supplier) { this.diskCacheQueueLength = Objects.requireNonNull(supplier); } + + public void onDiskCacheRead(long bytes) { + this.diskCacheReadBytes.add(bytes); + } + + public void onDiskCacheWrite(long bytes) { + this.diskCacheWriteBytes.add(bytes); + } public void add(StringJoiner joiner) { long cacheHitCountMemory = this.cacheHitCountMemory.get(); @@ -71,9 +95,39 @@ public void add(StringJoiner joiner) { joiner.add(String.format(" - memoryCache (count/bytesPerEntry): %s / %s ", memoryCacheEntryCount, bytes(memoryCacheBytesPerEntry))); - long diskCacheQueueLength = this.diskCacheQueueLength.getAsLong(); - - joiner.add(String.format(" - diskCache (queue): %s ", diskCacheQueueLength)); + if (this.config.enableDiskCache()) { + long diskCacheQueueLength = this.diskCacheQueueLength.getAsLong(); + + joiner.add(String.format(" - diskCache (queue): %s", diskCacheQueueLength)); + + long diskCacheWaitTime = (long) this.diskCacheWaitTime.average(); + long diskCacheReadTime = (long) this.diskCacheReadTime.average(); + long diskCacheWriteTime = (long) this.diskCacheWriteTime.average(); + + joiner.add(String.format(" - diskCacheTime (wait/read/write): %s / %s / %s", + time(diskCacheWaitTime), time(diskCacheReadTime), time(diskCacheWriteTime))); + + long diskCacheReadBytes = (long) this.diskCacheReadBytes.average(); + long diskCacheWriteBytes = (long) this.diskCacheWriteBytes.average(); + + double diskCacheReadTimeSeconds = 1d; + if (diskCacheReadTime > 0) { + diskCacheReadTimeSeconds = (double) diskCacheReadTime / (double) TimeUnit.SECONDS.toNanos(1); + } + long diskCacheReadBytesPerSecond = Math.round((double) diskCacheReadBytes / diskCacheReadTimeSeconds); + + double diskCacheWriteTimeSeconds = 1d; + if (diskCacheWriteTime > 0) { + diskCacheWriteTimeSeconds = (double) diskCacheWriteTime / (double) TimeUnit.SECONDS.toNanos(1); + } + long diskCacheWriteBytesPerSecond = Math.round((double) diskCacheWriteBytes / diskCacheWriteTimeSeconds); + + joiner.add(String.format(" - diskCacheThroughput (read/write): %s/s / %s/s", + bytes(diskCacheReadBytesPerSecond), bytes(diskCacheWriteBytesPerSecond))); + + joiner.add(String.format(" - diskCacheTaskSize (read/write): %s / %s", + bytes(diskCacheReadBytes), bytes(diskCacheWriteBytes))); + } } @Override @@ -86,5 +140,10 @@ public void debug(Consumer> consumer) { consumer.accept(Map.entry("memoryCacheEntryCount", Long.toString(memoryCacheEntryCount.getAsLong()))); consumer.accept(Map.entry("diskCacheQueueLength", Long.toString(diskCacheQueueLength.getAsLong()))); + consumer.accept(Map.entry("diskCacheReadBytes", diskCacheReadBytes.debugLong(this::bytes))); + consumer.accept(Map.entry("diskCacheWriteBytes", diskCacheWriteBytes.debugLong(this::bytes))); + consumer.accept(Map.entry("diskCacheWaitTime", diskCacheWaitTime.debugLong(this::time))); + consumer.accept(Map.entry("diskCacheReadTime", diskCacheReadTime.debugLong(this::time))); + consumer.accept(Map.entry("diskCacheWriteTime", diskCacheWriteTime.debugLong(this::time))); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java index 4288440a..71eae0a1 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java @@ -8,9 +8,9 @@ public class ObfuscationStatistics implements StatisticsSource { - public final RollingTimer debofuscation = new RollingTimer(8192); + public final RollingTimer debofuscation = new RollingTimer(4096); - public final RollingTimer executorWaitTime = new RollingTimer(8192); + public final RollingTimer executorWaitTime = new RollingTimer(4096); public final RollingTimer executorUtilization = new RollingTimer(4096); public final RollingTimer proximityWait = new RollingTimer(4096); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java index c9dbb7e7..ba08d541 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java @@ -4,11 +4,13 @@ public class OrebfuscatorStatistics { - public final CacheStatistics cache = new CacheStatistics(); + public final CacheStatistics cache; public final InjectorStatistics injector = new InjectorStatistics(); public final ObfuscationStatistics obfuscation = new ObfuscationStatistics(); public OrebfuscatorStatistics(Config config, StatisticsRegistry registry) { + this.cache = new CacheStatistics(config); + if (config.cache().enabled()) { registry.register("cache", this.cache); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/AbstractHttpService.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/AbstractHttpService.java similarity index 75% rename from orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/AbstractHttpService.java rename to orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/AbstractHttpService.java index 1ab196ce..7d6c8d7e 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/AbstractHttpService.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/AbstractHttpService.java @@ -1,4 +1,4 @@ -package net.imprex.orebfuscator.util; +package dev.imprex.orebfuscator.util; import java.io.IOException; import java.io.InputStreamReader; @@ -10,14 +10,9 @@ import java.net.http.HttpResponse.BodySubscribers; import java.nio.charset.StandardCharsets; import java.util.Optional; - -import org.bukkit.plugin.PluginDescriptionFile; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; - -import dev.imprex.orebfuscator.util.Version; -import net.imprex.orebfuscator.Orebfuscator; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; public abstract class AbstractHttpService { @@ -29,9 +24,8 @@ public abstract class AbstractHttpService { protected final String userAgent; - public AbstractHttpService(Orebfuscator orebfuscator) { - PluginDescriptionFile plugin = orebfuscator.getDescription(); - this.userAgent = String.format("Imprex-Development/%s/%s", plugin.getName(), plugin.getVersion()); + public AbstractHttpService(OrebfuscatorCore orebfuscator) { + this.userAgent = String.format("Imprex-Development/%s/%s", orebfuscator.name(), orebfuscator.orebfuscatorVersion()); } protected HttpRequest.Builder request(String url) { @@ -48,7 +42,6 @@ protected static BodyHandler> optionalJson(Class target) { } catch (IOException e) { throw new UncheckedIOException("I/O while reading JSON", e); } - }) - : BodySubscribers.replacing(Optional.empty()); + }) : BodySubscribers.replacing(Optional.empty()); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/ConsoleUtil.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ConsoleUtil.java similarity index 90% rename from orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/ConsoleUtil.java rename to orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ConsoleUtil.java index 7333b96d..6ae4372c 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/ConsoleUtil.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ConsoleUtil.java @@ -1,11 +1,8 @@ -package net.imprex.orebfuscator.util; +package dev.imprex.orebfuscator.util; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import org.bukkit.ChatColor; - import dev.imprex.orebfuscator.logging.LogLevel; import dev.imprex.orebfuscator.logging.OfcLogger; @@ -18,9 +15,9 @@ private ConsoleUtil() { } public static String replaceAnsiColorWithChatColor(String value) { - value = value.replaceAll("\u001B\\[m", ChatColor.RESET.toString()); - value = value.replaceAll("\u001B\\[31;1m", ChatColor.RED.toString()); - value = value.replaceAll("\u001B\\[33;1m", ChatColor.YELLOW.toString()); + value = value.replaceAll("\u001B\\[m", "\u00A7r"); + value = value.replaceAll("\u001B\\[31;1m", "\u00A7c"); + value = value.replaceAll("\u001B\\[33;1m", "\u00A7e"); return value; } 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 d1530283..00691f60 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 @@ -9,9 +9,10 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; @NullMarked -public record Version(int major, int minor, int patch) implements Comparable { +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+))?(?.*)?"); @@ -36,7 +37,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) { @@ -104,7 +107,7 @@ public boolean equals(Object obj) { @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, this.suffix); } public static final class Json extends TypeAdapter { 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 index 20c9e13b..150b7d38 100644 --- 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 @@ -5,18 +5,18 @@ 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; -// TODO: public schedule method @NullMarked public class OrebfuscatorExecutor implements Executor { - private final ScheduledExecutorService scheduledExecutorService = - Executors.newScheduledThreadPool(1, r -> new Thread(OrebfuscatorCore.THREAD_GROUP, r, "orebfuscator-scheduler")); + private final ScheduledExecutorService scheduledExecutorService = Executors + .newSingleThreadScheduledExecutor(r -> new Thread(OrebfuscatorCore.THREAD_GROUP, r, "orebfuscator-scheduler")); private final int poolSize; private final ExecutorService executorService; @@ -48,6 +48,23 @@ public void execute(Runnable 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 { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index 4dc61791..9f0eaaa0 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -11,6 +11,7 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; +import dev.imprex.orebfuscator.UpdateSystem; import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; import dev.imprex.orebfuscator.cache.ObfuscationCache; import dev.imprex.orebfuscator.chunk.ChunkFactory; @@ -22,7 +23,7 @@ import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; import dev.imprex.orebfuscator.obfuscation.ObfuscationProcessor; -import dev.imprex.orebfuscator.proximity.ProximityDirectorThread; +import dev.imprex.orebfuscator.proximity.ProximitySystem; import dev.imprex.orebfuscator.statistics.OrebfuscatorStatistics; import dev.imprex.orebfuscator.statistics.StatisticsRegistry; import dev.imprex.orebfuscator.util.Version; @@ -50,7 +51,7 @@ public class Orebfuscator extends JavaPlugin implements Listener, OrebfuscatorCo private ObfuscationPipeline obfuscationPipeline; private ObfuscationSystem obfuscationSystem; - private ProximityDirectorThread proximityThread; + private ProximitySystem proximitySystem; private ProximityPacketListener proximityPacketListener; private UpdateSystem updateSystem; @@ -81,7 +82,7 @@ public void onEnable() { BukkitPlayerAccessor.registerListener(this); new MetricsSystem(this); - this.updateSystem = new UpdateSystem(this); + this.updateSystem = new UpdateSystem(this, "bukkit"); this.statistics = new OrebfuscatorStatistics(this.config, this.statisticsRegistry); this.executor = new OrebfuscatorExecutor(this); @@ -92,9 +93,9 @@ public void onEnable() { this.obfuscationPipeline = new ObfuscationPipeline(this); this.obfuscationSystem = new ObfuscationSystem(this); - this.proximityThread = new ProximityDirectorThread(this); + this.proximitySystem = new ProximitySystem(this); if (this.config.proximityEnabled()) { - this.proximityThread.start(); + this.proximitySystem.start(); this.proximityPacketListener = new ProximityPacketListener(this); } @@ -120,6 +121,10 @@ public void onEnable() { @Override public void onDisable() { + if (this.executor != null) { + this.executor.shutdown(); + } + if (this.obfuscationCache != null) { this.obfuscationCache.close(); } @@ -128,10 +133,8 @@ public void onDisable() { this.obfuscationSystem.shutdown(); } - if (this.config != null && this.config.proximityEnabled() && this.proximityPacketListener != null - && this.proximityThread != null) { + if (this.config != null && this.config.proximityEnabled() && this.proximityPacketListener != null) { this.proximityPacketListener.unregister(); - this.proximityThread.close(); } OrebfuscatorCompatibility.close(); @@ -201,27 +204,32 @@ public boolean isGameThread() { } @Override - public Path getConfigDirectory() { + public Path configDirectory() { return getDataFolder().toPath(); } @Override - public Path getWorldDirectory() { + public Path worldDirectory() { return Bukkit.getWorldContainer().toPath(); } + + @Override + public String name() { + return getDescription().getName(); + } @Override - public Version getOrebfuscatorVersion() { + public Version orebfuscatorVersion() { return Version.parse(getDescription().getVersion()); } @Override - public Version getMinecraftVersion() { + public Version minecraftVersion() { return MinecraftVersion.current(); } @Override - public RegistryAccessor getRegistry() { + public RegistryAccessor registry() { return OrebfuscatorNms.registry(); } @@ -231,14 +239,14 @@ public AbstractRegionFileCache createRegionFileCache() { } @Override - public List getWorlds() { + public List worlds() { return BukkitWorldAccessor.getWorlds().stream() .map(WorldAccessor.class::cast) .toList(); } @Override - public List getPlayers() { + public List players() { return BukkitPlayerAccessor.getAll().stream() .map(PlayerAccessor.class::cast) .toList(); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java index 313d9248..775c5062 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java @@ -28,7 +28,7 @@ import com.google.gson.JsonObject; import com.google.gson.internal.Streams; import com.google.gson.stream.JsonWriter; - +import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.util.JavaVersion; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; @@ -55,13 +55,13 @@ public boolean onCommand(CommandSender sender, Command command, String label, St return false; } - if (!PermissionUtil.canAccessAdminTools(sender)) { + if (!PermissionUtil.hasPermission(sender, PermissionRequirements.ADMIN)) { sender.sendMessage("You don't have the 'orebfuscator.admin' permission."); return false; } if (args.length == 0) { - sender.sendMessage("You are using " + this.orebfuscator.toString()); + sender.sendMessage("You are using %s %s".formatted(this.orebfuscator.name(), this.orebfuscator.orebfuscatorVersion())); sender.sendMessage(this.orebfuscator.statisticsRegistry().format()); } else if (args[0].equalsIgnoreCase("dump")) { TemporalAccessor now = OffsetDateTime.now(ZoneOffset.UTC); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java index fbd903f2..718ad3d1 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java @@ -15,6 +15,7 @@ import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.potion.PotionEffectType; import org.jspecify.annotations.Nullable; +import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.interop.OrebfuscatorCore; import dev.imprex.orebfuscator.interop.PlayerAccessor; import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; @@ -23,6 +24,7 @@ import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.OrebfuscatorNms; +import net.imprex.orebfuscator.util.PermissionUtil; public class BukkitPlayerAccessor implements PlayerAccessor { @@ -131,8 +133,8 @@ public double lavaFogDistance() { } @Override - public boolean hasPermission(String permission) { - return player.hasPermission(permission); + public boolean hasPermission(PermissionRequirements permission) { + return PermissionUtil.hasPermission(player, permission); } @Override diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java index eeaaacae..e5a00dfb 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java @@ -18,11 +18,18 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; +import dev.imprex.orebfuscator.PermissionRequirements; +import dev.imprex.orebfuscator.UpdateSystem; import dev.imprex.orebfuscator.config.OrebfuscatorConfig; +import dev.imprex.orebfuscator.util.ConsoleUtil; import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.UpdateSystem; -import net.imprex.orebfuscator.util.ConsoleUtil; +import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.util.PermissionUtil; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.hover.content.Text; public class DeobfuscationListener implements Listener { @@ -98,17 +105,27 @@ public void onPlayerInteract(PlayerInteractEvent event) { public void onJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - if (this.config.general().bypassNotification() && PermissionUtil.canBypassObfuscate(player)) { + if (this.config.general().bypassNotification() && PermissionUtil.hasPermission(player, PermissionRequirements.BYPASS)) { player.sendMessage( "[§bOrebfuscator§f]§7 You bypass Orebfuscator because you have the 'orebfuscator.bypass' permission."); } - if (PermissionUtil.canAccessAdminTools(player)) { + if (PermissionUtil.hasPermission(player, PermissionRequirements.ADMIN)) { String configReport = this.config.report(); if (configReport != null) { player.sendMessage("[§bOrebfuscator§f]§c " + ConsoleUtil.replaceAnsiColorWithChatColor(configReport)); } - this.updateSystem.checkForUpdates(player); + + this.updateSystem.ifNewerDownloadAvailable(downloadUri -> { + BaseComponent[] components = new ComponentBuilder("[§bOrebfuscator§f]§7 A new release is available ") + .append("§f§l[CLICK HERE]") + .event(new ClickEvent(ClickEvent.Action.OPEN_URL, downloadUri)) + .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new Text(new ComponentBuilder("§7Click here to see the latest release").create()))).create(); + OrebfuscatorCompatibility.runForPlayer(player, () -> { + player.spigot().sendMessage(components); + }); + }); } } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java index c8b49f9d..afc69fd7 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java @@ -10,6 +10,7 @@ import com.comphenix.protocol.async.AsyncListenerHandler; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketEvent; +import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; @@ -83,7 +84,7 @@ public void onPacketSending(PacketEvent event) { } BukkitWorldAccessor world = player.world(); - if (player.hasPermission("orebfuscator.bypass") || !world.config().needsObfuscation()) { + if (player.hasPermission(PermissionRequirements.BYPASS) || !world.config().needsObfuscation()) { return; } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java index ec16158e..3f3ca2e0 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java @@ -8,6 +8,7 @@ import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.ChunkCoordIntPair; +import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.config.api.ProximityConfig; import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; import net.imprex.orebfuscator.Orebfuscator; @@ -35,7 +36,7 @@ public void unregister() { @Override public void onPacketSending(PacketEvent event) { BukkitPlayerAccessor player = BukkitPlayerAccessor.tryGet(event.getPlayer()); - if (player == null || player.hasPermission("orebfuscator.bypass")) { + if (player == null || player.hasPermission(PermissionRequirements.BYPASS)) { return; } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java index 9d7946d4..9bde8c57 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java @@ -1,19 +1,12 @@ package net.imprex.orebfuscator.util; import org.bukkit.permissions.Permissible; +import dev.imprex.orebfuscator.PermissionRequirements; public class PermissionUtil { - public static boolean canBypassObfuscate(Permissible permissible) { - try { - return permissible.hasPermission("orebfuscator.bypass"); - } catch (UnsupportedOperationException e) { - // fix #131: catch TemporaryPlayer not implementing hasPermission - return false; - } - } - - public static boolean canAccessAdminTools(Permissible permissible) { - return permissible.isOp() || permissible.hasPermission("orebfuscator.admin"); + public static boolean hasPermission(Permissible permissible, PermissionRequirements check) { + return (check.operatorLevel().isPresent() && permissible.isOp()) + || (check.permission().isPresent() && permissible.hasPermission(check.permission().get())); } } From 07782e5570c412ea4ad175746cdc4a1d3df132d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sun, 18 Jan 2026 19:47:26 +0100 Subject: [PATCH 05/14] perf: add todos for possible next step to improve pref --- .../imprex/orebfuscator/api/OrebfuscatorService.java | 2 ++ .../imprex/orebfuscator/PermissionRequirements.java | 2 ++ .../java/dev/imprex/orebfuscator/UpdateSystem.java | 6 ++++-- .../orebfuscator/config/AbstractWorldConfig.java | 2 ++ .../orebfuscator/player/OrebfuscatorPlayer.java | 2 +- .../orebfuscator/util/AbstractHttpService.java | 2 ++ .../orebfuscator/DefaultOrebfuscatorService.java | 6 ++++-- .../java/net/imprex/orebfuscator/MetricsSystem.java | 12 +++++------- .../orebfuscator/iterop/BukkitPlayerAccessor.java | 2 ++ .../orebfuscator/iterop/BukkitWorldAccessor.java | 1 + .../obfuscation/DeobfuscationListener.java | 1 + .../obfuscation/ObfuscationListener.java | 6 ++++++ .../orebfuscator/obfuscation/ObfuscationSystem.java | 1 + .../proximity/ProximityPacketListener.java | 1 + .../net/imprex/orebfuscator/util/PermissionUtil.java | 2 ++ .../util/WrappedClientboundLevelChunkPacketData.java | 2 ++ 16 files changed, 38 insertions(+), 12 deletions(-) diff --git a/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java b/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java index 9a0d8bf7..096f9faa 100644 --- a/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java +++ b/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java @@ -3,6 +3,7 @@ import java.util.Collection; import org.bukkit.block.Block; +import org.jspecify.annotations.NullMarked; /** *

@@ -16,6 +17,7 @@ * * @since 5.2.0 */ +@NullMarked public interface OrebfuscatorService { /** diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java index 62598b4f..bd64e355 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java @@ -2,7 +2,9 @@ import java.util.Optional; import java.util.OptionalInt; +import org.jspecify.annotations.NullMarked; +@NullMarked public record PermissionRequirements(OptionalInt operatorLevel, Optional permission) { public static final PermissionRequirements BYPASS = new PermissionRequirements(OptionalInt.empty(), Optional.of("orebfuscator.bypass")); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java index 14f2902f..5f8ad5c3 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java @@ -21,6 +21,7 @@ import dev.imprex.orebfuscator.util.AbstractHttpService; import dev.imprex.orebfuscator.util.ConsoleUtil; import dev.imprex.orebfuscator.util.Version; +import org.jspecify.annotations.Nullable; @NullMarked public class UpdateSystem extends AbstractHttpService { @@ -42,8 +43,9 @@ private static boolean isDevVersion(String version) { private final OrebfuscatorCore orebfuscator; private final GeneralConfig generalConfig; - private final AtomicReference validUntil = new AtomicReference<>(); - private final AtomicReference>> latestVersion = new AtomicReference<>(); + private final AtomicReference<@Nullable Instant> validUntil = new AtomicReference<>(); + private final AtomicReference<@Nullable CompletableFuture>> latestVersion + = new AtomicReference<>(); public UpdateSystem(OrebfuscatorCore orebfuscator, String loader) { super(orebfuscator); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java index 8a06bed0..e33daea2 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java @@ -76,6 +76,8 @@ protected void deserializeRandomBlocks(BlockParser.Factory blockParserFactory, C return; } + // TODO: validate each height has some valid values or limit height or use some default fill in value + for (ConfigurationSection subSection : subSectionContainer.getSubSections()) { ConfigParsingContext subContext = context.section(subSection.getName()); this.weightedBlockLists.add(new WeightedBlockList(blockParserFactory, subSection, subContext)); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java index 8d3c804d..c87537b4 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayer.java @@ -109,7 +109,7 @@ public void addChunk(WorldAccessor world, int chunkX, int chunkZ, List PLAYER_COUNT_GROUPS = new TreeMap<>(); @@ -89,8 +89,6 @@ public void addUsageCharts(OrebfuscatorConfig config) { this.metrics.addCustomChart(new SimplePie("frustum_culling", () -> { return Boolean.toString(config.usesFrustumCulling()); })); - this.metrics.addCustomChart(new SimplePie("ray_cast", () -> { - return config.usesRayCastCheck(); - })); + this.metrics.addCustomChart(new SimplePie("ray_cast", config::usesRayCastCheck)); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java index 718ad3d1..83d36c14 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java @@ -26,6 +26,8 @@ import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.util.PermissionUtil; +// TODO: abstract static listener away into common management class, same thing for worlds as well +// TODO: Nullability public class BukkitPlayerAccessor implements PlayerAccessor { private static final Map PLAYERS = new HashMap<>(); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java index b529503e..00ac31db 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java @@ -26,6 +26,7 @@ import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.util.MinecraftVersion; +// TODO: Nullability public class BukkitWorldAccessor implements WorldAccessor { private static final boolean HAS_DYNAMIC_HEIGHT = MinecraftVersion.isAtOrAbove("1.17"); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java index e5a00dfb..7044cdd5 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java @@ -31,6 +31,7 @@ import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.hover.content.Text; +// TODO: Nullability public class DeobfuscationListener implements Listener { public static void createAndRegister(Orebfuscator orebfuscator, ObfuscationSystem obfuscationSystem) { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java index afc69fd7..b3834e36 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java @@ -19,6 +19,12 @@ import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.util.ServerVersion; +// TODO: Nullability +// TODO: add sync map chunk packet listener that starts obfuscation on the main thread and tries to get neighboring chunks +// now to reduce the potential wait time for async chunk requests. +// TODO: add support for chunk batch system in sync listener (cancel) any packets and track current batch. On batch delimiter use +// future.all and send all packets at once for server to trigger multple write and single flush. +// TODO: maybe replace async listener entirely with sync listener and packet queue public class ObfuscationListener extends PacketAdapter { private static final List PACKET_TYPES = Arrays.asList( diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java index 2680dbac..563ca99f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java @@ -7,6 +7,7 @@ import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; +// TODO: Nullability public class ObfuscationSystem { private final Orebfuscator orebfuscator; diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java index 3f3ca2e0..89a7ddcc 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java @@ -16,6 +16,7 @@ import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.util.MinecraftVersion; +// TODO: Nullability public class ProximityPacketListener extends PacketAdapter { private static final boolean HAS_CHUNK_POS_FIELD = MinecraftVersion.isAtOrAbove("1.20.2"); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java index 9bde8c57..5d33193f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java @@ -2,7 +2,9 @@ import org.bukkit.permissions.Permissible; import dev.imprex.orebfuscator.PermissionRequirements; +import org.jspecify.annotations.NullMarked; +@NullMarked public class PermissionUtil { public static boolean hasPermission(Permissible permissible, PermissionRequirements check) { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java index d6546dc3..323db9fc 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java @@ -11,6 +11,8 @@ import dev.imprex.orebfuscator.util.BlockPos; +// TODO: replace all ProtocolLib reflections with own reflect lib +// TODO: Nullability public class WrappedClientboundLevelChunkPacketData { private static final Class CLIENTBOUND_LEVEL_CHUNK_PACKET_DATA = MinecraftReflection.getMinecraftClass( From adb14064c0beb0981cefcf8cf09067f1ce5c30c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Tue, 20 Jan 2026 20:48:15 +0100 Subject: [PATCH 06/14] feat: use sync listener to start obfuscation but complete in async listener --- .../OrebfuscatorCompatibility.java | 8 +- .../compatibility/CompatibilityLayer.java | 4 +- .../bukkit/BukkitChunkLoader.java | 45 ++++++----- .../bukkit/BukkitCompatibilityLayer.java | 14 +++- .../AbstractPaperCompatibilityLayer.java | 38 ++++++---- .../obfuscation/ObfuscationPipeline.java | 4 +- .../iterop/BukkitChunkPacketAccessor.java | 2 + .../iterop/BukkitPlayerAccessor.java | 43 ++++++++++- .../iterop/BukkitWorldAccessor.java | 6 +- .../obfuscation/DeobfuscationListener.java | 3 +- ...ner.java => ObfuscationAsyncListener.java} | 75 ++++++++++++------- .../obfuscation/ObfuscationSyncListener.java | 57 ++++++++++++++ .../obfuscation/ObfuscationSystem.java | 16 +++- .../obfuscation/PendingChunkBatch.java | 56 ++++++++++++++ .../proximity/ProximityPacketListener.java | 3 +- ...rappedClientboundLevelChunkPacketData.java | 5 +- 16 files changed, 294 insertions(+), 85 deletions(-) rename orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/{ObfuscationListener.java => ObfuscationAsyncListener.java} (58%) create mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java create mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java index 71b94d0e..a18f05b4 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java @@ -8,10 +8,10 @@ import org.bukkit.plugin.Plugin; import dev.imprex.orebfuscator.config.api.Config; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.util.ChunkCacheKey; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import net.imprex.orebfuscator.compatibility.CompatibilityLayer; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.imprex.orebfuscator.util.ServerVersion; public class OrebfuscatorCompatibility { @@ -64,8 +64,8 @@ public static void cancelTasks() { instance.getScheduler().cancelTasks(); } - public static CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { - return instance.getNeighboringChunks(world, key); + public static CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request) { + return instance.getNeighboringChunks(world, request); } public static void close() { diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java index 79fb1b8b..4074ee4c 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java @@ -4,8 +4,8 @@ import org.bukkit.World; -import dev.imprex.orebfuscator.util.ChunkCacheKey; import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; public interface CompatibilityLayer { @@ -13,5 +13,5 @@ public interface CompatibilityLayer { CompatibilityScheduler getScheduler(); - CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key); + CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request); } diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java index 6267ac9b..0976412d 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java @@ -4,20 +4,19 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; - import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.plugin.Plugin; - import dev.imprex.orebfuscator.config.api.Config; -import dev.imprex.orebfuscator.util.ChunkCacheKey; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import dev.imprex.orebfuscator.util.ChunkDirection; import net.imprex.orebfuscator.OrebfuscatorNms; -import dev.imprex.orebfuscator.interop.ChunkAccessor; public class BukkitChunkLoader implements Runnable { - private final Queue requests = new ConcurrentLinkedQueue<>(); + private final Queue tasks = new ConcurrentLinkedQueue<>(); private final long availableNanosPerTick; @@ -27,43 +26,51 @@ public BukkitChunkLoader(Plugin plugin, Config config) { Bukkit.getScheduler().runTaskTimer(plugin, this, 0, 1); } - public CompletableFuture submitRequest(World world, ChunkCacheKey key) { - Request request = new Request(world, key); - this.requests.offer(request); - return request.future; + public CompletableFuture submitRequest(World world, ObfuscationRequest request) { + Task task = new Task(world, request); + this.tasks.offer(task); + return task.future; } @Override public void run() { final long time = System.nanoTime(); - Request request = null; - while (System.nanoTime() - time < this.availableNanosPerTick && (request = this.requests.poll()) != null) { - request.run(); + Task task = null; + while (System.nanoTime() - time < this.availableNanosPerTick && (task = this.tasks.poll()) != null) { + task.run(); } } - private class Request implements Runnable { + private class Task implements Runnable { private final World world; - private final ChunkCacheKey key; + private final ObfuscationRequest request; private final CompletableFuture future = new CompletableFuture<>(); - public Request(World world, ChunkCacheKey key) { + public Task(World world, ObfuscationRequest request) { this.world = world; - this.key = key; + this.request = request; } @Override public void run() { + final ChunkPacketAccessor packet = this.request.packet(); final ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; for (ChunkDirection direction : ChunkDirection.values()) { - int chunkX = key.x() + direction.getOffsetX(); - int chunkZ = key.z() + direction.getOffsetZ(); + int chunkX = packet.chunkX() + direction.getOffsetX(); + int chunkZ = packet.chunkZ() + direction.getOffsetZ(); + + int index = direction.ordinal(); + var chunk = this.request.neighborChunks()[index]; - neighboringChunks[direction.ordinal()] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); + if (chunk != null) { + neighboringChunks[index] = chunk; + } else { + neighboringChunks[index] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); + } } future.complete(neighboringChunks); diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java index 62a0c59c..6f286432 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java @@ -1,15 +1,17 @@ package net.imprex.orebfuscator.compatibility.bukkit; +import java.util.Arrays; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import org.bukkit.World; import org.bukkit.plugin.Plugin; import dev.imprex.orebfuscator.config.api.Config; -import dev.imprex.orebfuscator.util.ChunkCacheKey; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import net.imprex.orebfuscator.compatibility.CompatibilityLayer; import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; -import dev.imprex.orebfuscator.interop.ChunkAccessor; public class BukkitCompatibilityLayer implements CompatibilityLayer { @@ -34,7 +36,11 @@ public CompatibilityScheduler getScheduler() { } @Override - public CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { - return this.chunkLoader.submitRequest(world, key); + public CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request) { + if (!Arrays.stream(request.neighborChunks()).anyMatch(Objects::isNull)) { + return CompletableFuture.completedFuture(request.neighborChunks()); + } + + return this.chunkLoader.submitRequest(world, request); } } diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java index c63218e0..2c6b3a78 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java @@ -1,30 +1,42 @@ package net.imprex.orebfuscator.compatibility.paper; +import java.util.Arrays; +import java.util.Objects; import java.util.concurrent.CompletableFuture; - import org.bukkit.World; - -import dev.imprex.orebfuscator.util.ChunkCacheKey; +import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; +import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import dev.imprex.orebfuscator.util.ChunkDirection; import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.compatibility.CompatibilityLayer; -import dev.imprex.orebfuscator.interop.ChunkAccessor; public abstract class AbstractPaperCompatibilityLayer implements CompatibilityLayer { @Override - public CompletableFuture getNeighboringChunks(World world, ChunkCacheKey key) { - CompletableFuture[] futures = new CompletableFuture[4]; - ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; + public CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request) { + if (!Arrays.stream(request.neighborChunks()).anyMatch(Objects::isNull)) { + return CompletableFuture.completedFuture(request.neighborChunks()); + } + + final ChunkPacketAccessor packet = request.packet(); + final CompletableFuture[] futures = new CompletableFuture[4]; + final ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; for (ChunkDirection direction : ChunkDirection.values()) { - int chunkX = key.x() + direction.getOffsetX(); - int chunkZ = key.z() + direction.getOffsetZ(); - int index = direction.ordinal(); + int chunkX = packet.chunkX() + direction.getOffsetX(); + int chunkZ = packet.chunkZ() + direction.getOffsetZ(); - futures[index] = world.getChunkAtAsync(chunkX, chunkZ).thenAccept(chunk -> { - neighboringChunks[index] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); - }); + int index = direction.ordinal(); + var chunk = request.neighborChunks()[index]; + + if (chunk != null) { + futures[index] = CompletableFuture.completedFuture(chunk); + } else { + futures[index] = world.getChunkAtAsync(chunkX, chunkZ).thenAccept(c -> { + neighboringChunks[index] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); + }); + } } return CompletableFuture.allOf(futures).thenApply(v -> neighboringChunks); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java index 5abc2872..ffb61472 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java @@ -57,9 +57,6 @@ private CompletionStage requestInternal( final var request = new ObfuscationRequest(world, player, packet, neighborChunks); - final var neighborTimer = statistics.injector.pipelineDelayNeighbors.start(); -// final var neighborFuture = neighborTimer.wrap(world.getNeighboringChunks(request)); - final CacheRequest cacheRequest; final CompletionStage> cacheFuture; @@ -85,6 +82,7 @@ private CompletionStage requestInternal( if (optional.isPresent()) { return CompletableFuture.completedStage(optional.get()); } else { + final var neighborTimer = statistics.injector.pipelineDelayNeighbors.start(); return neighborTimer.wrap(world.getNeighboringChunks(request)) .handleAsync((neighbors, throwable) -> { if (throwable != null) { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java index 7dd35b79..40ae2da2 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java @@ -4,6 +4,7 @@ import java.util.Iterator; import java.util.List; import java.util.function.Predicate; +import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.nbt.NbtBase; @@ -14,6 +15,7 @@ import net.imprex.orebfuscator.util.MinecraftVersion; import net.imprex.orebfuscator.util.WrappedClientboundLevelChunkPacketData; +@NullMarked public class BukkitChunkPacketAccessor implements ChunkPacketAccessor { private static final boolean HAS_CLIENTBOUND_LEVEL_CHUNK_PACKET_DATA = MinecraftVersion.isAtOrAbove("1.18"); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java index 83d36c14..28821007 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.WeakHashMap; +import java.util.concurrent.CompletableFuture; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.entity.Player; @@ -14,7 +16,10 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.potion.PotionEffectType; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import com.comphenix.protocol.AsynchronousManager; +import com.comphenix.protocol.events.PacketEvent; import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.interop.OrebfuscatorCore; import dev.imprex.orebfuscator.interop.PlayerAccessor; @@ -24,10 +29,11 @@ import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.OrebfuscatorNms; +import net.imprex.orebfuscator.obfuscation.PendingChunkBatch; import net.imprex.orebfuscator.util.PermissionUtil; // TODO: abstract static listener away into common management class, same thing for worlds as well -// TODO: Nullability +@NullMarked public class BukkitPlayerAccessor implements PlayerAccessor { private static final Map PLAYERS = new HashMap<>(); @@ -86,17 +92,52 @@ public static List getAll() { return PLAYERS.values().stream().toList(); } + private final OrebfuscatorCore orebfuscator; private final Player player; private BukkitWorldAccessor world; private final OrebfuscatorPlayer orebfuscatorPlayer; + + private final Map> pendingPackets = new WeakHashMap<>(); + private volatile @Nullable PendingChunkBatch chunkBatch; public BukkitPlayerAccessor(OrebfuscatorCore orebfuscator, Player player) { + this.orebfuscator = orebfuscator; this.player = player; this.world = BukkitWorldAccessor.get(player.getWorld()); this.orebfuscatorPlayer = new OrebfuscatorPlayer(orebfuscator, this); } + public @Nullable CompletableFuture obfuscationFuture(PacketEvent event) { + return pendingPackets.remove(event.getPacket().getHandle()); + } + + public void obfuscationFuture(PacketEvent event, CompletableFuture future) { + pendingPackets.putIfAbsent(event.getPacket().getHandle(), future); + } + + public void startBatch(AsynchronousManager asynchronousManager, PacketEvent event) { + if (this.chunkBatch != null) { + throw new RuntimeException("Started new chunk batch before previous one was finished!"); + } + this.chunkBatch = new PendingChunkBatch(this.orebfuscator.statistics().injector, asynchronousManager, event); + } + + public boolean addBatchChunk(PacketEvent event, CompletableFuture future) { + if (this.chunkBatch != null) { + this.chunkBatch.addChunk(event, future); + return true; + } + return false; + } + + public void finishBatch(PacketEvent event) { + if (this.chunkBatch != null) { + this.chunkBatch.finish(event); + this.chunkBatch = null; + } + } + @Override public OrebfuscatorPlayer orebfuscatorPlayer() { return this.orebfuscatorPlayer; diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java index 00ac31db..058e2abd 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java @@ -11,6 +11,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; +import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.MethodAccessor; import dev.imprex.orebfuscator.config.api.WorldConfigBundle; @@ -19,14 +20,13 @@ import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import dev.imprex.orebfuscator.util.BlockPos; -import dev.imprex.orebfuscator.util.ChunkCacheKey; import dev.imprex.orebfuscator.util.ChunkDirection; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.util.MinecraftVersion; -// TODO: Nullability +@NullMarked public class BukkitWorldAccessor implements WorldAccessor { private static final boolean HAS_DYNAMIC_HEIGHT = MinecraftVersion.isAtOrAbove("1.17"); @@ -180,7 +180,7 @@ public ChunkAccessor[] getNeighboringChunks(int chunkX, int chunkZ) { @Override public CompletableFuture getNeighboringChunks(ObfuscationRequest request) { - return OrebfuscatorCompatibility.getNeighboringChunks(world, new ChunkCacheKey(request)); + return OrebfuscatorCompatibility.getNeighboringChunks(world, request); } @Override diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java index 7044cdd5..419b0722 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java @@ -18,6 +18,7 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.PermissionRequirements; import dev.imprex.orebfuscator.UpdateSystem; import dev.imprex.orebfuscator.config.OrebfuscatorConfig; @@ -31,7 +32,7 @@ import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.hover.content.Text; -// TODO: Nullability +@NullMarked public class DeobfuscationListener implements Listener { public static void createAndRegister(Orebfuscator orebfuscator, ObfuscationSystem obfuscationSystem) { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java similarity index 58% rename from orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java rename to orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java index b3834e36..4c5d82b9 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java @@ -3,7 +3,9 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.AsynchronousManager; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -11,7 +13,9 @@ import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketEvent; import dev.imprex.orebfuscator.PermissionRequirements; +import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; +import dev.imprex.orebfuscator.statistics.InjectorStatistics; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; @@ -19,16 +23,13 @@ import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.util.ServerVersion; -// TODO: Nullability -// TODO: add sync map chunk packet listener that starts obfuscation on the main thread and tries to get neighboring chunks -// now to reduce the potential wait time for async chunk requests. -// TODO: add support for chunk batch system in sync listener (cancel) any packets and track current batch. On batch delimiter use -// future.all and send all packets at once for server to trigger multple write and single flush. -// TODO: maybe replace async listener entirely with sync listener and packet queue -public class ObfuscationListener extends PacketAdapter { +@NullMarked +public class ObfuscationAsyncListener extends PacketAdapter { private static final List PACKET_TYPES = Arrays.asList( PacketType.Play.Server.MAP_CHUNK, + PacketType.Play.Server.CHUNK_BATCH_START, + PacketType.Play.Server.CHUNK_BATCH_FINISHED, PacketType.Play.Server.UNLOAD_CHUNK, PacketType.Play.Server.CHUNKS_BIOMES, PacketType.Play.Server.LIGHT_UPDATE, @@ -43,21 +44,22 @@ public class ObfuscationListener extends PacketAdapter { PacketType.Play.Server.BLOCK_CHANGE, PacketType.Play.Server.MULTI_BLOCK_CHANGE, // Clientbound packet - PacketType.Play.Client.CHUNK_BATCH_RECEIVED - ); + PacketType.Play.Client.CHUNK_BATCH_RECEIVED); private final ObfuscationPipeline pipeline; + private final InjectorStatistics statistics; private final AsynchronousManager asynchronousManager; private final AsyncListenerHandler asyncListenerHandler; - public ObfuscationListener(Orebfuscator orebfuscator) { + public ObfuscationAsyncListener(Orebfuscator orebfuscator) { super(orebfuscator, PACKET_TYPES.stream() .filter(Objects::nonNull) .filter(PacketType::isSupported) .collect(Collectors.toList())); this.pipeline = orebfuscator.obfuscationPipeline(); + this.statistics = orebfuscator.statistics().injector; this.asynchronousManager = ProtocolLibrary.getProtocolManager().getAsynchronousManager(); this.asyncListenerHandler = this.asynchronousManager.registerAsyncHandler(this); @@ -75,12 +77,15 @@ public void unregister() { @Override public void onPacketReceiving(PacketEvent event) { - event.getPacket().getFloat().write(0, 10f); + statistics.injectorBatchSize.add(event.getPacket().getFloat().read(0)); } @Override public void onPacketSending(PacketEvent event) { - if (event.getPacket().getType() != PacketType.Play.Server.MAP_CHUNK) { + PacketType type = event.getPacket().getType(); + if (type != PacketType.Play.Server.MAP_CHUNK && + type != PacketType.Play.Server.CHUNK_BATCH_START && + type != PacketType.Play.Server.CHUNK_BATCH_FINISHED) { return; } @@ -88,27 +93,43 @@ public void onPacketSending(PacketEvent event) { if (player == null || !player.isAlive()) { return; } - + BukkitWorldAccessor world = player.world(); if (player.hasPermission(PermissionRequirements.BYPASS) || !world.config().needsObfuscation()) { return; } - var packet = new BukkitChunkPacketAccessor(event.getPacket(), world); - if (packet.isEmpty()) { - return; - } + if (type == PacketType.Play.Server.CHUNK_BATCH_START) { + player.startBatch(asynchronousManager, event); + } else if (type == PacketType.Play.Server.CHUNK_BATCH_FINISHED) { + player.finishBatch(event); + } else { + var future = player.obfuscationFuture(event); + if (future == null) { + OfcLogger.warn("Processing chunk packet async without an obfuscation future, that shouldn't happen!"); + + var packet = new BukkitChunkPacketAccessor(event.getPacket(), world); + if (packet.isEmpty()) { + future = CompletableFuture.completedFuture(null); + } else { + future = pipeline.request(world, player, packet, null).toCompletableFuture(); + } + } + + if (!player.addBatchChunk(event, future)) { + // no pending batch so we send each packet individually + event.getAsyncMarker().incrementProcessingDelay(); + + var timer = statistics.packetDelayChunk.start(); + future.whenComplete((result, throwable) -> { + if (throwable != null) { + OfcLogger.error(throwable); + } - var neighboringChunks = world - .getNeighboringChunks(packet.chunkX(), packet.chunkZ()); - var future = pipeline.request(world, player, packet, neighboringChunks) - .toCompletableFuture(); - - if (!future.isDone()) { - event.getAsyncMarker().incrementProcessingDelay(); - future.whenComplete((result, throwable) -> { - this.asynchronousManager.signalPacketTransmission(event); - }); + this.asynchronousManager.signalPacketTransmission(event); + timer.stop(); + }); + } } } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java new file mode 100644 index 00000000..12b2f101 --- /dev/null +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java @@ -0,0 +1,57 @@ +package net.imprex.orebfuscator.obfuscation; + +import org.jspecify.annotations.NullMarked; +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketEvent; +import dev.imprex.orebfuscator.PermissionRequirements; +import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; +import net.imprex.orebfuscator.Orebfuscator; +import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; +import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; + +@NullMarked +public class ObfuscationSyncListener extends PacketAdapter { + + private final ObfuscationPipeline pipeline; + private final ProtocolManager protocolManager; + + public ObfuscationSyncListener(Orebfuscator orebfuscator) { + super(orebfuscator, PacketType.Play.Server.MAP_CHUNK); + + this.pipeline = orebfuscator.obfuscationPipeline(); + + this.protocolManager = ProtocolLibrary.getProtocolManager(); + this.protocolManager.addPacketListener(this); + } + + public void unregister() { + this.protocolManager.removePacketListener(this); + } + + @Override + public void onPacketSending(PacketEvent event) { + BukkitPlayerAccessor player = BukkitPlayerAccessor.tryGet(event.getPlayer()); + if (player == null || !player.isAlive()) { + return; + } + + BukkitWorldAccessor world = player.world(); + if (player.hasPermission(PermissionRequirements.BYPASS) || !world.config().needsObfuscation()) { + return; + } + + var packet = new BukkitChunkPacketAccessor(event.getPacket(), world); + if (packet.isEmpty()) { + return; + } + + var neighboringChunks = world.getNeighboringChunks(packet.chunkX(), packet.chunkZ()); + var future = pipeline.request(world, player, packet, neighboringChunks).toCompletableFuture(); + + player.obfuscationFuture(event, future); + } +} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java index 563ca99f..0ba1331f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java @@ -2,16 +2,18 @@ import java.util.Collection; import org.bukkit.block.Block; +import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.obfuscation.DeobfuscationWorker; import dev.imprex.orebfuscator.util.BlockPos; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; -// TODO: Nullability +@NullMarked public class ObfuscationSystem { private final Orebfuscator orebfuscator; - private ObfuscationListener listener; + private ObfuscationSyncListener syncListener; + private ObfuscationAsyncListener asyncListener; private final DeobfuscationWorker deobfuscationWorker; @@ -23,7 +25,8 @@ public ObfuscationSystem(Orebfuscator orebfuscator) { } public void registerChunkListener() { - this.listener = new ObfuscationListener(orebfuscator); + this.syncListener = new ObfuscationSyncListener(orebfuscator); + this.asyncListener = new ObfuscationAsyncListener(orebfuscator); } public void deobfuscate(Block block) { @@ -46,6 +49,11 @@ public void deobfuscate(Collection blocks) { } public void shutdown() { - this.listener.unregister(); + if (this.syncListener != null) { + this.syncListener.unregister(); + } + if (this.asyncListener != null) { + this.asyncListener.unregister(); + } } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java new file mode 100644 index 00000000..873c336a --- /dev/null +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java @@ -0,0 +1,56 @@ +package net.imprex.orebfuscator.obfuscation; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import org.jspecify.annotations.NullMarked; +import com.comphenix.protocol.AsynchronousManager; +import com.comphenix.protocol.events.PacketEvent; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.statistics.InjectorStatistics; + +@NullMarked +public class PendingChunkBatch { + + private final InjectorStatistics statistics; + private final long enqueuedAt = System.nanoTime(); + + private final AsynchronousManager asynchronousManager; + private final AtomicBoolean finished = new AtomicBoolean(false); + private final PacketEvent event; + + private final List> pendingFutures = new ArrayList<>(); + + public PendingChunkBatch(InjectorStatistics statistics, AsynchronousManager asynchronousManager, PacketEvent event) { + this.statistics = statistics; + this.asynchronousManager = asynchronousManager; + + this.event = event; + event.getAsyncMarker().incrementProcessingDelay(); + } + + public void addChunk(PacketEvent event, CompletableFuture future) { + if (!this.finished.get()) { + this.pendingFutures.add(future); + } + } + + public void finish(PacketEvent event) { + if (this.finished.compareAndSet(false, true)) { + var futures = this.pendingFutures.toArray(CompletableFuture[]::new); + + CompletableFuture.allOf(futures).whenComplete((v, throwable) -> { + if (throwable != null) { + OfcLogger.error("An error occurred while processing a chunk batch", throwable); + } + + // only delay/signal start packet as any packet after has to wait anyways and that way we + // only take up a single processing slot in ProtocolLib's async filter manager per batch + this.asynchronousManager.signalPacketTransmission(this.event); + + statistics.packetDelayChunk.add(System.nanoTime() - this.enqueuedAt); + }); + } + } +} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java index 89a7ddcc..4ce49f9e 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java @@ -1,5 +1,6 @@ package net.imprex.orebfuscator.proximity; +import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; @@ -16,7 +17,7 @@ import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.util.MinecraftVersion; -// TODO: Nullability +@NullMarked public class ProximityPacketListener extends PacketAdapter { private static final boolean HAS_CHUNK_POS_FIELD = MinecraftVersion.isAtOrAbove("1.20.2"); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java index 323db9fc..777d8c70 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java @@ -3,16 +3,15 @@ import java.util.Iterator; import java.util.List; import java.util.function.Predicate; - +import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.utility.MinecraftReflection; - import dev.imprex.orebfuscator.util.BlockPos; // TODO: replace all ProtocolLib reflections with own reflect lib -// TODO: Nullability +@NullMarked public class WrappedClientboundLevelChunkPacketData { private static final Class CLIENTBOUND_LEVEL_CHUNK_PACKET_DATA = MinecraftReflection.getMinecraftClass( From 384b48acf555df83e582279619d25c657b52d1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Tue, 20 Jan 2026 21:05:24 +0100 Subject: [PATCH 07/14] chore: format code --- .../orebfuscator/PermissionRequirements.java | 8 +++++--- .../dev/imprex/orebfuscator/UpdateSystem.java | 4 ++-- .../cache/AsyncChunkSerializer.java | 8 ++++---- .../orebfuscator/cache/CacheResponse.java | 3 ++- .../orebfuscator/cache/ChunkSerializer.java | 2 +- .../orebfuscator/cache/ObfuscationCache.java | 8 ++++---- .../config/components/ConfigBlockValue.java | 2 +- .../interop/OrebfuscatorCore.java | 2 +- .../orebfuscator/interop/PlayerAccessor.java | 2 +- .../orebfuscator/interop/WorldAccessor.java | 2 +- .../obfuscation/DeobfuscationWorker.java | 2 +- .../obfuscation/ObfuscationPipeline.java | 10 +++++----- .../obfuscation/ObfuscationRequest.java | 2 +- .../player/OrebfuscatorPlayerChunk.java | 20 ++++++++++--------- .../orebfuscator/player/ProximityBlock.java | 4 ++-- .../proximity/ProximityRayCaster.java | 16 +++++++-------- .../proximity/ProximitySystem.java | 8 ++++---- .../proximity/ProximityWorker.java | 20 +++++++++---------- .../statistics/CacheStatistics.java | 12 +++++------ .../statistics/InjectorStatistics.java | 2 +- .../statistics/ObfuscationStatistics.java | 10 +++++----- .../statistics/OrebfuscatorStatistics.java | 2 +- .../statistics/StatisticsRegistry.java | 2 +- .../dev/imprex/orebfuscator/util/Version.java | 2 +- .../orebfuscator/nms/AbstractNmsManager.java | 2 +- .../orebfuscator-nms-v1_21_R6/pom.xml | 6 ++++-- .../orebfuscator-nms-v1_21_R7/pom.xml | 13 ++++++++---- .../net/imprex/orebfuscator/Orebfuscator.java | 4 ++-- .../orebfuscator/OrebfuscatorCommand.java | 3 ++- .../iterop/BukkitChunkPacketAccessor.java | 2 +- .../iterop/BukkitPlayerAccessor.java | 16 ++++++++------- .../iterop/BukkitWorldAccessor.java | 2 +- .../obfuscation/DeobfuscationListener.java | 3 ++- .../obfuscation/ObfuscationAsyncListener.java | 2 +- .../obfuscation/ObfuscationSystem.java | 6 +++--- .../proximity/ProximityPacketListener.java | 2 +- 36 files changed, 115 insertions(+), 99 deletions(-) diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java index bd64e355..50d1fb49 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/PermissionRequirements.java @@ -7,9 +7,11 @@ @NullMarked public record PermissionRequirements(OptionalInt operatorLevel, Optional permission) { - public static final PermissionRequirements BYPASS = new PermissionRequirements(OptionalInt.empty(), Optional.of("orebfuscator.bypass")); - public static final PermissionRequirements ADMIN = new PermissionRequirements(OptionalInt.of(4), Optional.of("orebfuscator.admin")); - + public static final PermissionRequirements BYPASS = new PermissionRequirements(OptionalInt.empty(), + Optional.of("orebfuscator.bypass")); + public static final PermissionRequirements ADMIN = new PermissionRequirements(OptionalInt.of(4), + Optional.of("orebfuscator.admin")); + public PermissionRequirements { if (operatorLevel.isEmpty() && permission.isEmpty()) { throw new IllegalArgumentException("Either an operator level, permission or both have to defined"); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java index 5f8ad5c3..cbe0f8bc 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java @@ -39,7 +39,7 @@ private static boolean isDevVersion(String version) { private static final Duration CACHE_DURATION = Duration.ofMinutes(10L); private final String loader; - + private final OrebfuscatorCore orebfuscator; private final GeneralConfig generalConfig; @@ -49,7 +49,7 @@ private static boolean isDevVersion(String version) { public UpdateSystem(OrebfuscatorCore orebfuscator, String loader) { super(orebfuscator); - + this.loader = loader; this.orebfuscator = orebfuscator; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java index 1e3590b3..ae5c7f35 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AsyncChunkSerializer.java @@ -30,7 +30,7 @@ public class AsyncChunkSerializer implements Runnable { private final CacheStatistics statistics; - + private final Lock lock = new ReentrantLock(true); private final Condition notFull = lock.newCondition(); private final Condition notEmpty = lock.newCondition(); @@ -141,7 +141,7 @@ public void close() { this.lock.unlock(); } } - + private abstract class TimedTask implements Runnable { private final RollingTimer.Instance waitTimer = statistics.diskCacheWaitTime.start(); @@ -150,7 +150,7 @@ private abstract class TimedTask implements Runnable { public TimedTask(RollingTimer runTimer) { this.runTimer = runTimer; } - + @Override public final void run() { waitTimer.stop(); @@ -162,7 +162,7 @@ public final void run() { timer.stop(); } } - + protected abstract void execute(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java index 42b76b3c..9518e606 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheResponse.java @@ -9,8 +9,9 @@ public sealed interface CacheResponse permits CacheResponse.Success, CacheRespon public static CacheResponse success(ChunkCacheEntry entry) { return new Success(entry); } - + record Success(ChunkCacheEntry entry) implements CacheResponse { + public Success { Objects.requireNonNull(entry, "entry"); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java index 6cd0253e..465ab488 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ChunkSerializer.java @@ -32,7 +32,7 @@ public ChunkCacheEntry read(ChunkCacheKey key) throws IOException { byte[] compressedData = new byte[dataInputStream.readInt()]; dataInputStream.readFully(compressedData); - + statistics.onDiskCacheRead(9 + compressedData.length); return new ChunkCacheEntry(key, compressedData); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java index fc5c8609..c7e5b07f 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/ObfuscationCache.java @@ -88,10 +88,10 @@ private CompletionStage probeCaches(CacheRequest request) { if (this.serializer != null) { future = future.thenComposeAsync(response -> - // only access disk cache if we couldn't find an entry in memory cache - response == CacheResponse.Failure.NOT_FOUND - ? this.probeDisk(request) - : CompletableFuture.completedStage(response) + // only access disk cache if we couldn't find an entry in memory cache + response == CacheResponse.Failure.NOT_FOUND + ? this.probeDisk(request) + : CompletableFuture.completedStage(response) , this.executor); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java index ef90cdbb..e32f9f01 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java @@ -18,7 +18,7 @@ public record ConfigBlockValue(String value, Set blocks) implem private static final JsonElement INVALID = new JsonPrimitive("invalid"); private static final JsonElement VALID = new JsonPrimitive("valid"); - + public static JsonObject toJson(Collection values) { JsonObject object = new JsonObject(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java index 3f6ca88b..c759bdc8 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java @@ -13,7 +13,7 @@ public interface OrebfuscatorCore extends ServerAccessor { ThreadGroup THREAD_GROUP = new ThreadGroup("orebfuscator"); - + String name(); OrebfuscatorExecutor executor(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java index d1f35ee4..dd8c0f77 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/PlayerAccessor.java @@ -20,7 +20,7 @@ public interface PlayerAccessor { boolean isAlive(); boolean isSpectator(); - + double lavaFogDistance(); boolean hasPermission(PermissionRequirements permission); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java index c82a3407..ddd93391 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java @@ -30,7 +30,7 @@ public interface WorldAccessor { CompletableFuture getNeighboringChunks(ObfuscationRequest request); ChunkAccessor getChunk(int chunkX, int chunkZ); - + @Deprecated int getBlockState(int x, int y, int z); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java index b7b9228b..8de7a8e0 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java @@ -86,7 +86,7 @@ public void deobfuscate(WorldAccessor world, @Nullable List blocks) { timer.stop(); } } - + private void deobfuscateNow(WorldAccessor world, List blocks) { final BlockFlags blockFlags = world.config().blockFlags(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java index ffb61472..5f7f1487 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java @@ -44,7 +44,7 @@ public CompletionStage request( WorldAccessor world, PlayerAccessor player, ChunkPacketAccessor packet, - @Nullable ChunkAccessor @Nullable[] neighborChunks) { + @Nullable ChunkAccessor @Nullable [] neighborChunks) { var timer = statistics.injector.pipelineDelayTotal.start(); return timer.wrap(requestInternal(world, player, packet, neighborChunks)); } @@ -53,7 +53,7 @@ private CompletionStage requestInternal( WorldAccessor world, PlayerAccessor player, ChunkPacketAccessor packet, - @Nullable ChunkAccessor @Nullable[] neighborChunks) { + @Nullable ChunkAccessor @Nullable [] neighborChunks) { final var request = new ObfuscationRequest(world, player, packet, neighborChunks); @@ -70,7 +70,7 @@ private CompletionStage requestInternal( .asBytes(); cacheRequest = new CacheRequest(cacheKey, hash); - + var cacheTimer = statistics.injector.pipelineDelayCache.start(); cacheFuture = cacheTimer.wrap(this.cache.get(cacheRequest)); } else { @@ -114,7 +114,7 @@ private CompletionStage requestInternal( .toCompletableFuture() .orTimeout(advancedConfig.obfuscationTimeout(), TimeUnit.MILLISECONDS); } - + return future.thenApplyAsync(response -> { this.postProcess(request, response); return null; @@ -138,7 +138,7 @@ private void postProcess(ObfuscationRequest request, ObfuscationResponse respons private void handleExceptions(ObfuscationRequest request, Throwable throwable) { var packet = request.packet(); - + if (throwable instanceof CompletionException && throwable.getCause() != null) { throwable = throwable.getCause(); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java index 8a8dcd73..338a6300 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java @@ -14,7 +14,7 @@ public record ObfuscationRequest( WorldAccessor world, PlayerAccessor player, ChunkPacketAccessor packet, - @Nullable ChunkAccessor @Nullable[] neighborChunks) { + @Nullable ChunkAccessor @Nullable [] neighborChunks) { public ObfuscationRequest { Objects.requireNonNull(world); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java index 58cace67..1ec300fe 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/OrebfuscatorPlayerChunk.java @@ -11,7 +11,7 @@ public class OrebfuscatorPlayerChunk { private static final int FLAG_DELETED = 0x80; private static final int FLAG_LAVA_OBFUSCATED = 0x01; - + private final int chunkX; private final int chunkZ; @@ -41,8 +41,9 @@ public boolean isEmpty() { public ProximityIterator proximityIterator() { return new ProximityItr(); } - + public interface ProximityIterator extends Iterator, AutoCloseable { + void close(); } @@ -54,7 +55,7 @@ private class ProximityItr implements ProximityIterator { private int cursor; private int removeCursor = -1; private int deleteCount; - + @Override public boolean hasNext() { return cursor < proximitySize; @@ -68,7 +69,7 @@ public ProximityBlock next() { int sectionPos = proximityBlocks[removeCursor = cursor]; int flags = proximityFlags[cursor++]; - + var blockPos = BlockPos.fromSectionPos(x, z, sectionPos); return new ProximityBlock(blockPos, (flags & FLAG_LAVA_OBFUSCATED) != 0); } @@ -82,23 +83,24 @@ public void remove() { // remove entry final int index = removeCursor; int flags = proximityFlags[index]; - if ((flags & FLAG_DELETED) != 0) + if ((flags & FLAG_DELETED) != 0) { throw new IllegalStateException("Already deleted!"); + } // update cursor positions removeCursor = -1; - + proximityFlags[index] |= FLAG_DELETED; deleteCount++; } - + @Override public void close() { if (deleteCount > 0) { int newSize = Math.max(0, proximitySize - deleteCount); int[] newProximityBlocks = new int[newSize]; byte[] newProximityFlags = new byte[newSize]; - + int newIndex = 0; for (int oldIndex = 0; newIndex < newSize && oldIndex < proximitySize; oldIndex++) { if ((proximityFlags[oldIndex] & FLAG_DELETED) == 0) { @@ -106,7 +108,7 @@ public void close() { newProximityFlags[newIndex++] = proximityFlags[oldIndex]; } } - + proximitySize = newSize; proximityBlocks = newProximityBlocks; proximityFlags = newProximityFlags; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java index 40b2d075..89effafa 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/player/ProximityBlock.java @@ -7,11 +7,11 @@ public record ProximityBlock(BlockPos blockPos, boolean lavaObfuscated) { private static final byte FLAG_LAVA_OBFUSCATED = 0x01; - + public ProximityBlock(BlockPos blockPos, byte flags) { this(blockPos, (flags & FLAG_LAVA_OBFUSCATED) == FLAG_LAVA_OBFUSCATED); } - + public byte flags() { return lavaObfuscated ? FLAG_LAVA_OBFUSCATED : 0x00; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java index 3be65a69..e1d31be8 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java @@ -41,12 +41,12 @@ public boolean isVisible(EntityPose origin, BlockPos target) { || canRayPass(origin, target, 0.0, 1.0, 1.0) || canRayPass(origin, target, 1.0, 1.0, 1.0); } - + private boolean canRayPass(EntityPose origin, BlockPos target, double offsetX, double offsetY, double offsetZ) { double tx = target.x() + offsetX; double ty = target.y() + offsetY; double tz = target.z() + offsetZ; - + double dx = origin.x() - tx; double dy = origin.y() - ty; double dz = origin.z() - tz; @@ -56,26 +56,26 @@ private boolean canRayPass(EntityPose origin, BlockPos target, double offsetX, d if (maxAbs < 1) { return true; } - + // step in "dominant-axis" units dx /= maxAbs; dy /= maxAbs; dz /= maxAbs; - + // our current position double cx = origin.x(); double cy = origin.y(); double cz = origin.z(); - + // position of current block int x, y, z; - + for (int steps = (int) Math.ceil(maxAbs); steps > 0; steps--) { // move from origin toward target cx -= dx; cy -= dy; cz -= dz; - + x = (int) QuickMaths.floor(cx); y = (int) QuickMaths.floor(cy); z = (int) QuickMaths.floor(cz); @@ -84,7 +84,7 @@ private boolean canRayPass(EntityPose origin, BlockPos target, double offsetX, d if (x == target.x() && y == target.y() && z == target.z()) { return true; } - + int blockId = level.getBlockState(x, y, z); // fail on first hit, this ray is "blocked" if (registry.isOccluding(blockId)) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java index ad74f8ac..82e0d5f8 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java @@ -36,7 +36,7 @@ public ProximitySystem(OrebfuscatorCore orebfuscator) { this.worker = new ProximityWorker(orebfuscator); } - + public void start() { this.executor.schedule(this, this.checkInterval, TimeUnit.NANOSECONDS); } @@ -52,7 +52,7 @@ public void run() { if (this.executor.isShutdown()) { return; } - + long processTime = System.nanoTime() - processStart; this.statistics.proximityProcess.add(processTime); @@ -69,7 +69,7 @@ public void run() { } }); } - + private CompletableFuture process() { var players = this.orebfuscator.players(); if (players.isEmpty()) { @@ -83,7 +83,7 @@ private CompletableFuture process() { // calculate bucket int bucketCount = (int) Math.ceil((float) playerCount / maxBucketSize); int bucketSize = (int) Math.ceil((float) playerCount / (float) bucketCount); - + var pendingFutures = new CompletableFuture[bucketCount]; Iterator iterator = players.iterator(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java index 01783626..41edc353 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java @@ -78,10 +78,10 @@ private void process(PlayerAccessor player) { FrustumIntersection frustum = proximityConfig.frustumCullingEnabled() ? new FrustumIntersection(proximityConfig.frustumCullingProjectionMatrix() - .rotate(new Quaternionf() - .rotateX((float) Math.toRadians(eyeLocation.rotX())) - .rotateY((float) Math.toRadians(eyeLocation.rotY() + 180))) - .translate((float) -eyeLocation.x(), (float) -eyeLocation.y(), (float) -eyeLocation.z()), false) + .rotate(new Quaternionf() + .rotateX((float) Math.toRadians(eyeLocation.rotX())) + .rotateY((float) Math.toRadians(eyeLocation.rotY() + 180))) + .translate((float) -eyeLocation.x(), (float) -eyeLocation.y(), (float) -eyeLocation.z()), false) : null; EntityPose location = player.pose(); @@ -89,14 +89,14 @@ private void process(PlayerAccessor player) { int maxChunkX = (location.blockX() + distance) >> 4; int minChunkZ = (location.blockZ() - distance) >> 4; int maxChunkZ = (location.blockZ() + distance) >> 4; - + ChunkAccessor playerChunk = world.getChunk(location.blockX() >> 4, location.blockZ() >> 4); int eyeBlockId = playerChunk.getBlockState(location.blockX(), eyeLocation.blockY(), location.blockZ()); boolean isInLava = eyeBlockId >= 0 && this.registry.isLava(eyeBlockId); - + double lavaDistance = player.lavaFogDistance(); double lavaDistanceSquared = lavaDistance * lavaDistance; - + ProximityRayCaster rayCaster = proximityConfig.rayCastCheckEnabled() ? new ProximityRayCaster(registry, world) : null; @@ -112,13 +112,13 @@ private void process(PlayerAccessor player) { while (iterator.hasNext()) { ProximityBlock proximityBlock = iterator.next(); BlockPos blockPos = proximityBlock.blockPos(); - + // skip lava obfuscated if not in lava - // TODO: the current deobfuscation would only deobfuscate lava if the neighoring block is a hiddenBlock + // TODO: the current deobfuscation would only deobfuscate lava if the neighboring block is a hiddenBlock if (proximityBlock.lavaObfuscated() && !isInLava) { continue; } - + double compareDistanceSquared; double blockDistanceSquared; if (proximityBlock.lavaObfuscated()) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java index e613d030..c6b1addc 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java @@ -13,7 +13,7 @@ import dev.imprex.orebfuscator.util.RollingTimer; public class CacheStatistics implements StatisticsSource { - + private final CacheConfig config; private final AtomicLong cacheHitCountMemory = new AtomicLong(0); @@ -29,7 +29,7 @@ public class CacheStatistics implements StatisticsSource { public final RollingTimer diskCacheWaitTime = new RollingTimer(4096); public final RollingTimer diskCacheReadTime = new RollingTimer(4096); public final RollingTimer diskCacheWriteTime = new RollingTimer(4096); - + public CacheStatistics(Config config) { this.config = config.cache(); } @@ -57,11 +57,11 @@ public void setMemoryCacheEntryCount(LongSupplier supplier) { public void setDiskCacheQueueLength(LongSupplier supplier) { this.diskCacheQueueLength = Objects.requireNonNull(supplier); } - + public void onDiskCacheRead(long bytes) { this.diskCacheReadBytes.add(bytes); } - + public void onDiskCacheWrite(long bytes) { this.diskCacheWriteBytes.add(bytes); } @@ -99,14 +99,14 @@ public void add(StringJoiner joiner) { long diskCacheQueueLength = this.diskCacheQueueLength.getAsLong(); joiner.add(String.format(" - diskCache (queue): %s", diskCacheQueueLength)); - + long diskCacheWaitTime = (long) this.diskCacheWaitTime.average(); long diskCacheReadTime = (long) this.diskCacheReadTime.average(); long diskCacheWriteTime = (long) this.diskCacheWriteTime.average(); joiner.add(String.format(" - diskCacheTime (wait/read/write): %s / %s / %s", time(diskCacheWaitTime), time(diskCacheReadTime), time(diskCacheWriteTime))); - + long diskCacheReadBytes = (long) this.diskCacheReadBytes.average(); long diskCacheWriteBytes = (long) this.diskCacheWriteBytes.average(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java index ca6fde6c..76b10a91 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java @@ -48,7 +48,7 @@ public void debug(Consumer> consumer) { consumer.accept(Map.entry("pipelineDelayCache", this.pipelineDelayCache.debugLong(this::time))); consumer.accept(Map.entry("pipelineDelayNeighbors", this.pipelineDelayNeighbors.debugLong(this::time))); consumer.accept(Map.entry("pipelineDelayProcessor", this.pipelineDelayProcessor.debugLong(this::time))); - + consumer.accept(Map.entry("injectorDelaySync", this.injectorDelaySync.debugLong(this::time))); consumer.accept(Map.entry("injectorBatchSize", this.injectorBatchSize.debugLong(this::time))); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java index 71eae0a1..cd19abaf 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java @@ -15,7 +15,7 @@ public class ObfuscationStatistics implements StatisticsSource { public final RollingTimer proximityWait = new RollingTimer(4096); public final RollingTimer proximityProcess = new RollingTimer(4096); - + public final RollingAverage missingNeighboringChunks = new RollingAverage(4096); public final RollingAverage originalChunkSize = new RollingAverage(4096); @@ -27,13 +27,13 @@ public void add(StringJoiner joiner) { joiner.add(String.format(" - debofuscation: %s", time(debofuscation))); - + long executorWaitTime = (long) this.executorWaitTime.average(); double executorUtilization = this.executorUtilization.average(); joiner.add(String.format(" - executor (wait/utilization): %s / %s", time(executorWaitTime), percent(executorUtilization))); - + double proximityWait = this.proximityWait.average(); double proximityProcess = this.proximityProcess.average(); double proximityTotalTime = proximityWait + proximityProcess; @@ -42,10 +42,10 @@ public void add(StringJoiner joiner) { if (proximityTotalTime > 0) { proximityUtilization = (double) proximityProcess / proximityTotalTime; } - + joiner.add(String.format(" - proximity utilization: %s", percent(proximityUtilization))); - + double missingNeighboringChunks = this.missingNeighboringChunks.average(); joiner.add(String.format(" - missingNeighbors: %s", diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java index ba08d541..11d9052d 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/OrebfuscatorStatistics.java @@ -10,7 +10,7 @@ public class OrebfuscatorStatistics { public OrebfuscatorStatistics(Config config, StatisticsRegistry registry) { this.cache = new CacheStatistics(config); - + if (config.cache().enabled()) { registry.register("cache", this.cache); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java index 772200c7..f6ed4e9b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java @@ -51,7 +51,7 @@ public JsonObject json() { return object; } - + private List> entries() { var entries = new ArrayList>(); 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 00691f60..c9a38dc7 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 @@ -38,7 +38,7 @@ public static Optional tryParse(String version) { int patch = patchGroup != null ? Integer.parseInt(patchGroup) : 0; String suffix = matcher.group("suffix"); - + return Optional.of(new Version(major, minor, patch, suffix)); } 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 38758611..91a29f20 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 @@ -110,7 +110,7 @@ public final boolean isOccluding(int id) { public final boolean isBlockEntity(int id) { return this.blockStates[id].isBlockEntity(); } - + @Override public @Nullable ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ) { throw new UnsupportedOperationException(); diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/pom.xml b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/pom.xml index 1626c36b..19686ccd 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/pom.xml +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 @@ -25,7 +27,7 @@ provided - + diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/pom.xml b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/pom.xml index 1b946ba0..ffa5485b 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/pom.xml +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 @@ -38,7 +40,8 @@ net.imprex.orebfuscator.nms.v1_21_R7 - net.imprex.orebfuscator.nms.v1_21_R7_mojang + net.imprex.orebfuscator.nms.v1_21_R7_mojang + @@ -56,7 +59,8 @@ remap-obf - org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:txt:maps-mojang + org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:txt:maps-mojang + true org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-mojang @@ -76,7 +80,8 @@ ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-obf diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index 9f0eaaa0..4f56cacb 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -86,7 +86,7 @@ public void onEnable() { this.statistics = new OrebfuscatorStatistics(this.config, this.statisticsRegistry); this.executor = new OrebfuscatorExecutor(this); - + this.chunkFactory = new ChunkFactory(this); this.obfuscationProcessor = new ObfuscationProcessor(this); this.obfuscationCache = new ObfuscationCache(this); @@ -212,7 +212,7 @@ public Path configDirectory() { public Path worldDirectory() { return Bukkit.getWorldContainer().toPath(); } - + @Override public String name() { return getDescription().getName(); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java index 775c5062..a884ea64 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java @@ -61,7 +61,8 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } if (args.length == 0) { - sender.sendMessage("You are using %s %s".formatted(this.orebfuscator.name(), this.orebfuscator.orebfuscatorVersion())); + sender.sendMessage( + "You are using %s %s".formatted(this.orebfuscator.name(), this.orebfuscator.orebfuscatorVersion())); sender.sendMessage(this.orebfuscator.statisticsRegistry().format()); } else if (args[0].equalsIgnoreCase("dump")) { TemporalAccessor now = OffsetDateTime.now(ZoneOffset.UTC); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java index 40ae2da2..64100f14 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java @@ -81,7 +81,7 @@ public byte[] data() { @Override public void update(ObfuscationResponse response) { Predicate blockEntityPredicate = relativePostion -> - response.blockEntities().contains(relativePostion.add(chunkX << 4, 0, chunkZ << 4)); + response.blockEntities().contains(relativePostion.add(chunkX << 4, 0, chunkZ << 4)); if (this.packetData != null) { this.packetData.setBuffer(response.data()); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java index 28821007..b66d3f4e 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java @@ -57,12 +57,12 @@ public void onChangedWorld(PlayerChangedWorldEvent event) { bukkitPlayer.orebfuscatorPlayer.clearChunks(); } } - + @EventHandler public void onQuit(PlayerQuitEvent event) { PLAYERS.remove(event.getPlayer().getUniqueId()); } - + @EventHandler public void onDisable(PluginDisableEvent event) { if (event.getPlugin() == orebfuscator) { @@ -70,7 +70,7 @@ public void onDisable(PluginDisableEvent event) { } } }, orebfuscator); - + for (Player player : Bukkit.getOnlinePlayers()) { var bukkitPlayer = PLAYERS.computeIfAbsent(player.getUniqueId(), key -> new BukkitPlayerAccessor(orebfuscator, player)); @@ -91,7 +91,7 @@ public static BukkitPlayerAccessor tryGet(Player player) { public static List getAll() { return PLAYERS.values().stream().toList(); } - + private final OrebfuscatorCore orebfuscator; private final Player player; private BukkitWorldAccessor world; @@ -100,7 +100,7 @@ public static List getAll() { private final Map> pendingPackets = new WeakHashMap<>(); private volatile @Nullable PendingChunkBatch chunkBatch; - + public BukkitPlayerAccessor(OrebfuscatorCore orebfuscator, Player player) { this.orebfuscator = orebfuscator; this.player = player; @@ -146,13 +146,15 @@ public OrebfuscatorPlayer orebfuscatorPlayer() { @Override public EntityPose pose() { var location = player.getLocation(); - return new EntityPose(world, location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw()); + return new EntityPose(world, location.getX(), location.getY(), location.getZ(), location.getPitch(), + location.getYaw()); } @Override public EntityPose eyePose() { var location = player.getEyeLocation(); - return new EntityPose(world, location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw()); + return new EntityPose(world, location.getX(), location.getY(), location.getZ(), location.getPitch(), + location.getYaw()); } @Override diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java index 058e2abd..0aff3cae 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java @@ -179,7 +179,7 @@ public ChunkAccessor[] getNeighboringChunks(int chunkX, int chunkZ) { } @Override - public CompletableFuture getNeighboringChunks(ObfuscationRequest request) { + public CompletableFuture getNeighboringChunks(ObfuscationRequest request) { return OrebfuscatorCompatibility.getNeighboringChunks(world, request); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java index 419b0722..4f54d807 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java @@ -107,7 +107,8 @@ public void onPlayerInteract(PlayerInteractEvent event) { public void onJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - if (this.config.general().bypassNotification() && PermissionUtil.hasPermission(player, PermissionRequirements.BYPASS)) { + if (this.config.general().bypassNotification() && PermissionUtil.hasPermission(player, + PermissionRequirements.BYPASS)) { player.sendMessage( "[§bOrebfuscator§f]§7 You bypass Orebfuscator because you have the 'orebfuscator.bypass' permission."); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java index 4c5d82b9..ed072129 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java @@ -119,7 +119,7 @@ public void onPacketSending(PacketEvent event) { if (!player.addBatchChunk(event, future)) { // no pending batch so we send each packet individually event.getAsyncMarker().incrementProcessingDelay(); - + var timer = statistics.packetDelayChunk.start(); future.whenComplete((result, throwable) -> { if (throwable != null) { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java index 0ba1331f..38aa0b53 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java @@ -28,18 +28,18 @@ public void registerChunkListener() { this.syncListener = new ObfuscationSyncListener(orebfuscator); this.asyncListener = new ObfuscationAsyncListener(orebfuscator); } - + public void deobfuscate(Block block) { var world = BukkitWorldAccessor.get(block.getWorld()); var blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); this.deobfuscationWorker.deobfuscate(world, blockPos); } - + public void deobfuscate(Collection blocks) { if (blocks.isEmpty()) { return; } - + var world = BukkitWorldAccessor.get(blocks.stream().findFirst().get().getWorld()); var blockPos = blocks.stream() .map(block -> new BlockPos(block.getX(), block.getY(), block.getZ())) diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java index 4ce49f9e..ceced80f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java @@ -50,7 +50,7 @@ public void onPacketSending(PacketEvent event) { PacketContainer packet = event.getPacket(); OrebfuscatorPlayer orebfuscatorPlayer = player.orebfuscatorPlayer(); - + if (HAS_CHUNK_POS_FIELD) { ChunkCoordIntPair chunkPos = packet.getChunkCoordIntPairs().read(0); orebfuscatorPlayer.removeChunk(world, chunkPos.getChunkX(), chunkPos.getChunkZ()); From b5593b73f448c847b78480debe8056c93ed139cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Tue, 20 Jan 2026 22:28:18 +0100 Subject: [PATCH 08/14] feat: move world/player accessor listener to non static code --- .../dev/imprex/orebfuscator/chunk/Chunk.java | 4 +- .../config/OrebfuscatorConfig.java | 10 +- .../config/components/WeightedBlockList.java | 6 +- .../orebfuscator/interop/WorldAccessor.java | 16 +-- .../obfuscation/ObfuscationPipeline.java | 4 +- .../obfuscation/ObfuscationProcessor.java | 6 +- .../orebfuscator/util/ChunkCacheKey.java | 4 +- .../imprex/orebfuscator/nms/NmsManager.java | 1 + .../net/imprex/orebfuscator/Orebfuscator.java | 25 ++-- .../orebfuscator/OrebfuscatorCommand.java | 11 +- .../iterop/BukkitChunkPacketAccessor.java | 2 +- .../iterop/BukkitPlayerAccessor.java | 123 +++++------------- .../iterop/BukkitPlayerAccessorManager.java | 75 +++++++++++ .../iterop/BukkitWorldAccessor.java | 88 ++++--------- .../iterop/BukkitWorldAccessorManager.java | 63 +++++++++ .../obfuscation/ObfuscationAsyncListener.java | 9 +- .../obfuscation/ObfuscationSyncListener.java | 6 +- .../obfuscation/ObfuscationSystem.java | 20 +-- .../obfuscation/PendingChunkBatch.java | 26 ++-- .../proximity/ProximityPacketListener.java | 6 +- 20 files changed, 288 insertions(+), 217 deletions(-) create mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessorManager.java create mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessorManager.java diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java index 7d737e98..068bf075 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/chunk/Chunk.java @@ -28,7 +28,7 @@ public class Chunk implements AutoCloseable { this.chunkZ = packet.chunkZ(); this.worldAccessor = request.world(); - this.sections = new ChunkSectionHolder[this.worldAccessor.getSectionCount()]; + this.sections = new ChunkSectionHolder[this.worldAccessor.sectionCount()]; byte[] data = packet.data(); this.inputBuffer = Unpooled.wrappedBuffer(data); @@ -59,7 +59,7 @@ public ChunkSection getSection(int index) { public int getBlockState(int x, int y, int z) { if (x >> 4 == this.chunkX && z >> 4 == this.chunkZ) { - ChunkSectionHolder chunkSection = this.sections[this.worldAccessor.getSectionIndex(y)]; + ChunkSectionHolder chunkSection = this.sections[this.worldAccessor.sectionIndex(y)]; if (chunkSection != null) { return chunkSection.data[ChunkSection.positionToIndex(x & 0xF, y & 0xF, z & 0xF)]; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java index 3889b6ea..977f3c7d 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java @@ -357,7 +357,7 @@ private class OrebfuscatorWorldConfigBundle implements WorldConfigBundle { private final WeightedRandom @Nullable [] proximityRandoms; public OrebfuscatorWorldConfigBundle(WorldAccessor world) { - String worldName = world.getName(); + String worldName = world.name(); this.world = world; this.obfuscationConfig = findConfig(obfuscationConfigs, worldName, "obfuscation"); @@ -374,8 +374,8 @@ public OrebfuscatorWorldConfigBundle(WorldAccessor world) { this.obfuscationConfig != null ? this.obfuscationConfig.getMaxY() : BlockPos.MIN_Y, this.proximityConfig != null ? this.proximityConfig.getMaxY() : BlockPos.MIN_Y); - this.minSectionIndex = world.getSectionIndex(this.minY); - this.maxSectionIndex = world.getSectionIndex(this.maxY - 1) + 1; + this.minSectionIndex = world.sectionIndex(this.minY); + this.maxSectionIndex = world.sectionIndex(this.maxY - 1) + 1; this.obfuscationRandoms = obfuscationConfig != null && obfuscationConfig.isEnabled() ? this.obfuscationConfig.createWeightedRandoms(world) : null; @@ -440,13 +440,13 @@ public boolean shouldObfuscate(int y) { @Override public int nextRandomObfuscationBlock(RandomGenerator random, int y) { return this.obfuscationRandoms != null - ? this.obfuscationRandoms[y - this.world.getMinBuildHeight()].next(random) : 0; + ? this.obfuscationRandoms[y - this.world.minBuildHeight()].next(random) : 0; } @Override public int nextRandomProximityBlock(RandomGenerator random, int y) { return this.proximityRandoms != null - ? this.proximityRandoms[y - this.world.getMinBuildHeight()].next(random) : 0; + ? this.proximityRandoms[y - this.world.minBuildHeight()].next(random) : 0; } } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java index 91191969..3085db7c 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/WeightedBlockList.java @@ -23,21 +23,21 @@ public class WeightedBlockList { public static WeightedRandom[] create(WorldAccessor world, List lists) { - WeightedRandom[] heightMap = new WeightedRandom[world.getHeight()]; + WeightedRandom[] heightMap = new WeightedRandom[world.height()]; List last = new ArrayList<>(); List next = new ArrayList<>(); int count = 0; - for (int y = world.getMinBuildHeight(); y < world.getMaxBuildHeight(); y++) { + for (int y = world.minBuildHeight(); y < world.maxBuildHeight(); y++) { for (WeightedBlockList list : lists) { if (list.minY <= y && list.maxY >= y) { next.add(list); } } - int index = y - world.getMinBuildHeight(); + int index = y - world.minBuildHeight(); if (index > 0 && last.equals(next)) { // copy last weighted random heightMap[index] = heightMap[index - 1]; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java index ddd93391..9dec6270 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java @@ -9,21 +9,21 @@ @NullMarked public interface WorldAccessor { - String getName(); + String name(); - int getHeight(); + int height(); - int getMinBuildHeight(); + int minBuildHeight(); - int getMaxBuildHeight(); + int maxBuildHeight(); - int getSectionCount(); + int sectionCount(); - int getMinSection(); + int minSection(); - int getMaxSection(); + int maxSection(); - int getSectionIndex(int y); + int sectionIndex(int y); WorldConfigBundle config(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java index 5f7f1487..c79f94cb 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java @@ -144,11 +144,11 @@ private void handleExceptions(ObfuscationRequest request, Throwable throwable) { } if (throwable instanceof TimeoutException) { - OfcLogger.warn("Obfuscation for chunk[world=%s, x=%d, z=%d] timed out".formatted(request.world().getName(), + OfcLogger.warn("Obfuscation for chunk[world=%s, x=%d, z=%d] timed out".formatted(request.world().name(), packet.chunkX(), packet.chunkZ())); } else { OfcLogger.error("An error occurred while obfuscating chunk[world=%s, x=%d, z=%d]" - .formatted(request.world().getName(), packet.chunkX(), packet.chunkZ()), throwable); + .formatted(request.world().name(), packet.chunkX(), packet.chunkZ()), throwable); } } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java index c8db662c..73a22090 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java @@ -81,7 +81,7 @@ private ObfuscationResponse processInternal(ObfuscationRequest request) { continue; } - final int baseY = worldAccessor.getMinBuildHeight() + (sectionIndex << 4); + final int baseY = worldAccessor.minBuildHeight() + (sectionIndex << 4); for (int index = 0; index < 4096; index++) { int y = baseY + (index >> 8 & 15); if (!bundle.shouldObfuscate(y)) { @@ -154,7 +154,7 @@ private int getBlockStateBelow(RandomGenerator random, WorldConfigBundle bundle, boolean allowNonOcclude) { BlockFlags blockFlags = bundle.blockFlags(); - for (int targetY = y - 1; targetY > chunk.world().getMinBuildHeight(); targetY--) { + for (int targetY = y - 1; targetY > chunk.world().minBuildHeight(); targetY--) { int blockData = chunk.getBlockState(x, targetY, z); if (blockData != -1 && (allowNonOcclude || registryAccessor.isOccluding(blockData))) { int mask = blockFlags.flags(blockData, y); @@ -194,7 +194,7 @@ private boolean isAdjacentBlockOccluding(ObfuscationRequest request, Chunk chunk } private int getBlockId(ObfuscationRequest request, Chunk chunk, int x, int y, int z) { - if (y >= chunk.world().getMaxBuildHeight() || y < chunk.world().getMinBuildHeight()) { + if (y >= chunk.world().maxBuildHeight() || y < chunk.world().minBuildHeight()) { return -1; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java index 94f2b725..96ae50c3 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkCacheKey.java @@ -12,11 +12,11 @@ public ChunkCacheKey(ObfuscationRequest request) { } public ChunkCacheKey(WorldAccessor world, BlockPos position) { - this(world.getName(), position.x() >> 4, position.z() >> 4); + this(world.name(), position.x() >> 4, position.z() >> 4); } public ChunkCacheKey(WorldAccessor world, int x, int z) { - this(world.getName(), x, z); + this(world.name(), x, z); } @Override 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 ed18fc61..132814d0 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 @@ -15,6 +15,7 @@ public interface NmsManager extends RegistryAccessor { ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ); + // TODO: change to getChunkNow, implement in each version and add use in deobfuscation worker @Nullable ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ); int getBlockState(World world, int x, int y, int z); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index 4f56cacb..da74c9ec 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -2,6 +2,8 @@ import java.nio.file.Path; import java.util.List; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; +import net.imprex.orebfuscator.iterop.BukkitWorldAccessorManager; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; @@ -45,6 +47,9 @@ public class Orebfuscator extends JavaPlugin implements Listener, OrebfuscatorCo private OrebfuscatorStatistics statistics; private OrebfuscatorExecutor executor; + private BukkitWorldAccessorManager worldManager; + private BukkitPlayerAccessorManager playerManager; + private ChunkFactory chunkFactory; private ObfuscationProcessor obfuscationProcessor; private ObfuscationCache obfuscationCache; @@ -74,13 +79,13 @@ public void onEnable() { } this.statisticsRegistry = new StatisticsRegistry(); + this.worldManager = new BukkitWorldAccessorManager(this); - BukkitWorldAccessor.registerListener(this); OrebfuscatorNms.initialize(); this.config = new OrebfuscatorConfig(this); OrebfuscatorCompatibility.initialize(this, config); - BukkitPlayerAccessor.registerListener(this); + this.playerManager = new BukkitPlayerAccessorManager(this); new MetricsSystem(this); this.updateSystem = new UpdateSystem(this, "bukkit"); @@ -163,6 +168,14 @@ public StatisticsRegistry statisticsRegistry() { return statisticsRegistry; } + public BukkitWorldAccessorManager worldManager() { + return worldManager; + } + + public BukkitPlayerAccessorManager playerManager() { + return playerManager; + } + @Override public OrebfuscatorExecutor executor() { return executor; @@ -240,16 +253,12 @@ public AbstractRegionFileCache createRegionFileCache() { @Override public List worlds() { - return BukkitWorldAccessor.getWorlds().stream() - .map(WorldAccessor.class::cast) - .toList(); + return this.worldManager.all(); } @Override public List players() { - return BukkitPlayerAccessor.getAll().stream() - .map(PlayerAccessor.class::cast) - .toList(); + return this.playerManager.all(); } @Override diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java index a884ea64..1e5df7fb 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java @@ -1,5 +1,6 @@ package net.imprex.orebfuscator; +import com.google.gson.JsonArray; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -91,12 +92,12 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } root.add("plugins", plugins); - JsonObject worlds = new JsonObject(); - for (World bukkitWorld : Bukkit.getWorlds()) { + JsonArray worlds = new JsonArray(); + for (var accessor : orebfuscator.worldManager().all()) { JsonObject world = new JsonObject(); - world.addProperty("uuid", bukkitWorld.getUID().toString()); - world.addProperty("heightAccessor", BukkitWorldAccessor.get(bukkitWorld).toString()); - worlds.add(bukkitWorld.getName(), world); + world.addProperty("name", accessor.name()); + world.addProperty("heightAccessor", accessor.toString()); + worlds.add(world); } root.add("worlds", worlds); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java index 64100f14..44974721 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java @@ -54,7 +54,7 @@ public BukkitChunkPacketAccessor(PacketContainer packet, BukkitWorldAccessor wor } } else { this.sectionMask = new BitSet(); - this.sectionMask.set(0, worldAccessor.getSectionCount()); + this.sectionMask.set(0, worldAccessor.sectionCount()); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java index b66d3f4e..3350317f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessor.java @@ -1,113 +1,52 @@ package net.imprex.orebfuscator.iterop; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.WeakHashMap; -import java.util.concurrent.CompletableFuture; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.potion.PotionEffectType; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; import com.comphenix.protocol.AsynchronousManager; import com.comphenix.protocol.events.PacketEvent; import dev.imprex.orebfuscator.PermissionRequirements; -import dev.imprex.orebfuscator.interop.OrebfuscatorCore; import dev.imprex.orebfuscator.interop.PlayerAccessor; +import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.EntityPose; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.obfuscation.PendingChunkBatch; import net.imprex.orebfuscator.util.PermissionUtil; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffectType; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; -// TODO: abstract static listener away into common management class, same thing for worlds as well @NullMarked public class BukkitPlayerAccessor implements PlayerAccessor { - private static final Map PLAYERS = new HashMap<>(); - - public static void registerListener(Orebfuscator orebfuscator) { - Bukkit.getPluginManager().registerEvents(new Listener() { - @EventHandler - public void onJoin(PlayerJoinEvent event) { - var player = event.getPlayer(); - var bukkitPlayer = PLAYERS.computeIfAbsent(player.getUniqueId(), - key -> new BukkitPlayerAccessor(orebfuscator, player)); - bukkitPlayer.orebfuscatorPlayer.clearChunks(); - } - - @EventHandler - public void onChangedWorld(PlayerChangedWorldEvent event) { - var player = event.getPlayer(); - var bukkitPlayer = PLAYERS.get(player.getUniqueId()); - if (bukkitPlayer != null) { - bukkitPlayer.world = BukkitWorldAccessor.get(player.getWorld()); - bukkitPlayer.orebfuscatorPlayer.clearChunks(); - } - } - - @EventHandler - public void onQuit(PlayerQuitEvent event) { - PLAYERS.remove(event.getPlayer().getUniqueId()); - } - - @EventHandler - public void onDisable(PluginDisableEvent event) { - if (event.getPlugin() == orebfuscator) { - PLAYERS.clear(); - } - } - }, orebfuscator); - - for (Player player : Bukkit.getOnlinePlayers()) { - var bukkitPlayer = PLAYERS.computeIfAbsent(player.getUniqueId(), - key -> new BukkitPlayerAccessor(orebfuscator, player)); - bukkitPlayer.orebfuscatorPlayer.clearChunks(); - } - } - - @Nullable - public static BukkitPlayerAccessor tryGet(Player player) { - try { - return PLAYERS.get(player.getUniqueId()); - } catch (UnsupportedOperationException e) { - // catch TemporaryPlayer not implementing getUniqueId - return null; - } - } - - public static List getAll() { - return PLAYERS.values().stream().toList(); - } - - private final OrebfuscatorCore orebfuscator; + private final Orebfuscator orebfuscator; private final Player player; private BukkitWorldAccessor world; private final OrebfuscatorPlayer orebfuscatorPlayer; private final Map> pendingPackets = new WeakHashMap<>(); - private volatile @Nullable PendingChunkBatch chunkBatch; + private final AtomicReference<@Nullable PendingChunkBatch> chunkBatch = new AtomicReference<>(); - public BukkitPlayerAccessor(OrebfuscatorCore orebfuscator, Player player) { + public BukkitPlayerAccessor(Orebfuscator orebfuscator, Player player) { this.orebfuscator = orebfuscator; this.player = player; - this.world = BukkitWorldAccessor.get(player.getWorld()); + this.world = orebfuscator.worldManager().get(player.getWorld()); this.orebfuscatorPlayer = new OrebfuscatorPlayer(orebfuscator, this); } + public void changeWorld(BukkitWorldAccessor world) { + this.world = world; + this.orebfuscatorPlayer.clearChunks(); + } + public @Nullable CompletableFuture obfuscationFuture(PacketEvent event) { return pendingPackets.remove(event.getPacket().getHandle()); } @@ -117,24 +56,28 @@ public void obfuscationFuture(PacketEvent event, CompletableFuture future) } public void startBatch(AsynchronousManager asynchronousManager, PacketEvent event) { - if (this.chunkBatch != null) { - throw new RuntimeException("Started new chunk batch before previous one was finished!"); + var nextBatch = new PendingChunkBatch(this.orebfuscator.statistics().injector, asynchronousManager, event); + var prevBatch = this.chunkBatch.getAndSet(nextBatch); + + if (prevBatch != null) { + prevBatch.finish(); + OfcLogger.warn("Pending chunk batch discarded because a new batch was initiated."); } - this.chunkBatch = new PendingChunkBatch(this.orebfuscator.statistics().injector, asynchronousManager, event); } - public boolean addBatchChunk(PacketEvent event, CompletableFuture future) { - if (this.chunkBatch != null) { - this.chunkBatch.addChunk(event, future); + public boolean addBatchChunk(CompletableFuture future) { + var batch = this.chunkBatch.get(); + if (batch != null) { + batch.addChunk(future); return true; } return false; } - public void finishBatch(PacketEvent event) { - if (this.chunkBatch != null) { - this.chunkBatch.finish(event); - this.chunkBatch = null; + public void finishBatch() { + var batch = this.chunkBatch.getAndSet(null); + if (batch != null) { + batch.finish(); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessorManager.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessorManager.java new file mode 100644 index 00000000..e91685b0 --- /dev/null +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitPlayerAccessorManager.java @@ -0,0 +1,75 @@ +package net.imprex.orebfuscator.iterop; + +import dev.imprex.orebfuscator.interop.PlayerAccessor; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.imprex.orebfuscator.Orebfuscator; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +public class BukkitPlayerAccessorManager implements Listener { + + private final Map players = new HashMap<>(); + + private final Orebfuscator orebfuscator; + private final BukkitWorldAccessorManager worldManager; + + public BukkitPlayerAccessorManager(Orebfuscator orebfuscator) { + this.orebfuscator = orebfuscator; + this.worldManager = orebfuscator.worldManager(); + + Bukkit.getPluginManager().registerEvents(this, orebfuscator); + + for (Player player : Bukkit.getOnlinePlayers()) { + this.players.computeIfAbsent(player, key -> new BukkitPlayerAccessor(orebfuscator, key)) + .orebfuscatorPlayer().clearChunks(); + } + } + + public List all() { + return this.players.values().stream() + .map(PlayerAccessor.class::cast) + .toList(); + } + + public @Nullable BukkitPlayerAccessor tryGet(Player player) { + return this.players.get(player); + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + this.players.computeIfAbsent(event.getPlayer(), key -> new BukkitPlayerAccessor(orebfuscator, key)) + .orebfuscatorPlayer().clearChunks(); + } + + @EventHandler + public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { + var player = event.getPlayer(); + var bukkitPlayer = this.players.get(player); + if (bukkitPlayer != null) { + bukkitPlayer.changeWorld(this.worldManager.get(player.getWorld())); + } + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + this.players.remove(event.getPlayer()); + } + + @EventHandler + public void onDisable(PluginDisableEvent event) { + if (event.getPlugin() == this.orebfuscator) { + this.players.clear(); + } + } +} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java index 0aff3cae..01dcc7ec 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java @@ -1,17 +1,5 @@ package net.imprex.orebfuscator.iterop; -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.WorldLoadEvent; -import org.bukkit.event.world.WorldUnloadEvent; -import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.MethodAccessor; import dev.imprex.orebfuscator.config.api.WorldConfigBundle; @@ -21,28 +9,25 @@ import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.ChunkDirection; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.util.MinecraftVersion; +import org.bukkit.World; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; @NullMarked public class BukkitWorldAccessor implements WorldAccessor { private static final boolean HAS_DYNAMIC_HEIGHT = MinecraftVersion.isAtOrAbove("1.17"); - private static final Map ACCESSOR_LOOKUP = new ConcurrentHashMap<>(); - - public static BukkitWorldAccessor get(World world) { - return ACCESSOR_LOOKUP.computeIfAbsent(world, key -> { - throw new IllegalStateException("Created world accessor outside of event!"); - }); - } - - private static final MethodAccessor WORLD_GET_MAX_HEIGHT = getWorldMethod("getMaxHeight"); - private static final MethodAccessor WORLD_GET_MIN_HEIGHT = getWorldMethod("getMinHeight"); + private static final @Nullable MethodAccessor WORLD_GET_MAX_HEIGHT = getWorldMethod("getMaxHeight"); + private static final @Nullable MethodAccessor WORLD_GET_MIN_HEIGHT = getWorldMethod("getMinHeight"); - private static MethodAccessor getWorldMethod(String methodName) { + private static @Nullable MethodAccessor getWorldMethod(String methodName) { if (HAS_DYNAMIC_HEIGHT) { MethodAccessor methodAccessor = getWorldMethod0(World.class, methodName); if (methodAccessor == null) { @@ -54,7 +39,7 @@ private static MethodAccessor getWorldMethod(String methodName) { return null; } - private static MethodAccessor getWorldMethod0(Class target, String methodName) { + private static @Nullable MethodAccessor getWorldMethod0(Class target, String methodName) { try { return Accessors.getMethodAccessor(target, methodName); } catch (IllegalArgumentException e) { @@ -72,42 +57,19 @@ private static int blockToSectionCoord(int block) { return block >> 4; } - public static Collection getWorlds() { - return ACCESSOR_LOOKUP.values(); - } - - public static void registerListener(Orebfuscator orebfuscator) { - Bukkit.getPluginManager().registerEvents(new Listener() { - @EventHandler - public void onWorldUnload(WorldLoadEvent event) { - World world = event.getWorld(); - ACCESSOR_LOOKUP.put(world, new BukkitWorldAccessor(world, orebfuscator)); - } - - @EventHandler - public void onWorldUnload(WorldUnloadEvent event) { - ACCESSOR_LOOKUP.remove(event.getWorld()); - } - }, orebfuscator); - - for (World world : Bukkit.getWorlds()) { - ACCESSOR_LOOKUP.put(world, new BukkitWorldAccessor(world, orebfuscator)); - } - } - public final World world; private final Orebfuscator orebfuscator; private final int maxHeight; private final int minHeight; - private WorldConfigBundle worldConfigBundle; + private @Nullable WorldConfigBundle worldConfigBundle; - private BukkitWorldAccessor(World world, Orebfuscator orebfuscator) { + BukkitWorldAccessor(World world, Orebfuscator orebfuscator) { this.world = Objects.requireNonNull(world); this.orebfuscator = Objects.requireNonNull(orebfuscator); - if (HAS_DYNAMIC_HEIGHT) { + if (WORLD_GET_MAX_HEIGHT != null && WORLD_GET_MIN_HEIGHT != null) { this.maxHeight = (int) WORLD_GET_MAX_HEIGHT.invoke(world); this.minHeight = (int) WORLD_GET_MIN_HEIGHT.invoke(world); } else { @@ -125,43 +87,43 @@ public WorldConfigBundle config() { } @Override - public String getName() { + public String name() { return this.world.getName(); } @Override - public int getHeight() { + public int height() { return this.maxHeight - this.minHeight; } @Override - public int getMinBuildHeight() { + public int minBuildHeight() { return this.minHeight; } @Override - public int getMaxBuildHeight() { + public int maxBuildHeight() { return this.maxHeight; } @Override - public int getSectionCount() { - return this.getMaxSection() - this.getMinSection(); + public int sectionCount() { + return this.maxSection() - this.minSection(); } @Override - public int getMinSection() { - return blockToSectionCoord(this.getMinBuildHeight()); + public int minSection() { + return blockToSectionCoord(this.minBuildHeight()); } @Override - public int getMaxSection() { - return blockToSectionCoord(this.getMaxBuildHeight() - 1) + 1; + public int maxSection() { + return blockToSectionCoord(this.maxBuildHeight() - 1) + 1; } @Override - public int getSectionIndex(int y) { - return blockToSectionCoord(y) - getMinSection(); + public int sectionIndex(int y) { + return blockToSectionCoord(y) - minSection(); } public ChunkAccessor[] getNeighboringChunks(int chunkX, int chunkZ) { @@ -213,6 +175,6 @@ public boolean equals(Object obj) { @Override public String toString() { - return String.format("[%s, minY=%s, maxY=%s]", world.getName(), minHeight, maxHeight); + return "[minY=%s, maxY=%s]".formatted(minHeight, maxHeight); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessorManager.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessorManager.java new file mode 100644 index 00000000..aa5801ff --- /dev/null +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessorManager.java @@ -0,0 +1,63 @@ +package net.imprex.orebfuscator.iterop; + +import dev.imprex.orebfuscator.interop.WorldAccessor; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.imprex.orebfuscator.Orebfuscator; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldUnloadEvent; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class BukkitWorldAccessorManager implements Listener { + + private final Map worlds = new HashMap<>(); + + private final Orebfuscator orebfuscator; + + public BukkitWorldAccessorManager(Orebfuscator orebfuscator) { + this.orebfuscator = orebfuscator; + Bukkit.getPluginManager().registerEvents(this, orebfuscator); + + for (World world : Bukkit.getWorlds()) { + this.worlds.put(world, new BukkitWorldAccessor(world, orebfuscator)); + } + } + + public List all() { + return this.worlds.values().stream() + .map(WorldAccessor.class::cast) + .toList(); + } + + public BukkitWorldAccessor get(World world) { + var bukkitWorld = this.worlds.get(world); + if (bukkitWorld == null) { + throw new IllegalStateException("Can't find accessor for world " + world.getName()); + } + return bukkitWorld; + } + + @EventHandler + public void onWorldLoad(WorldLoadEvent event) { + this.worlds.put(event.getWorld(), new BukkitWorldAccessor(event.getWorld(), this.orebfuscator)); + } + + @EventHandler + public void onWorldUnload(WorldUnloadEvent event) { + this.worlds.remove(event.getWorld()); + } + + @EventHandler + public void onDisable(PluginDisableEvent event) { + if (event.getPlugin() == this.orebfuscator) { + this.worlds.clear(); + } + } +} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java index ed072129..a1fe5734 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java @@ -5,6 +5,7 @@ import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.AsynchronousManager; import com.comphenix.protocol.PacketType; @@ -48,6 +49,7 @@ public class ObfuscationAsyncListener extends PacketAdapter { private final ObfuscationPipeline pipeline; private final InjectorStatistics statistics; + private final BukkitPlayerAccessorManager playerManager; private final AsynchronousManager asynchronousManager; private final AsyncListenerHandler asyncListenerHandler; @@ -60,6 +62,7 @@ public ObfuscationAsyncListener(Orebfuscator orebfuscator) { this.pipeline = orebfuscator.obfuscationPipeline(); this.statistics = orebfuscator.statistics().injector; + this.playerManager = orebfuscator.playerManager(); this.asynchronousManager = ProtocolLibrary.getProtocolManager().getAsynchronousManager(); this.asyncListenerHandler = this.asynchronousManager.registerAsyncHandler(this); @@ -89,7 +92,7 @@ public void onPacketSending(PacketEvent event) { return; } - BukkitPlayerAccessor player = BukkitPlayerAccessor.tryGet(event.getPlayer()); + BukkitPlayerAccessor player = this.playerManager.tryGet(event.getPlayer()); if (player == null || !player.isAlive()) { return; } @@ -102,7 +105,7 @@ public void onPacketSending(PacketEvent event) { if (type == PacketType.Play.Server.CHUNK_BATCH_START) { player.startBatch(asynchronousManager, event); } else if (type == PacketType.Play.Server.CHUNK_BATCH_FINISHED) { - player.finishBatch(event); + player.finishBatch(); } else { var future = player.obfuscationFuture(event); if (future == null) { @@ -116,7 +119,7 @@ public void onPacketSending(PacketEvent event) { } } - if (!player.addBatchChunk(event, future)) { + if (!player.addBatchChunk(future)) { // no pending batch so we send each packet individually event.getAsyncMarker().incrementProcessingDelay(); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java index 12b2f101..7a6ed788 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java @@ -1,5 +1,6 @@ package net.imprex.orebfuscator.obfuscation; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -17,12 +18,15 @@ public class ObfuscationSyncListener extends PacketAdapter { private final ObfuscationPipeline pipeline; + private final BukkitPlayerAccessorManager playerManager; + private final ProtocolManager protocolManager; public ObfuscationSyncListener(Orebfuscator orebfuscator) { super(orebfuscator, PacketType.Play.Server.MAP_CHUNK); this.pipeline = orebfuscator.obfuscationPipeline(); + this.playerManager = orebfuscator.playerManager(); this.protocolManager = ProtocolLibrary.getProtocolManager(); this.protocolManager.addPacketListener(this); @@ -34,7 +38,7 @@ public void unregister() { @Override public void onPacketSending(PacketEvent event) { - BukkitPlayerAccessor player = BukkitPlayerAccessor.tryGet(event.getPlayer()); + BukkitPlayerAccessor player = this.playerManager.tryGet(event.getPlayer()); if (player == null || !player.isAlive()) { return; } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java index 38aa0b53..54bf7490 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java @@ -1,24 +1,28 @@ package net.imprex.orebfuscator.obfuscation; -import java.util.Collection; -import org.bukkit.block.Block; -import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.obfuscation.DeobfuscationWorker; import dev.imprex.orebfuscator.util.BlockPos; +import java.util.Collection; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; +import net.imprex.orebfuscator.iterop.BukkitWorldAccessorManager; +import org.bukkit.block.Block; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; @NullMarked public class ObfuscationSystem { private final Orebfuscator orebfuscator; - private ObfuscationSyncListener syncListener; - private ObfuscationAsyncListener asyncListener; - + private final BukkitWorldAccessorManager worldManager; private final DeobfuscationWorker deobfuscationWorker; + private @Nullable ObfuscationSyncListener syncListener; + private @Nullable ObfuscationAsyncListener asyncListener; + public ObfuscationSystem(Orebfuscator orebfuscator) { this.orebfuscator = orebfuscator; + this.worldManager = orebfuscator.worldManager(); this.deobfuscationWorker = new DeobfuscationWorker(orebfuscator); DeobfuscationListener.createAndRegister(orebfuscator, this); @@ -30,7 +34,7 @@ public void registerChunkListener() { } public void deobfuscate(Block block) { - var world = BukkitWorldAccessor.get(block.getWorld()); + var world = this.worldManager.get(block.getWorld()); var blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); this.deobfuscationWorker.deobfuscate(world, blockPos); } @@ -40,7 +44,7 @@ public void deobfuscate(Collection blocks) { return; } - var world = BukkitWorldAccessor.get(blocks.stream().findFirst().get().getWorld()); + var world = this.worldManager.get(blocks.stream().findFirst().get().getWorld()); var blockPos = blocks.stream() .map(block -> new BlockPos(block.getX(), block.getY(), block.getZ())) .toList(); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java index 873c336a..24e0cbbc 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/PendingChunkBatch.java @@ -1,42 +1,44 @@ package net.imprex.orebfuscator.obfuscation; +import com.comphenix.protocol.AsynchronousManager; +import com.comphenix.protocol.events.PacketEvent; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.statistics.InjectorStatistics; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import org.jspecify.annotations.NullMarked; -import com.comphenix.protocol.AsynchronousManager; -import com.comphenix.protocol.events.PacketEvent; -import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.statistics.InjectorStatistics; @NullMarked public class PendingChunkBatch { - private final InjectorStatistics statistics; private final long enqueuedAt = System.nanoTime(); + private final InjectorStatistics statistics; private final AsynchronousManager asynchronousManager; + private final AtomicBoolean finished = new AtomicBoolean(false); - private final PacketEvent event; + private final PacketEvent startPacket; private final List> pendingFutures = new ArrayList<>(); - public PendingChunkBatch(InjectorStatistics statistics, AsynchronousManager asynchronousManager, PacketEvent event) { + public PendingChunkBatch(InjectorStatistics statistics, AsynchronousManager asynchronousManager, + PacketEvent startPacket) { this.statistics = statistics; this.asynchronousManager = asynchronousManager; - this.event = event; - event.getAsyncMarker().incrementProcessingDelay(); + this.startPacket = startPacket; + startPacket.getAsyncMarker().incrementProcessingDelay(); } - public void addChunk(PacketEvent event, CompletableFuture future) { + public void addChunk(CompletableFuture future) { if (!this.finished.get()) { this.pendingFutures.add(future); } } - public void finish(PacketEvent event) { + public void finish() { if (this.finished.compareAndSet(false, true)) { var futures = this.pendingFutures.toArray(CompletableFuture[]::new); @@ -47,7 +49,7 @@ public void finish(PacketEvent event) { // only delay/signal start packet as any packet after has to wait anyways and that way we // only take up a single processing slot in ProtocolLib's async filter manager per batch - this.asynchronousManager.signalPacketTransmission(this.event); + this.asynchronousManager.signalPacketTransmission(this.startPacket); statistics.packetDelayChunk.add(System.nanoTime() - this.enqueuedAt); }); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java index ceced80f..e629731a 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java @@ -1,5 +1,6 @@ package net.imprex.orebfuscator.proximity; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -22,11 +23,14 @@ public class ProximityPacketListener extends PacketAdapter { private static final boolean HAS_CHUNK_POS_FIELD = MinecraftVersion.isAtOrAbove("1.20.2"); + private final BukkitPlayerAccessorManager playerManager; private final ProtocolManager protocolManager; public ProximityPacketListener(Orebfuscator orebfuscator) { super(orebfuscator, PacketType.Play.Server.UNLOAD_CHUNK); + this.playerManager = orebfuscator.playerManager(); + this.protocolManager = ProtocolLibrary.getProtocolManager(); this.protocolManager.addPacketListener(this); } @@ -37,7 +41,7 @@ public void unregister() { @Override public void onPacketSending(PacketEvent event) { - BukkitPlayerAccessor player = BukkitPlayerAccessor.tryGet(event.getPlayer()); + BukkitPlayerAccessor player = this.playerManager.tryGet(event.getPlayer()); if (player == null || player.hasPermission(PermissionRequirements.BYPASS)) { return; } From 8917690f989f8f7fe5e9e30e2e17e1951a2c0acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sun, 1 Feb 2026 13:44:21 +0100 Subject: [PATCH 09/14] feat: only force load chunks for obfuscation --- .../orebfuscator/api/OrebfuscatorService.java | 1 - .../OrebfuscatorCompatibility.java | 26 +-- .../compatibility/CompatibilityLayer.java | 9 - .../compatibility/CompatibilityScheduler.java | 2 - .../bukkit/BukkitChunkLoader.java | 79 ------- .../bukkit/BukkitCompatibilityLayer.java | 46 ---- .../spigot/SpigotCompatibilityLayer.java | 27 +++ .../SpigotScheduler.java} | 16 +- .../folia/FoliaCompatibilityLayer.java | 7 +- .../compatibility/folia/FoliaScheduler.java | 13 +- .../AbstractPaperCompatibilityLayer.java | 44 ---- .../paper/PaperCompatibilityLayer.java | 12 +- .../orebfuscator/OrebfuscatorDumpFile.java | 135 +++++++++++ .../config/AbstractWorldConfig.java | 7 +- .../config/OrebfuscatorConfig.java | 13 +- .../config/OrebfuscatorObfuscationConfig.java | 9 +- .../config/OrebfuscatorProximityConfig.java | 8 +- .../config/components/BlockParser.java | 2 +- .../config/components/ConfigBlockValue.java | 23 +- .../orebfuscator/interop/ChunkAccessor.java | 12 + .../interop/OrebfuscatorCore.java | 4 + .../interop/RegistryAccessor.java | 1 + .../orebfuscator/interop/WorldAccessor.java | 8 +- .../obfuscation/DeobfuscationWorker.java | 11 +- .../obfuscation/ObfuscationPipeline.java | 4 +- .../obfuscation/ObfuscationProcessor.java | 14 +- .../obfuscation/ObfuscationRequest.java | 7 +- .../proximity/ProximityRayCaster.java | 18 +- .../proximity/ProximityWorker.java | 4 +- .../statistics/StatisticsRegistry.java | 16 +- .../imprex/orebfuscator/util/BlockTag.java | 4 +- .../imprex/orebfuscator/OrebfuscatorNms.java | 49 +--- .../orebfuscator/nms/AbstractNmsManager.java | 18 +- .../imprex/orebfuscator/nms/NmsManager.java | 16 +- .../orebfuscator/util/MinecraftVersion.java | 6 +- .../orebfuscator-nms-v1_16_R1/pom.xml | 35 --- .../orebfuscator/nms/v1_16_R1/NmsManager.java | 206 ----------------- .../nms/v1_16_R1/ReadOnlyChunkWrapper.java | 18 -- .../nms/v1_16_R1/RegionFileCache.java | 44 ---- .../orebfuscator-nms-v1_16_R2/pom.xml | 35 --- .../orebfuscator/nms/v1_16_R2/NmsManager.java | 210 ------------------ .../nms/v1_16_R2/ReadOnlyChunkWrapper.java | 18 -- .../nms/v1_16_R2/RegionFileCache.java | 44 ---- ...Wrapper.java => DefaultChunkAccessor.java} | 8 +- .../orebfuscator/nms/v1_16_R3/NmsManager.java | 65 +++--- .../nms/v1_16_R3/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_17_R1/NmsManager.java | 59 ++--- .../nms/v1_17_R1/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_18_R1/NmsManager.java | 59 ++--- .../nms/v1_18_R1/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_18_R2/NmsManager.java | 61 ++--- .../nms/v1_18_R2/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_19_R1/NmsManager.java | 61 ++--- .../nms/v1_19_R1/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_19_R2/NmsManager.java | 61 ++--- .../nms/v1_19_R2/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_19_R3/NmsManager.java | 61 ++--- .../nms/v1_19_R3/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_20_R1/NmsManager.java | 61 ++--- .../nms/v1_20_R1/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_20_R2/NmsManager.java | 61 ++--- .../nms/v1_20_R2/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_20_R3/NmsManager.java | 61 ++--- .../nms/v1_20_R3/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_20_R4/NmsManager.java | 61 ++--- .../nms/v1_20_R4/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_21_R1/NmsManager.java | 61 ++--- .../nms/v1_21_R1/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_21_R2/NmsManager.java | 61 ++--- .../nms/v1_21_R2/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_21_R3/NmsManager.java | 61 ++--- .../nms/v1_21_R3/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_21_R4/NmsManager.java | 61 ++--- .../nms/v1_21_R4/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_21_R5/NmsManager.java | 61 ++--- .../nms/v1_21_R5/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_21_R6/NmsManager.java | 61 ++--- .../nms/v1_21_R6/RegionFileCache.java | 10 +- ...Wrapper.java => DefaultChunkAccessor.java} | 10 +- .../orebfuscator/nms/v1_21_R7/NmsManager.java | 68 +++--- .../nms/v1_21_R7/RegionFileCache.java | 10 +- orebfuscator-nms/pom.xml | 2 - orebfuscator-plugin/pom.xml | 12 - .../net/imprex/orebfuscator/Orebfuscator.java | 37 ++- .../orebfuscator/OrebfuscatorCommand.java | 121 +++------- .../iterop/BukkitChunkPacketAccessor.java | 10 +- .../iterop/BukkitLoggerAccessor.java | 4 +- .../iterop/BukkitWorldAccessor.java | 48 ++-- .../obfuscation/DeobfuscationListener.java | 24 +- .../obfuscation/ObfuscationAsyncListener.java | 24 +- .../obfuscation/ObfuscationSyncListener.java | 6 +- .../obfuscation/ObfuscationSystem.java | 1 - .../proximity/ProximityPacketListener.java | 4 +- .../orebfuscator/util/PermissionUtil.java | 2 +- ...rappedClientboundLevelChunkPacketData.java | 8 +- 111 files changed, 1142 insertions(+), 1905 deletions(-) delete mode 100644 orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java delete mode 100644 orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java create mode 100644 orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/spigot/SpigotCompatibilityLayer.java rename orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/{bukkit/BukkitScheduler.java => spigot/SpigotScheduler.java} (63%) delete mode 100644 orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/OrebfuscatorDumpFile.java delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R1/pom.xml delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/NmsManager.java delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/ReadOnlyChunkWrapper.java delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/RegionFileCache.java delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R2/pom.xml delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/NmsManager.java delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/ReadOnlyChunkWrapper.java delete mode 100644 orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/RegionFileCache.java rename orebfuscator-nms/orebfuscator-nms-v1_16_R3/src/main/java/net/imprex/orebfuscator/nms/v1_16_R3/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (62%) rename orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) rename orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/{ReadOnlyChunkWrapper.java => DefaultChunkAccessor.java} (50%) diff --git a/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java b/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java index 096f9faa..4f996253 100644 --- a/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java +++ b/orebfuscator-api/src/main/java/net/imprex/orebfuscator/api/OrebfuscatorService.java @@ -1,7 +1,6 @@ package net.imprex.orebfuscator.api; import java.util.Collection; - import org.bukkit.block.Block; import org.jspecify.annotations.NullMarked; diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java index a18f05b4..f8961432 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorCompatibility.java @@ -1,18 +1,12 @@ package net.imprex.orebfuscator; -import java.lang.reflect.Constructor; -import java.util.concurrent.CompletableFuture; - -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - import dev.imprex.orebfuscator.config.api.Config; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; +import java.lang.reflect.Constructor; import net.imprex.orebfuscator.compatibility.CompatibilityLayer; import net.imprex.orebfuscator.util.ServerVersion; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; public class OrebfuscatorCompatibility { @@ -23,7 +17,7 @@ public static void initialize(Plugin plugin, Config config) { throw new IllegalStateException("Compatibility layer is already initialized!"); } - String className = "net.imprex.orebfuscator.compatibility.bukkit.BukkitCompatibilityLayer"; + String className = "net.imprex.orebfuscator.compatibility.spigot.SpigotCompatibilityLayer"; if (ServerVersion.isFolia()) { className = "net.imprex.orebfuscator.compatibility.folia.FoliaCompatibilityLayer"; } else if (ServerVersion.isPaper()) { @@ -56,18 +50,6 @@ public static void runAsyncNow(Runnable runnable) { instance.getScheduler().runAsyncNow(runnable); } - public static void runAsyncAtFixedRate(Runnable runnable, long delay, long period) { - instance.getScheduler().runAsyncAtFixedRate(runnable, delay, period); - } - - public static void cancelTasks() { - instance.getScheduler().cancelTasks(); - } - - public static CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request) { - return instance.getNeighboringChunks(world, request); - } - public static void close() { if (instance != null) { instance.getScheduler().cancelTasks(); diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java index 4074ee4c..f80845aa 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityLayer.java @@ -1,17 +1,8 @@ package net.imprex.orebfuscator.compatibility; -import java.util.concurrent.CompletableFuture; - -import org.bukkit.World; - -import dev.imprex.orebfuscator.interop.ChunkAccessor; -import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; - public interface CompatibilityLayer { boolean isGameThread(); CompatibilityScheduler getScheduler(); - - CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request); } diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityScheduler.java b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityScheduler.java index 37d1436b..a9ac2ba2 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityScheduler.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-api/src/main/java/net/imprex/orebfuscator/compatibility/CompatibilityScheduler.java @@ -8,7 +8,5 @@ public interface CompatibilityScheduler { void runAsyncNow(Runnable runnable); - void runAsyncAtFixedRate(Runnable runnable, long delay, long period); - void cancelTasks(); } diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java deleted file mode 100644 index 0976412d..00000000 --- a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitChunkLoader.java +++ /dev/null @@ -1,79 +0,0 @@ -package net.imprex.orebfuscator.compatibility.bukkit; - -import java.util.Queue; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.TimeUnit; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.plugin.Plugin; -import dev.imprex.orebfuscator.config.api.Config; -import dev.imprex.orebfuscator.interop.ChunkAccessor; -import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; -import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; -import dev.imprex.orebfuscator.util.ChunkDirection; -import net.imprex.orebfuscator.OrebfuscatorNms; - -public class BukkitChunkLoader implements Runnable { - - private final Queue tasks = new ConcurrentLinkedQueue<>(); - - private final long availableNanosPerTick; - - public BukkitChunkLoader(Plugin plugin, Config config) { - this.availableNanosPerTick = TimeUnit.MILLISECONDS.toNanos(config.advanced().maxMillisecondsPerTick()); - - Bukkit.getScheduler().runTaskTimer(plugin, this, 0, 1); - } - - public CompletableFuture submitRequest(World world, ObfuscationRequest request) { - Task task = new Task(world, request); - this.tasks.offer(task); - return task.future; - } - - @Override - public void run() { - final long time = System.nanoTime(); - - Task task = null; - while (System.nanoTime() - time < this.availableNanosPerTick && (task = this.tasks.poll()) != null) { - task.run(); - } - } - - private class Task implements Runnable { - - private final World world; - private final ObfuscationRequest request; - - private final CompletableFuture future = new CompletableFuture<>(); - - public Task(World world, ObfuscationRequest request) { - this.world = world; - this.request = request; - } - - @Override - public void run() { - final ChunkPacketAccessor packet = this.request.packet(); - final ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; - - for (ChunkDirection direction : ChunkDirection.values()) { - int chunkX = packet.chunkX() + direction.getOffsetX(); - int chunkZ = packet.chunkZ() + direction.getOffsetZ(); - - int index = direction.ordinal(); - var chunk = this.request.neighborChunks()[index]; - - if (chunk != null) { - neighboringChunks[index] = chunk; - } else { - neighboringChunks[index] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); - } - } - - future.complete(neighboringChunks); - } - } -} diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java deleted file mode 100644 index 6f286432..00000000 --- a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitCompatibilityLayer.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.imprex.orebfuscator.compatibility.bukkit; - -import java.util.Arrays; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; - -import org.bukkit.World; -import org.bukkit.plugin.Plugin; - -import dev.imprex.orebfuscator.config.api.Config; -import dev.imprex.orebfuscator.interop.ChunkAccessor; -import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; -import net.imprex.orebfuscator.compatibility.CompatibilityLayer; -import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; - -public class BukkitCompatibilityLayer implements CompatibilityLayer { - - private final Thread mainThread = Thread.currentThread(); - - private final BukkitScheduler scheduler; - private final BukkitChunkLoader chunkLoader; - - public BukkitCompatibilityLayer(Plugin plugin, Config config) { - this.scheduler = new BukkitScheduler(plugin); - this.chunkLoader = new BukkitChunkLoader(plugin, config); - } - - @Override - public boolean isGameThread() { - return Thread.currentThread() == this.mainThread; - } - - @Override - public CompatibilityScheduler getScheduler() { - return this.scheduler; - } - - @Override - public CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request) { - if (!Arrays.stream(request.neighborChunks()).anyMatch(Objects::isNull)) { - return CompletableFuture.completedFuture(request.neighborChunks()); - } - - return this.chunkLoader.submitRequest(world, request); - } -} diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/spigot/SpigotCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/spigot/SpigotCompatibilityLayer.java new file mode 100644 index 00000000..8c98c1fb --- /dev/null +++ b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/spigot/SpigotCompatibilityLayer.java @@ -0,0 +1,27 @@ +package net.imprex.orebfuscator.compatibility.spigot; + +import dev.imprex.orebfuscator.config.api.Config; +import net.imprex.orebfuscator.compatibility.CompatibilityLayer; +import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; +import org.bukkit.plugin.Plugin; + +public class SpigotCompatibilityLayer implements CompatibilityLayer { + + private final Thread mainThread = Thread.currentThread(); + + private final SpigotScheduler scheduler; + + public SpigotCompatibilityLayer(Plugin plugin, Config config) { + this.scheduler = new SpigotScheduler(plugin); + } + + @Override + public boolean isGameThread() { + return Thread.currentThread() == this.mainThread; + } + + @Override + public CompatibilityScheduler getScheduler() { + return this.scheduler; + } +} diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitScheduler.java b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/spigot/SpigotScheduler.java similarity index 63% rename from orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitScheduler.java rename to orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/spigot/SpigotScheduler.java index c5ce35ef..0dc6fe71 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/bukkit/BukkitScheduler.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-bukkit/src/main/java/net/imprex/orebfuscator/compatibility/spigot/SpigotScheduler.java @@ -1,16 +1,15 @@ -package net.imprex.orebfuscator.compatibility.bukkit; +package net.imprex.orebfuscator.compatibility.spigot; +import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; - -public class BukkitScheduler implements CompatibilityScheduler { +public class SpigotScheduler implements CompatibilityScheduler { private final Plugin plugin; - public BukkitScheduler(Plugin plugin) { + public SpigotScheduler(Plugin plugin) { this.plugin = plugin; } @@ -28,13 +27,6 @@ public void runAsyncNow(Runnable runnable) { } } - @Override - public void runAsyncAtFixedRate(Runnable runnable, long delay, long period) { - if (this.plugin.isEnabled()) { - Bukkit.getScheduler().runTaskTimerAsynchronously(this.plugin, runnable, delay, period); - } - } - @Override public void cancelTasks() { Bukkit.getScheduler().cancelTasks(this.plugin); diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaCompatibilityLayer.java index ab557a86..1ab1984e 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaCompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaCompatibilityLayer.java @@ -1,12 +1,11 @@ package net.imprex.orebfuscator.compatibility.folia; -import org.bukkit.plugin.Plugin; - import dev.imprex.orebfuscator.config.api.Config; +import net.imprex.orebfuscator.compatibility.CompatibilityLayer; import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; -import net.imprex.orebfuscator.compatibility.paper.AbstractPaperCompatibilityLayer; +import org.bukkit.plugin.Plugin; -public class FoliaCompatibilityLayer extends AbstractPaperCompatibilityLayer { +public class FoliaCompatibilityLayer implements CompatibilityLayer { private static final Class TICK_THREAD_CLASS = getTickThreadClass(); diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaScheduler.java b/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaScheduler.java index 677713fa..e76693b2 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaScheduler.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-folia/src/main/java/net/imprex/orebfuscator/compatibility/folia/FoliaScheduler.java @@ -1,13 +1,10 @@ package net.imprex.orebfuscator.compatibility.folia; -import java.util.concurrent.TimeUnit; - +import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; - public class FoliaScheduler implements CompatibilityScheduler { private final Plugin plugin; @@ -30,14 +27,6 @@ public void runAsyncNow(Runnable runnable) { } } - @Override - public void runAsyncAtFixedRate(Runnable runnable, long delay, long period) { - if (this.plugin.isEnabled()) { - Bukkit.getAsyncScheduler().runAtFixedRate(this.plugin, task -> runnable.run(), - delay * 50, period * 50, TimeUnit.MILLISECONDS); - } - } - @Override public void cancelTasks() { Bukkit.getAsyncScheduler().cancelTasks(this.plugin); diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java deleted file mode 100644 index 2c6b3a78..00000000 --- a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/AbstractPaperCompatibilityLayer.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.imprex.orebfuscator.compatibility.paper; - -import java.util.Arrays; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import org.bukkit.World; -import dev.imprex.orebfuscator.interop.ChunkAccessor; -import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; -import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; -import dev.imprex.orebfuscator.util.ChunkDirection; -import net.imprex.orebfuscator.OrebfuscatorNms; -import net.imprex.orebfuscator.compatibility.CompatibilityLayer; - -public abstract class AbstractPaperCompatibilityLayer implements CompatibilityLayer { - - @Override - public CompletableFuture getNeighboringChunks(World world, ObfuscationRequest request) { - if (!Arrays.stream(request.neighborChunks()).anyMatch(Objects::isNull)) { - return CompletableFuture.completedFuture(request.neighborChunks()); - } - - final ChunkPacketAccessor packet = request.packet(); - final CompletableFuture[] futures = new CompletableFuture[4]; - final ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; - - for (ChunkDirection direction : ChunkDirection.values()) { - int chunkX = packet.chunkX() + direction.getOffsetX(); - int chunkZ = packet.chunkZ() + direction.getOffsetZ(); - - int index = direction.ordinal(); - var chunk = request.neighborChunks()[index]; - - if (chunk != null) { - futures[index] = CompletableFuture.completedFuture(chunk); - } else { - futures[index] = world.getChunkAtAsync(chunkX, chunkZ).thenAccept(c -> { - neighboringChunks[index] = OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); - }); - } - } - - return CompletableFuture.allOf(futures).thenApply(v -> neighboringChunks); - } -} diff --git a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/PaperCompatibilityLayer.java b/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/PaperCompatibilityLayer.java index a72d8a23..d8047c4d 100644 --- a/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/PaperCompatibilityLayer.java +++ b/orebfuscator-compatibility/orebfuscator-compatibility-paper/src/main/java/net/imprex/orebfuscator/compatibility/paper/PaperCompatibilityLayer.java @@ -1,19 +1,19 @@ package net.imprex.orebfuscator.compatibility.paper; -import org.bukkit.plugin.Plugin; - import dev.imprex.orebfuscator.config.api.Config; +import net.imprex.orebfuscator.compatibility.CompatibilityLayer; import net.imprex.orebfuscator.compatibility.CompatibilityScheduler; -import net.imprex.orebfuscator.compatibility.bukkit.BukkitScheduler; +import net.imprex.orebfuscator.compatibility.spigot.SpigotScheduler; +import org.bukkit.plugin.Plugin; -public class PaperCompatibilityLayer extends AbstractPaperCompatibilityLayer { +public class PaperCompatibilityLayer implements CompatibilityLayer { private final Thread mainThread = Thread.currentThread(); - private final BukkitScheduler scheduler; + private final SpigotScheduler scheduler; public PaperCompatibilityLayer(Plugin plugin, Config config) { - this.scheduler = new BukkitScheduler(plugin); + this.scheduler = new SpigotScheduler(plugin); } @Override diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/OrebfuscatorDumpFile.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/OrebfuscatorDumpFile.java new file mode 100644 index 00000000..40e5aaab --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/OrebfuscatorDumpFile.java @@ -0,0 +1,135 @@ +package dev.imprex.orebfuscator; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.internal.Streams; +import com.google.gson.stream.JsonWriter; +import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.interop.WorldAccessor; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.util.JavaVersion; +import java.io.BufferedWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.util.Base64; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +public class OrebfuscatorDumpFile extends ConfigurationSection { + + private static final DateTimeFormatter FILE_FORMAT = DateTimeFormatter.ofPattern("uuuu-MM-dd_HH.mm.ss"); + private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + + private static final Gson GSON = new GsonBuilder().setPrettyPrinting() + .registerTypeAdapter(ConfigurationSection.class, new Json()) + .create(); + + private final OrebfuscatorCore orebfuscator; + private final TemporalAccessor now; + + public OrebfuscatorDumpFile(OrebfuscatorCore orebfuscator) { + super(""); + + this.orebfuscator = orebfuscator; + this.now = OffsetDateTime.now(ZoneOffset.UTC); + + this.initialize(); + } + + private void initialize() { + set("timestamp", TIME_FORMAT.format(now)); + + set("versions.java", JavaVersion.get()); + set("versions.orebfuscator", orebfuscator.orebfuscatorVersion().toString()); + + var statistics = createSection("statistics"); + orebfuscator.statisticsRegistry().entries().stream() + .sorted(Comparator.comparing(Map.Entry::getKey)) + .forEach(entry -> statistics.set(entry.getKey(), entry.getValue())); + + var levels = createSection("levels"); + for (WorldAccessor accessor : orebfuscator.worlds()) { + var section = levels.createSection(accessor.name()); + section.set("accessor", accessor); + section.set("minY", accessor.minBuildHeight()); + section.set("maxY", accessor.maxBuildHeight()); + } + + orebfuscator.config().dumpBlocks(createSection("blocks")); + + Base64.Encoder encoder = Base64.getUrlEncoder(); + String latestLog = OfcLogger.getLatestVerboseLog(); + set("verboseLog", encoder.encodeToString(latestLog.getBytes(StandardCharsets.UTF_8))); + + try { + Path configPath = orebfuscator.configDirectory().resolve("config.yml"); + String config = String.join("\n", Files.readAllLines(configPath)); + set("config", encoder.encodeToString(config.getBytes(StandardCharsets.UTF_8))); + } catch (IOException e) { + OfcLogger.error(e); + } + + String configReport = orebfuscator.config().report(); + configReport = configReport != null ? configReport : ""; + set("configReport", encoder.encodeToString(configReport.getBytes(StandardCharsets.UTF_8))); + } + + public Path write() { + Path path = orebfuscator.configDirectory().resolve("dump-" + FILE_FORMAT.format(now) + ".json"); + try (BufferedWriter writer = Files.newBufferedWriter(path)) { + GSON.toJson(this, writer); + } catch (IOException e) { + OfcLogger.error(e); + } + + return path; + } + + private static class Json implements JsonSerializer { + + @Override + public JsonElement serialize(ConfigurationSection section, Type type, JsonSerializationContext jsonSerializationContext) { + return serialize(section); + } + + private JsonElement serialize(Object value) { + if (value instanceof Boolean booleanValue) { + return new JsonPrimitive(booleanValue); + } else if (value instanceof Number numberValue) { + return new JsonPrimitive(numberValue); + } else if (value instanceof String stringValue) { + return new JsonPrimitive(stringValue); + } else if (value instanceof List list) { + JsonArray json = new JsonArray(list.size()); + for (Object item : list) { + json.add(serialize(item)); + } + return json; + } else if (value instanceof ConfigurationSection section) { + JsonObject json = new JsonObject(); + for (String key : section.getKeys()) { + json.add(key, serialize(section.get(key))); + } + return json; + } + + throw new JsonIOException("Unexpected type " + value.getClass()); + } + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java index e33daea2..f61acdbd 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/AbstractWorldConfig.java @@ -104,12 +104,11 @@ protected String getName() { return name; } - public JsonObject randomBlocksToJson() { - JsonObject object = new JsonObject(); + public void dumpBlocks(ConfigurationSection section) { + var randomBlocks = section.createSection("randomBlocks"); for (WeightedBlockList list : weightedBlockLists) { - object.add(list.getName(), ConfigBlockValue.toJson(list.getBlocks())); + ConfigBlockValue.dump(randomBlocks.createSection(list.getName()), list.getBlocks()); } - return object; } @Override diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java index 977f3c7d..839e52f1 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java @@ -17,7 +17,6 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import com.google.common.hash.Hashing; -import com.google.gson.JsonObject; import dev.imprex.orebfuscator.config.api.AdvancedConfig; import dev.imprex.orebfuscator.config.api.BlockFlags; import dev.imprex.orebfuscator.config.api.CacheConfig; @@ -236,18 +235,16 @@ private void serialize(ConfigurationSection section) { } } - public JsonObject toJson() { - JsonObject object = new JsonObject(); - + public void dumpBlocks(ConfigurationSection section) { + var obfuscation = section.createSection("obfuscation"); for (var config : obfuscationConfigs) { - object.add(config.getName(), config.toJson()); + config.dumpBlocks(obfuscation.createSection(config.getName())); } + var proximity = section.createSection("proximity"); for (var config : proximityConfigs) { - object.add(config.getName(), config.toJson()); + config.dumpBlocks(proximity.createSection(config.getName())); } - - return object; } @Override diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java index 3ac4996a..d4bae980 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorObfuscationConfig.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.config; +import dev.imprex.orebfuscator.config.components.WeightedBlockList; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; @@ -69,11 +70,9 @@ private void serializeHiddenBlocks(ConfigurationSection section) { section.set("hiddenBlocks", blockNames); } - public JsonObject toJson() { - JsonObject object = new JsonObject(); - object.add("hiddenBlocks", ConfigBlockValue.toJson(hiddenBlocks)); - object.add("randomBlocks", randomBlocksToJson()); - return object; + public void dumpBlocks(ConfigurationSection section) { + ConfigBlockValue.dump(section.createSection("hiddenBlocks"), hiddenBlocks); + super.dumpBlocks(section); } @Override diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java index 0ebab9bc..edbb71d1 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorProximityConfig.java @@ -161,11 +161,9 @@ private void serializeHiddenBlocks(ConfigurationSection section) { } } - public JsonObject toJson() { - JsonObject object = new JsonObject(); - object.add("hiddenBlocks", ConfigBlockValue.toJson(hiddenBlocks.keySet())); - object.add("randomBlocks", randomBlocksToJson()); - return object; + public void dumpBlocks(ConfigurationSection section) { + ConfigBlockValue.dump(section.createSection("hiddenBlocks"), hiddenBlocks.keySet()); + super.dumpBlocks(section); } @Override diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java index 355082c8..f199392a 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/BlockParser.java @@ -13,7 +13,7 @@ @NullMarked public class BlockParser { - public static BlockParser.Factory factory(RegistryAccessor registryAccessor) { + public static Factory factory(RegistryAccessor registryAccessor) { return new Factory(registryAccessor); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java index e32f9f01..8a411dfe 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/components/ConfigBlockValue.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.config.components; +import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; import java.util.Collection; import java.util.Collections; import java.util.Objects; @@ -19,26 +20,18 @@ public record ConfigBlockValue(String value, Set blocks) implem private static final JsonElement INVALID = new JsonPrimitive("invalid"); private static final JsonElement VALID = new JsonPrimitive("valid"); - public static JsonObject toJson(Collection values) { - JsonObject object = new JsonObject(); - - var list = values.stream().sorted().toList(); - - for (var entry : list) { + public static void dump(ConfigurationSection section, Collection values) { + for (var entry : values.stream().sorted().toList()) { if (entry.blocks().size() > 1) { - JsonArray array = new JsonArray(entry.blocks().size()); - for (var block : entry.blocks()) { - array.add(block.getKey().toString()); - } - object.add(entry.value(), array); + section.set(entry.value(), entry.blocks().stream() + .map(block -> block.getKey().toString()) + .toList()); } else if (!entry.blocks().isEmpty()) { - object.add(entry.value(), VALID); + section.set(entry.value(), VALID); } else { - object.add(entry.value(), INVALID); + section.set(entry.value(), INVALID); } } - - return object; } public static ConfigBlockValue invalid(String value) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java index 758e5ac8..144a744e 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/ChunkAccessor.java @@ -1,6 +1,8 @@ package dev.imprex.orebfuscator.interop; +import org.jetbrains.annotations.Contract; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; @NullMarked public interface ChunkAccessor { @@ -11,5 +13,15 @@ static long chunkCoordsToLong(int chunkX, int chunkZ) { return (chunkZ & 0xffffffffL) << 32 | chunkX & 0xffffffffL; } + @Contract("null -> true; !null -> _") + static boolean isNullOrEmpty(@Nullable ChunkAccessor chunkAccessor) { + return chunkAccessor == null || chunkAccessor == EMPTY; + } + + @Contract("null -> !null; !null -> param1") + static ChunkAccessor ofNullable(@Nullable ChunkAccessor chunkAccessor) { + return chunkAccessor == null ? EMPTY : chunkAccessor; + } + int getBlockState(int x, int y, int z); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java index c759bdc8..79cb2887 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/OrebfuscatorCore.java @@ -1,5 +1,7 @@ package dev.imprex.orebfuscator.interop; +import dev.imprex.orebfuscator.statistics.StatisticsRegistry; +import dev.imprex.orebfuscator.util.Version; import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.cache.ObfuscationCache; import dev.imprex.orebfuscator.chunk.ChunkFactory; @@ -18,6 +20,8 @@ public interface OrebfuscatorCore extends ServerAccessor { OrebfuscatorExecutor executor(); + StatisticsRegistry statisticsRegistry(); + OrebfuscatorStatistics statistics(); OrebfuscatorConfig config(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java index 54275308..b38e183e 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/RegistryAccessor.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.interop; +import org.jetbrains.annotations.Range; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import dev.imprex.orebfuscator.util.BlockProperties; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java index 9dec6270..56c9119b 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/interop/WorldAccessor.java @@ -1,10 +1,13 @@ package dev.imprex.orebfuscator.interop; +import dev.imprex.orebfuscator.util.ChunkDirection; import java.util.concurrent.CompletableFuture; +import org.jetbrains.annotations.CheckReturnValue; import org.jspecify.annotations.NullMarked; import dev.imprex.orebfuscator.config.api.WorldConfigBundle; import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import dev.imprex.orebfuscator.util.BlockPos; +import org.jspecify.annotations.Nullable; @NullMarked public interface WorldAccessor { @@ -29,10 +32,7 @@ public interface WorldAccessor { CompletableFuture getNeighboringChunks(ObfuscationRequest request); - ChunkAccessor getChunk(int chunkX, int chunkZ); - - @Deprecated - int getBlockState(int x, int y, int z); + ChunkAccessor getChunkNow(int chunkX, int chunkZ); void sendBlockUpdates(Iterable iterable); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java index 8de7a8e0..81fd8dc2 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/DeobfuscationWorker.java @@ -26,7 +26,7 @@ public class DeobfuscationWorker { private static List precomputeOffsets(int radius) { - List> offset = new ArrayList<>(); + List> offset = new ArrayList<>(); for (int dx = -radius; dx <= radius; dx++) { for (int dy = -radius; dy <= radius; dy++) { @@ -40,9 +40,9 @@ private static List precomputeOffsets(int radius) { } offset - .sort(Comparator.comparingInt((Map.Entry e) -> e.getValue()).thenComparing(Entry::getKey)); + .sort(Comparator.comparingInt((Entry e) -> e.getValue()).thenComparing(Entry::getKey)); - return offset.stream().map(Map.Entry::getKey).toList(); + return offset.stream().map(Entry::getKey).toList(); } private final OrebfuscatorConfig config; @@ -102,9 +102,8 @@ private void deobfuscateNow(WorldAccessor world, List blocks) { int chunkZ = position.z() >> 4; long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); - // TODO: use getChunkNow instead of getChunk with force load? - var chunk = chunks.computeIfAbsent(key, k -> world.getChunk(chunkX, chunkZ)); - if (chunk == null) { + ChunkAccessor chunk = chunks.computeIfAbsent(key, k -> world.getChunkNow(chunkX, chunkZ)); + if (ChunkAccessor.isNullOrEmpty(chunk)) { continue; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java index c79f94cb..2d162b63 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationPipeline.java @@ -89,11 +89,9 @@ private CompletionStage requestInternal( OfcLogger.error("Can't get neighboring chunks for (%d, %d)".formatted(packet.chunkX(), packet.chunkZ()), throwable); return request; - } else if (neighbors == null) { - return request; } - long missingChunks = Arrays.stream(neighbors).filter(n -> n == ChunkAccessor.EMPTY).count(); + long missingChunks = Arrays.stream(neighbors).filter(ChunkAccessor::isNullOrEmpty).count(); statistics.obfuscation.missingNeighboringChunks.add(missingChunks); return request.withNeighbors(neighbors); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java index 73a22090..c39c01fe 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationProcessor.java @@ -27,7 +27,7 @@ @NullMarked public class ObfuscationProcessor { - private static final ThreadLocal STATE = ThreadLocal.withInitial(() -> new State()); + private static final ThreadLocal STATE = ThreadLocal.withInitial(State::new); private final ChunkFactory chunkFactory; private final RegistryAccessor registryAccessor; @@ -178,15 +178,13 @@ && isAdjacentBlockOccluding(request, chunk, state, x, y, z + 1) private boolean isAdjacentBlockOccluding(ObfuscationRequest request, Chunk chunk, State state, int x, int y, int z) { int blockId = getBlockId(request, chunk, x, y, z); - if (blockId < 0) { - return false; - } - if (registryAccessor.isOccluding(blockId)) { return true; - } else if (registryAccessor.isLava(blockId)) { + } + + if (registryAccessor.isLava(blockId)) { int aboveBlockId = getBlockId(request, chunk, x, y + 1, z); - state.isLava = aboveBlockId >= 0 && registryAccessor.isLava(aboveBlockId); + state.isLava = registryAccessor.isLava(aboveBlockId); return state.isLava; } @@ -195,7 +193,7 @@ private boolean isAdjacentBlockOccluding(ObfuscationRequest request, Chunk chunk private int getBlockId(ObfuscationRequest request, Chunk chunk, int x, int y, int z) { if (y >= chunk.world().maxBuildHeight() || y < chunk.world().minBuildHeight()) { - return -1; + return 0; } int blockId = chunk.getBlockState(x, y, z); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java index 338a6300..cce17292 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/obfuscation/ObfuscationRequest.java @@ -1,5 +1,6 @@ package dev.imprex.orebfuscator.obfuscation; +import java.util.Arrays; import java.util.Objects; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -14,8 +15,9 @@ public record ObfuscationRequest( WorldAccessor world, PlayerAccessor player, ChunkPacketAccessor packet, - @Nullable ChunkAccessor @Nullable [] neighborChunks) { + ChunkAccessor @Nullable [] neighborChunks) { + @SuppressWarnings("ConstantConditions") public ObfuscationRequest { Objects.requireNonNull(world); Objects.requireNonNull(player); @@ -23,6 +25,8 @@ public record ObfuscationRequest( if (neighborChunks != null && neighborChunks.length != 4) { throw new IllegalArgumentException("Expected 4 neighboring chunks but got " + neighborChunks.length); + } else if (neighborChunks != null && Arrays.stream(neighborChunks).anyMatch(Objects::isNull)) { + throw new IllegalArgumentException("Neighboring chunks must not be null"); } } @@ -35,7 +39,6 @@ public int getBlockState(int x, int y, int z) { ChunkDirection direction = ChunkDirection.fromPosition(packet, x, z); return neighborChunks[direction.ordinal()].getBlockState(x, y, z); } - return 0; } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java index e1d31be8..6f2285a2 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityRayCaster.java @@ -1,10 +1,13 @@ package dev.imprex.orebfuscator.proximity; +import dev.imprex.orebfuscator.interop.ChunkAccessor; import dev.imprex.orebfuscator.interop.RegistryAccessor; import dev.imprex.orebfuscator.interop.WorldAccessor; import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.EntityPose; import dev.imprex.orebfuscator.util.QuickMaths; +import java.util.Map; +import java.util.HashMap; public class ProximityRayCaster { @@ -12,6 +15,8 @@ public class ProximityRayCaster { private final WorldAccessor level; private final boolean onlyCheckCenter; + private final Map chunks = new HashMap<>(); + public ProximityRayCaster(RegistryAccessor registry, WorldAccessor level) { this.registry = registry; this.level = level; @@ -85,7 +90,7 @@ private boolean canRayPass(EntityPose origin, BlockPos target, double offsetX, d return true; } - int blockId = level.getBlockState(x, y, z); + int blockId = this.getBlockState(x, y, z); // fail on first hit, this ray is "blocked" if (registry.isOccluding(blockId)) { return false; @@ -94,4 +99,15 @@ private boolean canRayPass(EntityPose origin, BlockPos target, double offsetX, d return true; } + + private int getBlockState(int x, int y, int z) { + int chunkX = x >> 4; + int chunkZ = z >> 4; + + long key = ChunkAccessor.chunkCoordsToLong(chunkX, chunkZ); + + return chunks + .computeIfAbsent(key, k -> level.getChunkNow(chunkX, chunkZ)) + .getBlockState(x, y, z); + } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java index 41edc353..aea8a1aa 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximityWorker.java @@ -90,9 +90,9 @@ private void process(PlayerAccessor player) { int minChunkZ = (location.blockZ() - distance) >> 4; int maxChunkZ = (location.blockZ() + distance) >> 4; - ChunkAccessor playerChunk = world.getChunk(location.blockX() >> 4, location.blockZ() >> 4); + ChunkAccessor playerChunk = world.getChunkNow(location.blockX() >> 4, location.blockZ() >> 4); int eyeBlockId = playerChunk.getBlockState(location.blockX(), eyeLocation.blockY(), location.blockZ()); - boolean isInLava = eyeBlockId >= 0 && this.registry.isLava(eyeBlockId); + boolean isInLava = this.registry.isLava(eyeBlockId); double lavaDistance = player.lavaFogDistance(); double lavaDistanceSquared = lavaDistance * lavaDistance; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java index f6ed4e9b..2be8fbaa 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java @@ -38,21 +38,7 @@ public String debug() { .collect(Collectors.joining("\n")); } - public JsonObject json() { - JsonObject object = new JsonObject(); - - var entries = entries().stream() - .sorted(Comparator.comparing(Map.Entry::getKey)) - .toList(); - - for (var entry : entries) { - object.addProperty(entry.getKey(), entry.getValue()); - } - - return object; - } - - private List> entries() { + public List> entries() { var entries = new ArrayList>(); for (var source : sources.values()) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java index 35cdfa77..bf9b7ccb 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockTag.java @@ -9,8 +9,8 @@ public record BlockTag(NamespacedKey key, Set blocks) { public BlockTag(NamespacedKey key, Set blocks) { - this.key = key; - this.blocks = Collections.unmodifiableSet(blocks); + this.key = Objects.requireNonNull(key); + this.blocks = Collections.unmodifiableSet(Objects.requireNonNull(blocks)); } @Override 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 cde371db..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,18 +1,19 @@ package net.imprex.orebfuscator; -import java.lang.reflect.Constructor; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.jspecify.annotations.Nullable; 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.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 { @@ -52,44 +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 isLava(int blockId) { - return instance.isLava(blockId); - } - - public static boolean isOccluding(int blockId) { - return instance.isOccluding(blockId); - } - - public static boolean isBlockEntity(int blockId) { - return instance.isBlockEntity(blockId); - } - - public static ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - return instance.getChunkAccessor(world, chunkX, chunkZ); - } - - public static @Nullable ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ) { - return instance.tryGetChunkAccessor(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 91a29f20..325815ae 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,12 +1,5 @@ package net.imprex.orebfuscator.nms; -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; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import dev.imprex.orebfuscator.reflect.Reflector; import dev.imprex.orebfuscator.reflect.accessor.MethodAccessor; import dev.imprex.orebfuscator.util.BlockProperties; @@ -14,6 +7,12 @@ import dev.imprex.orebfuscator.util.BlockTag; 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 { @@ -110,9 +109,4 @@ public final boolean isOccluding(int id) { public final boolean isBlockEntity(int id) { return this.blockStates[id].isBlockEntity(); } - - @Override - public @Nullable ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ) { - throw new UnsupportedOperationException(); - } } 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 132814d0..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,24 +1,24 @@ package net.imprex.orebfuscator.nms; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.jspecify.annotations.Nullable; 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); - ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ); - - // TODO: change to getChunkNow, implement in each version and add use in deobfuscation worker - @Nullable ChunkAccessor tryGetChunkAccessor(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/util/MinecraftVersion.java b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java index 25dcbf1e..0b730e2f 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,15 +1,13 @@ 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 { 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 fd075f5c..00000000 --- a/orebfuscator-nms/orebfuscator-nms-v1_16_R1/src/main/java/net/imprex/orebfuscator/nms/v1_16_R1/NmsManager.java +++ /dev/null @@ -1,206 +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.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 net.imprex.orebfuscator.nms.AbstractNmsManager; -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()) - .withIsLava(block == Blocks.LAVA) - .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 ChunkAccessor getChunkAccessor(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 68664ff6..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 dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.server.v1_16_R1.Chunk; - -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - 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 e7cc4f1f..00000000 --- a/orebfuscator-nms/orebfuscator-nms-v1_16_R2/src/main/java/net/imprex/orebfuscator/nms/v1_16_R2/NmsManager.java +++ /dev/null @@ -1,210 +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 dev.imprex.orebfuscator.interop.ChunkAccessor; -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()) - .withIsLava(block == Blocks.LAVA) - .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 ChunkAccessor getChunkAccessor(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 d34605b8..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 dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.server.v1_16_R2.Chunk; - -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - 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 62% 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 e9a3fbf8..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 @@ -3,13 +3,7 @@ import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.server.v1_16_R3.Chunk; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - 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 4862bd91..212387ac 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 dev.imprex.orebfuscator.interop.ChunkAccessor; 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,7 +76,7 @@ private static EntityPlayer player(Player player) { public NmsManager() { super(Block.REGISTRY_ID.a()); - for (Map.Entry, Block> entry : IRegistry.BLOCK.d()) { + for (Entry, Block> entry : IRegistry.BLOCK.d()) { NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().a().toString()); Block block = entry.getValue(); @@ -115,33 +119,29 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(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); } @@ -157,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; } @@ -171,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..b7b22032 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,19 +1,17 @@ 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; public class RegionFileCache extends AbstractRegionFileCache { 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/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/DefaultChunkAccessor.java index 69e73457..8ed70d1d 100644 --- 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/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_17_R1; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int 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 ea496330..4f00bc42 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 dev.imprex.orebfuscator.interop.ChunkAccessor; 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) { @@ -113,25 +119,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(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 @@ -170,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/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/RegionFileCache.java index 7e2724c9..cd690fdf 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,19 +1,17 @@ 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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/DefaultChunkAccessor.java index 38519080..c5866dd2 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_18_R1; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int 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 cabfb642..0ace78d8 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 dev.imprex.orebfuscator.interop.ChunkAccessor; 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) { @@ -115,25 +121,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -171,7 +177,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java index a6a4b47a..0f281c55 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_18_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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/DefaultChunkAccessor.java index 8948f582..f3d48857 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_18_R2; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java index 3951a3a4..053b70f3 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java @@ -1,28 +1,27 @@ package net.imprex.orebfuscator.nms.v1_18_R2; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.comphenix.protocol.events.PacketContainer; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; @@ -39,15 +38,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) { @@ -112,25 +118,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -168,7 +174,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java index 4780508b..6e7052e0 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_18_R2; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/DefaultChunkAccessor.java index 37529a31..a05db925 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_19_R1; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java index f1438133..a587cf57 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_19_R1; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; 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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java index 89beb5f2..8d33cfaf 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_19_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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/DefaultChunkAccessor.java index a6f0f650..7c9339d4 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_19_R2; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java index e5fc5798..ac8a5c98 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_19_R2; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java index 202c568a..31a5502e 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_19_R2; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/DefaultChunkAccessor.java index dd41aca6..bd2462f3 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_19_R3; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java index 94dcf144..586f1514 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_19_R3; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java index 43f958d5..5a4029f8 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_19_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.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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/DefaultChunkAccessor.java index bd3d6d99..949eec8e 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R1; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java index 479c3e7b..e093c5a5 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_20_R1; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java index c9d9189a..8bb56666 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_20_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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/DefaultChunkAccessor.java index cd66cd63..eebb6b8e 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R2; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java index 987bf567..5c6fe9e0 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_20_R2; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java index 0f65e500..976e3457 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_20_R2; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/DefaultChunkAccessor.java index f747824a..b73a3f5a 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R3; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java index 3381cc75..2a721ada 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_20_R3; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java index 5c1a773e..137399cc 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_20_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.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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/DefaultChunkAccessor.java index af640a51..68ef374c 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_20_R4; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java index aa34a0a6..2f1684af 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_20_R4; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java index b7032b0e..b6cdd506 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_20_R4; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/DefaultChunkAccessor.java index 7613e16a..e70a6ef2 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R1; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java index 5b0235d1..d486f8d7 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java @@ -1,27 +1,26 @@ package net.imprex.orebfuscator.nms.v1_21_R1; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -111,25 +117,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.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).getChunkSource(); - 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 @@ -167,7 +173,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java index f3f23166..09bf2f8a 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_21_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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/DefaultChunkAccessor.java index 59de9739..6c62b108 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R2; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java index 780212aa..ba07f13e 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java @@ -1,26 +1,25 @@ package net.imprex.orebfuscator.nms.v1_21_R2; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -36,15 +35,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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -109,25 +115,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.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).getChunkSource(); - 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 @@ -165,7 +171,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java index 2ffe052e..e2741027 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_21_R2; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/DefaultChunkAccessor.java index 7c096175..aa1fbc39 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R3; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java index 62930138..29382eb1 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java @@ -1,26 +1,25 @@ package net.imprex.orebfuscator.nms.v1_21_R3; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -36,15 +35,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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -109,25 +115,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.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).getChunkSource(); - 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 @@ -165,7 +171,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java index 148f1a8e..42978b55 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_21_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.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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/DefaultChunkAccessor.java index 47de6fee..0e9e1a36 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R4; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java index 2625c0ac..994eee09 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java @@ -1,26 +1,25 @@ package net.imprex.orebfuscator.nms.v1_21_R4; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -36,15 +35,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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -109,25 +115,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.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).getChunkSource(); - 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 @@ -165,7 +171,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java index 011c5f4f..d467823d 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_21_R4; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/DefaultChunkAccessor.java index 29751811..1bfb23c3 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R5; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java index aad87cb2..fa93f999 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java @@ -1,26 +1,25 @@ package net.imprex.orebfuscator.nms.v1_21_R5; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -36,15 +35,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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -109,25 +115,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.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).getChunkSource(); - 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 @@ -165,7 +171,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java index 365fcb44..de9cdb62 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_21_R5; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/DefaultChunkAccessor.java index 52a3fa3b..3e611308 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R6; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java index f94eec73..7975d1ce 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java @@ -1,26 +1,25 @@ package net.imprex.orebfuscator.nms.v1_21_R6; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -36,15 +35,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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -109,25 +115,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.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).getChunkSource(); - 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 @@ -165,7 +171,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java index da91ac3b..3baa83c4 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_21_R6; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/DefaultChunkAccessor.java similarity index 50% rename from orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/ReadOnlyChunkWrapper.java rename to orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/DefaultChunkAccessor.java index ac486727..832d4552 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/ReadOnlyChunkWrapper.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/DefaultChunkAccessor.java @@ -1,15 +1,9 @@ package net.imprex.orebfuscator.nms.v1_21_R7; import dev.imprex.orebfuscator.interop.ChunkAccessor; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ChunkAccess; -public class ReadOnlyChunkWrapper implements ChunkAccessor { - - private final LevelChunk chunk; - - ReadOnlyChunkWrapper(LevelChunk chunk) { - this.chunk = chunk; - } +public record DefaultChunkAccessor(ChunkAccess chunk) implements ChunkAccessor { @Override public int getBlockState(int x, int y, int z) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java index fb90ae6b..bfe4bbf8 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java @@ -1,26 +1,25 @@ package net.imprex.orebfuscator.nms.v1_21_R7; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.World; -import org.bukkit.entity.Player; 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.Short2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.nms.AbstractNmsManager; -import dev.imprex.orebfuscator.interop.ChunkAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -36,15 +35,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.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +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) { @@ -109,32 +115,25 @@ public AbstractRegionFileCache createRegionFileCache(Config config) { } @Override - public ChunkAccessor getChunkAccessor(World world, int chunkX, int chunkZ) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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).getChunkSource() + .getChunkFuture(chunkX, chunkZ, ChunkStatus.FULL, true) + .thenApply(result -> { + var chunk = result.orElse(null); + return chunk != null ? new DefaultChunkAccessor(chunk) : null; + }); } @Override - public ChunkAccessor tryGetChunkAccessor(World world, int chunkX, int chunkZ) { + public @Nullable ChunkAccessor getChunkNow(World world, int chunkX, int chunkZ) { ServerChunkCache serverChunkCache = level(world).getChunkSource(); - LevelChunk chunk = serverChunkCache.getChunkNow(chunkX, chunkZ); - return chunk != null ? new ReadOnlyChunkWrapper(chunk) : null; - } - @Override - public int getBlockState(World world, int x, int y, int z) { - ServerChunkCache serverChunkCache = level(world).getChunkSource(); - 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 @@ -172,7 +171,10 @@ public void sendBlockUpdates(Player player, Iterable packet = blockEntity.getUpdatePacket(); + if (packet != null) { + blockEntityPackets.add(packet); + } } } } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java index be2fc633..a57cac6b 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java @@ -1,19 +1,17 @@ package net.imprex.orebfuscator.nms.v1_21_R7; +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; public class RegionFileCache extends AbstractRegionFileCache { diff --git a/orebfuscator-nms/pom.xml b/orebfuscator-nms/pom.xml index a3508500..3ef15021 100644 --- a/orebfuscator-nms/pom.xml +++ b/orebfuscator-nms/pom.xml @@ -14,8 +14,6 @@ orebfuscator-nms-api - orebfuscator-nms-v1_16_R1 - orebfuscator-nms-v1_16_R2 orebfuscator-nms-v1_16_R3 orebfuscator-nms-v1_17_R1 orebfuscator-nms-v1_18_R1 diff --git a/orebfuscator-plugin/pom.xml b/orebfuscator-plugin/pom.xml index faf9de80..2262b336 100644 --- a/orebfuscator-plugin/pom.xml +++ b/orebfuscator-plugin/pom.xml @@ -175,18 +175,6 @@ ${revision} compile - - net.imprex - orebfuscator-nms-v1_16_R1 - ${revision} - compile - - - net.imprex - orebfuscator-nms-v1_16_R2 - ${revision} - compile - net.imprex orebfuscator-nms-v1_16_R3 diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index da74c9ec..c777587b 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -1,18 +1,5 @@ package net.imprex.orebfuscator; -import java.nio.file.Path; -import java.util.List; -import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; -import net.imprex.orebfuscator.iterop.BukkitWorldAccessorManager; -import org.bukkit.Bukkit; -import org.bukkit.event.Event; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginEnableEvent; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.ServicePriority; -import org.bukkit.plugin.java.JavaPlugin; import dev.imprex.orebfuscator.UpdateSystem; import dev.imprex.orebfuscator.cache.AbstractRegionFileCache; import dev.imprex.orebfuscator.cache.ObfuscationCache; @@ -30,13 +17,24 @@ import dev.imprex.orebfuscator.statistics.StatisticsRegistry; import dev.imprex.orebfuscator.util.Version; import dev.imprex.orebfuscator.util.concurrent.OrebfuscatorExecutor; +import java.nio.file.Path; +import java.util.List; import net.imprex.orebfuscator.api.OrebfuscatorService; import net.imprex.orebfuscator.iterop.BukkitLoggerAccessor; -import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; -import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; +import net.imprex.orebfuscator.iterop.BukkitWorldAccessorManager; import net.imprex.orebfuscator.obfuscation.ObfuscationSystem; import net.imprex.orebfuscator.proximity.ProximityPacketListener; import net.imprex.orebfuscator.util.MinecraftVersion; +import org.bukkit.Bukkit; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; public class Orebfuscator extends JavaPlugin implements Listener, OrebfuscatorCore { @@ -164,10 +162,6 @@ public ObfuscationSystem getObfuscationSystem() { return obfuscationSystem; } - public StatisticsRegistry statisticsRegistry() { - return statisticsRegistry; - } - public BukkitWorldAccessorManager worldManager() { return worldManager; } @@ -181,6 +175,11 @@ public OrebfuscatorExecutor executor() { return executor; } + @Override + public StatisticsRegistry statisticsRegistry() { + return statisticsRegistry; + } + @Override public OrebfuscatorStatistics statistics() { return statistics; diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java index 1e5df7fb..2ee5e2ca 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java @@ -1,47 +1,26 @@ package net.imprex.orebfuscator; -import com.google.gson.JsonArray; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketListener; +import dev.imprex.orebfuscator.OrebfuscatorDumpFile; +import dev.imprex.orebfuscator.PermissionRequirements; import java.nio.file.Path; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.time.temporal.TemporalAccessor; -import java.util.Arrays; -import java.util.Base64; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; - +import net.imprex.orebfuscator.util.MinecraftVersion; +import net.imprex.orebfuscator.util.PermissionUtil; import org.bukkit.Bukkit; -import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; - -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.PacketListener; -import com.google.gson.JsonObject; -import com.google.gson.internal.Streams; -import com.google.gson.stream.JsonWriter; -import dev.imprex.orebfuscator.PermissionRequirements; -import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.util.JavaVersion; -import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; -import net.imprex.orebfuscator.util.MinecraftVersion; -import net.imprex.orebfuscator.util.PermissionUtil; +import org.jspecify.annotations.NonNull; public class OrebfuscatorCommand implements CommandExecutor, TabCompleter { - private static final List TAB_COMPLETE = Arrays.asList("dump"); - - private final DateTimeFormatter fileFormat = DateTimeFormatter.ofPattern("uuuu-MM-dd_HH.mm.ss"); - private final DateTimeFormatter timeFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + private static final List TAB_COMPLETE = List.of("dump"); private final Orebfuscator orebfuscator; @@ -50,7 +29,7 @@ public OrebfuscatorCommand(Orebfuscator orebfuscator) { } @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + public boolean onCommand(@NonNull CommandSender sender, Command command, @NonNull String label, String[] args) { if (!command.getName().equalsIgnoreCase("orebfuscator")) { sender.sendMessage("Incorrect command registered!"); return false; @@ -66,79 +45,32 @@ public boolean onCommand(CommandSender sender, Command command, String label, St "You are using %s %s".formatted(this.orebfuscator.name(), this.orebfuscator.orebfuscatorVersion())); sender.sendMessage(this.orebfuscator.statisticsRegistry().format()); } else if (args[0].equalsIgnoreCase("dump")) { - TemporalAccessor now = OffsetDateTime.now(ZoneOffset.UTC); - - JsonObject root = new JsonObject(); - root.addProperty("timestamp", timeFormat.format(now)); - - JsonObject versions = new JsonObject(); - versions.addProperty("java", Integer.toString(JavaVersion.get())); - versions.addProperty("nms", MinecraftVersion.nmsVersion()); - versions.addProperty("server", Bukkit.getVersion()); - versions.addProperty("bukkit", Bukkit.getBukkitVersion()); - versions.addProperty("protocolLib", ProtocolLibrary.getPlugin().toString()); - versions.addProperty("orebfuscator", orebfuscator.toString()); - root.add("versions", versions); + var dumpFile = new OrebfuscatorDumpFile(this.orebfuscator); - root.add("statistics", orebfuscator.statisticsRegistry().json()); + dumpFile.set("versions.nms", MinecraftVersion.nmsVersion()); + dumpFile.set("versions.server", Bukkit.getVersion()); + dumpFile.set("versions.bukkit", Bukkit.getBukkitVersion()); + dumpFile.set("versions.protocolLib", ProtocolLibrary.getPlugin().toString()); - JsonObject plugins = new JsonObject(); + var plugins = dumpFile.createSection("plugins"); for (Plugin bukkitPlugin : Bukkit.getPluginManager().getPlugins()) { PluginDescriptionFile description = bukkitPlugin.getDescription(); - JsonObject plugin = new JsonObject(); - plugin.addProperty("version", description.getVersion()); - plugin.addProperty("author", description.getAuthors().toString()); - plugins.add(bukkitPlugin.getName(), plugin); - } - root.add("plugins", plugins); - JsonArray worlds = new JsonArray(); - for (var accessor : orebfuscator.worldManager().all()) { - JsonObject world = new JsonObject(); - world.addProperty("name", accessor.name()); - world.addProperty("heightAccessor", accessor.toString()); - worlds.add(world); + var plugin = plugins.createSection(bukkitPlugin.getName()); + plugin.set("version", description.getVersion()); + plugin.set("author", description.getAuthors().toString()); } - root.add("worlds", worlds); - JsonObject listeners = new JsonObject(); + var listeners = dumpFile.createSection("listeners"); for (PacketListener packetListener : ProtocolLibrary.getProtocolManager().getPacketListeners()) { - JsonObject listener = new JsonObject(); - listener.addProperty("plugin", packetListener.getPlugin().toString()); - listener.addProperty("receivingWhitelist", packetListener.getSendingWhitelist().toString()); - listener.addProperty("sendingWhitelist", packetListener.getSendingWhitelist().toString()); - String key = packetListener.getClass().toGenericString() + "@" + System.identityHashCode(packetListener); - listeners.add(key, listener); - } - root.add("listeners", listeners); - - root.add("blocks", orebfuscator.config().toJson()); - - Base64.Encoder encoder = Base64.getUrlEncoder(); - - String latestLog = OfcLogger.getLatestVerboseLog(); - root.addProperty("verboseLog", encoder.encodeToString(latestLog.getBytes(StandardCharsets.UTF_8))); - - try { - Path configPath = orebfuscator.getDataFolder().toPath().resolve("config.yml"); - String config = Files.readAllLines(configPath).stream().collect(Collectors.joining("\n")); - root.addProperty("config", encoder.encodeToString(config.getBytes(StandardCharsets.UTF_8))); - } catch (IOException e) { - e.printStackTrace(); - } - - String configReport = orebfuscator.config().report(); - configReport = configReport != null ? configReport : ""; - root.addProperty("configReport", encoder.encodeToString(configReport.getBytes(StandardCharsets.UTF_8))); - - Path path = orebfuscator.getDataFolder().toPath().resolve("dump-" + fileFormat.format(now) + ".json"); - try (JsonWriter writer = new JsonWriter(Files.newBufferedWriter(path))) { - writer.setIndent(" "); - Streams.write(root, writer); - } catch (IOException e) { - e.printStackTrace(); + var listener = listeners.createSection( + packetListener.getClass().toGenericString() + "@" + System.identityHashCode(packetListener)); + listener.set("plugin", packetListener.getPlugin().toString()); + listener.set("receivingWhitelist", packetListener.getSendingWhitelist().toString()); + listener.set("sendingWhitelist", packetListener.getSendingWhitelist().toString()); } + Path path = dumpFile.write(); sender.sendMessage("Dump file created at: " + path); } else { return false; @@ -148,7 +80,8 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } @Override - public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + public List onTabComplete(@NonNull CommandSender sender, @NonNull Command command, @NonNull String alias, + String[] args) { return args.length == 1 ? TAB_COMPLETE : Collections.emptyList(); } } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java index 44974721..007d21f0 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitChunkPacketAccessor.java @@ -1,10 +1,5 @@ package net.imprex.orebfuscator.iterop; -import java.util.BitSet; -import java.util.Iterator; -import java.util.List; -import java.util.function.Predicate; -import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.nbt.NbtBase; @@ -12,8 +7,13 @@ import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; import dev.imprex.orebfuscator.obfuscation.ObfuscationResponse; import dev.imprex.orebfuscator.util.BlockPos; +import java.util.BitSet; +import java.util.Iterator; +import java.util.List; +import java.util.function.Predicate; import net.imprex.orebfuscator.util.MinecraftVersion; import net.imprex.orebfuscator.util.WrappedClientboundLevelChunkPacketData; +import org.jspecify.annotations.NullMarked; @NullMarked public class BukkitChunkPacketAccessor implements ChunkPacketAccessor { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java index 25a15f3f..74400da5 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitLoggerAccessor.java @@ -1,12 +1,12 @@ package net.imprex.orebfuscator.iterop; +import dev.imprex.orebfuscator.logging.LogLevel; +import dev.imprex.orebfuscator.logging.LoggerAccessor; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import dev.imprex.orebfuscator.logging.LogLevel; -import dev.imprex.orebfuscator.logging.LoggerAccessor; @NullMarked public record BukkitLoggerAccessor(Logger logger) implements LoggerAccessor { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java index 01dcc7ec..0a78d150 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java @@ -4,15 +4,16 @@ import com.comphenix.protocol.reflect.accessors.MethodAccessor; import dev.imprex.orebfuscator.config.api.WorldConfigBundle; import dev.imprex.orebfuscator.interop.ChunkAccessor; +import dev.imprex.orebfuscator.interop.ChunkPacketAccessor; import dev.imprex.orebfuscator.interop.WorldAccessor; import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.obfuscation.ObfuscationRequest; import dev.imprex.orebfuscator.util.BlockPos; import dev.imprex.orebfuscator.util.ChunkDirection; +import java.util.Arrays; import java.util.Objects; import java.util.concurrent.CompletableFuture; import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.OrebfuscatorNms; import net.imprex.orebfuscator.util.MinecraftVersion; import org.bukkit.World; @@ -126,33 +127,52 @@ public int sectionIndex(int y) { return blockToSectionCoord(y) - minSection(); } - public ChunkAccessor[] getNeighboringChunks(int chunkX, int chunkZ) { - ChunkAccessor[] neighboringChunks = new ChunkAccessor[4]; + public ChunkAccessor[] getNeighboringChunksNow(int chunkX, int chunkZ) { + final ChunkAccessor[] chunks = new ChunkAccessor[4]; for (ChunkDirection direction : ChunkDirection.values()) { int x = chunkX + direction.getOffsetX(); int z = chunkZ + direction.getOffsetZ(); - int index = direction.ordinal(); - - neighboringChunks[index] = OrebfuscatorNms.tryGetChunkAccessor(world, x, z); + chunks[direction.ordinal()] = getChunkNow(x, z); } - return neighboringChunks; + return chunks; } @Override + @SuppressWarnings("unchecked") public CompletableFuture getNeighboringChunks(ObfuscationRequest request) { - return OrebfuscatorCompatibility.getNeighboringChunks(world, request); - } + var neighborChunks = request.neighborChunks(); + if (neighborChunks != null && Arrays.stream(neighborChunks).noneMatch(ChunkAccessor::isNullOrEmpty)) { + return CompletableFuture.completedFuture(neighborChunks); + } - @Override - public ChunkAccessor getChunk(int chunkX, int chunkZ) { - return OrebfuscatorNms.getChunkAccessor(world, chunkX, chunkZ); + final ChunkPacketAccessor packet = request.packet(); + final CompletableFuture[] futures = (CompletableFuture[]) new CompletableFuture[4]; + + for (ChunkDirection direction : ChunkDirection.values()) { + int chunkX = packet.chunkX() + direction.getOffsetX(); + int chunkZ = packet.chunkZ() + direction.getOffsetZ(); + + int index = direction.ordinal(); + var chunk = neighborChunks != null ? neighborChunks[index] : null; + + if (ChunkAccessor.isNullOrEmpty(chunk)) { + futures[index] = OrebfuscatorNms.getChunkFuture(world, chunkX, chunkZ) + .thenApply(ChunkAccessor::ofNullable); + } else { + futures[index] = CompletableFuture.completedFuture(chunk); + } + } + + return CompletableFuture.allOf(futures).thenApply(v -> + Arrays.stream(futures).map(CompletableFuture::join).toArray(ChunkAccessor[]::new)); } @Override - public int getBlockState(int x, int y, int z) { - return OrebfuscatorNms.getBlockState(world, x, y, z); + public ChunkAccessor getChunkNow(int chunkX, int chunkZ) { + ChunkAccessor chunkAccessor = OrebfuscatorNms.getChunkNow(world, chunkX, chunkZ); + return ChunkAccessor.ofNullable(chunkAccessor); } @Override diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java index 4f54d807..f691181f 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/DeobfuscationListener.java @@ -1,5 +1,17 @@ package net.imprex.orebfuscator.obfuscation; +import dev.imprex.orebfuscator.PermissionRequirements; +import dev.imprex.orebfuscator.UpdateSystem; +import dev.imprex.orebfuscator.config.OrebfuscatorConfig; +import dev.imprex.orebfuscator.util.ConsoleUtil; +import net.imprex.orebfuscator.Orebfuscator; +import net.imprex.orebfuscator.OrebfuscatorCompatibility; +import net.imprex.orebfuscator.util.PermissionUtil; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -19,18 +31,6 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.jspecify.annotations.NullMarked; -import dev.imprex.orebfuscator.PermissionRequirements; -import dev.imprex.orebfuscator.UpdateSystem; -import dev.imprex.orebfuscator.config.OrebfuscatorConfig; -import dev.imprex.orebfuscator.util.ConsoleUtil; -import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.OrebfuscatorCompatibility; -import net.imprex.orebfuscator.util.PermissionUtil; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.ComponentBuilder; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.hover.content.Text; @NullMarked public class DeobfuscationListener implements Listener { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java index a1fe5734..248af419 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java @@ -1,12 +1,5 @@ package net.imprex.orebfuscator.obfuscation; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; -import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.AsynchronousManager; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -17,12 +10,18 @@ import dev.imprex.orebfuscator.logging.OfcLogger; import dev.imprex.orebfuscator.obfuscation.ObfuscationPipeline; import dev.imprex.orebfuscator.statistics.InjectorStatistics; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.OrebfuscatorCompatibility; import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.util.ServerVersion; +import org.jspecify.annotations.NullMarked; @NullMarked public class ObfuscationAsyncListener extends PacketAdapter { @@ -56,7 +55,6 @@ public class ObfuscationAsyncListener extends PacketAdapter { public ObfuscationAsyncListener(Orebfuscator orebfuscator) { super(orebfuscator, PACKET_TYPES.stream() - .filter(Objects::nonNull) .filter(PacketType::isSupported) .collect(Collectors.toList())); @@ -86,9 +84,9 @@ public void onPacketReceiving(PacketEvent event) { @Override public void onPacketSending(PacketEvent event) { PacketType type = event.getPacket().getType(); - if (type != PacketType.Play.Server.MAP_CHUNK && - type != PacketType.Play.Server.CHUNK_BATCH_START && - type != PacketType.Play.Server.CHUNK_BATCH_FINISHED) { + if (type != Server.MAP_CHUNK && + type != Server.CHUNK_BATCH_START && + type != Server.CHUNK_BATCH_FINISHED) { return; } @@ -102,9 +100,9 @@ public void onPacketSending(PacketEvent event) { return; } - if (type == PacketType.Play.Server.CHUNK_BATCH_START) { + if (type == Server.CHUNK_BATCH_START) { player.startBatch(asynchronousManager, event); - } else if (type == PacketType.Play.Server.CHUNK_BATCH_FINISHED) { + } else if (type == Server.CHUNK_BATCH_FINISHED) { player.finishBatch(); } else { var future = player.obfuscationFuture(event); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java index 7a6ed788..53d200fd 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSyncListener.java @@ -1,7 +1,5 @@ package net.imprex.orebfuscator.obfuscation; -import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; -import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; @@ -12,7 +10,9 @@ import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.iterop.BukkitChunkPacketAccessor; import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; +import org.jspecify.annotations.NullMarked; @NullMarked public class ObfuscationSyncListener extends PacketAdapter { @@ -53,7 +53,7 @@ public void onPacketSending(PacketEvent event) { return; } - var neighboringChunks = world.getNeighboringChunks(packet.chunkX(), packet.chunkZ()); + var neighboringChunks = world.getNeighboringChunksNow(packet.chunkX(), packet.chunkZ()); var future = pipeline.request(world, player, packet, neighboringChunks).toCompletableFuture(); player.obfuscationFuture(event, future); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java index 54bf7490..8aae36c1 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationSystem.java @@ -4,7 +4,6 @@ import dev.imprex.orebfuscator.util.BlockPos; import java.util.Collection; import net.imprex.orebfuscator.Orebfuscator; -import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.iterop.BukkitWorldAccessorManager; import org.bukkit.block.Block; import org.jspecify.annotations.NullMarked; diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java index e629731a..c04f6c5c 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/proximity/ProximityPacketListener.java @@ -1,7 +1,5 @@ package net.imprex.orebfuscator.proximity; -import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; -import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; @@ -15,8 +13,10 @@ import dev.imprex.orebfuscator.player.OrebfuscatorPlayer; import net.imprex.orebfuscator.Orebfuscator; import net.imprex.orebfuscator.iterop.BukkitPlayerAccessor; +import net.imprex.orebfuscator.iterop.BukkitPlayerAccessorManager; import net.imprex.orebfuscator.iterop.BukkitWorldAccessor; import net.imprex.orebfuscator.util.MinecraftVersion; +import org.jspecify.annotations.NullMarked; @NullMarked public class ProximityPacketListener extends PacketAdapter { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java index 5d33193f..e4f67300 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java @@ -1,7 +1,7 @@ package net.imprex.orebfuscator.util; -import org.bukkit.permissions.Permissible; import dev.imprex.orebfuscator.PermissionRequirements; +import org.bukkit.permissions.Permissible; import org.jspecify.annotations.NullMarked; @NullMarked diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java index 777d8c70..4ff7b254 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/WrappedClientboundLevelChunkPacketData.java @@ -1,14 +1,14 @@ package net.imprex.orebfuscator.util; -import java.util.Iterator; -import java.util.List; -import java.util.function.Predicate; -import org.jspecify.annotations.NullMarked; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.utility.MinecraftReflection; import dev.imprex.orebfuscator.util.BlockPos; +import java.util.Iterator; +import java.util.List; +import java.util.function.Predicate; +import org.jspecify.annotations.NullMarked; // TODO: replace all ProtocolLib reflections with own reflect lib @NullMarked From 43e88e3649e56313acb6c546002e436130cbcfba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sun, 1 Feb 2026 13:56:29 +0100 Subject: [PATCH 10/14] fix: compile errors --- .../obfuscation/ObfuscationAsyncListener.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java index 248af419..9deabef1 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/obfuscation/ObfuscationAsyncListener.java @@ -84,9 +84,9 @@ public void onPacketReceiving(PacketEvent event) { @Override public void onPacketSending(PacketEvent event) { PacketType type = event.getPacket().getType(); - if (type != Server.MAP_CHUNK && - type != Server.CHUNK_BATCH_START && - type != Server.CHUNK_BATCH_FINISHED) { + if (type != PacketType.Play.Server.MAP_CHUNK && + type != PacketType.Play.Server.CHUNK_BATCH_START && + type != PacketType.Play.Server.CHUNK_BATCH_FINISHED) { return; } @@ -100,9 +100,9 @@ public void onPacketSending(PacketEvent event) { return; } - if (type == Server.CHUNK_BATCH_START) { + if (type == PacketType.Play.Server.CHUNK_BATCH_START) { player.startBatch(asynchronousManager, event); - } else if (type == Server.CHUNK_BATCH_FINISHED) { + } else if (type == PacketType.Play.Server.CHUNK_BATCH_FINISHED) { player.finishBatch(); } else { var future = player.obfuscationFuture(event); From 136b7b8b92c5d57d7ae64952141c1e04c992608f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Fri, 6 Feb 2026 22:56:54 +0100 Subject: [PATCH 11/14] fix: minor bug in bukkit command chore: use new minecrat 26+ file structure for cache --- .../cache/CacheFileCleanupTask.java | 17 ++++++++++++++++- .../config/OrebfuscatorCacheConfig.java | 4 +++- .../orebfuscator/OrebfuscatorCommand.java | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java index e61324ec..38e59695 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/CacheFileCleanupTask.java @@ -4,12 +4,17 @@ import dev.imprex.orebfuscator.config.api.Config; import dev.imprex.orebfuscator.logging.OfcLogger; import java.io.IOException; +import java.nio.file.DirectoryNotEmptyException; import java.nio.file.FileVisitResult; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; @NullMarked public class CacheFileCleanupTask implements Runnable { @@ -45,7 +50,17 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) thro Files.delete(path); CacheFileCleanupTask.this.deleteCount++; - OfcLogger.debug("deleted cache file: " + path); + OfcLogger.debug("Deleted cache file: " + path); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, @Nullable IOException exc) throws IOException { + try { + Files.delete(dir); + } catch (NoSuchFileException | DirectoryNotEmptyException e) { + // NOOP; we don't care } return FileVisitResult.CONTINUE; } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java index 37f2033b..901615ea 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorCacheConfig.java @@ -1,6 +1,7 @@ package dev.imprex.orebfuscator.config; import java.io.IOException; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; @@ -147,7 +148,8 @@ public Path baseDirectory() { @Override public Path regionFile(ChunkCacheKey key) { - return this.baseDirectory.resolve(key.world().replace(":", "_")) + var separator = this.baseDirectory.getFileSystem().getSeparator(); + return this.baseDirectory.resolve(key.world().replace(":", separator)) .resolve("r." + (key.x() >> 5) + "." + (key.z() >> 5) + ".mca"); } diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java index 2ee5e2ca..065097b5 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java @@ -66,7 +66,7 @@ public boolean onCommand(@NonNull CommandSender sender, Command command, @NonNul var listener = listeners.createSection( packetListener.getClass().toGenericString() + "@" + System.identityHashCode(packetListener)); listener.set("plugin", packetListener.getPlugin().toString()); - listener.set("receivingWhitelist", packetListener.getSendingWhitelist().toString()); + listener.set("receivingWhitelist", packetListener.getReceivingWhitelist().toString()); listener.set("sendingWhitelist", packetListener.getSendingWhitelist().toString()); } From e0a26b8b1b6b6bc940fc3e20fc1c2326ecf9e88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sat, 7 Feb 2026 00:22:55 +0100 Subject: [PATCH 12/14] fix: Version parse/toString/compareTo/hashCode/equals --- .../dev/imprex/orebfuscator/UpdateSystem.java | 38 ++--- .../dev/imprex/orebfuscator/util/Version.java | 18 ++- .../imprex/orebfuscator/util/VersionTest.java | 131 ++++++++++++++++++ 3 files changed, 163 insertions(+), 24 deletions(-) create mode 100644 orebfuscator-core/src/test/java/dev/imprex/orebfuscator/util/VersionTest.java diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java index cbe0f8bc..8c7d6450 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/UpdateSystem.java @@ -1,5 +1,13 @@ package dev.imprex.orebfuscator; +import com.google.gson.annotations.SerializedName; +import dev.imprex.orebfuscator.config.api.GeneralConfig; +import dev.imprex.orebfuscator.interop.OrebfuscatorCore; +import dev.imprex.orebfuscator.logging.LogLevel; +import dev.imprex.orebfuscator.logging.OfcLogger; +import dev.imprex.orebfuscator.util.AbstractHttpService; +import dev.imprex.orebfuscator.util.ConsoleUtil; +import dev.imprex.orebfuscator.util.Version; import java.time.Duration; import java.time.Instant; import java.util.Arrays; @@ -13,23 +21,19 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jspecify.annotations.NullMarked; -import com.google.gson.annotations.SerializedName; -import dev.imprex.orebfuscator.config.api.GeneralConfig; -import dev.imprex.orebfuscator.interop.OrebfuscatorCore; -import dev.imprex.orebfuscator.logging.LogLevel; -import dev.imprex.orebfuscator.logging.OfcLogger; -import dev.imprex.orebfuscator.util.AbstractHttpService; -import dev.imprex.orebfuscator.util.ConsoleUtil; -import dev.imprex.orebfuscator.util.Version; import org.jspecify.annotations.Nullable; @NullMarked public class UpdateSystem extends AbstractHttpService { - private static final Pattern DEV_VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:-b(?\\d+))?"); + private static final Pattern DEV_VERSION_PATTERN = Pattern.compile("(?:-b(?\\d+))?"); + + private static boolean isDevVersion(Version version) { + if (version.suffix() == null) { + return false; + } - private static boolean isDevVersion(String version) { - Matcher matcher = DEV_VERSION_PATTERN.matcher(version); + Matcher matcher = DEV_VERSION_PATTERN.matcher(version.suffix()); return matcher.find() && matcher.group("build") != null; } @@ -59,27 +63,25 @@ public UpdateSystem(OrebfuscatorCore orebfuscator, String loader) { } private CompletableFuture> requestLatestVersion() { - String installedVersion = this.orebfuscator.orebfuscatorVersion().toString(); + Version installedVersion = this.orebfuscator.orebfuscatorVersion(); if (!this.generalConfig.checkForUpdates() || isDevVersion(installedVersion)) { OfcLogger.debug("UpdateSystem - Update check disabled or dev version detected; skipping"); return CompletableFuture.completedFuture(Optional.empty()); } - var uri = String.format(API_URI, this.loader, this.orebfuscator.minecraftVersion().toString()); + var uri = String.format(API_URI, this.loader, this.orebfuscator.minecraftVersion()); return HTTP.sendAsync(request(uri).build(), optionalJson(ModrinthVersion[].class)).thenApply(response -> response.body().flatMap(body -> { - var version = Version.parse(installedVersion); var latestVersion = Arrays.stream(body) .filter(e -> Objects.equals(e.versionType, "release")) .filter(e -> Objects.equals(e.status, "listed")) - .sorted(Comparator.reverseOrder()) - .findFirst(); + .max(Comparator.naturalOrder()); latestVersion.ifPresentOrElse( v -> OfcLogger.debug("UpdateSystem - Fetched latest version " + v.version), () -> OfcLogger.debug("UpdateSystem - Couldn't fetch latest version")); - return latestVersion.map(v -> version.isBelow(v.version) ? v : null); + return latestVersion.map(v -> installedVersion.isBelow(v.version) ? v : null); }) ).exceptionally(throwable -> { OfcLogger.log(LogLevel.WARN, "UpdateSystem - Unable to fetch latest version", throwable); @@ -134,7 +136,7 @@ private void checkForUpdates() { public static class ModrinthVersion implements Comparable { private static final Comparator COMPARATOR = - Comparator.comparing(e -> e.version, Comparator.nullsLast(Version::compareTo)); + Comparator.comparing(e -> e.version, Comparator.nullsFirst(Version::compareTo)); @SerializedName("version_number") public Version version; 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 c9a38dc7..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; @@ -15,7 +16,7 @@ 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) @@ -23,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(); @@ -86,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 @@ -102,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%s", this.major, this.minor, this.patch, this.suffix); + 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/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) { + } +} From cad04a693dc19cdf492e04ab10a80748f21d5ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sat, 7 Feb 2026 00:48:24 +0100 Subject: [PATCH 13/14] fix: nullability for region file cache --- .../imprex/orebfuscator/cache/AbstractRegionFileCache.java | 2 +- .../imprex/orebfuscator/nms/v1_16_R3/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_17_R1/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java | 5 ++++- .../imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java | 5 ++++- 19 files changed, 73 insertions(+), 19 deletions(-) diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java index 4edf76c5..2a8fcff4 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/cache/AbstractRegionFileCache.java @@ -72,7 +72,7 @@ private void remove(Map.Entry entry) { } } - protected final T get(Path path) throws IOException { + private T get(Path path) throws IOException { this.lock.readLock().lock(); try { T t = this.regionFiles.get(path); 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 b7b22032..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 @@ -12,7 +12,10 @@ 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) { @@ -31,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/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_17_R1/src/main/java/net/imprex/orebfuscator/nms/v1_17_R1/RegionFileCache.java index cd690fdf..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 @@ -12,7 +12,10 @@ 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) { @@ -31,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/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java index 0f281c55..d7b94a55 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R1/src/main/java/net/imprex/orebfuscator/nms/v1_18_R1/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java index 6e7052e0..94585d2b 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java index 8d33cfaf..68ee8543 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java index 31a5502e..96ae9c94 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java index 5a4029f8..e853aa94 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java index 8bb56666..8200ba7e 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java index 976e3457..f784d340 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java index 137399cc..a274cfff 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java index b6cdd506..cb71ffa8 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java index 09bf2f8a..b6f262d6 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java index e2741027..971c8b33 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java index 42978b55..b48ffbc7 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java index d467823d..d8799bba 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java index de9cdb62..447a01fa 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java index 3baa83c4..26c14f24 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java index a57cac6b..70c2b687 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/RegionFileCache.java @@ -12,7 +12,10 @@ 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) { @@ -31,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())); } From f1948fa5b7494c07dae9037452cf2d677ab2d6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sat, 7 Feb 2026 22:04:42 +0100 Subject: [PATCH 14/14] feat: resolve some PR comments --- .../config/OrebfuscatorAdvancedConfig.java | 43 ++--- .../config/OrebfuscatorConfig.java | 2 +- .../config/api/AdvancedConfig.java | 6 +- .../config/migrations/ConfigMigrationV5.java | 23 +++ .../config/migrations/ConfigMigrator.java | 1 + .../proximity/ProximitySystem.java | 2 +- .../AbstractExecutablePredicate.java | 32 ++-- .../statistics/CacheStatistics.java | 29 ++-- .../statistics/InjectorStatistics.java | 19 +-- .../statistics/ObfuscationStatistics.java | 19 +-- .../statistics/StatisticsRegistry.java | 11 +- .../statistics/StatisticsSource.java | 4 +- .../imprex/orebfuscator/util/BlockPos.java | 2 +- .../orebfuscator/util/BlockProperties.java | 3 +- .../orebfuscator/util/ChunkDirection.java | 19 --- .../imprex/orebfuscator/util/ConsoleUtil.java | 14 +- .../orebfuscator/util/NamespacedKey.java | 151 +++--------------- .../orebfuscator/util/RollingTimer.java | 6 +- .../util/concurrent/OrebfuscatorExecutor.java | 2 +- .../main/resources/config/config-1.16.0.yml | 6 +- .../main/resources/config/config-1.17.0.yml | 6 +- .../main/resources/config/config-1.18.0.yml | 6 +- .../main/resources/config/config-1.20.3.yml | 6 +- .../main/resources/config/config-1.21.9.yml | 6 +- .../orebfuscator/nms/AbstractNmsManager.java | 4 +- .../orebfuscator/util/MinecraftVersion.java | 12 +- .../orebfuscator/nms/v1_16_R3/NmsManager.java | 4 +- .../orebfuscator/nms/v1_17_R1/NmsManager.java | 4 +- .../orebfuscator/nms/v1_18_R1/NmsManager.java | 4 +- .../orebfuscator/nms/v1_18_R2/NmsManager.java | 4 +- .../orebfuscator/nms/v1_19_R1/NmsManager.java | 4 +- .../orebfuscator/nms/v1_19_R2/NmsManager.java | 4 +- .../orebfuscator/nms/v1_19_R3/NmsManager.java | 4 +- .../orebfuscator/nms/v1_20_R1/NmsManager.java | 4 +- .../orebfuscator/nms/v1_20_R2/NmsManager.java | 4 +- .../orebfuscator/nms/v1_20_R3/NmsManager.java | 4 +- .../orebfuscator/nms/v1_20_R4/NmsManager.java | 4 +- .../orebfuscator/nms/v1_21_R1/NmsManager.java | 4 +- .../orebfuscator/nms/v1_21_R2/NmsManager.java | 4 +- .../orebfuscator/nms/v1_21_R3/NmsManager.java | 4 +- .../orebfuscator/nms/v1_21_R4/NmsManager.java | 4 +- .../orebfuscator/nms/v1_21_R5/NmsManager.java | 4 +- .../orebfuscator/nms/v1_21_R6/NmsManager.java | 4 +- .../orebfuscator/nms/v1_21_R7/NmsManager.java | 4 +- .../imprex/orebfuscator/MetricsSystem.java | 9 +- .../net/imprex/orebfuscator/Orebfuscator.java | 4 +- .../iterop/BukkitWorldAccessor.java | 2 +- pom.xml | 4 - 48 files changed, 198 insertions(+), 327 deletions(-) create mode 100644 orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV5.java diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java index e5f03eaa..d4283a71 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorAdvancedConfig.java @@ -11,36 +11,30 @@ public class OrebfuscatorAdvancedConfig implements AdvancedConfig { private boolean verbose = false; + private int threads = -1; - private int obfuscationThreads = -1; private long obfuscationTimeout = 10_000L; - private int maxMillisecondsPerTick = 10; - private int proximityThreads = -1; private int proximityDefaultBucketSize = 50; private int proximityThreadCheckInterval = 50; private int proximityPlayerCheckInterval = 5000; - private boolean obfuscationThreadsSet = false; + private boolean hasThreads = false; private boolean hasObfuscationTimeout = false; - private boolean proximityThreadsSet = false; private boolean hasProximityPlayerCheckInterval = true; public void deserialize(ConfigurationSection section, ConfigParsingContext context) { this.verbose = section.getBoolean("verbose", false); + this.threads = section.getInt("threads", -1); + this.hasThreads = (this.threads > 0); + // parse obfuscation section ConfigParsingContext obfuscationContext = context.section("obfuscation"); ConfigurationSection obfuscationSection = section.getSection("obfuscation"); if (obfuscationSection != null) { - this.obfuscationThreads = obfuscationSection.getInt("threads", -1); - this.obfuscationThreadsSet = (this.obfuscationThreads > 0); - this.obfuscationTimeout = obfuscationSection.getLong("timeout", 10_000L); this.hasObfuscationTimeout = (this.obfuscationTimeout > 0); - - this.maxMillisecondsPerTick = obfuscationSection.getInt("maxMillisecondsPerTick", 10); - obfuscationContext.errorMinMaxValue("maxMillisecondsPerTick", 1, 50, this.maxMillisecondsPerTick); } else { obfuscationContext.warn(ConfigMessage.MISSING_USING_DEFAULTS); } @@ -49,9 +43,6 @@ public void deserialize(ConfigurationSection section, ConfigParsingContext conte ConfigParsingContext proximityContext = context.section("proximity"); ConfigurationSection proximitySection = section.getSection("proximity"); if (proximitySection != null) { - this.proximityThreads = proximitySection.getInt("threads", -1); - this.proximityThreadsSet = (this.proximityThreads > 0); - this.proximityDefaultBucketSize = proximitySection.getInt("defaultBucketSize", 50); proximityContext.errorMinValue("defaultBucketSize", 1, this.proximityDefaultBucketSize); @@ -65,22 +56,18 @@ public void deserialize(ConfigurationSection section, ConfigParsingContext conte } int availableThreads = Runtime.getRuntime().availableProcessors(); - this.obfuscationThreads = obfuscationThreadsSet ? obfuscationThreads : availableThreads; - this.proximityThreads = (int) (proximityThreadsSet ? proximityThreads : Math.ceil(availableThreads / 2f)); + this.threads = hasThreads ? threads : availableThreads; OfcLogger.setVerboseLogging(this.verbose); - OfcLogger.debug("advanced.obfuscationThreads = " + this.obfuscationThreads); - OfcLogger.debug("advanced.proximityThreads = " + this.proximityThreads); + OfcLogger.debug("advanced.threads = " + this.threads); } public void serialize(ConfigurationSection section) { section.set("verbose", this.verbose); + section.set("threads", this.hasThreads ? this.threads : -1); - section.set("obfuscation.threads", this.obfuscationThreadsSet ? this.obfuscationThreads : -1); section.set("obfuscation.timeout", this.hasObfuscationTimeout ? this.obfuscationTimeout : -1); - section.set("obfuscation.maxMillisecondsPerTick", this.maxMillisecondsPerTick); - section.set("proximity.threads", this.proximityThreadsSet ? this.proximityThreads : -1); section.set("proximity.defaultBucketSize", this.proximityDefaultBucketSize); section.set("proximity.threadCheckInterval", this.proximityThreadCheckInterval); section.set("proximity.playerCheckInterval", @@ -88,8 +75,8 @@ public void serialize(ConfigurationSection section) { } @Override - public int obfuscationThreads() { - return this.obfuscationThreads; + public int threads() { + return this.threads; } @Override @@ -102,16 +89,6 @@ public long obfuscationTimeout() { return this.obfuscationTimeout; } - @Override - public int maxMillisecondsPerTick() { - return this.maxMillisecondsPerTick; - } - - @Override - public int proximityThreads() { - return this.proximityThreads; - } - @Override public int proximityDefaultBucketSize() { return this.proximityDefaultBucketSize; diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java index 839e52f1..53789ec5 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/OrebfuscatorConfig.java @@ -43,7 +43,7 @@ @NullMarked public class OrebfuscatorConfig implements Config { - private static final int CONFIG_VERSION = 5; + private static final int CONFIG_VERSION = 6; private final OrebfuscatorGeneralConfig generalConfig = new OrebfuscatorGeneralConfig(); private final OrebfuscatorAdvancedConfig advancedConfig = new OrebfuscatorAdvancedConfig(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java index 83035c4b..b559a1d2 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/api/AdvancedConfig.java @@ -5,16 +5,12 @@ @NullMarked public interface AdvancedConfig { - int obfuscationThreads(); + int threads(); boolean hasObfuscationTimeout(); long obfuscationTimeout(); - int maxMillisecondsPerTick(); - - int proximityThreads(); - int proximityDefaultBucketSize(); int proximityThreadCheckInterval(); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV5.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV5.java new file mode 100644 index 00000000..dda68643 --- /dev/null +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrationV5.java @@ -0,0 +1,23 @@ +package dev.imprex.orebfuscator.config.migrations; + +import dev.imprex.orebfuscator.config.yaml.ConfigurationSection; +import java.util.List; +import java.util.Map; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class ConfigMigrationV5 implements ConfigMigration { + + @Override + public int sourceVersion() { + return 5; + } + + @Override + public ConfigurationSection migrate(ConfigurationSection root) { + ConfigMigration.migrateNames(root.getSection("advanced"), List.of( + Map.entry("obfuscation.threads", "threads") + )); + return root; + } +} diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java index 7474b6ca..79bf0fe4 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/config/migrations/ConfigMigrator.java @@ -17,6 +17,7 @@ public class ConfigMigrator { register(new ConfigMigrationV2()); register(new ConfigMigrationV3()); register(new ConfigMigrationV4()); + register(new ConfigMigrationV5()); } private static void register(ConfigMigration migration) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java index 82e0d5f8..54fc5e8a 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/proximity/ProximitySystem.java @@ -30,7 +30,7 @@ public ProximitySystem(OrebfuscatorCore orebfuscator) { this.executor = orebfuscator.executor(); AdvancedConfig advancedConfig = orebfuscator.config().advanced(); - this.workerCount = advancedConfig.proximityThreads(); + this.workerCount = advancedConfig.threads(); this.defaultBucketSize = advancedConfig.proximityDefaultBucketSize(); this.checkInterval = TimeUnit.MILLISECONDS.toNanos(advancedConfig.proximityThreadCheckInterval()); diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java index 2e221be7..b9546bc3 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/reflect/predicate/AbstractExecutablePredicate.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.OptionalInt; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -95,7 +96,7 @@ public TThis parameterCount(int parameterCount) { return instance(); } - private record IndexedClassMatcher(ClassPredicate matcher, @Nullable Integer index) implements + private record IndexedClassMatcher(ClassPredicate matcher, OptionalInt index) implements Comparable { private static boolean all(Class[] classArray, List classMatchers) { @@ -103,47 +104,50 @@ private static boolean all(Class[] classArray, List clas } private static String toString(List classMatchers) { - return classMatchers.stream() - .sorted() - .map(IndexedClassMatcher::toString) + return classMatchers.stream().sorted().map(IndexedClassMatcher::toString) .collect(Collectors.joining(",\n ", "{\n ", "\n }")); } public IndexedClassMatcher(ClassPredicate matcher) { - this(matcher, null); + this(matcher, OptionalInt.empty()); + } + + public IndexedClassMatcher(ClassPredicate matcher, int index) { + this(matcher, OptionalInt.of(index)); } public boolean matches(Class[] classArray) { - if (index() == null) { + if (index.isEmpty()) { for (Class entry : classArray) { - if (matcher().test(entry)) { + if (matcher.test(entry)) { return true; } } return false; } - return index() < classArray.length && matcher().test(classArray[index()]); + int i = index.getAsInt(); + return i < classArray.length && matcher.test(classArray[i]); } @Override public int compareTo(IndexedClassMatcher other) { - if (this.index == null && other.index == null) { + if (this.index.isEmpty() && other.index.isEmpty()) { return 0; } - if (this.index == null) { + if (this.index.isEmpty()) { return -1; } - if (other.index == null) { + if (other.index.isEmpty()) { return 1; } - return this.index.compareTo(other.index); + return Integer.compare(this.index.getAsInt(), other.index.getAsInt()); } @Override public String toString() { - String key = index() == null ? "" : index().toString(); - return String.format("%s=%s", key, matcher().requirement()); + String key = index.isEmpty() ? "" : Integer.toString(index.getAsInt()); + return String.format("%s=%s", key, matcher.requirement()); } } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java index c6b1addc..c6ac8c3d 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/CacheStatistics.java @@ -5,6 +5,7 @@ import java.util.StringJoiner; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.LongSupplier; import dev.imprex.orebfuscator.config.api.CacheConfig; @@ -131,19 +132,19 @@ public void add(StringJoiner joiner) { } @Override - public void debug(Consumer> consumer) { - consumer.accept(Map.entry("cacheHitCountMemory", Long.toString(cacheHitCountMemory.get()))); - consumer.accept(Map.entry("cacheHitCountDisk", Long.toString(cacheHitCountDisk.get()))); - consumer.accept(Map.entry("cacheMissCount", Long.toString(cacheMissCount.get()))); - - consumer.accept(Map.entry("memoryCacheByteSize", Long.toString(memoryCacheByteSize.get()))); - consumer.accept(Map.entry("memoryCacheEntryCount", Long.toString(memoryCacheEntryCount.getAsLong()))); - - consumer.accept(Map.entry("diskCacheQueueLength", Long.toString(diskCacheQueueLength.getAsLong()))); - consumer.accept(Map.entry("diskCacheReadBytes", diskCacheReadBytes.debugLong(this::bytes))); - consumer.accept(Map.entry("diskCacheWriteBytes", diskCacheWriteBytes.debugLong(this::bytes))); - consumer.accept(Map.entry("diskCacheWaitTime", diskCacheWaitTime.debugLong(this::time))); - consumer.accept(Map.entry("diskCacheReadTime", diskCacheReadTime.debugLong(this::time))); - consumer.accept(Map.entry("diskCacheWriteTime", diskCacheWriteTime.debugLong(this::time))); + public void debug(BiConsumer consumer) { + consumer.accept("cacheHitCountMemory", Long.toString(cacheHitCountMemory.get())); + consumer.accept("cacheHitCountDisk", Long.toString(cacheHitCountDisk.get())); + consumer.accept("cacheMissCount", Long.toString(cacheMissCount.get())); + + consumer.accept("memoryCacheByteSize", Long.toString(memoryCacheByteSize.get())); + consumer.accept("memoryCacheEntryCount", Long.toString(memoryCacheEntryCount.getAsLong())); + + consumer.accept("diskCacheQueueLength", Long.toString(diskCacheQueueLength.getAsLong())); + consumer.accept("diskCacheReadBytes", diskCacheReadBytes.debugLong(this::bytes)); + consumer.accept("diskCacheWriteBytes", diskCacheWriteBytes.debugLong(this::bytes)); + consumer.accept("diskCacheWaitTime", diskCacheWaitTime.debugLong(this::time)); + consumer.accept("diskCacheReadTime", diskCacheReadTime.debugLong(this::time)); + consumer.accept("diskCacheWriteTime", diskCacheWriteTime.debugLong(this::time)); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java index 76b10a91..786b0586 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/InjectorStatistics.java @@ -2,6 +2,7 @@ import java.util.Map; import java.util.StringJoiner; +import java.util.function.BiConsumer; import java.util.function.Consumer; import dev.imprex.orebfuscator.util.RollingAverage; import dev.imprex.orebfuscator.util.RollingTimer; @@ -43,16 +44,16 @@ public void add(StringJoiner joiner) { } @Override - public void debug(Consumer> consumer) { - consumer.accept(Map.entry("pipelineDelayTotal", this.pipelineDelayTotal.debugLong(this::time))); - consumer.accept(Map.entry("pipelineDelayCache", this.pipelineDelayCache.debugLong(this::time))); - consumer.accept(Map.entry("pipelineDelayNeighbors", this.pipelineDelayNeighbors.debugLong(this::time))); - consumer.accept(Map.entry("pipelineDelayProcessor", this.pipelineDelayProcessor.debugLong(this::time))); + public void debug(BiConsumer consumer) { + consumer.accept("pipelineDelayTotal", this.pipelineDelayTotal.debugLong(this::time)); + consumer.accept("pipelineDelayCache", this.pipelineDelayCache.debugLong(this::time)); + consumer.accept("pipelineDelayNeighbors", this.pipelineDelayNeighbors.debugLong(this::time)); + consumer.accept("pipelineDelayProcessor", this.pipelineDelayProcessor.debugLong(this::time)); - consumer.accept(Map.entry("injectorDelaySync", this.injectorDelaySync.debugLong(this::time))); - consumer.accept(Map.entry("injectorBatchSize", this.injectorBatchSize.debugLong(this::time))); + consumer.accept("injectorDelaySync", this.injectorDelaySync.debugLong(this::time)); + consumer.accept("injectorBatchSize", this.injectorBatchSize.debugLong(this::time)); - consumer.accept(Map.entry("packetDelayAny", this.packetDelayAny.debugLong(this::time))); - consumer.accept(Map.entry("packetDelayChunk", this.packetDelayChunk.debugLong(this::time))); + consumer.accept("packetDelayAny", this.packetDelayAny.debugLong(this::time)); + consumer.accept("packetDelayChunk", this.packetDelayChunk.debugLong(this::time)); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java index cd19abaf..623bfc0a 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/ObfuscationStatistics.java @@ -2,6 +2,7 @@ import java.util.Map; import java.util.StringJoiner; +import java.util.function.BiConsumer; import java.util.function.Consumer; import dev.imprex.orebfuscator.util.RollingAverage; import dev.imprex.orebfuscator.util.RollingTimer; @@ -64,18 +65,18 @@ public void add(StringJoiner joiner) { } @Override - public void debug(Consumer> consumer) { - consumer.accept(Map.entry("debofuscation", this.debofuscation.debugLong(this::time))); + public void debug(BiConsumer consumer) { + consumer.accept("debofuscation", this.debofuscation.debugLong(this::time)); - consumer.accept(Map.entry("executorWaitTime", this.executorWaitTime.debugLong(this::time))); - consumer.accept(Map.entry("executorUtilization", this.executorUtilization.debugDouble(this::percent))); + consumer.accept("executorWaitTime", this.executorWaitTime.debugLong(this::time)); + consumer.accept("executorUtilization", this.executorUtilization.debugDouble(this::percent)); - consumer.accept(Map.entry("proximityWait", this.proximityWait.debugLong(this::time))); - consumer.accept(Map.entry("proximityProcess", this.proximityProcess.debugDouble(this::percent))); + consumer.accept("proximityWait", this.proximityWait.debugLong(this::time)); + consumer.accept("proximityProcess", this.proximityProcess.debugDouble(this::percent)); - consumer.accept(Map.entry("missingNeighboringChunks", this.missingNeighboringChunks.debugDouble(this::faction))); + consumer.accept("missingNeighboringChunks", this.missingNeighboringChunks.debugDouble(this::faction)); - consumer.accept(Map.entry("originalChunkSize", this.originalChunkSize.debugLong(this::bytes))); - consumer.accept(Map.entry("obfuscatedChunkSize", this.obfuscatedChunkSize.debugLong(this::bytes))); + consumer.accept("originalChunkSize", this.originalChunkSize.debugLong(this::bytes)); + consumer.accept("obfuscatedChunkSize", this.obfuscatedChunkSize.debugLong(this::bytes)); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java index 2be8fbaa..29cf9fcd 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsRegistry.java @@ -3,8 +3,11 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; import com.google.gson.JsonObject; @@ -38,13 +41,13 @@ public String debug() { .collect(Collectors.joining("\n")); } - public List> entries() { - var entries = new ArrayList>(); + public Set> entries() { + var entries = new LinkedHashMap(); for (var source : sources.values()) { - source.debug(entries::add); + source.debug(entries::put); } - return entries; + return entries.entrySet(); } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java index e29b703d..6288f966 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/statistics/StatisticsSource.java @@ -1,7 +1,9 @@ package dev.imprex.orebfuscator.statistics; import java.util.Map; +import java.util.Map.Entry; import java.util.StringJoiner; +import java.util.function.BiConsumer; import java.util.function.Consumer; public interface StatisticsSource { @@ -38,5 +40,5 @@ default String bytes(long bytes) { void add(StringJoiner joiner); - void debug(Consumer> consumer); + void debug(BiConsumer consumer); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java index 63ff370b..c1337add 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockPos.java @@ -50,7 +50,7 @@ public static BlockPos fromLong(long value) { } public int toSectionPos() { - return (this.x & 0xF) << 12 | (this.y & 0xFFF) << 0 | (this.z & 0xF) << 16; + return (this.x & 0xF) << 12 | (this.y & 0xFFF) | (this.z & 0xF) << 16; } public static BlockPos fromSectionPos(int x, int z, int sectionPos) { diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java index a6a72da1..667e3479 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/BlockProperties.java @@ -20,8 +20,7 @@ public static Builder builder(NamespacedKey key) { private BlockProperties(Builder builder) { this.key = builder.key; - assert builder.defaultBlockState != null; - this.defaultBlockState = builder.defaultBlockState; + this.defaultBlockState = Objects.requireNonNull(builder.defaultBlockState); this.blockStates = ImmutableList.copyOf(builder.blockStates); } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java index 0a109a87..eab3c852 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ChunkDirection.java @@ -44,23 +44,4 @@ public static ChunkDirection fromPosition(ChunkPacketAccessor packetAccessor, in throw new IllegalArgumentException(String.format("invalid offset (chunkX: %d, chunkZ: %d, x: %d, z: %d)", packetAccessor.chunkX(), packetAccessor.chunkZ(), targetX, targetZ)); } - - @Deprecated - public static ChunkDirection fromPosition(ChunkCacheKey key, int targetX, int targetZ) { - int offsetX = (targetX >> 4) - key.x(); - int offsetZ = (targetZ >> 4) - key.z(); - - if (offsetX == 1 && offsetZ == 0) { - return NORTH; - } else if (offsetX == 0 && offsetZ == 1) { - return EAST; - } else if (offsetX == -1 && offsetZ == 0) { - return SOUTH; - } else if (offsetX == 0 && offsetZ == -1) { - return WEST; - } - - throw new IllegalArgumentException( - String.format("invalid offset (origin: %s, x: %d, z: %d)", key, targetX, targetZ)); - } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ConsoleUtil.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ConsoleUtil.java index 6ae4372c..7fc58d0f 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ConsoleUtil.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/ConsoleUtil.java @@ -73,7 +73,7 @@ public static Iterable createBox(String... lines) { int totalWidth = width + BOX_PADDING * 2; // create top/bottom lines - String bottomTopLine = repeat('-', totalWidth); + String bottomTopLine = "-".repeat(totalWidth); String topLine = String.format("+%s+", bottomTopLine); String bottomLine = String.format("+%s+", bottomTopLine); @@ -87,10 +87,10 @@ public static Iterable createBox(String... lines) { // center line String leftPadding, rightPadding; if (space % 2 == 0) { - leftPadding = rightPadding = repeat(' ', space / 2); + leftPadding = rightPadding = " ".repeat(space / 2); } else { - leftPadding = repeat(' ', space / 2 + 1); - rightPadding = repeat(' ', space / 2); + leftPadding = " ".repeat(space / 2 + 1); + rightPadding = " ".repeat(space / 2); } box.add(String.format("|%s%s%s|", leftPadding, line, rightPadding)); @@ -99,10 +99,4 @@ public static Iterable createBox(String... lines) { box.add(bottomLine); return box; } - - private static String repeat(char character, int length) { - char[] string = new char[length]; - Arrays.fill(string, character); - return new String(string); - } } diff --git a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java index 094b9f1c..2770a075 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/NamespacedKey.java @@ -1,7 +1,10 @@ package dev.imprex.orebfuscator.util; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; /** * Represents a String based key which consists of two components - a namespace and a key. @@ -17,147 +20,45 @@ @NullMarked public record NamespacedKey(String namespace, String key) { - /** - * The namespace representing all inbuilt keys. - */ - public static final String MINECRAFT = "minecraft"; + private static final String DEFAULT_NAMESPACE = "minecraft"; - private static boolean isValidNamespaceChar(char c) { - return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-'; - } + private static final Pattern PARSE = Pattern.compile("^(?:(?[a-z0-9._-]+):)?(?[a-z0-9/._-]+)$"); + private static final Predicate VALID_NAMESPACE = Pattern.compile("^[a-z0-9._-]+$").asMatchPredicate(); + private static final Predicate VALID_KEY = Pattern.compile("^[a-z0-9/._-]+$").asMatchPredicate(); - private static boolean isValidKeyChar(char c) { - return isValidNamespaceChar(c) || c == '/'; + public static NamespacedKey parse(String value) { + return tryParse(value).orElseThrow(() -> new IllegalArgumentException( + "Invalid namespaced key. Must be /^([a-z0-9._-]+:)?[a-z0-9/._-]+$/: %s".formatted(value))); } - private static boolean isInvalidNamespace(@Nullable String namespace) { - if (namespace == null) { - return true; + public static Optional tryParse(String value) { + Matcher matcher = PARSE.matcher(value); + if (!matcher.find()) { + return Optional.empty(); } - int len = namespace.length(); - if (len == 0) { - return true; - } + String namespace = matcher.group("namespace"); + String key = matcher.group("key"); - for (int i = 0; i < len; i++) { - if (!isValidNamespaceChar(namespace.charAt(i))) { - return true; - } + if ("..".equals(namespace)) { + return Optional.empty(); } - return false; + return Optional.of(new NamespacedKey(namespace == null ? DEFAULT_NAMESPACE : namespace, key)); } - private static boolean isInvalidKey(@Nullable String key) { - if (key == null) { - return true; - } - - int len = key.length(); - if (len == 0) { - return true; - } - - for (int i = 0; i < len; i++) { - if (!isValidKeyChar(key.charAt(i))) { - return true; - } - } - - return false; - } - - /** - * 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 (isInvalidNamespace(namespace)) { - throw new IllegalArgumentException(String.format("Invalid namespace. Must be [a-z0-9._-]: %s", namespace)); - } else if (isInvalidKey(key)) { - throw new IllegalArgumentException(String.format("Invalid key. Must be [a-z0-9/._-]: %s", key)); - } - - 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)); - } - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; + @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)); } - if (getClass() != obj.getClass()) { - return false; + if (key == null || !VALID_KEY.test(key)) { + throw new IllegalArgumentException("Invalid key. Must be [a-z0-9/._-]: %s".formatted(key)); } - 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 @Nullable NamespacedKey fromString(String string) { - if (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() || isInvalidKey(value)) { - return null; - } - - return minecraft(value); - } else if (components.length == 2 && isInvalidKey(key)) { - return null; - } - - String namespace = components[0]; - if (namespace.isEmpty()) { - return minecraft(key); - } - - if (isInvalidNamespace(namespace)) { - return null; - } - - return new NamespacedKey(namespace, key); - } } 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 index 7771caa5..e4406d39 100644 --- a/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java +++ b/orebfuscator-core/src/main/java/dev/imprex/orebfuscator/util/RollingTimer.java @@ -1,6 +1,7 @@ package dev.imprex.orebfuscator.util; import java.util.concurrent.CompletionStage; +import java.util.concurrent.atomic.AtomicBoolean; import org.jspecify.annotations.NullMarked; @NullMarked @@ -17,7 +18,7 @@ public Instance start() { public class Instance { private final long time = System.nanoTime(); - private boolean running = true; + private final AtomicBoolean running = new AtomicBoolean(true); private Instance() { } @@ -27,9 +28,8 @@ public CompletionStage wrap(CompletionStage completionStage) { } public void stop() { - if (running) { + if (this.running.compareAndSet(true, false)) { add(System.nanoTime() - time); - running = false; } } } 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 index 150b7d38..d09fa587 100644 --- 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 @@ -29,7 +29,7 @@ public class OrebfuscatorExecutor implements Executor { public OrebfuscatorExecutor(OrebfuscatorCore orebfuscator) { this.statistics = orebfuscator.statistics(); - this.poolSize = orebfuscator.config().advanced().obfuscationThreads(); + this.poolSize = orebfuscator.config().advanced().threads(); this.executorService = Executors.newFixedThreadPool(this.poolSize, OrebfuscatorThread::new); this.scheduledExecutorService.scheduleAtFixedRate(this::updateStatistics, 1L, 1L, TimeUnit.SECONDS); 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-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 325815ae..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 @@ -82,12 +82,12 @@ public final int getMaxBitsPerBlockState() { @Override public final @Nullable BlockProperties getBlockByName(String name) { - return this.blocks.get(NamespacedKey.fromString(name)); + return NamespacedKey.tryParse(name).map(this.blocks::get).orElse(null); } @Override public final @Nullable BlockTag getBlockTagByName(String name) { - return this.tags.get(NamespacedKey.fromString(name)); + return NamespacedKey.tryParse(name).map(this.tags::get).orElse(null); } @Override 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 0b730e2f..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 @@ -10,7 +10,7 @@ public final class MinecraftVersion { - private static final class NmsMapping { + private record NmsMapping(Version version, String nmsVersion) { private static final List MAPPINGS = new ArrayList<>(); @@ -40,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_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 212387ac..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 @@ -77,7 +77,7 @@ public NmsManager() { super(Block.REGISTRY_ID.a()); for (Entry, Block> entry : IRegistry.BLOCK.d()) { - NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().a().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(entry.getKey().a().toString()); Block block = entry.getValue(); ImmutableList possibleBlockStates = block.getStates().a(); @@ -99,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()) { 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 4f00bc42..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 @@ -77,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(); @@ -99,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()) { 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 0ace78d8..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 @@ -79,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 possibleBlockStates = block.getStateDefinition().getPossibleStates(); @@ -101,7 +101,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()) { diff --git a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java index 053b70f3..e25fdd72 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_18_R2/src/main/java/net/imprex/orebfuscator/nms/v1_18_R2/NmsManager.java @@ -78,7 +78,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(); @@ -100,7 +100,7 @@ public NmsManager() { } Registry.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java index a587cf57..686de3b0 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R1/src/main/java/net/imprex/orebfuscator/nms/v1_19_R1/NmsManager.java @@ -77,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(); @@ -99,7 +99,7 @@ public NmsManager() { } Registry.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java index ac8a5c98..87766e48 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R2/src/main/java/net/imprex/orebfuscator/nms/v1_19_R2/NmsManager.java @@ -77,7 +77,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -99,7 +99,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java index 586f1514..f660b6d4 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_19_R3/src/main/java/net/imprex/orebfuscator/nms/v1_19_R3/NmsManager.java @@ -77,7 +77,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -99,7 +99,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java index e093c5a5..7833682b 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R1/src/main/java/net/imprex/orebfuscator/nms/v1_20_R1/NmsManager.java @@ -77,7 +77,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -99,7 +99,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java index 5c6fe9e0..43160198 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R2/src/main/java/net/imprex/orebfuscator/nms/v1_20_R2/NmsManager.java @@ -77,7 +77,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -99,7 +99,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java index 2a721ada..5ea95c77 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R3/src/main/java/net/imprex/orebfuscator/nms/v1_20_R3/NmsManager.java @@ -77,7 +77,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -99,7 +99,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java index 2f1684af..d05090f4 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java @@ -77,7 +77,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -99,7 +99,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java index d486f8d7..efa10a96 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R1/src/main/java/net/imprex/orebfuscator/nms/v1_21_R1/NmsManager.java @@ -77,7 +77,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -99,7 +99,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().map(Pair::getSecond).forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java index ba07f13e..36819e99 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java @@ -75,7 +75,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -97,7 +97,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java index 29382eb1..1ff873dc 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R3/src/main/java/net/imprex/orebfuscator/nms/v1_21_R3/NmsManager.java @@ -75,7 +75,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -97,7 +97,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java index 994eee09..2388501d 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R4/src/main/java/net/imprex/orebfuscator/nms/v1_21_R4/NmsManager.java @@ -75,7 +75,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -97,7 +97,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java index fa93f999..c8f15ae7 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R5/src/main/java/net/imprex/orebfuscator/nms/v1_21_R5/NmsManager.java @@ -75,7 +75,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -97,7 +97,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java index 7975d1ce..61b8964e 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R6/src/main/java/net/imprex/orebfuscator/nms/v1_21_R6/NmsManager.java @@ -75,7 +75,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.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(); @@ -97,7 +97,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.location().toString()))) diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java index bfe4bbf8..45f12a2a 100644 --- a/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R7/src/main/java/net/imprex/orebfuscator/nms/v1_21_R7/NmsManager.java @@ -75,7 +75,7 @@ public NmsManager() { super(Block.BLOCK_STATE_REGISTRY.size()); for (Map.Entry, Block> entry : BuiltInRegistries.BLOCK.entrySet()) { - NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().identifier().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(entry.getKey().identifier().toString()); Block block = entry.getValue(); ImmutableList possibleBlockStates = block.getStateDefinition().getPossibleStates(); @@ -97,7 +97,7 @@ public NmsManager() { } BuiltInRegistries.BLOCK.getTags().forEach(tag -> { - NamespacedKey namespacedKey = NamespacedKey.fromString(tag.key().location().toString()); + NamespacedKey namespacedKey = NamespacedKey.parse(tag.key().location().toString()); Set blocks = tag.stream() .map(holder -> holder.unwrapKey().map(key -> getBlockByName(key.identifier().toString()))) diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java index aae3e07e..acf7f3ae 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/MetricsSystem.java @@ -62,8 +62,8 @@ public void addPlayerCountChart() { } public void addConfigCharts(OrebfuscatorConfig config) { - this.metrics.addCustomChart(new SimplePie("max_mspt", () -> { - return Integer.toString(config.advanced().maxMillisecondsPerTick()); + this.metrics.addCustomChart(new SimplePie("obfuscation_timeout", () -> { + return Long.toString(config.advanced().obfuscationTimeout()); })); this.metrics.addCustomChart(new SimplePie("update_radius", () -> { return Integer.toString(config.general().updateRadius()); @@ -78,7 +78,10 @@ public void addUsageCharts(OrebfuscatorConfig config) { return Boolean.toString(config.general().ignoreSpectator()); })); this.metrics.addCustomChart(new SimplePie("cache", () -> { - return Boolean.toString(config.cache().enabled()); + if (config.cache().enabled()) { + return config.cache().enableDiskCache() ? "disk" : "true"; + } + return "false"; })); this.metrics.addCustomChart(new SimplePie("proximity", () -> { return Boolean.toString(config.proximityEnabled()); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index c777587b..fa26bf63 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -57,11 +57,13 @@ public class Orebfuscator extends JavaPlugin implements Listener, OrebfuscatorCo private ProximitySystem proximitySystem; private ProximityPacketListener proximityPacketListener; + private Version orebfuscatorVersion; private UpdateSystem updateSystem; @Override public void onLoad() { OfcLogger.setLogger(new BukkitLoggerAccessor(getLogger())); + this.orebfuscatorVersion = Version.parse(getDescription().getVersion()); } @Override @@ -232,7 +234,7 @@ public String name() { @Override public Version orebfuscatorVersion() { - return Version.parse(getDescription().getVersion()); + return this.orebfuscatorVersion; } @Override diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java index 0a78d150..1527cfa8 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/iterop/BukkitWorldAccessor.java @@ -195,6 +195,6 @@ public boolean equals(Object obj) { @Override public String toString() { - return "[minY=%s, maxY=%s]".formatted(minHeight, maxHeight); + return "[name=%s, minY=%s, maxY=%s]".formatted(name(), minHeight, maxHeight); } } diff --git a/pom.xml b/pom.xml index 5713c175..19f34f1b 100644 --- a/pom.xml +++ b/pom.xml @@ -60,10 +60,6 @@ papermc https://repo.papermc.io/repository/maven-public/ - - codemc-releases - https://repo.codemc.io/repository/maven-releases/ -