Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 008ad52bbc | |||
| d0b44a1ffc | |||
| 4ffe430686 | |||
| 19ca97c6c1 | |||
| 3334394bfd | |||
| 180e7cd814 | |||
| 84cf4505f2 | |||
| 1d74eea3ef | |||
| 6ee2e6be25 | |||
| b5c47d67cb | |||
| ead59d0817 | |||
| 1c9229c8f1 | |||
| 968a14c6a5 | |||
| 851c7439d5 | |||
| c902357a8f | |||
| 63170078f5 | |||
| d0dd1f125b | |||
| 32950d793e | |||
| 54e9bad907 |
+18
-21
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package com.seibel.distanthorizons.common.wrappers.chunk;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
|
||||
@@ -80,6 +81,8 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
|
||||
private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
|
||||
|
||||
private static boolean heightmapThreadWarningLogged = false;
|
||||
|
||||
|
||||
private final ChunkAccess chunk;
|
||||
private final DhChunkPos chunkPos;
|
||||
@@ -107,22 +110,21 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
/**
|
||||
* Note: this constructor should be very
|
||||
* fast since it will be called frequently on the MC
|
||||
* server thread and a slow method will cause server lag.
|
||||
*/
|
||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
||||
{
|
||||
this(chunk, wrappedLevel, true);
|
||||
}
|
||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel, boolean recreateHeightmaps)
|
||||
{
|
||||
this.chunk = chunk;
|
||||
this.wrappedLevel = wrappedLevel;
|
||||
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||
|
||||
if (recreateHeightmaps)
|
||||
{
|
||||
this.createDhHeightMaps();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkWrapper copy() { return new ChunkWrapper(this.chunk, this.wrappedLevel); }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
@@ -242,11 +244,15 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
}
|
||||
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
|
||||
|
||||
@Override
|
||||
public void createDhHeightMaps()
|
||||
{
|
||||
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
|
||||
this.minNonEmptyHeight = Integer.MIN_VALUE;
|
||||
this.maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||
if (heightmapThreadWarningLogged
|
||||
&& !DhApi.isDhThread())
|
||||
{
|
||||
LOGGER.warn("ChunkWrapper Height maps created on non-DH thread ["+Thread.currentThread().getName()+"]. This may cause stuttering.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
@@ -614,15 +620,6 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// other methods //
|
||||
//===============//
|
||||
|
||||
@Override
|
||||
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
+1
-7
@@ -203,19 +203,13 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GLProxy.hasInstance())
|
||||
{
|
||||
// rendering setup hasn't finished
|
||||
return;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
player.sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||
#elif MC_VER < MC_1_21_9
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
|
||||
#else
|
||||
|
||||
GLProxy.getInstance().queueRunningOnRenderThread(() ->
|
||||
GLProxy.queueRunningOnRenderThread(() ->
|
||||
{
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
|
||||
});
|
||||
|
||||
+1
-20
@@ -259,9 +259,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
#if MC_VER <= MC_1_21_10
|
||||
return this.level.dimension().location().toString();
|
||||
#else
|
||||
String namespace = this.level.dimension().identifier().getNamespace();
|
||||
String path = this.level.dimension().identifier().getPath();
|
||||
return namespace + "@@" + path;
|
||||
return this.level.dimension().identifier().toString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -297,23 +295,6 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
|
||||
if (chunk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkWrapper(chunk, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientLevel getWrappedMcObject() { return this.level; }
|
||||
|
||||
|
||||
+1
-20
@@ -187,9 +187,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
||||
#if MC_VER <= MC_1_21_10
|
||||
return this.level.dimension().location().toString();
|
||||
#else
|
||||
String namespace = this.level.dimension().identifier().getNamespace();
|
||||
String path = this.level.dimension().identifier().getPath();
|
||||
return namespace + "@@" + path;
|
||||
return this.level.dimension().identifier().toString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -225,23 +223,6 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false);
|
||||
if (chunk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkWrapper(chunk, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLevel getWrappedMcObject() { return this.level; }
|
||||
|
||||
|
||||
+39
-4
@@ -28,6 +28,7 @@ import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
@@ -37,6 +38,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
|
||||
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||
@@ -100,6 +102,15 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
|
||||
public static final int EXCEPTION_COUNTER_TRIGGER = 20;
|
||||
|
||||
/**
|
||||
* Used to revert the ignore logic in {@link SharedApi} so
|
||||
* that a given chunk pos can be handled again.
|
||||
* A timer is used so we don't have to inject into MC's code and it works sell enough
|
||||
* most of the time.
|
||||
* If a chunk does get through due the timeout not being long enough that isn't the end of the world.
|
||||
*/
|
||||
private static final int MS_TO_IGNORE_CHUNK_AFTER_COMPLETION = 5_000;
|
||||
|
||||
|
||||
|
||||
private final IDhServerLevel dhServerLevel;
|
||||
@@ -107,6 +118,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
public final InternalServerGenerator internalServerGenerator;
|
||||
public final ChunkFileReader chunkFileReader;
|
||||
|
||||
private final Timer chunkSaveIgnoreTimer = TimerUtil.CreateTimer("ChunkSaveIgnoreTimer");
|
||||
|
||||
|
||||
|
||||
public final LinkedBlockingQueue<GenerationEvent> generationEventQueue = new LinkedBlockingQueue<>();
|
||||
@@ -435,10 +448,9 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
|
||||
|
||||
|
||||
//=============================//
|
||||
//=========================//
|
||||
// process existing chunks //
|
||||
//
|
||||
//=============================//
|
||||
//=========================//
|
||||
|
||||
ArrayGridList<ChunkWrapper> chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize);
|
||||
regionChunks.forEachPos((relX, relZ) ->
|
||||
@@ -454,8 +466,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
}
|
||||
else if (chunk != null)
|
||||
{
|
||||
//
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper());
|
||||
chunkWrapper.createDhHeightMaps();
|
||||
chunkWrapperList.set(relX, relZ, chunkWrapper);
|
||||
|
||||
// try setting the wrapper's lighting
|
||||
@@ -575,6 +587,11 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
ProtoChunk protoChunk = ((ProtoChunk) chunk);
|
||||
protoChunk.setLightEngine(region.getLightEngine());
|
||||
}
|
||||
|
||||
// usually ignoring the chunk's position is unnecessary,
|
||||
// but this improves performance if a chunk update event does sneak through
|
||||
SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(chunkWrapper.getChunkPos());
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -684,6 +701,24 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
this.dhServerLevel.updateBeaconBeamsForChunkPos(centerChunkWrapper.getChunkPos(), activeBeamList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < iChunkWrapperList.size(); i++)
|
||||
{
|
||||
ChunkWrapper chunkWrapper = (ChunkWrapper) iChunkWrapperList.get(i);
|
||||
if (chunkWrapper == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// give MC a few seconds to save the chunk before
|
||||
// we can process update events there again
|
||||
this.chunkSaveIgnoreTimer.schedule(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run() { SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.removePosToIgnore(chunkWrapper.getChunkPos()); }
|
||||
}, MS_TO_IGNORE_CHUNK_AFTER_COMPLETION);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); }
|
||||
|
||||
+2
-1
@@ -51,7 +51,7 @@ public class InternalServerGenerator
|
||||
|
||||
/**
|
||||
* Used to revert the ignore logic in {@link SharedApi} so
|
||||
* that given chunk pos can be handled again.
|
||||
* that a given chunk pos can be handled again.
|
||||
* A timer is used so we don't have to inject into MC's code and it works sell enough
|
||||
* most of the time.
|
||||
* If a chunk does get through due the timeout not being long enough that isn't the end of the world.
|
||||
@@ -156,6 +156,7 @@ public class InternalServerGenerator
|
||||
if (chunk != null)
|
||||
{
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper());
|
||||
chunkWrapper.createDhHeightMaps();
|
||||
chunkWrappers.add(chunkWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -222,7 +222,8 @@ public class ChunkCompoundTagParser
|
||||
boolean hasHeightmapData = readHeightmaps(chunk, chunkData);
|
||||
|
||||
// chunk wrapper so we can pass along extra data more easily
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper(), !hasHeightmapData);
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper());
|
||||
chunkWrapper.createDhHeightMaps();
|
||||
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -293,7 +293,7 @@ public class ChunkFileReader implements AutoCloseable
|
||||
public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos)
|
||||
{
|
||||
ProtoChunk chunk = CreateProtoChunk(level, chunkPos);
|
||||
return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper(), false);
|
||||
return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper());
|
||||
}
|
||||
public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,9 @@ accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/
|
||||
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
|
||||
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
|
||||
|
||||
# getting existing chunks outside the main thread
|
||||
accessible method net/minecraft/server/level/ChunkMap getVisibleChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
|
||||
|
||||
# lod generation from save file
|
||||
accessible field net/minecraft/world/level/chunk/storage/SimpleRegionStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
||||
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
|
||||
|
||||
+1
-1
Submodule coreSubProjects updated: aabb90ada6...7c4ac2bd7e
+5
-3
@@ -67,9 +67,11 @@ public class MixinFogRenderer
|
||||
|
||||
Entity entity = camera.getEntity();
|
||||
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
|
||||
if (!isSpecialFog && cameraNotInFluid && fogMode == FogMode.FOG_TERRAIN
|
||||
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
|
||||
&& Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get())
|
||||
if (!isSpecialFog
|
||||
&& cameraNotInFluid
|
||||
&& fogMode == FogMode.FOG_TERRAIN
|
||||
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
|
||||
&& !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get())
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
|
||||
|
||||
+3
-3
@@ -5,8 +5,8 @@ org.gradle.caching=true
|
||||
|
||||
# Mod Info
|
||||
mod_name=DistantHorizons
|
||||
mod_version=2.4.2-b
|
||||
api_version=5.0.0
|
||||
mod_version=2.4.4-b
|
||||
api_version=5.1.0
|
||||
maven_group=com.seibel.distanthorizons
|
||||
mod_readable_name=Distant Horizons
|
||||
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.
|
||||
@@ -18,7 +18,7 @@ mod_issues=https://gitlab.com/jeseibel/distant-horizons/-/issues
|
||||
mod_discord=https://discord.gg/xAB8G4cENx
|
||||
|
||||
# Global Plugin Versions
|
||||
manifold_version=2025.1.27
|
||||
manifold_version=2025.1.28
|
||||
# 2023.1.17 can be used if there are mystery Java compiler issues
|
||||
nightconfig_version=3.6.6
|
||||
lz4_version=1.8.0
|
||||
|
||||
Reference in New Issue
Block a user