From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf
Date: Mon, 21 Oct 2024 11:06:24 -0700
Subject: [PATCH] fixup! Moonrise optimisation patches
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java b/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java
@@ -0,0 +0,0 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache;
+import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
import com.mojang.logging.LogUtils;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
@@ -0,0 +0,0 @@ public final class ChunkSystem {
}
public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) {
-
+ // Update progress listener for LevelLoadingScreen
+ final ChunkProgressListener progressListener = level.getChunkSource().chunkMap.progressListener;
+ if (progressListener != null) {
+ ChunkSystem.scheduleChunkTask(level, holder.getPos().x, holder.getPos().z, () -> {
+ progressListener.onStatusChange(holder.getPos(), null);
+ });
+ }
}
public static void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) {
@@ -0,0 +0,0 @@ public final class ChunkSystem {
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
);
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
- chunk.postProcessGeneration();
+ chunk.postProcessGeneration((ServerLevel)chunk.getLevel());
}
((ServerLevel)chunk.getLevel()).startTickingChunk(chunk);
((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet();
+ ((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
}
public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove(
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
);
+ ((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
}
public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.block_counting;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.shorts.ShortArrayList;
public interface BlockCountingBitStorage {
- public Int2ObjectOpenHashMap moonrise$countEntries();
+ public Int2ObjectOpenHashMap moonrise$countEntries();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.block_counting;
-import ca.spottedleaf.moonrise.common.list.IBlockDataList;
+import ca.spottedleaf.moonrise.common.list.ShortList;
public interface BlockCountingChunkSection {
- public int moonrise$getSpecialCollidingBlocks();
+ public boolean moonrise$hasSpecialCollidingBlocks();
- public IBlockDataList moonrise$getTickingBlockList();
+ public ShortList moonrise$getTickingBlockList();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/PropertyAccess.java b/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/PropertyAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/PropertyAccess.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.blockstate_propertyaccess;
+
+public interface PropertyAccess {
+
+ public int moonrise$getId();
+
+ public int moonrise$getIdFor(final T value);
+
+ public T moonrise$getById(final int id);
+
+ public void moonrise$setById(final T[] values);
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/PropertyAccessStateHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/PropertyAccessStateHolder.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/PropertyAccessStateHolder.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.blockstate_propertyaccess;
+
+public interface PropertyAccessStateHolder {
+
+ public long moonrise$getTableIndex();
+
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java b/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.util;
+
+import ca.spottedleaf.concurrentutil.util.IntegerUtil;
+import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess;
+import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccessStateHolder;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.AbstractObjectSet;
+import it.unimi.dsi.fastutil.objects.AbstractReference2ObjectMap;
+import it.unimi.dsi.fastutil.objects.ObjectIterator;
+import it.unimi.dsi.fastutil.objects.ObjectSet;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import net.minecraft.world.level.block.state.StateHolder;
+import net.minecraft.world.level.block.state.properties.Property;
+
+public final class ZeroCollidingReferenceStateTable {
+
+ private final Int2ObjectOpenHashMap propertyToIndexer;
+ private S[] lookup;
+ private final Collection> properties;
+
+ public ZeroCollidingReferenceStateTable(final Collection> properties) {
+ this.propertyToIndexer = new Int2ObjectOpenHashMap<>(properties.size());
+ this.properties = new ReferenceOpenHashSet<>(properties);
+
+ final List> sortedProperties = new ArrayList<>(properties);
+
+ // important that each table sees the same property order given the same _set_ of properties,
+ // as each table will calculate the index for the block state
+ sortedProperties.sort((final Property> p1, final Property> p2) -> {
+ return Integer.compare(
+ ((PropertyAccess>)p1).moonrise$getId(),
+ ((PropertyAccess>)p2).moonrise$getId()
+ );
+ });
+
+ int currentMultiple = 1;
+ for (final Property> property : sortedProperties) {
+ final int totalValues = property.getPossibleValues().size();
+
+ this.propertyToIndexer.put(
+ ((PropertyAccess>)property).moonrise$getId(),
+ new Indexer(
+ totalValues,
+ currentMultiple,
+ IntegerUtil.getUnsignedDivisorMagic((long)currentMultiple, 32),
+ IntegerUtil.getUnsignedDivisorMagic((long)totalValues, 32)
+ )
+ );
+
+ currentMultiple *= totalValues;
+ }
+ }
+
+ public > boolean hasProperty(final Property property) {
+ return this.propertyToIndexer.containsKey(((PropertyAccess)property).moonrise$getId());
+ }
+
+ public long getIndex(final StateHolder stateHolder) {
+ long ret = 0L;
+
+ for (final Map.Entry, Comparable>> entry : stateHolder.getValues().entrySet()) {
+ final Property> property = entry.getKey();
+ final Comparable> value = entry.getValue();
+
+ final Indexer indexer = this.propertyToIndexer.get(((PropertyAccess>)property).moonrise$getId());
+
+ ret += (((PropertyAccess)property).moonrise$getIdFor(value)) * indexer.multiple;
+ }
+
+ return ret;
+ }
+
+ public boolean isLoaded() {
+ return this.lookup != null;
+ }
+
+ public void loadInTable(final Map
- */
-public final class RegionFileIOThread extends PrioritisedQueueExecutorThread {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(RegionFileIOThread.class);
-
- /**
- * The kinds of region files controlled by the region file thread. Add more when needed, and ensure
- * getControllerFor is updated.
- */
- public static enum RegionFileType {
- CHUNK_DATA,
- POI_DATA,
- ENTITY_DATA;
- }
-
- private static final RegionFileType[] CACHED_REGIONFILE_TYPES = RegionFileType.values();
-
- public static ChunkDataController getControllerFor(final ServerLevel world, final RegionFileType type) {
- switch (type) {
- case CHUNK_DATA:
- return ((ChunkSystemServerLevel)world).moonrise$getChunkDataController();
- case POI_DATA:
- return ((ChunkSystemServerLevel)world).moonrise$getPoiChunkDataController();
- case ENTITY_DATA:
- return ((ChunkSystemServerLevel)world).moonrise$getEntityChunkDataController();
- default:
- throw new IllegalStateException("Unknown controller type " + type);
- }
- }
-
- /**
- * Collects regionfile data for a certain chunk.
- */
- public static final class RegionFileData {
-
- private final boolean[] hasResult = new boolean[CACHED_REGIONFILE_TYPES.length];
- private final CompoundTag[] data = new CompoundTag[CACHED_REGIONFILE_TYPES.length];
- private final Throwable[] throwables = new Throwable[CACHED_REGIONFILE_TYPES.length];
-
- /**
- * Sets the result associated with the specified regionfile type. Note that
- * results can only be set once per regionfile type.
- *
- * @param type The regionfile type.
- * @param data The result to set.
- */
- public void setData(final RegionFileType type, final CompoundTag data) {
- final int index = type.ordinal();
-
- if (this.hasResult[index]) {
- throw new IllegalArgumentException("Result already exists for type " + type);
- }
- this.hasResult[index] = true;
- this.data[index] = data;
- }
-
- /**
- * Sets the result associated with the specified regionfile type. Note that
- * results can only be set once per regionfile type.
- *
- * @param type The regionfile type.
- * @param throwable The result to set.
- */
- public void setThrowable(final RegionFileType type, final Throwable throwable) {
- final int index = type.ordinal();
-
- if (this.hasResult[index]) {
- throw new IllegalArgumentException("Result already exists for type " + type);
- }
- this.hasResult[index] = true;
- this.throwables[index] = throwable;
- }
-
- /**
- * Returns whether there is a result for the specified regionfile type.
- *
- * @param type Specified regionfile type.
- *
- * @return Whether a result exists for {@code type}.
- */
- public boolean hasResult(final RegionFileType type) {
- return this.hasResult[type.ordinal()];
- }
-
- /**
- * Returns the data result for the regionfile type.
- *
- * @param type Specified regionfile type.
- *
- * @throws IllegalArgumentException If the result has not been set for {@code type}.
- * @return The data result for the specified type. If the result is a {@code Throwable},
- * then returns {@code null}.
- */
- public CompoundTag getData(final RegionFileType type) {
- final int index = type.ordinal();
-
- if (!this.hasResult[index]) {
- throw new IllegalArgumentException("Result does not exist for type " + type);
- }
-
- return this.data[index];
- }
-
- /**
- * Returns the throwable result for the regionfile type.
- *
- * @param type Specified regionfile type.
- *
- * @throws IllegalArgumentException If the result has not been set for {@code type}.
- * @return The throwable result for the specified type. If the result is an {@code CompoundTag},
- * then returns {@code null}.
- */
- public Throwable getThrowable(final RegionFileType type) {
- final int index = type.ordinal();
-
- if (!this.hasResult[index]) {
- throw new IllegalArgumentException("Result does not exist for type " + type);
- }
-
- return this.throwables[index];
- }
- }
-
- private static final Object INIT_LOCK = new Object();
-
- static RegionFileIOThread[] threads;
-
- /* needs to be consistent given a set of parameters */
- static RegionFileIOThread selectThread(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type) {
- if (threads == null) {
- throw new IllegalStateException("Threads not initialised");
- }
-
- final int regionX = chunkX >> 5;
- final int regionZ = chunkZ >> 5;
- final int typeOffset = type.ordinal();
-
- return threads[(System.identityHashCode(world) + regionX + regionZ + typeOffset) % threads.length];
- }
-
- /**
- * Shuts down the I/O executor(s). Watis for all tasks to complete if specified.
- * Tasks queued during this call might not be accepted, and tasks queued after will not be accepted.
- *
- * @param wait Whether to wait until all tasks have completed.
- */
- public static void close(final boolean wait) {
- for (int i = 0, len = threads.length; i < len; ++i) {
- threads[i].close(false, true);
- }
- if (wait) {
- RegionFileIOThread.flush();
- }
- }
-
- public static long[] getExecutedTasks() {
- final long[] ret = new long[threads.length];
- for (int i = 0, len = threads.length; i < len; ++i) {
- ret[i] = threads[i].getTotalTasksExecuted();
- }
-
- return ret;
- }
-
- public static long[] getTasksScheduled() {
- final long[] ret = new long[threads.length];
- for (int i = 0, len = threads.length; i < len; ++i) {
- ret[i] = threads[i].getTotalTasksScheduled();
- }
- return ret;
- }
-
- public static void flush() {
- for (int i = 0, len = threads.length; i < len; ++i) {
- threads[i].waitUntilAllExecuted();
- }
- }
-
- public static void flushRegionStorages(final ServerLevel world) throws IOException {
- for (final RegionFileType type : CACHED_REGIONFILE_TYPES) {
- getControllerFor(world, type).getCache().flush();
- }
- }
-
- public static void partialFlush(final int totalTasksRemaining) {
- long failures = 1L; // start out at 0.25ms
-
- for (;;) {
- final long[] executed = getExecutedTasks();
- final long[] scheduled = getTasksScheduled();
-
- long sum = 0;
- for (int i = 0; i < executed.length; ++i) {
- sum += scheduled[i] - executed[i];
- }
-
- if (sum <= totalTasksRemaining) {
- break;
- }
-
- failures = ConcurrentUtil.linearLongBackoff(failures, 250_000L, 5_000_000L); // 500us, 5ms
- }
- }
-
- /**
- * Inits the executor with the specified number of threads.
- *
- * @param threads Specified number of threads.
- */
- public static void init(final int threads) {
- synchronized (INIT_LOCK) {
- if (RegionFileIOThread.threads != null) {
- throw new IllegalStateException("Already initialised threads");
- }
-
- RegionFileIOThread.threads = new RegionFileIOThread[threads];
-
- for (int i = 0; i < threads; ++i) {
- RegionFileIOThread.threads[i] = new RegionFileIOThread(i);
- RegionFileIOThread.threads[i].start();
- }
- }
- }
-
- public static void deinit() {
- if (true) { // Paper
- // TODO does this cause issues with mods? how to implement
- close(true);
- synchronized (INIT_LOCK) {
- RegionFileIOThread.threads = null;
- }
- } else { RegionFileIOThread.flush(); }
- }
-
- private RegionFileIOThread(final int threadNumber) {
- super(new PrioritisedThreadedTaskQueue(), (int)(1.0e6)); // 1.0ms spinwait time
- this.setName("RegionFile I/O Thread #" + threadNumber);
- this.setPriority(Thread.NORM_PRIORITY - 2); // we keep priority close to normal because threads can wait on us
- this.setUncaughtExceptionHandler((final Thread thread, final Throwable thr) -> {
- LOGGER.error("Uncaught exception thrown from I/O thread, report this! Thread: " + thread.getName(), thr);
- });
- }
-
- /**
- * Returns whether the current thread is a regionfile I/O executor.
- * @return Whether the current thread is a regionfile I/O executor.
- */
- public static boolean isRegionFileThread() {
- return Thread.currentThread() instanceof RegionFileIOThread;
- }
-
- /**
- * Returns the priority associated with blocking I/O based on the current thread. The goal is to avoid
- * dumb plugins from taking away priority from threads we consider crucial.
- * @return The priroity to use with blocking I/O on the current thread.
- */
- public static Priority getIOBlockingPriorityForCurrentThread() {
- if (TickThread.isTickThread()) {
- return Priority.BLOCKING;
- }
- return Priority.HIGHEST;
- }
-
- /**
- * Returns the current {@code CompoundTag} pending for write for the specified chunk & regionfile type.
- * Note that this does not copy the result, so do not modify the result returned.
- *
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param type Specified regionfile type.
- *
- * @return The compound tag associated for the specified chunk. {@code null} if no write was pending, or if {@code null} is the write pending.
- */
- public static CompoundTag getPendingWrite(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type) {
- final RegionFileIOThread thread = RegionFileIOThread.selectThread(world, chunkX, chunkZ, type);
- return thread.getPendingWriteInternal(world, chunkX, chunkZ, type);
- }
-
- CompoundTag getPendingWriteInternal(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type) {
- final ChunkDataController taskController = getControllerFor(world, type);
- final ChunkDataTask task = taskController.tasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
-
- if (task == null) {
- return null;
- }
-
- final CompoundTag ret = task.inProgressWrite;
-
- return ret == ChunkDataTask.NOTHING_TO_WRITE ? null : ret;
- }
-
- /**
- * Returns the priority for the specified regionfile type for the specified chunk.
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param type Specified regionfile type.
- * @return The priority for the chunk
- */
- public static Priority getPriority(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type) {
- final RegionFileIOThread thread = RegionFileIOThread.selectThread(world, chunkX, chunkZ, type);
- return thread.getPriorityInternal(world, chunkX, chunkZ, type);
- }
-
- Priority getPriorityInternal(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type) {
- final ChunkDataController taskController = getControllerFor(world, type);
- final ChunkDataTask task = taskController.tasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
-
- if (task == null) {
- return Priority.COMPLETING;
- }
-
- return task.prioritisedTask.getPriority();
- }
-
- /**
- * Sets the priority for all regionfile types for the specified chunk. Note that great care should
- * be taken using this method, as there can be multiple tasks tied to the same chunk that want different
- * priorities.
- *
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param priority New priority.
- *
- * @see #raisePriority(ServerLevel, int, int, Priority)
- * @see #raisePriority(ServerLevel, int, int, RegionFileType, Priority)
- * @see #lowerPriority(ServerLevel, int, int, Priority)
- * @see #lowerPriority(ServerLevel, int, int, RegionFileType, Priority)
- */
- public static void setPriority(final ServerLevel world, final int chunkX, final int chunkZ,
- final Priority priority) {
- for (final RegionFileType type : CACHED_REGIONFILE_TYPES) {
- RegionFileIOThread.setPriority(world, chunkX, chunkZ, type, priority);
- }
- }
-
- /**
- * Sets the priority for the specified regionfile type for the specified chunk. Note that great care should
- * be taken using this method, as there can be multiple tasks tied to the same chunk that want different
- * priorities.
- *
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param type Specified regionfile type.
- * @param priority New priority.
- *
- * @see #raisePriority(ServerLevel, int, int, Priority)
- * @see #raisePriority(ServerLevel, int, int, RegionFileType, Priority)
- * @see #lowerPriority(ServerLevel, int, int, Priority)
- * @see #lowerPriority(ServerLevel, int, int, RegionFileType, Priority)
- */
- public static void setPriority(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type,
- final Priority priority) {
- final RegionFileIOThread thread = RegionFileIOThread.selectThread(world, chunkX, chunkZ, type);
- thread.setPriorityInternal(world, chunkX, chunkZ, type, priority);
- }
-
- void setPriorityInternal(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type,
- final Priority priority) {
- final ChunkDataController taskController = getControllerFor(world, type);
- final ChunkDataTask task = taskController.tasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
-
- if (task != null) {
- task.prioritisedTask.setPriority(priority);
- }
- }
-
- /**
- * Raises the priority for all regionfile types for the specified chunk.
- *
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param priority New priority.
- *
- * @see #setPriority(ServerLevel, int, int, Priority)
- * @see #setPriority(ServerLevel, int, int, RegionFileType, Priority)
- * @see #lowerPriority(ServerLevel, int, int, Priority)
- * @see #lowerPriority(ServerLevel, int, int, RegionFileType, Priority)
- */
- public static void raisePriority(final ServerLevel world, final int chunkX, final int chunkZ,
- final Priority priority) {
- for (final RegionFileType type : CACHED_REGIONFILE_TYPES) {
- RegionFileIOThread.raisePriority(world, chunkX, chunkZ, type, priority);
- }
- }
-
- /**
- * Raises the priority for the specified regionfile type for the specified chunk.
- *
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param type Specified regionfile type.
- * @param priority New priority.
- *
- * @see #setPriority(ServerLevel, int, int, Priority)
- * @see #setPriority(ServerLevel, int, int, RegionFileType, Priority)
- * @see #lowerPriority(ServerLevel, int, int, Priority)
- * @see #lowerPriority(ServerLevel, int, int, RegionFileType, Priority)
- */
- public static void raisePriority(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type,
- final Priority priority) {
- final RegionFileIOThread thread = RegionFileIOThread.selectThread(world, chunkX, chunkZ, type);
- thread.raisePriorityInternal(world, chunkX, chunkZ, type, priority);
- }
-
- void raisePriorityInternal(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type,
- final Priority priority) {
- final ChunkDataController taskController = getControllerFor(world, type);
- final ChunkDataTask task = taskController.tasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
-
- if (task != null) {
- task.prioritisedTask.raisePriority(priority);
- }
- }
-
- /**
- * Lowers the priority for all regionfile types for the specified chunk.
- *
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param priority New priority.
- *
- * @see #raisePriority(ServerLevel, int, int, Priority)
- * @see #raisePriority(ServerLevel, int, int, RegionFileType, Priority)
- * @see #setPriority(ServerLevel, int, int, Priority)
- * @see #setPriority(ServerLevel, int, int, RegionFileType, Priority)
- */
- public static void lowerPriority(final ServerLevel world, final int chunkX, final int chunkZ,
- final Priority priority) {
- for (final RegionFileType type : CACHED_REGIONFILE_TYPES) {
- RegionFileIOThread.lowerPriority(world, chunkX, chunkZ, type, priority);
- }
- }
-
- /**
- * Lowers the priority for the specified regionfile type for the specified chunk.
- *
- * @param world Specified world.
- * @param chunkX Specified chunk x.
- * @param chunkZ Specified chunk z.
- * @param type Specified regionfile type.
- * @param priority New priority.
- *
- * @see #raisePriority(ServerLevel, int, int, Priority)
- * @see #raisePriority(ServerLevel, int, int, RegionFileType, Priority)
- * @see #setPriority(ServerLevel, int, int, Priority)
- * @see #setPriority(ServerLevel, int, int, RegionFileType, Priority)
- */
- public static void lowerPriority(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type,
- final Priority priority) {
- final RegionFileIOThread thread = RegionFileIOThread.selectThread(world, chunkX, chunkZ, type);
- thread.lowerPriorityInternal(world, chunkX, chunkZ, type, priority);
- }
-
- void lowerPriorityInternal(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type,
- final Priority priority) {
- final ChunkDataController taskController = getControllerFor(world, type);
- final ChunkDataTask task = taskController.tasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
-
- if (task != null) {
- task.prioritisedTask.lowerPriority(priority);
- }
- }
-
- /**
- * Schedules the chunk data to be written asynchronously.
- *
- * Impl notes:
- *
- *
- * This function presumes a chunk load for the coordinates is not called during this function (anytime after is OK). This means
- * saves must be scheduled before a chunk is unloaded.
- *
- *
- * Writes may be called concurrently, although only the "later" write will go through.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param data Chunk's data
- * @param type The regionfile type to write to.
- *
- * @throws IllegalStateException If the file io thread has shutdown.
- */
- public static void scheduleSave(final ServerLevel world, final int chunkX, final int chunkZ, final CompoundTag data,
- final RegionFileType type) {
- RegionFileIOThread.scheduleSave(world, chunkX, chunkZ, data, type, Priority.NORMAL);
- }
-
- /**
- * Schedules the chunk data to be written asynchronously.
- *
- * Impl notes:
- *
- *
- * This function presumes a chunk load for the coordinates is not called during this function (anytime after is OK). This means
- * saves must be scheduled before a chunk is unloaded.
- *
- *
- * Writes may be called concurrently, although only the "later" write will go through.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param data Chunk's data
- * @param type The regionfile type to write to.
- * @param priority The minimum priority to schedule at.
- *
- * @throws IllegalStateException If the file io thread has shutdown.
- */
- public static void scheduleSave(final ServerLevel world, final int chunkX, final int chunkZ, final CompoundTag data,
- final RegionFileType type, final Priority priority) {
- final RegionFileIOThread thread = RegionFileIOThread.selectThread(world, chunkX, chunkZ, type);
- thread.scheduleSaveInternal(world, chunkX, chunkZ, data, type, priority);
- }
-
- void scheduleSaveInternal(final ServerLevel world, final int chunkX, final int chunkZ, final CompoundTag data,
- final RegionFileType type, final Priority priority) {
- final ChunkDataController taskController = getControllerFor(world, type);
-
- final boolean[] created = new boolean[1];
- final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
- final ChunkDataTask task = taskController.tasks.compute(key, (final long keyInMap, final ChunkDataTask taskRunning) -> {
- if (taskRunning == null || taskRunning.failedWrite) {
- // no task is scheduled or the previous write failed - meaning we need to overwrite it
-
- // create task
- final ChunkDataTask newTask = new ChunkDataTask(world, chunkX, chunkZ, taskController, RegionFileIOThread.this, priority);
- newTask.inProgressWrite = data;
- created[0] = true;
-
- return newTask;
- }
-
- taskRunning.inProgressWrite = data;
-
- return taskRunning;
- });
-
- if (created[0]) {
- task.prioritisedTask.queue();
- } else {
- task.prioritisedTask.raisePriority(priority);
- }
- }
-
- /**
- * Schedules a load to be executed asynchronously. This task will load all regionfile types, and then call
- * {@code onComplete}. This is a bulk load operation, see {@link #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean)}
- * for single load.
- *
- * Impl notes:
- *
- *
- * The {@code onComplete} parameter may be completed during the execution of this function synchronously or it may
- * be completed asynchronously on this file io thread. Interacting with the file IO thread in the completion of
- * data is undefined behaviour, and can cause deadlock.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param onComplete Consumer to execute once this task has completed
- * @param intendingToBlock Whether the caller is intending to block on completion. This only affects the cost
- * of this call.
- *
- * @return The {@link Cancellable} for this chunk load. Cancelling it will not affect other loads for the same chunk data.
- *
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean)
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean, Priority)
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, RegionFileType...)
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, Priority, RegionFileType...)
- */
- public static Cancellable loadAllChunkData(final ServerLevel world, final int chunkX, final int chunkZ,
- final Consumer onComplete, final boolean intendingToBlock) {
- return RegionFileIOThread.loadAllChunkData(world, chunkX, chunkZ, onComplete, intendingToBlock, Priority.NORMAL);
- }
-
- /**
- * Schedules a load to be executed asynchronously. This task will load all regionfile types, and then call
- * {@code onComplete}. This is a bulk load operation, see {@link #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean, Priority)}
- * for single load.
- *
- * Impl notes:
- *
- *
- * The {@code onComplete} parameter may be completed during the execution of this function synchronously or it may
- * be completed asynchronously on this file io thread. Interacting with the file IO thread in the completion of
- * data is undefined behaviour, and can cause deadlock.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param onComplete Consumer to execute once this task has completed
- * @param intendingToBlock Whether the caller is intending to block on completion. This only affects the cost
- * of this call.
- * @param priority The minimum priority to load the data at.
- *
- * @return The {@link Cancellable} for this chunk load. Cancelling it will not affect other loads for the same chunk data.
- *
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean)
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean, Priority)
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, RegionFileType...)
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, Priority, RegionFileType...)
- */
- public static Cancellable loadAllChunkData(final ServerLevel world, final int chunkX, final int chunkZ,
- final Consumer onComplete, final boolean intendingToBlock,
- final Priority priority) {
- return RegionFileIOThread.loadChunkData(world, chunkX, chunkZ, onComplete, intendingToBlock, priority, CACHED_REGIONFILE_TYPES);
- }
-
- /**
- * Schedules a load to be executed asynchronously. This task will load data for the specified regionfile type(s), and
- * then call {@code onComplete}. This is a bulk load operation, see {@link #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean)}
- * for single load.
- *
- * Impl notes:
- *
- *
- * The {@code onComplete} parameter may be completed during the execution of this function synchronously or it may
- * be completed asynchronously on this file io thread. Interacting with the file IO thread in the completion of
- * data is undefined behaviour, and can cause deadlock.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param onComplete Consumer to execute once this task has completed
- * @param intendingToBlock Whether the caller is intending to block on completion. This only affects the cost
- * of this call.
- * @param types The regionfile type(s) to load.
- *
- * @return The {@link Cancellable} for this chunk load. Cancelling it will not affect other loads for the same chunk data.
- *
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean)
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean, Priority)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean, Priority)
- */
- public static Cancellable loadChunkData(final ServerLevel world, final int chunkX, final int chunkZ,
- final Consumer onComplete, final boolean intendingToBlock,
- final RegionFileType... types) {
- return RegionFileIOThread.loadChunkData(world, chunkX, chunkZ, onComplete, intendingToBlock, Priority.NORMAL, types);
- }
-
- /**
- * Schedules a load to be executed asynchronously. This task will load data for the specified regionfile type(s), and
- * then call {@code onComplete}. This is a bulk load operation, see {@link #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean, Priority)}
- * for single load.
- *
- * Impl notes:
- *
- *
- * The {@code onComplete} parameter may be completed during the execution of this function synchronously or it may
- * be completed asynchronously on this file io thread. Interacting with the file IO thread in the completion of
- * data is undefined behaviour, and can cause deadlock.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param onComplete Consumer to execute once this task has completed
- * @param intendingToBlock Whether the caller is intending to block on completion. This only affects the cost
- * of this call.
- * @param types The regionfile type(s) to load.
- * @param priority The minimum priority to load the data at.
- *
- * @return The {@link Cancellable} for this chunk load. Cancelling it will not affect other loads for the same chunk data.
- *
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean)
- * @see #loadDataAsync(ServerLevel, int, int, RegionFileType, BiConsumer, boolean, Priority)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean, Priority)
- */
- public static Cancellable loadChunkData(final ServerLevel world, final int chunkX, final int chunkZ,
- final Consumer onComplete, final boolean intendingToBlock,
- final Priority priority, final RegionFileType... types) {
- if (types == null) {
- throw new NullPointerException("Types cannot be null");
- }
- if (types.length == 0) {
- throw new IllegalArgumentException("Types cannot be empty");
- }
-
- final RegionFileData ret = new RegionFileData();
-
- final Cancellable[] reads = new CancellableRead[types.length];
- final AtomicInteger completions = new AtomicInteger();
- final int expectedCompletions = types.length;
-
- for (int i = 0; i < expectedCompletions; ++i) {
- final RegionFileType type = types[i];
- reads[i] = RegionFileIOThread.loadDataAsync(world, chunkX, chunkZ, type,
- (final CompoundTag data, final Throwable throwable) -> {
- if (throwable != null) {
- ret.setThrowable(type, throwable);
- } else {
- ret.setData(type, data);
- }
-
- if (completions.incrementAndGet() == expectedCompletions) {
- onComplete.accept(ret);
- }
- }, intendingToBlock, priority);
- }
-
- return new CancellableReads(reads);
- }
-
- /**
- * Schedules a load to be executed asynchronously. This task will load the specified regionfile type, and then call
- * {@code onComplete}.
- *
- * Impl notes:
- *
- *
- * The {@code onComplete} parameter may be completed during the execution of this function synchronously or it may
- * be completed asynchronously on this file io thread. Interacting with the file IO thread in the completion of
- * data is undefined behaviour, and can cause deadlock.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param onComplete Consumer to execute once this task has completed
- * @param intendingToBlock Whether the caller is intending to block on completion. This only affects the cost
- * of this call.
- *
- * @return The {@link Cancellable} for this chunk load. Cancelling it will not affect other loads for the same chunk data.
- *
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, RegionFileType...)
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, Priority, RegionFileType...)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean, Priority)
- */
- public static Cancellable loadDataAsync(final ServerLevel world, final int chunkX, final int chunkZ,
- final RegionFileType type, final BiConsumer onComplete,
- final boolean intendingToBlock) {
- return RegionFileIOThread.loadDataAsync(world, chunkX, chunkZ, type, onComplete, intendingToBlock, Priority.NORMAL);
- }
-
- /**
- * Schedules a load to be executed asynchronously. This task will load the specified regionfile type, and then call
- * {@code onComplete}.
- *
- * Impl notes:
- *
- *
- * The {@code onComplete} parameter may be completed during the execution of this function synchronously or it may
- * be completed asynchronously on this file io thread. Interacting with the file IO thread in the completion of
- * data is undefined behaviour, and can cause deadlock.
- *
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param onComplete Consumer to execute once this task has completed
- * @param intendingToBlock Whether the caller is intending to block on completion. This only affects the cost
- * of this call.
- * @param priority Minimum priority to load the data at.
- *
- * @return The {@link Cancellable} for this chunk load. Cancelling it will not affect other loads for the same chunk data.
- *
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, RegionFileType...)
- * @see #loadChunkData(ServerLevel, int, int, Consumer, boolean, Priority, RegionFileType...)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean)
- * @see #loadAllChunkData(ServerLevel, int, int, Consumer, boolean, Priority)
- */
- public static Cancellable loadDataAsync(final ServerLevel world, final int chunkX, final int chunkZ,
- final RegionFileType type, final BiConsumer onComplete,
- final boolean intendingToBlock, final Priority priority) {
- final RegionFileIOThread thread = RegionFileIOThread.selectThread(world, chunkX, chunkZ, type);
- return thread.loadDataAsyncInternal(world, chunkX, chunkZ, type, onComplete, intendingToBlock, priority);
- }
-
- Cancellable loadDataAsyncInternal(final ServerLevel world, final int chunkX, final int chunkZ,
- final RegionFileType type, final BiConsumer onComplete,
- final boolean intendingToBlock, final Priority priority) {
- final ChunkDataController taskController = getControllerFor(world, type);
-
- final ImmediateCallbackCompletion callbackInfo = new ImmediateCallbackCompletion();
-
- final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
- final BiLong1Function compute = (final long keyInMap, final ChunkDataTask running) -> {
- if (running == null) {
- // not scheduled
-
- // set up task
- final ChunkDataTask newTask = new ChunkDataTask(
- world, chunkX, chunkZ, taskController, RegionFileIOThread.this, priority
- );
- newTask.inProgressRead = new InProgressRead();
- newTask.inProgressRead.addToAsyncWaiters(onComplete);
-
- callbackInfo.tasksNeedsScheduling = true;
- return newTask;
- }
-
- final CompoundTag pendingWrite = running.inProgressWrite;
-
- if (pendingWrite == ChunkDataTask.NOTHING_TO_WRITE) {
- // need to add to waiters here, because the regionfile thread will use compute() to lock and check for cancellations
- if (!running.inProgressRead.addToAsyncWaiters(onComplete)) {
- callbackInfo.data = running.inProgressRead.value;
- callbackInfo.throwable = running.inProgressRead.throwable;
- callbackInfo.completeNow = true;
- }
- return running;
- }
-
- // at this stage we have to use the in progress write's data to avoid an order issue
- callbackInfo.data = pendingWrite;
- callbackInfo.throwable = null;
- callbackInfo.completeNow = true;
- return running;
- };
-
- final ChunkDataTask ret = taskController.tasks.compute(key, compute);
-
- // needs to be scheduled
- if (callbackInfo.tasksNeedsScheduling) {
- ret.prioritisedTask.queue();
- } else if (callbackInfo.completeNow) {
- try {
- onComplete.accept(callbackInfo.data == null ? null : callbackInfo.data.copy(), callbackInfo.throwable);
- } catch (final Throwable thr) {
- LOGGER.error("Callback " + ConcurrentUtil.genericToString(onComplete) + " synchronously failed to handle chunk data for task " + ret.toString(), thr);
- }
- } else {
- // we're waiting on a task we didn't schedule, so raise its priority to what we want
- ret.prioritisedTask.raisePriority(priority);
- }
-
- return new CancellableRead(onComplete, ret);
- }
-
- /**
- * Schedules a load task to be executed asynchronously, and blocks on that task.
- *
- * @param world Chunk's world
- * @param chunkX Chunk's x coordinate
- * @param chunkZ Chunk's z coordinate
- * @param type Regionfile type
- * @param priority Minimum priority to load the data at.
- *
- * @return The chunk data for the chunk. Note that a {@code null} result means the chunk or regionfile does not exist on disk.
- *
- * @throws IOException If the load fails for any reason
- */
- public static CompoundTag loadData(final ServerLevel world, final int chunkX, final int chunkZ, final RegionFileType type,
- final Priority priority) throws IOException {
- final CompletableFuture ret = new CompletableFuture<>();
-
- RegionFileIOThread.loadDataAsync(world, chunkX, chunkZ, type, (final CompoundTag compound, final Throwable thr) -> {
- if (thr != null) {
- ret.completeExceptionally(thr);
- } else {
- ret.complete(compound);
- }
- }, true, priority);
-
- try {
- return ret.join();
- } catch (final CompletionException ex) {
- throw new IOException(ex);
- }
- }
-
- private static final class ImmediateCallbackCompletion {
-
- public CompoundTag data;
- public Throwable throwable;
- public boolean completeNow;
- public boolean tasksNeedsScheduling;
-
- }
-
- private static final class CancellableRead implements Cancellable {
-
- private BiConsumer callback;
- private ChunkDataTask task;
-
- CancellableRead(final BiConsumer callback, final ChunkDataTask task) {
- this.callback = callback;
- this.task = task;
- }
-
- @Override
- public boolean cancel() {
- final BiConsumer callback = this.callback;
- final ChunkDataTask task = this.task;
-
- if (callback == null || task == null) {
- return false;
- }
-
- this.callback = null;
- this.task = null;
-
- final InProgressRead read = task.inProgressRead;
-
- // read can be null if no read was scheduled (i.e no regionfile existed or chunk in regionfile didn't)
- return read != null && read.cancel(callback);
- }
- }
-
- private static final class CancellableReads implements Cancellable {
-
- private Cancellable[] reads;
-
- private static final VarHandle READS_HANDLE = ConcurrentUtil.getVarHandle(CancellableReads.class, "reads", Cancellable[].class);
-
- CancellableReads(final Cancellable[] reads) {
- this.reads = reads;
- }
-
- @Override
- public boolean cancel() {
- final Cancellable[] reads = (Cancellable[])READS_HANDLE.getAndSet((CancellableReads)this, (Cancellable[])null);
-
- if (reads == null) {
- return false;
- }
-
- boolean ret = false;
-
- for (final Cancellable read : reads) {
- ret |= read.cancel();
- }
-
- return ret;
- }
- }
-
- private static final class InProgressRead {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(InProgressRead.class);
-
- private CompoundTag value;
- private Throwable throwable;
- private final MultiThreadedQueue> callbacks = new MultiThreadedQueue<>();
-
- public boolean hasNoWaiters() {
- return this.callbacks.isEmpty();
- }
-
- public boolean addToAsyncWaiters(final BiConsumer callback) {
- return this.callbacks.add(callback);
- }
-
- public boolean cancel(final BiConsumer callback) {
- return this.callbacks.remove(callback);
- }
-
- public void complete(final ChunkDataTask task, final CompoundTag value, final Throwable throwable) {
- this.value = value;
- this.throwable = throwable;
-
- BiConsumer consumer;
- while ((consumer = this.callbacks.pollOrBlockAdds()) != null) {
- try {
- consumer.accept(value == null ? null : value.copy(), throwable);
- } catch (final Throwable thr) {
- LOGGER.error("Callback " + ConcurrentUtil.genericToString(consumer) + " failed to handle chunk data for task " + task.toString(), thr);
- }
- }
- }
- }
-
- public static abstract class ChunkDataController {
-
- // ConcurrentHashMap synchronizes per chain, so reduce the chance of task's hashes colliding.
- private final ConcurrentLong2ReferenceChainedHashTable tasks = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(8192, 0.5f);
-
- public final RegionFileType type;
-
- public ChunkDataController(final RegionFileType type) {
- this.type = type;
- }
-
- public abstract RegionFileStorage getCache();
-
- public abstract void writeData(final int chunkX, final int chunkZ, final CompoundTag compound) throws IOException;
-
- public abstract CompoundTag readData(final int chunkX, final int chunkZ) throws IOException;
-
- public boolean hasTasks() {
- return !this.tasks.isEmpty();
- }
-
- public boolean doesRegionFileNotExist(final int chunkX, final int chunkZ) {
- return ((ChunkSystemRegionFileStorage)(Object)this.getCache()).moonrise$doesRegionFileNotExistNoIO(chunkX, chunkZ);
- }
-
- public T computeForRegionFile(final int chunkX, final int chunkZ, final boolean existingOnly, final Function function) {
- final RegionFileStorage cache = this.getCache();
- final RegionFile regionFile;
- synchronized (cache) {
- try {
- if (existingOnly) {
- regionFile = ((ChunkSystemRegionFileStorage)(Object)cache).moonrise$getRegionFileIfExists(chunkX, chunkZ);
- } else {
- regionFile = cache.getRegionFile(new ChunkPos(chunkX, chunkZ), existingOnly);
- }
- } catch (final IOException ex) {
- throw new RuntimeException(ex);
- }
-
- return function.apply(regionFile);
- }
- }
-
- public T computeForRegionFileIfLoaded(final int chunkX, final int chunkZ, final Function function) {
- final RegionFileStorage cache = this.getCache();
- final RegionFile regionFile;
-
- synchronized (cache) {
- regionFile = ((ChunkSystemRegionFileStorage)(Object)cache).moonrise$getRegionFileIfLoaded(chunkX, chunkZ);
-
- return function.apply(regionFile);
- }
- }
- }
-
- private static final class ChunkDataTask implements Runnable {
-
- private static final CompoundTag NOTHING_TO_WRITE = new CompoundTag();
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ChunkDataTask.class);
-
- private InProgressRead inProgressRead;
- private volatile CompoundTag inProgressWrite = NOTHING_TO_WRITE; // only needs to be acquire/release
-
- private boolean failedWrite;
-
- private final ServerLevel world;
- private final int chunkX;
- private final int chunkZ;
- private final ChunkDataController taskController;
-
- private final PrioritisedTask prioritisedTask;
-
- /*
- * IO thread will perform reads before writes for a given chunk x and z
- *
- * How reads/writes are scheduled:
- *
- * If read is scheduled while scheduling write, take no special action and just schedule write
- * If read is scheduled while scheduling read and no write is scheduled, chain the read task
- *
- *
- * If write is scheduled while scheduling read, use the pending write data and ret immediately (so no read is scheduled)
- * If write is scheduled while scheduling write (ignore read in progress), overwrite the write in progress data
- *
- * This allows the reads and writes to act as if they occur synchronously to the thread scheduling them, however
- * it fails to properly propagate write failures thanks to writes overwriting each other
- */
-
- public ChunkDataTask(final ServerLevel world, final int chunkX, final int chunkZ, final ChunkDataController taskController,
- final PrioritisedExecutor executor, final Priority priority) {
- this.world = world;
- this.chunkX = chunkX;
- this.chunkZ = chunkZ;
- this.taskController = taskController;
- this.prioritisedTask = executor.createTask(this, priority);
- }
-
- @Override
- public String toString() {
- return "Task for world: '" + WorldUtil.getWorldName(this.world) + "' at (" + this.chunkX + "," + this.chunkZ +
- ") type: " + this.taskController.type.name() + ", hash: " + this.hashCode();
- }
-
- @Override
- public void run() {
- final InProgressRead read = this.inProgressRead;
- final long chunkKey = CoordinateUtils.getChunkKey(this.chunkX, this.chunkZ);
-
- if (read != null) {
- final boolean[] canRead = new boolean[] { true };
-
- if (read.hasNoWaiters()) {
- // cancelled read? go to task controller to confirm
- final ChunkDataTask inMap = this.taskController.tasks.compute(chunkKey, (final long keyInMap, final ChunkDataTask valueInMap) -> {
- if (valueInMap == null) {
- throw new IllegalStateException("Write completed concurrently, expected this task: " + ChunkDataTask.this.toString() + ", report this!");
- }
- if (valueInMap != ChunkDataTask.this) {
- throw new IllegalStateException("Chunk task mismatch, expected this task: " + ChunkDataTask.this.toString() + ", got: " + valueInMap.toString() + ", report this!");
- }
-
- if (!read.hasNoWaiters()) {
- return valueInMap;
- } else {
- canRead[0] = false;
- }
-
- return valueInMap.inProgressWrite == NOTHING_TO_WRITE ? null : valueInMap;
- });
-
- if (inMap == null) {
- // read is cancelled - and no write pending, so we're done
- return;
- }
- // if there is a write in progress, we don't actually have to worry about waiters gaining new entries -
- // the readers will just use the in progress write, so the value in canRead is good to use without
- // further synchronisation.
- }
-
- if (canRead[0]) {
- CompoundTag compound = null;
- Throwable throwable = null;
-
- try {
- compound = this.taskController.readData(this.chunkX, this.chunkZ);
- } catch (final Throwable thr) {
- throwable = thr;
- LOGGER.error("Failed to read chunk data for task: " + this.toString(), thr);
- }
- read.complete(this, compound, throwable);
- }
- }
-
- CompoundTag write = this.inProgressWrite;
-
- if (write == NOTHING_TO_WRITE) {
- final ChunkDataTask inMap = this.taskController.tasks.compute(chunkKey, (final long keyInMap, final ChunkDataTask valueInMap) -> {
- if (valueInMap == null) {
- throw new IllegalStateException("Write completed concurrently, expected this task: " + ChunkDataTask.this.toString() + ", report this!");
- }
- if (valueInMap != ChunkDataTask.this) {
- throw new IllegalStateException("Chunk task mismatch, expected this task: " + ChunkDataTask.this.toString() + ", got: " + valueInMap.toString() + ", report this!");
- }
- return valueInMap.inProgressWrite == NOTHING_TO_WRITE ? null : valueInMap;
- });
-
- if (inMap == null) {
- return; // set the task value to null, indicating we're done
- } // else: inProgressWrite changed, so now we have something to write
- }
-
- for (;;) {
- write = this.inProgressWrite;
- final CompoundTag dataWritten = write;
-
- boolean failedWrite = false;
-
- try {
- this.taskController.writeData(this.chunkX, this.chunkZ, write);
- } catch (final Throwable thr) {
- if (thr instanceof RegionFileStorage.RegionFileSizeException) {
- final int maxSize = RegionFile.MAX_CHUNK_SIZE / (1024 * 1024);
- LOGGER.error("Chunk at (" + this.chunkX + "," + this.chunkZ + ") in '" + WorldUtil.getWorldName(this.world) + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk.");
- } else {
- failedWrite = thr instanceof IOException;
- LOGGER.error("Failed to write chunk data for task: " + this.toString(), thr);
- }
- }
-
- final boolean finalFailWrite = failedWrite;
- final boolean[] done = new boolean[] { false };
-
- this.taskController.tasks.compute(chunkKey, (final long keyInMap, final ChunkDataTask valueInMap) -> {
- if (valueInMap == null) {
- throw new IllegalStateException("Write completed concurrently, expected this task: " + ChunkDataTask.this.toString() + ", report this!");
- }
- if (valueInMap != ChunkDataTask.this) {
- throw new IllegalStateException("Chunk task mismatch, expected this task: " + ChunkDataTask.this.toString() + ", got: " + valueInMap.toString() + ", report this!");
- }
- if (valueInMap.inProgressWrite == dataWritten) {
- valueInMap.failedWrite = finalFailWrite;
- done[0] = true;
- // keep the data in map if we failed the write so we can try to prevent data loss
- return finalFailWrite ? valueInMap : null;
- }
- // different data than expected, means we need to retry write
- return valueInMap;
- });
-
- if (done[0]) {
- return;
- }
-
- // fetch & write new data
- continue;
- }
- }
- }
-}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/ChunkDataController.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/ChunkDataController.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/ChunkDataController.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/ChunkDataController.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
+import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemChunkMap;
+import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkStorage;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import java.io.IOException;
-import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
-public final class ChunkDataController extends RegionFileIOThread.ChunkDataController {
+public final class ChunkDataController extends MoonriseRegionFileIO.RegionDataController {
private final ServerLevel world;
- public ChunkDataController(final ServerLevel world) {
- super(RegionFileIOThread.RegionFileType.CHUNK_DATA);
+ public ChunkDataController(final ServerLevel world, final ChunkTaskScheduler taskScheduler) {
+ super(MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, taskScheduler.ioExecutor, taskScheduler.compressionExecutor);
this.world = world;
}
@@ -0,0 +0,0 @@ public final class ChunkDataController extends RegionFileIOThread.ChunkDataContr
}
@Override
- public void writeData(final int chunkX, final int chunkZ, final CompoundTag compound) throws IOException {
- final CompletableFuture future = this.world.getChunkSource().chunkMap.write(new ChunkPos(chunkX, chunkZ), compound);
-
- try {
- if (future != null) {
- // rets non-null when sync writing (i.e. future should be completed here)
- future.join();
- }
- } catch (final CompletionException ex) {
- if (ex.getCause() instanceof IOException ioException) {
- throw ioException;
- }
- throw ex;
- }
+ public WriteData startWrite(final int chunkX, final int chunkZ, final CompoundTag compound) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$startWrite(chunkX, chunkZ, compound);
}
@Override
- public CompoundTag readData(final int chunkX, final int chunkZ) throws IOException {
- try {
- return this.world.getChunkSource().chunkMap.read(new ChunkPos(chunkX, chunkZ)).join().orElse(null);
- } catch (final CompletionException ex) {
- if (ex.getCause() instanceof IOException ioException) {
- throw ioException;
- }
- throw ex;
- }
+ public void finishWrite(final int chunkX, final int chunkZ, final WriteData writeData) throws IOException {
+ ((ChunkSystemChunkMap)this.world.getChunkSource().chunkMap).moonrise$writeFinishCallback(new ChunkPos(chunkX, chunkZ));
+ ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$finishWrite(chunkX, chunkZ, writeData);
+ }
+
+ @Override
+ public ReadData readData(final int chunkX, final int chunkZ) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$readData(chunkX, chunkZ);
+ }
+
+ @Override
+ public CompoundTag finishRead(final int chunkX, final int chunkZ, final ReadData readData) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$finishRead(chunkX, chunkZ, readData);
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/EntityDataController.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/EntityDataController.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/EntityDataController.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/EntityDataController.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
+import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.EntityStorage;
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
import java.io.IOException;
import java.nio.file.Path;
-public final class EntityDataController extends RegionFileIOThread.ChunkDataController {
+public final class EntityDataController extends MoonriseRegionFileIO.RegionDataController {
private final EntityRegionFileStorage storage;
- public EntityDataController(final EntityRegionFileStorage storage) {
- super(RegionFileIOThread.RegionFileType.ENTITY_DATA);
+ public EntityDataController(final EntityRegionFileStorage storage, final ChunkTaskScheduler taskScheduler) {
+ super(MoonriseRegionFileIO.RegionFileType.ENTITY_DATA, taskScheduler.ioExecutor, taskScheduler.compressionExecutor);
this.storage = storage;
}
@@ -0,0 +0,0 @@ public final class EntityDataController extends RegionFileIOThread.ChunkDataCont
}
@Override
- public void writeData(final int chunkX, final int chunkZ, final CompoundTag compound) throws IOException {
- this.storage.write(new ChunkPos(chunkX, chunkZ), compound);
+ public WriteData startWrite(final int chunkX, final int chunkZ, final CompoundTag compound) throws IOException {
+ checkPosition(new ChunkPos(chunkX, chunkZ), compound);
+
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$startWrite(chunkX, chunkZ, compound);
+ }
+
+ @Override
+ public void finishWrite(final int chunkX, final int chunkZ, final WriteData writeData) throws IOException {
+ ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$finishWrite(chunkX, chunkZ, writeData);
+ }
+
+ @Override
+ public ReadData readData(final int chunkX, final int chunkZ) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$readData(chunkX, chunkZ);
}
@Override
- public CompoundTag readData(final int chunkX, final int chunkZ) throws IOException {
- return this.storage.read(new ChunkPos(chunkX, chunkZ));
+ public CompoundTag finishRead(final int chunkX, final int chunkZ, final ReadData readData) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$finishRead(chunkX, chunkZ, readData);
+ }
+
+ private static void checkPosition(final ChunkPos pos, final CompoundTag nbt) {
+ final ChunkPos nbtPos = nbt == null ? null : EntityStorage.readChunkPos(nbt);
+ if (nbtPos != null && !pos.equals(nbtPos)) {
+ throw new IllegalArgumentException(
+ "Entity chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos.toString()
+ + " but compound says coordinate is " + nbtPos
+ );
+ }
}
public static final class EntityRegionFileStorage extends RegionFileStorage {
@@ -0,0 +0,0 @@ public final class EntityDataController extends RegionFileIOThread.ChunkDataCont
@Override
public void write(final ChunkPos pos, final CompoundTag nbt) throws IOException {
- final ChunkPos nbtPos = nbt == null ? null : EntityStorage.readChunkPos(nbt);
- if (nbtPos != null && !pos.equals(nbtPos)) {
- throw new IllegalArgumentException(
- "Entity chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos.toString()
- + " but compound says coordinate is " + nbtPos + " for world: " + this
- );
- }
+ checkPosition(pos, nbt);
super.write(pos, nbt);
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/PoiDataController.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/PoiDataController.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/PoiDataController.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/datacontroller/PoiDataController.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import ca.spottedleaf.moonrise.patches.chunk_system.level.storage.ChunkSystemSectionStorage;
+import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import java.io.IOException;
-public final class PoiDataController extends RegionFileIOThread.ChunkDataController {
+public final class PoiDataController extends MoonriseRegionFileIO.RegionDataController {
private final ServerLevel world;
- public PoiDataController(final ServerLevel world) {
- super(RegionFileIOThread.RegionFileType.POI_DATA);
+ public PoiDataController(final ServerLevel world, final ChunkTaskScheduler taskScheduler) {
+ super(MoonriseRegionFileIO.RegionFileType.POI_DATA, taskScheduler.ioExecutor, taskScheduler.compressionExecutor);
this.world = world;
}
@@ -0,0 +0,0 @@ public final class PoiDataController extends RegionFileIOThread.ChunkDataControl
}
@Override
- public void writeData(final int chunkX, final int chunkZ, final CompoundTag compound) throws IOException {
- ((ChunkSystemSectionStorage)this.world.getPoiManager()).moonrise$write(chunkX, chunkZ, compound);
+ public WriteData startWrite(final int chunkX, final int chunkZ, final CompoundTag compound) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$startWrite(chunkX, chunkZ, compound);
}
@Override
- public CompoundTag readData(final int chunkX, final int chunkZ) throws IOException {
- return ((ChunkSystemSectionStorage)this.world.getPoiManager()).moonrise$read(chunkX, chunkZ);
+ public void finishWrite(final int chunkX, final int chunkZ, final WriteData writeData) throws IOException {
+ ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$finishWrite(chunkX, chunkZ, writeData);
+ }
+
+ @Override
+ public ReadData readData(final int chunkX, final int chunkZ) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$readData(chunkX, chunkZ);
+ }
+
+ @Override
+ public CompoundTag finishRead(final int chunkX, final int chunkZ, final ReadData readData) throws IOException {
+ return ((ChunkSystemRegionFileStorage)this.getCache()).moonrise$finishRead(chunkX, chunkZ, readData);
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemChunkMap.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemChunkMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemChunkMap.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.chunk_system.level;
+
+import net.minecraft.world.level.ChunkPos;
+import java.io.IOException;
+
+public interface ChunkSystemChunkMap {
+
+ public void moonrise$writeFinishCallback(final ChunkPos pos) throws IOException;
+
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level;
+import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
@@ -0,0 +0,0 @@ public interface ChunkSystemLevel {
public void moonrise$midTickTasks();
+ public ChunkData moonrise$getChunkData(final long chunkKey);
+
+ public ChunkData moonrise$getChunkData(final int chunkX, final int chunkZ);
+
+ public ChunkData moonrise$requestChunkData(final long chunkKey);
+
+ public ChunkData moonrise$releaseChunkData(final long chunkKey);
+
+ public boolean moonrise$areChunksLoaded(final int fromX, final int fromZ, final int toX, final int toZ);
+
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.list.ReferenceList;
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import net.minecraft.core.BlockPos;
+import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.status.ChunkStatus;
@@ -0,0 +0,0 @@ public interface ChunkSystemServerLevel extends ChunkSystemLevel {
public ChunkTaskScheduler moonrise$getChunkTaskScheduler();
- public RegionFileIOThread.ChunkDataController moonrise$getChunkDataController();
+ public MoonriseRegionFileIO.RegionDataController moonrise$getChunkDataController();
- public RegionFileIOThread.ChunkDataController moonrise$getPoiChunkDataController();
+ public MoonriseRegionFileIO.RegionDataController moonrise$getPoiChunkDataController();
- public RegionFileIOThread.ChunkDataController moonrise$getEntityChunkDataController();
+ public MoonriseRegionFileIO.RegionDataController moonrise$getEntityChunkDataController();
public int moonrise$getRegionChunkShift();
- // Paper - marked closing not needed on CB
+ public boolean moonrise$isMarkedClosing();
+
+ public void moonrise$setMarkedClosing(final boolean value);
public RegionizedPlayerChunkLoader moonrise$getPlayerChunkLoader();
public void moonrise$loadChunksAsync(final BlockPos pos, final int radiusBlocks,
- final PrioritisedExecutor.Priority priority,
+ final Priority priority,
final Consumer> onLoad);
public void moonrise$loadChunksAsync(final BlockPos pos, final int radiusBlocks,
- final ChunkStatus chunkStatus, final PrioritisedExecutor.Priority priority,
+ final ChunkStatus chunkStatus, final Priority priority,
final Consumer> onLoad);
public void moonrise$loadChunksAsync(final int minChunkX, final int maxChunkX, final int minChunkZ, final int maxChunkZ,
- final PrioritisedExecutor.Priority priority,
+ final Priority priority,
final Consumer> onLoad);
public void moonrise$loadChunksAsync(final int minChunkX, final int maxChunkX, final int minChunkZ, final int maxChunkZ,
- final ChunkStatus chunkStatus, final PrioritisedExecutor.Priority priority,
+ final ChunkStatus chunkStatus, final Priority priority,
final Consumer> onLoad);
public RegionizedPlayerChunkLoader.ViewDistanceHolder moonrise$getViewDistanceHolder();
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkData.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkData.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkData.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.chunk_system.level.chunk;
+
+import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
+
+public final class ChunkData {
+
+ private int referenceCount = 0;
+ public NearbyPlayers.TrackedChunk nearbyPlayers; // Moonrise - nearby players
+
+ public ChunkData() {
+
+ }
+
+ public int increaseRef() {
+ return ++this.referenceCount;
+ }
+
+ public int decreaseRef() {
+ return --this.referenceCount;
+ }
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemDistanceManager.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemDistanceManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemDistanceManager.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemDistanceManager.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level.chunk;
+import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
import net.minecraft.server.level.ChunkMap;
public interface ChunkSystemDistanceManager {
public ChunkMap moonrise$getChunkMap();
+ public ChunkHolderManager moonrise$getChunkHolderManager();
+
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level.entity;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.list.EntityList;
+import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
@@ -0,0 +0,0 @@ import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.boss.EnderDragonPart;
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
@@ -0,0 +0,0 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;
-import org.bukkit.event.entity.EntityRemoveEvent;
public final class ChunkEntitySlices {
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
private final EntityList entities = new EntityList();
public FullChunkStatus status;
+ public final ChunkData chunkData;
private boolean isTransient;
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
}
public ChunkEntitySlices(final Level world, final int chunkX, final int chunkZ, final FullChunkStatus status,
- final int minSection, final int maxSection) { // inclusive, inclusive
+ final ChunkData chunkData, final int minSection, final int maxSection) { // inclusive, inclusive
this.minSection = minSection;
this.maxSection = maxSection;
this.chunkX = chunkX;
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
this.entitiesByType = new Reference2ObjectOpenHashMap<>();
this.status = status;
+ this.chunkData = chunkData;
}
public static List readEntities(final ServerLevel world, final CompoundTag compoundTag) {
// TODO check this and below on update for format changes
- return EntityType.loadEntitiesRecursive(compoundTag.getList("Entities", 10), world).collect(ImmutableList.toImmutableList());
+ return EntityType.loadEntitiesRecursive(compoundTag.getList("Entities", 10), world, EntitySpawnReason.LOAD).collect(ImmutableList.toImmutableList());
}
// Paper start - rewrite chunk system
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
}
final ListTag entitiesTag = new ListTag();
- for (final Entity entity : entities) {
+ for (final Entity entity : PlatformHooks.get().modifySavedEntities(world, chunkPos.x, chunkPos.z, entities)) {
CompoundTag compoundTag = new CompoundTag();
if (entity.save(compoundTag)) {
entitiesTag.add(compoundTag);
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
continue;
}
if (entity.shouldBeSaved()) {
- entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, EntityRemoveEvent.Cause.UNLOAD);
+ PlatformHooks.get().unloadEntity(entity);
if (entity.isVehicle()) {
// we cannot assume that these entities are contained within this chunk, because entities can
// desync - so we need to remove them all
for (final Entity passenger : entity.getIndirectPassengers()) {
- passenger.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, EntityRemoveEvent.Cause.UNLOAD);
+ PlatformHooks.get().unloadEntity(passenger);
}
}
}
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
return this.entities.size() != 0;
}
- // Paper start
- public org.bukkit.entity.Entity[] getChunkEntities() {
- List ret = new java.util.ArrayList<>();
- final Entity[] entities = this.entities.getRawData();
- for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
- final Entity entity = entities[i];
- if (entity == null) {
- continue;
- }
- final org.bukkit.entity.Entity bukkit = entity.getBukkitEntity();
- if (bukkit != null && bukkit.isValid()) {
- ret.add(bukkit);
- }
- }
-
- return ret.toArray(new org.bukkit.entity.Entity[0]);
- }
-
- public void callEntitiesLoadEvent() {
- org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesLoadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
- }
-
- public void callEntitiesUnloadEvent() {
- org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
- }
- // Paper end
-
- private List getAllEntities() {
+ public List getAllEntities() {
final int len = this.entities.size();
if (len == 0) {
return new ArrayList<>();
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
return false;
}
((ChunkSystemEntity)entity).moonrise$setChunkStatus(this.status);
+ ((ChunkSystemEntity)entity).moonrise$setChunkData(this.chunkData);
final int sectionIndex = chunkSection - this.minSection;
this.allEntities.addEntity(entity, sectionIndex);
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
return false;
}
((ChunkSystemEntity)entity).moonrise$setChunkStatus(null);
+ ((ChunkSystemEntity)entity).moonrise$setChunkData(null);
final int sectionIndex = chunkSection - this.minSection;
this.allEntities.removeEntity(entity, sectionIndex);
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
protected final SWMRLong2ObjectHashTable regions = new SWMRLong2ObjectHashTable<>(128, 0.5f);
- protected final int minSection; // inclusive
- protected final int maxSection; // inclusive
protected final LevelCallback worldCallback;
protected final ConcurrentLong2ReferenceChainedHashTable entityById = new ConcurrentLong2ReferenceChainedHashTable<>();
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
public EntityLookup(final Level world, final LevelCallback worldCallback) {
this.world = world;
- this.minSection = WorldUtil.getMinSection(world);
- this.maxSection = WorldUtil.getMaxSection(world);
this.worldCallback = worldCallback;
}
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
protected abstract void entityEndTicking(final Entity entity);
- protected abstract boolean screenEntity(final Entity entity);
+ protected abstract boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event);
private static Entity maskNonAccessible(final Entity entity) {
if (entity == null) {
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
}
protected void addRecursivelySafe(final Entity root, final boolean fromDisk) {
- if (!this.addEntity(root, fromDisk)) {
+ if (!this.addEntity(root, fromDisk, true)) {
// possible we are a passenger, and so should dismount from any valid entity in the world
root.stopRiding();
return;
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
}
public boolean addNewEntity(final Entity entity) {
- return this.addEntity(entity, false);
+ return this.addNewEntity(entity, true);
+ }
+
+ public boolean addNewEntity(final Entity entity, final boolean event) {
+ return this.addEntity(entity, false, event);
}
public static Visibility getEntityStatus(final Entity entity) {
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
return Visibility.fromFullChunkStatus(entityStatus == null ? FullChunkStatus.INACCESSIBLE : entityStatus);
}
- protected boolean addEntity(final Entity entity, final boolean fromDisk) {
+ protected boolean addEntity(final Entity entity, final boolean fromDisk, final boolean event) {
final BlockPos pos = entity.blockPosition();
final int sectionX = pos.getX() >> 4;
- final int sectionY = Mth.clamp(pos.getY() >> 4, this.minSection, this.maxSection);
+ final int sectionY = Mth.clamp(pos.getY() >> 4, WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world));
final int sectionZ = pos.getZ() >> 4;
this.checkThread(sectionX, sectionZ, "Cannot add entity off-main thread");
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
return false;
}
- if (!this.screenEntity(entity)) {
+ if (!this.screenEntity(entity, fromDisk, event)) {
return false;
}
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
final int sectionZ = ((ChunkSystemEntity)entity).moonrise$getSectionZ();
final BlockPos newPos = entity.blockPosition();
final int newSectionX = newPos.getX() >> 4;
- final int newSectionY = Mth.clamp(newPos.getY() >> 4, this.minSection, this.maxSection);
+ final int newSectionY = Mth.clamp(newPos.getY() >> 4, WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world));
final int newSectionZ = newPos.getZ() >> 4;
if (newSectionX == sectionX && newSectionY == sectionY && newSectionZ == sectionZ) {
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
public ChunkEntitySlices getOrCreateChunk(final int chunkX, final int chunkZ) {
final ChunkSlicesRegion region = this.getRegion(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT);
- ChunkEntitySlices ret;
+ final ChunkEntitySlices ret;
if (region == null || (ret = region.get((chunkX & REGION_MASK) | ((chunkZ & REGION_MASK) << REGION_SHIFT))) == null) {
return this.createEntityChunk(chunkX, chunkZ, true);
}
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
@Override
public void onRemove(final Entity.RemovalReason reason) {
final Entity entity = this.entity;
- EntityLookup.this.checkThread(entity, "Cannot remove entity off-main"); // Paper - rewrite chunk system
+ EntityLookup.this.checkThread(entity, "Cannot remove entity off-main");
final Visibility tickingState = EntityLookup.getEntityStatus(entity);
EntityLookup.this.removeEntity(entity);
@@ -0,0 +0,0 @@ public abstract class EntityLookup implements LevelEntityGetter {
@Override
public void onRemove(final Entity.RemovalReason reason) {}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/client/ClientEntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/client/ClientEntityLookup.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/client/ClientEntityLookup.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/client/ClientEntityLookup.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level.entity.client;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
@@ -0,0 +0,0 @@ public final class ClientEntityLookup extends EntityLookup {
final ChunkEntitySlices ret = new ChunkEntitySlices(
this.world, chunkX, chunkZ,
- ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
+ ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
+ WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
);
// note: not handled by superclass
@@ -0,0 +0,0 @@ public final class ClientEntityLookup extends EntityLookup {
protected void entitySectionChangeCallback(final Entity entity,
final int oldSectionX, final int oldSectionY, final int oldSectionZ,
final int newSectionX, final int newSectionY, final int newSectionZ) {
-
+ PlatformHooks.get().entityMove(
+ entity,
+ CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
+ CoordinateUtils.getChunkSectionKey(newSectionX, newSectionY, newSectionZ)
+ );
}
@Override
@@ -0,0 +0,0 @@ public final class ClientEntityLookup extends EntityLookup {
}
@Override
- protected boolean screenEntity(final Entity entity) {
+ protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
return true;
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/dfl/DefaultEntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/dfl/DefaultEntityLookup.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/dfl/DefaultEntityLookup.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/dfl/DefaultEntityLookup.java
@@ -0,0 +0,0 @@ public final class DefaultEntityLookup extends EntityLookup {
protected ChunkEntitySlices createEntityChunk(final int chunkX, final int chunkZ, final boolean transientChunk) {
final ChunkEntitySlices ret = new ChunkEntitySlices(
this.world, chunkX, chunkZ, FullChunkStatus.FULL,
- WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
+ null, WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
);
// note: not handled by superclass
@@ -0,0 +0,0 @@ public final class DefaultEntityLookup extends EntityLookup {
}
@Override
- protected boolean screenEntity(final Entity entity) {
+ protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
return true;
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.list.ReferenceList;
+import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.TickThread;
import ca.spottedleaf.moonrise.common.util.ChunkSystem;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
@@ -0,0 +0,0 @@ public final class ServerEntityLookup extends EntityLookup {
private final ServerLevel serverWorld;
public final ReferenceList trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
- public final ReferenceList trackerUnloadedEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
public ServerEntityLookup(final ServerLevel world, final LevelCallback worldCallback) {
super(world, worldCallback);
@@ -0,0 +0,0 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer player) {
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().tickPlayer(player);
}
+ PlatformHooks.get().entityMove(
+ entity,
+ CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
+ CoordinateUtils.getChunkSectionKey(newSectionX, newSectionY, newSectionZ)
+ );
}
@Override
@@ -0,0 +0,0 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer player) {
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player);
}
- this.trackerUnloadedEntities.remove(entity); // Moonrise - entity tracker
}
@Override
protected void entityStartLoaded(final Entity entity) {
// Moonrise start - entity tracker
this.trackerEntities.add(entity);
- this.trackerUnloadedEntities.remove(entity);
// Moonrise end - entity tracker
}
@@ -0,0 +0,0 @@ public final class ServerEntityLookup extends EntityLookup {
protected void entityEndLoaded(final Entity entity) {
// Moonrise start - entity tracker
this.trackerEntities.remove(entity);
- this.trackerUnloadedEntities.add(entity);
// Moonrise end - entity tracker
}
@@ -0,0 +0,0 @@ public final class ServerEntityLookup extends EntityLookup {
}
@Override
- protected boolean screenEntity(final Entity entity) {
- return ChunkSystem.screenEntity(this.serverWorld, entity);
+ protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
+ return ChunkSystem.screenEntity(this.serverWorld, entity, fromDisk, event);
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/poi/PoiChunk.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/poi/PoiChunk.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/poi/PoiChunk.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/poi/PoiChunk.java
@@ -0,0 +0,0 @@ package ca.spottedleaf.moonrise.patches.chunk_system.level.poi;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.TickThread;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
-import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.SharedConstants;
import net.minecraft.nbt.CompoundTag;
@@ -0,0 +0,0 @@ public final class PoiChunk {
ret.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion());
final ServerLevel world = this.world;
- final PoiManager poiManager = world.getPoiManager();
final int chunkX = this.chunkX;
final int chunkZ = this.chunkZ;
@@ -0,0 +0,0 @@ public final class PoiChunk {
continue;
}
- final long key = CoordinateUtils.getChunkSectionKey(chunkX, sectionY, chunkZ);
- // codecs are honestly such a fucking disaster. What the fuck is this trash?
- final Codec codec = PoiSection.codec(() -> {
- poiManager.setDirty(key);
- });
-
- final DataResult serializedResult = codec.encodeStart(registryOps, section);
+ // I do not believe asynchronously converting to CompoundTag is worth the scheduling.
+ final DataResult serializedResult = PoiSection.Packed.CODEC.encodeStart(registryOps, section.pack());
final int finalSectionY = sectionY;
final Tag serialized = serializedResult.resultOrPartial((final String description) -> {
LOGGER.error("Failed to serialize poi chunk for world: " + WorldUtil.getWorldName(world) + ", chunk: (" + chunkX + "," + finalSectionY + "," + chunkZ + "); description: " + description);
@@ -0,0 +0,0 @@ public final class PoiChunk {
continue;
}
- final long coordinateKey = CoordinateUtils.getChunkSectionKey(chunkX, sectionY, chunkZ);
- // codecs are honestly such a fucking disaster. What the fuck is this trash?
- final Codec codec = PoiSection.codec(() -> {
- poiManager.setDirty(coordinateKey);
- });
-
final CompoundTag section = sections.getCompound(key);
- final DataResult deserializeResult = codec.parse(registryOps, section);
+ final DataResult deserializeResult = PoiSection.Packed.CODEC.parse(registryOps, section);
final int finalSectionY = sectionY;
- final PoiSection deserialized = deserializeResult.resultOrPartial((final String description) -> {
+ final PoiSection.Packed packed = deserializeResult.resultOrPartial((final String description) -> {
LOGGER.error("Failed to deserialize poi chunk for world: " + WorldUtil.getWorldName(world) + ", chunk: (" + chunkX + "," + finalSectionY + "," + chunkZ + "); description: " + description);
}).orElse(null);
+ final long coordinateKey = CoordinateUtils.getChunkSectionKey(chunkX, sectionY, chunkZ);
+ final PoiSection deserialized = packed == null ? null : packed.unpack(() -> {
+ poiManager.setDirty(coordinateKey);
+ });
+
if (deserialized == null || ((ChunkSystemPoiSection)deserialized).moonrise$isEmpty()) {
// completely empty, no point in storing this
continue;
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/storage/ChunkSystemSectionStorage.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/storage/ChunkSystemSectionStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/storage/ChunkSystemSectionStorage.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/storage/ChunkSystemSectionStorage.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level.storage;
-import com.mojang.serialization.Dynamic;
import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.Tag;
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import java.io.IOException;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
public interface ChunkSystemSectionStorage {
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.player;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.misc.AllocatingRateLimiter;
import ca.spottedleaf.moonrise.common.misc.SingleUserAreaMap;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) {
((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$addReceivedChunk(this.player);
- PlayerChunkSender.sendChunk(this.player.connection, this.world, ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ));
+
+ final LevelChunk chunk = ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
+
+ PlatformHooks.get().onChunkWatch(this.world, chunk, this.player);
+ PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
return;
}
throw new IllegalStateException();
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
}
private void sendUnloadChunkRaw(final int chunkX, final int chunkZ) {
+ PlatformHooks.get().onChunkUnWatch(this.world, new ChunkPos(chunkX, chunkZ), this.player);
// Note: Check PlayerChunkSender#dropChunk for other logic
// Note: drop isAlive() check so that chunks properly unload client-side when the player dies
((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$removeReceivedChunk(this.player);
- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
- this.player.connection.send(new ClientboundForgetLevelChunkPacket(chunkPos));
- // Paper start - PlayerChunkUnloadEvent
- if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) {
- new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(this.world.getWorld().getChunkAt(chunkPos.longKey), this.player.getBukkitEntity()).callEvent();
- }
- // Paper end - PlayerChunkUnloadEvent
+ this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)));
}
private final SingleUserAreaMap broadcastMap = new SingleUserAreaMap<>(this) {
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
final int playerSendViewDistance, final int worldSendViewDistance) {
return Math.min(
loadViewDistance - 1,
- playerSendViewDistance < 0 ? (!io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.autoConfigSendDistance || clientViewDistance < 0 ? (worldSendViewDistance < 0 ? (loadViewDistance - 1) : worldSendViewDistance) : clientViewDistance + 1) : playerSendViewDistance
+ playerSendViewDistance < 0 ? (!PlatformHooks.get().configAutoConfigSendDistance() || clientViewDistance < 0 ? (worldSendViewDistance < 0 ? (loadViewDistance - 1) : worldSendViewDistance) : clientViewDistance + 1) : playerSendViewDistance
);
}
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
}
private double getMaxChunkLoadRate() {
- final double configRate = io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkLoadRate;
+ final double configRate = PlatformHooks.get().configPlayerMaxLoadRate();
return configRate <= 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate);
}
private double getMaxChunkGenRate() {
- final double configRate = io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkGenerateRate;
+ final double configRate = PlatformHooks.get().configPlayerMaxGenRate();
return configRate <= 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate);
}
private double getMaxChunkSendRate() {
- final double configRate = io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkSendRate;
+ final double configRate = PlatformHooks.get().configPlayerMaxSendRate();
return configRate <= 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate);
}
private long getMaxChunkLoads() {
final long radiusChunks = (2L * this.lastLoadDistance + 1L) * (2L * this.lastLoadDistance + 1L);
- long configLimit = io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkLoads;
+ long configLimit = (long)PlatformHooks.get().configPlayerMaxConcurrentLoads();
if (configLimit == 0L) {
// by default, only allow 1/5th of the chunks in the view distance to be concurrently active
configLimit = Math.max(5L, radiusChunks / 5L);
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
private long getMaxChunkGenerates() {
final long radiusChunks = (2L * this.lastLoadDistance + 1L) * (2L * this.lastLoadDistance + 1L);
- long configLimit = io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkGenerates;
+ long configLimit = (long)PlatformHooks.get().configPlayerMaxConcurrentGens();
if (configLimit == 0L) {
// by default, only allow 1/5th of the chunks in the view distance to be concurrently active
configLimit = Math.max(5L, radiusChunks / 5L);
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
final int queuedChunkX = CoordinateUtils.getChunkX(queuedLoadChunk);
final int queuedChunkZ = CoordinateUtils.getChunkZ(queuedLoadChunk);
((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().scheduleChunkLoad(
- queuedChunkX, queuedChunkZ, ChunkStatus.EMPTY, false, PrioritisedExecutor.Priority.NORMAL, null
+ queuedChunkX, queuedChunkZ, ChunkStatus.EMPTY, false, Priority.NORMAL, null
);
if (this.removed) {
return;
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
}
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
// not yet post-processed, need to do this so that tile entities can properly be sent to clients
- chunk.postProcessGeneration();
+ chunk.postProcessGeneration(this.world);
// check if there was any recursive action
if (this.removed || this.sendQueue.isEmpty() || this.sendQueue.firstLong() != pendingSend) {
return;
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
final int clientViewDistance = getClientViewDistance(this.player);
final int sendViewDistance = getSendViewDistance(loadViewDistance, clientViewDistance, playerDistances.sendViewDistance, worldDistances.sendViewDistance);
- // TODO check PlayerList diff in paper chunk system patch
// send view distances
this.player.connection.send(this.updateClientChunkRadius(sendViewDistance));
this.player.connection.send(this.updateClientSimulationDistance(tickViewDistance));
@@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader {
// now all tickets should be removed, which is all of our external state
}
+
+ public LongOpenHashSet getSentChunksRaw() {
+ return this.sentChunks;
+ }
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
+import ca.spottedleaf.concurrentutil.util.Priority;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
-import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
import ca.spottedleaf.moonrise.common.util.TickThread;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.common.util.ChunkSystem;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
import ca.spottedleaf.moonrise.patches.chunk_system.level.poi.PoiChunk;
@@ -0,0 +0,0 @@ import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket;
import ca.spottedleaf.moonrise.patches.chunk_system.util.ChunkSystemSortedArraySet;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
-import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.longs.Long2ByteLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
import it.unimi.dsi.fastutil.longs.Long2IntMap;
@@ -0,0 +0,0 @@ import net.minecraft.server.level.TicketType;
import net.minecraft.util.SortedArraySet;
import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.chunk.LevelChunk;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayDeque;
@@ -0,0 +0,0 @@ import java.util.function.Predicate;
public final class ChunkHolderManager {
- private static final Logger LOGGER = LogUtils.getClassLogger();
+ private static final Logger LOGGER = LoggerFactory.getLogger(ChunkHolderManager.class);
public static final int FULL_LOADED_TICKET_LEVEL = ChunkLevel.FULL_CHUNK_LEVEL;
public static final int BLOCK_TICKING_TICKET_LEVEL = ChunkLevel.BLOCK_TICKING_LEVEL;
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
if (halt) {
LOGGER.info("Waiting 60s for chunk system to halt for world '" + WorldUtil.getWorldName(this.world) + "'");
if (!this.taskScheduler.halt(true, TimeUnit.SECONDS.toNanos(60L))) {
- LOGGER.warn("Failed to halt world generation/loading tasks for world '" + WorldUtil.getWorldName(this.world) + "'");
+ LOGGER.warn("Failed to halt generation/loading tasks for world '" + WorldUtil.getWorldName(this.world) + "'");
} else {
LOGGER.info("Halted chunk system for world '" + WorldUtil.getWorldName(this.world) + "'");
}
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
this.saveAllChunks(true, true, true);
}
- boolean hasTasks = false;
- for (final RegionFileIOThread.RegionFileType type : RegionFileIOThread.RegionFileType.values()) {
- if (RegionFileIOThread.getControllerFor(this.world, type).hasTasks()) {
- hasTasks = true;
- break;
+ MoonriseRegionFileIO.flush(this.world);
+
+ if (halt) {
+ LOGGER.info("Waiting 60s for chunk I/O to halt for world '" + WorldUtil.getWorldName(this.world) + "'");
+ if (!this.taskScheduler.haltIO(true, TimeUnit.SECONDS.toNanos(60L))) {
+ LOGGER.warn("Failed to halt I/O tasks for world '" + WorldUtil.getWorldName(this.world) + "'");
+ } else {
+ LOGGER.info("Halted I/O scheduler for world '" + WorldUtil.getWorldName(this.world) + "'");
}
}
- if (hasTasks) {
- RegionFileIOThread.flush();
- }
// kill regionfile cache
- for (final RegionFileIOThread.RegionFileType type : RegionFileIOThread.RegionFileType.values()) {
+ for (final MoonriseRegionFileIO.RegionFileType type : MoonriseRegionFileIO.RegionFileType.values()) {
try {
- RegionFileIOThread.getControllerFor(this.world, type).getCache().close();
+ MoonriseRegionFileIO.getControllerFor(this.world, type).getCache().close();
} catch (final IOException ex) {
LOGGER.error("Failed to close '" + type.name() + "' regionfile cache for world '" + WorldUtil.getWorldName(this.world) + "'", ex);
}
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
public void autoSave() {
final List reschedule = new ArrayList<>();
final long currentTick = this.currentTick;
- final long maxSaveTime = currentTick - Math.max(1L, this.world.paperConfig().chunks.autoSaveInterval.value());
- final int maxToSave = this.world.paperConfig().chunks.maxAutoSaveChunksPerTick;
+ final long maxSaveTime = currentTick - Math.max(1L, PlatformHooks.get().configAutoSaveInterval());
+ final int maxToSave = PlatformHooks.get().configMaxAutoSavePerTick();
for (int autoSaved = 0; autoSaved < maxToSave && !this.autoSaveQueue.isEmpty();) {
final NewChunkHolder holder = this.autoSaveQueue.first();
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
long start = System.nanoTime();
long lastLog = start;
- boolean needsFlush = false;
- final int flushInterval = 50;
+ final int flushInterval = 200;
+ int lastFlush = 0;
int savedChunk = 0;
int savedEntity = 0;
int savedPoi = 0;
+ if (shutdown) {
+ // Normal unload process does not occur during shutdown: fire event manually
+ // for mods that expect ChunkEvent.Unload to fire on shutdown (before LevelEvent.Unload)
+ for (int i = 0, len = holders.size(); i < len; ++i) {
+ final NewChunkHolder holder = holders.get(i);
+ if (holder.getCurrentChunk() instanceof LevelChunk levelChunk) {
+ PlatformHooks.get().chunkUnloadFromWorld(levelChunk);
+ }
+ }
+ }
for (int i = 0, len = holders.size(); i < len; ++i) {
final NewChunkHolder holder = holders.get(i);
try {
final NewChunkHolder.SaveStat saveStat = holder.save(shutdown);
if (saveStat != null) {
- ++saved;
- needsFlush = flush;
if (saveStat.savedChunk()) {
++savedChunk;
+ ++saved;
}
if (saveStat.savedEntityChunk()) {
++savedEntity;
+ ++saved;
}
if (saveStat.savedPoiChunk()) {
++savedPoi;
+ ++saved;
}
}
} catch (final Throwable thr) {
LOGGER.error("Failed to save chunk (" + holder.chunkX + "," + holder.chunkZ + ") in world '" + WorldUtil.getWorldName(this.world) + "'", thr);
}
- if (needsFlush && (saved % flushInterval) == 0) {
- needsFlush = false;
- RegionFileIOThread.partialFlush(flushInterval / 2);
+ if (flush && (saved - lastFlush) > (flushInterval / 2)) {
+ lastFlush = saved;
+ MoonriseRegionFileIO.partialFlush(this.world, flushInterval / 2);
}
if (logProgress) {
final long currTime = System.nanoTime();
if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(10L)) {
lastLog = currTime;
- LOGGER.info("Saved " + saved + " chunks (" + format.format((double)(i+1)/(double)len * 100.0) + "%) in world '" + WorldUtil.getWorldName(this.world) + "'");
+ LOGGER.info(
+ "Saved " + savedChunk + " block chunks, " + savedEntity + " entity chunks, " + savedPoi
+ + " poi chunks in world '" + WorldUtil.getWorldName(this.world) + "', progress: "
+ + format.format((double)(i+1)/(double)len * 100.0)
+ );
}
}
}
if (flush) {
- RegionFileIOThread.flush();
+ MoonriseRegionFileIO.flush(this.world);
try {
- RegionFileIOThread.flushRegionStorages(this.world);
+ MoonriseRegionFileIO.flushRegionStorages(this.world);
} catch (final IOException ex) {
LOGGER.error("Exception when flushing regions in world '" + WorldUtil.getWorldName(this.world) + "'", ex);
}
}
if (logProgress) {
- LOGGER.info("Saved " + savedChunk + " block chunks, " + savedEntity + " entity chunks, " + savedPoi + " poi chunks in world '" + WorldUtil.getWorldName(this.world) + "' in " + format.format(1.0E-9 * (System.nanoTime() - start)) + "s");
+ LOGGER.info(
+ "Saved " + savedChunk + " block chunks, " + savedEntity + " entity chunks, " + savedPoi
+ + " poi chunks in world '" + WorldUtil.getWorldName(this.world) + "' in "
+ + format.format(1.0E-9 * (System.nanoTime() - start)) + "s"
+ );
}
}
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
return this.chunkHolders.get(position);
}
- public void raisePriority(final int x, final int z, final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final int x, final int z, final Priority priority) {
final NewChunkHolder chunkHolder = this.getChunkHolder(x, z);
if (chunkHolder != null) {
chunkHolder.raisePriority(priority);
}
}
- public void setPriority(final int x, final int z, final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final int x, final int z, final Priority priority) {
final NewChunkHolder chunkHolder = this.getChunkHolder(x, z);
if (chunkHolder != null) {
chunkHolder.setPriority(priority);
}
}
- public void lowerPriority(final int x, final int z, final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final int x, final int z, final Priority priority) {
final NewChunkHolder chunkHolder = this.getChunkHolder(x, z);
if (chunkHolder != null) {
chunkHolder.lowerPriority(priority);
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
final ChunkLoadTask.EntityDataLoadTask entityLoad = current.getEntityDataLoadTask();
if (entityLoad != null) {
- entityLoad.raisePriority(PrioritisedExecutor.Priority.BLOCKING);
+ entityLoad.raisePriority(Priority.BLOCKING);
}
}
}
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
final ChunkLoadTask.PoiDataLoadTask poiLoad = current.getPoiDataLoadTask();
if (poiLoad != null) {
- poiLoad.raisePriority(PrioritisedExecutor.Priority.BLOCKING);
+ poiLoad.raisePriority(Priority.BLOCKING);
}
}
} finally {
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
}
ChunkHolderManager.this.processPendingFullUpdate();
- }, PrioritisedExecutor.Priority.HIGHEST);
+ }, Priority.HIGHEST);
} else {
final ArrayDeque pendingFullLoadUpdate = this.pendingFullLoadUpdate;
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
}
private void removeChunkHolder(final NewChunkHolder holder) {
- holder.markUnloaded();
+ holder.onUnload();
this.autoSaveQueue.remove(holder);
ChunkSystem.onChunkHolderDelete(this.world, holder.vanillaChunkHolder);
this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ));
-
}
// note: never call while inside the chunk system, this will absolutely break everything
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
throw new IllegalStateException("Cannot update ticket level while unloading chunks or updating entity manager");
}
+ if (!PlatformHooks.get().allowAsyncTicketUpdates() && !TickThread.isTickThread()) {
+ TickThread.ensureTickThread("Cannot asynchronously process ticket updates");
+ }
List changedFullStatus = null;
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
}
changedFullStatus = new ArrayList<>();
- ret |= this.ticketLevelPropagator.performUpdates(
- this.ticketLockArea, this.taskScheduler.schedulingLockArea,
- scheduledTasks, changedFullStatus
- );
+ this.blockTicketUpdates();
+ try {
+ ret |= this.ticketLevelPropagator.performUpdates(
+ this.ticketLockArea, this.taskScheduler.schedulingLockArea,
+ scheduledTasks, changedFullStatus
+ );
+ } finally {
+ this.unblockTicketUpdates(Boolean.FALSE);
+ }
}
if (changedFullStatus != null) {
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadPool;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadedTaskQueue;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.queue.PrioritisedTaskQueue;
+import ca.spottedleaf.concurrentutil.executor.thread.PrioritisedThreadPool;
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
+import ca.spottedleaf.moonrise.common.config.moonrise.MoonriseConfig;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.JsonUtil;
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
import ca.spottedleaf.moonrise.common.util.TickThread;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkStatus;
import ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer;
@@ -0,0 +0,0 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkUpgrade
import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer;
import ca.spottedleaf.moonrise.patches.chunk_system.status.ChunkSystemChunkStep;
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
-import com.mojang.logging.LogUtils;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.CrashReport;
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStep;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -0,0 +0,0 @@ import java.util.function.Consumer;
public final class ChunkTaskScheduler {
- private static final Logger LOGGER = LogUtils.getClassLogger();
+ private static final Logger LOGGER = LoggerFactory.getLogger(ChunkTaskScheduler.class);
- static int newChunkSystemIOThreads;
- static int newChunkSystemGenParallelism;
- static int newChunkSystemGenPopulationParallelism;
- static int newChunkSystemLoadParallelism;
-
- private static boolean initialised = false;
-
- public static void init(io.papermc.paper.configuration.GlobalConfiguration.ChunkSystem chunkSystem) {
- if (initialised) {
- return;
- }
- initialised = true;
- MoonriseCommon.init(chunkSystem); // Paper
- newChunkSystemIOThreads = chunkSystem.ioThreads;
- if (newChunkSystemIOThreads <= 0) {
- newChunkSystemIOThreads = 1;
- } else {
- newChunkSystemIOThreads = Math.max(1, newChunkSystemIOThreads);
- }
-
- String newChunkSystemGenParallelism = chunkSystem.genParallelism;
- if (newChunkSystemGenParallelism.equalsIgnoreCase("default")) {
- newChunkSystemGenParallelism = "true";
- }
-
- boolean useParallelGen;
- if (newChunkSystemGenParallelism.equalsIgnoreCase("on") || newChunkSystemGenParallelism.equalsIgnoreCase("enabled")
- || newChunkSystemGenParallelism.equalsIgnoreCase("true")) {
- useParallelGen = true;
- } else if (newChunkSystemGenParallelism.equalsIgnoreCase("off") || newChunkSystemGenParallelism.equalsIgnoreCase("disabled")
- || newChunkSystemGenParallelism.equalsIgnoreCase("false")) {
- useParallelGen = false;
- } else {
- throw new IllegalStateException("Invalid option for gen-parallelism: must be one of [on, off, enabled, disabled, true, false, default]");
+ public static void init(final boolean useParallelGen) {
+ for (final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor executor : MoonriseCommon.RADIUS_AWARE_GROUP.getAllExecutors()) {
+ executor.setMaxParallelism(useParallelGen ? -1 : 1);
}
- ChunkTaskScheduler.newChunkSystemGenParallelism = MoonriseCommon.WORKER_THREADS;
- ChunkTaskScheduler.newChunkSystemGenPopulationParallelism = useParallelGen ? MoonriseCommon.WORKER_THREADS : 1;
- ChunkTaskScheduler.newChunkSystemLoadParallelism = MoonriseCommon.WORKER_THREADS;
-
- RegionFileIOThread.init(newChunkSystemIOThreads);
-
- LOGGER.info("Chunk system is using " + newChunkSystemIOThreads + " I/O threads, " + MoonriseCommon.WORKER_THREADS + " worker threads, and population gen parallelism of " + ChunkTaskScheduler.newChunkSystemGenPopulationParallelism + " threads");
+ LOGGER.info("Chunk system is using population gen parallelism: " + useParallelGen);
}
public static final TicketType CHUNK_LOAD = TicketType.create("chunk_system:chunk_load", Long::compareTo);
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
}
public final ServerLevel world;
- public final PrioritisedThreadPool workers;
public final RadiusAwarePrioritisedExecutor radiusAwareScheduler;
- public final PrioritisedThreadPool.PrioritisedPoolExecutor parallelGenExecutor;
- private final PrioritisedThreadPool.PrioritisedPoolExecutor radiusAwareGenExecutor;
- public final PrioritisedThreadPool.PrioritisedPoolExecutor loadExecutor;
+ public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor parallelGenExecutor;
+ private final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor radiusAwareGenExecutor;
+ public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor loadExecutor;
+ public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor ioExecutor;
+ public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor compressionExecutor;
+ public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor saveExecutor;
- private final PrioritisedThreadedTaskQueue mainThreadExecutor = new PrioritisedThreadedTaskQueue();
+ private final PrioritisedTaskQueue mainThreadExecutor = new PrioritisedTaskQueue();
public final ChunkHolderManager chunkHolderManager;
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
return this.lockShift;
}
- public ChunkTaskScheduler(final ServerLevel world, final PrioritisedThreadPool workers) {
+ public ChunkTaskScheduler(final ServerLevel world) {
this.world = world;
- this.workers = workers;
// must be >= region shift (in paper, doesn't exist) and must be >= ticket propagator section shift
// it must be >= region shift since the regioniser assumes ticket updates do not occur in parallel for the region sections
// it must be >= ticket propagator section shift so that the ticket propagator can assume that owning a position implies owning
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
this.lockShift = Math.max(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift(), ThreadedTicketLevelPropagator.SECTION_SHIFT);
this.schedulingLockArea = new ReentrantAreaLock(this.getChunkSystemLockShift());
- final String worldName = WorldUtil.getWorldName(world);
- this.parallelGenExecutor = workers.createExecutor("Chunk parallel generation executor for world '" + worldName + "'", 1, Math.max(1, newChunkSystemGenParallelism));
- this.radiusAwareGenExecutor = workers.createExecutor("Chunk radius aware generator for world '" + worldName + "'", 1, Math.max(1, newChunkSystemGenPopulationParallelism));
- this.loadExecutor = workers.createExecutor("Chunk load executor for world '" + worldName + "'", 1, newChunkSystemLoadParallelism);
- this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, Math.max(2, 1 + newChunkSystemGenPopulationParallelism));
+ this.parallelGenExecutor = MoonriseCommon.PARALLEL_GEN_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0);
+ this.radiusAwareGenExecutor = MoonriseCommon.RADIUS_AWARE_GROUP.createExecutor(1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0);
+ this.loadExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0);
+ this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, 16);
+ this.ioExecutor = MoonriseCommon.SERVER_REGION_IO_GROUP.createExecutor(-1, MoonriseCommon.IO_QUEUE_HOLD_TIME, 0);
+ // we need a separate executor here so that on shutdown we can continue to process I/O tasks
+ this.compressionExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0);
+ this.saveExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0);
this.chunkHolderManager = new ChunkHolderManager(world, this);
}
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
};
// this may not be good enough, specifically thanks to stupid ass plugins swallowing exceptions
- this.scheduleChunkTask(chunkX, chunkZ, crash, PrioritisedExecutor.Priority.BLOCKING);
+ this.scheduleChunkTask(chunkX, chunkZ, crash, Priority.BLOCKING);
// so, make the main thread pick it up
((ChunkSystemMinecraftServer)this.world.getServer()).moonrise$setChunkSystemCrash(new RuntimeException("Chunk system crash propagated from unrecoverableChunkSystemFailure", reportedException));
}
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
return this.mainThreadExecutor.executeTask();
}
- public void raisePriority(final int x, final int z, final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final int x, final int z, final Priority priority) {
this.chunkHolderManager.raisePriority(x, z, priority);
}
- public void setPriority(final int x, final int z, final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final int x, final int z, final Priority priority) {
this.chunkHolderManager.setPriority(x, z, priority);
}
- public void lowerPriority(final int x, final int z, final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final int x, final int z, final Priority priority) {
this.chunkHolderManager.lowerPriority(x, z, priority);
}
public void scheduleTickingState(final int chunkX, final int chunkZ, final FullChunkStatus toStatus,
- final boolean addTicket, final PrioritisedExecutor.Priority priority,
+ final boolean addTicket, final Priority priority,
final Consumer onComplete) {
final int radius = toStatus.ordinal() - 1; // 0 -> BORDER, 1 -> TICKING, 2 -> ENTITY_TICKING
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
}
public void scheduleChunkLoad(final int chunkX, final int chunkZ, final boolean gen, final ChunkStatus toStatus, final boolean addTicket,
- final PrioritisedExecutor.Priority priority, final Consumer onComplete) {
+ final Priority priority, final Consumer onComplete) {
if (gen) {
this.scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
return;
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
// only appropriate to use with syncLoadNonFull
public boolean beginChunkLoadForNonFullSync(final int chunkX, final int chunkZ, final ChunkStatus toStatus,
- final PrioritisedExecutor.Priority priority) {
+ final Priority priority) {
final int accessRadius = getAccessRadius(toStatus);
final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
final int minLevel = ChunkTaskScheduler.getTicketLevel(toStatus);
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
if (status == null || status.isOrAfter(ChunkStatus.FULL)) {
throw new IllegalArgumentException("Status: " + status);
}
+
+ if (!TickThread.isTickThread()) {
+ return this.world.getChunkSource().getChunk(chunkX, chunkZ, status, true);
+ }
+
ChunkAccess loaded = ((ChunkSystemServerLevel)this.world).moonrise$getSpecificChunkIfLoaded(chunkX, chunkZ, status);
if (loaded != null) {
return loaded;
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
this.chunkHolderManager.addTicketAtLevel(NON_FULL_CHUNK_LOAD, chunkX, chunkZ, ticketLevel, ticketId);
this.chunkHolderManager.processTicketUpdates();
- this.beginChunkLoadForNonFullSync(chunkX, chunkZ, status, PrioritisedExecutor.Priority.BLOCKING);
+ this.beginChunkLoadForNonFullSync(chunkX, chunkZ, status, Priority.BLOCKING);
// we could do a simple spinwait here, since we do not need to process tasks while performing this load
// but we process tasks only because it's a better use of the time spent
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
}
public void scheduleChunkLoad(final int chunkX, final int chunkZ, final ChunkStatus toStatus, final boolean addTicket,
- final PrioritisedExecutor.Priority priority, final Consumer onComplete) {
+ final Priority priority, final Consumer onComplete) {
if (!TickThread.isTickThreadFor(this.world, chunkX, chunkZ)) {
this.scheduleChunkTask(chunkX, chunkZ, () -> {
ChunkTaskScheduler.this.scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
private ChunkProgressionTask createTask(final int chunkX, final int chunkZ, final ChunkAccess chunk,
final NewChunkHolder chunkHolder, final StaticCache2D neighbours,
- final ChunkStatus toStatus, final PrioritisedExecutor.Priority initialPriority) {
+ final ChunkStatus toStatus, final Priority initialPriority) {
if (toStatus == ChunkStatus.EMPTY) {
return new ChunkLoadTask(this, this.world, chunkX, chunkZ, chunkHolder, initialPriority);
}
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
ChunkProgressionTask schedule(final int chunkX, final int chunkZ, final ChunkStatus targetStatus, final NewChunkHolder chunkHolder,
final List allTasks) {
- return this.schedule(chunkX, chunkZ, targetStatus, chunkHolder, allTasks, chunkHolder.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL));
+ return this.schedule(chunkX, chunkZ, targetStatus, chunkHolder, allTasks, chunkHolder.getEffectivePriority(Priority.NORMAL));
}
// rets new task scheduled for the _specified_ chunk
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
// schedule will ignore the generation target, so it should be checked by the caller to ensure the target is not regressed!
private ChunkProgressionTask schedule(final int chunkX, final int chunkZ, final ChunkStatus targetStatus,
final NewChunkHolder chunkHolder, final List allTasks,
- final PrioritisedExecutor.Priority minPriority) {
+ final Priority minPriority) {
if (!this.schedulingLockArea.isHeldByCurrentThread(chunkX, chunkZ, getAccessRadius(targetStatus))) {
throw new IllegalStateException("Not holding scheduling lock");
}
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
return null;
}
- final PrioritisedExecutor.Priority requestedPriority = PrioritisedExecutor.Priority.max(
- minPriority, chunkHolder.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL)
+ final Priority requestedPriority = Priority.max(
+ minPriority, chunkHolder.getEffectivePriority(Priority.NORMAL)
);
final ChunkStatus currentGenStatus = chunkHolder.getCurrentGenStatus();
final ChunkAccess chunk = chunkHolder.getCurrentChunk();
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
final int neighbourReadRadius = Math.max(
0,
- chunkPyramid.getStepTo(toStatus).getAccumulatedRadiusOf(ChunkStatus.EMPTY)
+ chunkStep.getAccumulatedRadiusOf(ChunkStatus.EMPTY)
);
boolean unGeneratedNeighbours = false;
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
final ChunkProgressionTask task = this.createTask(
chunkX, chunkZ, chunk, chunkHolder, neighbours, toStatus,
- chunkHolder.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL)
+ chunkHolder.getEffectivePriority(Priority.NORMAL)
);
allTasks.add(task);
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
// rets true if the neighbour is not at the required status, false otherwise
private boolean checkNeighbour(final int chunkX, final int chunkZ, final ChunkStatus requiredStatus, final NewChunkHolder center,
- final List tasks, final PrioritisedExecutor.Priority minPriority) {
+ final List tasks, final Priority minPriority) {
final NewChunkHolder chunkHolder = this.chunkHolderManager.getChunkHolder(chunkX, chunkZ);
if (chunkHolder == null) {
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
*/
@Deprecated
public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final Runnable run) {
- return this.scheduleChunkTask(run, PrioritisedExecutor.Priority.NORMAL);
+ return this.scheduleChunkTask(run, Priority.NORMAL);
}
/**
* @deprecated Chunk tasks must be tied to coordinates in the future
*/
@Deprecated
- public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final Runnable run, final PrioritisedExecutor.Priority priority) {
- return this.mainThreadExecutor.queueRunnable(run, priority);
+ public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final Runnable run, final Priority priority) {
+ return this.mainThreadExecutor.queueTask(run, priority);
}
public PrioritisedExecutor.PrioritisedTask createChunkTask(final int chunkX, final int chunkZ, final Runnable run) {
- return this.createChunkTask(chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL);
+ return this.createChunkTask(chunkX, chunkZ, run, Priority.NORMAL);
}
public PrioritisedExecutor.PrioritisedTask createChunkTask(final int chunkX, final int chunkZ, final Runnable run,
- final PrioritisedExecutor.Priority priority) {
+ final Priority priority) {
return this.mainThreadExecutor.createTask(run, priority);
}
public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final int chunkX, final int chunkZ, final Runnable run) {
- return this.scheduleChunkTask(chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL);
+ return this.scheduleChunkTask(chunkX, chunkZ, run, Priority.NORMAL);
}
public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final int chunkX, final int chunkZ, final Runnable run,
- final PrioritisedExecutor.Priority priority) {
- return this.mainThreadExecutor.queueRunnable(run, priority);
+ final Priority priority) {
+ return this.mainThreadExecutor.queueTask(run, priority);
}
public boolean halt(final boolean sync, final long maxWaitNS) {
this.radiusAwareGenExecutor.halt();
this.parallelGenExecutor.halt();
this.loadExecutor.halt();
- final long time = System.nanoTime();
if (sync) {
+ final long time = System.nanoTime();
for (long failures = 9L;; failures = ConcurrentUtil.linearLongBackoff(failures, 500_000L, 50_000_000L)) {
if (
!this.radiusAwareGenExecutor.isActive() &&
@@ -0,0 +0,0 @@ public final class ChunkTaskScheduler {
return true;
}
+ public boolean haltIO(final boolean sync, final long maxWaitNS) {
+ this.ioExecutor.halt();
+ this.saveExecutor.halt();
+ this.compressionExecutor.halt();
+ if (sync) {
+ final long time = System.nanoTime();
+ for (long failures = 9L;; failures = ConcurrentUtil.linearLongBackoff(failures, 500_000L, 50_000_000L)) {
+ if (
+ !this.ioExecutor.isActive() &&
+ !this.saveExecutor.isActive() &&
+ !this.compressionExecutor.isActive()
+ ) {
+ return true;
+ }
+ if ((System.nanoTime() - time) >= maxWaitNS) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
public static final ArrayDeque WAITING_CHUNKS = new ArrayDeque<>(); // stack
public static final class ChunkInfo {
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
-import ca.spottedleaf.concurrentutil.completable.Completable;
+import ca.spottedleaf.concurrentutil.completable.CallbackCompletable;
import ca.spottedleaf.concurrentutil.executor.Cancellable;
-import ca.spottedleaf.concurrentutil.executor.standard.DelayedPrioritisedTask;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
+import ca.spottedleaf.moonrise.common.misc.LazyRunnable;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.TickThread;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.common.util.ChunkSystem;
-import ca.spottedleaf.moonrise.patches.chunk_system.ChunkSystemFeatures;
-import ca.spottedleaf.moonrise.patches.chunk_system.async_save.AsyncChunkSaveData;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
+import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkStatus;
@@ -0,0 +0,0 @@ import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkLevel;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
-import net.minecraft.world.level.chunk.storage.ChunkSerializer;
+import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.VarHandle;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(NewChunkHolder.class);
+ public final ChunkData holderData;
+
public final ServerLevel world;
public final int chunkX;
public final int chunkZ;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
if (this.entityChunk == null) {
ret = this.entityChunk = new ChunkEntitySlices(
this.world, this.chunkX, this.chunkZ, this.getChunkStatus(),
- WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
+ this.holderData, WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
);
ret.setTransient(transientChunk);
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
// no tasks to schedule _for_
} else {
entityDataLoadTask = this.entityDataLoadTask = new ChunkLoadTask.EntityDataLoadTask(
- this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL)
+ this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(Priority.NORMAL)
);
entityDataLoadTask.addCallback(this::completeEntityLoad);
// need one schedule() per waiter
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
if (this.entityDataLoadTask == null) {
this.entityDataLoadTask = new ChunkLoadTask.EntityDataLoadTask(
- this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL)
+ this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(Priority.NORMAL)
);
this.entityDataLoadTask.addCallback(this::completeEntityLoad);
this.entityDataLoadTaskWaiters = new ArrayList<>();
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
// no tasks to schedule _for_
} else {
poiDataLoadTask = this.poiDataLoadTask = new ChunkLoadTask.PoiDataLoadTask(
- this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL)
+ this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(Priority.NORMAL)
);
poiDataLoadTask.addCallback(this::completePoiLoad);
// need one schedule() per waiter
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
if (this.poiDataLoadTask == null) {
this.poiDataLoadTask = new ChunkLoadTask.PoiDataLoadTask(
- this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL)
+ this.scheduler, this.world, this.chunkX, this.chunkZ, this.getEffectivePriority(Priority.NORMAL)
);
this.poiDataLoadTask.addCallback(this::completePoiLoad);
this.poiDataLoadTaskWaiters = new ArrayList<>();
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
// priority state
// the target priority for this chunk to generate at
- private PrioritisedExecutor.Priority priority = null;
+ private Priority priority = null;
private boolean priorityLocked;
// the priority neighbouring chunks have requested this chunk generate at
- private PrioritisedExecutor.Priority neighbourRequestedPriority = null;
+ private Priority neighbourRequestedPriority = null;
- public PrioritisedExecutor.Priority getEffectivePriority(final PrioritisedExecutor.Priority dfl) {
- final PrioritisedExecutor.Priority neighbour = this.neighbourRequestedPriority;
- final PrioritisedExecutor.Priority us = this.priority;
+ public Priority getEffectivePriority(final Priority dfl) {
+ final Priority neighbour = this.neighbourRequestedPriority;
+ final Priority us = this.priority;
if (neighbour == null) {
return us == null ? dfl : us;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
return neighbour;
}
- return PrioritisedExecutor.Priority.max(us, neighbour);
+ return Priority.max(us, neighbour);
}
private void recalculateNeighbourRequestedPriority() {
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
return;
}
- PrioritisedExecutor.Priority max = null;
+ Priority max = null;
for (final NewChunkHolder holder : this.neighboursWaitingForUs.keySet()) {
- final PrioritisedExecutor.Priority neighbourPriority = holder.getEffectivePriority(null);
+ final Priority neighbourPriority = holder.getEffectivePriority(null);
if (neighbourPriority != null && (max == null || neighbourPriority.isHigherPriority(max))) {
max = neighbourPriority;
}
}
- final PrioritisedExecutor.Priority current = this.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL);
+ final Priority current = this.getEffectivePriority(Priority.NORMAL);
this.neighbourRequestedPriority = max;
- final PrioritisedExecutor.Priority next = this.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL);
+ final Priority next = this.getEffectivePriority(Priority.NORMAL);
if (current == next) {
return;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
}
// must hold scheduling lock
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final Priority priority) {
if (this.priority != null && this.priority.isHigherOrEqualPriority(priority)) {
return;
}
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
}
// must hold scheduling lock
- public void setPriority(final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final Priority priority) {
if (this.priorityLocked) {
return;
}
- final PrioritisedExecutor.Priority old = this.getEffectivePriority(null);
+ final Priority old = this.getEffectivePriority(null);
this.priority = priority;
- final PrioritisedExecutor.Priority newPriority = this.getEffectivePriority(PrioritisedExecutor.Priority.NORMAL);
+ final Priority newPriority = this.getEffectivePriority(Priority.NORMAL);
if (old != newPriority) {
if (this.generationTask != null) {
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
}
// must hold scheduling lock
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final Priority priority) {
if (this.priority != null && this.priority.isLowerOrEqualPriority(priority)) {
return;
}
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
}
// ticket level state
- public int oldTicketLevel = ChunkHolderManager.MAX_TICKET_LEVEL + 1;
+ private int oldTicketLevel = ChunkHolderManager.MAX_TICKET_LEVEL + 1;
private int currentTicketLevel = ChunkHolderManager.MAX_TICKET_LEVEL + 1;
public int getTicketLevel() {
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
world.getLightEngine(), null, world.getChunkSource().chunkMap
);
((ChunkSystemChunkHolder)this.vanillaChunkHolder).moonrise$setRealChunkHolder(this);
+ this.holderData = ((ChunkSystemLevel)this.world).moonrise$requestChunkData(CoordinateUtils.getChunkKey(chunkX, chunkZ));
}
public ChunkAccess getCurrentChunk() {
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
/** Unloaded from chunk map */
private boolean unloaded;
- void markUnloaded() {
+ void onUnload() {
this.unloaded = true;
+ ((ChunkSystemLevel)this.world).moonrise$releaseChunkData(CoordinateUtils.getChunkKey(this.chunkX, this.chunkZ));
}
private boolean inUnloadQueue = false;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
private UnloadTask entityDataUnload;
private UnloadTask poiDataUnload;
- public static final record UnloadTask(Completable completable, DelayedPrioritisedTask task) {}
+ public static final record UnloadTask(CallbackCompletable completable, PrioritisedExecutor.PrioritisedTask task,
+ LazyRunnable toRun) {}
- public UnloadTask getUnloadTask(final RegionFileIOThread.RegionFileType type) {
+ public UnloadTask getUnloadTask(final MoonriseRegionFileIO.RegionFileType type) {
switch (type) {
case CHUNK_DATA:
return this.chunkDataUnload;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
}
}
- private void removeUnloadTask(final RegionFileIOThread.RegionFileType type) {
+ private void removeUnloadTask(final MoonriseRegionFileIO.RegionFileType type) {
switch (type) {
case CHUNK_DATA: {
this.chunkDataUnload = null;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
// chunk state
this.currentChunk = null;
this.currentGenStatus = null;
- this.lastChunkCompletion = null;
for (int i = 0; i < this.chunkCompletions.length; ++i) {
- CHUNK_COMPLETION_ARRAY_HANDLE.setVolatile(this.chunkCompletions, i, (ChunkCompletion)null);
+ CHUNK_COMPLETION_ARRAY_HANDLE.setRelease(this.chunkCompletions, i, (ChunkCompletion)null);
}
+ this.lastChunkCompletion = null;
// entity chunk state
this.entityChunk = null;
this.pendingEntityChunk = null;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
this.priorityLocked = false;
if (chunk != null) {
- this.chunkDataUnload = new UnloadTask(new Completable<>(), new DelayedPrioritisedTask(PrioritisedExecutor.Priority.NORMAL));
+ final LazyRunnable toRun = new LazyRunnable();
+ this.chunkDataUnload = new UnloadTask(new CallbackCompletable<>(), this.scheduler.saveExecutor.createTask(toRun), toRun);
}
if (poiChunk != null) {
- this.poiDataUnload = new UnloadTask(new Completable<>(), null);
+ this.poiDataUnload = new UnloadTask(new CallbackCompletable<>(), null, null);
}
if (entityChunk != null) {
- this.entityDataUnload = new UnloadTask(new Completable<>(), null);
+ this.entityDataUnload = new UnloadTask(new CallbackCompletable<>(), null, null);
}
return this.unloadState = (chunk != null || entityChunk != null || poiChunk != null) ? new UnloadState(this, chunk, entityChunk, poiChunk) : null;
}
// data is null if failed or does not need to be saved
- void completeAsyncUnloadDataSave(final RegionFileIOThread.RegionFileType type, final CompoundTag data) {
+ void completeAsyncUnloadDataSave(final MoonriseRegionFileIO.RegionFileType type, final CompoundTag data) {
if (data != null) {
- RegionFileIOThread.scheduleSave(this.world, this.chunkX, this.chunkZ, data, type);
+ MoonriseRegionFileIO.scheduleSave(this.world, this.chunkX, this.chunkZ, data, type);
}
this.getUnloadTask(type).completable().complete(data);
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
final ChunkEntitySlices entityChunk = state.entityChunk();
final PoiChunk poiChunk = state.poiChunk();
- final boolean shouldLevelChunkNotSave = ChunkSystemFeatures.forceNoSave(chunk);
+ final boolean shouldLevelChunkNotSave = PlatformHooks.get().forceNoSave(chunk);
// unload chunk data
if (chunk != null) {
if (chunk instanceof LevelChunk levelChunk) {
levelChunk.setLoaded(false);
+ PlatformHooks.get().chunkUnloadFromWorld(levelChunk);
}
if (!shouldLevelChunkNotSave) {
this.saveChunk(chunk, true);
} else {
- this.completeAsyncUnloadDataSave(RegionFileIOThread.RegionFileType.CHUNK_DATA, null);
+ this.completeAsyncUnloadDataSave(MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, null);
}
if (chunk instanceof LevelChunk levelChunk) {
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
if (oldUnloaded != newUnloaded) {
this.checkUnload();
}
+
+ // Don't really have a choice but to place this hook here
+ PlatformHooks.get().onChunkHolderTicketChange(this.world, this, oldLevel, newLevel);
}
static final int NEIGHBOUR_RADIUS = 2;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
private static final long CHUNK_LOADED_MASK_RAD1 = getLoadedMask(1);
private static final long CHUNK_LOADED_MASK_RAD2 = getLoadedMask(2);
- public static boolean areNeighboursFullLoaded(final long bitset, final int radius) {
- switch (radius) {
- case 0: {
- return (bitset & CHUNK_LOADED_MASK_RAD0) == CHUNK_LOADED_MASK_RAD0;
- }
- case 1: {
- return (bitset & CHUNK_LOADED_MASK_RAD1) == CHUNK_LOADED_MASK_RAD1;
- }
- case 2: {
- return (bitset & CHUNK_LOADED_MASK_RAD2) == CHUNK_LOADED_MASK_RAD2;
- }
-
- default: {
- throw new IllegalArgumentException("Radius not recognized: " + radius);
- }
- }
- }
-
// only updated while holding scheduling lock
private FullChunkStatus pendingFullChunkStatus = FullChunkStatus.INACCESSIBLE;
// updated while holding no locks, but adds a ticket before to prevent pending status from dropping
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
}
private void completeStatusConsumers(ChunkStatus status, final ChunkAccess chunk) {
+ // Update progress listener for LevelLoadingScreen
+ if (chunk != null) {
+ final ChunkProgressListener progressListener = this.world.getChunkSource().chunkMap.progressListener;
+ if (progressListener != null) {
+ final ChunkStatus finalStatus = status;
+ this.scheduler.scheduleChunkTask(this.chunkX, this.chunkZ, () -> {
+ progressListener.onStatusChange(this.vanillaChunkHolder.getPos(), finalStatus);
+ });
+ }
+ }
+
// need to tell future statuses to complete if cancelled
do {
this.completeStatusConsumers0(status, chunk);
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
LOGGER.error("Failed to process chunk status callback", thr);
}
}
- }, PrioritisedExecutor.Priority.HIGHEST);
+ }, Priority.HIGHEST);
}
private final Reference2ObjectOpenHashMap>> fullStatusWaiters = new Reference2ObjectOpenHashMap<>();
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
LOGGER.error("Failed to process chunk status callback", thr);
}
}
- }, PrioritisedExecutor.Priority.HIGHEST);
+ }, Priority.HIGHEST);
}
// note: must hold scheduling lock
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
public static final record SaveStat(boolean savedChunk, boolean savedEntityChunk, boolean savedPoiChunk) {}
+ private static final MoonriseRegionFileIO.RegionFileType[] REGION_FILE_TYPES = MoonriseRegionFileIO.RegionFileType.values();
+
public SaveStat save(final boolean shutdown) {
TickThread.ensureTickThread(this.world, this.chunkX, this.chunkZ, "Cannot save data off-main");
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
PoiChunk poi = this.getPoiChunk();
ChunkEntitySlices entities = this.getEntityChunk();
boolean executedUnloadTask = false;
+ final boolean[] executedUnloadTasks = new boolean[REGION_FILE_TYPES.length];
if (shutdown) {
// make sure that the async unloads complete
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
poi = this.unloadState.poiChunk();
entities = this.unloadState.entityChunk();
}
- final UnloadTask chunkUnloadTask = this.chunkDataUnload;
- final DelayedPrioritisedTask chunkDataUnloadTask = chunkUnloadTask == null ? null : chunkUnloadTask.task();
- if (chunkDataUnloadTask != null) {
- final PrioritisedExecutor.PrioritisedTask unloadTask = chunkDataUnloadTask.getTask();
- if (unloadTask != null) {
- executedUnloadTask = unloadTask.execute();
+ for (final MoonriseRegionFileIO.RegionFileType regionFileType : REGION_FILE_TYPES) {
+ final UnloadTask unloadTask = this.getUnloadTask(regionFileType);
+ if (unloadTask == null) {
+ continue;
+ }
+
+ final PrioritisedExecutor.PrioritisedTask task = unloadTask.task();
+ if (task != null && task.isQueued()) {
+ final boolean executed = task.execute();
+ executedUnloadTask |= executed;
+ executedUnloadTasks[regionFileType.ordinal()] = executed;
}
}
}
- final boolean forceNoSaveChunk = ChunkSystemFeatures.forceNoSave(chunk);
+ final boolean forceNoSaveChunk = PlatformHooks.get().forceNoSave(chunk);
// can only synchronously save worldgen chunks during shutdown
boolean canSaveChunk = !forceNoSaveChunk && (chunk != null && ((shutdown || chunk instanceof LevelChunk) && chunk.isUnsaved()));
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
}
}
- return executedUnloadTask | canSaveChunk | canSaveEntities | canSavePOI ? new SaveStat(executedUnloadTask || canSaveChunk, canSaveEntities, canSavePOI): null;
- }
-
- static final class AsyncChunkSerializeTask implements Runnable {
-
- private final ServerLevel world;
- private final ChunkAccess chunk;
- private final AsyncChunkSaveData asyncSaveData;
- private final NewChunkHolder toComplete;
-
- public AsyncChunkSerializeTask(final ServerLevel world, final ChunkAccess chunk, final AsyncChunkSaveData asyncSaveData,
- final NewChunkHolder toComplete) {
- this.world = world;
- this.chunk = chunk;
- this.asyncSaveData = asyncSaveData;
- this.toComplete = toComplete;
- }
-
- @Override
- public void run() {
- final CompoundTag toSerialize;
- try {
- toSerialize = ChunkSystemFeatures.saveChunkAsync(this.world, this.chunk, this.asyncSaveData);
- } catch (final Throwable throwable) {
- LOGGER.error("Failed to asynchronously save chunk " + this.chunk.getPos() + " for world '" + WorldUtil.getWorldName(this.world) + "', falling back to synchronous save", throwable);
- final ChunkPos pos = this.chunk.getPos();
- ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().scheduleChunkTask(pos.x, pos.z, () -> {
- final CompoundTag synchronousSave;
- try {
- synchronousSave = ChunkSystemFeatures.saveChunkAsync(AsyncChunkSerializeTask.this.world, AsyncChunkSerializeTask.this.chunk, AsyncChunkSerializeTask.this.asyncSaveData);
- } catch (final Throwable throwable2) {
- LOGGER.error("Failed to synchronously save chunk " + AsyncChunkSerializeTask.this.chunk.getPos() + " for world '" + WorldUtil.getWorldName(AsyncChunkSerializeTask.this.world) + "', chunk data will be lost", throwable2);
- AsyncChunkSerializeTask.this.toComplete.completeAsyncUnloadDataSave(RegionFileIOThread.RegionFileType.CHUNK_DATA, null);
- return;
- }
-
- AsyncChunkSerializeTask.this.toComplete.completeAsyncUnloadDataSave(RegionFileIOThread.RegionFileType.CHUNK_DATA, synchronousSave);
- LOGGER.info("Successfully serialized chunk " + AsyncChunkSerializeTask.this.chunk.getPos() + " for world '" + WorldUtil.getWorldName(AsyncChunkSerializeTask.this.world) + "' synchronously");
-
- }, PrioritisedExecutor.Priority.HIGHEST);
- return;
- }
- this.toComplete.completeAsyncUnloadDataSave(RegionFileIOThread.RegionFileType.CHUNK_DATA, toSerialize);
- }
-
- @Override
- public String toString() {
- return "AsyncChunkSerializeTask{" +
- "chunk={pos=" + this.chunk.getPos() + ",world=\"" + WorldUtil.getWorldName(this.world) + "\"}" +
- "}";
- }
+ return executedUnloadTask | canSaveChunk | canSaveEntities | canSavePOI ?
+ new SaveStat(
+ canSaveChunk | executedUnloadTasks[MoonriseRegionFileIO.RegionFileType.CHUNK_DATA.ordinal()],
+ canSaveEntities | executedUnloadTasks[MoonriseRegionFileIO.RegionFileType.ENTITY_DATA.ordinal()],
+ canSavePOI | executedUnloadTasks[MoonriseRegionFileIO.RegionFileType.POI_DATA.ordinal()]
+ )
+ : null;
}
private boolean saveChunk(final ChunkAccess chunk, final boolean unloading) {
if (!chunk.isUnsaved()) {
if (unloading) {
- this.completeAsyncUnloadDataSave(RegionFileIOThread.RegionFileType.CHUNK_DATA, null);
+ this.completeAsyncUnloadDataSave(MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, null);
}
return false;
}
- boolean completing = false;
- boolean failedAsyncPrepare = false;
try {
- if (unloading && ChunkSystemFeatures.supportsAsyncChunkSave()) {
- try {
- final AsyncChunkSaveData asyncSaveData = ChunkSystemFeatures.getAsyncSaveData(this.world, chunk);
+ final SerializableChunkData chunkData = SerializableChunkData.copyOf(this.world, chunk);
+ PlatformHooks.get().chunkSyncSave(this.world, chunk, chunkData);
- final PrioritisedExecutor.PrioritisedTask task = this.scheduler.loadExecutor.createTask(new AsyncChunkSerializeTask(this.world, chunk, asyncSaveData, this));
+ chunk.tryMarkSaved();
- this.chunkDataUnload.task().setTask(task);
+ final CallbackCompletable completable = new CallbackCompletable<>();
- chunk.setUnsaved(false);
+ final Runnable run = () -> {
+ final CompoundTag data = chunkData.write();
- task.queue();
+ completable.complete(data);
- return true;
- } catch (final Throwable thr) {
- LOGGER.error("Failed to prepare async chunk data (" + this.chunkX + "," + this.chunkZ + ") in world '" + WorldUtil.getWorldName(this.world) + "', falling back to synchronous save", thr);
- failedAsyncPrepare = true;
- // fall through to synchronous save
+ if (unloading) {
+ NewChunkHolder.this.completeAsyncUnloadDataSave(MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, data);
}
- }
-
- final CompoundTag save = ChunkSerializer.write(this.world, chunk);
+ };
+ final PrioritisedExecutor.PrioritisedTask task;
if (unloading) {
- completing = true;
- this.completeAsyncUnloadDataSave(RegionFileIOThread.RegionFileType.CHUNK_DATA, save);
- if (failedAsyncPrepare) {
- LOGGER.info("Successfully serialized chunk data (" + this.chunkX + "," + this.chunkZ + ") in world '" + WorldUtil.getWorldName(this.world) + "' synchronously");
- }
+ this.chunkDataUnload.toRun().setRunnable(run);
+ task = this.chunkDataUnload.task();
} else {
- RegionFileIOThread.scheduleSave(this.world, this.chunkX, this.chunkZ, save, RegionFileIOThread.RegionFileType.CHUNK_DATA);
+ task = this.scheduler.saveExecutor.createTask(run);
}
- chunk.setUnsaved(false);
+
+ task.queue();
+
+ MoonriseRegionFileIO.scheduleSave(
+ this.world, this.chunkX, this.chunkZ, completable, task, MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, Priority.NORMAL
+ );
} catch (final Throwable thr) {
LOGGER.error("Failed to save chunk data (" + this.chunkX + "," + this.chunkZ + ") in world '" + WorldUtil.getWorldName(this.world) + "'", thr);
- if (unloading && !completing) {
- this.completeAsyncUnloadDataSave(RegionFileIOThread.RegionFileType.CHUNK_DATA, null);
- }
}
return true;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
return false;
}
try {
- mergeFrom = RegionFileIOThread.loadData(this.world, this.chunkX, this.chunkZ, RegionFileIOThread.RegionFileType.ENTITY_DATA, PrioritisedExecutor.Priority.BLOCKING);
+ mergeFrom = MoonriseRegionFileIO.loadData(this.world, this.chunkX, this.chunkZ, MoonriseRegionFileIO.RegionFileType.ENTITY_DATA, Priority.BLOCKING);
} catch (final Exception ex) {
LOGGER.error("Cannot merge transient entities for chunk (" + this.chunkX + "," + this.chunkZ + ") in world '" + WorldUtil.getWorldName(this.world) + "', data on disk will be replaced", ex);
}
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
return false;
}
- RegionFileIOThread.scheduleSave(this.world, this.chunkX, this.chunkZ, save, RegionFileIOThread.RegionFileType.ENTITY_DATA);
+ MoonriseRegionFileIO.scheduleSave(this.world, this.chunkX, this.chunkZ, save, MoonriseRegionFileIO.RegionFileType.ENTITY_DATA);
this.lastEntitySaveNull = save == null;
if (unloading) {
this.lastEntityUnload = save;
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
return false;
}
- RegionFileIOThread.scheduleSave(this.world, this.chunkX, this.chunkZ, save, RegionFileIOThread.RegionFileType.POI_DATA);
+ MoonriseRegionFileIO.scheduleSave(this.world, this.chunkX, this.chunkZ, save, MoonriseRegionFileIO.RegionFileType.POI_DATA);
this.lastPoiSaveNull = save == null;
if (unloading) {
this.poiDataUnload.completable().complete(save);
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
return element == null ? JsonNull.INSTANCE : new JsonPrimitive(element.toString());
}
- private static JsonObject serializeCompletable(final Completable> completable) {
+ private static JsonObject serializeCompletable(final CallbackCompletable> completable) {
final JsonObject ret = new JsonObject();
if (completable == null) {
@@ -0,0 +0,0 @@ public final class NewChunkHolder {
ret.add("poi_unload_completable", serializeCompletable(poiDataUnload == null ? null : poiDataUnload.completable()));
ret.add("chunk_unload_completable", serializeCompletable(chunkDataUnload == null ? null : chunkDataUnload.completable()));
- final DelayedPrioritisedTask unloadTask = chunkDataUnload == null ? null : chunkDataUnload.task();
+ final PrioritisedExecutor.PrioritisedTask unloadTask = chunkDataUnload == null ? null : chunkDataUnload.task();
if (unloadTask == null) {
ret.addProperty("unload_task_priority", "null");
- ret.addProperty("unload_task_priority_raw", "null");
+ ret.addProperty("unload_task_suborder", Long.valueOf(0L));
} else {
ret.addProperty("unload_task_priority", Objects.toString(unloadTask.getPriority()));
- ret.addProperty("unload_task_priority_raw", Integer.valueOf(unloadTask.getPriorityInternal()));
+ ret.addProperty("unload_task_suborder", Long.valueOf(unloadTask.getSubOrder()));
}
ret.addProperty("killed", Boolean.valueOf(this.unloaded));
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/PriorityHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/PriorityHolder.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/PriorityHolder.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/PriorityHolder.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
import java.lang.invoke.VarHandle;
public abstract class PriorityHolder {
@@ -0,0 +0,0 @@ public abstract class PriorityHolder {
PRIORITY_HANDLE.set((PriorityHolder)this, (int)val);
}
- protected PriorityHolder(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ protected PriorityHolder(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.setPriorityPlain(priority.priority);
@@ -0,0 +0,0 @@ public abstract class PriorityHolder {
return;
}
- this.scheduleTask(PrioritisedExecutor.Priority.getPriority(priority));
+ this.scheduleTask(Priority.getPriority(priority));
int failures = 0;
for (;;) {
@@ -0,0 +0,0 @@ public abstract class PriorityHolder {
return;
}
- this.setPriorityScheduled(PrioritisedExecutor.Priority.getPriority(priority));
+ this.setPriorityScheduled(Priority.getPriority(priority));
++failures;
for (int i = 0; i < failures; ++i) {
@@ -0,0 +0,0 @@ public abstract class PriorityHolder {
}
}
- public final PrioritisedExecutor.Priority getPriority() {
+ public final Priority getPriority() {
final int ret = this.getPriorityVolatile();
if ((ret & PRIORITY_EXECUTED) != 0) {
- return PrioritisedExecutor.Priority.COMPLETING;
+ return Priority.COMPLETING;
}
if ((ret & PRIORITY_SCHEDULED) != 0) {
return this.getScheduledPriority();
}
- return PrioritisedExecutor.Priority.getPriority(ret);
+ return Priority.getPriority(ret);
}
- public final void lowerPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public final void lowerPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public abstract class PriorityHolder {
}
}
- public final void setPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public final void setPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public abstract class PriorityHolder {
}
}
- public final void raisePriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public final void raisePriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public abstract class PriorityHolder {
protected abstract void cancelScheduled();
- protected abstract PrioritisedExecutor.Priority getScheduledPriority();
+ protected abstract Priority getScheduledPriority();
- protected abstract void scheduleTask(final PrioritisedExecutor.Priority priority);
+ protected abstract void scheduleTask(final Priority priority);
- protected abstract void lowerPriorityScheduled(final PrioritisedExecutor.Priority priority);
+ protected abstract void lowerPriorityScheduled(final Priority priority);
- protected abstract void setPriorityScheduled(final PrioritisedExecutor.Priority priority);
+ protected abstract void setPriorityScheduled(final Priority priority);
- protected abstract void raisePriorityScheduled(final PrioritisedExecutor.Priority priority);
+ protected abstract void raisePriorityScheduled(final Priority priority);
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
-
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
return Long.compare(t1.id, t2.id);
};
- private final DependencyTree[] queues = new DependencyTree[PrioritisedExecutor.Priority.TOTAL_SCHEDULABLE_PRIORITIES];
+ private final PrioritisedExecutor executor;
+ private final DependencyTree[] queues = new DependencyTree[Priority.TOTAL_SCHEDULABLE_PRIORITIES];
private static final int NO_TASKS_QUEUED = -1;
private int selectedQueue = NO_TASKS_QUEUED;
private boolean canQueueTasks = true;
public RadiusAwarePrioritisedExecutor(final PrioritisedExecutor executor, final int maxToSchedule) {
+ this.executor = executor;
+
for (int i = 0; i < this.queues.length; ++i) {
- this.queues[i] = new DependencyTree(this, executor, maxToSchedule, i);
+ this.queues[i] = new DependencyTree(this, executor, maxToSchedule);
+ }
+ }
+
+ public void setMaxToSchedule(final int maxToSchedule) {
+ final List tasks;
+
+ synchronized (this) {
+ for (final DependencyTree dependencyTree : this.queues) {
+ dependencyTree.maxToSchedule = maxToSchedule;
+ }
+
+ if (this.selectedQueue == NO_TASKS_QUEUED || !this.canQueueTasks) {
+ return;
+ }
+
+ tasks = this.queues[this.selectedQueue].tryPushTasks();
}
+
+ scheduleTasks(tasks);
}
private boolean canQueueTasks() {
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
return null;
}
- private List queue(final Task task, final PrioritisedExecutor.Priority priority) {
+ private List queue(final Task task, final Priority priority) {
final int priorityId = priority.priority;
final DependencyTree queue = this.queues[priorityId];
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
return null;
}
- if (PrioritisedExecutor.Priority.isHigherPriority(priorityId, this.selectedQueue)) {
+ if (Priority.isHigherPriority(priorityId, this.selectedQueue)) {
// prevent the lower priority tree from queueing more tasks
this.canQueueTasks = false;
return null;
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
}
public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius,
- final Runnable run, final PrioritisedExecutor.Priority priority) {
+ final Runnable run, final Priority priority) {
if (radius < 0) {
throw new IllegalArgumentException("Radius must be > 0: " + radius);
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius,
final Runnable run) {
- return this.createTask(chunkX, chunkZ, radius, run, PrioritisedExecutor.Priority.NORMAL);
+ return this.createTask(chunkX, chunkZ, radius, run, Priority.NORMAL);
}
public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius,
- final Runnable run, final PrioritisedExecutor.Priority priority) {
+ final Runnable run, final Priority priority) {
final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run, priority);
ret.queue();
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
return ret;
}
- public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final Priority priority) {
return new Task(this, 0, 0, -1, run, priority);
}
public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run) {
- return this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL);
+ return this.createInfiniteRadiusTask(run, Priority.NORMAL);
}
- public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final Priority priority) {
final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, priority);
ret.queue();
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
}
public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run) {
- final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL);
+ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, Priority.NORMAL);
ret.queue();
return ret;
}
+ private static void scheduleTasks(final List toSchedule) {
+ if (toSchedule != null) {
+ for (int i = 0, len = toSchedule.size(); i < len; ++i) {
+ toSchedule.get(i).queue();
+ }
+ }
+ }
+
// all accesses must be synchronised by the radius aware object
private static final class DependencyTree {
private final RadiusAwarePrioritisedExecutor scheduler;
private final PrioritisedExecutor executor;
- private final int maxToSchedule;
- private final int treeIndex;
+ private int maxToSchedule;
private int currentlyExecuting;
private long idGenerator;
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
private final Long2ReferenceOpenHashMap nodeByPosition = new Long2ReferenceOpenHashMap<>();
public DependencyTree(final RadiusAwarePrioritisedExecutor scheduler, final PrioritisedExecutor executor,
- final int maxToSchedule, final int treeIndex) {
+ final int maxToSchedule) {
this.scheduler = scheduler;
this.executor = executor;
this.maxToSchedule = maxToSchedule;
- this.treeIndex = treeIndex;
}
public boolean hasWaitingTasks() {
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
private final int chunkZ;
private final int radius;
private Runnable run;
- private PrioritisedExecutor.Priority priority;
+ private Priority priority;
private DependencyNode dependencyNode;
private PrioritisedExecutor.PrioritisedTask queuedTask;
private Task(final RadiusAwarePrioritisedExecutor scheduler, final int chunkX, final int chunkZ, final int radius,
- final Runnable run, final PrioritisedExecutor.Priority priority) {
+ final Runnable run, final Priority priority) {
this.scheduler = scheduler;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
run.run();
}
- private static void scheduleTasks(final List toSchedule) {
- if (toSchedule != null) {
- for (int i = 0, len = toSchedule.size(); i < len; ++i) {
- toSchedule.get(i).queue();
- }
- }
- }
-
private void returnNode() {
final List toSchedule;
synchronized (this.scheduler) {
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
scheduleTasks(toSchedule);
}
+ @Override
+ public PrioritisedExecutor getExecutor() {
+ return this.scheduler.executor;
+ }
+
@Override
public void run() {
final Runnable run = this.run;
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
public boolean queue() {
final List toSchedule;
synchronized (this.scheduler) {
- if (this.queuedTask != null || this.dependencyNode != null || this.priority == PrioritisedExecutor.Priority.COMPLETING) {
+ if (this.queuedTask != null || this.dependencyNode != null || this.priority == Priority.COMPLETING) {
return false;
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
return true;
}
+ @Override
+ public boolean isQueued() {
+ synchronized (this.scheduler) {
+ return (this.queuedTask != null || this.dependencyNode != null) && this.priority != Priority.COMPLETING;
+ }
+ }
+
@Override
public boolean cancel() {
final PrioritisedExecutor.PrioritisedTask task;
synchronized (this.scheduler) {
if ((task = this.queuedTask) == null) {
- if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
+ if (this.priority == Priority.COMPLETING) {
return false;
}
- this.priority = PrioritisedExecutor.Priority.COMPLETING;
+ this.priority = Priority.COMPLETING;
if (this.dependencyNode != null) {
this.dependencyNode.purged = true;
this.dependencyNode = null;
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
final PrioritisedExecutor.PrioritisedTask task;
synchronized (this.scheduler) {
if ((task = this.queuedTask) == null) {
- if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
+ if (this.priority == Priority.COMPLETING) {
return false;
}
- this.priority = PrioritisedExecutor.Priority.COMPLETING;
+ this.priority = Priority.COMPLETING;
if (this.dependencyNode != null) {
this.dependencyNode.purged = true;
this.dependencyNode = null;
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
}
@Override
- public PrioritisedExecutor.Priority getPriority() {
+ public Priority getPriority() {
final PrioritisedExecutor.PrioritisedTask task;
synchronized (this.scheduler) {
if ((task = this.queuedTask) == null) {
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
}
@Override
- public boolean setPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public boolean setPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
List toSchedule = null;
synchronized (this.scheduler) {
if ((task = this.queuedTask) == null) {
- if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
+ if (this.priority == Priority.COMPLETING) {
return false;
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
}
@Override
- public boolean raisePriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public boolean raisePriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
List toSchedule = null;
synchronized (this.scheduler) {
if ((task = this.queuedTask) == null) {
- if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
+ if (this.priority == Priority.COMPLETING) {
return false;
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
}
@Override
- public boolean lowerPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public boolean lowerPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
List toSchedule = null;
synchronized (this.scheduler) {
if ((task = this.queuedTask) == null) {
- if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
+ if (this.priority == Priority.COMPLETING) {
return false;
}
@@ -0,0 +0,0 @@ public class RadiusAwarePrioritisedExecutor {
return true;
}
+
+ @Override
+ public long getSubOrder() {
+ // TODO implement
+ return 0;
+ }
+
+ @Override
+ public boolean setSubOrder(final long subOrder) {
+ // TODO implement
+ return false;
+ }
+
+ @Override
+ public boolean raiseSubOrder(final long subOrder) {
+ // TODO implement
+ return false;
+ }
+
+ @Override
+ public boolean lowerSubOrder(final long subOrder) {
+ // TODO implement
+ return false;
+ }
+
+ @Override
+ public boolean setPriorityAndSubOrder(final Priority priority, final long subOrder) {
+ // TODO implement
+ return this.setPriority(priority);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
import ca.spottedleaf.moonrise.patches.chunk_system.level.poi.ChunkSystemPoiManager;
@@ -0,0 +0,0 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
private final PrioritisedExecutor.PrioritisedTask convertToFullTask;
public ChunkFullTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, final int chunkZ,
- final NewChunkHolder chunkHolder, final ChunkAccess fromChunk, final PrioritisedExecutor.Priority priority) {
+ final NewChunkHolder chunkHolder, final ChunkAccess fromChunk, final Priority priority) {
super(scheduler, world, chunkX, chunkZ);
this.chunkHolder = chunkHolder;
this.fromChunk = fromChunk;
@@ -0,0 +0,0 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
@Override
public void run() {
+ final PlatformHooks platformHooks = PlatformHooks.get();
+
// See Vanilla ChunkPyramid#LOADING_PYRAMID.FULL for what this function should be doing
final LevelChunk chunk;
try {
@@ -0,0 +0,0 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
final ServerLevel world = this.world;
final ProtoChunk protoChunk = (ProtoChunk)this.fromChunk;
chunk = new LevelChunk(this.world, protoChunk, (final LevelChunk unused) -> {
- ChunkStatusTasks.postLoadProtoChunk(world, protoChunk.getEntities(), protoChunk.getPos()); // Paper - pass chunk pos
+ PlatformHooks.get().postLoadProtoChunk(world, protoChunk);
});
this.chunkHolder.replaceProtoChunk(new ImposterProtoChunk(chunk, false));
}
@@ -0,0 +0,0 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
final NewChunkHolder chunkHolder = this.chunkHolder;
chunk.setFullStatus(chunkHolder::getChunkStatus);
- chunk.runPostLoad();
- // Unlike Vanilla, we load the entity chunk here, as we load the NBT in empty status (unlike Vanilla)
- // This brings entity addition back in line with older versions of the game
- // Since we load the NBT in the empty status, this will never block for I/O
- ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager.getOrCreateEntityChunk(this.chunkX, this.chunkZ, false);
-
- // we don't need the entitiesInLevel, not sure why it's there
- chunk.setLoaded(true);
- chunk.registerAllBlockEntitiesAfterLevelLoad();
- chunk.registerTickContainerInLevel(this.world);
+ try {
+ platformHooks.setCurrentlyLoading(this.chunkHolder.vanillaChunkHolder, chunk);
+ chunk.runPostLoad();
+ // Unlike Vanilla, we load the entity chunk here, as we load the NBT in empty status (unlike Vanilla)
+ // This brings entity addition back in line with older versions of the game
+ // Since we load the NBT in the empty status, this will never block for I/O
+ ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager.getOrCreateEntityChunk(this.chunkX, this.chunkZ, false);
+ chunk.setLoaded(true);
+ chunk.registerAllBlockEntitiesAfterLevelLoad();
+ chunk.registerTickContainerInLevel(this.world);
+ chunk.setUnsavedListener(this.world.getChunkSource().chunkMap.worldGenContext.unsavedListener());
+ platformHooks.chunkFullStatusComplete(chunk, (ProtoChunk)this.fromChunk);
+ } finally {
+ platformHooks.setCurrentlyLoading(this.chunkHolder.vanillaChunkHolder, null);
+ }
} catch (final Throwable throwable) {
this.complete(null, throwable);
return;
@@ -0,0 +0,0 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
}
@Override
- public PrioritisedExecutor.Priority getPriority() {
+ public Priority getPriority() {
return this.convertToFullTask.getPriority();
}
@Override
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void lowerPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.convertToFullTask.lowerPriority(priority);
}
@Override
- public void setPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void setPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.convertToFullTask.setPriority(priority);
}
@Override
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void raisePriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.convertToFullTask.raisePriority(priority);
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLightTask.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLightTask.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLightTask.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLightTask.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.PriorityHolder;
@@ -0,0 +0,0 @@ public final class ChunkLightTask extends ChunkProgressionTask {
private final LightTaskPriorityHolder priorityHolder;
public ChunkLightTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, final int chunkZ,
- final ChunkAccess chunk, final PrioritisedExecutor.Priority priority) {
+ final ChunkAccess chunk, final Priority priority) {
super(scheduler, world, chunkX, chunkZ);
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.priorityHolder = new LightTaskPriorityHolder(priority, this);
@@ -0,0 +0,0 @@ public final class ChunkLightTask extends ChunkProgressionTask {
}
@Override
- public PrioritisedExecutor.Priority getPriority() {
+ public Priority getPriority() {
return this.priorityHolder.getPriority();
}
@Override
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final Priority priority) {
this.priorityHolder.raisePriority(priority);
}
@Override
- public void setPriority(final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final Priority priority) {
this.priorityHolder.setPriority(priority);
}
@Override
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final Priority priority) {
this.priorityHolder.raisePriority(priority);
}
@@ -0,0 +0,0 @@ public final class ChunkLightTask extends ChunkProgressionTask {
private final ChunkLightTask task;
- private LightTaskPriorityHolder(final PrioritisedExecutor.Priority priority, final ChunkLightTask task) {
+ private LightTaskPriorityHolder(final Priority priority, final ChunkLightTask task) {
super(priority);
this.task = task;
}
@@ -0,0 +0,0 @@ public final class ChunkLightTask extends ChunkProgressionTask {
}
@Override
- protected PrioritisedExecutor.Priority getScheduledPriority() {
+ protected Priority getScheduledPriority() {
final ChunkLightTask task = this.task;
return ((StarLightLightingProvider)task.world.getChunkSource().getLightEngine()).starlight$getLightEngine().getServerLightQueue().getPriority(task.chunkX, task.chunkZ);
}
@Override
- protected void scheduleTask(final PrioritisedExecutor.Priority priority) {
+ protected void scheduleTask(final Priority priority) {
final ChunkLightTask task = this.task;
final StarLightInterface starLightInterface = ((StarLightLightingProvider)task.world.getChunkSource().getLightEngine()).starlight$getLightEngine();
final StarLightInterface.ServerLightQueue lightQueue = starLightInterface.getServerLightQueue();
@@ -0,0 +0,0 @@ public final class ChunkLightTask extends ChunkProgressionTask {
}
@Override
- protected void lowerPriorityScheduled(final PrioritisedExecutor.Priority priority) {
+ protected void lowerPriorityScheduled(final Priority priority) {
final ChunkLightTask task = this.task;
final StarLightInterface starLightInterface = ((StarLightLightingProvider)task.world.getChunkSource().getLightEngine()).starlight$getLightEngine();
final StarLightInterface.ServerLightQueue lightQueue = starLightInterface.getServerLightQueue();
@@ -0,0 +0,0 @@ public final class ChunkLightTask extends ChunkProgressionTask {
}
@Override
- protected void setPriorityScheduled(final PrioritisedExecutor.Priority priority) {
+ protected void setPriorityScheduled(final Priority priority) {
final ChunkLightTask task = this.task;
final StarLightInterface starLightInterface = ((StarLightLightingProvider)task.world.getChunkSource().getLightEngine()).starlight$getLightEngine();
final StarLightInterface.ServerLightQueue lightQueue = starLightInterface.getServerLightQueue();
@@ -0,0 +0,0 @@ public final class ChunkLightTask extends ChunkProgressionTask {
}
@Override
- protected void raisePriorityScheduled(final PrioritisedExecutor.Priority priority) {
+ protected void raisePriorityScheduled(final Priority priority) {
final ChunkLightTask task = this.task;
final StarLightInterface starLightInterface = ((StarLightLightingProvider)task.world.getChunkSource().getLightEngine()).starlight$getLightEngine();
final StarLightInterface.ServerLightQueue lightQueue = starLightInterface.getServerLightQueue();
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLoadTask.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLoadTask.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLoadTask.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkLoadTask.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task;
import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.patches.chunk_system.ChunkSystemConverters;
-import ca.spottedleaf.moonrise.patches.chunk_system.ChunkSystemFeatures;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import ca.spottedleaf.moonrise.patches.chunk_system.level.poi.PoiChunk;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.chunk.status.ChunkStatus;
-import net.minecraft.world.level.chunk.storage.ChunkSerializer;
+import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
private final AtomicInteger taskCountToComplete = new AtomicInteger(3); // one for poi, one for entity, and one for chunk data
public ChunkLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, final int chunkZ,
- final NewChunkHolder chunkHolder, final PrioritisedExecutor.Priority priority) {
+ final NewChunkHolder chunkHolder, final Priority priority) {
super(scheduler, world, chunkX, chunkZ);
this.chunkHolder = chunkHolder;
this.loadTask = new ChunkDataLoadTask(scheduler, world, chunkX, chunkZ, priority);
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
}
@Override
- public PrioritisedExecutor.Priority getPriority() {
+ public Priority getPriority() {
return this.loadTask.getPriority();
}
@Override
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final Priority priority) {
final EntityDataLoadTask entityLoad = this.chunkHolder.getEntityDataLoadTask();
if (entityLoad != null) {
entityLoad.lowerPriority(priority);
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
}
@Override
- public void setPriority(final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final Priority priority) {
final EntityDataLoadTask entityLoad = this.chunkHolder.getEntityDataLoadTask();
if (entityLoad != null) {
entityLoad.setPriority(priority);
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
}
@Override
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final Priority priority) {
final EntityDataLoadTask entityLoad = this.chunkHolder.getEntityDataLoadTask();
if (entityLoad != null) {
entityLoad.raisePriority(priority);
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
protected static final VarHandle COMPLETED_HANDLE = ConcurrentUtil.getVarHandle(CallbackDataLoadTask.class, "completed", boolean.class);
protected CallbackDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX,
- final int chunkZ, final RegionFileIOThread.RegionFileType type,
- final PrioritisedExecutor.Priority priority) {
+ final int chunkZ, final MoonriseRegionFileIO.RegionFileType type,
+ final Priority priority) {
super(scheduler, world, chunkX, chunkZ, type, priority);
}
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
}
}
- private static final class ChunkDataLoadTask extends CallbackDataLoadTask {
+
+ private static record ReadChunk(ProtoChunk protoChunk, SerializableChunkData chunkData) {}
+
+ private static final class ChunkDataLoadTask extends CallbackDataLoadTask {
private ChunkDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX,
- final int chunkZ, final PrioritisedExecutor.Priority priority) {
- super(scheduler, world, chunkX, chunkZ, RegionFileIOThread.RegionFileType.CHUNK_DATA, priority);
+ final int chunkZ, final Priority priority) {
+ super(scheduler, world, chunkX, chunkZ, MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, priority);
}
@Override
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
}
@Override
- protected PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ protected PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final Priority priority) {
return this.scheduler.loadExecutor.createTask(run, priority);
}
@Override
- protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final Priority priority) {
return this.scheduler.createChunkTask(this.chunkX, this.chunkZ, run, priority);
}
@Override
- protected TaskResult completeOnMainOffMain(final CompoundTag data, final Throwable throwable) {
+ protected TaskResult completeOnMainOffMain(final ReadChunk data, final Throwable throwable) {
if (throwable != null) {
return new TaskResult<>(null, throwable);
}
- if (data == null) {
+
+ if (data == null || data.protoChunk() == null) {
return new TaskResult<>(this.getEmptyChunk(), null);
}
- if (ChunkSystemFeatures.supportsAsyncChunkDeserialization()) {
- return this.deserialize(data);
+ if (!PlatformHooks.get().hasMainChunkLoadHook()) {
+ return new TaskResult<>(data.protoChunk(), null);
}
- // need to deserialize on main thread
+
+ // need to invoke the callback for loading on the main thread
return null;
}
private ProtoChunk getEmptyChunk() {
return new ProtoChunk(
new ChunkPos(this.chunkX, this.chunkZ), UpgradeData.EMPTY, this.world,
- this.world.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData)null
+ this.world.registryAccess().lookupOrThrow(Registries.BIOME), (BlendingData)null
);
}
@Override
- protected TaskResult runOffMain(final CompoundTag data, final Throwable throwable) {
+ protected TaskResult runOffMain(final CompoundTag data, final Throwable throwable) {
if (throwable != null) {
LOGGER.error("Failed to load chunk data for task: " + this.toString() + ", chunk data will be lost", throwable);
return new TaskResult<>(null, null);
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
try {
// run converters
- final CompoundTag converted = this.world.getChunkSource().chunkMap.upgradeChunkTag(data, new net.minecraft.world.level.ChunkPos(this.chunkX, this.chunkZ));
+ final CompoundTag converted = this.world.getChunkSource().chunkMap.upgradeChunkTag(data);
- return new TaskResult<>(converted, null);
- } catch (final Throwable thr2) {
- LOGGER.error("Failed to parse chunk data for task: " + this.toString() + ", chunk data will be lost", thr2);
- return new TaskResult<>(null, null);
- }
- }
+ // unpack the data
+ final SerializableChunkData chunkData = SerializableChunkData.parse(
+ this.world, this.world.registryAccess(), converted
+ );
- private TaskResult deserialize(final CompoundTag data) {
- try {
- final ChunkAccess deserialized = ChunkSerializer.read(
- this.world, this.world.getPoiManager(), this.world.getChunkSource().chunkMap.storageInfo(), new ChunkPos(this.chunkX, this.chunkZ), data
+ if (chunkData == null) {
+ LOGGER.error("Deserialized chunk for task: " + this.toString() + " produced null, chunk data will be lost?");
+ }
+
+ // read into ProtoChunk
+ final ProtoChunk chunk = chunkData == null ? null : chunkData.read(
+ this.world, this.world.getPoiManager(), this.world.getChunkSource().chunkMap.storageInfo(),
+ new ChunkPos(this.chunkX, this.chunkZ)
);
- return new TaskResult<>(deserialized, null);
+
+ return new TaskResult<>(new ReadChunk(chunk, chunkData), null);
} catch (final Throwable thr2) {
LOGGER.error("Failed to parse chunk data for task: " + this.toString() + ", chunk data will be lost", thr2);
- return new TaskResult<>(this.getEmptyChunk(), null);
+ return new TaskResult<>(null, null);
}
}
@Override
- protected TaskResult runOnMain(final CompoundTag data, final Throwable throwable) {
- // data != null && throwable == null
- if (ChunkSystemFeatures.supportsAsyncChunkDeserialization()) {
- throw new UnsupportedOperationException();
- }
- return this.deserialize(data);
+ protected TaskResult runOnMain(final ReadChunk data, final Throwable throwable) {
+ PlatformHooks.get().mainChunkLoad(data.protoChunk(), data.chunkData());
+
+ return new TaskResult<>(data.protoChunk(), null);
}
}
public static final class PoiDataLoadTask extends CallbackDataLoadTask {
public PoiDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX,
- final int chunkZ, final PrioritisedExecutor.Priority priority) {
- super(scheduler, world, chunkX, chunkZ, RegionFileIOThread.RegionFileType.POI_DATA, priority);
+ final int chunkZ, final Priority priority) {
+ super(scheduler, world, chunkX, chunkZ, MoonriseRegionFileIO.RegionFileType.POI_DATA, priority);
}
@Override
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
}
@Override
- protected PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ protected PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final Priority priority) {
return this.scheduler.loadExecutor.createTask(run, priority);
}
@Override
- protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final Priority priority) {
throw new UnsupportedOperationException();
}
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
public static final class EntityDataLoadTask extends CallbackDataLoadTask {
public EntityDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX,
- final int chunkZ, final PrioritisedExecutor.Priority priority) {
- super(scheduler, world, chunkX, chunkZ, RegionFileIOThread.RegionFileType.ENTITY_DATA, priority);
+ final int chunkZ, final Priority priority) {
+ super(scheduler, world, chunkX, chunkZ, MoonriseRegionFileIO.RegionFileType.ENTITY_DATA, priority);
}
@Override
@@ -0,0 +0,0 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
}
@Override
- protected PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ protected PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final Priority priority) {
return this.scheduler.loadExecutor.createTask(run, priority);
}
@Override
- protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final PrioritisedExecutor.Priority priority) {
+ protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final Priority priority) {
throw new UnsupportedOperationException();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task;
import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import net.minecraft.server.level.ServerLevel;
@@ -0,0 +0,0 @@ public abstract class ChunkProgressionTask {
/* May be called multiple times */
public abstract void cancel();
- public abstract PrioritisedExecutor.Priority getPriority();
+ public abstract Priority getPriority();
/* Schedule lock is always held for the priority update calls */
- public abstract void lowerPriority(final PrioritisedExecutor.Priority priority);
+ public abstract void lowerPriority(final Priority priority);
- public abstract void setPriority(final PrioritisedExecutor.Priority priority);
+ public abstract void setPriority(final Priority priority);
- public abstract void raisePriority(final PrioritisedExecutor.Priority priority);
+ public abstract void raisePriority(final Priority priority);
public final void onComplete(final BiConsumer onComplete) {
if (!this.waiters.add(onComplete)) {
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkStatus;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
@@ -0,0 +0,0 @@ public final class ChunkUpgradeGenericStatusTask extends ChunkProgressionTask im
public ChunkUpgradeGenericStatusTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX,
final int chunkZ, final ChunkAccess chunk, final StaticCache2D neighbours,
- final ChunkStatus toStatus, final PrioritisedExecutor.Priority priority) {
+ final ChunkStatus toStatus, final Priority priority) {
super(scheduler, world, chunkX, chunkZ);
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.fromChunk = chunk;
@@ -0,0 +0,0 @@ public final class ChunkUpgradeGenericStatusTask extends ChunkProgressionTask im
}
@Override
- public PrioritisedExecutor.Priority getPriority() {
+ public Priority getPriority() {
return this.generateTask.getPriority();
}
@Override
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void lowerPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.generateTask.lowerPriority(priority);
}
@Override
- public void setPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void setPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.generateTask.setPriority(priority);
}
@Override
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void raisePriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.generateTask.raisePriority(priority);
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task;
+import ca.spottedleaf.concurrentutil.completable.CallbackCompletable;
import ca.spottedleaf.concurrentutil.completable.Completable;
import ca.spottedleaf.concurrentutil.executor.Cancellable;
-import ca.spottedleaf.concurrentutil.executor.standard.DelayedPrioritisedTask;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
-import ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread;
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
protected final ServerLevel world;
protected final int chunkX;
protected final int chunkZ;
- protected final RegionFileIOThread.RegionFileType type;
+ protected final MoonriseRegionFileIO.RegionFileType type;
public GenericDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX,
- final int chunkZ, final RegionFileIOThread.RegionFileType type,
- final PrioritisedExecutor.Priority priority) {
+ final int chunkZ, final MoonriseRegionFileIO.RegionFileType type,
+ final Priority priority) {
this.scheduler = scheduler;
this.world = world;
this.chunkX = chunkX;
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
protected abstract boolean hasOnMain();
- protected abstract PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final PrioritisedExecutor.Priority priority);
+ protected abstract PrioritisedExecutor.PrioritisedTask createOffMain(final Runnable run, final Priority priority);
- protected abstract PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final PrioritisedExecutor.Priority priority);
+ protected abstract PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final Priority priority);
protected abstract TaskResult runOffMain(final CompoundTag data, final Throwable throwable);
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
", type: " + this.type.toString() + "}";
}
- public PrioritisedExecutor.Priority getPriority() {
+ public Priority getPriority() {
if (this.processOnMain != null) {
return this.processOnMain.getPriority();
} else {
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
}
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final Priority priority) {
// can't lower I/O tasks, we don't know what they affect
if (this.processOffMain != null) {
this.processOffMain.lowerPriority(priority);
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
}
- public void setPriority(final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final Priority priority) {
// can't lower I/O tasks, we don't know what they affect
this.loadDataFromDiskTask.raisePriority(priority);
if (this.processOffMain != null) {
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
}
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final Priority priority) {
// can't lower I/O tasks, we don't know what they affect
this.loadDataFromDiskTask.raisePriority(priority);
if (this.processOffMain != null) {
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
private final int chunkX;
private final int chunkZ;
- private final RegionFileIOThread.RegionFileType type;
+ private final MoonriseRegionFileIO.RegionFileType type;
private Cancellable dataLoadTask;
private Cancellable dataUnloadCancellable;
- private DelayedPrioritisedTask dataUnloadTask;
+ private PrioritisedExecutor.PrioritisedTask dataUnloadTask;
private final BiConsumer onComplete;
private final AtomicBoolean scheduled = new AtomicBoolean();
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
// onComplete should be caller sensitive, it may complete synchronously with schedule() - which does
// hold a priority lock.
public LoadDataFromDiskTask(final ServerLevel world, final int chunkX, final int chunkZ,
- final RegionFileIOThread.RegionFileType type,
+ final MoonriseRegionFileIO.RegionFileType type,
final BiConsumer onComplete,
- final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.world = world;
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
return (this.getPriorityVolatile() & PRIORITY_EXECUTED) != 0;
}
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void lowerPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
if ((curr & PRIORITY_LOAD_SCHEDULED) != 0) {
- RegionFileIOThread.lowerPriority(this.world, this.chunkX, this.chunkZ, this.type, priority);
+ MoonriseRegionFileIO.lowerPriority(this.world, this.chunkX, this.chunkZ, this.type, priority);
return;
}
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
}
- public void setPriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void setPriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
if ((curr & PRIORITY_LOAD_SCHEDULED) != 0) {
- RegionFileIOThread.setPriority(this.world, this.chunkX, this.chunkZ, this.type, priority);
+ MoonriseRegionFileIO.setPriority(this.world, this.chunkX, this.chunkZ, this.type, priority);
return;
}
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
}
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
- if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
+ public void raisePriority(final Priority priority) {
+ if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
if ((curr & PRIORITY_LOAD_SCHEDULED) != 0) {
- RegionFileIOThread.raisePriority(this.world, this.chunkX, this.chunkZ, this.type, priority);
+ MoonriseRegionFileIO.raisePriority(this.world, this.chunkX, this.chunkZ, this.type, priority);
return;
}
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
} // else: cancelled
};
- final PrioritisedExecutor.Priority initialPriority = PrioritisedExecutor.Priority.getPriority(priority);
+ final Priority initialPriority = Priority.getPriority(priority);
boolean scheduledUnload = false;
final NewChunkHolder holder = ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(this.chunkX, this.chunkZ);
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
consumer.accept(data, null);
} else {
// need to schedule task
- LoadDataFromDiskTask.this.schedule(false, consumer, PrioritisedExecutor.Priority.getPriority(LoadDataFromDiskTask.this.getPriorityVolatile() & ~PRIORITY_FLAGS));
+ LoadDataFromDiskTask.this.schedule(false, consumer, Priority.getPriority(LoadDataFromDiskTask.this.getPriorityVolatile() & ~PRIORITY_FLAGS));
}
};
Cancellable unloadCancellable = null;
CompoundTag syncComplete = null;
final NewChunkHolder.UnloadTask unloadTask = holder.getUnloadTask(this.type); // can be null if no task exists
- final Completable unloadCompletable = unloadTask == null ? null : unloadTask.completable();
+ final CallbackCompletable unloadCompletable = unloadTask == null ? null : unloadTask.completable();
if (unloadCompletable != null) {
unloadCancellable = unloadCompletable.addAsynchronousWaiter(unloadConsumer);
if (unloadCancellable == null) {
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
this.schedule(scheduledUnload, consumer, initialPriority);
}
- private void schedule(final boolean scheduledUnload, final BiConsumer consumer, final PrioritisedExecutor.Priority initialPriority) {
+ private void schedule(final boolean scheduledUnload, final BiConsumer consumer, final Priority initialPriority) {
int priority = this.getPriorityVolatile();
if ((priority & PRIORITY_EXECUTED) != 0) {
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
}
if (!scheduledUnload) {
- this.dataLoadTask = RegionFileIOThread.loadDataAsync(
+ this.dataLoadTask = MoonriseRegionFileIO.loadDataAsync(
this.world, this.chunkX, this.chunkZ, this.type, consumer,
- initialPriority.isHigherPriority(PrioritisedExecutor.Priority.NORMAL), initialPriority
+ initialPriority.isHigherPriority(Priority.NORMAL), initialPriority
);
}
@@ -0,0 +0,0 @@ public abstract class GenericDataLoadTask {
if (scheduledUnload) {
if (this.dataUnloadTask != null) {
- this.dataUnloadTask.setPriority(PrioritisedExecutor.Priority.getPriority(priority & ~PRIORITY_FLAGS));
+ this.dataUnloadTask.setPriority(Priority.getPriority(priority & ~PRIORITY_FLAGS));
}
} else {
- RegionFileIOThread.setPriority(this.world, this.chunkX, this.chunkZ, this.type, PrioritisedExecutor.Priority.getPriority(priority & ~PRIORITY_FLAGS));
+ MoonriseRegionFileIO.setPriority(this.world, this.chunkX, this.chunkZ, this.type, Priority.getPriority(priority & ~PRIORITY_FLAGS));
}
++failures;
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.chunk_system.storage;
+
+import net.minecraft.world.level.chunk.storage.RegionFile;
+import java.io.IOException;
+
+public interface ChunkSystemChunkBuffer {
+ public boolean moonrise$getWriteOnClose();
+
+ public void moonrise$setWriteOnClose(final boolean value);
+
+ public void moonrise$write(final RegionFile regionFile) throws IOException;
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemRegionFile.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemRegionFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemRegionFile.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.chunk_system.storage;
+
+import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.level.ChunkPos;
+import java.io.IOException;
+
+public interface ChunkSystemRegionFile {
+
+ public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(final CompoundTag data, final ChunkPos pos) throws IOException;
+
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.chunk_system.util;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
+import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongIterator;
@@ -0,0 +0,0 @@ public final class ParallelSearchRadiusIteration {
// expected that this list returns for a given radius, the set of chunks ordered
// by manhattan distance
- private static final long[][] SEARCH_RADIUS_ITERATION_LIST = new long[64+2+1][];
+ private static final long[][] SEARCH_RADIUS_ITERATION_LIST = new long[MoonriseConstants.MAX_VIEW_DISTANCE+2+1][];
static {
for (int i = 0; i < SEARCH_RADIUS_ITERATION_LIST.length; ++i) {
// a BFS around -x, -z, +x, +z will give increasing manhatten distance
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/util/stream/ExternalChunkStreamMarker.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/util/stream/ExternalChunkStreamMarker.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/util/stream/ExternalChunkStreamMarker.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.chunk_system.util.stream;
+
+import java.io.DataInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+
+/**
+ * Used to mark chunk data streams that are on external files
+ */
+public class ExternalChunkStreamMarker extends DataInputStream {
+
+ private static final Field IN_FIELD;
+ static {
+ Field field;
+ try {
+ field = FilterInputStream.class.getDeclaredField("in");
+ field.setAccessible(true);
+ } catch (final Throwable throwable) {
+ field = null;
+ }
+
+ IN_FIELD = field;
+ }
+
+ private static InputStream getWrapped(final FilterInputStream in) {
+ try {
+ return (InputStream)IN_FIELD.get(in);
+ } catch (final Throwable throwable) {
+ return in;
+ }
+ }
+
+ public ExternalChunkStreamMarker(final DataInputStream in) {
+ super(getWrapped(in));
+ }
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.collisions;
+import ca.spottedleaf.moonrise.common.util.WorldUtil;
+import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter;
+import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
+import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
+import ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData;
+import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionDiscreteVoxelShape;
+import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
+import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
+import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
+import it.unimi.dsi.fastutil.doubles.DoubleList;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.util.Mth;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.border.WorldBorder;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkSource;
+import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.PalettedContainer;
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import net.minecraft.world.level.material.FluidState;
+import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.Vec3;
+import net.minecraft.world.phys.shapes.ArrayVoxelShape;
+import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape;
+import net.minecraft.world.phys.shapes.BooleanOp;
+import net.minecraft.world.phys.shapes.CollisionContext;
+import net.minecraft.world.phys.shapes.DiscreteVoxelShape;
+import net.minecraft.world.phys.shapes.EntityCollisionContext;
+import net.minecraft.world.phys.shapes.OffsetDoubleList;
+import net.minecraft.world.phys.shapes.Shapes;
+import net.minecraft.world.phys.shapes.SliceShape;
+import net.minecraft.world.phys.shapes.VoxelShape;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+
public final class CollisionUtil {
public static final double COLLISION_EPSILON = 1.0E-7;
- public static final it.unimi.dsi.fastutil.doubles.DoubleArrayList ZERO_ONE = it.unimi.dsi.fastutil.doubles.DoubleArrayList.wrap(new double[] { 0.0, 1.0 });
+ public static final DoubleArrayList ZERO_ONE = DoubleArrayList.wrap(new double[] { 0.0, 1.0 });
public static boolean isSpecialCollidingBlock(final net.minecraft.world.level.block.state.BlockBehaviour.BlockStateBase block) {
- return block.hasLargeCollisionShape() || block.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON;
+ return block.hasLargeCollisionShape() || block.getBlock() == Blocks.MOVING_PISTON;
}
- public static boolean isEmpty(final net.minecraft.world.phys.AABB aabb) {
+ public static boolean isEmpty(final AABB aabb) {
return (aabb.maxX - aabb.minX) < COLLISION_EPSILON || (aabb.maxY - aabb.minY) < COLLISION_EPSILON || (aabb.maxZ - aabb.minZ) < COLLISION_EPSILON;
}
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return (maxX - minX) < COLLISION_EPSILON || (maxY - minY) < COLLISION_EPSILON || (maxZ - minZ) < COLLISION_EPSILON;
}
- public static net.minecraft.world.phys.AABB getBoxForChunk(final int chunkX, final int chunkZ) {
+ public static AABB getBoxForChunk(final int chunkX, final int chunkZ) {
double x = (double)(chunkX << 4);
double z = (double)(chunkZ << 4);
// use a bounding box bigger than the chunk to prevent entities from entering it on move
- return new net.minecraft.world.phys.AABB(x - 3*COLLISION_EPSILON, Double.NEGATIVE_INFINITY, z - 3*COLLISION_EPSILON,
+ return new AABB(x - 3*COLLISION_EPSILON, Double.NEGATIVE_INFINITY, z - 3*COLLISION_EPSILON,
x + (16.0 + 3*COLLISION_EPSILON), Double.POSITIVE_INFINITY, z + (16.0 + 3*COLLISION_EPSILON));
}
@@ -0,0 +0,0 @@ public final class CollisionUtil {
(minZ1 - maxZ2) < -COLLISION_EPSILON && (maxZ1 - minZ2) > COLLISION_EPSILON;
}
- public static boolean voxelShapeIntersect(final net.minecraft.world.phys.AABB box, final double minX, final double minY, final double minZ,
+ public static boolean voxelShapeIntersect(final AABB box, final double minX, final double minY, final double minZ,
final double maxX, final double maxY, final double maxZ) {
return (box.minX - maxX) < -COLLISION_EPSILON && (box.maxX - minX) > COLLISION_EPSILON &&
(box.minY - maxY) < -COLLISION_EPSILON && (box.maxY - minY) > COLLISION_EPSILON &&
(box.minZ - maxZ) < -COLLISION_EPSILON && (box.maxZ - minZ) > COLLISION_EPSILON;
}
- public static boolean voxelShapeIntersect(final net.minecraft.world.phys.AABB box1, final net.minecraft.world.phys.AABB box2) {
+ public static boolean voxelShapeIntersect(final AABB box1, final AABB box2) {
return (box1.minX - box2.maxX) < -COLLISION_EPSILON && (box1.maxX - box2.minX) > COLLISION_EPSILON &&
(box1.minY - box2.maxY) < -COLLISION_EPSILON && (box1.maxY - box2.minY) > COLLISION_EPSILON &&
(box1.minZ - box2.maxZ) < -COLLISION_EPSILON && (box1.maxZ - box2.minZ) > COLLISION_EPSILON;
}
// assume !isEmpty(target) && abs(source_move) >= COLLISION_EPSILON
- public static double collideX(final net.minecraft.world.phys.AABB target, final net.minecraft.world.phys.AABB source, final double source_move) {
+ public static double collideX(final AABB target, final AABB source, final double source_move) {
if ((source.minY - target.maxY) < -COLLISION_EPSILON && (source.maxY - target.minY) > COLLISION_EPSILON &&
(source.minZ - target.maxZ) < -COLLISION_EPSILON && (source.maxZ - target.minZ) > COLLISION_EPSILON) {
if (source_move >= 0.0) {
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
// assume !isEmpty(target) && abs(source_move) >= COLLISION_EPSILON
- public static double collideY(final net.minecraft.world.phys.AABB target, final net.minecraft.world.phys.AABB source, final double source_move) {
+ public static double collideY(final AABB target, final AABB source, final double source_move) {
if ((source.minX - target.maxX) < -COLLISION_EPSILON && (source.maxX - target.minX) > COLLISION_EPSILON &&
(source.minZ - target.maxZ) < -COLLISION_EPSILON && (source.maxZ - target.minZ) > COLLISION_EPSILON) {
if (source_move >= 0.0) {
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
// assume !isEmpty(target) && abs(source_move) >= COLLISION_EPSILON
- public static double collideZ(final net.minecraft.world.phys.AABB target, final net.minecraft.world.phys.AABB source, final double source_move) {
+ public static double collideZ(final AABB target, final AABB source, final double source_move) {
if ((source.minX - target.maxX) < -COLLISION_EPSILON && (source.maxX - target.minX) > COLLISION_EPSILON &&
(source.minY - target.maxY) < -COLLISION_EPSILON && (source.maxY - target.minY) > COLLISION_EPSILON) {
if (source_move >= 0.0) {
@@ -0,0 +0,0 @@ public final class CollisionUtil {
// startIndex and endIndex inclusive
// assumes indices are in range of array
- private static int findFloor(final double[] values, final double value, int startIndex, int endIndex) {
+ public static int findFloor(final double[] values, final double value, int startIndex, int endIndex) {
+ Objects.checkFromToIndex(startIndex, endIndex + 1, values.length);
do {
final int middle = (startIndex + endIndex) >>> 1;
final double middleVal = values[middle];
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return startIndex - 1;
}
- public static boolean voxelShapeIntersectNoEmpty(final net.minecraft.world.phys.shapes.VoxelShape voxel, final net.minecraft.world.phys.AABB aabb) {
+ private static VoxelShape sliceShapeVanilla(final VoxelShape src, final Direction.Axis axis,
+ final int index) {
+ return new SliceShape(src, axis, index);
+ }
+
+ private static DoubleList offsetList(final double[] src, final double by) {
+ final DoubleArrayList wrap = DoubleArrayList.wrap(src);
+ if (by == 0.0) {
+ return wrap;
+ }
+ return new OffsetDoubleList(wrap, by);
+ }
+
+ private static VoxelShape sliceShapeOptimised(final VoxelShape src, final Direction.Axis axis,
+ final int index) {
+ // assume index in range
+ final double off_x = ((CollisionVoxelShape)src).moonrise$offsetX();
+ final double off_y = ((CollisionVoxelShape)src).moonrise$offsetY();
+ final double off_z = ((CollisionVoxelShape)src).moonrise$offsetZ();
+
+ final double[] coords_x = ((CollisionVoxelShape)src).moonrise$rootCoordinatesX();
+ final double[] coords_y = ((CollisionVoxelShape)src).moonrise$rootCoordinatesY();
+ final double[] coords_z = ((CollisionVoxelShape)src).moonrise$rootCoordinatesZ();
+
+ final CachedShapeData cached_shape_data = ((CollisionVoxelShape)src).moonrise$getCachedVoxelData();
+
+ // note: size = coords.length - 1
+ final int size_x = cached_shape_data.sizeX();
+ final int size_y = cached_shape_data.sizeY();
+ final int size_z = cached_shape_data.sizeZ();
+
+ final long[] bitset = cached_shape_data.voxelSet();
+
+ final DoubleList list_x;
+ final DoubleList list_y;
+ final DoubleList list_z;
+ final int shape_sx;
+ final int shape_ex;
+ final int shape_sy;
+ final int shape_ey;
+ final int shape_sz;
+ final int shape_ez;
+
+ switch (axis) {
+ case X: {
+ // validate index
+ if (index < 0 || index >= size_x) {
+ return Shapes.empty();
+ }
+
+ // test if input is already "sliced"
+ if (coords_x.length == 2 && (coords_x[0] + off_x) == 0.0 && (coords_x[1] + off_x) == 1.0) {
+ return src;
+ }
+
+ // test if result would be full box
+ if (coords_y.length == 2 && coords_z.length == 2 &&
+ (coords_y[0] + off_y) == 0.0 && (coords_y[1] + off_y) == 1.0 &&
+ (coords_z[0] + off_z) == 0.0 && (coords_z[1] + off_z) == 1.0) {
+ // note: size_y == size_z == 1
+ final int bitIdx = 0 + 0*size_z + index*(size_z*size_y);
+ return (bitset[bitIdx >>> 6] & (1L << bitIdx)) == 0L ? Shapes.empty() : Shapes.block();
+ }
+
+ list_x = ZERO_ONE;
+ list_y = offsetList(coords_y, off_y);
+ list_z = offsetList(coords_z, off_z);
+ shape_sx = index;
+ shape_ex = index + 1;
+ shape_sy = 0;
+ shape_ey = size_y;
+ shape_sz = 0;
+ shape_ez = size_z;
+
+ break;
+ }
+ case Y: {
+ // validate index
+ if (index < 0 || index >= size_y) {
+ return Shapes.empty();
+ }
+
+ // test if input is already "sliced"
+ if (coords_y.length == 2 && (coords_y[0] + off_y) == 0.0 && (coords_y[1] + off_y) == 1.0) {
+ return src;
+ }
+
+ // test if result would be full box
+ if (coords_x.length == 2 && coords_z.length == 2 &&
+ (coords_x[0] + off_x) == 0.0 && (coords_x[1] + off_x) == 1.0 &&
+ (coords_z[0] + off_z) == 0.0 && (coords_z[1] + off_z) == 1.0) {
+ // note: size_x == size_z == 1
+ final int bitIdx = 0 + index*size_z + 0*(size_z*size_y);
+ return (bitset[bitIdx >>> 6] & (1L << bitIdx)) == 0L ? Shapes.empty() : Shapes.block();
+ }
+
+ list_x = offsetList(coords_x, off_x);
+ list_y = ZERO_ONE;
+ list_z = offsetList(coords_z, off_z);
+ shape_sx = 0;
+ shape_ex = size_x;
+ shape_sy = index;
+ shape_ey = index + 1;
+ shape_sz = 0;
+ shape_ez = size_z;
+
+ break;
+ }
+ case Z: {
+ // validate index
+ if (index < 0 || index >= size_z) {
+ return Shapes.empty();
+ }
+
+ // test if input is already "sliced"
+ if (coords_z.length == 2 && (coords_z[0] + off_z) == 0.0 && (coords_z[1] + off_z) == 1.0) {
+ return src;
+ }
+
+ // test if result would be full box
+ if (coords_x.length == 2 && coords_y.length == 2 &&
+ (coords_x[0] + off_x) == 0.0 && (coords_x[1] + off_x) == 1.0 &&
+ (coords_y[0] + off_y) == 0.0 && (coords_y[1] + off_y) == 1.0) {
+ // note: size_x == size_y == 1
+ final int bitIdx = index + 0*size_z + 0*(size_z*size_y);
+ return (bitset[bitIdx >>> 6] & (1L << bitIdx)) == 0L ? Shapes.empty() : Shapes.block();
+ }
+
+ list_x = offsetList(coords_x, off_x);
+ list_y = offsetList(coords_y, off_y);
+ list_z = ZERO_ONE;
+ shape_sx = 0;
+ shape_ex = size_x;
+ shape_sy = 0;
+ shape_ey = size_y;
+ shape_sz = index;
+ shape_ez = index + 1;
+
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unknown axis: " + axis);
+ }
+ }
+
+ final int local_len_x = shape_ex - shape_sx;
+ final int local_len_y = shape_ey - shape_sy;
+ final int local_len_z = shape_ez - shape_sz;
+
+ final BitSetDiscreteVoxelShape shape = new BitSetDiscreteVoxelShape(local_len_x, local_len_y, local_len_z);
+
+ final int bitset_mul_x = size_z*size_y;
+ final int idx_off = shape_sz + shape_sy*size_z + shape_sx*bitset_mul_x;
+ final int shape_mul_x = local_len_y*local_len_z;
+ for (int x = 0; x < local_len_x; ++x) {
+ boolean setX = false;
+ for (int y = 0; y < local_len_y; ++y) {
+ boolean setY = false;
+ for (int z = 0; z < local_len_z; ++z) {
+ final int unslicedIdx = idx_off + z + y*size_z + x*bitset_mul_x;
+ if ((bitset[unslicedIdx >>> 6] & (1L << unslicedIdx)) == 0L) {
+ continue;
+ }
+
+ setY = true;
+ setX = true;
+ shape.zMin = Math.min(shape.zMin, z);
+ shape.zMax = Math.max(shape.zMax, z + 1);
+
+ shape.storage.set(
+ z + y*local_len_z + x*shape_mul_x
+ );
+ }
+
+ if (setY) {
+ shape.yMin = Math.min(shape.yMin, y);
+ shape.yMax = Math.max(shape.yMax, y + 1);
+ }
+ }
+ if (setX) {
+ shape.xMin = Math.min(shape.xMin, x);
+ shape.xMax = Math.max(shape.xMax, x + 1);
+ }
+ }
+
+ return shape.isEmpty() ? Shapes.empty() : new ArrayVoxelShape(
+ shape, list_x, list_y, list_z
+ );
+ }
+
+ private static final boolean DEBUG_SLICE_SHAPE = false;
+
+ public static VoxelShape sliceShape(final VoxelShape src, final Direction.Axis axis,
+ final int index) {
+ final VoxelShape ret = sliceShapeOptimised(src, axis, index);
+ if (DEBUG_SLICE_SHAPE) {
+ final VoxelShape vanilla = sliceShapeVanilla(src, axis, index);
+ if (!equals(ret, vanilla)) {
+ // special case: SliceShape is not empty when it should be!
+ if (areAnyFull(ret.shape) || areAnyFull(vanilla.shape)) {
+ equals(ret, vanilla);
+ sliceShapeOptimised(src, axis, index);
+ throw new IllegalStateException("Slice shape mismatch");
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean voxelShapeIntersectNoEmpty(final VoxelShape voxel, final AABB aabb) {
if (voxel.isEmpty()) {
return false;
}
@@ -0,0 +0,0 @@ public final class CollisionUtil {
// note: this function assumes that for any i in coords that coord[i + 1] - coord[i] > COLLISION_EPSILON is true
// offsets that should be applied to coords
- final double off_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$offsetX();
- final double off_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$offsetY();
- final double off_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$offsetZ();
+ final double off_x = ((CollisionVoxelShape)voxel).moonrise$offsetX();
+ final double off_y = ((CollisionVoxelShape)voxel).moonrise$offsetY();
+ final double off_z = ((CollisionVoxelShape)voxel).moonrise$offsetZ();
- final double[] coords_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$rootCoordinatesX();
- final double[] coords_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$rootCoordinatesY();
- final double[] coords_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$rootCoordinatesZ();
+ final double[] coords_x = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesX();
+ final double[] coords_y = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesY();
+ final double[] coords_z = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesZ();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData cached_shape_data = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$getCachedVoxelData();
+ final CachedShapeData cached_shape_data = ((CollisionVoxelShape)voxel).moonrise$getCachedVoxelData();
// note: size = coords.length - 1
final int size_x = cached_shape_data.sizeX();
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
// assume !target.isEmpty() && abs(source_move) >= COLLISION_EPSILON
- public static double collideX(final net.minecraft.world.phys.shapes.VoxelShape target, final net.minecraft.world.phys.AABB source, final double source_move) {
- final net.minecraft.world.phys.AABB single_aabb = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$getSingleAABBRepresentation();
+ public static double collideX(final VoxelShape target, final AABB source, final double source_move) {
+ final AABB single_aabb = ((CollisionVoxelShape)target).moonrise$getSingleAABBRepresentation();
if (single_aabb != null) {
return collideX(single_aabb, source, source_move);
}
// note: this function assumes that for any i in coords that coord[i + 1] - coord[i] > COLLISION_EPSILON is true
// offsets that should be applied to coords
- final double off_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetX();
- final double off_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetY();
- final double off_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetZ();
+ final double off_x = ((CollisionVoxelShape)target).moonrise$offsetX();
+ final double off_y = ((CollisionVoxelShape)target).moonrise$offsetY();
+ final double off_z = ((CollisionVoxelShape)target).moonrise$offsetZ();
- final double[] coords_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesX();
- final double[] coords_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesY();
- final double[] coords_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesZ();
+ final double[] coords_x = ((CollisionVoxelShape)target).moonrise$rootCoordinatesX();
+ final double[] coords_y = ((CollisionVoxelShape)target).moonrise$rootCoordinatesY();
+ final double[] coords_z = ((CollisionVoxelShape)target).moonrise$rootCoordinatesZ();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData cached_shape_data = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$getCachedVoxelData();
+ final CachedShapeData cached_shape_data = ((CollisionVoxelShape)target).moonrise$getCachedVoxelData();
// note: size = coords.length - 1
final int size_x = cached_shape_data.sizeX();
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
}
- public static double collideY(final net.minecraft.world.phys.shapes.VoxelShape target, final net.minecraft.world.phys.AABB source, final double source_move) {
- final net.minecraft.world.phys.AABB single_aabb = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$getSingleAABBRepresentation();
+ public static double collideY(final VoxelShape target, final AABB source, final double source_move) {
+ final AABB single_aabb = ((CollisionVoxelShape)target).moonrise$getSingleAABBRepresentation();
if (single_aabb != null) {
return collideY(single_aabb, source, source_move);
}
// note: this function assumes that for any i in coords that coord[i + 1] - coord[i] > COLLISION_EPSILON is true
// offsets that should be applied to coords
- final double off_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetX();
- final double off_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetY();
- final double off_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetZ();
+ final double off_x = ((CollisionVoxelShape)target).moonrise$offsetX();
+ final double off_y = ((CollisionVoxelShape)target).moonrise$offsetY();
+ final double off_z = ((CollisionVoxelShape)target).moonrise$offsetZ();
- final double[] coords_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesX();
- final double[] coords_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesY();
- final double[] coords_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesZ();
+ final double[] coords_x = ((CollisionVoxelShape)target).moonrise$rootCoordinatesX();
+ final double[] coords_y = ((CollisionVoxelShape)target).moonrise$rootCoordinatesY();
+ final double[] coords_z = ((CollisionVoxelShape)target).moonrise$rootCoordinatesZ();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData cached_shape_data = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$getCachedVoxelData();
+ final CachedShapeData cached_shape_data = ((CollisionVoxelShape)target).moonrise$getCachedVoxelData();
// note: size = coords.length - 1
final int size_x = cached_shape_data.sizeX();
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
}
- public static double collideZ(final net.minecraft.world.phys.shapes.VoxelShape target, final net.minecraft.world.phys.AABB source, final double source_move) {
- final net.minecraft.world.phys.AABB single_aabb = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$getSingleAABBRepresentation();
+ public static double collideZ(final VoxelShape target, final AABB source, final double source_move) {
+ final AABB single_aabb = ((CollisionVoxelShape)target).moonrise$getSingleAABBRepresentation();
if (single_aabb != null) {
return collideZ(single_aabb, source, source_move);
}
// note: this function assumes that for any i in coords that coord[i + 1] - coord[i] > COLLISION_EPSILON is true
// offsets that should be applied to coords
- final double off_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetX();
- final double off_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetY();
- final double off_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$offsetZ();
+ final double off_x = ((CollisionVoxelShape)target).moonrise$offsetX();
+ final double off_y = ((CollisionVoxelShape)target).moonrise$offsetY();
+ final double off_z = ((CollisionVoxelShape)target).moonrise$offsetZ();
- final double[] coords_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesX();
- final double[] coords_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesY();
- final double[] coords_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$rootCoordinatesZ();
+ final double[] coords_x = ((CollisionVoxelShape)target).moonrise$rootCoordinatesX();
+ final double[] coords_y = ((CollisionVoxelShape)target).moonrise$rootCoordinatesY();
+ final double[] coords_z = ((CollisionVoxelShape)target).moonrise$rootCoordinatesZ();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData cached_shape_data = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)target).moonrise$getCachedVoxelData();
+ final CachedShapeData cached_shape_data = ((CollisionVoxelShape)target).moonrise$getCachedVoxelData();
// note: size = coords.length - 1
final int size_x = cached_shape_data.sizeX();
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
// does not use epsilon
- public static boolean strictlyContains(final net.minecraft.world.phys.shapes.VoxelShape voxel, final net.minecraft.world.phys.Vec3 point) {
+ public static boolean strictlyContains(final VoxelShape voxel, final Vec3 point) {
return strictlyContains(voxel, point.x, point.y, point.z);
}
// does not use epsilon
- public static boolean strictlyContains(final net.minecraft.world.phys.shapes.VoxelShape voxel, double x, double y, double z) {
- final net.minecraft.world.phys.AABB single_aabb = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$getSingleAABBRepresentation();
+ public static boolean strictlyContains(final VoxelShape voxel, double x, double y, double z) {
+ final AABB single_aabb = ((CollisionVoxelShape)voxel).moonrise$getSingleAABBRepresentation();
if (single_aabb != null) {
return single_aabb.contains(x, y, z);
}
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
// offset input
- x -= ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$offsetX();
- y -= ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$offsetY();
- z -= ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$offsetZ();
+ x -= ((CollisionVoxelShape)voxel).moonrise$offsetX();
+ y -= ((CollisionVoxelShape)voxel).moonrise$offsetY();
+ z -= ((CollisionVoxelShape)voxel).moonrise$offsetZ();
- final double[] coords_x = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$rootCoordinatesX();
- final double[] coords_y = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$rootCoordinatesY();
- final double[] coords_z = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$rootCoordinatesZ();
+ final double[] coords_x = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesX();
+ final double[] coords_y = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesY();
+ final double[] coords_z = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesZ();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData cached_shape_data = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$getCachedVoxelData();
+ final CachedShapeData cached_shape_data = ((CollisionVoxelShape)voxel).moonrise$getCachedVoxelData();
// note: size = coords.length - 1
final int size_x = cached_shape_data.sizeX();
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return ((ft ? 1 : 0) << 1) | ((tf ? 1 : 0) << 2) | ((tt ? 1 : 0) << 3);
}
- private static net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape merge(final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataFirst, final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataSecond,
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedX, final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedY,
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedZ,
- final int booleanOp) {
+ private static BitSetDiscreteVoxelShape merge(final CachedShapeData shapeDataFirst, final CachedShapeData shapeDataSecond,
+ final MergedVoxelCoordinateList mergedX, final MergedVoxelCoordinateList mergedY,
+ final MergedVoxelCoordinateList mergedZ,
+ final int booleanOp) {
final int sizeX = mergedX.voxels;
final int sizeY = mergedY.voxels;
final int sizeZ = mergedZ.voxels;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
final int s2Mul2 = s2Mul1 * shapeDataSecond.sizeY();
// note: indices may contain -1, but nothing > size
- final net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape ret = new net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape(sizeX, sizeY, sizeZ);
+ final BitSetDiscreteVoxelShape ret = new BitSetDiscreteVoxelShape(sizeX, sizeY, sizeZ);
boolean empty = true;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
final int s1z = mergedZ.firstIndices[idxZ];
final int s2z = mergedZ.secondIndices[idxZ];
- int idx;
+ int idx1;
+ int idx2;
- final int isS1Full = (s1x | s1y | s1z) < 0 ? 0 : (int)((s1Voxels[(idx = s1z + s1y*s1Mul1 + s1x*s1Mul2) >>> 6] >>> idx) & 1L);
- final int isS2Full = (s2x | s2y | s2z) < 0 ? 0 : (int)((s2Voxels[(idx = s2z + s2y*s2Mul1 + s2x*s2Mul2) >>> 6] >>> idx) & 1L);
+ final int isS1Full = (s1x | s1y | s1z) < 0 ? 0 : (int)((s1Voxels[(idx1 = s1z + s1y*s1Mul1 + s1x*s1Mul2) >>> 6] >>> idx1) & 1L);
+ final int isS2Full = (s2x | s2y | s2z) < 0 ? 0 : (int)((s2Voxels[(idx2 = s2z + s2y*s2Mul1 + s2x*s2Mul2) >>> 6] >>> idx2) & 1L);
// idx ff -> 0
// idx ft -> 1
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return empty ? null : ret;
}
- private static boolean isMergeEmpty(final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataFirst, final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataSecond,
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedX, final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedY,
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedZ,
+ private static boolean isMergeEmpty(final CachedShapeData shapeDataFirst, final CachedShapeData shapeDataSecond,
+ final MergedVoxelCoordinateList mergedX, final MergedVoxelCoordinateList mergedY,
+ final MergedVoxelCoordinateList mergedZ,
final int booleanOp) {
final int sizeX = mergedX.voxels;
final int sizeY = mergedY.voxels;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
final int s1z = mergedZ.firstIndices[idxZ];
final int s2z = mergedZ.secondIndices[idxZ];
- int idx;
+ int idx1;
+ int idx2;
- final int isS1Full = (s1x | s1y | s1z) < 0 ? 0 : (int)((s1Voxels[(idx = s1z + s1y*s1Mul1 + s1x*s1Mul2) >>> 6] >>> idx) & 1L);
- final int isS2Full = (s2x | s2y | s2z) < 0 ? 0 : (int)((s2Voxels[(idx = s2z + s2y*s2Mul1 + s2x*s2Mul2) >>> 6] >>> idx) & 1L);
+ final int isS1Full = (s1x | s1y | s1z) < 0 ? 0 : (int)((s1Voxels[(idx1 = s1z + s1y*s1Mul1 + s1x*s1Mul2) >>> 6] >>> idx1) & 1L);
+ final int isS2Full = (s2x | s2y | s2z) < 0 ? 0 : (int)((s2Voxels[(idx2 = s2z + s2y*s2Mul1 + s2x*s2Mul2) >>> 6] >>> idx2) & 1L);
// idx ff -> 0
// idx ft -> 1
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return true;
}
- public static net.minecraft.world.phys.shapes.VoxelShape joinOptimized(final net.minecraft.world.phys.shapes.VoxelShape first, final net.minecraft.world.phys.shapes.VoxelShape second, final net.minecraft.world.phys.shapes.BooleanOp operator) {
+ public static VoxelShape joinOptimized(final VoxelShape first, final VoxelShape second, final BooleanOp operator) {
return joinUnoptimized(first, second, operator).optimize();
}
- public static net.minecraft.world.phys.shapes.VoxelShape joinUnoptimized(final net.minecraft.world.phys.shapes.VoxelShape first, final net.minecraft.world.phys.shapes.VoxelShape second, final net.minecraft.world.phys.shapes.BooleanOp operator) {
+ public static VoxelShape joinUnoptimized(final VoxelShape first, final VoxelShape second, final BooleanOp operator) {
final boolean ff = operator.apply(false, false);
if (ff) {
// technically, should be an infinite box but that's clearly an error
@@ -0,0 +0,0 @@ public final class CollisionUtil {
final boolean tt = operator.apply(true, true);
if (first == second) {
- return tt ? first : net.minecraft.world.phys.shapes.Shapes.empty();
+ return tt ? first : Shapes.empty();
}
final boolean ft = operator.apply(false, true);
final boolean tf = operator.apply(true, false);
if (first.isEmpty()) {
- return ft ? second : net.minecraft.world.phys.shapes.Shapes.empty();
+ return ft ? second : Shapes.empty();
}
if (second.isEmpty()) {
- return tf ? first : net.minecraft.world.phys.shapes.Shapes.empty();
+ return tf ? first : Shapes.empty();
}
if (!tt) {
// try to check for no intersection, since tt = false
- final net.minecraft.world.phys.AABB aabbF = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getSingleAABBRepresentation();
- final net.minecraft.world.phys.AABB aabbS = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$getSingleAABBRepresentation();
+ final AABB aabbF = ((CollisionVoxelShape)first).moonrise$getSingleAABBRepresentation();
+ final AABB aabbS = ((CollisionVoxelShape)second).moonrise$getSingleAABBRepresentation();
final boolean intersect;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
if (!intersect) {
if (!tf & !ft) {
- return net.minecraft.world.phys.shapes.Shapes.empty();
+ return Shapes.empty();
}
if (!tf | !ft) {
return tf ? first : second;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
}
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedX = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.merge(
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$rootCoordinatesX(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$offsetX(),
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$rootCoordinatesX(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$offsetX(),
+ final MergedVoxelCoordinateList mergedX = MergedVoxelCoordinateList.merge(
+ ((CollisionVoxelShape)first).moonrise$rootCoordinatesX(), ((CollisionVoxelShape)first).moonrise$offsetX(),
+ ((CollisionVoxelShape)second).moonrise$rootCoordinatesX(), ((CollisionVoxelShape)second).moonrise$offsetX(),
ft, tf
);
- if (mergedX == ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.EMPTY) {
- return net.minecraft.world.phys.shapes.Shapes.empty();
+ if (mergedX == null) {
+ return Shapes.empty();
}
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedY = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.merge(
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$rootCoordinatesY(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$offsetY(),
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$rootCoordinatesY(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$offsetY(),
+ final MergedVoxelCoordinateList mergedY = MergedVoxelCoordinateList.merge(
+ ((CollisionVoxelShape)first).moonrise$rootCoordinatesY(), ((CollisionVoxelShape)first).moonrise$offsetY(),
+ ((CollisionVoxelShape)second).moonrise$rootCoordinatesY(), ((CollisionVoxelShape)second).moonrise$offsetY(),
ft, tf
);
- if (mergedY == ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.EMPTY) {
- return net.minecraft.world.phys.shapes.Shapes.empty();
+ if (mergedY == null) {
+ return Shapes.empty();
}
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedZ = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.merge(
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$rootCoordinatesZ(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$offsetZ(),
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$rootCoordinatesZ(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$offsetZ(),
+ final MergedVoxelCoordinateList mergedZ = MergedVoxelCoordinateList.merge(
+ ((CollisionVoxelShape)first).moonrise$rootCoordinatesZ(), ((CollisionVoxelShape)first).moonrise$offsetZ(),
+ ((CollisionVoxelShape)second).moonrise$rootCoordinatesZ(), ((CollisionVoxelShape)second).moonrise$offsetZ(),
ft, tf
);
- if (mergedZ == ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.EMPTY) {
- return net.minecraft.world.phys.shapes.Shapes.empty();
+ if (mergedZ == null) {
+ return Shapes.empty();
}
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataFirst = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getCachedVoxelData();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataSecond = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$getCachedVoxelData();
+ final CachedShapeData shapeDataFirst = ((CollisionVoxelShape)first).moonrise$getCachedVoxelData();
+ final CachedShapeData shapeDataSecond = ((CollisionVoxelShape)second).moonrise$getCachedVoxelData();
- final net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape mergedShape = merge(
+ final BitSetDiscreteVoxelShape mergedShape = merge(
shapeDataFirst, shapeDataSecond,
mergedX, mergedY, mergedZ,
makeBitset(ft, tf, tt)
);
if (mergedShape == null) {
- return net.minecraft.world.phys.shapes.Shapes.empty();
+ return Shapes.empty();
}
- return new net.minecraft.world.phys.shapes.ArrayVoxelShape(
+ return new ArrayVoxelShape(
mergedShape, mergedX.wrapCoords(), mergedY.wrapCoords(), mergedZ.wrapCoords()
);
}
- public static boolean isJoinNonEmpty(final net.minecraft.world.phys.shapes.VoxelShape first, final net.minecraft.world.phys.shapes.VoxelShape second, final net.minecraft.world.phys.shapes.BooleanOp operator) {
+ public static boolean isJoinNonEmpty(final VoxelShape first, final VoxelShape second, final BooleanOp operator) {
final boolean ff = operator.apply(false, false);
if (ff) {
// technically, should be an infinite box but that's clearly an error
@@ -0,0 +0,0 @@ public final class CollisionUtil {
final boolean tf = operator.apply(true, false);
// try to check intersection
- final net.minecraft.world.phys.AABB aabbF = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getSingleAABBRepresentation();
- final net.minecraft.world.phys.AABB aabbS = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$getSingleAABBRepresentation();
+ final AABB aabbF = ((CollisionVoxelShape)first).moonrise$getSingleAABBRepresentation();
+ final AABB aabbS = ((CollisionVoxelShape)second).moonrise$getSingleAABBRepresentation();
final boolean intersect;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
}
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedX = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.merge(
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$rootCoordinatesX(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$offsetX(),
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$rootCoordinatesX(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$offsetX(),
+ final MergedVoxelCoordinateList mergedX = MergedVoxelCoordinateList.merge(
+ ((CollisionVoxelShape)first).moonrise$rootCoordinatesX(), ((CollisionVoxelShape)first).moonrise$offsetX(),
+ ((CollisionVoxelShape)second).moonrise$rootCoordinatesX(), ((CollisionVoxelShape)second).moonrise$offsetX(),
ft, tf
);
- if (mergedX == ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.EMPTY) {
+ if (mergedX == null) {
return false;
}
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedY = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.merge(
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$rootCoordinatesY(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$offsetY(),
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$rootCoordinatesY(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$offsetY(),
+ final MergedVoxelCoordinateList mergedY = MergedVoxelCoordinateList.merge(
+ ((CollisionVoxelShape)first).moonrise$rootCoordinatesY(), ((CollisionVoxelShape)first).moonrise$offsetY(),
+ ((CollisionVoxelShape)second).moonrise$rootCoordinatesY(), ((CollisionVoxelShape)second).moonrise$offsetY(),
ft, tf
);
- if (mergedY == ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.EMPTY) {
+ if (mergedY == null) {
return false;
}
- final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList mergedZ = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.merge(
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$rootCoordinatesZ(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$offsetZ(),
- ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$rootCoordinatesZ(), ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$offsetZ(),
+ final MergedVoxelCoordinateList mergedZ = MergedVoxelCoordinateList.merge(
+ ((CollisionVoxelShape)first).moonrise$rootCoordinatesZ(), ((CollisionVoxelShape)first).moonrise$offsetZ(),
+ ((CollisionVoxelShape)second).moonrise$rootCoordinatesZ(), ((CollisionVoxelShape)second).moonrise$offsetZ(),
ft, tf
);
- if (mergedZ == ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList.EMPTY) {
+ if (mergedZ == null) {
return false;
}
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataFirst = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getCachedVoxelData();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeDataSecond = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$getCachedVoxelData();
+ final CachedShapeData shapeDataFirst = ((CollisionVoxelShape)first).moonrise$getCachedVoxelData();
+ final CachedShapeData shapeDataSecond = ((CollisionVoxelShape)second).moonrise$getCachedVoxelData();
return !isMergeEmpty(
shapeDataFirst, shapeDataSecond,
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
}
- private static final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList EMPTY = new ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList(
- new double[] { 0.0 }, 0.0, new int[0], new int[0], 0
- );
-
private static int[] getIndices(final int length) {
final int[] ret = new int[length];
@@ -0,0 +0,0 @@ public final class CollisionUtil {
this.voxels = voxels;
}
- public it.unimi.dsi.fastutil.doubles.DoubleList wrapCoords() {
+ public DoubleList wrapCoords() {
if (this.coordinateOffset == 0.0) {
- return it.unimi.dsi.fastutil.doubles.DoubleArrayList.wrap(this.coordinates, this.voxels + 1);
+ return DoubleArrayList.wrap(this.coordinates, this.voxels + 1);
}
- return new net.minecraft.world.phys.shapes.OffsetDoubleList(it.unimi.dsi.fastutil.doubles.DoubleArrayList.wrap(this.coordinates, this.voxels + 1), this.coordinateOffset);
+ return new OffsetDoubleList(DoubleArrayList.wrap(this.coordinates, this.voxels + 1), this.coordinateOffset);
}
// assume coordinates.length > 1
- public static ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList getForSingle(final double[] coordinates, final double offset) {
+ public static MergedVoxelCoordinateList getForSingle(final double[] coordinates, final double offset) {
final int voxels = coordinates.length - 1;
final int[] indices = voxels < SIMPLE_INDICES_CACHE.length ? SIMPLE_INDICES_CACHE[voxels] : getIndices(voxels);
- return new ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList(coordinates, offset, indices, indices, voxels);
+ return new MergedVoxelCoordinateList(coordinates, offset, indices, indices, voxels);
}
// assume coordinates.length > 1
- public static ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList merge(final double[] firstCoordinates, final double firstOffset,
- final double[] secondCoordinates, final double secondOffset,
- final boolean ft, final boolean tf) {
+ public static MergedVoxelCoordinateList merge(final double[] firstCoordinates, final double firstOffset,
+ final double[] secondCoordinates, final double secondOffset,
+ final boolean ft, final boolean tf) {
if (firstCoordinates == secondCoordinates && firstOffset == secondOffset) {
return getForSingle(firstCoordinates, firstOffset);
}
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
}
- return resultSize <= 1 ? EMPTY : new ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.MergedVoxelCoordinateList(coordinates, 0.0, firstIndices, secondIndices, resultSize - 1);
+ return resultSize <= 1 ? null : new MergedVoxelCoordinateList(coordinates, 0.0, firstIndices, secondIndices, resultSize - 1);
}
}
- public static boolean equals(final net.minecraft.world.phys.shapes.DiscreteVoxelShape shape1, final net.minecraft.world.phys.shapes.DiscreteVoxelShape shape2) {
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData cachedShapeData1 = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionDiscreteVoxelShape)shape1).moonrise$getOrCreateCachedShapeData();
- final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData cachedShapeData2 = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionDiscreteVoxelShape)shape2).moonrise$getOrCreateCachedShapeData();
+ public static boolean equals(final DiscreteVoxelShape shape1, final DiscreteVoxelShape shape2) {
+ final CachedShapeData cachedShapeData1 = ((CollisionDiscreteVoxelShape)shape1).moonrise$getOrCreateCachedShapeData();
+ final CachedShapeData cachedShapeData2 = ((CollisionDiscreteVoxelShape)shape2).moonrise$getOrCreateCachedShapeData();
final boolean isEmpty1 = cachedShapeData1.isEmpty();
final boolean isEmpty2 = cachedShapeData2.isEmpty();
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return true;
} else if (isEmpty1 ^ isEmpty2) {
return false;
- }
+ } // else: isEmpty1 = isEmpty2 = false
if (cachedShapeData1.hasSingleAABB() != cachedShapeData2.hasSingleAABB()) {
return false;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return false;
}
- return java.util.Arrays.equals(cachedShapeData1.voxelSet(), cachedShapeData2.voxelSet());
+ return Arrays.equals(cachedShapeData1.voxelSet(), cachedShapeData2.voxelSet());
}
// useful only for testing
- public static boolean equals(final net.minecraft.world.phys.shapes.VoxelShape shape1, final net.minecraft.world.phys.shapes.VoxelShape shape2) {
+ public static boolean equals(final VoxelShape shape1, final VoxelShape shape2) {
+ if (shape1.isEmpty() & shape2.isEmpty()) {
+ return true;
+ } else if (shape1.isEmpty() ^ shape2.isEmpty()) {
+ return false;
+ }
+
if (!equals(shape1.shape, shape2.shape)) {
return false;
}
- return shape1.getCoords(net.minecraft.core.Direction.Axis.X).equals(shape2.getCoords(net.minecraft.core.Direction.Axis.X)) &&
- shape1.getCoords(net.minecraft.core.Direction.Axis.Y).equals(shape2.getCoords(net.minecraft.core.Direction.Axis.Y)) &&
- shape1.getCoords(net.minecraft.core.Direction.Axis.Z).equals(shape2.getCoords(net.minecraft.core.Direction.Axis.Z));
+ return shape1.getCoords(Direction.Axis.X).equals(shape2.getCoords(Direction.Axis.X)) &&
+ shape1.getCoords(Direction.Axis.Y).equals(shape2.getCoords(Direction.Axis.Y)) &&
+ shape1.getCoords(Direction.Axis.Z).equals(shape2.getCoords(Direction.Axis.Z));
+ }
+
+ public static boolean areAnyFull(final DiscreteVoxelShape shape) {
+ if (shape.isEmpty()) {
+ return false;
+ }
+
+ final int sizeX = shape.getXSize();
+ final int sizeY = shape.getYSize();
+ final int sizeZ = shape.getZSize();
+
+ for (int x = 0; x < sizeX; ++x) {
+ for (int y = 0; y < sizeY; ++y) {
+ for (int z = 0; z < sizeZ; ++z) {
+ if (shape.isFull(x, y, z)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static String shapeMismatch(final DiscreteVoxelShape shape1, final DiscreteVoxelShape shape2) {
+ final CachedShapeData cachedShapeData1 = ((CollisionDiscreteVoxelShape)shape1).moonrise$getOrCreateCachedShapeData();
+ final CachedShapeData cachedShapeData2 = ((CollisionDiscreteVoxelShape)shape2).moonrise$getOrCreateCachedShapeData();
+
+ final boolean isEmpty1 = cachedShapeData1.isEmpty();
+ final boolean isEmpty2 = cachedShapeData2.isEmpty();
+
+ if (isEmpty1 & isEmpty2) {
+ return null;
+ } else if (isEmpty1 ^ isEmpty2) {
+ return null;
+ } // else: isEmpty1 = isEmpty2 = false
+
+ if (cachedShapeData1.sizeX() != cachedShapeData2.sizeX()) {
+ return "size x: " + cachedShapeData1.sizeX() + " != " + cachedShapeData2.sizeX();
+ }
+ if (cachedShapeData1.sizeY() != cachedShapeData2.sizeY()) {
+ return "size y: " + cachedShapeData1.sizeY() + " != " + cachedShapeData2.sizeY();
+ }
+ if (cachedShapeData1.sizeZ() != cachedShapeData2.sizeZ()) {
+ return "size z: " + cachedShapeData1.sizeZ() + " != " + cachedShapeData2.sizeZ();
+ }
+
+ final StringBuilder ret = new StringBuilder();
+
+ final int sizeX = cachedShapeData1.sizeX();;
+ final int sizeY = cachedShapeData1.sizeY();
+ final int sizeZ = cachedShapeData1.sizeZ();
+
+ boolean first = true;
+
+ for (int x = 0; x < sizeX; ++x) {
+ for (int y = 0; y < sizeY; ++y) {
+ for (int z = 0; z < sizeZ; ++z) {
+ final boolean isFull1 = shape1.isFull(x, y, z);
+ final boolean isFull2 = shape2.isFull(x, y, z);
+
+ if (isFull1 == isFull2) {
+ continue;
+ }
+
+ if (first) {
+ first = false;
+ } else {
+ ret.append(", ");
+ }
+
+ ret.append("(").append(x).append(",").append(y).append(",").append(z)
+ .append("): shape1: ").append(isFull1).append(", shape2: ").append(isFull2);
+ }
+ }
+ }
+
+ return ret.isEmpty() ? null : ret.toString();
}
- public static net.minecraft.world.phys.AABB offsetX(final net.minecraft.world.phys.AABB box, final double dx) {
- return new net.minecraft.world.phys.AABB(box.minX + dx, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ);
+ public static AABB offsetX(final AABB box, final double dx) {
+ return new AABB(box.minX + dx, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB offsetY(final net.minecraft.world.phys.AABB box, final double dy) {
- return new net.minecraft.world.phys.AABB(box.minX, box.minY + dy, box.minZ, box.maxX, box.maxY + dy, box.maxZ);
+ public static AABB offsetY(final AABB box, final double dy) {
+ return new AABB(box.minX, box.minY + dy, box.minZ, box.maxX, box.maxY + dy, box.maxZ);
}
- public static net.minecraft.world.phys.AABB offsetZ(final net.minecraft.world.phys.AABB box, final double dz) {
- return new net.minecraft.world.phys.AABB(box.minX, box.minY, box.minZ + dz, box.maxX, box.maxY, box.maxZ + dz);
+ public static AABB offsetZ(final AABB box, final double dz) {
+ return new AABB(box.minX, box.minY, box.minZ + dz, box.maxX, box.maxY, box.maxZ + dz);
}
- public static net.minecraft.world.phys.AABB expandRight(final net.minecraft.world.phys.AABB box, final double dx) { // dx > 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ);
+ public static AABB expandRight(final AABB box, final double dx) { // dx > 0.0
+ return new AABB(box.minX, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB expandLeft(final net.minecraft.world.phys.AABB box, final double dx) { // dx < 0.0
- return new net.minecraft.world.phys.AABB(box.minX - dx, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ);
+ public static AABB expandLeft(final AABB box, final double dx) { // dx < 0.0
+ return new AABB(box.minX - dx, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB expandUpwards(final net.minecraft.world.phys.AABB box, final double dy) { // dy > 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY + dy, box.maxZ);
+ public static AABB expandUpwards(final AABB box, final double dy) { // dy > 0.0
+ return new AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY + dy, box.maxZ);
}
- public static net.minecraft.world.phys.AABB expandDownwards(final net.minecraft.world.phys.AABB box, final double dy) { // dy < 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY - dy, box.minZ, box.maxX, box.maxY, box.maxZ);
+ public static AABB expandDownwards(final AABB box, final double dy) { // dy < 0.0
+ return new AABB(box.minX, box.minY - dy, box.minZ, box.maxX, box.maxY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB expandForwards(final net.minecraft.world.phys.AABB box, final double dz) { // dz > 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ + dz);
+ public static AABB expandForwards(final AABB box, final double dz) { // dz > 0.0
+ return new AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ + dz);
}
- public static net.minecraft.world.phys.AABB expandBackwards(final net.minecraft.world.phys.AABB box, final double dz) { // dz < 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY, box.minZ - dz, box.maxX, box.maxY, box.maxZ);
+ public static AABB expandBackwards(final AABB box, final double dz) { // dz < 0.0
+ return new AABB(box.minX, box.minY, box.minZ - dz, box.maxX, box.maxY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB cutRight(final net.minecraft.world.phys.AABB box, final double dx) { // dx > 0.0
- return new net.minecraft.world.phys.AABB(box.maxX, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ);
+ public static AABB cutRight(final AABB box, final double dx) { // dx > 0.0
+ return new AABB(box.maxX, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB cutLeft(final net.minecraft.world.phys.AABB box, final double dx) { // dx < 0.0
- return new net.minecraft.world.phys.AABB(box.minX + dx, box.minY, box.minZ, box.minX, box.maxY, box.maxZ);
+ public static AABB cutLeft(final AABB box, final double dx) { // dx < 0.0
+ return new AABB(box.minX + dx, box.minY, box.minZ, box.minX, box.maxY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB cutUpwards(final net.minecraft.world.phys.AABB box, final double dy) { // dy > 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.maxY, box.minZ, box.maxX, box.maxY + dy, box.maxZ);
+ public static AABB cutUpwards(final AABB box, final double dy) { // dy > 0.0
+ return new AABB(box.minX, box.maxY, box.minZ, box.maxX, box.maxY + dy, box.maxZ);
}
- public static net.minecraft.world.phys.AABB cutDownwards(final net.minecraft.world.phys.AABB box, final double dy) { // dy < 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY + dy, box.minZ, box.maxX, box.minY, box.maxZ);
+ public static AABB cutDownwards(final AABB box, final double dy) { // dy < 0.0
+ return new AABB(box.minX, box.minY + dy, box.minZ, box.maxX, box.minY, box.maxZ);
}
- public static net.minecraft.world.phys.AABB cutForwards(final net.minecraft.world.phys.AABB box, final double dz) { // dz > 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY, box.maxZ, box.maxX, box.maxY, box.maxZ + dz);
+ public static AABB cutForwards(final AABB box, final double dz) { // dz > 0.0
+ return new AABB(box.minX, box.minY, box.maxZ, box.maxX, box.maxY, box.maxZ + dz);
}
- public static net.minecraft.world.phys.AABB cutBackwards(final net.minecraft.world.phys.AABB box, final double dz) { // dz < 0.0
- return new net.minecraft.world.phys.AABB(box.minX, box.minY, box.minZ + dz, box.maxX, box.maxY, box.minZ);
+ public static AABB cutBackwards(final AABB box, final double dz) { // dz < 0.0
+ return new AABB(box.minX, box.minY, box.minZ + dz, box.maxX, box.maxY, box.minZ);
}
- public static double performAABBCollisionsX(final net.minecraft.world.phys.AABB currentBoundingBox, double value, final java.util.List potentialCollisions) {
+ public static double performAABBCollisionsX(final AABB currentBoundingBox, double value, final List potentialCollisions) {
for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
if (Math.abs(value) < COLLISION_EPSILON) {
return 0.0;
}
- final net.minecraft.world.phys.AABB target = potentialCollisions.get(i);
+ final AABB target = potentialCollisions.get(i);
value = collideX(target, currentBoundingBox, value);
}
- return value;
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
}
- public static double performAABBCollisionsY(final net.minecraft.world.phys.AABB currentBoundingBox, double value, final java.util.List potentialCollisions) {
+ public static double performAABBCollisionsY(final AABB currentBoundingBox, double value, final List potentialCollisions) {
for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
if (Math.abs(value) < COLLISION_EPSILON) {
return 0.0;
}
- final net.minecraft.world.phys.AABB target = potentialCollisions.get(i);
+ final AABB target = potentialCollisions.get(i);
value = collideY(target, currentBoundingBox, value);
}
- return value;
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
}
- public static double performAABBCollisionsZ(final net.minecraft.world.phys.AABB currentBoundingBox, double value, final java.util.List potentialCollisions) {
+ public static double performAABBCollisionsZ(final AABB currentBoundingBox, double value, final List potentialCollisions) {
for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
if (Math.abs(value) < COLLISION_EPSILON) {
return 0.0;
}
- final net.minecraft.world.phys.AABB target = potentialCollisions.get(i);
+ final AABB target = potentialCollisions.get(i);
value = collideZ(target, currentBoundingBox, value);
}
- return value;
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
}
- public static double performVoxelCollisionsX(final net.minecraft.world.phys.AABB currentBoundingBox, double value, final java.util.List potentialCollisions) {
+ public static double performVoxelCollisionsX(final AABB currentBoundingBox, double value, final List potentialCollisions) {
for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
if (Math.abs(value) < COLLISION_EPSILON) {
return 0.0;
}
- final net.minecraft.world.phys.shapes.VoxelShape target = potentialCollisions.get(i);
+ final VoxelShape target = potentialCollisions.get(i);
value = collideX(target, currentBoundingBox, value);
}
- return value;
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
}
- public static double performVoxelCollisionsY(final net.minecraft.world.phys.AABB currentBoundingBox, double value, final java.util.List potentialCollisions) {
+ public static double performVoxelCollisionsY(final AABB currentBoundingBox, double value, final List potentialCollisions) {
for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
if (Math.abs(value) < COLLISION_EPSILON) {
return 0.0;
}
- final net.minecraft.world.phys.shapes.VoxelShape target = potentialCollisions.get(i);
+ final VoxelShape target = potentialCollisions.get(i);
value = collideY(target, currentBoundingBox, value);
}
- return value;
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
}
- public static double performVoxelCollisionsZ(final net.minecraft.world.phys.AABB currentBoundingBox, double value, final java.util.List potentialCollisions) {
+ public static double performVoxelCollisionsZ(final AABB currentBoundingBox, double value, final List potentialCollisions) {
for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
if (Math.abs(value) < COLLISION_EPSILON) {
return 0.0;
}
- final net.minecraft.world.phys.shapes.VoxelShape target = potentialCollisions.get(i);
+ final VoxelShape target = potentialCollisions.get(i);
value = collideZ(target, currentBoundingBox, value);
}
- return value;
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
}
- public static net.minecraft.world.phys.Vec3 performVoxelCollisions(final net.minecraft.world.phys.Vec3 moveVector, net.minecraft.world.phys.AABB axisalignedbb, final java.util.List potentialCollisions) {
+ public static Vec3 performVoxelCollisions(final Vec3 moveVector, AABB axisalignedbb, final List potentialCollisions) {
double x = moveVector.x;
double y = moveVector.y;
double z = moveVector.z;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
z = performVoxelCollisionsZ(axisalignedbb, z, potentialCollisions);
}
- return new net.minecraft.world.phys.Vec3(x, y, z);
+ return new Vec3(x, y, z);
}
- public static net.minecraft.world.phys.Vec3 performAABBCollisions(final net.minecraft.world.phys.Vec3 moveVector, net.minecraft.world.phys.AABB axisalignedbb, final java.util.List potentialCollisions) {
+ public static Vec3 performAABBCollisions(final Vec3 moveVector, AABB axisalignedbb, final List potentialCollisions) {
double x = moveVector.x;
double y = moveVector.y;
double z = moveVector.z;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
z = performAABBCollisionsZ(axisalignedbb, z, potentialCollisions);
}
- return new net.minecraft.world.phys.Vec3(x, y, z);
+ return new Vec3(x, y, z);
}
- public static net.minecraft.world.phys.Vec3 performCollisions(final net.minecraft.world.phys.Vec3 moveVector, net.minecraft.world.phys.AABB axisalignedbb,
- final java.util.List voxels,
- final java.util.List aabbs) {
+ public static Vec3 performCollisions(final Vec3 moveVector, AABB axisalignedbb,
+ final List voxels,
+ final List aabbs) {
if (voxels.isEmpty()) {
// fast track only AABBs
return performAABBCollisions(moveVector, axisalignedbb, aabbs);
@@ -0,0 +0,0 @@ public final class CollisionUtil {
z = performVoxelCollisionsZ(axisalignedbb, z, voxels);
}
- return new net.minecraft.world.phys.Vec3(x, y, z);
+ return new Vec3(x, y, z);
}
- public static boolean isCollidingWithBorder(final net.minecraft.world.level.border.WorldBorder worldborder, final net.minecraft.world.phys.AABB boundingBox) {
+ public static boolean isCollidingWithBorder(final WorldBorder worldborder, final AABB boundingBox) {
return isCollidingWithBorder(worldborder, boundingBox.minX, boundingBox.maxX, boundingBox.minZ, boundingBox.maxZ);
}
- public static boolean isCollidingWithBorder(final net.minecraft.world.level.border.WorldBorder worldborder,
+ public static boolean isCollidingWithBorder(final WorldBorder worldborder,
final double boxMinX, final double boxMaxX,
final double boxMinZ, final double boxMaxZ) {
final double borderMinX = Math.floor(worldborder.getMinX()); // -X
@@ -0,0 +0,0 @@ public final class CollisionUtil {
final double borderMaxZ = Math.ceil(worldborder.getMaxZ()); // +Z
// inverted check for world border enclosing the specified box expanded by -EPSILON
- return (borderMinX - boxMinX) > ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON || (borderMaxX - boxMaxX) < -ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON ||
- (borderMinZ - boxMinZ) > ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON || (borderMaxZ - boxMaxZ) < -ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON;
+ return (borderMinX - boxMinX) > CollisionUtil.COLLISION_EPSILON || (borderMaxX - boxMaxX) < -CollisionUtil.COLLISION_EPSILON ||
+ (borderMinZ - boxMinZ) > CollisionUtil.COLLISION_EPSILON || (borderMaxZ - boxMaxZ) < -CollisionUtil.COLLISION_EPSILON;
}
/* Math.max/min specify that any NaN argument results in a NaN return, unlike these functions */
@@ -0,0 +0,0 @@ public final class CollisionUtil {
public static final int COLLISION_FLAG_CHECK_BORDER = 1 << 2;
public static final int COLLISION_FLAG_CHECK_ONLY = 1 << 3;
- public static boolean getCollisionsForBlocksOrWorldBorder(final net.minecraft.world.level.Level world, final net.minecraft.world.entity.Entity entity, final net.minecraft.world.phys.AABB aabb,
- final java.util.List intoVoxel, final java.util.List intoAABB,
- final int collisionFlags, final java.util.function.BiPredicate predicate) {
+ public static boolean getCollisionsForBlocksOrWorldBorder(final Level world, final Entity entity, final AABB aabb,
+ final List intoVoxel, final List intoAABB,
+ final int collisionFlags, final BiPredicate predicate) {
final boolean checkOnly = (collisionFlags & COLLISION_FLAG_CHECK_ONLY) != 0;
boolean ret = false;
if ((collisionFlags & COLLISION_FLAG_CHECK_BORDER) != 0) {
- final net.minecraft.world.level.border.WorldBorder worldBorder = world.getWorldBorder();
- if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isCollidingWithBorder(worldBorder, aabb) && entity != null && worldBorder.isInsideCloseToBorder(entity, aabb)) {
+ final WorldBorder worldBorder = world.getWorldBorder();
+ if (CollisionUtil.isCollidingWithBorder(worldBorder, aabb) && entity != null && worldBorder.isInsideCloseToBorder(entity, aabb)) {
if (checkOnly) {
return true;
} else {
- final net.minecraft.world.phys.shapes.VoxelShape borderShape = worldBorder.getCollisionShape();
+ final VoxelShape borderShape = worldBorder.getCollisionShape();
intoVoxel.add(borderShape);
ret = true;
}
}
}
- final int minSection = ((ca.spottedleaf.moonrise.patches.collisions.world.CollisionLevel)world).moonrise$getMinSection();
+ final int minSection = WorldUtil.getMinSection(world);
- final int minBlockX = net.minecraft.util.Mth.floor(aabb.minX - COLLISION_EPSILON) - 1;
- final int maxBlockX = net.minecraft.util.Mth.floor(aabb.maxX + COLLISION_EPSILON) + 1;
+ final int minBlockX = Mth.floor(aabb.minX - COLLISION_EPSILON) - 1;
+ final int maxBlockX = Mth.floor(aabb.maxX + COLLISION_EPSILON) + 1;
- final int minBlockY = Math.max((minSection << 4) - 1, net.minecraft.util.Mth.floor(aabb.minY - COLLISION_EPSILON) - 1);
- final int maxBlockY = Math.min((((ca.spottedleaf.moonrise.patches.collisions.world.CollisionLevel)world).moonrise$getMaxSection() << 4) + 16, net.minecraft.util.Mth.floor(aabb.maxY + COLLISION_EPSILON) + 1);
+ final int minBlockY = Math.max((minSection << 4) - 1, Mth.floor(aabb.minY - COLLISION_EPSILON) - 1);
+ final int maxBlockY = Math.min((WorldUtil.getMaxSection(world) << 4) + 16, Mth.floor(aabb.maxY + COLLISION_EPSILON) + 1);
- final int minBlockZ = net.minecraft.util.Mth.floor(aabb.minZ - COLLISION_EPSILON) - 1;
- final int maxBlockZ = net.minecraft.util.Mth.floor(aabb.maxZ + COLLISION_EPSILON) + 1;
+ final int minBlockZ = Mth.floor(aabb.minZ - COLLISION_EPSILON) - 1;
+ final int maxBlockZ = Mth.floor(aabb.maxZ + COLLISION_EPSILON) + 1;
- final net.minecraft.core.BlockPos.MutableBlockPos mutablePos = new net.minecraft.core.BlockPos.MutableBlockPos();
- final net.minecraft.world.phys.shapes.CollisionContext collisionShape = new ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.LazyEntityCollisionContext(entity);
+ final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
+ final CollisionContext collisionShape = new LazyEntityCollisionContext(entity);
// special cases:
if (minBlockY > maxBlockY) {
@@ -0,0 +0,0 @@ public final class CollisionUtil {
final int maxChunkZ = maxBlockZ >> 4;
final boolean loadChunks = (collisionFlags & COLLISION_FLAG_LOAD_CHUNKS) != 0;
- final net.minecraft.world.level.chunk.ChunkSource chunkSource = world.getChunkSource();
+ final ChunkSource chunkSource = world.getChunkSource();
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
- final net.minecraft.world.level.chunk.ChunkAccess chunk = chunkSource.getChunk(currChunkX, currChunkZ, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, loadChunks);
+ final ChunkAccess chunk = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, loadChunks);
if (chunk == null) {
if ((collisionFlags & COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS) != 0) {
@@ -0,0 +0,0 @@ public final class CollisionUtil {
continue;
}
- final net.minecraft.world.level.chunk.LevelChunkSection[] sections = chunk.getSections();
+ final LevelChunkSection[] sections = chunk.getSections();
// bound y
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
@@ -0,0 +0,0 @@ public final class CollisionUtil {
if (sectionIdx < 0 || sectionIdx >= sections.length) {
continue;
}
- final net.minecraft.world.level.chunk.LevelChunkSection section = sections[sectionIdx];
- if (section == null || section.hasOnlyAir()) {
+ final LevelChunkSection section = sections[sectionIdx];
+ if (section.hasOnlyAir()) {
// empty
continue;
}
- final boolean hasSpecial = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getSpecialCollidingBlocks() != 0;
+ final boolean hasSpecial = ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks();
final int sectionAdjust = !hasSpecial ? 1 : 0;
- final net.minecraft.world.level.chunk.PalettedContainer blocks = section.states;
+ final PalettedContainer blocks = section.states;
final int minXIterate = currChunkX == minChunkX ? (minBlockX & 15) + sectionAdjust : 0;
final int maxXIterate = currChunkX == maxChunkX ? (maxBlockX & 15) - sectionAdjust : 15;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
continue;
}
- final net.minecraft.world.level.block.state.BlockState blockData = blocks.get(localBlockIndex);
+ final BlockState blockData = blocks.get(localBlockIndex);
- if (((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)blockData).moonrise$emptyCollisionShape()) {
+ if (((CollisionBlockState)blockData).moonrise$emptyContextCollisionShape()) {
continue;
}
- net.minecraft.world.phys.shapes.VoxelShape blockCollision = ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)blockData).moonrise$getConstantCollisionShape();
+ VoxelShape blockCollision = ((CollisionBlockState)blockData).moonrise$getConstantContextCollisionShape();
- if (edgeCount == 0 || ((edgeCount != 1 || blockData.hasLargeCollisionShape()) && (edgeCount != 2 || blockData.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON))) {
+ if (edgeCount == 0 || ((edgeCount != 1 || blockData.hasLargeCollisionShape()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON))) {
if (blockCollision == null) {
mutablePos.set(blockX, blockY, blockZ);
blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape);
}
- net.minecraft.world.phys.AABB singleAABB = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)blockCollision).moonrise$getSingleAABBRepresentation();
+ AABB singleAABB = ((CollisionVoxelShape)blockCollision).moonrise$getSingleAABBRepresentation();
if (singleAABB != null) {
singleAABB = singleAABB.move((double)blockX, (double)blockY, (double)blockZ);
if (!voxelShapeIntersect(aabb, singleAABB)) {
@@ -0,0 +0,0 @@ public final class CollisionUtil {
continue;
}
- final net.minecraft.world.phys.shapes.VoxelShape blockCollisionOffset = blockCollision.move((double)blockX, (double)blockY, (double)blockZ);
+ final VoxelShape blockCollisionOffset = blockCollision.move((double)blockX, (double)blockY, (double)blockZ);
if (!voxelShapeIntersectNoEmpty(blockCollisionOffset, aabb)) {
continue;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return ret;
}
- public static boolean getEntityHardCollisions(final net.minecraft.world.level.Level world, final net.minecraft.world.entity.Entity entity, net.minecraft.world.phys.AABB aabb,
- final java.util.List into, final int collisionFlags, final java.util.function.Predicate predicate) {
+ public static boolean getEntityHardCollisions(final Level world, final Entity entity, AABB aabb,
+ final List into, final int collisionFlags, final Predicate predicate) {
final boolean checkOnly = (collisionFlags & COLLISION_FLAG_CHECK_ONLY) != 0;
boolean ret = false;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
// Vanilla for hard collisions has this backwards, and they expand by +epsilon but this causes terrible problems
// specifically with boat collisions.
aabb = aabb.inflate(-COLLISION_EPSILON, -COLLISION_EPSILON, -COLLISION_EPSILON);
- final java.util.List entities;
- if (entity != null && ((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)entity).moonrise$isHardColliding()) {
+ final List entities;
+ if (entity != null && ((ChunkSystemEntity)entity).moonrise$isHardColliding()) {
entities = world.getEntities(entity, aabb, predicate);
} else {
- entities = ((ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter)world).moonrise$getHardCollidingEntities(entity, aabb, predicate);
+ entities = ((ChunkSystemEntityGetter)world).moonrise$getHardCollidingEntities(entity, aabb, predicate);
}
for (int i = 0, len = entities.size(); i < len; ++i) {
- final net.minecraft.world.entity.Entity otherEntity = entities.get(i);
+ final Entity otherEntity = entities.get(i);
if (otherEntity.isSpectator()) {
continue;
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return ret;
}
- public static boolean getCollisions(final net.minecraft.world.level.Level world, final net.minecraft.world.entity.Entity entity, final net.minecraft.world.phys.AABB aabb,
- final java.util.List intoVoxel, final java.util.List intoAABB, final int collisionFlags,
- final java.util.function.BiPredicate blockPredicate,
- final java.util.function.Predicate entityPredicate) {
+ public static boolean getCollisions(final Level world, final Entity entity, final AABB aabb,
+ final List intoVoxel, final List intoAABB, final int collisionFlags,
+ final BiPredicate blockPredicate,
+ final Predicate entityPredicate) {
if ((collisionFlags & COLLISION_FLAG_CHECK_ONLY) != 0) {
return getCollisionsForBlocksOrWorldBorder(world, entity, aabb, intoVoxel, intoAABB, collisionFlags, blockPredicate)
|| getEntityHardCollisions(world, entity, aabb, intoAABB, collisionFlags, entityPredicate);
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
}
- public static final class LazyEntityCollisionContext extends net.minecraft.world.phys.shapes.EntityCollisionContext {
+ public static final class LazyEntityCollisionContext extends EntityCollisionContext {
- private net.minecraft.world.phys.shapes.CollisionContext delegate;
+ private CollisionContext delegate;
private boolean delegated;
- public LazyEntityCollisionContext(final net.minecraft.world.entity.Entity entity) {
+ public LazyEntityCollisionContext(final Entity entity) {
super(false, 0.0, null, null, entity);
}
@@ -0,0 +0,0 @@ public final class CollisionUtil {
return delegated;
}
- public net.minecraft.world.phys.shapes.CollisionContext getDelegate() {
+ public CollisionContext getDelegate() {
this.delegated = true;
- final net.minecraft.world.entity.Entity entity = this.getEntity();
- return this.delegate == null ? this.delegate = (entity == null ? net.minecraft.world.phys.shapes.CollisionContext.empty() : net.minecraft.world.phys.shapes.CollisionContext.of(entity)) : this.delegate;
+ final Entity entity = this.getEntity();
+ return this.delegate == null ? this.delegate = (entity == null ? CollisionContext.empty() : CollisionContext.of(entity)) : this.delegate;
}
@Override
@@ -0,0 +0,0 @@ public final class CollisionUtil {
}
@Override
- public boolean isAbove(final net.minecraft.world.phys.shapes.VoxelShape shape, final net.minecraft.core.BlockPos pos, final boolean defaultValue) {
+ public boolean isAbove(final VoxelShape shape, final BlockPos pos, final boolean defaultValue) {
return this.getDelegate().isAbove(shape, pos, defaultValue);
}
@Override
- public boolean isHoldingItem(final net.minecraft.world.item.Item item) {
+ public boolean isHoldingItem(final Item item) {
return this.getDelegate().isHoldingItem(item);
}
@Override
- public boolean canStandOnFluid(final net.minecraft.world.level.material.FluidState state, final net.minecraft.world.level.material.FluidState fluidState) {
+ public boolean canStandOnFluid(final FluidState state, final FluidState fluidState) {
return this.getDelegate().canStandOnFluid(state, fluidState);
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/ExplosionBlockCache.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/ExplosionBlockCache.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/ExplosionBlockCache.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/ExplosionBlockCache.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.collisions;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.FluidState;
+import net.minecraft.world.phys.shapes.VoxelShape;
+
public final class ExplosionBlockCache {
public final long key;
- public final net.minecraft.core.BlockPos immutablePos;
- public final net.minecraft.world.level.block.state.BlockState blockState;
- public final net.minecraft.world.level.material.FluidState fluidState;
+ public final BlockPos immutablePos;
+ public final BlockState blockState;
+ public final FluidState fluidState;
public final float resistance;
public final boolean outOfWorld;
public Boolean shouldExplode; // null -> not called yet
- public net.minecraft.world.phys.shapes.VoxelShape cachedCollisionShape;
+ public VoxelShape cachedCollisionShape;
- public ExplosionBlockCache(final long key, final net.minecraft.core.BlockPos immutablePos, final net.minecraft.world.level.block.state.BlockState blockState,
- final net.minecraft.world.level.material.FluidState fluidState, final float resistance, final boolean outOfWorld) {
+ public ExplosionBlockCache(final long key, final BlockPos immutablePos, final BlockState blockState,
+ final FluidState fluidState, final float resistance, final boolean outOfWorld) {
this.key = key;
this.immutablePos = immutablePos;
this.blockState = blockState;
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/block/CollisionBlockState.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/block/CollisionBlockState.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/block/CollisionBlockState.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/block/CollisionBlockState.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.collisions.block;
+import net.minecraft.world.phys.shapes.VoxelShape;
+
public interface CollisionBlockState {
// note: this does not consider canOcclude, it is only based on the cached collision shape (i.e hasCache())
@@ -0,0 +0,0 @@ public interface CollisionBlockState {
// whether the cached collision shape exists and is empty
public boolean moonrise$emptyCollisionShape();
+ // whether the context-sensitive shape is constant and is empty
+ public boolean moonrise$emptyContextCollisionShape();
+
// indicates that occludesFullBlock is cached for the collision shape
public boolean moonrise$hasCache();
@@ -0,0 +0,0 @@ public interface CollisionBlockState {
// value is still unique
public int moonrise$uniqueId2();
- public net.minecraft.world.phys.shapes.VoxelShape moonrise$getConstantCollisionShape();
-
- public net.minecraft.world.phys.AABB moonrise$getConstantCollisionAABB();
+ public VoxelShape moonrise$getConstantContextCollisionShape();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CachedToAABBs.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CachedToAABBs.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CachedToAABBs.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CachedToAABBs.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.collisions.shape;
+import net.minecraft.world.phys.AABB;
+import java.util.ArrayList;
+import java.util.List;
+
public record CachedToAABBs(
- java.util.List aabbs,
+ List aabbs,
boolean isOffset,
double offX, double offY, double offZ
) {
- public ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs removeOffset() {
- final java.util.List toOffset = this.aabbs;
+ public CachedToAABBs removeOffset() {
+ final List toOffset = this.aabbs;
final double offX = this.offX;
final double offY = this.offY;
final double offZ = this.offZ;
- final java.util.List ret = new java.util.ArrayList<>(toOffset.size());
+ final List ret = new ArrayList<>(toOffset.size());
for (int i = 0, len = toOffset.size(); i < len; ++i) {
ret.add(toOffset.get(i).move(offX, offY, offZ));
}
- return new ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs(ret, false, 0.0, 0.0, 0.0);
+ return new CachedToAABBs(ret, false, 0.0, 0.0, 0.0);
}
- public static ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs offset(final ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs cache, final double offX, final double offY, final double offZ) {
+ public static CachedToAABBs offset(final CachedToAABBs cache, final double offX, final double offY, final double offZ) {
if (offX == 0.0 && offY == 0.0 && offZ == 0.0) {
return cache;
}
@@ -0,0 +0,0 @@ public record CachedToAABBs(
final double resY = cache.offY + offY;
final double resZ = cache.offZ + offZ;
- return new ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs(cache.aabbs, true, resX, resY, resZ);
+ return new CachedToAABBs(cache.aabbs, true, resX, resY, resZ);
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionDiscreteVoxelShape.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionDiscreteVoxelShape.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionDiscreteVoxelShape.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionDiscreteVoxelShape.java
@@ -0,0 +0,0 @@ package ca.spottedleaf.moonrise.patches.collisions.shape;
public interface CollisionDiscreteVoxelShape {
- public ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData moonrise$getOrCreateCachedShapeData();
+ public CachedShapeData moonrise$getOrCreateCachedShapeData();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionVoxelShape.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionVoxelShape.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionVoxelShape.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/CollisionVoxelShape.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.collisions.shape;
+import net.minecraft.core.Direction;
+import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.shapes.VoxelShape;
+
public interface CollisionVoxelShape {
public double moonrise$offsetX();
@@ -0,0 +0,0 @@ public interface CollisionVoxelShape {
public double[] moonrise$rootCoordinatesZ();
- public ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData moonrise$getCachedVoxelData();
+ public CachedShapeData moonrise$getCachedVoxelData();
// rets null if not possible to represent this shape as one AABB
- public net.minecraft.world.phys.AABB moonrise$getSingleAABBRepresentation();
+ public AABB moonrise$getSingleAABBRepresentation();
// ONLY USE INTERNALLY, ONLY FOR INITIALISING IN CONSTRUCTOR: VOXELSHAPES ARE STATIC
public void moonrise$initCache();
// this returns empty if not clamped to 1.0 or 0.0 depending on direction
- public net.minecraft.world.phys.shapes.VoxelShape moonrise$getFaceShapeClamped(final net.minecraft.core.Direction direction);
+ public VoxelShape moonrise$getFaceShapeClamped(final Direction direction);
public boolean moonrise$isFullBlock();
@@ -0,0 +0,0 @@ public interface CollisionVoxelShape {
public boolean moonrise$occludesFullBlockIfCached();
// uses a cache internally
- public net.minecraft.world.phys.shapes.VoxelShape moonrise$orUnoptimized(final net.minecraft.world.phys.shapes.VoxelShape other);
+ public VoxelShape moonrise$orUnoptimized(final VoxelShape other);
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/MergedORCache.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/MergedORCache.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/MergedORCache.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/shape/MergedORCache.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.collisions.shape;
+import net.minecraft.world.phys.shapes.VoxelShape;
+
public record MergedORCache(
- net.minecraft.world.phys.shapes.VoxelShape key,
- net.minecraft.world.phys.shapes.VoxelShape result
+ VoxelShape key,
+ VoxelShape result
) {
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/util/EmptyStreamForMoveCall.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/util/EmptyStreamForMoveCall.java
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/util/EmptyStreamForMoveCall.java
+++ /dev/null
@@ -0,0 +0,0 @@
-package ca.spottedleaf.moonrise.patches.collisions.util;
-
-import java.util.Iterator;
-import java.util.Optional;
-import java.util.Spliterator;
-import java.util.stream.Stream;
-
-public final class EmptyStreamForMoveCall implements java.util.stream.Stream {
-
- public static final ca.spottedleaf.moonrise.patches.collisions.util.EmptyStreamForMoveCall INSTANCE = new ca.spottedleaf.moonrise.patches.collisions.util.EmptyStreamForMoveCall();
-
- @Override
- public boolean noneMatch(java.util.function.Predicate super T> predicate) {
- return false; // important: ret false so the branch is never taken by mojang code
- }
-
- @Override
- public java.util.stream.Stream filter(java.util.function.Predicate super T> predicate) {
- return null;
- }
-
- @Override
- public java.util.stream.Stream map(java.util.function.Function super T, ? extends R> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction super T> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction super T> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction super T> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.Stream flatMap(java.util.function.Function super T, ? extends java.util.stream.Stream extends R>> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.IntStream flatMapToInt(java.util.function.Function super T, ? extends java.util.stream.IntStream> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.LongStream flatMapToLong(java.util.function.Function super T, ? extends java.util.stream.LongStream> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function super T, ? extends java.util.stream.DoubleStream> mapper) {
- return null;
- }
-
- @Override
- public java.util.stream.Stream distinct() {
- return null;
- }
-
- @Override
- public java.util.stream.Stream sorted() {
- return null;
- }
-
- @Override
- public java.util.stream.Stream sorted(java.util.Comparator super T> comparator) {
- return null;
- }
-
- @Override
- public java.util.stream.Stream peek(java.util.function.Consumer super T> action) {
- return null;
- }
-
- @Override
- public java.util.stream.Stream limit(long maxSize) {
- return null;
- }
-
- @Override
- public java.util.stream.Stream skip(long n) {
- return null;
- }
-
- @Override
- public void forEach(java.util.function.Consumer super T> action) {
-
- }
-
- @Override
- public void forEachOrdered(java.util.function.Consumer super T> action) {
-
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Object[] toArray() {
- return new Object[0];
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public A[] toArray(java.util.function.IntFunction generator) {
- return null;
- }
-
- @Override
- public T reduce(T identity, java.util.function.BinaryOperator accumulator) {
- return null;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Optional reduce(java.util.function.BinaryOperator accumulator) {
- return java.util.Optional.empty();
- }
-
- @Override
- public U reduce(U identity, java.util.function.BiFunction accumulator, java.util.function.BinaryOperator combiner) {
- return null;
- }
-
- @Override
- public R collect(java.util.function.Supplier supplier, java.util.function.BiConsumer accumulator, java.util.function.BiConsumer combiner) {
- return null;
- }
-
- @Override
- public R collect(java.util.stream.Collector super T, A, R> collector) {
- return null;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Optional min(java.util.Comparator super T> comparator) {
- return java.util.Optional.empty();
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Optional max(java.util.Comparator super T> comparator) {
- return java.util.Optional.empty();
- }
-
- @Override
- public long count() {
- return 0;
- }
-
- @Override
- public boolean anyMatch(java.util.function.Predicate super T> predicate) {
- return false;
- }
-
- @Override
- public boolean allMatch(java.util.function.Predicate super T> predicate) {
- return false;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Optional findFirst() {
- return java.util.Optional.empty();
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Optional findAny() {
- return java.util.Optional.empty();
- }
-
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Iterator iterator() {
- return null;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Spliterator spliterator() {
- return null;
- }
-
- @Override
- public boolean isParallel() {
- return false;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Stream sequential() {
- return null;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Stream parallel() {
- return null;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Stream unordered() {
- return null;
- }
-
- @org.jetbrains.annotations.NotNull
- @Override
- public Stream onClose(Runnable closeHandler) {
- return null;
- }
-
- @Override
- public void close() {
-
- }
-}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.collisions.util;
-public record FluidOcclusionCacheKey(net.minecraft.world.level.block.state.BlockState first, net.minecraft.world.level.block.state.BlockState second, net.minecraft.core.Direction direction, boolean result) {
+import net.minecraft.core.Direction;
+import net.minecraft.world.level.block.state.BlockState;
+
+public record FluidOcclusionCacheKey(BlockState first, BlockState second, Direction direction, boolean result) {
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/world/CollisionLevel.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/world/CollisionLevel.java
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/world/CollisionLevel.java
+++ /dev/null
@@ -0,0 +0,0 @@
-package ca.spottedleaf.moonrise.patches.collisions.world;
-
-public interface CollisionLevel {
-
- public int moonrise$getMinSection();
-
- public int moonrise$getMaxSection();
-
-}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/entity_tracker/EntityTrackerTrackedEntity.java b/src/main/java/ca/spottedleaf/moonrise/patches/entity_tracker/EntityTrackerTrackedEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/entity_tracker/EntityTrackerTrackedEntity.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/entity_tracker/EntityTrackerTrackedEntity.java
@@ -0,0 +0,0 @@ public interface EntityTrackerTrackedEntity {
public void moonrise$clearPlayers();
+ public boolean moonrise$hasPlayers();
+
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/fast_palette/FastPalette.java b/src/main/java/ca/spottedleaf/moonrise/patches/fast_palette/FastPalette.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/fast_palette/FastPalette.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.fast_palette;
+
+public interface FastPalette {
+
+ public default T[] moonrise$getRawPalette(final FastPaletteData src) {
+ return null;
+ }
+
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/fast_palette/FastPaletteData.java b/src/main/java/ca/spottedleaf/moonrise/patches/fast_palette/FastPaletteData.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/fast_palette/FastPaletteData.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.fast_palette;
+
+public interface FastPaletteData {
+
+ public T[] moonrise$getPalette();
+
+ public void moonrise$setPalette(final T[] palette);
+
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/fluid/FluidFluidState.java b/src/main/java/ca/spottedleaf/moonrise/patches/fluid/FluidFluidState.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/fluid/FluidFluidState.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.fluid;
+
+public interface FluidFluidState {
+ public void moonrise$initCaches();
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_getblock/GetBlockChunk.java b/src/main/java/ca/spottedleaf/moonrise/patches/getblock/GetBlockChunk.java
similarity index 75%
rename from src/main/java/ca/spottedleaf/moonrise/patches/chunk_getblock/GetBlockChunk.java
rename to src/main/java/ca/spottedleaf/moonrise/patches/getblock/GetBlockChunk.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_getblock/GetBlockChunk.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/getblock/GetBlockChunk.java
@@ -0,0 +0,0 @@
-package ca.spottedleaf.moonrise.patches.chunk_getblock;
+package ca.spottedleaf.moonrise.patches.getblock;
import net.minecraft.world.level.block.state.BlockState;
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/blockstate/StarlightAbstractBlockState.java b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/blockstate/StarlightAbstractBlockState.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/blockstate/StarlightAbstractBlockState.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/blockstate/StarlightAbstractBlockState.java
@@ -0,0 +0,0 @@ public interface StarlightAbstractBlockState {
public boolean starlight$isConditionallyFullOpaque();
- public int starlight$getOpacityIfCached();
-
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/BlockStarLightEngine.java b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/BlockStarLightEngine.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/BlockStarLightEngine.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/BlockStarLightEngine.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.starlight.light;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.patches.starlight.blockstate.StarlightAbstractBlockState;
import ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk;
import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
@@ -0,0 +0,0 @@ public final class BlockStarLightEngine extends StarLightEngine {
final int currentLevel = this.getLightLevel(worldX, worldY, worldZ);
final BlockState blockState = this.getBlockState(worldX, worldY, worldZ);
- final int emittedLevel = blockState.getLightEmission() & emittedMask;
+ final int emittedLevel = (PlatformHooks.get().getLightEmission(blockState, lightAccess.getLevel(), this.lightEmissionPos.set(worldX, worldY, worldZ))) & emittedMask;
this.setLightLevel(worldX, worldY, worldZ, emittedLevel);
// this accounts for change in emitted light that would cause an increase
@@ -0,0 +0,0 @@ public final class BlockStarLightEngine extends StarLightEngine {
}
protected final BlockPos.MutableBlockPos recalcCenterPos = new BlockPos.MutableBlockPos();
- protected final BlockPos.MutableBlockPos recalcNeighbourPos = new BlockPos.MutableBlockPos();
@Override
protected int calculateLightValue(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ,
final int expect) {
+ this.recalcCenterPos.set(worldX, worldY, worldZ);
+
final BlockState centerState = this.getBlockState(worldX, worldY, worldZ);
- int level = centerState.getLightEmission() & 0xF;
+ final BlockGetter world = lightAccess.getLevel();
+ int level = (PlatformHooks.get().getLightEmission(centerState, world, this.recalcCenterPos)) & this.emittedLightMask;
if (level >= (15 - 1) || level > expect) {
return level;
}
- final int sectionOffset = this.chunkSectionIndexOffset;
- final BlockState conditionallyOpaqueState;
- int opacity = ((StarlightAbstractBlockState)centerState).starlight$getOpacityIfCached();
-
- if (opacity == -1) {
- this.recalcCenterPos.set(worldX, worldY, worldZ);
- opacity = centerState.getLightBlock(lightAccess.getLevel(), this.recalcCenterPos);
- if (((StarlightAbstractBlockState)centerState).starlight$isConditionallyFullOpaque()) {
- conditionallyOpaqueState = centerState;
- } else {
- conditionallyOpaqueState = null;
- }
- } else if (opacity >= 15) {
+ final int opacity = Math.max(1, centerState.getLightBlock());
+ if (opacity >= 15) {
return level;
+ }
+ final BlockState conditionallyOpaqueState;
+ if (((StarlightAbstractBlockState)centerState).starlight$isConditionallyFullOpaque()) {
+ conditionallyOpaqueState = centerState;
} else {
conditionallyOpaqueState = null;
}
- opacity = Math.max(1, opacity);
+ final int sectionOffset = this.chunkSectionIndexOffset;
for (final AxisDirection direction : AXIS_DIRECTIONS) {
final int offX = worldX + direction.x;
final int offY = worldY + direction.y;
@@ -0,0 +0,0 @@ public final class BlockStarLightEngine extends StarLightEngine {
// here the block can be conditionally opaque (i.e light cannot propagate from it), so we need to test that
// we don't read the blockstate because most of the time this is false, so using the faster
// known transparency lookup results in a net win
- this.recalcNeighbourPos.set(offX, offY, offZ);
- final VoxelShape neighbourFace = neighbourState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcNeighbourPos, direction.opposite.nms);
- final VoxelShape thisFace = conditionallyOpaqueState == null ? Shapes.empty() : conditionallyOpaqueState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcCenterPos, direction.nms);
+ final VoxelShape neighbourFace = neighbourState.getFaceOcclusionShape(direction.opposite.nms);
+ final VoxelShape thisFace = conditionallyOpaqueState == null ? Shapes.empty() : conditionallyOpaqueState.getFaceOcclusionShape(direction.nms);
if (Shapes.faceShapeOccludes(thisFace, neighbourFace)) {
// not allowed to propagate
continue;
@@ -0,0 +0,0 @@ public final class BlockStarLightEngine extends StarLightEngine {
final int offX = chunk.getPos().x << 4;
final int offZ = chunk.getPos().z << 4;
+ final PlatformHooks platformHooks = PlatformHooks.get();
+
+ final BlockGetter world = lightAccess.getLevel();
final LevelChunkSection[] sections = chunk.getSections();
for (int sectionY = this.minSection; sectionY <= this.maxSection; ++sectionY) {
final LevelChunkSection section = sections[sectionY - this.minSection];
- if (section == null || section.hasOnlyAir()) {
+ if (section.hasOnlyAir()) {
// no sources in empty sections
continue;
}
- if (!section.maybeHas((final BlockState state) -> {
- return state.getLightEmission() > 0;
- })) {
+ if (!section.maybeHas(platformHooks.maybeHasLightEmission())) {
// no light sources in palette
continue;
}
final PalettedContainer states = section.states;
final int offY = sectionY << 4;
+ final BlockPos.MutableBlockPos mutablePos = this.lightEmissionPos;
for (int index = 0; index < (16 * 16 * 16); ++index) {
final BlockState state = states.get(index);
- if (state.getLightEmission() <= 0) {
+ mutablePos.set(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15));
+
+ if ((platformHooks.getLightEmission(state, world, mutablePos)) == 0) {
continue;
}
// index = x | (z << 4) | (y << 8)
- sources.add(new BlockPos(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15)));
+ sources.add(mutablePos.immutable());
}
}
@@ -0,0 +0,0 @@ public final class BlockStarLightEngine extends StarLightEngine {
@Override
public void lightChunk(final LightChunkGetter lightAccess, final ChunkAccess chunk, final boolean needsEdgeChecks) {
// setup sources
+ final BlockGetter world = lightAccess.getLevel();
+ final PlatformHooks platformHooks = PlatformHooks.get();
+
final int emittedMask = this.emittedLightMask;
final List positions = this.getSources(lightAccess, chunk);
for (int i = 0, len = positions.size(); i < len; ++i) {
final BlockPos pos = positions.get(i);
final BlockState blockState = this.getBlockState(pos.getX(), pos.getY(), pos.getZ());
- final int emittedLight = blockState.getLightEmission() & emittedMask;
+ final int emittedLight = platformHooks.getLightEmission(blockState, world, pos) & emittedMask;
if (emittedLight <= this.getLightLevel(pos.getX(), pos.getY(), pos.getZ())) {
// some other source is brighter
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/SkyStarLightEngine.java b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/SkyStarLightEngine.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/SkyStarLightEngine.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/SkyStarLightEngine.java
@@ -0,0 +0,0 @@ public final class SkyStarLightEngine extends StarLightEngine {
);
}
- protected final BlockPos.MutableBlockPos recalcCenterPos = new BlockPos.MutableBlockPos();
- protected final BlockPos.MutableBlockPos recalcNeighbourPos = new BlockPos.MutableBlockPos();
-
@Override
protected int calculateLightValue(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ,
final int expect) {
@@ -0,0 +0,0 @@ public final class SkyStarLightEngine extends StarLightEngine {
final int sectionOffset = this.chunkSectionIndexOffset;
final BlockState centerState = this.getBlockState(worldX, worldY, worldZ);
- int opacity = ((StarlightAbstractBlockState)centerState).starlight$getOpacityIfCached();
final BlockState conditionallyOpaqueState;
- if (opacity < 0) {
- this.recalcCenterPos.set(worldX, worldY, worldZ);
- opacity = Math.max(1, centerState.getLightBlock(lightAccess.getLevel(), this.recalcCenterPos));
- if (((StarlightAbstractBlockState)centerState).starlight$isConditionallyFullOpaque()) {
- conditionallyOpaqueState = centerState;
- } else {
- conditionallyOpaqueState = null;
- }
+ final int opacity = Math.max(1, centerState.getLightBlock());
+ if (((StarlightAbstractBlockState)centerState).starlight$isConditionallyFullOpaque()) {
+ conditionallyOpaqueState = centerState;
} else {
conditionallyOpaqueState = null;
- opacity = Math.max(1, opacity);
}
int level = 0;
@@ -0,0 +0,0 @@ public final class SkyStarLightEngine extends StarLightEngine {
// here the block can be conditionally opaque (i.e light cannot propagate from it), so we need to test that
// we don't read the blockstate because most of the time this is false, so using the faster
// known transparency lookup results in a net win
- this.recalcNeighbourPos.set(offX, offY, offZ);
- final VoxelShape neighbourFace = neighbourState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcNeighbourPos, direction.opposite.nms);
- final VoxelShape thisFace = conditionallyOpaqueState == null ? Shapes.empty() : conditionallyOpaqueState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcCenterPos, direction.nms);
+ final VoxelShape neighbourFace = neighbourState.getFaceOcclusionShape(direction.opposite.nms);
+ final VoxelShape thisFace = conditionallyOpaqueState == null ? Shapes.empty() : conditionallyOpaqueState.getFaceOcclusionShape(direction.nms);
if (Shapes.faceShapeOccludes(thisFace, neighbourFace)) {
// not allowed to propagate
continue;
@@ -0,0 +0,0 @@ public final class SkyStarLightEngine extends StarLightEngine {
// clobbering the light values will result in broken propagation)
protected final int tryPropagateSkylight(final BlockGetter world, final int worldX, int startY, final int worldZ,
final boolean extrudeInitialised, final boolean delayLightSet) {
- final BlockPos.MutableBlockPos mutablePos = this.mutablePos3;
final int encodeOffset = this.coordinateOffset;
final long propagateDirection = AxisDirection.POSITIVE_Y.everythingButThisDirection; // just don't check upwards.
@@ -0,0 +0,0 @@ public final class SkyStarLightEngine extends StarLightEngine {
final VoxelShape fromShape;
if (((StarlightAbstractBlockState)above).starlight$isConditionallyFullOpaque()) {
- this.mutablePos2.set(worldX, startY + 1, worldZ);
- fromShape = above.getFaceOcclusionShape(world, this.mutablePos2, AxisDirection.NEGATIVE_Y.nms);
+ fromShape = above.getFaceOcclusionShape(AxisDirection.NEGATIVE_Y.nms);
if (Shapes.faceShapeOccludes(Shapes.empty(), fromShape)) {
// above wont let us propagate
break;
@@ -0,0 +0,0 @@ public final class SkyStarLightEngine extends StarLightEngine {
fromShape = Shapes.empty();
}
- final int opacityIfCached = ((StarlightAbstractBlockState)current).starlight$getOpacityIfCached();
// does light propagate from the top down?
- if (opacityIfCached != -1) {
- if (opacityIfCached != 0) {
- // we cannot propagate 15 through this
- break;
- }
- // most of the time it falls here.
- // add to propagate
- // light set delayed until we determine if this nibble section is null
- this.appendToIncreaseQueue(
- ((worldX + (worldZ << 6) + (startY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | (15L << (6 + 6 + 16)) // we know we're at full lit here
- | (propagateDirection << (6 + 6 + 16 + 4))
- );
- } else {
- mutablePos.set(worldX, startY, worldZ);
- long flags = 0L;
- if (((StarlightAbstractBlockState)current).starlight$isConditionallyFullOpaque()) {
- final VoxelShape cullingFace = current.getFaceOcclusionShape(world, mutablePos, AxisDirection.POSITIVE_Y.nms);
+ long flags = 0L;
+ if (((StarlightAbstractBlockState)current).starlight$isConditionallyFullOpaque()) {
+ final VoxelShape cullingFace = current.getFaceOcclusionShape(AxisDirection.POSITIVE_Y.nms);
- if (Shapes.faceShapeOccludes(fromShape, cullingFace)) {
- // can't propagate here, we're done on this column.
- break;
- }
- flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
- }
-
- final int opacity = current.getLightBlock(world, mutablePos);
- if (opacity > 0) {
- // let the queued value (if any) handle it from here.
+ if (Shapes.faceShapeOccludes(fromShape, cullingFace)) {
+ // can't propagate here, we're done on this column.
break;
}
+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
+ }
- // light set delayed until we determine if this nibble section is null
- this.appendToIncreaseQueue(
- ((worldX + (worldZ << 6) + (startY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | (15L << (6 + 6 + 16)) // we know we're at full lit here
- | (propagateDirection << (6 + 6 + 16 + 4))
- | flags
- );
+ final int opacity = current.getLightBlock();
+ if (opacity > 0) {
+ // let the queued value (if any) handle it from here.
+ break;
}
+ // light set delayed until we determine if this nibble section is null
+ this.appendToIncreaseQueue(
+ ((worldX + (worldZ << 6) + (startY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | (15L << (6 + 6 + 16)) // we know we're at full lit here
+ | (propagateDirection << (6 + 6 + 16 + 4))
+ | flags
+ );
+
above = current;
if (this.getNibbleFromCache(worldX >> 4, startY >> 4, worldZ >> 4) == null) {
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightEngine.java b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightEngine.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightEngine.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightEngine.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.starlight.light;
import ca.spottedleaf.concurrentutil.util.IntegerUtil;
+import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.starlight.blockstate.StarlightAbstractBlockState;
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
protected static enum AxisDirection {
// Declaration order is important and relied upon. Do not change without modifying propagation code.
- POSITIVE_X(1, 0, 0), NEGATIVE_X(-1, 0, 0),
- POSITIVE_Z(0, 0, 1), NEGATIVE_Z(0, 0, -1),
- POSITIVE_Y(0, 1, 0), NEGATIVE_Y(0, -1, 0);
+ POSITIVE_X(1, 0, 0, Direction.EAST) , NEGATIVE_X(-1, 0, 0, Direction.WEST),
+ POSITIVE_Z(0, 0, 1, Direction.SOUTH), NEGATIVE_Z(0, 0, -1, Direction.NORTH),
+ POSITIVE_Y(0, 1, 0, Direction.UP) , NEGATIVE_Y(0, -1, 0, Direction.DOWN);
static {
POSITIVE_X.opposite = NEGATIVE_X; NEGATIVE_X.opposite = POSITIVE_X;
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
public final long everythingButThisDirection;
public final long everythingButTheOppositeDirection;
- AxisDirection(final int x, final int y, final int z) {
+ AxisDirection(final int x, final int y, final int z, final Direction nms) {
this.x = x;
this.y = y;
this.z = z;
- this.nms = Direction.fromDelta(x, y, z);
+ this.nms = nms;
this.everythingButThisDirection = (long)(ALL_DIRECTIONS_BITSET ^ (1 << this.ordinal()));
// positive is always even, negative is always odd. Flip the 1 bit to get the negative direction.
this.everythingButTheOppositeDirection = (long)(ALL_DIRECTIONS_BITSET ^ (1 << (this.ordinal() ^ 1)));
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
// index = x + (z * 5)
protected final boolean[][] emptinessMapCache = new boolean[5 * 5][];
- protected final BlockPos.MutableBlockPos mutablePos1 = new BlockPos.MutableBlockPos();
- protected final BlockPos.MutableBlockPos mutablePos2 = new BlockPos.MutableBlockPos();
- protected final BlockPos.MutableBlockPos mutablePos3 = new BlockPos.MutableBlockPos();
+ protected final BlockPos.MutableBlockPos lightEmissionPos = new BlockPos.MutableBlockPos();
protected int encodeOffsetX;
protected int encodeOffsetY;
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
if (blockState == null) {
continue;
}
- final int opacityCached = ((StarlightAbstractBlockState)blockState).starlight$getOpacityIfCached();
- if (opacityCached != -1) {
- final int targetLevel = propagatedLightLevel - Math.max(1, opacityCached);
- if (targetLevel > currentLevel) {
- currentNibble.set(localIndex, targetLevel);
- this.postLightUpdate(offX, offY, offZ);
-
- if (targetLevel > 1) {
- if (queueLength >= queue.length) {
- queue = this.resizeIncreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4));
- continue;
- }
- }
- continue;
- } else {
- this.mutablePos1.set(offX, offY, offZ);
- long flags = 0;
- if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
- final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms);
+ long flags = 0;
+ if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(propagate.getOpposite().nms);
- if (Shapes.faceShapeOccludes(Shapes.empty(), cullingFace)) {
- continue;
- }
- flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
- }
-
- final int opacity = blockState.getLightBlock(world, this.mutablePos1);
- final int targetLevel = propagatedLightLevel - Math.max(1, opacity);
- if (targetLevel <= currentLevel) {
+ if (Shapes.faceShapeOccludes(Shapes.empty(), cullingFace)) {
continue;
}
+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
+ }
- currentNibble.set(localIndex, targetLevel);
- this.postLightUpdate(offX, offY, offZ);
+ final int opacity = blockState.getLightBlock();
+ final int targetLevel = propagatedLightLevel - Math.max(1, opacity);
+ if (targetLevel <= currentLevel) {
+ continue;
+ }
- if (targetLevel > 1) {
- if (queueLength >= queue.length) {
- queue = this.resizeIncreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4))
- | (flags);
+ currentNibble.set(localIndex, targetLevel);
+ this.postLightUpdate(offX, offY, offZ);
+
+ if (targetLevel > 1) {
+ if (queueLength >= queue.length) {
+ queue = this.resizeIncreaseQueue();
}
- continue;
+ queue[queueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((targetLevel & 0xFL) << (6 + 6 + 16))
+ | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4))
+ | (flags);
}
+ continue;
}
} else {
// we actually need to worry about our state here
final BlockState fromBlock = this.getBlockState(posX, posY, posZ);
- this.mutablePos2.set(posX, posY, posZ);
for (final AxisDirection propagate : checkDirections) {
final int offX = posX + propagate.x;
final int offY = posY + propagate.y;
final int offZ = posZ + propagate.z;
- final VoxelShape fromShape = (((StarlightAbstractBlockState)fromBlock).starlight$isConditionallyFullOpaque()) ? fromBlock.getFaceOcclusionShape(world, this.mutablePos2, propagate.nms) : Shapes.empty();
+ final VoxelShape fromShape = (((StarlightAbstractBlockState)fromBlock).starlight$isConditionallyFullOpaque()) ? fromBlock.getFaceOcclusionShape(propagate.nms) : Shapes.empty();
if (fromShape != Shapes.empty() && Shapes.faceShapeOccludes(Shapes.empty(), fromShape)) {
continue;
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
if (blockState == null) {
continue;
}
- final int opacityCached = ((StarlightAbstractBlockState)blockState).starlight$getOpacityIfCached();
- if (opacityCached != -1) {
- final int targetLevel = propagatedLightLevel - Math.max(1, opacityCached);
- if (targetLevel > currentLevel) {
- currentNibble.set(localIndex, targetLevel);
- this.postLightUpdate(offX, offY, offZ);
-
- if (targetLevel > 1) {
- if (queueLength >= queue.length) {
- queue = this.resizeIncreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4));
- continue;
- }
- }
- continue;
- } else {
- this.mutablePos1.set(offX, offY, offZ);
- long flags = 0;
- if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
- final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms);
-
- if (Shapes.faceShapeOccludes(fromShape, cullingFace)) {
- continue;
- }
- flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
- }
+ long flags = 0;
+ if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(propagate.getOpposite().nms);
- final int opacity = blockState.getLightBlock(world, this.mutablePos1);
- final int targetLevel = propagatedLightLevel - Math.max(1, opacity);
- if (targetLevel <= currentLevel) {
+ if (Shapes.faceShapeOccludes(fromShape, cullingFace)) {
continue;
}
+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
+ }
- currentNibble.set(localIndex, targetLevel);
- this.postLightUpdate(offX, offY, offZ);
+ final int opacity = blockState.getLightBlock();
+ final int targetLevel = propagatedLightLevel - Math.max(1, opacity);
+ if (targetLevel <= currentLevel) {
+ continue;
+ }
- if (targetLevel > 1) {
- if (queueLength >= queue.length) {
- queue = this.resizeIncreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4))
- | (flags);
+ currentNibble.set(localIndex, targetLevel);
+ this.postLightUpdate(offX, offY, offZ);
+
+ if (targetLevel > 1) {
+ if (queueLength >= queue.length) {
+ queue = this.resizeIncreaseQueue();
}
- continue;
+ queue[queueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((targetLevel & 0xFL) << (6 + 6 + 16))
+ | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4))
+ | (flags);
}
+ continue;
}
}
}
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
final int sectionOffset = this.chunkSectionIndexOffset;
final int emittedMask = this.emittedLightMask;
+ final PlatformHooks platformHooks = PlatformHooks.get();
+
while (queueReadIndex < queueLength) {
final long queueValue = queue[queueReadIndex++];
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
if (blockState == null) {
continue;
}
- final int opacityCached = ((StarlightAbstractBlockState)blockState).starlight$getOpacityIfCached();
- if (opacityCached != -1) {
- final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacityCached));
- if (lightLevel > targetLevel) {
- // it looks like another source propagated here, so re-propagate it
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((lightLevel & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | FLAG_RECHECK_LEVEL;
- continue;
- }
- final int emittedLight = blockState.getLightEmission() & emittedMask;
- if (emittedLight != 0) {
- // re-propagate source
- // note: do not set recheck level, or else the propagation will fail
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((emittedLight & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque() ? (FLAG_WRITE_LEVEL | FLAG_HAS_SIDED_TRANSPARENT_BLOCKS) : FLAG_WRITE_LEVEL);
- }
-
- currentNibble.set(localIndex, 0);
- this.postLightUpdate(offX, offY, offZ);
+ this.lightEmissionPos.set(offX, offY, offZ);
+ long flags = 0;
+ if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(propagate.getOpposite().nms);
- if (targetLevel > 0) { // we actually need to propagate 0 just in case we find a neighbour...
- if (queueLength >= queue.length) {
- queue = this.resizeDecreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4));
+ if (Shapes.faceShapeOccludes(Shapes.empty(), cullingFace)) {
continue;
}
- continue;
- } else {
- this.mutablePos1.set(offX, offY, offZ);
- long flags = 0;
- if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
- final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms);
-
- if (Shapes.faceShapeOccludes(Shapes.empty(), cullingFace)) {
- continue;
- }
- flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
- }
+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
+ }
- final int opacity = blockState.getLightBlock(world, this.mutablePos1);
- final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacity));
- if (lightLevel > targetLevel) {
- // it looks like another source propagated here, so re-propagate it
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((lightLevel & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | (FLAG_RECHECK_LEVEL | flags);
- continue;
+ final int opacity = blockState.getLightBlock();
+ final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacity));
+ if (lightLevel > targetLevel) {
+ // it looks like another source propagated here, so re-propagate it
+ if (increaseQueueLength >= increaseQueue.length) {
+ increaseQueue = this.resizeIncreaseQueue();
}
- final int emittedLight = blockState.getLightEmission() & emittedMask;
- if (emittedLight != 0) {
- // re-propagate source
- // note: do not set recheck level, or else the propagation will fail
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((emittedLight & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | (flags | FLAG_WRITE_LEVEL);
+ increaseQueue[increaseQueueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((lightLevel & 0xFL) << (6 + 6 + 16))
+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
+ | (FLAG_RECHECK_LEVEL | flags);
+ continue;
+ }
+ final int emittedLight = (platformHooks.getLightEmission(blockState, world, this.lightEmissionPos)) & emittedMask;
+ if (emittedLight != 0) {
+ // re-propagate source
+ // note: do not set recheck level, or else the propagation will fail
+ if (increaseQueueLength >= increaseQueue.length) {
+ increaseQueue = this.resizeIncreaseQueue();
}
+ increaseQueue[increaseQueueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((emittedLight & 0xFL) << (6 + 6 + 16))
+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
+ | (flags | FLAG_WRITE_LEVEL);
+ }
- currentNibble.set(localIndex, 0);
- this.postLightUpdate(offX, offY, offZ);
+ currentNibble.set(localIndex, 0);
+ this.postLightUpdate(offX, offY, offZ);
- if (targetLevel > 0) {
- if (queueLength >= queue.length) {
- queue = this.resizeDecreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4))
- | flags;
+ if (targetLevel > 0) {
+ if (queueLength >= queue.length) {
+ queue = this.resizeDecreaseQueue();
}
- continue;
+ queue[queueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((targetLevel & 0xFL) << (6 + 6 + 16))
+ | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4))
+ | flags;
}
+ continue;
}
} else {
// we actually need to worry about our state here
final BlockState fromBlock = this.getBlockState(posX, posY, posZ);
- this.mutablePos2.set(posX, posY, posZ);
for (final AxisDirection propagate : checkDirections) {
final int offX = posX + propagate.x;
final int offY = posY + propagate.y;
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset;
final int localIndex = (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8);
- final VoxelShape fromShape = (((StarlightAbstractBlockState)fromBlock).starlight$isConditionallyFullOpaque()) ? fromBlock.getFaceOcclusionShape(world, this.mutablePos2, propagate.nms) : Shapes.empty();
+ final VoxelShape fromShape = (((StarlightAbstractBlockState)fromBlock).starlight$isConditionallyFullOpaque()) ? fromBlock.getFaceOcclusionShape(propagate.nms) : Shapes.empty();
if (fromShape != Shapes.empty() && Shapes.faceShapeOccludes(Shapes.empty(), fromShape)) {
continue;
@@ -0,0 +0,0 @@ public abstract class StarLightEngine {
if (blockState == null) {
continue;
}
- final int opacityCached = ((StarlightAbstractBlockState)blockState).starlight$getOpacityIfCached();
- if (opacityCached != -1) {
- final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacityCached));
- if (lightLevel > targetLevel) {
- // it looks like another source propagated here, so re-propagate it
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((lightLevel & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | FLAG_RECHECK_LEVEL;
- continue;
- }
- final int emittedLight = blockState.getLightEmission() & emittedMask;
- if (emittedLight != 0) {
- // re-propagate source
- // note: do not set recheck level, or else the propagation will fail
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((emittedLight & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque() ? (FLAG_WRITE_LEVEL | FLAG_HAS_SIDED_TRANSPARENT_BLOCKS) : FLAG_WRITE_LEVEL);
- }
-
- currentNibble.set(localIndex, 0);
- this.postLightUpdate(offX, offY, offZ);
+ this.lightEmissionPos.set(offX, offY, offZ);
+ long flags = 0;
+ if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(propagate.getOpposite().nms);
- if (targetLevel > 0) { // we actually need to propagate 0 just in case we find a neighbour...
- if (queueLength >= queue.length) {
- queue = this.resizeDecreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4));
+ if (Shapes.faceShapeOccludes(fromShape, cullingFace)) {
continue;
}
- continue;
- } else {
- this.mutablePos1.set(offX, offY, offZ);
- long flags = 0;
- if (((StarlightAbstractBlockState)blockState).starlight$isConditionallyFullOpaque()) {
- final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms);
-
- if (Shapes.faceShapeOccludes(fromShape, cullingFace)) {
- continue;
- }
- flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
- }
+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS;
+ }
- final int opacity = blockState.getLightBlock(world, this.mutablePos1);
- final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacity));
- if (lightLevel > targetLevel) {
- // it looks like another source propagated here, so re-propagate it
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((lightLevel & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | (FLAG_RECHECK_LEVEL | flags);
- continue;
+ final int opacity = blockState.getLightBlock();
+ final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacity));
+ if (lightLevel > targetLevel) {
+ // it looks like another source propagated here, so re-propagate it
+ if (increaseQueueLength >= increaseQueue.length) {
+ increaseQueue = this.resizeIncreaseQueue();
}
- final int emittedLight = blockState.getLightEmission() & emittedMask;
- if (emittedLight != 0) {
- // re-propagate source
- // note: do not set recheck level, or else the propagation will fail
- if (increaseQueueLength >= increaseQueue.length) {
- increaseQueue = this.resizeIncreaseQueue();
- }
- increaseQueue[increaseQueueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((emittedLight & 0xFL) << (6 + 6 + 16))
- | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
- | (flags | FLAG_WRITE_LEVEL);
+ increaseQueue[increaseQueueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((lightLevel & 0xFL) << (6 + 6 + 16))
+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
+ | (FLAG_RECHECK_LEVEL | flags);
+ continue;
+ }
+ final int emittedLight = (platformHooks.getLightEmission(blockState, world, this.lightEmissionPos)) & emittedMask;
+ if (emittedLight != 0) {
+ // re-propagate source
+ // note: do not set recheck level, or else the propagation will fail
+ if (increaseQueueLength >= increaseQueue.length) {
+ increaseQueue = this.resizeIncreaseQueue();
}
+ increaseQueue[increaseQueueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((emittedLight & 0xFL) << (6 + 6 + 16))
+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4))
+ | (flags | FLAG_WRITE_LEVEL);
+ }
- currentNibble.set(localIndex, 0);
- this.postLightUpdate(offX, offY, offZ);
+ currentNibble.set(localIndex, 0);
+ this.postLightUpdate(offX, offY, offZ);
- if (targetLevel > 0) { // we actually need to propagate 0 just in case we find a neighbour...
- if (queueLength >= queue.length) {
- queue = this.resizeDecreaseQueue();
- }
- queue[queueLength++] =
- ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
- | ((targetLevel & 0xFL) << (6 + 6 + 16))
- | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4))
- | flags;
+ if (targetLevel > 0) { // we actually need to propagate 0 just in case we find a neighbour...
+ if (queueLength >= queue.length) {
+ queue = this.resizeDecreaseQueue();
}
- continue;
+ queue[queueLength++] =
+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1))
+ | ((targetLevel & 0xFL) << (6 + 6 + 16))
+ | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4))
+ | flags;
}
+ continue;
}
}
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
@@ -0,0 +0,0 @@
package ca.spottedleaf.moonrise.patches.starlight.light;
import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
+import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
@@ -0,0 +0,0 @@ public final class StarLightInterface {
super(lightInterface);
}
- public void lowerPriority(final int chunkX, final int chunkZ, final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final int chunkX, final int chunkZ, final Priority priority) {
final ServerChunkTasks task = this.chunkTasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
if (task != null) {
task.lowerPriority(priority);
}
}
- public void setPriority(final int chunkX, final int chunkZ, final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final int chunkX, final int chunkZ, final Priority priority) {
final ServerChunkTasks task = this.chunkTasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
if (task != null) {
task.setPriority(priority);
}
}
- public void raisePriority(final int chunkX, final int chunkZ, final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final int chunkX, final int chunkZ, final Priority priority) {
final ServerChunkTasks task = this.chunkTasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
if (task != null) {
task.raisePriority(priority);
}
}
- public PrioritisedExecutor.Priority getPriority(final int chunkX, final int chunkZ) {
+ public Priority getPriority(final int chunkX, final int chunkZ) {
final ServerChunkTasks task = this.chunkTasks.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
if (task != null) {
return task.getPriority();
}
- return PrioritisedExecutor.Priority.COMPLETING;
+ return Priority.COMPLETING;
}
@Override
@@ -0,0 +0,0 @@ public final class StarLightInterface {
return ret;
}
- public ServerChunkTasks queueChunkLightTask(final ChunkPos pos, final BooleanSupplier lightTask, final PrioritisedExecutor.Priority priority) {
+ public ServerChunkTasks queueChunkLightTask(final ChunkPos pos, final BooleanSupplier lightTask, final Priority priority) {
final ServerChunkTasks ret = this.chunkTasks.compute(CoordinateUtils.getChunkKey(pos), (final long keyInMap, ServerChunkTasks valueInMap) -> {
if (valueInMap == null) {
valueInMap = new ServerChunkTasks(
@@ -0,0 +0,0 @@ public final class StarLightInterface {
public ServerChunkTasks(final long chunkCoordinate, final StarLightInterface lightEngine,
final ServerLightQueue queue) {
- this(chunkCoordinate, lightEngine, queue, PrioritisedExecutor.Priority.NORMAL);
+ this(chunkCoordinate, lightEngine, queue, Priority.NORMAL);
}
public ServerChunkTasks(final long chunkCoordinate, final StarLightInterface lightEngine,
- final ServerLightQueue queue, final PrioritisedExecutor.Priority priority) {
+ final ServerLightQueue queue, final Priority priority) {
super(chunkCoordinate, lightEngine, queue);
this.task = ((ChunkSystemServerLevel)(ServerLevel)lightEngine.getWorld()).moonrise$getChunkTaskScheduler().radiusAwareScheduler.createTask(
CoordinateUtils.getChunkX(chunkCoordinate), CoordinateUtils.getChunkZ(chunkCoordinate),
@@ -0,0 +0,0 @@ public final class StarLightInterface {
return this.task.cancel();
}
- public PrioritisedExecutor.Priority getPriority() {
+ public Priority getPriority() {
return this.task.getPriority();
}
- public void lowerPriority(final PrioritisedExecutor.Priority priority) {
+ public void lowerPriority(final Priority priority) {
this.task.lowerPriority(priority);
}
- public void setPriority(final PrioritisedExecutor.Priority priority) {
+ public void setPriority(final Priority priority) {
this.task.setPriority(priority);
}
- public void raisePriority(final PrioritisedExecutor.Priority priority) {
+ public void raisePriority(final Priority priority) {
this.task.raisePriority(priority);
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/storage/StarlightSectionData.java b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/storage/StarlightSectionData.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/storage/StarlightSectionData.java
@@ -0,0 +0,0 @@
+package ca.spottedleaf.moonrise.patches.starlight.storage;
+
+public interface StarlightSectionData {
+
+ public int starlight$getBlockLightState();
+
+ public void starlight$setBlockLightState(final int state);
+
+ public int starlight$getSkyLightState();
+
+ public void starlight$setSkyLightState(final int state);
+
+}
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/util/SaveUtil.java b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/util/SaveUtil.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/starlight/util/SaveUtil.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/starlight/util/SaveUtil.java
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.slf4j.Logger;
+// note: keep in-sync with SerializableChunkDataMixin
public final class SaveUtil {
private static final Logger LOGGER = LogUtils.getLogger();
- private static final int STARLIGHT_LIGHT_VERSION = 9;
+ public static final int STARLIGHT_LIGHT_VERSION = 9;
public static int getLightVersion() {
return STARLIGHT_LIGHT_VERSION;
}
- private static final String BLOCKLIGHT_STATE_TAG = "starlight.blocklight_state";
- private static final String SKYLIGHT_STATE_TAG = "starlight.skylight_state";
- private static final String STARLIGHT_VERSION_TAG = "starlight.light_version";
+ public static final String BLOCKLIGHT_STATE_TAG = "starlight.blocklight_state";
+ public static final String SKYLIGHT_STATE_TAG = "starlight.skylight_state";
+ public static final String STARLIGHT_VERSION_TAG = "starlight.light_version";
public static void saveLightHook(final Level world, final ChunkAccess chunk, final CompoundTag nbt) {
try {
diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
@@ -0,0 +0,0 @@ public class GlobalConfiguration extends ConfigurationPart {
@PostProcess
private void postProcess() {
+ ca.spottedleaf.moonrise.common.util.MoonriseCommon.adjustWorkerThreads(this.workerThreads, this.ioThreads);
ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.init(this);
}
}
diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/core/MappedRegistry.java
+++ b/src/main/java/net/minecraft/core/MappedRegistry.java
@@ -0,0 +0,0 @@ public class MappedRegistry implements WritableRegistry {
return this.getTags();
}
+ // Paper start - fluid method optimisations
+ private void injectFluidRegister(
+ final ResourceKey> resourceKey,
+ final T object
+ ) {
+ if (resourceKey.registryKey() == (Object)net.minecraft.core.registries.Registries.FLUID) {
+ for (final net.minecraft.world.level.material.FluidState possibleState : ((net.minecraft.world.level.material.Fluid)object).getStateDefinition().getPossibleStates()) {
+ ((ca.spottedleaf.moonrise.patches.fluid.FluidFluidState)(Object)possibleState).moonrise$initCaches();
+ }
+ }
+ }
+ // Paper end - fluid method optimisations
+
public MappedRegistry(ResourceKey extends Registry> key, Lifecycle lifecycle) {
this(key, lifecycle, false);
}
@@ -0,0 +0,0 @@ public class MappedRegistry implements WritableRegistry {
this.toId.put(value, i);
this.registrationInfos.put(key, info);
this.registryLifecycle = this.registryLifecycle.add(info.lifecycle());
+ this.injectFluidRegister(key, value); // Paper - fluid method optimisations
return reference;
}
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop trackerEntities = entityLookup.trackerEntities;
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
if (tracker == null) {
continue;
}
- ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity)tracker).moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition()));
- tracker.serverEntity.sendChanges();
- }
-
- // process unloads
- final ca.spottedleaf.moonrise.common.list.ReferenceList unloadedEntities = entityLookup.trackerUnloadedEntities;
- final Entity[] unloadedEntitiesRaw = java.util.Arrays.copyOf(unloadedEntities.getRawDataUnchecked(), unloadedEntities.size());
- unloadedEntities.clear();
-
- for (final Entity entity : unloadedEntitiesRaw) {
- 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();
}
- ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity)tracker).moonrise$clearPlayers();
}
}
// Paper end - optimise entity tracker
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.removePlayer(player);
}
}
+
+ @Override
+ public final boolean moonrise$hasPlayers() {
+ return !this.seenBy.isEmpty();
+ }
// Paper end - optimise entity tracker
public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) {
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
private int getEffectiveRange() {
- int i = this.range;
- Iterator iterator = this.entity.getIndirectPassengers().iterator();
+ // Paper start - optimise entity tracker
+ final Entity entity = this.entity;
+ int range = ca.spottedleaf.moonrise.common.PlatformHooks.get().modifyEntityTrackingRange(entity, this.range);
- while (iterator.hasNext()) {
- Entity entity = (Entity) iterator.next();
- int j = entity.getType().clientTrackingRange() * 16;
- j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper
+ if (entity.getPassengers() == ImmutableList.of()) {
+ return this.scaledRange(range);
+ }
- if (j > i) {
- i = j;
- }
+ // note: we change to List
+ final List passengers = (List)entity.getIndirectPassengers();
+ for (int i = 0, len = passengers.size(); i < len; ++i) {
+ final Entity passenger = passengers.get(i);
+ // note: max should be branchless
+ range = Math.max(range, ca.spottedleaf.moonrise.common.PlatformHooks.get().modifyEntityTrackingRange(passenger, passenger.getType().clientTrackingRange() << 4));
}
- return this.scaledRange(i);
+ return this.scaledRange(range);
+ // Paper end - optimise entity tracker
}
public void updatePlayers(List players) {
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler chunkTaskScheduler = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler();
final CompletableFuture completable = new CompletableFuture<>();
chunkTaskScheduler.scheduleChunkLoad(
- chunkX, chunkZ, toStatus, true, ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.BLOCKING,
+ chunkX, chunkZ, toStatus, true, ca.spottedleaf.concurrentutil.util.Priority.BLOCKING,
completable::complete
);
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
return ifPresent;
}
+ final ca.spottedleaf.moonrise.common.PlatformHooks platformHooks = ca.spottedleaf.moonrise.common.PlatformHooks.get();
+
+ if (platformHooks.hasCurrentlyLoadingChunk() && currentChunk != null) {
+ final ChunkAccess loading = platformHooks.getCurrentlyLoadingChunk(currentChunk.vanillaChunkHolder);
+ if (loading != null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) {
+ return loading;
+ }
+ }
+
return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null;
}
// Paper end - rewrite chunk system
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@Nullable
@Override
public LevelChunk getChunkNow(int chunkX, int chunkZ) {
- return this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); // Paper - rewrite chunk system
+ // Paper start - rewrite chunk system
+ final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
+ if (!ca.spottedleaf.moonrise.common.PlatformHooks.get().hasCurrentlyLoadingChunk()) {
+ return ret;
+ }
+
+ if (ret != null || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) {
+ return ret;
+ }
+
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler()
+ .chunkHolderManager.getChunkHolder(chunkX, chunkZ);
+ if (holder == null) {
+ return ret;
+ }
+
+ return ca.spottedleaf.moonrise.common.PlatformHooks.get().getCurrentlyLoadingChunk(holder.vanillaChunkHolder);
+ // Paper end - rewrite chunk system
}
private void clearCache() {
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(
chunkX, chunkZ, leastStatus, true,
- ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER,
+ ca.spottedleaf.concurrentutil.util.Priority.HIGHER,
complete
);
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
private void getFullChunk(long pos, Consumer chunkConsumer) {
// Paper start - rewrite chunk system
- final LevelChunk fullChunk = this.getChunkNow(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(pos), ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(pos));
+ // note: bypass currentlyLoaded from getChunkNow
+ final LevelChunk fullChunk = this.fullChunks.get(pos);
if (fullChunk != null) {
chunkConsumer.accept(fullChunk);
}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
// Paper start - optimise random ticking
+ private final ca.spottedleaf.moonrise.common.util.SimpleRandom simpleRandom = new ca.spottedleaf.moonrise.common.util.SimpleRandom(0L);
+
private void optimiseRandomTick(final LevelChunk chunk, final int tickSpeed) {
final LevelChunkSection[] sections = chunk.getSections();
final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection((ServerLevel)(Object)this);
- final RandomSource random = this.random;
- final boolean tickFluids = false; // Paper - not configurable - MC-224294
+ final ca.spottedleaf.moonrise.common.util.SimpleRandom simpleRandom = this.simpleRandom;
+ final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
final ChunkPos cpos = chunk.getPos();
final int offsetX = cpos.x << 4;
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
final int offsetY = (sectionIndex + minSection) << 4;
final LevelChunkSection section = sections[sectionIndex];
final net.minecraft.world.level.chunk.PalettedContainer states = section.states;
- if (section == null || !section.isRandomlyTickingBlocks()) {
+ if (!section.isRandomlyTickingBlocks()) {
continue;
}
- final ca.spottedleaf.moonrise.common.list.IBlockDataList tickList = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getTickingBlockList();
- if (tickList.size() == 0) {
- continue;
- }
+ final ca.spottedleaf.moonrise.common.list.ShortList tickList = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getTickingBlockList();
for (int i = 0; i < tickSpeed; ++i) {
final int tickingBlocks = tickList.size();
- final int index = random.nextInt() & ((16 * 16 * 16) - 1);
+ final int index = simpleRandom.nextInt() & ((16 * 16 * 16) - 1);
if (index >= tickingBlocks) {
// most of the time we fall here
continue;
}
- final long raw = tickList.getRaw(index);
- final int location = ca.spottedleaf.moonrise.common.list.IBlockDataList.getLocationFromRaw(raw);
- final int randomX = (location & 15);
- final int randomY = ((location >>> (4 + 4)) & 255);
- final int randomZ = ((location >>> 4) & 15);
- final BlockState state = states.get(randomX | (randomZ << 4) | (randomY << 8));
+ final int location = (int)tickList.getRaw(index) & 0xFFFF;
+ final BlockState state = states.get(location);
// do not use a mutable pos, as some random tick implementations store the input without calling immutable()!
- final BlockPos pos = new BlockPos(randomX | offsetX, randomY | offsetY, randomZ | offsetZ);
+ final BlockPos pos = new BlockPos((location & 15) | offsetX, ((location >>> (4 + 4)) & 15) | offsetY, ((location >>> 4) & 15) | offsetZ);
- state.randomTick((ServerLevel)(Object)this, pos, random);
- if (tickFluids) {
+ state.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
+ if (doubleTickFluids) {
final FluidState fluidState = state.getFluidState();
if (fluidState.isRandomlyTicking()) {
- fluidState.randomTick((ServerLevel)(Object)this, pos, random);
+ fluidState.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
}
}
}
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - optimise random ticking
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
+ final ca.spottedleaf.moonrise.common.util.SimpleRandom simpleRandom = this.simpleRandom; // Paper - optimise random ticking
ChunkPos chunkcoordintpair = chunk.getPos();
boolean flag = this.isRaining();
int j = chunkcoordintpair.getMinBlockX();
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("thunder");
- if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder
+ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && simpleRandom.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder // Paper - optimise random ticking
BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
if (this.isRainingAt(blockposition)) {
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow
for (int l = 0; l < randomTickSpeed; ++l) {
- if (this.random.nextInt(48) == 0) {
+ if (simpleRandom.nextInt(48) == 0) { // Paper - optimise random ticking
this.tickPrecipitation(this.getBlockRandomPos(j, 0, k, 15));
}
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -0,0 +0,0 @@ public abstract class PlayerList {
public void setViewDistance(int viewDistance) {
this.viewDistance = viewDistance;
- this.broadcastAll(new ClientboundSetChunkCacheRadiusPacket(viewDistance));
+ //this.broadcastAll(new ClientboundSetChunkCacheRadiusPacket(viewDistance)); // Paper - rewrite chunk system
Iterator iterator = this.server.getAllLevels().iterator();
while (iterator.hasNext()) {
diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/BitStorage.java
+++ b/src/main/java/net/minecraft/util/BitStorage.java
@@ -0,0 +0,0 @@ public interface BitStorage extends ca.spottedleaf.moonrise.patches.block_counti
// Paper start - block counting
// provide default impl in case mods implement this...
@Override
- public default it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() {
- final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>();
+ public default it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() {
+ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>();
final int size = this.getSize();
for (int index = 0; index < size; ++index) {
final int paletteIdx = this.get(index);
ret.computeIfAbsent(paletteIdx, (final int key) -> {
- return new it.unimi.dsi.fastutil.ints.IntArrayList();
- }).add(index);
+ return new it.unimi.dsi.fastutil.shorts.ShortArrayList();
+ }).add((short)index);
}
return ret;
diff --git a/src/main/java/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java b/src/main/java/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
+++ b/src/main/java/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
@@ -0,0 +0,0 @@ import java.util.Iterator;
import javax.annotation.Nullable;
import net.minecraft.core.IdMap;
-public class CrudeIncrementalIntIdentityHashBiMap implements IdMap {
+public class CrudeIncrementalIntIdentityHashBiMap implements IdMap, ca.spottedleaf.moonrise.patches.fast_palette.FastPalette { // Paper - optimise palette reads
private static final int NOT_FOUND = -1;
private static final Object EMPTY_SLOT = null;
private static final float LOADFACTOR = 0.8F;
@@ -0,0 +0,0 @@ public class CrudeIncrementalIntIdentityHashBiMap implements IdMap {
private int nextId;
private int size;
+ // Paper start - optimise palette reads
+ private ca.spottedleaf.moonrise.patches.fast_palette.FastPaletteData reference;
+
+ @Override
+ public final K[] moonrise$getRawPalette(final ca.spottedleaf.moonrise.patches.fast_palette.FastPaletteData src) {
+ this.reference = src;
+ return this.byId;
+ }
+ // Paper end - optimise palette reads
+
private CrudeIncrementalIntIdentityHashBiMap(int size) {
this.keys = (K[])(new Object[size]);
this.values = new int[size];
@@ -0,0 +0,0 @@ public class CrudeIncrementalIntIdentityHashBiMap implements IdMap {
this.byId = crudeIncrementalIntIdentityHashBiMap.byId;
this.nextId = crudeIncrementalIntIdentityHashBiMap.nextId;
this.size = crudeIncrementalIntIdentityHashBiMap.size;
+ // Paper start - optimise palette reads
+ final ca.spottedleaf.moonrise.patches.fast_palette.FastPaletteData ref = this.reference;
+ if (ref != null) {
+ ref.moonrise$setPalette(this.byId);
+ }
+ // Paper end - optimise palette reads
}
public void addMapping(K value, int id) {
diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/SimpleBitStorage.java
+++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java
@@ -0,0 +0,0 @@ public class SimpleBitStorage implements BitStorage {
private final int divideAdd; private final long divideAddUnsigned; // Paper - Perf: Optimize SimpleBitStorage
private final int divideShift;
+ // Paper start - optimise bitstorage read/write operations
+ private static final int[] BETTER_MAGIC = new int[33];
+ static {
+ // 20 bits of precision
+ // since index is always [0, 4095] (i.e 12 bits), multiplication by a magic value here (20 bits)
+ // fits exactly in an int and allows us to use integer arithmetic
+ for (int bits = 1; bits < BETTER_MAGIC.length; ++bits) {
+ BETTER_MAGIC[bits] = (int)ca.spottedleaf.concurrentutil.util.IntegerUtil.getUnsignedDivisorMagic(64L / bits, 20);
+ }
+ }
+ private final int magic;
+ private final int mulBits;
+ // Paper end - optimise bitstorage read/write operations
+
public SimpleBitStorage(int elementBits, int size, int[] data) {
this(elementBits, size);
int i = 0;
@@ -0,0 +0,0 @@ public class SimpleBitStorage implements BitStorage {
} else {
this.data = new long[j];
}
+ // Paper start - optimise bitstorage read/write operations
+ this.magic = BETTER_MAGIC[this.bits];
+ this.mulBits = (64 / this.bits) * this.bits;
+ if (this.size > 4096) {
+ throw new IllegalStateException("Size > 4096 not supported");
+ }
+ // Paper end - optimise bitstorage read/write operations
}
private int cellIndex(int index) {
@@ -0,0 +0,0 @@ public class SimpleBitStorage implements BitStorage {
public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
//Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
//Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper - Perf: Optimize SimpleBitStorage
- int i = this.cellIndex(index);
- long l = this.data[i];
- int j = (index - i * this.valuesPerLong) * this.bits;
- int k = (int)(l >> j & this.mask);
- this.data[i] = l & ~(this.mask << j) | ((long)value & this.mask) << j;
- return k;
+ // Paper start - optimise bitstorage read/write operations
+ final int full = this.magic * index; // 20 bits of magic + 12 bits of index = barely int
+ final int divQ = full >>> 20;
+ final int divR = (full & 0xFFFFF) * this.mulBits >>> 20;
+
+ final long[] dataArray = this.data;
+
+ final long data = dataArray[divQ];
+ final long mask = this.mask;
+
+ final long write = data & ~(mask << divR) | ((long)value & mask) << divR;
+
+ dataArray[divQ] = write;
+
+ return (int)(data >>> divR & mask);
+ // Paper end - optimise bitstorage read/write operations
}
@Override
public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
//Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
//Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper - Perf: Optimize SimpleBitStorage
- int i = this.cellIndex(index);
- long l = this.data[i];
- int j = (index - i * this.valuesPerLong) * this.bits;
- this.data[i] = l & ~(this.mask << j) | ((long)value & this.mask) << j;
+ // Paper start - optimise bitstorage read/write operations
+ final int full = this.magic * index; // 20 bits of magic + 12 bits of index = barely int
+ final int divQ = full >>> 20;
+ final int divR = (full & 0xFFFFF) * this.mulBits >>> 20;
+
+ final long[] dataArray = this.data;
+
+ final long data = dataArray[divQ];
+ final long mask = this.mask;
+
+ final long write = data & ~(mask << divR) | ((long)value & mask) << divR;
+
+ dataArray[divQ] = write;
+ // Paper end - optimise bitstorage read/write operations
}
@Override
public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage
//Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
- int i = this.cellIndex(index);
- long l = this.data[i];
- int j = (index - i * this.valuesPerLong) * this.bits;
- return (int)(l >> j & this.mask);
+ // Paper start - optimise bitstorage read/write operations
+ final int full = this.magic * index; // 20 bits of magic + 12 bits of index = barely int
+ final int divQ = full >>> 20;
+ final int divR = (full & 0xFFFFF) * this.mulBits >>> 20;
+
+ return (int)(this.data[divQ] >>> divR & this.mask);
+ // Paper end - optimise bitstorage read/write operations
}
@Override
@@ -0,0 +0,0 @@ public class SimpleBitStorage implements BitStorage {
// Paper start - block counting
@Override
- public final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() {
+ public final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() {
final int valuesPerLong = this.valuesPerLong;
final int bits = this.bits;
- final long mask = this.mask;
+ final long mask = (1L << bits) - 1L;
final int size = this.size;
- // we may be backed by global palette, so limit bits for init capacity
- final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(
- 1 << Math.min(6, bits)
- );
-
- int index = 0;
-
- for (long value : this.data) {
- int li = 0;
- do {
- final int paletteIdx = (int)(value & mask);
- value >>= bits;
+ if (bits <= 6) {
+ final it.unimi.dsi.fastutil.shorts.ShortArrayList[] byId = new it.unimi.dsi.fastutil.shorts.ShortArrayList[1 << bits];
+ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(1 << bits);
+
+ int index = 0;
+
+ for (long value : this.data) {
+ int li = 0;
+ do {
+ final int paletteIdx = (int)(value & mask);
+ value >>= bits;
+ ++li;
+
+ final it.unimi.dsi.fastutil.shorts.ShortArrayList coords = byId[paletteIdx];
+ if (coords != null) {
+ coords.add((short)index++);
+ continue;
+ } else {
+ final it.unimi.dsi.fastutil.shorts.ShortArrayList newCoords = new it.unimi.dsi.fastutil.shorts.ShortArrayList(64);
+ byId[paletteIdx] = newCoords;
+ newCoords.add((short)index++);
+ ret.put(paletteIdx, newCoords);
+ continue;
+ }
+ } while (li < valuesPerLong && index < size);
+ }
- ret.computeIfAbsent(paletteIdx, (final int key) -> {
- return new it.unimi.dsi.fastutil.ints.IntArrayList();
- }).add(index);
+ return ret;
+ } else {
+ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(
+ 1 << 6
+ );
+
+ int index = 0;
+
+ for (long value : this.data) {
+ int li = 0;
+ do {
+ final int paletteIdx = (int)(value & mask);
+ value >>= bits;
+ ++li;
+
+ ret.computeIfAbsent(paletteIdx, (final int key) -> {
+ return new it.unimi.dsi.fastutil.shorts.ShortArrayList(64);
+ }).add((short)index++);
+ } while (li < valuesPerLong && index < size);
+ }
- ++li;
- ++index;
- } while (li < valuesPerLong && index < size);
+ return ret;
}
-
- return ret;
}
// Paper end - block counting
diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java
+++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java
@@ -0,0 +0,0 @@ public class ZeroBitStorage implements BitStorage {
// Paper start - block counting
@Override
- public final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() {
+ public final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() {
final int size = this.size;
- final int[] raw = new int[size];
+ final short[] raw = new short[size];
for (int i = 0; i < size; ++i) {
- raw[i] = i;
+ raw[i] = (short)i;
}
- final it.unimi.dsi.fastutil.ints.IntArrayList coordinates = it.unimi.dsi.fastutil.ints.IntArrayList.wrap(raw, size);
+ final it.unimi.dsi.fastutil.shorts.ShortArrayList coordinates = it.unimi.dsi.fastutil.shorts.ShortArrayList.wrap(raw, size);
- final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(1);
+ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(1);
ret.put(0, coordinates);
return ret;
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// Paper start - rewrite chunk system
private final boolean isHardColliding = this.moonrise$isHardCollidingUncached();
private net.minecraft.server.level.FullChunkStatus chunkStatus;
+ private ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData chunkData;
private int sectionX = Integer.MIN_VALUE;
private int sectionY = Integer.MIN_VALUE;
private int sectionZ = Integer.MIN_VALUE;
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.chunkStatus = status;
}
+ @Override
+ public final ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData moonrise$getChunkData() {
+ return this.chunkData;
+ }
+
+ @Override
+ public final void moonrise$setChunkData(final ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData chunkData) {
+ this.chunkData = chunkData;
+ }
+
@Override
public final int moonrise$getSectionX() {
return this.sectionX;
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return this.getIndirectPassengersStream().anyMatch((entity) -> entity instanceof Player);
}
// Paper end - rewrite chunk system
+ // Paper start - optimise collisions
+ private static float[] calculateStepHeights(final AABB box, final List voxels, final List aabbs, final float stepHeight,
+ final float collidedY) {
+ final FloatArraySet ret = new FloatArraySet();
+
+ for (int i = 0, len = voxels.size(); i < len; ++i) {
+ final VoxelShape shape = voxels.get(i);
+
+ final double[] yCoords = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape).moonrise$rootCoordinatesY();
+ final double yOffset = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape).moonrise$offsetY();
+
+ for (final double yUnoffset : yCoords) {
+ final double y = yUnoffset + yOffset;
+
+ final float step = (float)(y - box.minY);
+
+ if (step > stepHeight) {
+ break;
+ }
+
+ if (step < 0.0f || !(step != collidedY)) {
+ continue;
+ }
+
+ ret.add(step);
+ }
+ }
+
+ for (int i = 0, len = aabbs.size(); i < len; ++i) {
+ final AABB shape = aabbs.get(i);
+
+ final float step1 = (float)(shape.minY - box.minY);
+ final float step2 = (float)(shape.maxY - box.minY);
+
+ if (!(step1 < 0.0f) && step1 != collidedY && !(step1 > stepHeight)) {
+ ret.add(step1);
+ }
+
+ if (!(step2 < 0.0f) && step2 != collidedY && !(step2 > stepHeight)) {
+ ret.add(step2);
+ }
+ }
+
+ final float[] steps = ret.toFloatArray();
+ FloatArrays.unstableSort(steps);
+ return steps;
+ }
+ // Paper end - optimise collisions
// Paper start - optimise entity tracker
private net.minecraft.server.level.ChunkMap.TrackedEntity trackedEntity;
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return movement;
}
- final Level world = this.level;
- final AABB currBoundingBox = this.getBoundingBox();
-
- if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(currBoundingBox)) {
- return movement;
- }
+ final AABB currentBox = this.getBoundingBox();
- final List