diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java
index 657e15ea6..e43640288 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.common.wrappers.chunk;
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.LodUtil;
@@ -40,13 +41,11 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.levelgen.Heightmap;
-import org.jetbrains.annotations.Nullable;
-
import java.util.*;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
#if POST_MC_1_17_1
import net.minecraft.core.QuartPos;
+import org.apache.logging.log4j.Logger;
#endif
#if POST_MC_1_20_1
@@ -57,6 +56,8 @@ import net.minecraft.core.SectionPos;
public class ChunkWrapper implements IChunkWrapper
{
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
+
/** useful for debugging, but can slow down chunk operations quite a bit due to being called every time. */
private static final boolean RUN_RELATIVE_POS_INDEX_VALIDATION = false;
@@ -67,6 +68,8 @@ public class ChunkWrapper implements IChunkWrapper
private final ILevelWrapper wrappedLevel;
private boolean isDhLightCorrect = false;
+ /** only used when connected to a dedicated server */
+ private boolean isMcClientLightingCorrect = false;
private final byte[] blockLightArray;
private final byte[] skyLightArray;
@@ -76,8 +79,8 @@ public class ChunkWrapper implements IChunkWrapper
private boolean useDhLighting;
/**
- * Due to vanilla `isClientLightReady()` not designed to be used by non-render thread, that value may return 'true'
- * just before the light engine is ticked, (right after all light changes is marked to the engine to be processed).
+ * Due to vanilla `isClientLightReady()` not being designed for use by a non-render thread, it may return 'true'
+ * before the light engine has ticked, (right after all light changes is marked by the engine to be processed).
* To fix this, on client-only mode, we mixin-redirect the `isClientLightReady()` so that after the call, it will
* trigger a synchronous update of this flag here on all chunks that are wrapped.
*
@@ -86,8 +89,9 @@ public class ChunkWrapper implements IChunkWrapper
* visible when a chunk is re-wrapped later.
* (Also, thread safety done via a reader writer lock)
*/
- private final static WeakHashMap chunksToUpdateClientLightReady = new WeakHashMap<>(); // TODO this is never cleared
- private final static ReentrantReadWriteLock weakMapLock = new ReentrantReadWriteLock();
+ private static ArrayList chunksToUpdateClientLightReadyWriter = new ArrayList<>(300);
+ /** two arrays are used to prevent concurrency issues and the need to use a read/write lock. */
+ private static ArrayList chunksToUpdateClientLightReadyReader = new ArrayList<>(300);
@@ -111,9 +115,7 @@ public class ChunkWrapper implements IChunkWrapper
this.blockLightArray = new byte[LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH * (this.getHeight() + 1)];
this.skyLightArray = new byte[LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH * (this.getHeight() + 1)];
- weakMapLock.writeLock().lock();
- chunksToUpdateClientLightReady.put(chunk, false);
- weakMapLock.writeLock().unlock();
+ chunksToUpdateClientLightReadyWriter.add(this);
}
@@ -218,14 +220,14 @@ public class ChunkWrapper implements IChunkWrapper
LevelChunk levelChunk = (LevelChunk) this.chunk;
if (levelChunk.getLevel().isClientSide())
{
- weakMapLock.readLock().lock();
- boolean fixedIsClientLightReady = chunksToUpdateClientLightReady.get(this.chunk);
- weakMapLock.readLock().unlock();
- return fixedIsClientLightReady;
+ // connected to a server
+ return this.isMcClientLightingCorrect;
+ }
+ else
+ {
+ // in a single player world
+ return this.chunk.isLightCorrect() && levelChunk.loaded;
}
-
- // called when in single player or in dedicated server, and the chunk is a level chunk (active)
- return this.chunk.isLightCorrect() && levelChunk.loaded;
}
else
{
@@ -395,14 +397,37 @@ public class ChunkWrapper implements IChunkWrapper
}
#endif
- // Should be called after client light updates are triggered.
- private static boolean updateClientLightReady(ChunkAccess chunk, boolean oldValue)
+
+ public static void syncedUpdateClientLightStatus()
{
- if (chunk instanceof LevelChunk && ((LevelChunk) chunk).getLevel() instanceof ClientLevel)
+ #if PRE_MC_1_18_2
+ // TODO: Check what to do in 1.18.1 and older
+ #else
+
+ // swap the buffers
+ ArrayList temp = chunksToUpdateClientLightReadyReader;
+ chunksToUpdateClientLightReadyReader = chunksToUpdateClientLightReadyWriter;
+ chunksToUpdateClientLightReadyWriter = temp;
+
+ // update the chunks client lighting
+ for (ChunkWrapper chunkWrapper : chunksToUpdateClientLightReadyReader)
{
- LevelChunk levelChunk = (LevelChunk) chunk;
+ chunkWrapper.updateIsClientLightingCorrect();
+ }
+ // remove the processed chunks.
+ // FIXME sometimes chunks will be processed slightly early and will be removed even if they have valid lighting, this can cause holes in the world when flying around.
+ chunksToUpdateClientLightReadyReader.clear();
+
+ #endif
+ }
+ /** Should be called after client light updates are triggered. */
+ private void updateIsClientLightingCorrect()
+ {
+ if (this.chunk instanceof LevelChunk && ((LevelChunk) this.chunk).getLevel() instanceof ClientLevel)
+ {
+ LevelChunk levelChunk = (LevelChunk) this.chunk;
ClientChunkCache clientChunkCache = ((ClientLevel) levelChunk.getLevel()).getChunkSource();
- return clientChunkCache.getChunkForLighting(chunk.getPos().x, chunk.getPos().z) != null &&
+ this.isMcClientLightingCorrect = clientChunkCache.getChunkForLighting(this.chunk.getPos().x, this.chunk.getPos().z) != null &&
#if MC_1_16_5 || MC_1_17_1
levelChunk.isLightCorrect();
#elif PRE_MC_1_20_1
@@ -411,27 +436,6 @@ public class ChunkWrapper implements IChunkWrapper
checkLightSectionsOnChunk(levelChunk, levelChunk.getLevel().getLightEngine());
#endif
}
- else
- {
- return oldValue;
- }
- }
-
- public static void syncedUpdateClientLightStatus()
- {
- #if PRE_MC_1_18_2
- // TODO: Check what to do in 1.18.1, or in other versions
- #else
- weakMapLock.writeLock().lock();
- try
- {
- chunksToUpdateClientLightReady.replaceAll(ChunkWrapper::updateClientLightReady);
- }
- finally
- {
- weakMapLock.writeLock().unlock();
- }
- #endif
}
diff --git a/coreSubProjects b/coreSubProjects
index 025484d5b..87572246a 160000
--- a/coreSubProjects
+++ b/coreSubProjects
@@ -1 +1 @@
-Subproject commit 025484d5b4ba1341e7d16ba93c3fc50fb108c0de
+Subproject commit 87572246a6323c6e5a35d8131552dde845d28195
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
index 9d0cfe32e..b1ca87de6 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
@@ -131,7 +131,7 @@ public class FabricClientProxy
LOGGER.trace("attack block at blockPos: " + blockPos);
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
- ClientApi.INSTANCE.clientChunkLoadEvent(
+ ClientApi.INSTANCE.clientChunkBlockChangedEvent(
new ChunkWrapper(chunk, level, wrappedLevel),
wrappedLevel
);
@@ -158,7 +158,7 @@ public class FabricClientProxy
LOGGER.trace("use block at blockPos: " + hitResult.getBlockPos());
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
- ClientApi.INSTANCE.clientChunkLoadEvent(
+ ClientApi.INSTANCE.clientChunkBlockChangedEvent(
new ChunkWrapper(chunk, level, wrappedLevel),
wrappedLevel
);
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
index 8732fbcdb..c13e7a704 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
@@ -191,7 +191,7 @@ public class ForgeClientProxy
if (chunk != null)
{
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
- ClientApi.INSTANCE.clientChunkLoadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
+ ClientApi.INSTANCE.clientChunkBlockChangedEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
}
}
}