nodes;
- /**
- * the block we're trying to path to
- *
- * while processing, we have no idea where this is so consumers of `Path` should check that the path is processed before checking the target block
- */
- private @Nullable BlockPos target;
- /**
- * how far we are to the target
- *
- * while processing, the target could be anywhere but theoretically we're always "close" to a theoretical target so default is 0
- */
- private float distToTarget = 0;
- /**
- * whether we can reach the target
- *
- * while processing, we can always theoretically reach the target so default is true
- */
- private boolean canReach = true;
-
- public AsyncPath(@NotNull List emptyNodeList, @NotNull Set positions, @NotNull Supplier pathSupplier) {
- //noinspection ConstantConditions
- super(emptyNodeList, null, false);
-
- this.nodes = emptyNodeList;
- this.positions = positions;
- this.pathSupplier = pathSupplier;
-
- AsyncPathProcessor.queue(this);
- }
-
- @Override
- public boolean isProcessed() {
- return this.processState == PathProcessState.COMPLETED;
- }
-
- /**
- * returns the future representing the processing state of this path
- */
- public synchronized void postProcessing(@NotNull Runnable runnable) {
- if (isProcessed()) {
- runnable.run();
- } else {
- this.postProcessing.add(runnable);
- }
- }
-
- /**
- * an easy way to check if this processing path is the same as an attempted new path
- *
- * @param positions - the positions to compare against
- * @return true if we are processing the same positions
- */
- public boolean hasSameProcessingPositions(final Set positions) {
- if (this.positions.size() != positions.size()) {
- return false;
- }
-
- return this.positions.containsAll(positions);
- }
-
- /**
- * starts processing this path
- */
- public synchronized void process() {
- if (this.processState == PathProcessState.COMPLETED ||
- this.processState == PathProcessState.PROCESSING) {
- return;
- }
-
- processState = PathProcessState.PROCESSING;
-
- final Path bestPath = this.pathSupplier.get();
-
- this.nodes.addAll(bestPath.nodes); // we mutate this list to reuse the logic in Path
- this.target = bestPath.getTarget();
- this.distToTarget = bestPath.getDistToTarget();
- this.canReach = bestPath.canReach();
-
- processState = PathProcessState.COMPLETED;
-
- for (Runnable runnable : this.postProcessing) {
- runnable.run();
- } // Run tasks after processing
- }
-
- /**
- * if this path is accessed while it hasn't processed, just process it in-place
- */
- private void checkProcessed() {
- if (this.processState == PathProcessState.WAITING ||
- this.processState == PathProcessState.PROCESSING) { // Block if we are on processing
- this.process();
- }
- }
-
- /*
- * overrides we need for final fields that we cannot modify after processing
- */
-
- @Override
- public @NotNull BlockPos getTarget() {
- this.checkProcessed();
-
- return this.target;
- }
-
- @Override
- public float getDistToTarget() {
- this.checkProcessed();
-
- return this.distToTarget;
- }
-
- @Override
- public boolean canReach() {
- this.checkProcessed();
-
- return this.canReach;
- }
-
- /*
- * overrides to ensure we're processed first
- */
-
- @Override
- public boolean isDone() {
- return this.processState == PathProcessState.COMPLETED && super.isDone();
- }
-
- @Override
- public void advance() {
- this.checkProcessed();
-
- super.advance();
- }
-
- @Override
- public boolean notStarted() {
- this.checkProcessed();
-
- return super.notStarted();
- }
-
- @Nullable
- @Override
- public Node getEndNode() {
- this.checkProcessed();
-
- return super.getEndNode();
- }
-
- @Override
- public Node getNode(int index) {
- this.checkProcessed();
-
- return super.getNode(index);
- }
-
- @Override
- public void truncateNodes(int length) {
- this.checkProcessed();
-
- super.truncateNodes(length);
- }
-
- @Override
- public void replaceNode(int index, Node node) {
- this.checkProcessed();
-
- super.replaceNode(index, node);
- }
-
- @Override
- public int getNodeCount() {
- this.checkProcessed();
-
- return super.getNodeCount();
- }
-
- @Override
- public int getNextNodeIndex() {
- this.checkProcessed();
-
- return super.getNextNodeIndex();
- }
-
- @Override
- public void setNextNodeIndex(int nodeIndex) {
- this.checkProcessed();
-
- super.setNextNodeIndex(nodeIndex);
- }
-
- @Override
- public Vec3 getEntityPosAtNode(Entity entity, int index) {
- this.checkProcessed();
-
- return super.getEntityPosAtNode(entity, index);
- }
-
- @Override
- public BlockPos getNodePos(int index) {
- this.checkProcessed();
-
- return super.getNodePos(index);
- }
-
- @Override
- public Vec3 getNextEntityPos(Entity entity) {
- this.checkProcessed();
-
- return super.getNextEntityPos(entity);
- }
-
- @Override
- public BlockPos getNextNodePos() {
- this.checkProcessed();
-
- return super.getNextNodePos();
- }
-
- @Override
- public Node getNextNode() {
- this.checkProcessed();
-
- return super.getNextNode();
- }
-
- @Nullable
- @Override
- public Node getPreviousNode() {
- this.checkProcessed();
-
- return super.getPreviousNode();
- }
-
- public PathProcessState getProcessState() {
- return processState;
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPathProcessor.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPathProcessor.java
deleted file mode 100644
index 1403a01..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPathProcessor.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.bxteam.divinemc.pathfinding;
-
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.world.level.pathfinder.Path;
-import org.bxteam.divinemc.configuration.DivineConfig;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.concurrent.*;
-import java.util.function.Consumer;
-
-/**
- * used to handle the scheduling of async path processing
- */
-public class AsyncPathProcessor {
- private static final Executor pathProcessingExecutor = new ThreadPoolExecutor(
- 1,
- DivineConfig.asyncPathfindingMaxThreads,
- DivineConfig.asyncPathfindingKeepalive, TimeUnit.SECONDS,
- new LinkedBlockingQueue<>(),
- new ThreadFactoryBuilder()
- .setNameFormat("DivineMC Async Pathfinding Thread - %d")
- .setPriority(Thread.NORM_PRIORITY - 2)
- .build()
- );
-
- protected static CompletableFuture queue(@NotNull AsyncPath path) {
- return CompletableFuture.runAsync(path::process, pathProcessingExecutor);
- }
-
- /**
- * takes a possibly unprocessed path, and waits until it is completed
- * the consumer will be immediately invoked if the path is already processed
- * the consumer will always be called on the main thread
- *
- * @param path a path to wait on
- * @param afterProcessing a consumer to be called
- */
- public static void awaitProcessing(@Nullable Path path, Consumer<@Nullable Path> afterProcessing) {
- if (path != null && !path.isProcessed() && path instanceof AsyncPath asyncPath) {
- asyncPath.postProcessing(() ->
- MinecraftServer.getServer().scheduleOnMain(() -> afterProcessing.accept(path))
- );
- } else {
- afterProcessing.accept(path);
- }
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorCache.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorCache.java
deleted file mode 100644
index add2e3e..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorCache.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.bxteam.divinemc.pathfinding;
-
-import net.minecraft.world.level.pathfinder.NodeEvaluator;
-import org.apache.commons.lang.Validate;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-public class NodeEvaluatorCache {
- private static final Map> threadLocalNodeEvaluators = new ConcurrentHashMap<>();
- private static final Map nodeEvaluatorToGenerator = new ConcurrentHashMap<>();
-
- private static @NotNull Queue getQueueForFeatures(@NotNull NodeEvaluatorFeatures nodeEvaluatorFeatures) {
- return threadLocalNodeEvaluators.computeIfAbsent(nodeEvaluatorFeatures, key -> new ConcurrentLinkedQueue<>());
- }
-
- public static @NotNull NodeEvaluator takeNodeEvaluator(@NotNull NodeEvaluatorGenerator generator, @NotNull NodeEvaluator localNodeEvaluator) {
- final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(localNodeEvaluator);
- NodeEvaluator nodeEvaluator = getQueueForFeatures(nodeEvaluatorFeatures).poll();
-
- if (nodeEvaluator == null) {
- nodeEvaluator = generator.generate(nodeEvaluatorFeatures);
- }
-
- nodeEvaluatorToGenerator.put(nodeEvaluator, generator);
-
- return nodeEvaluator;
- }
-
- public static void returnNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) {
- final NodeEvaluatorGenerator generator = nodeEvaluatorToGenerator.remove(nodeEvaluator);
- Validate.notNull(generator, "NodeEvaluator already returned");
-
- final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(nodeEvaluator);
- getQueueForFeatures(nodeEvaluatorFeatures).offer(nodeEvaluator);
- }
-
- public static void removeNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) {
- nodeEvaluatorToGenerator.remove(nodeEvaluator);
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorFeatures.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorFeatures.java
deleted file mode 100644
index 9ee6f0f..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorFeatures.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.bxteam.divinemc.pathfinding;
-
-import net.minecraft.world.level.pathfinder.NodeEvaluator;
-import net.minecraft.world.level.pathfinder.SwimNodeEvaluator;
-
-public record NodeEvaluatorFeatures(
- NodeEvaluatorType type,
- boolean canPassDoors,
- boolean canFloat,
- boolean canWalkOverFences,
- boolean canOpenDoors,
- boolean allowBreaching
-) {
- public static NodeEvaluatorFeatures fromNodeEvaluator(NodeEvaluator nodeEvaluator) {
- NodeEvaluatorType type = NodeEvaluatorType.fromNodeEvaluator(nodeEvaluator);
- boolean canPassDoors = nodeEvaluator.canPassDoors();
- boolean canFloat = nodeEvaluator.canFloat();
- boolean canWalkOverFences = nodeEvaluator.canWalkOverFences();
- boolean canOpenDoors = nodeEvaluator.canOpenDoors();
- boolean allowBreaching = nodeEvaluator instanceof SwimNodeEvaluator swimNodeEvaluator && swimNodeEvaluator.allowBreaching;
- return new NodeEvaluatorFeatures(type, canPassDoors, canFloat, canWalkOverFences, canOpenDoors, allowBreaching);
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorGenerator.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorGenerator.java
deleted file mode 100644
index de13612..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorGenerator.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.bxteam.divinemc.pathfinding;
-
-import net.minecraft.world.level.pathfinder.NodeEvaluator;
-import org.jetbrains.annotations.NotNull;
-
-public interface NodeEvaluatorGenerator {
- @NotNull NodeEvaluator generate(NodeEvaluatorFeatures nodeEvaluatorFeatures);
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorType.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorType.java
deleted file mode 100644
index 6657aac..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorType.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.bxteam.divinemc.pathfinding;
-
-import net.minecraft.world.level.pathfinder.*;
-
-public enum NodeEvaluatorType {
- WALK,
- SWIM,
- AMPHIBIOUS,
- FLY;
-
- public static NodeEvaluatorType fromNodeEvaluator(NodeEvaluator nodeEvaluator) {
- if (nodeEvaluator instanceof SwimNodeEvaluator) return SWIM;
- if (nodeEvaluator instanceof FlyNodeEvaluator) return FLY;
- if (nodeEvaluator instanceof AmphibiousNodeEvaluator) return AMPHIBIOUS;
- return WALK;
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/PathProcessState.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/PathProcessState.java
deleted file mode 100644
index 76f8a7a..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/PathProcessState.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.bxteam.divinemc.pathfinding;
-
-public enum PathProcessState {
- WAITING,
- PROCESSING,
- COMPLETED
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFile.java
deleted file mode 100644
index e1e48b1..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFile.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.bxteam.divinemc.region;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.file.Path;
-import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.world.level.ChunkPos;
-
-public interface AbstractRegionFile extends AutoCloseable, ChunkSystemRegionFile {
- Path getPath();
- void flush() throws IOException;
- void clear(ChunkPos pos) throws IOException;
- void close() throws IOException;
- void setOversized(int x, int z, boolean b) throws IOException;
- void write(ChunkPos pos, ByteBuffer buffer) throws IOException;
-
- boolean hasChunk(ChunkPos pos);
- boolean doesChunkExist(ChunkPos pos) throws Exception;
- boolean isOversized(int x, int z);
- boolean recalculateHeader() throws IOException;
-
- DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException;
- DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException;
- CompoundTag getOversizedData(int x, int z) throws IOException;
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFileFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFileFactory.java
deleted file mode 100644
index 8ed0888..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFileFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.bxteam.divinemc.region;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import net.minecraft.world.level.chunk.storage.RegionFile;
-import net.minecraft.world.level.chunk.storage.RegionFileVersion;
-import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
-import org.bxteam.divinemc.configuration.DivineConfig;
-
-public class AbstractRegionFileFactory {
- @Contract("_, _, _, _ -> new")
- public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException {
- return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync);
- }
-
- @Contract("_, _, _, _, _ -> new")
- public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync, boolean canRecalcHeader) throws IOException {
- return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync, canRecalcHeader);
- }
-
- @Contract("_, _, _, _, _ -> new")
- public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException {
- return getAbstractRegionFile(storageKey, path, directory, compressionFormat, dsync, true);
- }
-
- @Contract("_, _, _, _, _, _ -> new")
- public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, boolean canRecalcHeader) throws IOException {
- final String fullFileName = path.getFileName().toString();
- final String[] fullNameSplit = fullFileName.split("\\.");
- final String extensionName = fullNameSplit[fullNameSplit.length - 1];
- switch (RegionFileFormat.fromExtension(extensionName)) {
- case UNKNOWN -> {
- if (DivineConfig.throwOnUnknownExtension) {
- throw new IllegalArgumentException("Unknown region file extension for file: " + fullFileName + "!");
- }
-
- return new RegionFile(storageKey, path, directory, compressionFormat, dsync);
- }
-
- case LINEAR -> {
- return new LinearRegionFile(path, storageKey.linearCompressionLevel());
- }
-
- default -> {
- return new RegionFile(storageKey, path, directory, compressionFormat, dsync);
- }
- }
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java
deleted file mode 100644
index 643aee5..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java
+++ /dev/null
@@ -1,309 +0,0 @@
-package org.bxteam.divinemc.region;
-
-import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
-import com.github.luben.zstd.ZstdInputStream;
-import com.github.luben.zstd.ZstdOutputStream;
-import com.mojang.logging.LogUtils;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import javax.annotation.Nullable;
-
-import net.jpountz.lz4.LZ4Compressor;
-import net.jpountz.lz4.LZ4Factory;
-import net.jpountz.lz4.LZ4FastDecompressor;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.world.level.ChunkPos;
-import org.slf4j.Logger;
-import org.bxteam.divinemc.configuration.DivineConfig;
-
-public class LinearRegionFile implements AbstractRegionFile {
- private static final long SUPERBLOCK = -4323716122432332390L;
- private static final byte VERSION = 2;
- private static final int HEADER_SIZE = 32;
- private static final int FOOTER_SIZE = 8;
- private static final Logger LOGGER = LogUtils.getLogger();
- private static final List SUPPORTED_VERSIONS = Arrays.asList((byte) 1, (byte) 2);
- private final byte[][] buffer = new byte[1024][];
- private final int[] bufferUncompressedSize = new int[1024];
- private final int[] chunkTimestamps = new int[1024];
- private final LZ4Compressor compressor;
- private final LZ4FastDecompressor decompressor;
- private final int compressionLevel;
- public boolean closed = false;
- public Path path;
- private volatile long lastFlushed = System.nanoTime();
-
- public LinearRegionFile(Path file, int compression) throws IOException {
- this.path = file;
- this.compressionLevel = compression;
- this.compressor = LZ4Factory.fastestInstance().fastCompressor();
- this.decompressor = LZ4Factory.fastestInstance().fastDecompressor();
-
- File regionFile = new File(this.path.toString());
-
- Arrays.fill(this.bufferUncompressedSize, 0);
-
- if (!regionFile.canRead()) return;
-
- try (FileInputStream fileStream = new FileInputStream(regionFile);
- DataInputStream rawDataStream = new DataInputStream(fileStream)) {
-
- long superBlock = rawDataStream.readLong();
- if (superBlock != SUPERBLOCK)
- throw new RuntimeException("Invalid superblock: " + superBlock + " in " + file);
-
- byte version = rawDataStream.readByte();
- if (!SUPPORTED_VERSIONS.contains(version))
- throw new RuntimeException("Invalid version: " + version + " in " + file);
-
- // Skip newestTimestamp (Long) + Compression level (Byte) + Chunk count (Short): Unused.
- rawDataStream.skipBytes(11);
-
- int dataCount = rawDataStream.readInt();
- long fileLength = file.toFile().length();
- if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE)
- throw new IOException("Invalid file length: " + this.path + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE));
-
- rawDataStream.skipBytes(8); // Skip data hash (Long): Unused.
-
- byte[] rawCompressed = new byte[dataCount];
- rawDataStream.readFully(rawCompressed, 0, dataCount);
-
- superBlock = rawDataStream.readLong();
- if (superBlock != SUPERBLOCK)
- throw new IOException("Footer superblock invalid " + this.path);
-
- try (DataInputStream dataStream = new DataInputStream(new ZstdInputStream(new ByteArrayInputStream(rawCompressed)))) {
-
- int[] starts = new int[1024];
- for (int i = 0; i < 1024; i++) {
- starts[i] = dataStream.readInt();
- dataStream.skipBytes(4); // Skip timestamps (Int): Unused.
- }
-
- for (int i = 0; i < 1024; i++) {
- if (starts[i] > 0) {
- int size = starts[i];
- byte[] b = new byte[size];
- dataStream.readFully(b, 0, size);
-
- int maxCompressedLength = this.compressor.maxCompressedLength(size);
- byte[] compressed = new byte[maxCompressedLength];
- int compressedLength = this.compressor.compress(b, 0, size, compressed, 0, maxCompressedLength);
- b = new byte[compressedLength];
- System.arraycopy(compressed, 0, b, 0, compressedLength);
-
- this.buffer[i] = b;
- this.bufferUncompressedSize[i] = size;
- }
- }
- }
- }
- }
-
- private static int getChunkIndex(int x, int z) {
- return (x & 31) + ((z & 31) << 5);
- }
-
- private static int getTimestamp() {
- return (int) (System.currentTimeMillis() / 1000L);
- }
-
- public void flush() throws IOException {
- flushWrapper(); // sync
- }
-
- public void flushWrapper() {
- try {
- save();
- } catch (IOException e) {
- LOGGER.error("Failed to flush region file {}", path.toAbsolutePath(), e);
- }
- }
-
- public boolean doesChunkExist(ChunkPos pos) throws Exception {
- throw new Exception("doesChunkExist is a stub");
- }
-
- private synchronized void save() throws IOException {
- long timestamp = getTimestamp();
- short chunkCount = 0;
-
- File tempFile = new File(path.toString() + ".tmp");
-
- try (FileOutputStream fileStream = new FileOutputStream(tempFile);
- ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream();
- ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, this.compressionLevel);
- DataOutputStream zstdDataStream = new DataOutputStream(zstdStream);
- DataOutputStream dataStream = new DataOutputStream(fileStream)) {
-
- dataStream.writeLong(SUPERBLOCK);
- dataStream.writeByte(VERSION);
- dataStream.writeLong(timestamp);
- dataStream.writeByte(this.compressionLevel);
-
- ArrayList byteBuffers = new ArrayList<>();
- for (int i = 0; i < 1024; i++) {
- if (this.bufferUncompressedSize[i] != 0) {
- chunkCount += 1;
- byte[] content = new byte[bufferUncompressedSize[i]];
- this.decompressor.decompress(buffer[i], 0, content, 0, bufferUncompressedSize[i]);
-
- byteBuffers.add(content);
- } else byteBuffers.add(null);
- }
- for (int i = 0; i < 1024; i++) {
- zstdDataStream.writeInt(this.bufferUncompressedSize[i]); // Write uncompressed size
- zstdDataStream.writeInt(this.chunkTimestamps[i]); // Write timestamp
- }
- for (int i = 0; i < 1024; i++) {
- if (byteBuffers.get(i) != null)
- zstdDataStream.write(byteBuffers.get(i), 0, byteBuffers.get(i).length);
- }
- zstdDataStream.close();
-
- dataStream.writeShort(chunkCount);
-
- byte[] compressed = zstdByteArray.toByteArray();
-
- dataStream.writeInt(compressed.length);
- dataStream.writeLong(0);
-
- dataStream.write(compressed, 0, compressed.length);
- dataStream.writeLong(SUPERBLOCK);
-
- dataStream.flush();
- fileStream.getFD().sync();
- fileStream.getChannel().force(true); // Ensure atomicity on Btrfs
- }
- Files.move(tempFile.toPath(), this.path, StandardCopyOption.REPLACE_EXISTING);
- this.lastFlushed = System.nanoTime();
- }
-
- public synchronized void write(ChunkPos pos, ByteBuffer buffer) {
- try {
- byte[] b = toByteArray(new ByteArrayInputStream(buffer.array()));
- int uncompressedSize = b.length;
-
- int maxCompressedLength = this.compressor.maxCompressedLength(b.length);
- byte[] compressed = new byte[maxCompressedLength];
- int compressedLength = this.compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength);
- b = new byte[compressedLength];
- System.arraycopy(compressed, 0, b, 0, compressedLength);
-
- int index = getChunkIndex(pos.x, pos.z);
- this.buffer[index] = b;
- this.chunkTimestamps[index] = getTimestamp();
- this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize;
- } catch (IOException e) {
- LOGGER.error("Chunk write IOException {} {}", e, this.path);
- }
-
- if ((System.nanoTime() - this.lastFlushed) >= TimeUnit.NANOSECONDS.toSeconds(DivineConfig.linearFlushFrequency)) {
- this.flushWrapper();
- }
- }
-
- public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
- return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos)));
- }
-
- @Override
- public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) throws IOException {
- final DataOutputStream out = this.getChunkDataOutputStream(pos);
-
- return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData(
- data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE,
- out, regionFile -> out.close()
- );
- }
-
- private byte[] toByteArray(InputStream in) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- byte[] tempBuffer = new byte[4096];
-
- int length;
- while ((length = in.read(tempBuffer)) >= 0) {
- out.write(tempBuffer, 0, length);
- }
-
- return out.toByteArray();
- }
-
- @Nullable
- public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) {
- if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) {
- byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]];
- this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]);
- return new DataInputStream(new ByteArrayInputStream(content));
- }
- return null;
- }
-
- public void clear(ChunkPos pos) {
- int i = getChunkIndex(pos.x, pos.z);
- this.buffer[i] = null;
- this.bufferUncompressedSize[i] = 0;
- this.chunkTimestamps[i] = getTimestamp();
- this.flushWrapper();
- }
-
- public Path getPath() {
- return this.path;
- }
-
- public boolean hasChunk(ChunkPos pos) {
- return this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] > 0;
- }
-
- public void close() throws IOException {
- if (closed) return;
- closed = true;
- flush(); // sync
- }
-
- public boolean recalculateHeader() {
- return false;
- }
-
- public void setOversized(int x, int z, boolean something) {
- }
-
- public CompoundTag getOversizedData(int x, int z) throws IOException {
- throw new IOException("getOversizedData is a stub " + this.path);
- }
-
- public boolean isOversized(int x, int z) {
- return false;
- }
-
- private class ChunkBuffer extends ByteArrayOutputStream {
- private final ChunkPos pos;
-
- public ChunkBuffer(ChunkPos chunkcoordintpair) {
- super();
- this.pos = chunkcoordintpair;
- }
-
- public void close() {
- ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
- LinearRegionFile.this.write(this.pos, bytebuffer);
- }
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java
deleted file mode 100644
index c7f10dc..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.bxteam.divinemc.region;
-
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
-import java.util.Locale;
-
-public enum RegionFileFormat {
- LINEAR(".linear"),
- MCA(".mca"),
- UNKNOWN(null);
-
- private final String extensionName;
-
- RegionFileFormat(String extensionName) {
- this.extensionName = extensionName;
- }
-
- public String getExtensionName() {
- return this.extensionName;
- }
-
- @Contract(pure = true)
- public static RegionFileFormat fromName(@NotNull String name) {
- switch (name.toUpperCase(Locale.ROOT)) {
- default -> {
- return UNKNOWN;
- }
-
- case "MCA" -> {
- return MCA;
- }
-
- case "LINEAR" -> {
- return LINEAR;
- }
- }
- }
-
- @Contract(pure = true)
- public static RegionFileFormat fromExtension(@NotNull String name) {
- switch (name.toLowerCase()) {
- case "mca" -> {
- return MCA;
- }
-
- case "linear" -> {
- return LINEAR;
- }
-
- default -> {
- return UNKNOWN;
- }
- }
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Globals.java b/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Globals.java
deleted file mode 100644
index 7fb6008..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Globals.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.bxteam.divinemc.seed;
-
-import com.google.common.collect.Iterables;
-import net.minecraft.server.level.ServerLevel;
-import org.bxteam.divinemc.configuration.DivineConfig;
-
-import java.math.BigInteger;
-import java.security.SecureRandom;
-import java.util.Optional;
-
-public class Globals {
- public static final int WORLD_SEED_LONGS = 16;
- public static final int WORLD_SEED_BITS = WORLD_SEED_LONGS * 64;
-
- public static final long[] worldSeed = new long[WORLD_SEED_LONGS];
- public static final ThreadLocal dimension = ThreadLocal.withInitial(() -> 0);
-
- public enum Salt {
- UNDEFINED,
- BASTION_FEATURE,
- WOODLAND_MANSION_FEATURE,
- MINESHAFT_FEATURE,
- BURIED_TREASURE_FEATURE,
- NETHER_FORTRESS_FEATURE,
- PILLAGER_OUTPOST_FEATURE,
- GEODE_FEATURE,
- NETHER_FOSSIL_FEATURE,
- OCEAN_MONUMENT_FEATURE,
- RUINED_PORTAL_FEATURE,
- POTENTIONAL_FEATURE,
- GENERATE_FEATURE,
- JIGSAW_PLACEMENT,
- STRONGHOLDS,
- POPULATION,
- DECORATION,
- SLIME_CHUNK
- }
-
- public static void setupGlobals(ServerLevel world) {
- if (!DivineConfig.enableSecureSeed) return;
-
- long[] seed = world.getServer().getWorldData().worldGenOptions().featureSeed();
- System.arraycopy(seed, 0, worldSeed, 0, WORLD_SEED_LONGS);
- int worldIndex = Iterables.indexOf(world.getServer().levelKeys(), it -> it == world.dimension());
- if (worldIndex == -1)
- worldIndex = world.getServer().levelKeys().size(); // if we are in world construction it may not have been added to the map yet
- dimension.set(worldIndex);
- }
-
- public static long[] createRandomWorldSeed() {
- long[] seed = new long[WORLD_SEED_LONGS];
- SecureRandom rand = new SecureRandom();
- for (int i = 0; i < WORLD_SEED_LONGS; i++) {
- seed[i] = rand.nextLong();
- }
- return seed;
- }
-
- // 1024-bit string -> 16 * 64 long[]
- public static Optional parseSeed(String seedStr) {
- if (seedStr.isEmpty()) return Optional.empty();
-
- if (seedStr.length() != WORLD_SEED_BITS) {
- throw new IllegalArgumentException("Secure seed length must be " + WORLD_SEED_BITS + "-bit but found " + seedStr.length() + "-bit.");
- }
-
- long[] seed = new long[WORLD_SEED_LONGS];
-
- for (int i = 0; i < WORLD_SEED_LONGS; i++) {
- int start = i * 64;
- int end = start + 64;
- String seedSection = seedStr.substring(start, end);
-
- BigInteger seedInDecimal = new BigInteger(seedSection, 2);
- seed[i] = seedInDecimal.longValue();
- }
-
- return Optional.of(seed);
- }
-
- // 16 * 64 long[] -> 1024-bit string
- public static String seedToString(long[] seed) {
- StringBuilder sb = new StringBuilder();
-
- for (long longV : seed) {
- // Convert to 64-bit binary string per long
- // Use format to keep 64-bit length, and use 0 to complete space
- String binaryStr = String.format("%64s", Long.toBinaryString(longV)).replace(' ', '0');
-
- sb.append(binaryStr);
- }
-
- return sb.toString();
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Hashing.java b/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Hashing.java
deleted file mode 100644
index 930ddc1..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Hashing.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.bxteam.divinemc.seed;
-
-public class Hashing {
- // https://en.wikipedia.org/wiki/BLAKE_(hash_function)
- // https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java
-
- private final static long[] blake2b_IV = {
- 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL,
- 0xa54ff53a5f1d36f1L, 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL,
- 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L
- };
-
- private final static byte[][] blake2b_sigma = {
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
- {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
- {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
- {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
- {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
- {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
- {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
- {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
- {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
- {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
- {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}
- };
-
- public static long[] hashWorldSeed(long[] worldSeed) {
- long[] result = blake2b_IV.clone();
- result[0] ^= 0x01010040;
- hash(worldSeed, result, new long[16], 0, false);
- return result;
- }
-
- public static void hash(long[] message, long[] chainValue, long[] internalState, long messageOffset, boolean isFinal) {
- assert message.length == 16;
- assert chainValue.length == 8;
- assert internalState.length == 16;
-
- System.arraycopy(chainValue, 0, internalState, 0, chainValue.length);
- System.arraycopy(blake2b_IV, 0, internalState, chainValue.length, 4);
- internalState[12] = messageOffset ^ blake2b_IV[4];
- internalState[13] = blake2b_IV[5];
- if (isFinal) internalState[14] = ~blake2b_IV[6];
- internalState[15] = blake2b_IV[7];
-
- for (int round = 0; round < 12; round++) {
- G(message[blake2b_sigma[round][0]], message[blake2b_sigma[round][1]], 0, 4, 8, 12, internalState);
- G(message[blake2b_sigma[round][2]], message[blake2b_sigma[round][3]], 1, 5, 9, 13, internalState);
- G(message[blake2b_sigma[round][4]], message[blake2b_sigma[round][5]], 2, 6, 10, 14, internalState);
- G(message[blake2b_sigma[round][6]], message[blake2b_sigma[round][7]], 3, 7, 11, 15, internalState);
- G(message[blake2b_sigma[round][8]], message[blake2b_sigma[round][9]], 0, 5, 10, 15, internalState);
- G(message[blake2b_sigma[round][10]], message[blake2b_sigma[round][11]], 1, 6, 11, 12, internalState);
- G(message[blake2b_sigma[round][12]], message[blake2b_sigma[round][13]], 2, 7, 8, 13, internalState);
- G(message[blake2b_sigma[round][14]], message[blake2b_sigma[round][15]], 3, 4, 9, 14, internalState);
- }
-
- for (int i = 0; i < 8; i++) {
- chainValue[i] ^= internalState[i] ^ internalState[i + 8];
- }
- }
-
- private static void G(long m1, long m2, int posA, int posB, int posC, int posD, long[] internalState) {
- internalState[posA] = internalState[posA] + internalState[posB] + m1;
- internalState[posD] = Long.rotateRight(internalState[posD] ^ internalState[posA], 32);
- internalState[posC] = internalState[posC] + internalState[posD];
- internalState[posB] = Long.rotateRight(internalState[posB] ^ internalState[posC], 24); // replaces 25 of BLAKE
- internalState[posA] = internalState[posA] + internalState[posB] + m2;
- internalState[posD] = Long.rotateRight(internalState[posD] ^ internalState[posA], 16);
- internalState[posC] = internalState[posC] + internalState[posD];
- internalState[posB] = Long.rotateRight(internalState[posB] ^ internalState[posC], 63); // replaces 11 of BLAKE
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/WorldgenCryptoRandom.java b/divinemc-server/src/main/java/org/bxteam/divinemc/seed/WorldgenCryptoRandom.java
deleted file mode 100644
index d30487c..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/WorldgenCryptoRandom.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package org.bxteam.divinemc.seed;
-
-import net.minecraft.util.Mth;
-import net.minecraft.util.RandomSource;
-import net.minecraft.world.level.levelgen.LegacyRandomSource;
-import net.minecraft.world.level.levelgen.WorldgenRandom;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Arrays;
-
-public class WorldgenCryptoRandom extends WorldgenRandom {
- // hash the world seed to guard against badly chosen world seeds
- private static final long[] HASHED_ZERO_SEED = Hashing.hashWorldSeed(new long[Globals.WORLD_SEED_LONGS]);
- private static final ThreadLocal LAST_SEEN_WORLD_SEED = ThreadLocal.withInitial(() -> new long[Globals.WORLD_SEED_LONGS]);
- private static final ThreadLocal HASHED_WORLD_SEED = ThreadLocal.withInitial(() -> HASHED_ZERO_SEED);
-
- private final long[] worldSeed = new long[Globals.WORLD_SEED_LONGS];
- private final long[] randomBits = new long[8];
- private int randomBitIndex;
- private static final int MAX_RANDOM_BIT_INDEX = 64 * 8;
- private static final int LOG2_MAX_RANDOM_BIT_INDEX = 9;
- private long counter;
- private final long[] message = new long[16];
- private final long[] cachedInternalState = new long[16];
-
- public WorldgenCryptoRandom(int x, int z, Globals.Salt typeSalt, long salt) {
- super(new LegacyRandomSource(0L));
- if (typeSalt != null) {
- this.setSecureSeed(x, z, typeSalt, salt);
- }
- }
-
- public void setSecureSeed(int x, int z, Globals.Salt typeSalt, long salt) {
- System.arraycopy(Globals.worldSeed, 0, this.worldSeed, 0, Globals.WORLD_SEED_LONGS);
- message[0] = ((long) x << 32) | ((long) z & 0xffffffffL);
- message[1] = ((long) Globals.dimension.get() << 32) | ((long) salt & 0xffffffffL);
- message[2] = typeSalt.ordinal();
- message[3] = counter = 0;
- randomBitIndex = MAX_RANDOM_BIT_INDEX;
- }
-
- private long[] getHashedWorldSeed() {
- if (!Arrays.equals(worldSeed, LAST_SEEN_WORLD_SEED.get())) {
- HASHED_WORLD_SEED.set(Hashing.hashWorldSeed(worldSeed));
- System.arraycopy(worldSeed, 0, LAST_SEEN_WORLD_SEED.get(), 0, Globals.WORLD_SEED_LONGS);
- }
- return HASHED_WORLD_SEED.get();
- }
-
- private void moreRandomBits() {
- message[3] = counter++;
- System.arraycopy(getHashedWorldSeed(), 0, randomBits, 0, 8);
- Hashing.hash(message, randomBits, cachedInternalState, 64, true);
- }
-
- private long getBits(int count) {
- if (randomBitIndex >= MAX_RANDOM_BIT_INDEX) {
- moreRandomBits();
- randomBitIndex -= MAX_RANDOM_BIT_INDEX;
- }
-
- int alignment = randomBitIndex & 63;
- if ((randomBitIndex >>> 6) == ((randomBitIndex + count) >>> 6)) {
- long result = (randomBits[randomBitIndex >>> 6] >>> alignment) & ((1L << count) - 1);
- randomBitIndex += count;
- return result;
- } else {
- long result = (randomBits[randomBitIndex >>> 6] >>> alignment) & ((1L << (64 - alignment)) - 1);
- randomBitIndex += count;
- if (randomBitIndex >= MAX_RANDOM_BIT_INDEX) {
- moreRandomBits();
- randomBitIndex -= MAX_RANDOM_BIT_INDEX;
- }
- alignment = randomBitIndex & 63;
- result <<= alignment;
- result |= (randomBits[randomBitIndex >>> 6] >>> (64 - alignment)) & ((1L << alignment) - 1);
-
- return result;
- }
- }
-
- @Override
- public @NotNull RandomSource fork() {
- WorldgenCryptoRandom fork = new WorldgenCryptoRandom(0, 0, null, 0);
-
- System.arraycopy(Globals.worldSeed, 0, fork.worldSeed, 0, Globals.WORLD_SEED_LONGS);
- fork.message[0] = this.message[0];
- fork.message[1] = this.message[1];
- fork.message[2] = this.message[2];
- fork.message[3] = this.message[3];
- fork.randomBitIndex = this.randomBitIndex;
- fork.counter = this.counter;
- fork.nextLong();
-
- return fork;
- }
-
- @Override
- public int next(int bits) {
- return (int) getBits(bits);
- }
-
- @Override
- public void consumeCount(int count) {
- randomBitIndex += count;
- if (randomBitIndex >= MAX_RANDOM_BIT_INDEX * 2) {
- randomBitIndex -= MAX_RANDOM_BIT_INDEX;
- counter += randomBitIndex >>> LOG2_MAX_RANDOM_BIT_INDEX;
- randomBitIndex &= MAX_RANDOM_BIT_INDEX - 1;
- randomBitIndex += MAX_RANDOM_BIT_INDEX;
- }
- }
-
- @Override
- public int nextInt(int bound) {
- int bits = Mth.ceillog2(bound);
- int result;
- do {
- result = (int) getBits(bits);
- } while (result >= bound);
-
- return result;
- }
-
- @Override
- public long nextLong() {
- return getBits(64);
- }
-
- @Override
- public double nextDouble() {
- return getBits(53) * 0x1.0p-53;
- }
-
- @Override
- public long setDecorationSeed(long worldSeed, int blockX, int blockZ) {
- setSecureSeed(blockX, blockZ, Globals.Salt.POPULATION, 0);
- return ((long) blockX << 32) | ((long) blockZ & 0xffffffffL);
- }
-
- @Override
- public void setFeatureSeed(long populationSeed, int index, int step) {
- setSecureSeed((int) (populationSeed >> 32), (int) populationSeed, Globals.Salt.DECORATION, index + 10000L * step);
- }
-
- @Override
- public void setLargeFeatureSeed(long worldSeed, int chunkX, int chunkZ) {
- super.setLargeFeatureSeed(worldSeed, chunkX, chunkZ);
- }
-
- @Override
- public void setLargeFeatureWithSalt(long worldSeed, int regionX, int regionZ, int salt) {
- super.setLargeFeatureWithSalt(worldSeed, regionX, regionZ, salt);
- }
-
- public static RandomSource seedSlimeChunk(int chunkX, int chunkZ) {
- return new WorldgenCryptoRandom(chunkX, chunkZ, Globals.Salt.SLIME_CHUNK, 0);
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/tracker/MultithreadedTracker.java b/divinemc-server/src/main/java/org/bxteam/divinemc/tracker/MultithreadedTracker.java
deleted file mode 100644
index 454d852..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/tracker/MultithreadedTracker.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package org.bxteam.divinemc.tracker;
-
-import ca.spottedleaf.moonrise.common.list.ReferenceList;
-import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
-import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
-import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup;
-import ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity;
-import ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import net.minecraft.server.level.ChunkMap;
-import net.minecraft.server.level.FullChunkStatus;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.world.entity.Entity;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.bxteam.divinemc.configuration.DivineConfig;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-public class MultithreadedTracker {
- private static final Logger LOGGER = LogManager.getLogger("MultithreadedTracker");
-
- public static class MultithreadedTrackerThread extends Thread {
- @Override
- public void run() {
- super.run();
- }
- }
-
- private static final Executor trackerExecutor = new ThreadPoolExecutor(
- 1,
- DivineConfig.asyncEntityTrackerMaxThreads,
- DivineConfig.asyncEntityTrackerKeepalive, TimeUnit.SECONDS,
- new LinkedBlockingQueue<>(),
- new ThreadFactoryBuilder()
- .setThreadFactory(
- r -> new MultithreadedTrackerThread() {
- @Override
- public void run() {
- r.run();
- }
- }
- )
- .setNameFormat("DivineMC Async Tracker Thread - %d")
- .setPriority(Thread.NORM_PRIORITY - 2)
- .build());
-
- private MultithreadedTracker() { }
-
- public static Executor getTrackerExecutor() {
- return trackerExecutor;
- }
-
- public static void tick(ChunkSystemServerLevel level) {
- try {
- if (!DivineConfig.multithreadedCompatModeEnabled) {
- tickAsync(level);
- } else {
- tickAsyncWithCompatMode(level);
- }
- } catch (Exception e) {
- LOGGER.error("Error occurred while executing async task.", e);
- }
- }
-
- private static void tickAsync(ChunkSystemServerLevel level) {
- final NearbyPlayers nearbyPlayers = level.moonrise$getNearbyPlayers();
- final ServerEntityLookup entityLookup = (ServerEntityLookup) level.moonrise$getEntityLookup();
-
- final ReferenceList trackerEntities = entityLookup.trackerEntities;
- final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked();
-
- // Move tracking to off-main
- trackerExecutor.execute(() -> {
- for (final Entity entity : trackerEntitiesRaw) {
- if (entity == null) continue;
-
- final ChunkMap.TrackedEntity tracker = ((EntityTrackerEntity) entity).moonrise$getTrackedEntity();
-
- if (tracker == null) continue;
-
- ((EntityTrackerTrackedEntity) tracker).moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition()));
- tracker.serverEntity.sendChanges();
- }
- });
- }
-
- private static void tickAsyncWithCompatMode(ChunkSystemServerLevel level) {
- final NearbyPlayers nearbyPlayers = level.moonrise$getNearbyPlayers();
- final ServerEntityLookup entityLookup = (ServerEntityLookup) level.moonrise$getEntityLookup();
-
- final ReferenceList trackerEntities = entityLookup.trackerEntities;
- final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked();
- final Runnable[] sendChangesTasks = new Runnable[trackerEntitiesRaw.length];
- int index = 0;
-
- for (final Entity entity : trackerEntitiesRaw) {
- if (entity == null) continue;
-
- final ChunkMap.TrackedEntity tracker = ((EntityTrackerEntity) entity).moonrise$getTrackedEntity();
-
- if (tracker == null) continue;
-
- ((EntityTrackerTrackedEntity) tracker).moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition()));
- sendChangesTasks[index++] = () -> tracker.serverEntity.sendChanges(); // Collect send changes to task array
- }
-
- // batch submit tasks
- trackerExecutor.execute(() -> {
- for (final Runnable sendChanges : sendChangesTasks) {
- if (sendChanges == null) continue;
-
- sendChanges.run();
- }
- });
- }
-
- // Original ChunkMap#newTrackerTick of Paper
- // Just for diff usage for future update
- @SuppressWarnings("DuplicatedCode")
- private static void tickOriginal(ServerLevel level) {
- final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup entityLookup = (ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup) ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) level).moonrise$getEntityLookup();
-
- final ca.spottedleaf.moonrise.common.list.ReferenceList trackerEntities = entityLookup.trackerEntities;
- final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked();
- for (int i = 0, len = trackerEntities.size(); i < len; ++i) {
- final Entity entity = trackerEntitiesRaw[i];
- final ChunkMap.TrackedEntity tracker = ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity) entity).moonrise$getTrackedEntity();
- if (tracker == null) {
- continue;
- }
- ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity) tracker).moonrise$tick(((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity) entity).moonrise$getChunkData().nearbyPlayers);
- if (((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity) tracker).moonrise$hasPlayers()
- || ((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity) entity).moonrise$getChunkStatus().isOrAfter(FullChunkStatus.ENTITY_TICKING)) {
- tracker.serverEntity.sendChanges();
- }
- }
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncDataSaving.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncDataSaving.java
deleted file mode 100644
index 274c7c6..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncDataSaving.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.bxteam.divinemc.util;
-
-import net.minecraft.Util;
-import org.bxteam.divinemc.configuration.DivineConfig;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-
-public class AsyncDataSaving {
- private AsyncDataSaving() {
- throw new IllegalStateException("This class cannot be instantiated");
- }
-
- public static void saveAsync(Runnable runnable) {
- if (!DivineConfig.asyncPlayerDataSaveEnabled) {
- runnable.run();
- return;
- }
-
- ExecutorService ioExecutor = Util.backgroundExecutor().service();
- CompletableFuture.runAsync(runnable, ioExecutor);
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/BlockEntityTickersList.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/BlockEntityTickersList.java
deleted file mode 100644
index 6a934c8..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/BlockEntityTickersList.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.bxteam.divinemc.util;
-
-import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
-import it.unimi.dsi.fastutil.objects.ObjectArrayList;
-import net.minecraft.world.level.block.entity.TickingBlockEntity;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * A list for ServerLevel's blockEntityTickers
- *
- * This list is behaving identically to ObjectArrayList, but it has an additional method, `removeAllByIndex`, that allows a list of integers to be passed indicating what
- * indexes should be deleted from the list
- *
- * This is faster than using removeAll, since we don't need to compare the identity of each block entity, and faster than looping through each index manually and deleting with remove,
- * since we don't need to resize the array every single remove.
- */
-public final class BlockEntityTickersList extends ObjectArrayList {
- private final IntOpenHashSet toRemove = new IntOpenHashSet();
- private int startSearchFromIndex = -1;
-
- /** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. */
- public BlockEntityTickersList() {
- super();
- }
-
- /**
- * Creates a new array list and fills it with a given collection.
- *
- * @param c a collection that will be used to fill the array list.
- */
- public BlockEntityTickersList(final Collection extends TickingBlockEntity> c) {
- super(c);
- }
-
- /**
- * Marks an entry as removed
- *
- * @param index the index of the item on the list to be marked as removed
- */
- public void markAsRemoved(final int index) {
- // The block entities list always loop starting from 0, so we only need to check if the startSearchFromIndex is -1 and that's it
- if (this.startSearchFromIndex == -1)
- this.startSearchFromIndex = index;
- this.toRemove.add(index);
- }
-
- /**
- * Removes elements that have been marked as removed.
- */
- public void removeMarkedEntries() {
- if (this.startSearchFromIndex == -1) // No entries in the list, skip
- return;
-
- removeAllByIndex(startSearchFromIndex, toRemove);
- toRemove.clear();
- this.startSearchFromIndex = -1; // Reset the start search index
- }
-
- /**
- * Removes elements by their index.
- */
- private void removeAllByIndex(final int startSearchFromIndex, final IntOpenHashSet c) { // can't use Set because we want to avoid autoboxing when using contains
- final int requiredMatches = c.size();
- if (requiredMatches == 0)
- return; // exit early, we don't need to do anything
-
- final Object[] a = this.a;
- int j = startSearchFromIndex;
- int matches = 0;
- for (int i = startSearchFromIndex; i < size; i++) { // If the user knows the first index to be removed, we can skip a lot of unnecessary comparsions
- if (!c.contains(i)) {
- a[j++] = a[i];
- } else {
- matches++;
- }
-
- if (matches == requiredMatches) { // Exit the loop if we already removed everything, we don't need to check anything else
- if (i != (size - 1)) { // If it isn't the last index...
- System.arraycopy(a, i + 1, a, j, size - i - 1);
- }
- j = size - requiredMatches;
- break;
- }
- }
- Arrays.fill(a, j, size, null);
- size = j;
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/LagCompensation.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/LagCompensation.java
deleted file mode 100644
index c0739dc..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/LagCompensation.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.bxteam.divinemc.util;
-
-import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
-
-import java.util.Collections;
-import java.util.List;
-
-public class LagCompensation {
- public static float tt20(float ticks, boolean limitZero) {
- float newTicks = (float) rawTT20(ticks);
-
- if (limitZero) return newTicks > 0 ? newTicks : 1;
- else return newTicks;
- }
-
- public static int tt20(int ticks, boolean limitZero) {
- int newTicks = (int) Math.ceil(rawTT20(ticks));
-
- if (limitZero) return newTicks > 0 ? newTicks : 1;
- else return newTicks;
- }
-
- public static double tt20(double ticks, boolean limitZero) {
- double newTicks = rawTT20(ticks);
-
- if (limitZero) return newTicks > 0 ? newTicks : 1;
- else return newTicks;
- }
-
- public static double rawTT20(double ticks) {
- return ticks == 0 ? 0 : ticks * TPSCalculator.getMostAccurateTPS() / TPSCalculator.MAX_TPS;
- }
-
- public static class TPSCalculator {
- public static Long lastTick;
- public static Long currentTick;
- private static double allMissedTicks = 0;
- private static final List tpsHistory = Collections.synchronizedList(new DoubleArrayList());
- private static final int historyLimit = 40;
-
- public static final int MAX_TPS = 20;
- public static final int FULL_TICK = 50;
-
- private TPSCalculator() {}
-
- public static void onTick() {
- if (currentTick != null) {
- lastTick = currentTick;
- }
-
- currentTick = System.currentTimeMillis();
- addToHistory(getTPS());
- clearMissedTicks();
- missedTick();
- }
-
- private static void addToHistory(double tps) {
- if (tpsHistory.size() >= historyLimit) {
- tpsHistory.removeFirst();
- }
-
- tpsHistory.add(tps);
- }
-
- public static long getMSPT() {
- return currentTick - lastTick;
- }
-
- public static double getAverageTPS() {
- double sum = 0.0;
- for (double value : tpsHistory) {
- sum += value;
- }
- return tpsHistory.isEmpty() ? 0.1 : sum / tpsHistory.size();
- }
-
- public static double getTPS() {
- if (lastTick == null) return -1;
- if (getMSPT() <= 0) return 0.1;
-
- double tps = 1000 / (double) getMSPT();
- return tps > MAX_TPS ? MAX_TPS : tps;
- }
-
- public static void missedTick() {
- if (lastTick == null) return;
-
- long mspt = getMSPT() <= 0 ? 50 : getMSPT();
- double missedTicks = (mspt / (double) FULL_TICK) - 1;
- allMissedTicks += missedTicks <= 0 ? 0 : missedTicks;
- }
-
- public static double getMostAccurateTPS() {
- return Math.min(getTPS(), getAverageTPS());
- }
-
- public double getAllMissedTicks() {
- return allMissedTicks;
- }
-
- public static int applicableMissedTicks() {
- return (int) Math.floor(allMissedTicks);
- }
-
- public static void clearMissedTicks() {
- allMissedTicks -= applicableMissedTicks();
- }
-
- public void resetMissedTicks() {
- allMissedTicks = 0;
- }
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/c2me/ObjectCachingUtils.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/c2me/ObjectCachingUtils.java
deleted file mode 100644
index d5f3ad9..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/c2me/ObjectCachingUtils.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.bxteam.divinemc.util.c2me;
-
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-
-import java.util.BitSet;
-import java.util.function.IntFunction;
-
-public class ObjectCachingUtils {
- private static final IntFunction bitSetConstructor = BitSet::new;
-
- public static ThreadLocal> BITSETS = ThreadLocal.withInitial(Int2ObjectOpenHashMap::new);
-
- private ObjectCachingUtils() {}
-
- public static BitSet getCachedOrNewBitSet(int bits) {
- final BitSet bitSet = BITSETS.get().computeIfAbsent(bits, bitSetConstructor);
- bitSet.clear();
- return bitSet;
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/carpetams/BlockPatternHelper.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/carpetams/BlockPatternHelper.java
deleted file mode 100644
index 44b8a70..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/carpetams/BlockPatternHelper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.bxteam.divinemc.util.carpetams;
-
-import com.google.common.cache.LoadingCache;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Direction;
-import net.minecraft.world.level.Level;
-import net.minecraft.world.level.block.state.pattern.BlockInWorld;
-import net.minecraft.world.level.block.state.pattern.BlockPattern;
-
-/**
- * Original here
- *
- * @author 1024-byteeeee
- */
-public class BlockPatternHelper {
- public static BlockPattern.BlockPatternMatch partialSearchAround(BlockPattern pattern, Level world, BlockPos pos) {
- LoadingCache loadingCache = BlockPattern.createLevelCache(world, false);
- int i = Math.max(Math.max(pattern.getWidth(), pattern.getHeight()), pattern.getDepth());
-
- for (BlockPos blockPos : BlockPos.betweenClosed(pos, pos.offset(i - 1, 0, i - 1))) {
- for (Direction direction : Direction.values()) {
- for (Direction direction2 : Direction.values()) {
- BlockPattern.BlockPatternMatch result;
- if (direction2 == direction || direction2 == direction.getOpposite() || (result = pattern.matches(blockPos, direction, direction2, loadingCache)) == null)
- continue;
- return result;
- }
- }
- }
- return null;
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/CompactSineLUT.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/CompactSineLUT.java
deleted file mode 100644
index e372330..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/CompactSineLUT.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.bxteam.divinemc.util.lithium;
-
-import net.minecraft.util.Mth;
-
-/**
- * A replacement for the sine angle lookup table used in {@link Mth}, both reducing the size of LUT and improving
- * the access patterns for common paired sin/cos operations.
- *
- * sin(-x) = -sin(x)
- * ... to eliminate negative angles from the LUT.
- *
- * sin(x) = sin(pi/2 - x)
- * ... to eliminate supplementary angles from the LUT.
- *
- * Using these identities allows us to reduce the LUT from 64K entries (256 KB) to just 16K entries (64 KB), enabling
- * it to better fit into the CPU's caches at the expense of some cycles on the fast path. The implementation has been
- * tightly optimized to avoid branching where possible and to use very quick integer operations.
- *
- * Generally speaking, reducing the size of a lookup table is always a good optimization, but since we need to spend
- * extra CPU cycles trying to maintain parity with vanilla, there is the potential risk that this implementation ends
- * up being slower than vanilla when the lookup table is able to be kept in cache memory.
- *
- * Unlike other "fast math" implementations, the values returned by this class are *bit-for-bit identical* with those
- * from {@link Mth}. Validation is performed during runtime to ensure that the table is correct.
- *
- * @author coderbot16 Author of the original (and very clever) implementation in Rust
- * @author jellysquid3 Additional optimizations, port to Java
- */
-public class CompactSineLUT {
- private static final int[] SIN_INT = new int[16384 + 1];
- private static final float SIN_MIDPOINT;
-
- static {
- // Copy the sine table, covering to raw int bits
- for (int i = 0; i < SIN_INT.length; i++) {
- SIN_INT[i] = Float.floatToRawIntBits(Mth.SIN[i]);
- }
-
- SIN_MIDPOINT = Mth.SIN[Mth.SIN.length / 2];
-
- // Test that the lookup table is correct during runtime
- for (int i = 0; i < Mth.SIN.length; i++) {
- float expected = Mth.SIN[i];
- float value = lookup(i);
-
- if (expected != value) {
- throw new IllegalArgumentException(String.format("LUT error at index %d (expected: %s, found: %s)", i, expected, value));
- }
- }
- }
-
- // [VanillaCopy] Mth#sin(float)
- public static float sin(float f) {
- return lookup((int) (f * 10430.378f) & 0xFFFF);
- }
-
- // [VanillaCopy] Mth#cos(float)
- public static float cos(float f) {
- return lookup((int) (f * 10430.378f + 16384.0f) & 0xFFFF);
- }
-
- private static float lookup(int index) {
- // A special case... Is there some way to eliminate this?
- if (index == 32768) {
- return SIN_MIDPOINT;
- }
-
- // Trigonometric identity: sin(-x) = -sin(x)
- // Given a domain of 0 <= x <= 2*pi, just negate the value if x > pi.
- // This allows the sin table size to be halved.
- int neg = (index & 0x8000) << 16;
-
- // All bits set if (pi/2 <= x), none set otherwise
- // Extracts the 15th bit from 'half'
- int mask = (index << 17) >> 31;
-
- // Trigonometric identity: sin(x) = sin(pi/2 - x)
- int pos = (0x8001 & mask) + (index ^ mask);
-
- // Wrap the position in the table. Moving this down to immediately before the array access
- // seems to help the Hotspot compiler optimize the bit math better.
- pos &= 0x7fff;
-
- // Fetch the corresponding value from the LUT and invert the sign bit as needed
- // This directly manipulate the sign bit on the float bits to simplify logic
- return Float.intBitsToFloat(SIN_INT[pos] ^ neg);
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/IterateOutwardsCache.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/IterateOutwardsCache.java
deleted file mode 100644
index 5a9febc..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/IterateOutwardsCache.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.bxteam.divinemc.util.lithium;
-
-import it.unimi.dsi.fastutil.longs.LongArrayList;
-import it.unimi.dsi.fastutil.longs.LongList;
-import java.util.Iterator;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-import net.minecraft.core.BlockPos;
-
-/**
- * @author 2No2Name, original implemenation by SuperCoder7979 and Gegy1000
- */
-public class IterateOutwardsCache {
- // POS_ZERO must not be replaced with BlockPos.ORIGIN, otherwise iterateOutwards at BlockPos.ORIGIN will not use the cache
- public static final BlockPos POS_ZERO = new BlockPos(0,0,0);
-
- private final ConcurrentHashMap table;
- private final int capacity;
- private final Random random;
-
- public IterateOutwardsCache(int capacity) {
- this.capacity = capacity;
- this.table = new ConcurrentHashMap<>(31);
- this.random = new Random();
- }
-
- private void fillPositionsWithIterateOutwards(LongList entry, int xRange, int yRange, int zRange) {
- // Add all positions to the cached list
- for (BlockPos pos : BlockPos.withinManhattan(POS_ZERO, xRange, yRange, zRange)) {
- entry.add(pos.asLong());
- }
- }
-
- public LongList getOrCompute(int xRange, int yRange, int zRange) {
- long key = BlockPos.asLong(xRange, yRange, zRange);
-
- LongArrayList entry = this.table.get(key);
- if (entry != null) {
- return entry;
- }
-
- // Cache miss: compute and store
- entry = new LongArrayList(128);
-
- this.fillPositionsWithIterateOutwards(entry, xRange, yRange, zRange);
-
- // decrease the array size, as of now it won't be modified anymore anyways
- entry.trim();
-
- // this might overwrite an entry as the same entry could have been computed and added during this thread's computation
- // we do not use computeIfAbsent, as it can delay other threads for too long
- Object previousEntry = this.table.put(key, entry);
-
- if (previousEntry == null && this.table.size() > this.capacity) {
- // prevent a memory leak by randomly removing about 1/8th of the elements when the exceed the desired capacity is exceeded
- final Iterator iterator = this.table.keySet().iterator();
- // prevent an unlikely infinite loop caused by another thread filling the table concurrently using counting
- for (int i = -this.capacity; iterator.hasNext() && i < 5; i++) {
- Long key2 = iterator.next();
- // random is not threadsafe, but it doesn't matter here, because we don't need quality random numbers
- if (this.random.nextInt(8) == 0 && key2 != key) {
- iterator.remove();
- }
- }
- }
-
- return entry;
- }
-}
diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/LongList2BlockPosMutableIterable.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/LongList2BlockPosMutableIterable.java
deleted file mode 100644
index 2f0ad27..0000000
--- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/LongList2BlockPosMutableIterable.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.bxteam.divinemc.util.lithium;
-
-import it.unimi.dsi.fastutil.longs.LongIterator;
-import it.unimi.dsi.fastutil.longs.LongList;
-import java.util.Iterator;
-import net.minecraft.core.BlockPos;
-
-/**
- * @author 2No2Name
- */
-public class LongList2BlockPosMutableIterable implements Iterable {
- private final LongList positions;
- private final int xOffset, yOffset, zOffset;
-
- public LongList2BlockPosMutableIterable(BlockPos offset, LongList posList) {
- this.xOffset = offset.getX();
- this.yOffset = offset.getY();
- this.zOffset = offset.getZ();
- this.positions = posList;
- }
-
- @Override
- public Iterator iterator() {
- return new Iterator() {
- private final LongIterator it = LongList2BlockPosMutableIterable.this.positions.iterator();
- private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
-
- @Override
- public boolean hasNext() {
- return it.hasNext();
- }
-
- @Override
- public net.minecraft.core.BlockPos next() {
- long nextPos = this.it.nextLong();
- return this.pos.set(
- LongList2BlockPosMutableIterable.this.xOffset + BlockPos.getX(nextPos),
- LongList2BlockPosMutableIterable.this.yOffset + BlockPos.getY(nextPos),
- LongList2BlockPosMutableIterable.this.zOffset + BlockPos.getZ(nextPos));
- }
- };
- }
-}