9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-19 14:59:25 +00:00
Files
DivineMC/divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch
NONPLAYT 972ba4d252 Updated Upstream (Purpur)
Upstream has released updates that appear to apply and compile correctly

Purpur Changes:
PurpurMC/Purpur@47e758fb Updated Upstream (Paper)
2025-06-26 13:43:33 +03:00

3629 lines
201 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 00:09:39 +0300
Subject: [PATCH] Chunk System Optimizations
diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..78e3c49a233dc6bed558458d555fe740a8cc839e 100644
--- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
@@ -59,12 +59,15 @@ public final class NearbyPlayers {
public static final int GENERAL_REALLY_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_REALLY_SMALL_VIEW_DISTANCE << 4);
private final ServerLevel world;
- private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
- private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
- private final Long2ReferenceOpenHashMap<ReferenceList<ServerPlayer>>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES];
+ // DivineMC start - Chunk System optimization
+ private final Object callbackLock = new Object();
+ private final it.unimi.dsi.fastutil.objects.Reference2ReferenceMap<ServerPlayer, TrackedPlayer[]> players = it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps.synchronize(new Reference2ReferenceOpenHashMap<>());
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<TrackedChunk> byChunk = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>());
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<ReferenceList<ServerPlayer>>[] directByChunk = new it.unimi.dsi.fastutil.longs.Long2ReferenceMap[TOTAL_MAP_TYPES];
+ // DivineMC end - Chunk System optimization
{
for (int i = 0; i < this.directByChunk.length; ++i) {
- this.directByChunk[i] = new Long2ReferenceOpenHashMap<>();
+ this.directByChunk[i] = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>()); // DivineMC - Chunk System optimization
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..6bb36686ae7ca9f4bf763baa894086146f967806 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
@@ -405,6 +405,14 @@ public final class ChunkEntitySlices {
private E[] storage;
private int size;
+ private it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap entityToIndex = null; // DivineMC - Chunk System optimization
+
+ // DivineMC start - Chunk System optimization
+ private void setupIndexMap() {
+ this.entityToIndex = new it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap(2, 0.8f);
+ this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE);
+ }
+ // DivineMC end - Chunk System optimization
public BasicEntityList() {
this(0);
@@ -425,6 +433,7 @@ public final class ChunkEntitySlices {
private void resize() {
if (this.storage == EMPTY) {
this.storage = (E[])new Entity[DEFAULT_CAPACITY];
+ this.setupIndexMap(); // DivineMC - Chunk System optimization
} else {
this.storage = Arrays.copyOf(this.storage, this.storage.length * 2);
}
@@ -438,6 +447,7 @@ public final class ChunkEntitySlices {
} else {
this.storage[idx] = entity;
}
+ this.entityToIndex.put(entity.getId(), idx); // DivineMC - Chunk System optimization
}
public int indexOf(final E entity) {
@@ -453,24 +463,31 @@ public final class ChunkEntitySlices {
}
public boolean remove(final E entity) {
- final int idx = this.indexOf(entity);
- if (idx == -1) {
+ // DivineMC start - Chunk System optimization - by Sakura, copied from EntityList
+ if (this.entityToIndex == null) {
return false;
}
- final int size = --this.size;
- final E[] storage = this.storage;
- if (idx != size) {
- System.arraycopy(storage, idx + 1, storage, idx, size - idx);
+ final int index = this.entityToIndex.remove(entity.getId());
+ if (index == Integer.MIN_VALUE) {
+ return false;
}
- storage[size] = null;
+ final int endIndex = --this.size;
+ final E end = this.storage[endIndex];
+ if (index != endIndex) {
+ // not empty after this call
+ this.entityToIndex.put(end.getId(), index); // update index
+ }
+ this.storage[index] = end;
+ this.storage[endIndex] = null;
+ // DivineMC end - Chunk System optimization - by Sakura, copied from EntityList
return true;
}
public boolean has(final E entity) {
- return this.indexOf(entity) != -1;
+ return this.entityToIndex != null && this.entityToIndex.containsKey(entity.getId()); // DivineMC - Chunk System optimization
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index dc2b3ccf7810731c0e2c90e5a476c1c8203a1fb7..5cb896334f9916b030ee523119946d3b40585fc3 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -191,13 +191,13 @@ public final class RegionizedPlayerChunkLoader {
}
if (((ChunkSystemServerPlayer)player).moonrise$getChunkLoader() != null) {
- throw new IllegalStateException("Player is already added to player chunk loader");
+ return; // DivineMC - Chunk System optimization - already loaded
}
final PlayerChunkLoaderData loader = new PlayerChunkLoaderData(this.world, player);
- ((ChunkSystemServerPlayer)player).moonrise$setChunkLoader(loader);
loader.add();
+ player.moonrise$setChunkLoader(loader); // DivineMC - Chunk System optimization
}
public void updatePlayer(final ServerPlayer player) {
@@ -308,7 +308,7 @@ public final class RegionizedPlayerChunkLoader {
long currTime = System.nanoTime();
for (final ServerPlayer player : new java.util.ArrayList<>(this.world.players())) {
final PlayerChunkLoaderData loader = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
- if (loader == null || loader.removed || loader.world != this.world) {
+ if (loader == null || loader.removed || loader.world != this.world || !loader.canTick) { // DivineMC - Chunk System optimization
// not our problem anymore
continue;
}
@@ -327,6 +327,7 @@ public final class RegionizedPlayerChunkLoader {
private final ServerPlayer player;
private final ServerLevel world;
+ public volatile boolean canTick; // DivineMC - Chunk System optimization
private int lastChunkX = Integer.MIN_VALUE;
private int lastChunkZ = Integer.MIN_VALUE;
@@ -386,10 +387,19 @@ public final class RegionizedPlayerChunkLoader {
final int centerX = PlayerChunkLoaderData.this.lastChunkX;
final int centerZ = PlayerChunkLoaderData.this.lastChunkZ;
- return Integer.compare(
- Math.abs(c1x - centerX) + Math.abs(c1z - centerZ),
- Math.abs(c2x - centerX) + Math.abs(c2z - centerZ)
- );
+ // DivineMC start - Chunk Loading Priority Optimization
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkTaskPriority == org.bxteam.divinemc.server.chunk.ChunkTaskPriority.EUCLIDEAN_CIRCLE_PATTERN) {
+ return Integer.compare(
+ (c1x - centerX) * (c1x - centerX) + (c1z - centerZ) * (c1z - centerZ),
+ (c2x - centerX) * (c2x - centerX) + (c2z - centerZ) * (c2z - centerZ)
+ );
+ } else {
+ return Integer.compare(
+ Math.abs(c1x - centerX) + Math.abs(c1z - centerZ),
+ Math.abs(c2x - centerX) + Math.abs(c2z - centerZ)
+ );
+ }
+ // DivineMC end - Chunk Loading Priority Optimization
};
private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
@@ -857,6 +867,7 @@ public final class RegionizedPlayerChunkLoader {
}
void add() {
+ this.canTick = false; // DivineMC - Chunk System optimization
TickThread.ensureTickThread(this.player, "Cannot add player asynchronously");
if (this.removed) {
throw new IllegalStateException("Adding removed player chunk loader");
@@ -896,6 +907,7 @@ public final class RegionizedPlayerChunkLoader {
// now we can update
this.update();
+ this.canTick = true; // DivineMC - Chunk System optimization
}
private boolean isLoadedChunkGeneratable(final int chunkX, final int chunkZ) {
@@ -1064,6 +1076,7 @@ public final class RegionizedPlayerChunkLoader {
}
void remove() {
+ this.canTick = false; // DivineMC - Chunk System optimization
TickThread.ensureTickThread(this.player, "Cannot add player asynchronously");
if (this.removed) {
throw new IllegalStateException("Removing removed player chunk loader");
@@ -1091,7 +1104,7 @@ public final class RegionizedPlayerChunkLoader {
}
public LongOpenHashSet getSentChunksRaw() {
- return this.sentChunks;
+ return new LongOpenHashSet(this.sentChunks); // DivineMC - Chunk System optimization
}
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
index 6ce4a98e4d3b633e3c87944c23b6b3f0ff58f159..dce2b0ae83e70ccaf2ac97441f80b25876ee9058 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
@@ -73,37 +73,50 @@ public final class ChunkHolderManager {
private static final long NO_TIMEOUT_MARKER = Long.MIN_VALUE;
public final ReentrantAreaLock ticketLockArea;
- private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
- private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
+ // DivineMC start - Chunk System optimization
+ private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
+ private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
+ // DivineMC end - Chunk System optimization
final ChunkUnloadQueue unloadQueue;
- private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f);
+ private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F); // DivineMC - Chunk System optimization
private final ServerLevel world;
private final ChunkTaskScheduler taskScheduler;
private long currentTick;
- private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
- private final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>();
- private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
- if (c1 == c2) {
- return 0;
- }
+ // DivineMC start - Chunk System optimization
+ public static class LevelHolderData {
+ private final java.util.concurrent.ConcurrentLinkedDeque<NewChunkHolder> pendingFullLoadUpdate = new java.util.concurrent.ConcurrentLinkedDeque<>();
+ private final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>();
+ private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
+ if (c1 == c2) {
+ return 0;
+ }
- final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave);
+ final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave);
- if (saveTickCompare != 0) {
- return saveTickCompare;
- }
+ if (saveTickCompare != 0) {
+ return saveTickCompare;
+ }
- final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ);
- final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ);
+ final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ);
+ final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ);
- if (coord1 == coord2) {
- throw new IllegalStateException("Duplicate chunkholder in auto save queue");
- }
+ if (coord1 == coord2) {
+ throw new IllegalStateException("Duplicate chunkholder in auto save queue");
+ }
- return Long.compare(coord1, coord2);
- });
+ return Long.compare(coord1, coord2);
+ });
+ }
+
+ public LevelHolderData getData() {
+ if (this.world == null) {
+ throw new RuntimeException("World was null!");
+ }
+ return world.chunkHolderData;
+ }
+ // DivineMC end - Chunk System optimization
private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> ticketCounters = new ConcurrentLong2ReferenceChainedHashTable<>();
@@ -226,26 +239,29 @@ public final class ChunkHolderManager {
this.taskScheduler.setShutdown(true);
}
- void ensureInAutosave(final NewChunkHolder holder) {
- if (!this.autoSaveQueue.contains(holder)) {
+ // DivineMC start - Chunk System optimization
+ synchronized void ensureInAutosave(final NewChunkHolder holder) {
+ final LevelHolderData data = getData();
+ if (!data.autoSaveQueue.contains(holder)) {
holder.lastAutoSave = this.currentTick;
- this.autoSaveQueue.add(holder);
+ data.autoSaveQueue.add(holder);
}
}
- public void autoSave() {
+ public synchronized void autoSave() {
+ final LevelHolderData data = getData();
final List<NewChunkHolder> reschedule = new ArrayList<>();
final long currentTick = this.currentTick;
final long maxSaveTime = currentTick - Math.max(1L, PlatformHooks.get().configAutoSaveInterval(this.world));
final int maxToSave = PlatformHooks.get().configMaxAutoSavePerTick(this.world);
- for (int autoSaved = 0; autoSaved < maxToSave && !this.autoSaveQueue.isEmpty();) {
- final NewChunkHolder holder = this.autoSaveQueue.first();
+ for (int autoSaved = 0; autoSaved < maxToSave && !data.autoSaveQueue.isEmpty();) {
+ final NewChunkHolder holder = data.autoSaveQueue.first();
if (holder.lastAutoSave > maxSaveTime) {
break;
}
- this.autoSaveQueue.remove(holder);
+ data.autoSaveQueue.remove(holder);
holder.lastAutoSave = currentTick;
if (holder.save(false) != null) {
@@ -259,10 +275,11 @@ public final class ChunkHolderManager {
for (final NewChunkHolder holder : reschedule) {
if (holder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)) {
- this.autoSaveQueue.add(holder);
+ data.autoSaveQueue.add(holder);
}
}
}
+ // DivineMC end - Chunk System optimization
public void saveAllChunks(final boolean flush, final boolean shutdown, final boolean logProgress) {
final List<NewChunkHolder> holders = this.getChunkHolders();
@@ -321,13 +338,9 @@ public final class ChunkHolderManager {
}
if (logProgress) {
final long currTime = System.nanoTime();
- if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(10L)) {
+ if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(5L)) { // DivineMC - Log a bit more frequently
lastLog = currTime;
- 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)
- );
+ LOGGER.info("Saved {} block chunks, {} entity chunks, {} poi chunks in world '{}', progress: {}", savedChunk, savedEntity, savedPoi, ca.spottedleaf.moonrise.common.util.WorldUtil.getWorldName(this.world), format.format((double) (i + 1) / (double) len * 100.0)); // DivineMC - Beautify log
}
}
}
@@ -461,8 +474,8 @@ public final class ChunkHolderManager {
final Long2ObjectOpenHashMap<SortedArraySet<Ticket>> ret = new Long2ObjectOpenHashMap<>();
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
- final long coord = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long coord = iterator.next(); // DivineMC - Chunk System optimization
sections.computeIfAbsent(
CoordinateUtils.getChunkKey(
CoordinateUtils.getChunkX(coord) >> sectionShift,
@@ -559,7 +572,7 @@ public final class ChunkHolderManager {
chunkZ >> sectionShift
);
- this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (final long keyInMap) -> {
+ this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (keyInMap) -> { // DivineMC - Chunk System optimization
return new Long2IntOpenHashMap();
}).addTo(chunkKey, 1);
}
@@ -603,8 +616,8 @@ public final class ChunkHolderManager {
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
try {
- final SortedArraySet<Ticket> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> {
- return (SortedArraySet)SortedArraySet.create(4);
+ final SortedArraySet<Ticket> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (keyInMap) -> { // DivineMC - Chunk System optimization
+ return SortedArraySet.create(4);
});
final int levelBefore = getTicketLevelAt(ticketsAtChunk);
@@ -784,8 +797,8 @@ public final class ChunkHolderManager {
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
- final long coord = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long coord = iterator.next(); // DivineMC - Chunk System optimization
sections.computeIfAbsent(
CoordinateUtils.getChunkKey(
CoordinateUtils.getChunkX(coord) >> sectionShift,
@@ -836,8 +849,8 @@ public final class ChunkHolderManager {
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
- for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) {
- final long sectionKey = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long sectionKey = iterator.next(); // DivineMC - Chunk System optimization
if (!this.sectionToChunkToExpireCount.containsKey(sectionKey)) {
// removed concurrently
@@ -1145,18 +1158,29 @@ public final class ChunkHolderManager {
if (!TickThread.isTickThread()) {
// These will be handled on the next ServerChunkCache$MainThreadExecutor#pollTask, as it runs the distance manager update
// which will invoke processTicketUpdates
- this.offThreadPendingFullLoadUpdate.addAll(changedFullStatus);
+ this.getData().offThreadPendingFullLoadUpdate.addAll(changedFullStatus); // DivineMC - Chunk System optimization
+
+ // DivineMC start - Chunk System optimization
+ this.taskScheduler.scheduleChunkTask(() -> {
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.getData().pendingFullLoadUpdate;
+ for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
+ pendingFullLoadUpdate.add(changedFullStatus.get(i));
+ }
+
+ ChunkHolderManager.this.processPendingFullUpdate();
+ }, Priority.HIGHEST);
+ // DivineMC end - Chunk System optimization
} else {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
pendingFullLoadUpdate.add(changedFullStatus.get(i));
}
}
}
- private void removeChunkHolder(final NewChunkHolder holder) {
+ private synchronized void removeChunkHolder(final NewChunkHolder holder) { // DivineMC - Chunk System optimization
holder.onUnload();
- this.autoSaveQueue.remove(holder);
+ this.getData().autoSaveQueue.remove(holder); // DivineMC - Chunk System optimization
PlatformHooks.get().onChunkHolderDelete(this.world, holder.vanillaChunkHolder);
this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ));
}
@@ -1314,6 +1338,27 @@ public final class ChunkHolderManager {
}
}
+ // DivineMC start - Chunk System optimization
+ public final java.util.Set<Long> blockTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true));
+ public final java.util.Set<Long> entityTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true));
+
+ public void markBlockTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.add(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markNonBlockTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markEntityTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.add(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markNonEntityTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+ // DivineMC end - Chunk System optimization
+
public enum TicketOperationType {
ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE
}
@@ -1473,8 +1518,8 @@ public final class ChunkHolderManager {
// only call on tick thread
private void processOffThreadFullUpdates() {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
- final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = this.offThreadPendingFullLoadUpdate;
+ final java.util.concurrent.ConcurrentLinkedDeque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
+ final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = this.getData().offThreadPendingFullLoadUpdate; // DivineMC - Chunk System optimization
NewChunkHolder toUpdate;
while ((toUpdate = offThreadPendingFullLoadUpdate.poll()) != null) {
@@ -1486,7 +1531,7 @@ public final class ChunkHolderManager {
private boolean processPendingFullUpdate() {
this.processOffThreadFullUpdates();
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
boolean ret = false;
@@ -1522,8 +1567,7 @@ public final class ChunkHolderManager {
final JsonArray allTicketsJson = new JsonArray();
ret.add("tickets", allTicketsJson);
- for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>>> iterator = this.tickets.entryIterator();
- iterator.hasNext();) {
+ for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>>> iterator = this.tickets.entryIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>> coordinateTickets = iterator.next();
final long coordinate = coordinateTickets.getKey();
final SortedArraySet<Ticket> tickets = coordinateTickets.getValue();
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
index 8f8268924ac92fca5df8a11e08031fa8416c6e05..f1bc7a5e80de0293e1837b2f7401b347fc59f831 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
@@ -66,14 +66,6 @@ public final class ChunkTaskScheduler {
private static final Logger LOGGER = LogUtils.getClassLogger();
- public static void init(final boolean useParallelGen) {
- for (final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor executor : MoonriseCommon.RADIUS_AWARE_GROUP.getAllExecutors()) {
- executor.setMaxParallelism(useParallelGen ? -1 : 1);
- }
-
- LOGGER.info("Chunk system is using population gen parallelism: " + useParallelGen);
- }
-
public static final TicketType CHUNK_LOAD = ChunkSystemTicketType.create("chunk_system:chunk_load", Long::compareTo);
private static final AtomicLong CHUNK_LOAD_IDS = new AtomicLong();
@@ -116,12 +108,12 @@ public final class ChunkTaskScheduler {
public final ServerLevel world;
public final RadiusAwarePrioritisedExecutor radiusAwareScheduler;
- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor parallelGenExecutor;
- private final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor radiusAwareGenExecutor;
- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor loadExecutor;
+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor parallelGenExecutor;
+ private final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor radiusAwareGenExecutor;
+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor loadExecutor;
public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor ioExecutor;
- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor compressionExecutor;
- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor saveExecutor;
+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor compressionExecutor;
+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor saveExecutor;
private final PrioritisedTaskQueue mainThreadExecutor = new PrioritisedTaskQueue();
@@ -292,14 +284,14 @@ public final class ChunkTaskScheduler {
this.lockShift = Math.max(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift(), ThreadedTicketLevelPropagator.SECTION_SHIFT);
this.schedulingLockArea = new ReentrantAreaLock(this.getChunkSystemLockShift());
- 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.parallelGenExecutor = MoonriseCommon.PARALLEL_GEN_GROUP.createExecutor();
+ this.radiusAwareGenExecutor = MoonriseCommon.RADIUS_AWARE_GROUP.createExecutor();
+ this.loadExecutor = MoonriseCommon.LOAD_GROUP.createExecutor();
+ this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, 10_000);
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.compressionExecutor = MoonriseCommon.LOAD_GROUP.createExecutor();
+ this.saveExecutor = MoonriseCommon.LOAD_GROUP.createExecutor();
this.chunkHolderManager = new ChunkHolderManager(world, this);
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
index 2cc0e7c72d2b2e562452138f2b41fd1dcaf0570a..772694b751057aca58cea51741ebc45189078117 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
@@ -646,11 +646,19 @@ public final class NewChunkHolder {
}
public final ChunkHolder vanillaChunkHolder;
+ // DivineMC start - Chunk System optimization
+ private final long cachedLongPos;
+
+ public long getCachedLongPos() {
+ return cachedLongPos;
+ }
+ // DivineMC end - Chunk System optimization
public NewChunkHolder(final ServerLevel world, final int chunkX, final int chunkZ, final ChunkTaskScheduler scheduler) {
this.world = world;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
+ this.cachedLongPos = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(this.chunkX, this.chunkZ); // DivineMC - Chunk System optimization
this.scheduler = scheduler;
this.vanillaChunkHolder = new ChunkHolder(
new ChunkPos(chunkX, chunkZ), ChunkHolderManager.MAX_TICKET_LEVEL, world,
@@ -792,12 +800,14 @@ public final class NewChunkHolder {
// note: these are completed with null to indicate that no write occurred
// they are also completed with null to indicate a null write occurred
- private UnloadTask chunkDataUnload;
- private UnloadTask entityDataUnload;
- private UnloadTask poiDataUnload;
+ // DivineMC start - Chunk System optimization
+ private volatile UnloadTask chunkDataUnload;
+ private volatile UnloadTask entityDataUnload;
+ private volatile UnloadTask poiDataUnload;
+ // DivineMC end - Chunk System optimization
public static final record UnloadTask(CallbackCompletable<CompoundTag> completable, PrioritisedExecutor.PrioritisedTask task,
- LazyRunnable toRun) {}
+ org.bxteam.divinemc.server.chunk.ChunkRunnable toRun) {} // DivineMC - Chunk System optimization
public UnloadTask getUnloadTask(final MoonriseRegionFileIO.RegionFileType type) {
switch (type) {
@@ -860,7 +870,7 @@ public final class NewChunkHolder {
this.priorityLocked = false;
if (chunk != null) {
- final LazyRunnable toRun = new LazyRunnable();
+ final org.bxteam.divinemc.server.chunk.ChunkRunnable toRun = new org.bxteam.divinemc.server.chunk.ChunkRunnable(this.chunkX, this.chunkZ, this.world, null); // DivineMC - Chunk System optimization'
this.chunkDataUnload = new UnloadTask(new CallbackCompletable<>(), this.scheduler.saveExecutor.createTask(toRun), toRun);
}
if (poiChunk != null) {
@@ -879,7 +889,11 @@ public final class NewChunkHolder {
MoonriseRegionFileIO.scheduleSave(this.world, this.chunkX, this.chunkZ, data, type);
}
- this.getUnloadTask(type).completable().complete(data);
+ // DivineMC start - Chunk System optimization
+ UnloadTask task = this.getUnloadTask(type);
+ if (task == null) return;
+ task.completable().complete(data);
+ // DivineMC end - Chunk System optimization
final ReentrantAreaLock.Node schedulingLock = this.scheduler.schedulingLockArea.lock(this.chunkX, this.chunkZ);
try {
// can only write to these fields while holding the schedule lock
@@ -1192,6 +1206,7 @@ public final class NewChunkHolder {
for (int dz = -NEIGHBOUR_RADIUS; dz <= NEIGHBOUR_RADIUS; ++dz) {
for (int dx = -NEIGHBOUR_RADIUS; dx <= NEIGHBOUR_RADIUS; ++dx) {
final NewChunkHolder holder = (dx | dz) == 0 ? this : this.scheduler.chunkHolderManager.getChunkHolder(dx + this.chunkX, dz + this.chunkZ);
+ if (holder == null) continue; // DivineMC - Chunk System optimization
if (loaded) {
if (holder.setNeighbourFullLoaded(-dx, -dz)) {
changedFullStatus.add(holder);
@@ -1216,6 +1231,19 @@ public final class NewChunkHolder {
private void updateCurrentState(final FullChunkStatus to) {
this.currentFullChunkStatus = to;
+ // DivineMC start - Chunk System optimization
+ if (to.isOrAfter(FullChunkStatus.BLOCK_TICKING)) {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markBlockTicking(this);
+ } else {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonBlockTickingIfPossible(this);
+ }
+
+ if (to.isOrAfter(FullChunkStatus.ENTITY_TICKING)) {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markEntityTicking(this);
+ } else {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonEntityTickingIfPossible(this);
+ }
+ // DivineMC end - Chunk System optimization
}
// only to be called on the main thread, no locks need to be held
@@ -1350,11 +1378,11 @@ public final class NewChunkHolder {
return this.requestedGenStatus;
}
- private final Reference2ObjectOpenHashMap<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = new Reference2ObjectOpenHashMap<>();
+ private final Map<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Chunk System optimization
void addStatusConsumer(final ChunkStatus status, final Consumer<ChunkAccess> consumer) {
this.statusWaiters.computeIfAbsent(status, (final ChunkStatus keyInMap) -> {
- return new ArrayList<>(4);
+ return new java.util.concurrent.CopyOnWriteArrayList<>(); // DivineMC - Chunk System optimization
}).add(consumer);
}
@@ -1396,11 +1424,11 @@ public final class NewChunkHolder {
}, Priority.HIGHEST);
}
- private final Reference2ObjectOpenHashMap<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = new Reference2ObjectOpenHashMap<>();
+ private final Map<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Chunk System optimization
void addFullStatusConsumer(final FullChunkStatus status, final Consumer<LevelChunk> consumer) {
this.fullStatusWaiters.computeIfAbsent(status, (final FullChunkStatus keyInMap) -> {
- return new ArrayList<>(4);
+ return new java.util.concurrent.CopyOnWriteArrayList<>(); // DivineMC - Chunk System optimization
}).add(consumer);
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java
index 28ffa653e87a4e8ef7cf614916ef3fe61681fe16..b35b92b204fbefd139c4544f15e32d46bfa30777 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java
@@ -110,60 +110,27 @@ public class RadiusAwarePrioritisedExecutor {
return priorityId == this.selectedQueue ? queue.tryPushTasks() : null;
}
+ // DivineMC start - Chunk System Optimizations
public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius,
- final Runnable run, final Priority priority) {
+ final Runnable run, final Priority priority, final net.minecraft.server.level.ServerLevel world) {
if (radius < 0) {
throw new IllegalArgumentException("Radius must be > 0: " + radius);
}
- return new Task(this, chunkX, chunkZ, radius, run, priority);
+ return new Task(this, chunkX, chunkZ, radius, run, priority, world);
}
- public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius,
- final Runnable run) {
- 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 Priority priority) {
- final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run, priority);
-
- ret.queue();
-
- return ret;
- }
-
- public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius,
- final Runnable run) {
- final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run);
-
- ret.queue();
-
- return ret;
- }
-
- 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, Priority.NORMAL);
- }
-
- public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final Priority priority) {
- final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, priority);
-
- ret.queue();
-
- return ret;
+ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final Priority priority, final net.minecraft.server.level.ServerLevel world) {
+ return new Task(this, 0, 0, -1, run, priority, world);
}
- public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run) {
- final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, Priority.NORMAL);
+ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final net.minecraft.server.level.ServerLevel world) {
+ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, Priority.NORMAL, world);
ret.queue();
return ret;
}
+ // DivineMC end - Chunk System Optimizations
private static void scheduleTasks(final List<PrioritisedExecutor.PrioritisedTask> toSchedule) {
if (toSchedule != null) {
@@ -440,18 +407,20 @@ public class RadiusAwarePrioritisedExecutor {
private final int radius;
private Runnable run;
private Priority priority;
+ public final net.minecraft.server.level.ServerLevel world; // DivineMC - Chunk System Optimization
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 Priority priority) {
+ final Runnable run, final Priority priority, final net.minecraft.server.level.ServerLevel world) { // DivineMC - Chunk System Optimization
this.scheduler = scheduler;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
this.radius = radius;
this.run = run;
this.priority = priority;
+ this.world = world; // DivineMC - Chunk System Optimization
}
private boolean isFiniteRadius() {
@@ -473,6 +442,7 @@ public class RadiusAwarePrioritisedExecutor {
synchronized (this.scheduler) {
final DependencyNode node = this.dependencyNode;
this.dependencyNode = null;
+ if (node == null) return; // DivineMC - Chunk System Optimization
toSchedule = node.tree.returnNode(node);
}
@@ -489,6 +459,7 @@ public class RadiusAwarePrioritisedExecutor {
final Runnable run = this.run;
this.run = null;
try {
+ if (run == null) return; // DivineMC - Chunk System Optimization
run.run();
} finally {
this.returnNode();
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
index 96ccb8f657d755b2e58a8dd0cda00ca0df4886b2..89de0fcb3f8142f76399fc00e288e03d7f3742f2 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
@@ -35,7 +35,7 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
super(scheduler, world, chunkX, chunkZ);
this.chunkHolder = chunkHolder;
this.fromChunk = fromChunk;
- this.convertToFullTask = scheduler.createChunkTask(chunkX, chunkZ, this, priority);
+ this.convertToFullTask = scheduler.radiusAwareScheduler.createInfiniteRadiusTask(this, priority, world); // DivineMC - Chunk System Optimizations
}
@Override
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java
index e9623c334858ebc698c92d05b36b70f6d846d0b1..43ef4d7b7db64a766bb815e1c2202b1f30ae4f99 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java
@@ -69,7 +69,7 @@ public abstract class ChunkProgressionTask {
}
}
- protected final void complete(final ChunkAccess chunk, final Throwable throwable) {
+ protected void complete(final ChunkAccess chunk, final Throwable throwable) { // DivineMC - not final
try {
this.complete0(chunk, throwable);
} catch (final Throwable thr2) {
@@ -81,7 +81,7 @@ public abstract class ChunkProgressionTask {
private void complete0(final ChunkAccess chunk, final Throwable throwable) {
if ((boolean)COMPLETED_HANDLE.getAndSet((ChunkProgressionTask)this, (boolean)true)) {
- throw new IllegalStateException("Already completed");
+ return; // DivineMC - do not crash the server
}
this.completedChunk = chunk;
this.completedThrowable = throwable;
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java
index 25d8da4773dcee5096053e7e3788bfc224d705a7..2112ccbe382993dcfb56a50d991c3613765d7d56 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java
@@ -51,9 +51,9 @@ public final class ChunkUpgradeGenericStatusTask extends ChunkProgressionTask im
} else {
final int writeRadius = ((ChunkSystemChunkStatus)this.toStatus).moonrise$getWriteRadius();
if (writeRadius < 0) {
- this.generateTask = this.scheduler.radiusAwareScheduler.createInfiniteRadiusTask(this, priority);
+ this.generateTask = this.scheduler.radiusAwareScheduler.createInfiniteRadiusTask(this, priority, world); // DivineMC - Chunk System Optimizations
} else {
- this.generateTask = this.scheduler.radiusAwareScheduler.createTask(chunkX, chunkZ, writeRadius, this, priority);
+ this.generateTask = this.scheduler.radiusAwareScheduler.createTask(chunkX, chunkZ, writeRadius, this, priority, world); // DivineMC - Chunk System Optimizations
}
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java
index 95ed5a0ff3f0588f625ba48a5fee3aafbab9d13f..f2fd6d5eb024f646875868c441eb2da284206026 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java
@@ -333,6 +333,12 @@ public abstract class GenericDataLoadTask<OnMain,FinalCompletion> {
GenericDataLoadTask.this.onComplete((TaskResult<FinalCompletion, Throwable>)newData);
}
}
+
+ // DivineMC start - Chunk System Optimizations
+ public GenericDataLoadTask<OnMain,FinalCompletion> loadTask() {
+ return GenericDataLoadTask.this;
+ }
+ // DivineMC end - Chunk System Optimizations
}
public final class ProcessOnMainTask implements Runnable {
@@ -351,6 +357,12 @@ public abstract class GenericDataLoadTask<OnMain,FinalCompletion> {
GenericDataLoadTask.this.onComplete(result);
}
+
+ // DivineMC start - Chunk System Optimizations
+ public GenericDataLoadTask<OnMain,FinalCompletion> loadTask() {
+ return GenericDataLoadTask.this;
+ }
+ // DivineMC end - Chunk System Optimizations
}
protected static final class LoadDataFromDiskTask {
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java b/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
index 93fd23027c00cef76562098306737272fda1350a..44e443768f5163454fd11425afd3bc07b2c0c6c2 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
@@ -23,6 +23,7 @@ public final class ParallelSearchRadiusIteration {
}
public static long[] getSearchIteration(final int radius) {
+ if (radius >= SEARCH_RADIUS_ITERATION_LIST.length) return SEARCH_RADIUS_ITERATION_LIST[SEARCH_RADIUS_ITERATION_LIST.length - 1]; // DivineMC - Chunk System Optimizations
return SEARCH_RADIUS_ITERATION_LIST[radius];
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
index 6d1fe8028739145b11fce98ad62b2f8044299548..1885339f1ed5f24aa281aa2720a1d511a95740de 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
@@ -2,7 +2,7 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration;
public final class ChunkTickConstants {
- public static final int PLAYER_SPAWN_TRACK_RANGE = 8;
+ public static final int PLAYER_SPAWN_TRACK_RANGE = (int) Math.round(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange / 16.0); // DivineMC - Chunk System optimization
// the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter
// note: vanilla does not subtract 0.5 but the result is (luckily!) the same
public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5);
diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
index 4ca68a903e67606fc4ef0bfa9862a73797121c8b..f94f443f862611f039454d1dc8ff2a4ba5f081d3 100644
--- a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
+++ b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
@@ -325,7 +325,7 @@ public final class SWMRNibbleArray {
}
// operation type: updating
- public boolean updateVisible() {
+ public synchronized boolean updateVisible() { // DivineMC - Chunk System optimization
if (!this.isDirty()) {
return false;
}
diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
index 51f4dd4f583dfbd16cb00f1cb4418d1044cecb1c..2f83deafbb5b50e5ce191b5351ec5ed948262008 100644
--- a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
+++ b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
@@ -887,7 +887,7 @@ public final class StarLightInterface {
super(chunkCoordinate, lightEngine, queue);
this.task = ((ChunkSystemServerLevel)(ServerLevel)lightEngine.getWorld()).moonrise$getChunkTaskScheduler().radiusAwareScheduler.createTask(
CoordinateUtils.getChunkX(chunkCoordinate), CoordinateUtils.getChunkZ(chunkCoordinate),
- ((ChunkSystemChunkStatus)ChunkStatus.LIGHT).moonrise$getWriteRadius(), this, priority
+ ((ChunkSystemChunkStatus)ChunkStatus.LIGHT).moonrise$getWriteRadius(), this, priority, lightEngine.world.getMinecraftWorld() // DivineMC - Chunk System Optimizations
);
}
diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java
index df6fbb35e5023b42de0b97434712e04a6b3e66a3..8c6b853c77e5b3af90913e4a878f344b11f8a5aa 100644
--- a/io/papermc/paper/FeatureHooks.java
+++ b/io/papermc/paper/FeatureHooks.java
@@ -42,10 +42,6 @@ public final class FeatureHooks {
ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.setUnloadDelay(ticks); // Paper - rewrite chunk system
}
- public static void initChunkTaskScheduler(final boolean useParallelGen) {
- ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.init(useParallelGen); // Paper - Chunk system
- }
-
public static void registerPaperCommands(final Map<Set<String>, PaperSubcommand> commands) {
commands.put(Set.of("fixlight"), new FixLightCommand()); // Paper - rewrite chunk system
commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand()); // Paper - rewrite chunk system
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 687af4f52dc3ae5564079b6782b63a4277c43439..ab3b1c7442b9f3dd72a9ce8c70dc708d2371471a 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -132,8 +132,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public
private final String storageName;
private final PlayerMap playerMap = new PlayerMap();
- public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new Int2ObjectOpenHashMap<>();
- private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap();
+ public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new org.bxteam.divinemc.util.map.Int2ObjectConcurrentHashMap<>(); // DivineMC - Chunk System Optimizations
+ private final Long2ByteMap chunkTypeCache = it.unimi.dsi.fastutil.longs.Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); // DivineMC - Chunk System Optimizations
// Paper - rewrite chunk system
public int serverViewDistance;
public final WorldGenContext worldGenContext; // Paper - public
@@ -256,7 +256,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
for (int i = 0, len = inRange.size(); i < len; i++) {
- ++(backingSet[i].mobCounts[index]);
+ // DivineMC start - Chunk System Optimizations
+ ServerPlayer player = backingSet[i];
+ if (player == null) continue;
+ ++(player.mobCounts[index]);
+ // DivineMC end - Chunk System Optimizations
}
}
@@ -273,7 +277,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
for (int i = 0, len = inRange.size(); i < len; i++) {
- ++(backingSet[i].mobBackoffCounts[idx]);
+ // DivineMC start - Chunk System Optimizations
+ ServerPlayer player = backingSet[i];
+ if (player == null) continue;
+ ++(player.mobBackoffCounts[idx]);
+ // DivineMC end - Chunk System Optimizations
}
}
// Paper end - per player mob count backoff
@@ -774,27 +782,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return false;
}
- final ServerPlayer[] raw = players.getRawDataUnchecked();
- final int len = players.size();
-
- Objects.checkFromIndexSize(0, len, raw.length);
- for (int i = 0; i < len; ++i) {
- final ServerPlayer serverPlayer = raw[i];
- // Paper start - PlayerNaturallySpawnCreaturesEvent
- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
- blockRange = 16384.0D;
- if (reducedRange) {
- event = serverPlayer.playerNaturallySpawnedEvent;
- if (event == null || event.isCancelled()) continue;
- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
- }
- if (this.playerIsCloseEnoughForSpawning(serverPlayer, chunkPos, blockRange)) {
- // Paper end - PlayerNaturallySpawnCreaturesEvent
- return true;
- }
- }
-
- return false;
+ return !players.isEmpty(); // DivineMC - Chunk System Optimizations
// Paper end - chunk tick iteration optimisation
}
@@ -812,10 +800,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
final ServerPlayer[] raw = players.getRawDataUnchecked();
final int len = players.size();
- Objects.checkFromIndexSize(0, len, raw.length);
- for (int i = 0; i < len; ++i) {
+ for (int i = 0; i < raw.length; ++i) { // DivineMC - Chunk System Optimizations
final ServerPlayer player = raw[i];
- if (this.playerIsCloseEnoughForSpawning(player, chunkPos, 16384.0D)) { // Spigot
+ if (player == null) continue; // DivineMC - Chunk System Optimizations
+ if (this.playerIsCloseEnoughForSpawning(player, chunkPos, (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange^2))) { // Spigot // DivineMC - Chunk System Optimizations
if (ret == null) {
ret = new ArrayList<>(len - i);
ret.add(player);
@@ -1208,6 +1196,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
} else {
for (int i = 0, len = players.size(); i < len; ++i) {
final ServerPlayer player = playersRaw[i];
+ if (player == null) continue; // DivineMC - Chunk System Optimizations
this.updatePlayer(player);
}
diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java
index fd3d0f6cb53bc8b6186f0d86575f21007b2c20ed..7f3c41b59e288364d67534511fc038e6dbb268fa 100644
--- a/net/minecraft/server/level/DistanceManager.java
+++ b/net/minecraft/server/level/DistanceManager.java
@@ -127,15 +127,13 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches
public boolean inEntityTickingRange(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos);
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkHolderManager().entityTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean inBlockTickingRange(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos);
- return chunkHolder != null && chunkHolder.isTickingReady();
+ return this.moonrise$getChunkHolderManager().blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 75c8ce32e68f92e20201e9c243f46f2be716eac8..2873642844c683ae4388ae27a045e01441d15426 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -444,8 +444,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
public boolean isPositionTicking(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- return newChunkHolder != null && newChunkHolder.isTickingReady();
+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index d0d97e063acf8f11c32adf1fd2ec6bca59913c33..14c8df2f3b9c133b38e871e81f7ee2333322437c 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -179,6 +179,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public final ServerChunkCache chunkSource;
private final MinecraftServer server;
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
+ public final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData chunkHolderData; // DivineMC - Chunk System optimization
private int lastSpawnChunkRadius;
final EntityTickList entityTickList = new EntityTickList();
private final ServerWaypointManager waypointManager;
@@ -290,6 +291,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
// Paper end - optimise getPlayerByUUID
// Paper start - rewrite chunk system
+ public final org.bxteam.divinemc.server.chunk.PriorityHandler chunkSystemPriorities;
private final ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistanceHolder viewDistanceHolder = new ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistanceHolder();
private final ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader chunkLoader = new ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader((ServerLevel)(Object)this);
private final ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController entityDataController;
@@ -682,6 +684,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper start - rewrite chunk system
this.moonrise$setEntityLookup(new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup((ServerLevel)(Object)this, ((ServerLevel)(Object)this).new EntityCallbacks()));
this.chunkTaskScheduler = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler((ServerLevel)(Object)this);
+ this.chunkHolderData = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData(); // DivineMC - Chunk System optimization
this.entityDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController(
new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController.EntityRegionFileStorage(
new RegionStorageInfo(levelStorageAccess.getLevelId(), dimension, "entities"),
@@ -695,6 +698,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - rewrite chunk system
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
+ this.chunkSystemPriorities = new org.bxteam.divinemc.server.chunk.PriorityHandler(this); // DivineMC - Chunk System optimizations
}
// Paper start
@@ -825,8 +829,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public boolean shouldTickBlocksAt(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- return holder != null && holder.isTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
@@ -882,7 +885,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
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 int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(this); // DivineMC - Chunk System optimization
final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom simpleRandom = this.simpleRandom;
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
@@ -890,42 +893,41 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
final int offsetX = cpos.x << 4;
final int offsetZ = cpos.z << 4;
+ // DivineMC start - Chunk System optimization
for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) {
- final int offsetY = (sectionIndex + minSection) << 4;
final LevelChunkSection section = sections[sectionIndex];
- final net.minecraft.world.level.chunk.PalettedContainer<net.minecraft.world.level.block.state.BlockState> states = section.states;
if (!section.isRandomlyTickingBlocks()) {
continue;
}
+ final int offsetY = (sectionIndex + minSection) << 4;
+ final net.minecraft.world.level.chunk.PalettedContainer<net.minecraft.world.level.block.state.BlockState> states = section.states;
- final ca.spottedleaf.moonrise.common.list.ShortList tickList = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getTickingBlockList();
+ final ca.spottedleaf.moonrise.common.list.ShortList tickList = section.moonrise$getTickingBlockList();
for (int i = 0; i < tickSpeed; ++i) {
- final int tickingBlocks = tickList.size();
final int index = simpleRandom.nextInt() & ((16 * 16 * 16) - 1);
- if (index >= tickingBlocks) {
+ if (index >= tickList.size()) {
// most of the time we fall here
continue;
}
- final int location = (int)tickList.getRaw(index) & 0xFFFF;
+ final int location = tickList.getRaw(index);
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((location & 15) | offsetX, ((location >>> (4 + 4)) & 15) | offsetY, ((location >>> 4) & 15) | offsetZ);
+ final BlockPos pos = new BlockPos((location & 15) | offsetX, (location >>> (4 + 4)) | offsetY, ((location >>> 4) & 15) | offsetZ);
- state.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
+ state.randomTick(this, pos, simpleRandom);
if (doubleTickFluids) {
final FluidState fluidState = state.getFluidState();
if (fluidState.isRandomlyTicking()) {
- fluidState.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
+ fluidState.randomTick(this, pos, simpleRandom);
}
}
}
}
-
- return;
+ // DivineMC end - Chunk System optimization
}
// Paper end - optimise random ticking
@@ -2559,16 +2561,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public boolean isPositionTickingWithEntitiesLoaded(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- // isTicking implies the chunk is loaded, and the chunk is loaded now implies the entities are loaded
- return chunkHolder != null && chunkHolder.isTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean isPositionEntityTicking(BlockPos pos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos));
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ThreadedLevelLightEngine.java b/net/minecraft/server/level/ThreadedLevelLightEngine.java
index 216c2294f59a9d53613ac249ea63adeaa8a8efa4..b83438852a7b01fef9a736a5b0bc46f15ed1d59b 100644
--- a/net/minecraft/server/level/ThreadedLevelLightEngine.java
+++ b/net/minecraft/server/level/ThreadedLevelLightEngine.java
@@ -138,7 +138,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
}
}
);
- });
+ }, world); // DivineMC - Chunk System Optimizations
return chunks.size();
}
diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java
index 0842fd6488c8b27d98c4344e1244996b4c0e9912..cba72a86d99fb4b3a3f9f5aefe9993ec8e84abfd 100644
--- a/net/minecraft/world/level/LevelReader.java
+++ b/net/minecraft/world/level/LevelReader.java
@@ -74,10 +74,27 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste
@Override
default Holder<Biome> getNoiseBiome(int x, int y, int z) {
- ChunkAccess chunk = this.getChunk(QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false);
+ ChunkAccess chunk = this.fasterChunkAccess(this, QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false); // DivineMC - Chunk System optimization
return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z);
}
+ // DivineMC start - Chunk System optimization
+ private @Nullable ChunkAccess fasterChunkAccess(LevelReader instance, int x, int z, ChunkStatus chunkStatus, boolean create) {
+ if (!create && instance instanceof net.minecraft.server.level.ServerLevel world) {
+ final net.minecraft.server.level.ChunkHolder holder = (world.getChunkSource().chunkMap).getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
+ if (holder != null) {
+ final java.util.concurrent.CompletableFuture<net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk>> future = holder.getFullChunkFuture();
+ final net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk> either = future.getNow(null);
+ if (either != null) {
+ final net.minecraft.world.level.chunk.LevelChunk chunk = either.orElse(null);
+ if (chunk != null) return chunk;
+ }
+ }
+ }
+ return instance.getChunk(x, z, chunkStatus, create);
+ }
+ // DivineMC end - Chunk System optimization
+
Holder<Biome> getUncachedNoiseBiome(int x, int y, int z);
boolean isClientSide();
diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java
index 73962e79a0f3d892e3155443a1b84508b0f4042e..5622345280267792861c8d508d0366cfdfb2c17a 100644
--- a/net/minecraft/world/level/biome/BiomeManager.java
+++ b/net/minecraft/world/level/biome/BiomeManager.java
@@ -14,6 +14,7 @@ public class BiomeManager {
private static final int ZOOM_MASK = 3;
private final BiomeManager.NoiseBiomeSource noiseBiomeSource;
private final long biomeZoomSeed;
+ private static final double maxOffset = 0.4500000001D; // DivineMC - Chunk System Optimizations
public BiomeManager(BiomeManager.NoiseBiomeSource noiseBiomeSource, long biomeZoomSeed) {
this.noiseBiomeSource = noiseBiomeSource;
@@ -29,39 +30,65 @@ public class BiomeManager {
}
public Holder<Biome> getBiome(BlockPos pos) {
- int i = pos.getX() - 2;
- int i1 = pos.getY() - 2;
- int i2 = pos.getZ() - 2;
- int i3 = i >> 2;
- int i4 = i1 >> 2;
- int i5 = i2 >> 2;
- double d = (i & 3) / 4.0;
- double d1 = (i1 & 3) / 4.0;
- double d2 = (i2 & 3) / 4.0;
- int i6 = 0;
- double d3 = Double.POSITIVE_INFINITY;
+ // DivineMC start - Chunk System Optimizations
+ int xMinus2 = pos.getX() - 2;
+ int yMinus2 = pos.getY() - 2;
+ int zMinus2 = pos.getZ() - 2;
+ int x = xMinus2 >> 2;
+ int y = yMinus2 >> 2;
+ int z = zMinus2 >> 2;
+ double quartX = (double) (xMinus2 & 3) / 4.0;
+ double quartY = (double) (yMinus2 & 3) / 4.0;
+ double quartZ = (double) (zMinus2 & 3) / 4.0;
+ int smallestX = 0;
+ double smallestDist = Double.POSITIVE_INFINITY;
+ for (int biomeX = 0; biomeX < 8; ++biomeX) {
+ boolean everyOtherQuad = (biomeX & 4) == 0;
+ boolean everyOtherPair = (biomeX & 2) == 0;
+ boolean everyOther = (biomeX & 1) == 0;
+ double quartXX = everyOtherQuad ? quartX : quartX - 1.0;
+ double quartYY = everyOtherPair ? quartY : quartY - 1.0;
+ double quartZZ = everyOther ? quartZ : quartZ - 1.0;
- for (int i7 = 0; i7 < 8; i7++) {
- boolean flag = (i7 & 4) == 0;
- boolean flag1 = (i7 & 2) == 0;
- boolean flag2 = (i7 & 1) == 0;
- int i8 = flag ? i3 : i3 + 1;
- int i9 = flag1 ? i4 : i4 + 1;
- int i10 = flag2 ? i5 : i5 + 1;
- double d4 = flag ? d : d - 1.0;
- double d5 = flag1 ? d1 : d1 - 1.0;
- double d6 = flag2 ? d2 : d2 - 1.0;
- double fiddledDistance = getFiddledDistance(this.biomeZoomSeed, i8, i9, i10, d4, d5, d6);
- if (d3 > fiddledDistance) {
- i6 = i7;
- d3 = fiddledDistance;
+ double maxQuartYY = 0.0, maxQuartZZ = 0.0;
+ if (biomeX != 0) {
+ maxQuartYY = Mth.square(Math.max(quartYY + maxOffset, Math.abs(quartYY - maxOffset)));
+ maxQuartZZ = Mth.square(Math.max(quartZZ + maxOffset, Math.abs(quartZZ - maxOffset)));
+ double maxQuartXX = Mth.square(Math.max(quartXX + maxOffset, Math.abs(quartXX - maxOffset)));
+ if (smallestDist < maxQuartXX + maxQuartYY + maxQuartZZ) continue;
}
- }
+ int xx = everyOtherQuad ? x : x + 1;
+ int yy = everyOtherPair ? y : y + 1;
+ int zz = everyOther ? z : z + 1;
+
+ long seed = LinearCongruentialGenerator.next(this.biomeZoomSeed, xx);
+ seed = LinearCongruentialGenerator.next(seed, yy);
+ seed = LinearCongruentialGenerator.next(seed, zz);
+ seed = LinearCongruentialGenerator.next(seed, xx);
+ seed = LinearCongruentialGenerator.next(seed, yy);
+ seed = LinearCongruentialGenerator.next(seed, zz);
+ double offsetX = getFiddle(seed);
+ double sqrX = Mth.square(quartXX + offsetX);
+ if (biomeX != 0 && smallestDist < sqrX + maxQuartYY + maxQuartZZ) continue;
+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed);
+ double offsetY = getFiddle(seed);
+ double sqrY = Mth.square(quartYY + offsetY);
+ if (biomeX != 0 && smallestDist < sqrX + sqrY + maxQuartZZ) continue;
+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed);
+ double offsetZ = getFiddle(seed);
+ double biomeDist = sqrX + sqrY + Mth.square(quartZZ + offsetZ);
- int i7x = (i6 & 4) == 0 ? i3 : i3 + 1;
- int i11 = (i6 & 2) == 0 ? i4 : i4 + 1;
- int i12 = (i6 & 1) == 0 ? i5 : i5 + 1;
- return this.noiseBiomeSource.getNoiseBiome(i7x, i11, i12);
+ if (smallestDist > biomeDist) {
+ smallestX = biomeX;
+ smallestDist = biomeDist;
+ }
+ }
+ return this.noiseBiomeSource.getNoiseBiome(
+ (smallestX & 4) == 0 ? x : x + 1,
+ (smallestX & 2) == 0 ? y : y + 1,
+ (smallestX & 1) == 0 ? z : z + 1
+ );
+ // DivineMC end - Chunk System Optimizations
}
public Holder<Biome> getNoiseBiomeAtPosition(double x, double y, double z) {
diff --git a/net/minecraft/world/level/biome/TheEndBiomeSource.java b/net/minecraft/world/level/biome/TheEndBiomeSource.java
index cf3172be76fa4c7987ed569138439ff42f92fa7f..ed3c470056855a520a110ac7014f7839bcc85b88 100644
--- a/net/minecraft/world/level/biome/TheEndBiomeSource.java
+++ b/net/minecraft/world/level/biome/TheEndBiomeSource.java
@@ -27,6 +27,33 @@ public class TheEndBiomeSource extends BiomeSource {
private final Holder<Biome> islands;
private final Holder<Biome> barrens;
+ // DivineMC start - Chunk System Optimizations
+ private Holder<Biome> getBiomeForNoiseGenVanilla(int x, int y, int z, Climate.Sampler noise) {
+ int i = QuartPos.toBlock(x);
+ int j = QuartPos.toBlock(y);
+ int k = QuartPos.toBlock(z);
+ int l = SectionPos.blockToSectionCoord(i);
+ int m = SectionPos.blockToSectionCoord(k);
+ if ((long)l * (long)l + (long)m * (long)m <= 4096L) {
+ return this.end;
+ } else {
+ int n = (SectionPos.blockToSectionCoord(i) * 2 + 1) * 8;
+ int o = (SectionPos.blockToSectionCoord(k) * 2 + 1) * 8;
+ double d = noise.erosion().compute(new DensityFunction.SinglePointContext(n, j, o));
+ if (d > 0.25D) {
+ return this.highlands;
+ } else if (d >= -0.0625D) {
+ return this.midlands;
+ } else {
+ return d < -0.21875D ? this.islands : this.barrens;
+ }
+ }
+ }
+
+ private final ThreadLocal<it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap<Holder<Biome>>> cache = ThreadLocal.withInitial(it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap::new);
+ private final int cacheCapacity = 1024;
+ // DivineMC end - Chunk System Optimizations
+
public static TheEndBiomeSource create(HolderGetter<Biome> biomeGetter) {
return new TheEndBiomeSource(
biomeGetter.getOrThrow(Biomes.THE_END),
@@ -55,26 +82,24 @@ public class TheEndBiomeSource extends BiomeSource {
return CODEC;
}
+ // DivineMC start - Chunk System Optimizations
@Override
- public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
- int blockPosX = QuartPos.toBlock(x);
- int blockPosY = QuartPos.toBlock(y);
- int blockPosZ = QuartPos.toBlock(z);
- int sectionPosX = SectionPos.blockToSectionCoord(blockPosX);
- int sectionPosZ = SectionPos.blockToSectionCoord(blockPosZ);
- if ((long)sectionPosX * sectionPosX + (long)sectionPosZ * sectionPosZ <= 4096L) {
- return this.end;
+ public Holder<Biome> getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler multiNoiseSampler) {
+ final long key = net.minecraft.world.level.ChunkPos.asLong(biomeX, biomeZ);
+ final it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap<Holder<Biome>> cacheThreadLocal = cache.get();
+ final Holder<Biome> biome = cacheThreadLocal.get(key);
+ if (biome != null) {
+ return biome;
} else {
- int i = (SectionPos.blockToSectionCoord(blockPosX) * 2 + 1) * 8;
- int i1 = (SectionPos.blockToSectionCoord(blockPosZ) * 2 + 1) * 8;
- double d = sampler.erosion().compute(new DensityFunction.SinglePointContext(i, blockPosY, i1));
- if (d > 0.25) {
- return this.highlands;
- } else if (d >= -0.0625) {
- return this.midlands;
- } else {
- return d < -0.21875 ? this.islands : this.barrens;
+ final Holder<Biome> gennedBiome = getBiomeForNoiseGenVanilla(biomeX, biomeY, biomeZ, multiNoiseSampler);
+ cacheThreadLocal.put(key, gennedBiome);
+ if (cacheThreadLocal.size() > cacheCapacity) {
+ for (int i = 0; i < cacheCapacity / 16; i ++) {
+ cacheThreadLocal.removeFirst();
+ }
}
+ return gennedBiome;
}
}
+ // DivineMC end - Chunk System Optimizations
}
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
index 4db7ec2647b9f08536dc5253dac0fa8d3044e38b..e3abc97a1a66988e44b1ed78b76a198b82051da1 100644
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -23,6 +23,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
public short tickingFluidCount;
public final PalettedContainer<BlockState> states;
private PalettedContainer<Holder<Biome>> biomes; // CraftBukkit - read/write
+ private static final int sliceSize = 4; // DivineMC - Chunk System Optimizations
// Paper start - block counting
private static final it.unimi.dsi.fastutil.shorts.ShortArrayList FULL_LIST = new it.unimi.dsi.fastutil.shorts.ShortArrayList(16*16*16);
@@ -296,7 +297,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
}
public boolean maybeHas(Predicate<BlockState> predicate) {
- return this.states.maybeHas(predicate);
+ return this.states.maybeHasOrCatch(predicate, Blocks.AIR.defaultBlockState()); // DivineMC - Chunk System Optimizations
}
public Holder<Biome> getNoiseBiome(int x, int y, int z) {
@@ -312,13 +313,15 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
PalettedContainer<Holder<Biome>> palettedContainer = this.biomes.recreate();
int i = 4;
- for (int i1 = 0; i1 < 4; i1++) {
- for (int i2 = 0; i2 < 4; i2++) {
- for (int i3 = 0; i3 < 4; i3++) {
- palettedContainer.getAndSetUnchecked(i1, i2, i3, biomeResolver.getNoiseBiome(x + i1, y + i2, z + i3, climateSampler));
+ // DivineMC start - Chunk System Optimizations
+ for (int posY = 0; posY < sliceSize; ++posY) {
+ for (int posZ = 0; posZ < sliceSize; ++posZ) {
+ for (int posX = 0; posX < sliceSize; ++posX) {
+ palettedContainer.getAndSetUnchecked(posX, posY, posZ, biomeResolver.getNoiseBiome(x + posX, y + posY, z + posZ, climateSampler));
}
}
}
+ // DivineMC end - Chunk System Optimizations
this.biomes = palettedContainer;
}
diff --git a/net/minecraft/world/level/chunk/LinearPalette.java b/net/minecraft/world/level/chunk/LinearPalette.java
index 2073f6ff41aa570102621d183ee890b076267d54..25d46d1dff23a9bffd135d6954b551991e175cd4 100644
--- a/net/minecraft/world/level/chunk/LinearPalette.java
+++ b/net/minecraft/world/level/chunk/LinearPalette.java
@@ -12,7 +12,7 @@ public class LinearPalette<T> implements Palette<T>, ca.spottedleaf.moonrise.pat
private final T[] values;
private final PaletteResize<T> resizeHandler;
private final int bits;
- private int size;
+ private volatile int size; // DivineMC - Chunk System Optimizations
// Paper start - optimise palette reads
@Override
@@ -49,11 +49,14 @@ public class LinearPalette<T> implements Palette<T>, ca.spottedleaf.moonrise.pat
@Override
public int idFor(T state) {
- for (int i = 0; i < this.size; i++) {
- if (this.values[i] == state) {
+ // DivineMC start - Chunk System Optimizations
+ final T[] values = this.values;
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] == state) {
return i;
}
}
+ // DivineMC end - Chunk System Optimizations
int ix = this.size;
if (ix < this.values.length) {
@@ -67,17 +70,23 @@ public class LinearPalette<T> implements Palette<T>, ca.spottedleaf.moonrise.pat
@Override
public boolean maybeHas(Predicate<T> filter) {
- for (int i = 0; i < this.size; i++) {
- if (filter.test(this.values[i])) {
+ // DivineMC start - Chunk System Optimizations
+ final T[] values = this.values;
+ final int currentSize = this.size;
+
+ for (int i = 0; i < currentSize; i++) {
+ T value = values[i];
+ if (value != null && filter.test(value)) {
return true;
}
}
+ // DivineMC end - Chunk System Optimizations
return false;
}
@Override
- public T valueFor(int id) {
+ public synchronized T valueFor(int id) { // DivineMC - Chunk System Optimizations
if (id >= 0 && id < this.size) {
return this.values[id];
} else {
diff --git a/net/minecraft/world/level/chunk/Palette.java b/net/minecraft/world/level/chunk/Palette.java
index a80b2e9dceea423180a9c390d1970317dff4f1b0..6d9dfc1837dccef2073da180aaaf68b07b04a8e3 100644
--- a/net/minecraft/world/level/chunk/Palette.java
+++ b/net/minecraft/world/level/chunk/Palette.java
@@ -10,6 +10,12 @@ public interface Palette<T> extends ca.spottedleaf.moonrise.patches.fast_palette
boolean maybeHas(Predicate<T> filter);
+ // DivineMC start - Chunk System Optimizations
+ public default boolean maybeHasOrCatch(Predicate<T> filter, T defaultValue) {
+ return this.maybeHas(filter);
+ }
+ // DivineMC end - Chunk System Optimizations
+
T valueFor(int id);
void read(FriendlyByteBuf buffer);
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
index baa006132b1fa3d73fd4a14f6bc747a3957d1a0c..ce41cd702a61d96552567b310cf59b22d9363eeb 100644
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -392,6 +392,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
return this.data.palette.maybeHas(predicate);
}
+ // DivineMC start - Chunk System Optimizations
+ public boolean maybeHasOrCatch(Predicate<T> predicate, @org.jetbrains.annotations.NotNull T defaultValue) {
+ return this.data.palette.maybeHasOrCatch(predicate, defaultValue);
+ }
+ // DivineMC end - Chunk System Optimizations
+
@Override
public PalettedContainer<T> copy() {
return new PalettedContainer<>(this, this.presetValues); // Paper - Anti-Xray - Add preset values
diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java
index aa085d8a78a3fb40a214e4b152ab04d9a409f76f..2aea410b5ba3156cf08f92ffc554ae64c9e90664 100644
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
@@ -46,7 +46,7 @@ public class ProtoChunk extends ChunkAccess {
@Nullable
private volatile LevelLightEngine lightEngine;
private volatile ChunkStatus status = ChunkStatus.EMPTY;
- private final List<CompoundTag> entities = Lists.newArrayList();
+ private final List<CompoundTag> entities = Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System optimization
@Nullable
private CarvingMask carvingMask;
@Nullable
diff --git a/net/minecraft/world/level/chunk/SingleValuePalette.java b/net/minecraft/world/level/chunk/SingleValuePalette.java
index 2ffae24b0cb1a20c7d5a8520f1b5197c2cedea11..c3ec5e5645f680a915c95d833b589b680c82c35d 100644
--- a/net/minecraft/world/level/chunk/SingleValuePalette.java
+++ b/net/minecraft/world/level/chunk/SingleValuePalette.java
@@ -11,7 +11,7 @@ import org.apache.commons.lang3.Validate;
public class SingleValuePalette<T> implements Palette<T>, ca.spottedleaf.moonrise.patches.fast_palette.FastPalette<T> { // Paper - optimise palette reads
private final IdMap<T> registry;
@Nullable
- private T value;
+ private volatile T value; // DivineMC - Chunk System Optimizations
private final PaletteResize<T> resizeHandler;
// Paper start - optimise palette reads
@@ -44,6 +44,7 @@ public class SingleValuePalette<T> implements Palette<T>, ca.spottedleaf.moonris
if (this.value != null && this.value != state) {
return this.resizeHandler.onResize(1, state);
} else {
+ if (state == null) throw new IllegalArgumentException("Null state not allowed"); // DivineMC - Chunk System Optimizations
this.value = state;
// Paper start - optimise palette reads
if (this.rawPalette != null) {
@@ -63,6 +64,19 @@ public class SingleValuePalette<T> implements Palette<T>, ca.spottedleaf.moonris
}
}
+ // DivineMC start - Chunk System Optimizations
+ @Override
+ public boolean maybeHasOrCatch(final Predicate<T> filter, final T defaultValue) {
+ if (this.value == null) {
+ if (defaultValue == null) throw new IllegalArgumentException("Default value for 'maybeHasOrCatch' cannot be null!");
+ this.value = defaultValue;
+ return maybeHas(filter);
+ } else {
+ return filter.test(this.value);
+ }
+ }
+ // DivineMC end - Chunk System Optimizations
+
@Override
public T valueFor(int id) {
if (this.value != null && id == 0) {
diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java
index 27e1edbd8d8ffd80c1a3df17bc47f4a6936619f7..67d48ad11671e72e9dfeafbd64dc27031bd395d5 100644
--- a/net/minecraft/world/level/chunk/storage/IOWorker.java
+++ b/net/minecraft/world/level/chunk/storage/IOWorker.java
@@ -212,7 +212,38 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable {
});
}
+ // DivineMC start - Chunk System optimization
+ private void checkHardLimit() {
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit) {
+ LOGGER.warn("Chunk data cache size exceeded hard limit ({} >= {}), forcing writes to disk (you can increase chunkDataCacheLimit in c2me.toml)", this.pendingWrites.size(), org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit);
+ while (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit * 0.75) {
+ writeResult0();
+ }
+ }
+ }
+
+ private void writeResult0() {
+ java.util.Iterator<java.util.Map.Entry<net.minecraft.world.level.ChunkPos, net.minecraft.world.level.chunk.storage.IOWorker.PendingStore>> iterator = this.pendingWrites.entrySet().iterator();
+ if (iterator.hasNext()) {
+ java.util.Map.Entry<ChunkPos, IOWorker.PendingStore> entry = iterator.next();
+ iterator.remove();
+ this.runStore(entry.getKey(), entry.getValue());
+ }
+ }
+ // DivineMC end - Chunk System optimization
+
private void storePendingChunk() {
+ // DivineMC start - Chunk System optimization
+ if (!this.pendingWrites.isEmpty()) {
+ checkHardLimit();
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) {
+ int writeFrequency = Math.min(1, (this.pendingWrites.size() - (int) org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) / 16);
+ for (int i = 0; i < writeFrequency; i++) {
+ writeResult0();
+ }
+ }
+ }
+ // DivineMC end - Chunk System optimization
Entry<ChunkPos, IOWorker.PendingStore> entry = this.pendingWrites.pollFirstEntry();
if (entry != null) {
this.runStore(entry.getKey(), entry.getValue());
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 8d1174f25e0e90d0533970f4ddd8448442024936..c98cb390bda4b536f97445f228e06aaebcd84609 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -269,7 +269,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
protected RegionFileStorage(RegionStorageInfo info, Path folder, boolean sync) { // Paper - protected
this.folder = folder;
- this.sync = sync;
+ this.sync = Boolean.parseBoolean(System.getProperty("com.ishland.c2me.chunkio.syncDiskWrites", String.valueOf(sync))); // DivineMC - C2ME: sync disk writes
this.info = info;
this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
}
diff --git a/net/minecraft/world/level/levelgen/Aquifer.java b/net/minecraft/world/level/levelgen/Aquifer.java
index c62a15ea4a1bb22e7bcc2fc544acf8a601892029..bc67039f8374ae4e471ca14e0c623e6bf334020f 100644
--- a/net/minecraft/world/level/levelgen/Aquifer.java
+++ b/net/minecraft/world/level/levelgen/Aquifer.java
@@ -85,6 +85,15 @@ public interface Aquifer {
private final int minGridZ;
private final int gridSizeX;
private final int gridSizeZ;
+ // DivineMC start - Chunk System Optimizations
+ private int c2me$dist1;
+ private int c2me$dist2;
+ private int c2me$dist3;
+ private long c2me$pos1;
+ private long c2me$pos2;
+ private long c2me$pos3;
+ private double c2me$mutableDoubleThingy;
+ // DivineMC end - Chunk System Optimizations
private static final int[][] SURFACE_SAMPLING_OFFSETS_IN_CHUNKS = new int[][]{
{0, 0}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {-3, 0}, {-2, 0}, {-1, 0}, {1, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1}
};
@@ -120,6 +129,36 @@ public interface Aquifer {
this.aquiferCache = new Aquifer.FluidStatus[i4];
this.aquiferLocationCache = new long[i4];
Arrays.fill(this.aquiferLocationCache, Long.MAX_VALUE);
+ // DivineMC start - Chunk System Optimizations
+ if (this.aquiferLocationCache.length % (this.gridSizeX * this.gridSizeZ) != 0) {
+ throw new AssertionError("Array length");
+ }
+
+ int sizeY = this.aquiferLocationCache.length / (this.gridSizeX * this.gridSizeZ);
+
+ final RandomSource random = org.bxteam.divinemc.util.RandomUtil.getRandom(this.positionalRandomFactory);
+ // index: y, z, x
+ for (int y = 0; y < sizeY; y++) {
+ for (int z = 0; z < this.gridSizeZ; z++) {
+ for (int x = 0; x < this.gridSizeX; x++) {
+ final int x1 = x + this.minGridX;
+ final int y1 = y + this.minGridY;
+ final int z1 = z + this.minGridZ;
+ org.bxteam.divinemc.util.RandomUtil.derive(this.positionalRandomFactory, random, x1, y1, z1);
+ int x2 = x1 * 16 + random.nextInt(10);
+ int y2 = y1 * 12 + random.nextInt(9);
+ int z2 = z1 * 16 + random.nextInt(10);
+ int index = this.getIndex(x1, y1, z1);
+ this.aquiferLocationCache[index] = BlockPos.asLong(x2, y2, z2);
+ }
+ }
+ }
+ for (long blockPosition : this.aquiferLocationCache) {
+ if (blockPosition == Long.MAX_VALUE) {
+ throw new AssertionError("Array initialization");
+ }
+ }
+ // DivineMC end - Chunk System Optimizations
}
private int getIndex(int gridX, int gridY, int gridZ) {
@@ -132,140 +171,24 @@ public interface Aquifer {
@Nullable
@Override
public BlockState computeSubstance(DensityFunction.FunctionContext context, double substance) {
+ // DivineMC start - Chunk System Optimizations
int i = context.blockX();
- int i1 = context.blockY();
- int i2 = context.blockZ();
+ int j = context.blockY();
+ int k = context.blockZ();
if (substance > 0.0) {
this.shouldScheduleFluidUpdate = false;
return null;
} else {
- Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(i, i1, i2);
- if (fluidStatus.at(i1).is(Blocks.LAVA)) {
+ Aquifer.FluidStatus fluidLevel = this.globalFluidPicker.computeFluid(i, j, k);
+ if (fluidLevel.at(j).is(Blocks.LAVA)) {
this.shouldScheduleFluidUpdate = false;
return Blocks.LAVA.defaultBlockState();
} else {
- int i3 = Math.floorDiv(i - 5, 16);
- int i4 = Math.floorDiv(i1 + 1, 12);
- int i5 = Math.floorDiv(i2 - 5, 16);
- int i6 = Integer.MAX_VALUE;
- int i7 = Integer.MAX_VALUE;
- int i8 = Integer.MAX_VALUE;
- int i9 = Integer.MAX_VALUE;
- long l = 0L;
- long l1 = 0L;
- long l2 = 0L;
- long l3 = 0L;
-
- for (int i10 = 0; i10 <= 1; i10++) {
- for (int i11 = -1; i11 <= 1; i11++) {
- for (int i12 = 0; i12 <= 1; i12++) {
- int i13 = i3 + i10;
- int i14 = i4 + i11;
- int i15 = i5 + i12;
- int index = this.getIndex(i13, i14, i15);
- long l4 = this.aquiferLocationCache[index];
- long l5;
- if (l4 != Long.MAX_VALUE) {
- l5 = l4;
- } else {
- RandomSource randomSource = this.positionalRandomFactory.at(i13, i14, i15);
- l5 = BlockPos.asLong(
- i13 * 16 + randomSource.nextInt(10), i14 * 12 + randomSource.nextInt(9), i15 * 16 + randomSource.nextInt(10)
- );
- this.aquiferLocationCache[index] = l5;
- }
-
- int i16 = BlockPos.getX(l5) - i;
- int i17 = BlockPos.getY(l5) - i1;
- int i18 = BlockPos.getZ(l5) - i2;
- int i19 = i16 * i16 + i17 * i17 + i18 * i18;
- if (i6 >= i19) {
- l3 = l2;
- l2 = l1;
- l1 = l;
- l = l5;
- i9 = i8;
- i8 = i7;
- i7 = i6;
- i6 = i19;
- } else if (i7 >= i19) {
- l3 = l2;
- l2 = l1;
- l1 = l5;
- i9 = i8;
- i8 = i7;
- i7 = i19;
- } else if (i8 >= i19) {
- l3 = l2;
- l2 = l5;
- i9 = i8;
- i8 = i19;
- } else if (i9 >= i19) {
- l3 = l5;
- i9 = i19;
- }
- }
- }
- }
-
- Aquifer.FluidStatus aquiferStatus = this.getAquiferStatus(l);
- double d = similarity(i6, i7);
- BlockState blockState = aquiferStatus.at(i1);
- if (d <= 0.0) {
- if (d >= FLOWING_UPDATE_SIMULARITY) {
- Aquifer.FluidStatus aquiferStatus1 = this.getAquiferStatus(l1);
- this.shouldScheduleFluidUpdate = !aquiferStatus.equals(aquiferStatus1);
- } else {
- this.shouldScheduleFluidUpdate = false;
- }
-
- return blockState;
- } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, i1 - 1, i2).at(i1 - 1).is(Blocks.LAVA)) {
- this.shouldScheduleFluidUpdate = true;
- return blockState;
- } else {
- MutableDouble mutableDouble = new MutableDouble(Double.NaN);
- Aquifer.FluidStatus aquiferStatus2 = this.getAquiferStatus(l1);
- double d1 = d * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus2);
- if (substance + d1 > 0.0) {
- this.shouldScheduleFluidUpdate = false;
- return null;
- } else {
- Aquifer.FluidStatus aquiferStatus3 = this.getAquiferStatus(l2);
- double d2 = similarity(i6, i8);
- if (d2 > 0.0) {
- double d3 = d * d2 * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus3);
- if (substance + d3 > 0.0) {
- this.shouldScheduleFluidUpdate = false;
- return null;
- }
- }
-
- double d3 = similarity(i7, i8);
- if (d3 > 0.0) {
- double d4 = d * d3 * this.calculatePressure(context, mutableDouble, aquiferStatus2, aquiferStatus3);
- if (substance + d4 > 0.0) {
- this.shouldScheduleFluidUpdate = false;
- return null;
- }
- }
-
- boolean flag = !aquiferStatus.equals(aquiferStatus2);
- boolean flag1 = d3 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus2.equals(aquiferStatus3);
- boolean flag2 = d2 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus.equals(aquiferStatus3);
- if (!flag && !flag1 && !flag2) {
- this.shouldScheduleFluidUpdate = d2 >= FLOWING_UPDATE_SIMULARITY
- && similarity(i6, i9) >= FLOWING_UPDATE_SIMULARITY
- && !aquiferStatus.equals(this.getAquiferStatus(l3));
- } else {
- this.shouldScheduleFluidUpdate = true;
- }
-
- return blockState;
- }
- }
+ aquiferExtracted$refreshDistPosIdx(i, j, k);
+ return aquiferExtracted$applyPost(context, substance, j, i, k);
}
}
+ // DivineMC end - Chunk System Optimizations
}
@Override
@@ -278,65 +201,28 @@ public interface Aquifer {
return 1.0 - Math.abs(secondDistance - firstDistance) / 25.0;
}
+ // DivineMC start - Chunk System Optimizations
private double calculatePressure(
- DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus firstFluid, Aquifer.FluidStatus secondFluid
+ DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 // DivineMC - rename args
) {
int i = context.blockY();
- BlockState blockState = firstFluid.at(i);
- BlockState blockState1 = secondFluid.at(i);
- if ((!blockState.is(Blocks.LAVA) || !blockState1.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState1.is(Blocks.LAVA))) {
- int abs = Math.abs(firstFluid.fluidLevel - secondFluid.fluidLevel);
+ BlockState blockState = fluidLevel.at(i);
+ BlockState blockState2 = fluidLevel2.at(i);
+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) {
+ int abs = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel);
if (abs == 0) {
return 0.0;
} else {
- double d = 0.5 * (firstFluid.fluidLevel + secondFluid.fluidLevel);
- double d1 = i + 0.5 - d;
- double d2 = abs / 2.0;
- double d3 = 0.0;
- double d4 = 2.5;
- double d5 = 1.5;
- double d6 = 3.0;
- double d7 = 10.0;
- double d8 = 3.0;
- double d9 = d2 - Math.abs(d1);
- double d11;
- if (d1 > 0.0) {
- double d10 = 0.0 + d9;
- if (d10 > 0.0) {
- d11 = d10 / 1.5;
- } else {
- d11 = d10 / 2.5;
- }
- } else {
- double d10 = 3.0 + d9;
- if (d10 > 0.0) {
- d11 = d10 / 3.0;
- } else {
- d11 = d10 / 10.0;
- }
- }
-
- double d10x = 2.0;
- double d12;
- if (!(d11 < -2.0) && !(d11 > 2.0)) {
- double value = substance.getValue();
- if (Double.isNaN(value)) {
- double d13 = this.barrierNoise.compute(context);
- substance.setValue(d13);
- d12 = d13;
- } else {
- d12 = value;
- }
- } else {
- d12 = 0.0;
- }
+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel);
+ final double q = aquiferExtracted$getQ(i, d, abs);
- return 2.0 * (d12 + d11);
+ return aquiferExtracted$postCalculateDensity(context, substance, q);
}
} else {
return 2.0;
}
}
+ // DivineMC end - Chunk System Optimizations
private int gridX(int x) {
return Math.floorDiv(x, 16);
@@ -350,23 +236,25 @@ public interface Aquifer {
return Math.floorDiv(z, 16);
}
- private Aquifer.FluidStatus getAquiferStatus(long packedPos) {
- int x = BlockPos.getX(packedPos);
- int y = BlockPos.getY(packedPos);
- int z = BlockPos.getZ(packedPos);
- int i = this.gridX(x);
- int i1 = this.gridY(y);
- int i2 = this.gridZ(z);
- int index = this.getIndex(i, i1, i2);
- Aquifer.FluidStatus fluidStatus = this.aquiferCache[index];
- if (fluidStatus != null) {
- return fluidStatus;
+ // DivineMC start - Chunk System Optimizations
+ private Aquifer.FluidStatus getAquiferStatus(long pos) {
+ int i = BlockPos.getX(pos);
+ int j = BlockPos.getY(pos);
+ int k = BlockPos.getZ(pos);
+ int l = i >> 4; // C2ME - inline: floorDiv(i, 16)
+ int m = Math.floorDiv(j, 12); // C2ME - inline
+ int n = k >> 4; // C2ME - inline: floorDiv(k, 16)
+ int o = this.getIndex(l, m, n);
+ Aquifer.FluidStatus fluidLevel = this.aquiferCache[o];
+ if (fluidLevel != null) {
+ return fluidLevel;
} else {
- Aquifer.FluidStatus fluidStatus1 = this.computeFluid(x, y, z);
- this.aquiferCache[index] = fluidStatus1;
- return fluidStatus1;
+ Aquifer.FluidStatus fluidLevel2 = this.computeFluid(i, j, k);
+ this.aquiferCache[o] = fluidLevel2;
+ return fluidLevel2;
}
}
+ // DivineMC end - Chunk System Optimizations
private Aquifer.FluidStatus computeFluid(int x, int y, int z) {
Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(x, y, z);
@@ -407,22 +295,21 @@ public interface Aquifer {
}
private int computeSurfaceLevel(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int maxSurfaceLevel, boolean fluidPresent) {
- DensityFunction.SinglePointContext singlePointContext = new DensityFunction.SinglePointContext(x, y, z);
+ // DivineMC start - Chunk System Optimizations
+ DensityFunction.SinglePointContext unblendedNoisePos = new DensityFunction.SinglePointContext(x, y, z);
double d;
double d1;
- if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, singlePointContext)) {
+ if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, unblendedNoisePos)) {
d = -1.0;
d1 = -1.0;
} else {
int i = maxSurfaceLevel + 8 - y;
- int i1 = 64;
- double d2 = fluidPresent ? Mth.clampedMap((double)i, 0.0, 64.0, 1.0, 0.0) : 0.0;
- double d3 = Mth.clamp(this.fluidLevelFloodednessNoise.compute(singlePointContext), -1.0, 1.0);
- double d4 = Mth.map(d2, 1.0, 0.0, -0.3, 0.8);
- double d5 = Mth.map(d2, 1.0, 0.0, -0.8, 0.4);
- d = d3 - d5;
- d1 = d3 - d4;
+ double f = fluidPresent ? Mth.clampedLerp(1.0, 0.0, ((double) i) / 64.0) : 0.0; // inline
+ double g = Mth.clamp(this.fluidLevelFloodednessNoise.compute(unblendedNoisePos), -1.0, 1.0);
+ d = g + 0.8 + (f - 1.0) * 1.2; // inline
+ d1 = g + 0.3 + (f - 1.0) * 1.1; // inline
}
+ // DivineMC end - Chunk System Optimizations
int i;
if (d1 > 0.0) {
@@ -453,12 +340,12 @@ public interface Aquifer {
private BlockState computeFluidType(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int surfaceLevel) {
BlockState blockState = fluidStatus.fluidType;
if (surfaceLevel <= -10 && surfaceLevel != DimensionType.WAY_BELOW_MIN_Y && fluidStatus.fluidType != Blocks.LAVA.defaultBlockState()) {
- int i = 64;
- int i1 = 40;
- int i2 = Math.floorDiv(x, 64);
- int i3 = Math.floorDiv(y, 40);
- int i4 = Math.floorDiv(z, 64);
- double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(i2, i3, i4));
+ // DivineMC start - Chunk System Optimizations
+ int k = x >> 6;
+ int l = Math.floorDiv(y, 40);
+ int m = z >> 6;
+ double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(k, l, m));
+ // DivineMC end - Chunk System Optimizations
if (Math.abs(d) > 0.3) {
blockState = Blocks.LAVA.defaultBlockState();
}
@@ -466,5 +353,183 @@ public interface Aquifer {
return blockState;
}
+
+ // DivineMC start - Chunk System Optimizations
+ private @org.jetbrains.annotations.Nullable BlockState aquiferExtracted$applyPost(DensityFunction.FunctionContext pos, double density, int j, int i, int k) {
+ Aquifer.FluidStatus fluidLevel2 = this.getAquiferStatus(this.c2me$pos1);
+ double d = similarity(this.c2me$dist1, this.c2me$dist2);
+ BlockState blockState = fluidLevel2.at(j);
+ if (d <= 0.0) {
+ this.shouldScheduleFluidUpdate = d >= FLOWING_UPDATE_SIMULARITY;
+ return blockState;
+ } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, j - 1, k).at(j - 1).is(Blocks.LAVA)) {
+ this.shouldScheduleFluidUpdate = true;
+ return blockState;
+ } else {
+ this.c2me$mutableDoubleThingy = Double.NaN;
+ Aquifer.FluidStatus fluidLevel3 = this.getAquiferStatus(this.c2me$pos2);
+ double e = d * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel3);
+ if (density + e > 0.0) {
+ this.shouldScheduleFluidUpdate = false;
+ return null;
+ } else {
+ return aquiferExtracted$getFinalBlockState(pos, density, d, fluidLevel2, fluidLevel3, blockState);
+ }
+ }
+ }
+
+ private BlockState aquiferExtracted$getFinalBlockState(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, Aquifer.FluidStatus fluidLevel3, BlockState blockState) {
+ Aquifer.FluidStatus fluidLevel4 = this.getAquiferStatus(this.c2me$pos3);
+ double f = similarity(this.c2me$dist1, this.c2me$dist3);
+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel2, f, fluidLevel4)) return null;
+
+ double g = similarity(this.c2me$dist2, this.c2me$dist3);
+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel3, g, fluidLevel4)) return null;
+
+ this.shouldScheduleFluidUpdate = true;
+ return blockState;
+ }
+
+ private boolean aquiferExtracted$extractedCheckFG(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, double f, Aquifer.FluidStatus fluidLevel4) {
+ if (f > 0.0) {
+ double g = d * f * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel4);
+ if (density + g > 0.0) {
+ this.shouldScheduleFluidUpdate = false;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void aquiferExtracted$refreshDistPosIdx(int x, int y, int z) {
+ int gx = (x - 5) >> 4;
+ int gy = Math.floorDiv(y + 1, 12);
+ int gz = (z - 5) >> 4;
+ int dist1 = Integer.MAX_VALUE;
+ int dist2 = Integer.MAX_VALUE;
+ int dist3 = Integer.MAX_VALUE;
+ long pos1 = 0;
+ long pos2 = 0;
+ long pos3 = 0;
+
+ for (int offY = -1; offY <= 1; ++offY) {
+ for (int offZ = 0; offZ <= 1; ++offZ) {
+ for (int offX = 0; offX <= 1; ++offX) {
+ int posIdx = this.getIndex(gx + offX, gy + offY, gz + offZ);
+
+ long position = this.aquiferLocationCache[posIdx];
+
+ int dx = BlockPos.getX(position) - x;
+ int dy = BlockPos.getY(position) - y;
+ int dz = BlockPos.getZ(position) - z;
+ int dist = dx * dx + dy * dy + dz * dz;
+
+ if (dist3 >= dist) {
+ pos3 = position;
+ dist3 = dist;
+ }
+ if (dist2 >= dist) {
+ pos3 = pos2;
+ dist3 = dist2;
+ pos2 = position;
+ dist2 = dist;
+ }
+ if (dist1 >= dist) {
+ pos2 = pos1;
+ dist2 = dist1;
+ pos1 = position;
+ dist1 = dist;
+ }
+ }
+ }
+ }
+
+ this.c2me$dist1 = dist1;
+ this.c2me$dist2 = dist2;
+ this.c2me$dist3 = dist3;
+ this.c2me$pos1 = pos1;
+ this.c2me$pos2 = pos2;
+ this.c2me$pos3 = pos3;
+ }
+
+ private double c2me$calculateDensityModified(
+ DensityFunction.FunctionContext pos, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2
+ ) {
+ int i = pos.blockY();
+ BlockState blockState = fluidLevel.at(i);
+ BlockState blockState2 = fluidLevel2.at(i);
+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) {
+ int j = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel);
+ if (j == 0) {
+ return 0.0;
+ } else {
+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel);
+ final double q = aquiferExtracted$getQ(i, d, j);
+
+ return aquiferExtracted$postCalculateDensityModified(pos, q);
+ }
+ } else {
+ return 2.0;
+ }
+ }
+
+ private double aquiferExtracted$postCalculateDensity(DensityFunction.FunctionContext pos, MutableDouble mutableDouble, double q) {
+ double r;
+ if (!(q < -2.0) && !(q > 2.0)) {
+ double s = mutableDouble.getValue();
+ if (Double.isNaN(s)) {
+ double t = this.barrierNoise.compute(pos);
+ mutableDouble.setValue(t);
+ r = t;
+ } else {
+ r = s;
+ }
+ } else {
+ r = 0.0;
+ }
+
+ return 2.0 * (r + q);
+ }
+
+ private double aquiferExtracted$postCalculateDensityModified(DensityFunction.FunctionContext pos, double q) {
+ double r;
+ if (!(q < -2.0) && !(q > 2.0)) {
+ double s = this.c2me$mutableDoubleThingy;
+ if (Double.isNaN(s)) {
+ double t = this.barrierNoise.compute(pos);
+ this.c2me$mutableDoubleThingy = t;
+ r = t;
+ } else {
+ r = s;
+ }
+ } else {
+ r = 0.0;
+ }
+
+ return 2.0 * (r + q);
+ }
+
+ private static double aquiferExtracted$getQ(double i, double d, double j) {
+ double e = i + 0.5 - d;
+ double f = j / 2.0;
+ double o = f - Math.abs(e);
+ double q;
+ if (e > 0.0) {
+ if (o > 0.0) {
+ q = o / 1.5;
+ } else {
+ q = o / 2.5;
+ }
+ } else {
+ double p = 3.0 + o;
+ if (p > 0.0) {
+ q = p / 3.0;
+ } else {
+ q = p / 10.0;
+ }
+ }
+ return q;
+ }
+ // DivineMC end - Chunk System Optimizations
}
}
diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java
index 74d8202b5c9bb2a3ee832be70f95c0b5cbecb460..4c11b822fa65388c1d8d9aaa7fd70200d0eaa418 100644
--- a/net/minecraft/world/level/levelgen/Beardifier.java
+++ b/net/minecraft/world/level/levelgen/Beardifier.java
@@ -29,6 +29,17 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
});
private final ObjectListIterator<Beardifier.Rigid> pieceIterator;
private final ObjectListIterator<JigsawJunction> junctionIterator;
+ // DivineMC start - Chunk System Optimizations
+ private Beardifier.Rigid[] c2me$pieceArray;
+ private JigsawJunction[] c2me$junctionArray;
+
+ private void c2me$initArrays() {
+ this.c2me$pieceArray = com.google.common.collect.Iterators.toArray(this.pieceIterator, Beardifier.Rigid.class);
+ this.pieceIterator.back(Integer.MAX_VALUE);
+ this.c2me$junctionArray = com.google.common.collect.Iterators.toArray(this.junctionIterator, JigsawJunction.class);
+ this.junctionIterator.back(Integer.MAX_VALUE);
+ }
+ // DivineMC end - Chunk System Optimizations
public static Beardifier forStructuresInChunk(StructureManager structureManager, ChunkPos chunkPos) {
int minBlockX = chunkPos.getMinBlockX();
@@ -75,50 +86,44 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
this.junctionIterator = junctionIterator;
}
+ // DivineMC start - Chunk System Optimizations
@Override
public double compute(DensityFunction.FunctionContext context) {
+ if (this.c2me$pieceArray == null || this.c2me$junctionArray == null) {
+ this.c2me$initArrays();
+ }
int i = context.blockX();
- int i1 = context.blockY();
- int i2 = context.blockZ();
+ int j = context.blockY();
+ int k = context.blockZ();
double d = 0.0;
- while (this.pieceIterator.hasNext()) {
- Beardifier.Rigid rigid = this.pieceIterator.next();
- BoundingBox boundingBox = rigid.box();
- int groundLevelDelta = rigid.groundLevelDelta();
- int max = Math.max(0, Math.max(boundingBox.minX() - i, i - boundingBox.maxX()));
- int max1 = Math.max(0, Math.max(boundingBox.minZ() - i2, i2 - boundingBox.maxZ()));
- int i3 = boundingBox.minY() + groundLevelDelta;
- int i4 = i1 - i3;
-
- int i5 = switch (rigid.terrainAdjustment()) {
- case NONE -> 0;
- case BURY, BEARD_THIN -> i4;
- case BEARD_BOX -> Math.max(0, Math.max(i3 - i1, i1 - boundingBox.maxY()));
- case ENCAPSULATE -> Math.max(0, Math.max(boundingBox.minY() - i1, i1 - boundingBox.maxY()));
- };
+ for (Beardifier.Rigid piece : this.c2me$pieceArray) {
+ BoundingBox blockBox = piece.box();
+ int l = piece.groundLevelDelta();
+ int m = Math.max(0, Math.max(blockBox.minX() - i, i - blockBox.maxX()));
+ int n = Math.max(0, Math.max(blockBox.minZ() - k, k - blockBox.maxZ()));
+ int o = blockBox.minY() + l;
+ int p = j - o;
- d += switch (rigid.terrainAdjustment()) {
+ d += switch (piece.terrainAdjustment()) { // 2 switch statement merged
case NONE -> 0.0;
- case BURY -> getBuryContribution(max, i5 / 2.0, max1);
- case BEARD_THIN, BEARD_BOX -> getBeardContribution(max, i5, max1, i4) * 0.8;
- case ENCAPSULATE -> getBuryContribution(max / 2.0, i5 / 2.0, max1 / 2.0) * 0.8;
+ case BURY -> getBuryContribution(m, (double)p / 2.0, n);
+ case BEARD_THIN -> getBeardContribution(m, p, n, p) * 0.8;
+ case BEARD_BOX -> getBeardContribution(m, Math.max(0, Math.max(o - j, j - blockBox.maxY())), n, p) * 0.8;
+ case ENCAPSULATE -> getBuryContribution((double)m / 2.0, (double)Math.max(0, Math.max(blockBox.minY() - j, j - blockBox.maxY())) / 2.0, (double)n / 2.0) * 0.8;
};
}
- this.pieceIterator.back(Integer.MAX_VALUE);
-
- while (this.junctionIterator.hasNext()) {
- JigsawJunction jigsawJunction = this.junctionIterator.next();
- int i6 = i - jigsawJunction.getSourceX();
- int groundLevelDelta = i1 - jigsawJunction.getSourceGroundY();
- int max = i2 - jigsawJunction.getSourceZ();
- d += getBeardContribution(i6, groundLevelDelta, max, groundLevelDelta) * 0.4;
+ for (JigsawJunction jigsawJunction : this.c2me$junctionArray) {
+ int r = i - jigsawJunction.getSourceX();
+ int l = j - jigsawJunction.getSourceGroundY();
+ int m = k - jigsawJunction.getSourceZ();
+ d += getBeardContribution(r, l, m, l) * 0.4;
}
- this.junctionIterator.back(Integer.MAX_VALUE);
return d;
}
+ // DivineMC end - Chunk System Optimizations
@Override
public double minValue() {
@@ -131,8 +136,14 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
}
private static double getBuryContribution(double x, double y, double z) {
- double len = Mth.length(x, y, z);
- return Mth.clampedMap(len, 0.0, 6.0, 1.0, 0.0);
+ // DivineMC start - Chunk System Optimizations
+ double d = Math.sqrt(x * x + y * y + z * z);
+ if (d > 6.0) {
+ return 0.0;
+ } else {
+ return 1.0 - d / 6.0;
+ }
+ // DivineMC end - Chunk System Optimizations
}
private static double getBeardContribution(int x, int y, int z, int height) {
diff --git a/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java b/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java
index 3379c3893227d42bb54f3a94e697a9851d279605..06b1ea5fd3b9b1c6bace8be859aabff7590481ce 100644
--- a/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java
+++ b/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java
@@ -74,6 +74,7 @@ public final class BelowZeroRetrogen {
}
public void applyBedrockMask(ProtoChunk chunk) {
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.smoothBedrockLayer) return; // DivineMC - Smooth bedrock layer
LevelHeightAccessor heightAccessorForGeneration = chunk.getHeightAccessorForGeneration();
int minY = heightAccessorForGeneration.getMinY();
int maxY = heightAccessorForGeneration.getMaxY();
diff --git a/net/minecraft/world/level/levelgen/Column.java b/net/minecraft/world/level/levelgen/Column.java
index 4a1df0f8578c9ee5538ed8c94d3c7911f36f83b8..716c2c69843234cdef34339d859babc95ffe318c 100644
--- a/net/minecraft/world/level/levelgen/Column.java
+++ b/net/minecraft/world/level/levelgen/Column.java
@@ -156,7 +156,7 @@ public abstract class Column {
}
public int height() {
- return this.ceiling - this.floor - 1;
+ return net.minecraft.util.Mth.abs(this.ceiling - this.floor - 1); // DivineMC - Chunk System optimization
}
@Override
diff --git a/net/minecraft/world/level/levelgen/LegacyRandomSource.java b/net/minecraft/world/level/levelgen/LegacyRandomSource.java
index c67168517774a0ad9ca43422a79ef14a8ea0c2e8..026dfbbb6c3fd5cd274dcbf721e5cf3af889e3d9 100644
--- a/net/minecraft/world/level/levelgen/LegacyRandomSource.java
+++ b/net/minecraft/world/level/levelgen/LegacyRandomSource.java
@@ -53,13 +53,7 @@ public class LegacyRandomSource implements BitRandomSource {
return this.gaussianSource.nextGaussian();
}
- public static class LegacyPositionalRandomFactory implements PositionalRandomFactory {
- private final long seed;
-
- public LegacyPositionalRandomFactory(long seed) {
- this.seed = seed;
- }
-
+ public record LegacyPositionalRandomFactory(long seed) implements PositionalRandomFactory { // DivineMC - make record
@Override
public RandomSource at(int x, int y, int z) {
long seed = Mth.getSeed(x, y, z);
diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
index 65728ef17e63d71833677fdcbd5bb90794b4822b..eb61a3c995afe5af1cd385826e882acf441e2785 100644
--- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
+++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
@@ -65,11 +65,13 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
}
private static Aquifer.FluidPicker createFluidPicker(NoiseGeneratorSettings settings) {
- Aquifer.FluidStatus fluidStatus = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState());
- int seaLevel = settings.seaLevel();
- Aquifer.FluidStatus fluidStatus1 = new Aquifer.FluidStatus(seaLevel, settings.defaultFluid());
- Aquifer.FluidStatus fluidStatus2 = new Aquifer.FluidStatus(DimensionType.MIN_Y * 2, Blocks.AIR.defaultBlockState());
- return (x, y, z) -> y < Math.min(-54, seaLevel) ? fluidStatus : fluidStatus1;
+ // DivineMC start - Chunk System Optimizations
+ Aquifer.FluidStatus fluidLevel = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState());
+ int i = settings.seaLevel();
+ Aquifer.FluidStatus fluidLevel2 = new Aquifer.FluidStatus(i, settings.defaultFluid());
+ final int min = Math.min(-54, i);
+ return (j, k, lx) -> k < min ? fluidLevel : fluidLevel2;
+ // DivineMC end - Chunk System Optimizations
}
@Override
@@ -294,30 +296,32 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
public CompletableFuture<ChunkAccess> fillFromNoise(Blender blender, RandomState randomState, StructureManager structureManager, ChunkAccess chunk) {
NoiseSettings noiseSettings = this.settings.value().noiseSettings().clampToHeightAccessor(chunk.getHeightAccessorForGeneration());
int minY = noiseSettings.minY();
- int i = Mth.floorDiv(minY, noiseSettings.getCellHeight());
- int i1 = Mth.floorDiv(noiseSettings.height(), noiseSettings.getCellHeight());
- return i1 <= 0 ? CompletableFuture.completedFuture(chunk) : CompletableFuture.supplyAsync(() -> {
- int sectionIndex = chunk.getSectionIndex(i1 * noiseSettings.getCellHeight() - 1 + minY);
- int sectionIndex1 = chunk.getSectionIndex(minY);
- Set<LevelChunkSection> set = Sets.newHashSet();
-
- for (int i2 = sectionIndex; i2 >= sectionIndex1; i2--) {
- LevelChunkSection section = chunk.getSection(i2);
- section.acquire();
- set.add(section);
- }
+ // DivineMC start - Optimize noise fill
+ int minYDiv = Mth.floorDiv(minY, noiseSettings.getCellHeight());
+ int cellHeightDiv = Mth.floorDiv(noiseSettings.height(), noiseSettings.getCellHeight());
- ChunkAccess var20;
- try {
- var20 = this.doFill(blender, structureManager, randomState, chunk, i, i1);
- } finally {
- for (LevelChunkSection levelChunkSection1 : set) {
- levelChunkSection1.release();
- }
+ if (cellHeightDiv <= 0) {
+ return CompletableFuture.completedFuture(chunk);
+ }
+
+ try {
+ int startIndex = chunk.getSectionIndex(cellHeightDiv * noiseSettings.getCellHeight() - 1 + minY);
+ int minYIndex = chunk.getSectionIndex(minY);
+ LevelChunkSection[] sections = chunk.getSections();
+
+ for (int i = startIndex; i >= minYIndex; --i) {
+ sections[i].acquire();
}
- return var20;
- }, Runnable::run); // Paper - rewrite chunk system
+ ChunkAccess access = this.doFill(blender, structureManager, randomState, chunk, minYDiv, cellHeightDiv);
+ for (int i = startIndex; i >= minYIndex; --i) {
+ sections[i].release();
+ }
+ return CompletableFuture.completedFuture(access);
+ } catch (Throwable throwable) {
+ throw new RuntimeException("Unexpected error when running noise fill", throwable);
+ }
+ // DivineMC end - Optimize noise fill
}
private ChunkAccess doFill(Blender blender, StructureManager structureManager, RandomState random, ChunkAccess chunk, int minCellY, int cellCountY) {
@@ -375,7 +379,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
interpolatedState = this.debugPreliminarySurfaceLevel(noiseChunk, i10, i7, i13, interpolatedState);
if (interpolatedState != AIR && !SharedConstants.debugVoidTerrain(chunk.getPos())) {
- section.setBlockState(i11, i8, i14, interpolatedState, false);
+ optimizedBlockSetOp(section, i11, i8, i14, interpolatedState, false); // DivineMC - Optimize noise fill
heightmapUnprimed.update(i11, i7, i14, interpolatedState);
heightmapUnprimed1.update(i11, i7, i14, interpolatedState);
if (aquifer.shouldScheduleFluidUpdate() && !interpolatedState.getFluidState().isEmpty()) {
@@ -396,6 +400,26 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
return chunk;
}
+ // DivineMC start - Optimize noise fill
+ private void optimizedBlockSetOp(@org.jetbrains.annotations.NotNull LevelChunkSection chunkSection, int chunkSectionBlockPosX, int chunkSectionBlockPosY, int chunkSectionBlockPosZ, @org.jetbrains.annotations.NotNull BlockState blockState, boolean lock) {
+ chunkSection.nonEmptyBlockCount += 1;
+
+ if (!blockState.getFluidState().isEmpty()) {
+ chunkSection.tickingFluidCount += 1;
+ }
+
+ if (blockState.isRandomlyTicking()) {
+ chunkSection.tickingBlockCount += 1;
+ }
+
+ var blockStateId = chunkSection.states.data.palette.idFor(blockState);
+ chunkSection.states.data.storage().set(
+ chunkSection.states.strategy.getIndex(chunkSectionBlockPosX, chunkSectionBlockPosY,
+ chunkSectionBlockPosZ
+ ), blockStateId);
+ }
+ // DivineMC end - Optimize noise fill
+
private BlockState debugPreliminarySurfaceLevel(NoiseChunk chunk, int x, int y, int z, BlockState state) {
return state;
}
diff --git a/net/minecraft/world/level/levelgen/NoiseSettings.java b/net/minecraft/world/level/levelgen/NoiseSettings.java
index 4cf3a364595ba5f81f741295695cb9a449bdf672..44df2ac0bd972c4d97fc89cd0c2d2d83480ca3e1 100644
--- a/net/minecraft/world/level/levelgen/NoiseSettings.java
+++ b/net/minecraft/world/level/levelgen/NoiseSettings.java
@@ -8,7 +8,7 @@ import net.minecraft.core.QuartPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.dimension.DimensionType;
-public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) {
+public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical, int horizontalCellBlockCount, int verticalCellBlockCount) { // DivineMC - NoiseSettings optimizations
public static final Codec<NoiseSettings> CODEC = RecordCodecBuilder.<NoiseSettings>create(
instance -> instance.group(
Codec.intRange(DimensionType.MIN_Y, DimensionType.MAX_Y).fieldOf("min_y").forGetter(NoiseSettings::minY),
@@ -16,7 +16,10 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n
Codec.intRange(1, 4).fieldOf("size_horizontal").forGetter(NoiseSettings::noiseSizeHorizontal),
Codec.intRange(1, 4).fieldOf("size_vertical").forGetter(NoiseSettings::noiseSizeVertical)
)
- .apply(instance, NoiseSettings::new)
+ // DivineMC start - NoiseSettings optimizations
+ .apply(instance, (Integer minY1, Integer height1, Integer noiseSizeHorizontal1, Integer noiseSizeVertical1) -> new NoiseSettings(minY1, height1, noiseSizeHorizontal1, noiseSizeVertical1,
+ QuartPos.toBlock(noiseSizeHorizontal1), QuartPos.toBlock(noiseSizeVertical1)))
+ // DivineMC end - NoiseSettings optimizations
)
.comapFlatMap(NoiseSettings::guardY, Function.identity());
protected static final NoiseSettings OVERWORLD_NOISE_SETTINGS = create(-64, 384, 1, 2);
@@ -36,7 +39,7 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n
}
public static NoiseSettings create(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) {
- NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical);
+ NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical, QuartPos.toBlock(noiseSizeHorizontal), QuartPos.toBlock(noiseSizeVertical)); // DivineMC - NoiseSettings optimizations
guardY(noiseSettings).error().ifPresent(error -> {
throw new IllegalStateException(error.message());
});
@@ -44,16 +47,16 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n
}
public int getCellHeight() {
- return QuartPos.toBlock(this.noiseSizeVertical());
+ return verticalCellBlockCount(); // DivineMC - NoiseSettings optimizations
}
public int getCellWidth() {
- return QuartPos.toBlock(this.noiseSizeHorizontal());
+ return horizontalCellBlockCount(); // DivineMC - NoiseSettings optimizations
}
public NoiseSettings clampToHeightAccessor(LevelHeightAccessor heightAccessor) {
int max = Math.max(this.minY, heightAccessor.getMinY());
int i = Math.min(this.minY + this.height, heightAccessor.getMaxY() + 1) - max;
- return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical);
+ return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical, QuartPos.toBlock(this.noiseSizeHorizontal), QuartPos.toBlock(this.noiseSizeVertical)); // DivineMC - NoiseSettings optimizations
}
}
diff --git a/net/minecraft/world/level/levelgen/SurfaceRules.java b/net/minecraft/world/level/levelgen/SurfaceRules.java
index 32757c6847cf77862a2f1b38cc53e7166e6be492..92c7aa344d00067f52829f8d97a6ee219e6c2771 100644
--- a/net/minecraft/world/level/levelgen/SurfaceRules.java
+++ b/net/minecraft/world/level/levelgen/SurfaceRules.java
@@ -185,7 +185,7 @@ public class SurfaceRules {
@Override
protected boolean compute() {
- return this.context.biome.get().is(BiomeConditionSource.this.biomeNameTest);
+ return this.context.biome.is(BiomeConditionSource.this.biomeNameTest); // DivineMC - Chunk System Optimizations
}
}
@@ -281,7 +281,7 @@ public class SurfaceRules {
private int minSurfaceLevel;
long lastUpdateY = -9223372036854775807L;
final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
- Supplier<Holder<Biome>> biome;
+ Holder<Biome> biome; // DivineMC - Chunk System Optimizations
public int blockY;
int waterHeight;
int stoneDepthBelow;
@@ -314,7 +314,10 @@ public class SurfaceRules {
protected void updateY(int stoneDepthAbove, int stoneDepthBelow, int waterHeight, int blockX, int blockY, int blockZ) {
this.lastUpdateY++;
- this.biome = Suppliers.memoize(() -> this.biomeGetter.apply(this.pos.set(blockX, blockY, blockZ)));
+ // DivineMC start - Chunk System Optimizations
+ this.pos.set(blockX, blockY, blockZ);
+ this.biome = this.biomeGetter.apply(this.pos);
+ // DivineMC end - Chunk System Optimizations
this.blockY = blockY;
this.waterHeight = waterHeight;
this.stoneDepthBelow = stoneDepthBelow;
@@ -441,7 +444,6 @@ public class SurfaceRules {
protected boolean compute() {
return this.context
.biome
- .get()
.value()
.coldEnoughToSnow(this.context.pos.set(this.context.blockX, this.context.blockY, this.context.blockZ), this.context.getSeaLevel());
}
diff --git a/net/minecraft/world/level/levelgen/WorldgenRandom.java b/net/minecraft/world/level/levelgen/WorldgenRandom.java
index c2d7cd788071e25b8ba2503c30ae80c7a9f353ed..0a2e13c4a3db6517267e1f9e74b6152c73e8351f 100644
--- a/net/minecraft/world/level/levelgen/WorldgenRandom.java
+++ b/net/minecraft/world/level/levelgen/WorldgenRandom.java
@@ -73,7 +73,7 @@ public class WorldgenRandom extends LegacyRandomSource {
}
public static enum Algorithm {
- LEGACY(LegacyRandomSource::new),
+ LEGACY(ThreadSafeLegacyRandomSource::new), // DivineMC - Chunk System optimization
XOROSHIRO(XoroshiroRandomSource::new);
private final LongFunction<RandomSource> constructor;
diff --git a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
index 9d3a9ca1e13cd80f468f1352bbb74345f03903dd..d97b9b43686bda0a95fc02f6ca31b2d07d603a32 100644
--- a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
+++ b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
@@ -106,15 +106,7 @@ public class XoroshiroRandomSource implements RandomSource {
return this.randomNumberGenerator.nextLong() >>> 64 - bits;
}
- public static class XoroshiroPositionalRandomFactory implements PositionalRandomFactory {
- private final long seedLo;
- private final long seedHi;
-
- public XoroshiroPositionalRandomFactory(long seedLo, long seedHi) {
- this.seedLo = seedLo;
- this.seedHi = seedHi;
- }
-
+ public record XoroshiroPositionalRandomFactory(long seedLo, long seedHi) implements PositionalRandomFactory { // DivineMC - make record
@Override
public RandomSource at(int x, int y, int z) {
long seed = Mth.getSeed(x, y, z);
diff --git a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
index 21cbf6c1723feb1813d8cd5106e36594d140d987..29fad81878fe6902328b810e1584650cfb65aba6 100644
--- a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
+++ b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
@@ -55,17 +55,21 @@ public class RandomizedIntStateProvider extends BlockStateProvider {
@Override
public BlockState getState(RandomSource random, BlockPos pos) {
- BlockState state = this.source.getState(random, pos);
- if (this.property == null || !state.hasProperty(this.property)) {
- IntegerProperty integerProperty = findProperty(state, this.propertyName);
- if (integerProperty == null) {
- return state;
+ // DivineMC start - Chunk System optimization
+ BlockState blockState = this.source.getState(random, pos);
+ IntegerProperty propertyLocal = this.property;
+ if (propertyLocal == null || !blockState.hasProperty(propertyLocal)) {
+ IntegerProperty intProperty = findProperty(blockState, this.propertyName);
+ if (intProperty == null) {
+ return blockState;
}
- this.property = integerProperty;
+ propertyLocal = intProperty;
+ this.property = intProperty;
}
- return state.setValue(this.property, this.values.sample(random));
+ return (BlockState) blockState.setValue(this.property, this.values.sample(random));
+ // DivineMC end - Chunk System optimization
}
@Nullable
diff --git a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
index e2036a80eff3dc1a9ec625880d4aab6ef71d84fa..6c5200a311a6c5a93a49999cc0c3a8b3f3ca8240 100644
--- a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
+++ b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
@@ -12,7 +12,7 @@ public abstract class ScatteredFeaturePiece extends StructurePiece {
protected final int width;
protected final int height;
protected final int depth;
- protected int heightPosition = -1;
+ protected volatile int heightPosition = -1; // DivineMC - Chunk System optimization - make volatile
protected ScatteredFeaturePiece(StructurePieceType type, int x, int y, int z, int width, int height, int depth, Direction orientation) {
super(type, 0, StructurePiece.makeBoundingBox(x, y, z, orientation, width, height, depth));
diff --git a/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/net/minecraft/world/level/levelgen/structure/StructureCheck.java
index 7779a2f83f51465bde476776470bd77712f6be0d..c79c758ced104d2711b73b41370c43c4dc56b03e 100644
--- a/net/minecraft/world/level/levelgen/structure/StructureCheck.java
+++ b/net/minecraft/world/level/levelgen/structure/StructureCheck.java
@@ -47,6 +47,7 @@ public class StructureCheck {
private final LevelHeightAccessor heightAccessor;
private final BiomeSource biomeSource;
private final long seed;
+ private Object mapMutex = new Object(); // DivineMC - Chunk System Optimizations
private final DataFixer fixerUpper;
// Paper start - rewrite chunk system
// make sure to purge entries from the maps to prevent memory leaks
@@ -229,15 +230,13 @@ public class StructureCheck {
}
private void storeFullResults(long chunkPos, Object2IntMap<Structure> structureChunks) {
- // Paper start - rewrite chunk system
+ // DivineMC start - Chunk System Optimizations
this.loadedChunksSafe.put(chunkPos, deduplicateEmptyMap(structureChunks));
- // once we insert into loadedChunks, we don't really need to be very careful about removing everything
- // from this map, as everything that checks this map uses loadedChunks first
- // so, one way or another it's a race condition that doesn't matter
- for (ca.spottedleaf.moonrise.common.map.SynchronisedLong2BooleanMap value : this.featureChecksSafe.values()) {
- value.remove(chunkPos);
+
+ synchronized (this.mapMutex) {
+ this.featureChecksSafe.values().forEach((long2BooleanMap) -> long2BooleanMap.remove(chunkPos));
}
- // Paper end - rewrite chunk system
+ // DivineMC end - Chunk System Optimizations
}
public void incrementReference(ChunkPos pos, Structure structure) {
diff --git a/net/minecraft/world/level/levelgen/structure/StructureStart.java b/net/minecraft/world/level/levelgen/structure/StructureStart.java
index f9a15c3769f29af1952ef880f6fcd2612119ecf0..13f6654e06f87e9a9fbeba2217ee0e0eaa95347d 100644
--- a/net/minecraft/world/level/levelgen/structure/StructureStart.java
+++ b/net/minecraft/world/level/levelgen/structure/StructureStart.java
@@ -26,7 +26,7 @@ public final class StructureStart {
private final Structure structure;
private final PiecesContainer pieceContainer;
private final ChunkPos chunkPos;
- private int references;
+ private final java.util.concurrent.atomic.AtomicInteger references = new java.util.concurrent.atomic.AtomicInteger(); // DivineMC - Chunk System optimization
@Nullable
private volatile BoundingBox cachedBoundingBox;
@@ -39,7 +39,7 @@ public final class StructureStart {
public StructureStart(Structure structure, ChunkPos chunkPos, int references, PiecesContainer pieceContainer) {
this.structure = structure;
this.chunkPos = chunkPos;
- this.references = references;
+ this.references.set(references); // DivineMC - Chunk System optimization
this.pieceContainer = pieceContainer;
}
@@ -126,7 +126,7 @@ public final class StructureStart {
compoundTag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString());
compoundTag.putInt("ChunkX", chunkPos.x);
compoundTag.putInt("ChunkZ", chunkPos.z);
- compoundTag.putInt("references", this.references);
+ compoundTag.putInt("references", this.references.get()); // DivineMC - Chunk System optimization
compoundTag.put("Children", this.pieceContainer.save(context));
return compoundTag;
} else {
@@ -144,15 +144,15 @@ public final class StructureStart {
}
public boolean canBeReferenced() {
- return this.references < this.getMaxReferences();
+ return this.references.get() < this.getMaxReferences(); // DivineMC - Chunk System optimization
}
public void addReference() {
- this.references++;
+ this.references.getAndIncrement(); // DivineMC - Chunk System optimization
}
public int getReferences() {
- return this.references;
+ return this.references.get(); // DivineMC - Chunk System optimization
}
protected int getMaxReferences() {
diff --git a/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java b/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java
index c84d865837e0f009fcde19e14a44fa43aefe660a..64d7adbd4aa398044a1d68d51e463b672ee81edf 100644
--- a/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java
+++ b/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java
@@ -27,9 +27,9 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
public abstract class StructurePoolElement {
- public static final Codec<StructurePoolElement> CODEC = BuiltInRegistries.STRUCTURE_POOL_ELEMENT
+ public static final Codec<StructurePoolElement> CODEC = new org.bxteam.divinemc.util.SynchronizedCodec<>(BuiltInRegistries.STRUCTURE_POOL_ELEMENT // DivineMC - Chunk System Optimizations
.byNameCodec()
- .dispatch("element_type", StructurePoolElement::getType, StructurePoolElementType::codec);
+ .dispatch("element_type", StructurePoolElement::getType, StructurePoolElementType::codec)); // DivineMC - Chunk System Optimizations
private static final Holder<StructureProcessorList> EMPTY = Holder.direct(new StructureProcessorList(List.of()));
@Nullable
private volatile StructureTemplatePool.Projection projection;
diff --git a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java
index 0d2451a9ade43650dbbcbab69ce0f6e8f69b5aee..21b8e738c8823eac5d8fc8241dd8fb0e5ce82364 100644
--- a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java
@@ -23,29 +23,45 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables;
public class DesertPyramidPiece extends ScatteredFeaturePiece {
public static final int WIDTH = 21;
public static final int DEPTH = 21;
- private final boolean[] hasPlacedChest = new boolean[4];
- private final List<BlockPos> potentialSuspiciousSandWorldPositions = new ArrayList<>();
+ private final java.util.concurrent.atomic.AtomicReferenceArray<Boolean> hasPlacedChestAtomic = new java.util.concurrent.atomic.AtomicReferenceArray<>(new Boolean[4]); // DivineMC - Chunk System Optimizations
+ private final java.util.Set<BlockPos> potentialSuspiciousSandWorldPositions = com.google.common.collect.Sets.newConcurrentHashSet(); // DivineMC - Chunk System Optimizations
private BlockPos randomCollapsedRoofPos = BlockPos.ZERO;
+ // DivineMC start - Chunk System Optimizations
+ private void init() {
+ for (int i = 0; i < this.hasPlacedChestAtomic.length(); ++i) {
+ if (this.hasPlacedChestAtomic.get(i) == null) {
+ this.hasPlacedChestAtomic.set(i, false);
+ }
+ }
+ }
+ // DivineMC end - Chunk System Optimizations
+
public DesertPyramidPiece(RandomSource random, int x, int z) {
super(StructurePieceType.DESERT_PYRAMID_PIECE, x, 64, z, 21, 15, 21, getRandomHorizontalDirection(random));
+ init(); // DivineMC - Chunk System Optimizations
}
public DesertPyramidPiece(CompoundTag tag) {
super(StructurePieceType.DESERT_PYRAMID_PIECE, tag);
- this.hasPlacedChest[0] = tag.getBooleanOr("hasPlacedChest0", false);
- this.hasPlacedChest[1] = tag.getBooleanOr("hasPlacedChest1", false);
- this.hasPlacedChest[2] = tag.getBooleanOr("hasPlacedChest2", false);
- this.hasPlacedChest[3] = tag.getBooleanOr("hasPlacedChest3", false);
+ // DivineMC start - Chunk System Optimizations
+ this.hasPlacedChestAtomic.set(0, tag.getBooleanOr("hasPlacedChest0", false));
+ this.hasPlacedChestAtomic.set(1, tag.getBooleanOr("hasPlacedChest1", false));
+ this.hasPlacedChestAtomic.set(2, tag.getBooleanOr("hasPlacedChest2", false));
+ this.hasPlacedChestAtomic.set(3, tag.getBooleanOr("hasPlacedChest3", false));
+ init();
+ // DivineMC end - Chunk System Optimizations
}
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) {
super.addAdditionalSaveData(context, tag);
- tag.putBoolean("hasPlacedChest0", this.hasPlacedChest[0]);
- tag.putBoolean("hasPlacedChest1", this.hasPlacedChest[1]);
- tag.putBoolean("hasPlacedChest2", this.hasPlacedChest[2]);
- tag.putBoolean("hasPlacedChest3", this.hasPlacedChest[3]);
+ // DivineMC start - Chunk System Optimizations
+ tag.putBoolean("hasPlacedChest0", this.hasPlacedChestAtomic.get(0));
+ tag.putBoolean("hasPlacedChest1", this.hasPlacedChestAtomic.get(1));
+ tag.putBoolean("hasPlacedChest2", this.hasPlacedChestAtomic.get(2));
+ tag.putBoolean("hasPlacedChest3", this.hasPlacedChestAtomic.get(3));
+ // DivineMC end - Chunk System Optimizations
}
@Override
@@ -287,12 +303,12 @@ public class DesertPyramidPiece extends ScatteredFeaturePiece {
this.placeBlock(level, Blocks.CUT_SANDSTONE.defaultBlockState(), 10, -11, 13, box);
for (Direction direction : Direction.Plane.HORIZONTAL) {
- if (!this.hasPlacedChest[direction.get2DDataValue()]) {
+ if (!this.hasPlacedChestAtomic.get(direction.get2DDataValue())) { // DivineMC - Chunk System Optimizations
int i4 = direction.getStepX() * 2;
int i5 = direction.getStepZ() * 2;
- this.hasPlacedChest[direction.get2DDataValue()] = this.createChest(
+ this.hasPlacedChestAtomic.set(direction.get2DDataValue(), this.createChest( // DivineMC - Chunk System Optimizations
level, box, random, 10 + i4, -11, 10 + i5, BuiltInLootTables.DESERT_PYRAMID
- );
+ )); // DivineMC - Chunk System Optimizations
}
}
@@ -419,7 +435,7 @@ public class DesertPyramidPiece extends ScatteredFeaturePiece {
this.randomCollapsedRoofPos = new BlockPos(this.getWorldX(i1, randomInt), this.getWorldY(y), this.getWorldZ(i1, randomInt));
}
- public List<BlockPos> getPotentialSuspiciousSandWorldPositions() {
+ public java.util.Set<BlockPos> getPotentialSuspiciousSandWorldPositions() { // DivineMC - Chunk System Optimizations
return this.potentialSuspiciousSandWorldPositions;
}
diff --git a/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java b/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java
index d28f1a25e2137955402e41679d1a4220a0136579..d751eac6d7a97b8de44c83c35ff7d3e36ca3b066 100644
--- a/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java
@@ -30,10 +30,12 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables;
public class JungleTemplePiece extends ScatteredFeaturePiece {
public static final int WIDTH = 12;
public static final int DEPTH = 15;
- private boolean placedMainChest;
- private boolean placedHiddenChest;
- private boolean placedTrap1;
- private boolean placedTrap2;
+ // DivineMC start - Chunk System Optimizations
+ private final java.util.concurrent.atomic.AtomicBoolean placedMainChest = new java.util.concurrent.atomic.AtomicBoolean(false);
+ private final java.util.concurrent.atomic.AtomicBoolean placedHiddenChest = new java.util.concurrent.atomic.AtomicBoolean(false);
+ private final java.util.concurrent.atomic.AtomicBoolean placedTrap1 = new java.util.concurrent.atomic.AtomicBoolean(false);
+ private final java.util.concurrent.atomic.AtomicBoolean placedTrap2 = new java.util.concurrent.atomic.AtomicBoolean(false);
+ // DivineMC end - Chunk System Optimizations
private static final JungleTemplePiece.MossStoneSelector STONE_SELECTOR = new JungleTemplePiece.MossStoneSelector();
public JungleTemplePiece(RandomSource random, int x, int z) {
@@ -42,19 +44,23 @@ public class JungleTemplePiece extends ScatteredFeaturePiece {
public JungleTemplePiece(CompoundTag tag) {
super(StructurePieceType.JUNGLE_PYRAMID_PIECE, tag);
- this.placedMainChest = tag.getBooleanOr("placedMainChest", false);
- this.placedHiddenChest = tag.getBooleanOr("placedHiddenChest", false);
- this.placedTrap1 = tag.getBooleanOr("placedTrap1", false);
- this.placedTrap2 = tag.getBooleanOr("placedTrap2", false);
+ // DivineMC start - Chunk System Optimizations
+ this.placedMainChest.set(tag.getBooleanOr("placedMainChest", false));
+ this.placedHiddenChest.set(tag.getBooleanOr("placedHiddenChest", false));
+ this.placedTrap1.set(tag.getBooleanOr("placedTrap1", false));
+ this.placedTrap2.set(tag.getBooleanOr("placedTrap2", false));
+ // DivineMC end - Chunk System Optimizations
}
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) {
super.addAdditionalSaveData(context, tag);
- tag.putBoolean("placedMainChest", this.placedMainChest);
- tag.putBoolean("placedHiddenChest", this.placedHiddenChest);
- tag.putBoolean("placedTrap1", this.placedTrap1);
- tag.putBoolean("placedTrap2", this.placedTrap2);
+ // DivineMC start - Chunk System Optimizations
+ tag.putBoolean("placedMainChest", this.placedMainChest.get());
+ tag.putBoolean("placedHiddenChest", this.placedHiddenChest.get());
+ tag.putBoolean("placedTrap1", this.placedTrap1.get());
+ tag.putBoolean("placedTrap2", this.placedTrap2.get());
+ // DivineMC end - Chunk System Optimizations
}
@Override
@@ -236,8 +242,8 @@ public class JungleTemplePiece extends ScatteredFeaturePiece {
box
);
this.placeBlock(level, Blocks.MOSSY_COBBLESTONE.defaultBlockState(), 3, -3, 1, box);
- if (!this.placedTrap1) {
- this.placedTrap1 = this.createDispenser(level, box, random, 3, -2, 1, Direction.NORTH, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER);
+ if (!this.placedTrap1.get()) { // DivineMC - Chunk System Optimizations
+ this.placedTrap1.set(this.createDispenser(level, box, random, 3, -2, 1, Direction.NORTH, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER)); // DivineMC - Chunk System Optimizations
}
this.placeBlock(level, Blocks.VINE.defaultBlockState().setValue(VineBlock.SOUTH, true), 3, -2, 2, box);
@@ -328,14 +334,14 @@ public class JungleTemplePiece extends ScatteredFeaturePiece {
);
this.placeBlock(level, Blocks.MOSSY_COBBLESTONE.defaultBlockState(), 9, -3, 4, box);
this.placeBlock(level, blockState4, 9, -2, 4, box);
- if (!this.placedTrap2) {
- this.placedTrap2 = this.createDispenser(level, box, random, 9, -2, 3, Direction.WEST, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER);
+ if (!this.placedTrap2.get()) { // DivineMC - Chunk System Optimizations
+ this.placedTrap2.set(this.createDispenser(level, box, random, 9, -2, 3, Direction.WEST, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER)); // DivineMC - Chunk System Optimizations
}
this.placeBlock(level, Blocks.VINE.defaultBlockState().setValue(VineBlock.EAST, true), 8, -1, 3, box);
this.placeBlock(level, Blocks.VINE.defaultBlockState().setValue(VineBlock.EAST, true), 8, -2, 3, box);
- if (!this.placedMainChest) {
- this.placedMainChest = this.createChest(level, box, random, 8, -3, 3, BuiltInLootTables.JUNGLE_TEMPLE);
+ if (!this.placedMainChest.get()) { // DivineMC - Chunk System Optimizations
+ this.placedMainChest.set(this.createChest(level, box, random, 8, -3, 3, BuiltInLootTables.JUNGLE_TEMPLE)); // DivineMC - Chunk System Optimizations
}
this.placeBlock(level, Blocks.MOSSY_COBBLESTONE.defaultBlockState(), 9, -3, 2, box);
@@ -378,8 +384,8 @@ public class JungleTemplePiece extends ScatteredFeaturePiece {
this.placeBlock(level, Blocks.STICKY_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.WEST), 10, -2, 8, box);
this.placeBlock(level, Blocks.STICKY_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.WEST), 10, -1, 8, box);
this.placeBlock(level, Blocks.REPEATER.defaultBlockState().setValue(RepeaterBlock.FACING, Direction.NORTH), 10, -2, 10, box);
- if (!this.placedHiddenChest) {
- this.placedHiddenChest = this.createChest(level, box, random, 9, -3, 10, BuiltInLootTables.JUNGLE_TEMPLE);
+ if (!this.placedHiddenChest.get()) { // DivineMC - Chunk System Optimizations
+ this.placedHiddenChest.set(this.createChest(level, box, random, 9, -3, 10, BuiltInLootTables.JUNGLE_TEMPLE)); // DivineMC - Chunk System Optimizations
}
}
}
diff --git a/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java b/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java
index 53d3bf1d2a1debe46e276b1db25b420be4ad9958..5212e4a4392efa0171c9d709dc2606a4e14df07f 100644
--- a/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java
@@ -91,7 +91,7 @@ public class MineshaftPieces {
public static class MineShaftCorridor extends MineshaftPieces.MineShaftPiece {
private final boolean hasRails;
private final boolean spiderCorridor;
- private boolean hasPlacedSpider;
+ private volatile boolean hasPlacedSpider; // DivineMC - Chunk System Optimizations
private final int numSections;
public MineShaftCorridor(CompoundTag tag) {
@@ -950,7 +950,7 @@ public class MineshaftPieces {
}
public static class MineShaftRoom extends MineshaftPieces.MineShaftPiece {
- private final List<BoundingBox> childEntranceBoxes = Lists.newLinkedList();
+ private final List<BoundingBox> childEntranceBoxes = java.util.Collections.synchronizedList(Lists.newLinkedList()); // DivineMC - Chunk System Optimizations
public MineShaftRoom(int genDepth, RandomSource random, int x, int z, MineshaftStructure.Type type) {
super(
diff --git a/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java b/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java
index ae4ffcf1859e8ff7f8fbc91246e66e20f5c33dd7..b9124999f1aede4450f25e25c55bca96077670e8 100644
--- a/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java
@@ -1112,7 +1112,7 @@ public class NetherFortressPieces {
int i = 0;
for (NetherFortressPieces.PieceWeight pieceWeight : weights) {
- if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount < pieceWeight.maxPlaceCount) {
+ if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount.get() < pieceWeight.maxPlaceCount) { // DivineMC - Chunk System Optimizations
flag = true;
}
@@ -1152,7 +1152,7 @@ public class NetherFortressPieces {
pieceWeight, pieces, random, x, y, z, orientation, genDepth
);
if (netherBridgePiece != null) {
- pieceWeight.placeCount++;
+ pieceWeight.placeCount.set(pieceWeight.placeCount.get() + 1); // DivineMC - Chunk System Optimizations
startPiece.previousPiece = pieceWeight;
if (!pieceWeight.isValid()) {
weights.remove(pieceWeight);
@@ -1387,7 +1387,7 @@ public class NetherFortressPieces {
static class PieceWeight {
public final Class<? extends NetherFortressPieces.NetherBridgePiece> pieceClass;
public final int weight;
- public int placeCount;
+ public final ThreadLocal<Integer> placeCount = ThreadLocal.withInitial(() -> 0); // DivineMC - Chunk System Optimizations
public final int maxPlaceCount;
public final boolean allowInRow;
@@ -1403,11 +1403,11 @@ public class NetherFortressPieces {
}
public boolean doPlace(int genDepth) {
- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount;
+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations
}
public boolean isValid() {
- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount;
+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations
}
}
@@ -1545,24 +1545,24 @@ public class NetherFortressPieces {
}
public static class StartPiece extends NetherFortressPieces.BridgeCrossing {
- public NetherFortressPieces.PieceWeight previousPiece;
+ public volatile NetherFortressPieces.PieceWeight previousPiece; // DivineMC - Chunk System Optimizations
public List<NetherFortressPieces.PieceWeight> availableBridgePieces;
public List<NetherFortressPieces.PieceWeight> availableCastlePieces;
public final List<StructurePiece> pendingChildren = Lists.newArrayList();
public StartPiece(RandomSource random, int x, int z) {
super(x, z, getRandomHorizontalDirection(random));
- this.availableBridgePieces = Lists.newArrayList();
+ this.availableBridgePieces = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations
for (NetherFortressPieces.PieceWeight pieceWeight : NetherFortressPieces.BRIDGE_PIECE_WEIGHTS) {
- pieceWeight.placeCount = 0;
+ pieceWeight.placeCount.remove(); // DivineMC - Chunk System Optimizations
this.availableBridgePieces.add(pieceWeight);
}
- this.availableCastlePieces = Lists.newArrayList();
+ this.availableCastlePieces = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations
for (NetherFortressPieces.PieceWeight pieceWeight : NetherFortressPieces.CASTLE_PIECE_WEIGHTS) {
- pieceWeight.placeCount = 0;
+ pieceWeight.placeCount.remove(); // DivineMC - Chunk System Optimizations
this.availableCastlePieces.add(pieceWeight);
}
}
diff --git a/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java b/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java
index 1f1ee6e2d020cd06184313d19523ea928cf242c8..ab6d51b60cdbaed7ac7395d2a27eadd6d6b4518f 100644
--- a/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java
@@ -65,32 +65,36 @@ public class StrongholdPieces {
}
}
};
- private static List<StrongholdPieces.PieceWeight> currentPieces;
- static Class<? extends StrongholdPieces.StrongholdPiece> imposedPiece;
- private static int totalWeight;
+ // DivineMC start - Chunk System Optimizations
+ private static final ThreadLocal<List<PieceWeight>> currentPieces = new ThreadLocal<List<PieceWeight>>();
+ static final ThreadLocal<Class<? extends StrongholdPiece>> imposedPiece = new ThreadLocal<Class<? extends StrongholdPiece>>();
+ private static final ThreadLocal<Integer> totalWeight = ThreadLocal.withInitial(() -> 0);
+ // DivineMC end - Chunk System Optimizations
static final StrongholdPieces.SmoothStoneSelector SMOOTH_STONE_SELECTOR = new StrongholdPieces.SmoothStoneSelector();
public static void resetPieces() {
- currentPieces = Lists.newArrayList();
+ // DivineMC start - Chunk System Optimizations
+ currentPieces.set(Lists.newArrayList());
for (StrongholdPieces.PieceWeight pieceWeight : STRONGHOLD_PIECE_WEIGHTS) {
- pieceWeight.placeCount = 0;
- currentPieces.add(pieceWeight);
+ pieceWeight.placeCount.set(0);
+ currentPieces.get().add(pieceWeight);
}
- imposedPiece = null;
+ imposedPiece.set(null);
+ // DivineMC end - Chunk System Optimizations
}
private static boolean updatePieceWeight() {
boolean flag = false;
- totalWeight = 0;
+ totalWeight.set(0); // DivineMC - Chunk System Optimizations
- for (StrongholdPieces.PieceWeight pieceWeight : currentPieces) {
- if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount < pieceWeight.maxPlaceCount) {
+ for (StrongholdPieces.PieceWeight pieceWeight : currentPieces.get()) { // DivineMC - Chunk System Optimizations
+ if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount.get() < pieceWeight.maxPlaceCount) { // DivineMC - Chunk System Optimizations
flag = true;
}
- totalWeight = totalWeight + pieceWeight.weight;
+ totalWeight.set(totalWeight.get() + pieceWeight.weight); // DivineMC - Chunk System Optimizations
}
return flag;
@@ -140,9 +144,11 @@ public class StrongholdPieces {
if (!updatePieceWeight()) {
return null;
} else {
- if (imposedPiece != null) {
- StrongholdPieces.StrongholdPiece strongholdPiece = findAndCreatePieceFactory(imposedPiece, pieces, random, x, y, z, direction, genDepth);
- imposedPiece = null;
+ // DivineMC start - Chunk System Optimizations
+ if (imposedPiece.get() != null) {
+ StrongholdPieces.StrongholdPiece strongholdPiece = findAndCreatePieceFactory(imposedPiece.get(), pieces, random, x, y, z, direction, genDepth);
+ imposedPiece.set(null);
+ // DivineMC end - Chunk System Optimizations
if (strongholdPiece != null) {
return strongholdPiece;
}
@@ -152,9 +158,9 @@ public class StrongholdPieces {
while (i < 5) {
i++;
- int randomInt = random.nextInt(totalWeight);
+ int randomInt = random.nextInt(totalWeight.get()); // DivineMC - Chunk System Optimizations
- for (StrongholdPieces.PieceWeight pieceWeight : currentPieces) {
+ for (StrongholdPieces.PieceWeight pieceWeight : currentPieces.get()) { // DivineMC - Chunk System Optimizations
randomInt -= pieceWeight.weight;
if (randomInt < 0) {
if (!pieceWeight.doPlace(genDepth) || pieceWeight == piece.previousPiece) {
@@ -165,10 +171,10 @@ public class StrongholdPieces {
pieceWeight.pieceClass, pieces, random, x, y, z, direction, genDepth
);
if (strongholdPiece1 != null) {
- pieceWeight.placeCount++;
+ pieceWeight.placeCount.set(pieceWeight.placeCount.get() + 1); // DivineMC - Chunk System Optimizations
piece.previousPiece = pieceWeight;
if (!pieceWeight.isValid()) {
- currentPieces.remove(pieceWeight);
+ currentPieces.get().remove(pieceWeight); // DivineMC - Chunk System Optimizations
}
return strongholdPiece1;
@@ -204,7 +210,7 @@ public class StrongholdPieces {
private static final int WIDTH = 5;
private static final int HEIGHT = 5;
private static final int DEPTH = 7;
- private boolean hasPlacedChest;
+ private volatile boolean hasPlacedChest; // DivineMC - Chunk System Optimizations
public ChestCorridor(int genDepth, RandomSource random, BoundingBox box, Direction orientation) {
super(StructurePieceType.STRONGHOLD_CHEST_CORRIDOR, genDepth, box);
@@ -690,7 +696,7 @@ public class StrongholdPieces {
static class PieceWeight {
public final Class<? extends StrongholdPieces.StrongholdPiece> pieceClass;
public final int weight;
- public int placeCount;
+ public final ThreadLocal<Integer> placeCount = ThreadLocal.withInitial(() -> 0); // DivineMC - Chunk System Optimizations
public final int maxPlaceCount;
public PieceWeight(Class<? extends StrongholdPieces.StrongholdPiece> pieceClass, int weight, int maxPlaceCount) {
@@ -700,11 +706,11 @@ public class StrongholdPieces {
}
public boolean doPlace(int genDepth) {
- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount;
+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations
}
public boolean isValid() {
- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount;
+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations
}
}
@@ -712,7 +718,7 @@ public class StrongholdPieces {
protected static final int WIDTH = 11;
protected static final int HEIGHT = 8;
protected static final int DEPTH = 16;
- private boolean hasPlacedSpawner;
+ private volatile boolean hasPlacedSpawner; // DivineMC - Chunk System Optimizations
public PortalRoom(int genDepth, BoundingBox box, Direction orientation) {
super(StructurePieceType.STRONGHOLD_PORTAL_ROOM, genDepth, box);
@@ -1174,7 +1180,7 @@ public class StrongholdPieces {
@Override
public void addChildren(StructurePiece piece, StructurePieceAccessor pieces, RandomSource random) {
if (this.isSource) {
- StrongholdPieces.imposedPiece = StrongholdPieces.FiveCrossing.class;
+ StrongholdPieces.imposedPiece.set(StrongholdPieces.FiveCrossing.class);
}
this.generateSmallDoorChildForward((StrongholdPieces.StartPiece)piece, pieces, random, 1, 1);
@@ -1223,10 +1229,10 @@ public class StrongholdPieces {
}
public static class StartPiece extends StrongholdPieces.StairsDown {
- public StrongholdPieces.PieceWeight previousPiece;
+ public volatile StrongholdPieces.PieceWeight previousPiece; // DivineMC - Chunk System Optimizations
@Nullable
- public StrongholdPieces.PortalRoom portalRoomPiece;
- public final List<StructurePiece> pendingChildren = Lists.newArrayList();
+ public volatile StrongholdPieces.PortalRoom portalRoomPiece; // DivineMC - Chunk System Optimizations
+ public final List<StructurePiece> pendingChildren = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations
public StartPiece(RandomSource random, int x, int z) {
super(StructurePieceType.STRONGHOLD_START, 0, x, z, getRandomHorizontalDirection(random));
diff --git a/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java b/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java
index 872fd2ebe6f95cf1d59e18a4c5ca15d12a65b7b0..9e4aa26d18dd748b5f7af59e88af612ad1224d1f 100644
--- a/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java
@@ -126,7 +126,7 @@ public class WoodlandMansionPieces {
int i = 11;
this.entranceX = 7;
this.entranceY = 4;
- this.baseGrid = new WoodlandMansionPieces.SimpleGrid(11, 11, 5);
+ this.baseGrid = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5); // DivineMC - Chunk System Optimizations
this.baseGrid.set(this.entranceX, this.entranceY, this.entranceX + 1, this.entranceY + 1, 3);
this.baseGrid.set(this.entranceX - 1, this.entranceY, this.entranceX - 1, this.entranceY + 1, 2);
this.baseGrid.set(this.entranceX + 2, this.entranceY - 2, this.entranceX + 3, this.entranceY + 3, 5);
@@ -145,14 +145,16 @@ public class WoodlandMansionPieces {
}
this.floorRooms = new WoodlandMansionPieces.SimpleGrid[3];
- this.floorRooms[0] = new WoodlandMansionPieces.SimpleGrid(11, 11, 5);
- this.floorRooms[1] = new WoodlandMansionPieces.SimpleGrid(11, 11, 5);
- this.floorRooms[2] = new WoodlandMansionPieces.SimpleGrid(11, 11, 5);
+ // DivineMC start - Chunk System Optimizations
+ this.floorRooms[0] = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5);
+ this.floorRooms[1] = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5);
+ this.floorRooms[2] = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5);
+ // DivineMC end - Chunk System Optimizations
this.identifyRooms(this.baseGrid, this.floorRooms[0]);
this.identifyRooms(this.baseGrid, this.floorRooms[1]);
this.floorRooms[0].set(this.entranceX + 1, this.entranceY, this.entranceX + 1, this.entranceY + 1, 8388608);
this.floorRooms[1].set(this.entranceX + 1, this.entranceY, this.entranceX + 1, this.entranceY + 1, 8388608);
- this.thirdFloorGrid = new WoodlandMansionPieces.SimpleGrid(this.baseGrid.width, this.baseGrid.height, 5);
+ this.thirdFloorGrid = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(this.baseGrid.width, this.baseGrid.height, 5); // DivineMC - Chunk System Optimizations
this.setupThirdFloor();
this.identifyRooms(this.thirdFloorGrid, this.floorRooms[2]);
}
@@ -1139,9 +1141,11 @@ public class WoodlandMansionPieces {
}
static class PlacementData {
- public Rotation rotation;
- public BlockPos position;
- public String wallType;
+ // DivineMC start - Chunk System Optimizations
+ public volatile Rotation rotation;
+ public volatile BlockPos position;
+ public volatile String wallType;
+ // DivineMC end - Chunk System Optimizations
}
static class SecondFloorRoomCollection extends WoodlandMansionPieces.FloorRoomCollection {
diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java
index 05027cc20d174d78bef118cd2ba545ac56e1559c..32bbfe48dee44b0b491aa369dec59cbf0772c4b5 100644
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java
@@ -22,7 +22,7 @@ public class StructurePlaceSettings {
@Nullable
private RandomSource random;
public int palette = -1; // CraftBukkit - Set initial value so we know if the palette has been set forcefully
- private final List<StructureProcessor> processors = Lists.newArrayList();
+ private final List<StructureProcessor> processors = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations
private boolean knownShape;
private boolean finalizeEntities;
diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
index f21e612a35d6ac4482dbf5d14e506959659e371a..5a05536e474bec574aa637f86bfc51f566d76ebf 100644
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
@@ -75,8 +75,8 @@ public class StructureTemplate {
public static final String ENTITY_TAG_BLOCKPOS = "blockPos";
public static final String ENTITY_TAG_NBT = "nbt";
public static final String SIZE_TAG = "size";
- public final List<StructureTemplate.Palette> palettes = Lists.newArrayList();
- public final List<StructureTemplate.StructureEntityInfo> entityInfoList = Lists.newArrayList();
+ public final List<StructureTemplate.Palette> palettes = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations
+ public final List<StructureTemplate.StructureEntityInfo> entityInfoList = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations
private Vec3i size = Vec3i.ZERO;
private String author = "?";
// CraftBukkit start - data containers
diff --git a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java
index 46e98a99442523614284150964ba528d0c91493f..75df6465823ebacad48f3a0b3560c89ab3b6b093 100644
--- a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java
+++ b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java
@@ -11,6 +11,27 @@ public final class ImprovedNoise {
public final double yo;
public final double zo;
+ // DivineMC start - Chunk System Optimizations
+ private static final double[] FLAT_SIMPLEX_GRAD = new double[]{
+ 1, 1, 0, 0,
+ -1, 1, 0, 0,
+ 1, -1, 0, 0,
+ -1, -1, 0, 0,
+ 1, 0, 1, 0,
+ -1, 0, 1, 0,
+ 1, 0, -1, 0,
+ -1, 0, -1, 0,
+ 0, 1, 1, 0,
+ 0, -1, 1, 0,
+ 0, 1, -1, 0,
+ 0, -1, -1, 0,
+ 1, 1, 0, 0,
+ 0, -1, 1, 0,
+ -1, 1, 0, 0,
+ 0, -1, -1, 0,
+ };
+ // DivineMC end - Chunk System Optimizations
+
public ImprovedNoise(RandomSource random) {
this.xo = random.nextDouble() * 256.0;
this.yo = random.nextDouble() * 256.0;
@@ -38,9 +59,11 @@ public final class ImprovedNoise {
double d = x + this.xo;
double d1 = y + this.yo;
double d2 = z + this.zo;
- int floor = Mth.floor(d);
- int floor1 = Mth.floor(d1);
- int floor2 = Mth.floor(d2);
+ // DivineMC start - Chunk System Optimizations
+ double floor = Math.floor(d);
+ double floor1 = Math.floor(d1);
+ double floor2 = Math.floor(d2);
+ // DivineMC end - Chunk System Optimizations
double d3 = d - floor;
double d4 = d1 - floor1;
double d5 = d2 - floor2;
@@ -53,25 +76,27 @@ public final class ImprovedNoise {
d6 = d4;
}
- d7 = Mth.floor(d6 / yScale + 1.0E-7F) * yScale;
+ d7 = Math.floor(d6 / yScale + 1.0E-7F) * yScale; // DivineMC - Chunk System Optimizations
} else {
d7 = 0.0;
}
- return this.sampleAndLerp(floor, floor1, floor2, d3, d4 - d7, d5, d4);
+ return this.sampleAndLerp((int) floor, (int) floor1, (int) floor2, d3, d4 - d7, d5, d4); // DivineMC - Chunk System Optimizations
}
public double noiseWithDerivative(double x, double y, double z, double[] values) {
double d = x + this.xo;
double d1 = y + this.yo;
double d2 = z + this.zo;
- int floor = Mth.floor(d);
- int floor1 = Mth.floor(d1);
- int floor2 = Mth.floor(d2);
+ // DivineMC start - Chunk System Optimizations
+ double floor = Math.floor(d);
+ double floor1 = Math.floor(d1);
+ double floor2 = Math.floor(d2);
+ // DivineMC end - Chunk System Optimizations
double d3 = d - floor;
double d4 = d1 - floor1;
double d5 = d2 - floor2;
- return this.sampleWithDerivative(floor, floor1, floor2, d3, d4, d5, values);
+ return this.sampleWithDerivative((int) floor, (int) floor1, (int) floor2, d3, d4, d5, values); // DivineMC - Chunk System Optimizations
}
private static double gradDot(int gradIndex, double xFactor, double yFactor, double zFactor) {
@@ -83,24 +108,69 @@ public final class ImprovedNoise {
}
private double sampleAndLerp(int gridX, int gridY, int gridZ, double deltaX, double weirdDeltaY, double deltaZ, double deltaY) {
- int i = this.p(gridX);
- int i1 = this.p(gridX + 1);
- int i2 = this.p(i + gridY);
- int i3 = this.p(i + gridY + 1);
- int i4 = this.p(i1 + gridY);
- int i5 = this.p(i1 + gridY + 1);
- double d = gradDot(this.p(i2 + gridZ), deltaX, weirdDeltaY, deltaZ);
- double d1 = gradDot(this.p(i4 + gridZ), deltaX - 1.0, weirdDeltaY, deltaZ);
- double d2 = gradDot(this.p(i3 + gridZ), deltaX, weirdDeltaY - 1.0, deltaZ);
- double d3 = gradDot(this.p(i5 + gridZ), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ);
- double d4 = gradDot(this.p(i2 + gridZ + 1), deltaX, weirdDeltaY, deltaZ - 1.0);
- double d5 = gradDot(this.p(i4 + gridZ + 1), deltaX - 1.0, weirdDeltaY, deltaZ - 1.0);
- double d6 = gradDot(this.p(i3 + gridZ + 1), deltaX, weirdDeltaY - 1.0, deltaZ - 1.0);
- double d7 = gradDot(this.p(i5 + gridZ + 1), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ - 1.0);
- double d8 = Mth.smoothstep(deltaX);
- double d9 = Mth.smoothstep(deltaY);
- double d10 = Mth.smoothstep(deltaZ);
- return Mth.lerp3(d8, d9, d10, d, d1, d2, d3, d4, d5, d6, d7);
+ // DivineMC start - Chunk System Optimizations
+ final int var0 = gridX & 0xFF;
+ final int var1 = (gridX + 1) & 0xFF;
+ final int var2 = this.p[var0] & 0xFF;
+ final int var3 = this.p[var1] & 0xFF;
+ final int var4 = (var2 + gridY) & 0xFF;
+ final int var5 = (var3 + gridY) & 0xFF;
+ final int var6 = (var2 + gridY + 1) & 0xFF;
+ final int var7 = (var3 + gridY + 1) & 0xFF;
+ final int var8 = this.p[var4] & 0xFF;
+ final int var9 = this.p[var5] & 0xFF;
+ final int var10 = this.p[var6] & 0xFF;
+ final int var11 = this.p[var7] & 0xFF;
+
+ final int var12 = (var8 + gridZ) & 0xFF;
+ final int var13 = (var9 + gridZ) & 0xFF;
+ final int var14 = (var10 + gridZ) & 0xFF;
+ final int var15 = (var11 + gridZ) & 0xFF;
+ final int var16 = (var8 + gridZ + 1) & 0xFF;
+ final int var17 = (var9 + gridZ + 1) & 0xFF;
+ final int var18 = (var10 + gridZ + 1) & 0xFF;
+ final int var19 = (var11 + gridZ + 1) & 0xFF;
+ final int var20 = (this.p[var12] & 15) << 2;
+ final int var21 = (this.p[var13] & 15) << 2;
+ final int var22 = (this.p[var14] & 15) << 2;
+ final int var23 = (this.p[var15] & 15) << 2;
+ final int var24 = (this.p[var16] & 15) << 2;
+ final int var25 = (this.p[var17] & 15) << 2;
+ final int var26 = (this.p[var18] & 15) << 2;
+ final int var27 = (this.p[var19] & 15) << 2;
+ final double var60 = deltaX - 1.0;
+ final double var61 = weirdDeltaY - 1.0;
+ final double var62 = deltaZ - 1.0;
+ final double var87 = FLAT_SIMPLEX_GRAD[(var20) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var20) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var20) | 2] * deltaZ;
+ final double var88 = FLAT_SIMPLEX_GRAD[(var21) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var21) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var21) | 2] * deltaZ;
+ final double var89 = FLAT_SIMPLEX_GRAD[(var22) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var22) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var22) | 2] * deltaZ;
+ final double var90 = FLAT_SIMPLEX_GRAD[(var23) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var23) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var23) | 2] * deltaZ;
+ final double var91 = FLAT_SIMPLEX_GRAD[(var24) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var24) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var24) | 2] * var62;
+ final double var92 = FLAT_SIMPLEX_GRAD[(var25) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var25) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var25) | 2] * var62;
+ final double var93 = FLAT_SIMPLEX_GRAD[(var26) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var26) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var26) | 2] * var62;
+ final double var94 = FLAT_SIMPLEX_GRAD[(var27) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var27) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var27) | 2] * var62;
+
+ final double var95 = deltaX * 6.0 - 15.0;
+ final double var96 = deltaY * 6.0 - 15.0;
+ final double var97 = deltaZ * 6.0 - 15.0;
+ final double var98 = deltaX * var95 + 10.0;
+ final double var99 = deltaY * var96 + 10.0;
+ final double var100 = deltaZ * var97 + 10.0;
+ final double var101 = deltaX * deltaX * deltaX * var98;
+ final double var102 = deltaY * deltaY * deltaY * var99;
+ final double var103 = deltaZ * deltaZ * deltaZ * var100;
+
+ final double var113 = var87 + var101 * (var88 - var87);
+ final double var114 = var93 + var101 * (var94 - var93);
+ final double var115 = var91 + var101 * (var92 - var91);
+ final double var116 = var89 + var101 * (var90 - var89);
+ final double var117 = var114 - var115;
+ final double var118 = var102 * (var116 - var113);
+ final double var119 = var102 * var117;
+ final double var120 = var113 + var118;
+ final double var121 = var115 + var119;
+ return var120 + (var103 * (var121 - var120));
+ // DivineMC end - Chunk System Optimizations
}
private double sampleWithDerivative(int gridX, int gridY, int gridZ, double deltaX, double deltaY, double deltaZ, double[] noiseValues) {
diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
index ffac5b7b1eb1364ab8442d7145a7b4ebde68ee10..d331259b0bcf2d3c27718497ff2593a29d1558d0 100644
--- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
+++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
@@ -26,6 +26,10 @@ public class PerlinNoise {
public final double lowestFreqValueFactor;
public final double lowestFreqInputFactor;
private final double maxValue;
+ // DivineMC start - Chunk System Optimizations
+ private final int octaveSamplersCount;
+ private final double [] amplitudesArray;
+ // DivineMC end - Chunk System Optimizations
@Deprecated
public static PerlinNoise createLegacyForBlendedNoise(RandomSource random, IntStream octaves) {
@@ -127,6 +131,10 @@ public class PerlinNoise {
this.lowestFreqInputFactor = Math.pow(2.0, -i);
this.lowestFreqValueFactor = Math.pow(2.0, size - 1) / (Math.pow(2.0, size) - 1.0);
this.maxValue = this.edgeValue(2.0);
+ // DivineMC start - Chunk System Optimizations
+ this.octaveSamplersCount = this.noiseLevels.length;
+ this.amplitudesArray = this.amplitudes.toDoubleArray();
+ // DivineMC end - Chunk System Optimizations
}
protected double maxValue() {
@@ -138,7 +146,26 @@ public class PerlinNoise {
}
public double getValue(double x, double y, double z) {
- return this.getValue(x, y, z, 0.0, 0.0, false);
+ // DivineMC start - Chunk System Optimizations
+ double d = 0.0;
+ double e = this.lowestFreqInputFactor;
+ double f = this.lowestFreqValueFactor;
+
+ for (int i = 0; i < this.octaveSamplersCount; ++i) {
+ ImprovedNoise perlinNoiseSampler = this.noiseLevels[i];
+ if (perlinNoiseSampler != null) {
+ double g = perlinNoiseSampler.noise(
+ wrap(x * e), wrap(y * e), wrap(z * e), 0.0, 0.0
+ );
+ d += this.amplitudesArray[i] * g * f;
+ }
+
+ e *= 2.0;
+ f /= 2.0;
+ }
+
+ return d;
+ // DivineMC end - Chunk System Optimizations
}
@Deprecated
@@ -187,7 +214,7 @@ public class PerlinNoise {
}
public static double wrap(double value) {
- return value - Mth.lfloor(value / 3.3554432E7 + 0.5) * 3.3554432E7;
+ return value - Math.floor(value / 3.3554432E7 + 0.5) * 3.3554432E7; // DivineMC - Chunk System Optimizations
}
protected int firstOctave() {
diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java
index 66d0a6390febe929ef774b0a7813329015bc8cc2..d1917dee4ca6bba5f2c92475811c724caf2948cb 100644
--- a/net/minecraft/world/ticks/LevelChunkTicks.java
+++ b/net/minecraft/world/ticks/LevelChunkTicks.java
@@ -14,10 +14,10 @@ import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickContainerAccess<T>, ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks { // Paper - rewrite chunk system
- private final Queue<ScheduledTick<T>> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER);
+ private final Queue<ScheduledTick<T>> tickQueue = new java.util.concurrent.PriorityBlockingQueue<>(11, ScheduledTick.DRAIN_ORDER); // DivineMC - Chunk System Optimizations
@Nullable
private List<SavedTick<T>> pendingTicks;
- private final Set<ScheduledTick<?>> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Set<ScheduledTick<?>> ticksPerPosition = it.unimi.dsi.fastutil.objects.ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH)); // DivineMC - Chunk System Optimizations
@Nullable
private BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> onTickAdded;
@@ -67,10 +67,18 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
@Nullable
public ScheduledTick<T> poll() {
- ScheduledTick<T> scheduledTick = this.tickQueue.poll();
- if (scheduledTick != null) {
- this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system
+ // DivineMC start - Chunk System Optimizations
+ ScheduledTick<T> scheduledTick = null;
+ try {
+ scheduledTick = this.tickQueue.poll();
+ if (scheduledTick != null) {
+ this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system
+ }
+ } catch (Exception e) {
+ net.minecraft.server.MinecraftServer.LOGGER.error("Encountered caught exception when polling chunk ticks, blocking and returning null.", e);
+ return null;
}
+ // DivineMC end - Chunk System Optimizations
return scheduledTick;
}
@@ -83,6 +91,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
private void scheduleUnchecked(ScheduledTick<T> tick) {
+ if (tick == null) return; // DivineMC - Chunk System Optimizations
this.tickQueue.add(tick);
if (this.onTickAdded != null) {
this.onTickAdded.accept(this, tick);
@@ -124,6 +133,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
for (ScheduledTick<T> scheduledTick : this.tickQueue) {
+ if (scheduledTick == null) continue; // DivineMC - Chunk System Optimizations - fix NPE
list.add(scheduledTick.toSavedTick(gametime));
}
diff --git a/net/minecraft/world/ticks/LevelTicks.java b/net/minecraft/world/ticks/LevelTicks.java
index 0a9805d42142678ca5213c511235daa6505ddbf3..6e3d4e78a7d92a846e68fe60271cfe5a5cd7b569 100644
--- a/net/minecraft/world/ticks/LevelTicks.java
+++ b/net/minecraft/world/ticks/LevelTicks.java
@@ -30,17 +30,18 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
private static final Comparator<LevelChunkTicks<?>> CONTAINER_DRAIN_ORDER = (levelChunkTicks, levelChunkTicks1) -> ScheduledTick.INTRA_TICK_DRAIN_ORDER
.compare(levelChunkTicks.peek(), levelChunkTicks1.peek());
private final LongPredicate tickCheck;
- private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = new Long2ObjectOpenHashMap<>();
- private final Long2LongMap nextTickForContainer = Util.make(new Long2LongOpenHashMap(), map -> map.defaultReturnValue(Long.MAX_VALUE));
- private final Queue<LevelChunkTicks<T>> containersToTick = new PriorityQueue<>(CONTAINER_DRAIN_ORDER);
- private final Queue<ScheduledTick<T>> toRunThisTick = new ArrayDeque<>();
+ private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = it.unimi.dsi.fastutil.longs.Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); // DivineMC - Chunk System Optimizations
+ private final java.util.Map<Long, Long> nextTickForContainer = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Chunk System Optimizations
+ private final Queue<LevelChunkTicks<T>> containersToTick = new java.util.concurrent.PriorityBlockingQueue<>(11, CONTAINER_DRAIN_ORDER); // DivineMC - Chunk System Optimizations
+ private final Queue<ScheduledTick<T>> toRunThisTick = new java.util.concurrent.ConcurrentLinkedQueue<>(); // DivineMC - Chunk System Optimizations
private final List<ScheduledTick<T>> alreadyRunThisTick = new ArrayList<>();
- private final Set<ScheduledTick<?>> toRunThisTickSet = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Set<ScheduledTick<?>> toRunThisTickSet = com.google.common.collect.Sets.newConcurrentHashSet(); // DivineMC - Chunk System Optimizations
private final BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> chunkScheduleUpdater = (levelChunkTicks, scheduledTick) -> {
if (scheduledTick.equals(levelChunkTicks.peek())) {
this.updateContainerScheduling(scheduledTick);
}
};
+ private final java.util.concurrent.atomic.AtomicInteger toRunThisTickCount = new java.util.concurrent.atomic.AtomicInteger(0); // DivineMC - Chunk System Optimizations
public LevelTicks(LongPredicate tickCheck) {
this.tickCheck = tickCheck;
@@ -90,12 +91,14 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
}
private void sortContainersToTick(long gameTime) {
- ObjectIterator<Entry> objectIterator = Long2LongMaps.fastIterator(this.nextTickForContainer);
+ java.util.Iterator<java.util.Map.Entry<Long, Long>> objectIterator = this.nextTickForContainer.entrySet().iterator(); // DivineMC - Chunk System Optimizations
while (objectIterator.hasNext()) {
- Entry entry = objectIterator.next();
- long longKey = entry.getLongKey();
- long longValue = entry.getLongValue();
+ // DivineMC start - Chunk System Optimizations
+ java.util.Map.Entry<Long, Long> entry = objectIterator.next();
+ long longKey = entry.getKey();
+ long longValue = entry.getValue();
+ // DivineMC end - Chunk System Optimizations
if (longValue <= gameTime) {
LevelChunkTicks<T> levelChunkTicks = this.allContainers.get(longKey);
if (levelChunkTicks == null) {
@@ -162,16 +165,19 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
}
private void scheduleForThisTick(ScheduledTick<T> tick) {
+ if (tick == null) return; // DivineMC - Chunk System Optimizations
this.toRunThisTick.add(tick);
+ this.toRunThisTickCount.incrementAndGet(); // DivineMC - Chunk System Optimizations
}
private boolean canScheduleMoreTicks(int maxAllowedTicks) {
- return this.toRunThisTick.size() < maxAllowedTicks;
+ return this.toRunThisTickCount.get() < maxAllowedTicks; // DivineMC - Chunk System Optimizations
}
private void runCollectedTicks(BiConsumer<BlockPos, T> ticker) {
while (!this.toRunThisTick.isEmpty()) {
ScheduledTick<T> scheduledTick = this.toRunThisTick.poll();
+ this.toRunThisTickCount.decrementAndGet(); // DivineMC - Chunk System Optimizations
if (!this.toRunThisTickSet.isEmpty()) {
this.toRunThisTickSet.remove(scheduledTick);
}
@@ -182,7 +188,7 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
}
private void cleanupAfterTick() {
- this.toRunThisTick.clear();
+ this.toRunThisTickCount.set(0); // DivineMC - Chunk System Optimizations
this.containersToTick.clear();
this.alreadyRunThisTick.clear();
this.toRunThisTickSet.clear();