mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
Upstream has released updates that appear to apply and compile correctly Purpur Changes: PurpurMC/Purpur@47e758fb Updated Upstream (Paper)
3629 lines
201 KiB
Diff
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();
|