Allow world gen limits on singleplayer

This commit is contained in:
James Seibel
2025-12-10 07:09:29 -06:00
parent c1c4328fa5
commit 8f0930fa02
10 changed files with 121 additions and 53 deletions
@@ -1362,6 +1362,37 @@ public class Config
+ "")
.build();
public static ConfigEntry<Integer> generationCenterChunkX = new ConfigEntry.Builder<Integer>()
.setChatCommandName("generation.bounds.centerChunk.x")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.setMinDefaultMax(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)
.comment("" +
"The center X chunk position that the world gen max radius is centered around. \n" +
"")
.build();
public static ConfigEntry<Integer> generationCenterChunkZ = new ConfigEntry.Builder<Integer>()
.setChatCommandName("generation.bounds.centerChunk.z")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.setMinDefaultMax(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)
.comment("" +
"The center Z chunk position that the world gen max radius is centered around. \n" +
"")
.build();
public static ConfigEntry<Integer> generationMaxChunkRadius = new ConfigEntry.Builder<Integer>()
.setChatCommandName("generation.bounds.radiusInChunks")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.setMinDefaultMax(0, 0, Integer.MAX_VALUE)
.comment("" +
"The max radius in chunks around the central point where world generation is allowed. \n" +
"If this value is set to 0, generation bounds are disabled and the render distance will be used. \n" +
"\n" +
"This should only be set if you have a pre-generated world that has a very limited size. \n" +
"Setting this on a normal MC world will prevent the world generator from filling \n" +
"out your render distance. \n" +
"")
.build();
}
public static class LodBuilding
@@ -1686,32 +1717,6 @@ public class Config
"")
.build();
public static ConfigEntry<Integer> generationBoundsX = new ConfigEntry.Builder<Integer>()
.setChatCommandName("generation.bounds.x")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.setMinDefaultMax(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)
.comment("" +
"Defines the X-coordinate of the central point for generation boundaries, in blocks. \n" +
"")
.build();
public static ConfigEntry<Integer> generationBoundsZ = new ConfigEntry.Builder<Integer>()
.setChatCommandName("generation.bounds.z")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.setMinDefaultMax(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)
.comment("" +
"Defines the Z-coordinate of the central point for generation boundaries, in blocks. \n" +
"")
.build();
public static ConfigEntry<Integer> generationBoundsRadius = new ConfigEntry.Builder<Integer>()
.setChatCommandName("generation.bounds.radius")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.setMinDefaultMax(0, 0, Integer.MAX_VALUE)
.comment("" +
"Defines the radius around the central point within which generation is allowed, in blocks. \n" +
"If this value is set to 0, generation bounds are disabled." +
"")
.build();
// Real-time updates
public static ConfigEntry<Boolean> enableRealTimeUpdates = new ConfigEntry.Builder<Boolean>()
@@ -0,0 +1,12 @@
package com.seibel.distanthorizons.core.enums;
/**
* TODO
* might be deprecated in the future? in that case we'll probably want a wrapper
* function to handle colors for new MC versions
*
* source: https://minecraft.wiki/w/Formatting_codes
*/
public class EMinecraftColor
{
}
@@ -11,6 +11,7 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.WorldGenUtil;
import com.seibel.distanthorizons.core.util.objects.RollingAverage;
import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -110,12 +111,14 @@ public class RemoteWorldRetrievalQueue extends AbstractFullDataNetworkRequestQue
@Override
protected boolean isSectionAllowedToGenerate(long sectionPos, DhBlockPos2D targetPos)
{
if (this.networkState.sessionConfig.getGenerationBoundsRadius() > 0)
if (this.networkState.sessionConfig.getGenerationMaxChunkRadius() > 0)
{
if (DhSectionPos.getChebyshevSignedBlockDistance(sectionPos, new DhBlockPos2D(
this.networkState.sessionConfig.getGenerationBoundsX(),
this.networkState.sessionConfig.getGenerationBoundsZ()
)) > this.networkState.sessionConfig.getGenerationBoundsRadius())
boolean posInRange = WorldGenUtil.isPosInWorldGenRange(
sectionPos,
this.networkState.sessionConfig.getGenerationCenterChunkX(), this.networkState.sessionConfig.getGenerationCenterChunkZ(),
this.networkState.sessionConfig.getGenerationMaxChunkRadius()
);
if (!posInRange)
{
return false;
}
@@ -21,6 +21,7 @@ import com.seibel.distanthorizons.core.network.messages.requests.CancelMessage;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.WorldGenUtil;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
@@ -147,16 +148,15 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
return;
}
if (Config.Server.generationBoundsRadius.get() > 0)
boolean posInRange = WorldGenUtil.isPosInWorldGenRange(
message.sectionPos,
Config.Common.WorldGenerator.generationCenterChunkX.get(), Config.Common.WorldGenerator.generationCenterChunkZ.get(),
Config.Common.WorldGenerator.generationMaxChunkRadius.get()
);
if (!posInRange)
{
if (DhSectionPos.getChebyshevSignedBlockDistance(message.sectionPos, new DhBlockPos2D(
serverPlayerState.sessionConfig.getGenerationBoundsX(),
serverPlayerState.sessionConfig.getGenerationBoundsZ()
)) > Config.Server.generationBoundsRadius.get())
{
message.sendResponse(new RequestOutOfRangeException("Section out of allowed bounds"));
return;
}
message.sendResponse(new RequestOutOfRangeException("Section out of allowed bounds"));
return;
}
if (!Config.Server.Experimental.enableNSizedGeneration.get() && DhSectionPos.getDetailLevel(message.sectionPos) != DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
@@ -33,9 +33,9 @@ public class SessionConfig implements INetworkObject
registerConfigEntry(Config.Common.WorldGenerator.enableDistantGeneration, Boolean::logicalAnd);
registerConfigEntry(Config.Server.maxGenerationRequestDistance, Math::min);
registerConfigEntry(Config.Server.generationBoundsX, (x, y) -> y);
registerConfigEntry(Config.Server.generationBoundsZ, (x, y) -> y);
registerConfigEntry(Config.Server.generationBoundsRadius, (x, y) -> y);
registerConfigEntry(Config.Common.WorldGenerator.generationCenterChunkX, (x, y) -> y);
registerConfigEntry(Config.Common.WorldGenerator.generationCenterChunkZ, (x, y) -> y);
registerConfigEntry(Config.Common.WorldGenerator.generationMaxChunkRadius, (x, y) -> y);
registerConfigEntry(Config.Server.generationRequestRateLimit, Math::min);
registerConfigEntry(Config.Server.enableRealTimeUpdates, Boolean::logicalAnd);
@@ -68,9 +68,9 @@ public class SessionConfig implements INetworkObject
public boolean isDistantGenerationEnabled() { return this.getValue(Config.Common.WorldGenerator.enableDistantGeneration); }
public int getMaxGenerationRequestDistance() { return this.getValue(Config.Server.maxGenerationRequestDistance); }
public Integer getGenerationBoundsX() { return this.getValue(Config.Server.generationBoundsX); }
public Integer getGenerationBoundsZ() { return this.getValue(Config.Server.generationBoundsZ); }
public Integer getGenerationBoundsRadius() { return this.getValue(Config.Server.generationBoundsRadius); }
public Integer getGenerationCenterChunkX() { return this.getValue(Config.Common.WorldGenerator.generationCenterChunkX); }
public Integer getGenerationCenterChunkZ() { return this.getValue(Config.Common.WorldGenerator.generationCenterChunkZ); }
public Integer getGenerationMaxChunkRadius() { return this.getValue(Config.Common.WorldGenerator.generationMaxChunkRadius); }
public int getGenerationRequestRateLimit() { return this.getValue(Config.Server.generationRequestRateLimit); }
public boolean isRealTimeUpdatesEnabled() { return this.getValue(Config.Server.enableRealTimeUpdates); }
@@ -102,8 +102,8 @@ public class ServerPlayerState implements Closeable
private void sendConfigMessage()
{
double coordinateScale = this.getServerPlayer().getLevel().getDimensionType().getCoordinateScale();
this.sessionConfig.constrainValue(Config.Server.generationBoundsX, (int) (Config.Server.generationBoundsX.get() / coordinateScale));
this.sessionConfig.constrainValue(Config.Server.generationBoundsZ, (int) (Config.Server.generationBoundsZ.get() / coordinateScale));
this.sessionConfig.constrainValue(Config.Common.WorldGenerator.generationCenterChunkX, (int) (Config.Common.WorldGenerator.generationCenterChunkX.get() / coordinateScale));
this.sessionConfig.constrainValue(Config.Common.WorldGenerator.generationCenterChunkZ, (int) (Config.Common.WorldGenerator.generationCenterChunkZ.get() / coordinateScale));
this.networkSession.sendMessage(new SessionConfigMessage(this.sessionConfig));
}
@@ -281,17 +281,22 @@ public class DhSectionPos
+ Math.abs(getCenterBlockPosZ(pos) - blockPos.z);
}
public static int getChebyshevSignedBlockDistance(long pos, DhBlockPos2D blockPos)
{
return getChebyshevSignedBlockDistance(pos, blockPos);
}
/**
* Returns the signed distance from a given block to a given section. <br>
* Essentially acts like a distance from the block to the nearest edge of the section,
* except inside the section it's negative. <br>
* Useful for detail level insensitive distance comparisons.
*/
public static int getChebyshevSignedBlockDistance(long pos, DhBlockPos2D blockPos)
public static int getChebyshevSignedBlockDistance(long pos, DhBlockPos blockPos)
{
return Math.max(
Math.abs(getCenterBlockPosX(pos) - blockPos.x),
Math.abs(getCenterBlockPosZ(pos) - blockPos.z)
Math.abs(getCenterBlockPosX(pos) - blockPos.getX()),
Math.abs(getCenterBlockPosZ(pos) - blockPos.getZ())
) - getBlockWidth(pos) / 2;
}
@@ -762,7 +762,6 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
{
// walk through each node
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.nodeIterator();
ArrayList<CompletableFuture<Void>> renderDataBuildFutures = new ArrayList<>();
while (nodeIterator.hasNext())
{
QuadNode<LodRenderSection> quadNode = nodeIterator.next();
@@ -42,7 +42,7 @@ import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
import com.seibel.distanthorizons.core.render.renderer.generic.BeaconRenderHandler;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo;
import com.seibel.distanthorizons.core.util.PerfRecorder;
import com.seibel.distanthorizons.core.util.WorldGenUtil;
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -528,6 +528,18 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
}
long pos = missingGenerationPos.removeLong(i);
boolean posInRange = WorldGenUtil.isPosInWorldGenRange(
pos,
Config.Common.WorldGenerator.generationCenterChunkX.get(), Config.Common.WorldGenerator.generationCenterChunkZ.get(),
Config.Common.WorldGenerator.generationMaxChunkRadius.get()
);
if (!posInRange)
{
continue;
}
boolean positionQueued = (this.fullDataSourceProvider.queuePositionForRetrieval(pos) != null);
if (!positionQueued)
{
@@ -0,0 +1,32 @@
package com.seibel.distanthorizons.core.util;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
public class WorldGenUtil
{
/** will always return true if a generation max radius isn't set */
public static boolean isPosInWorldGenRange(
long requestedPos,
int centerChunkX, int centerChunkZ,
int maxChunkRadius)
{
if (Config.Common.WorldGenerator.generationMaxChunkRadius.get() <= 0)
{
return true;
}
DhBlockPos centerBlockPos = new DhChunkPos(centerChunkX, centerChunkZ).centerBlockPos();
int blockDistanceFromCenter = DhSectionPos.getChebyshevSignedBlockDistance(requestedPos, centerBlockPos);
int maxBlockRadius = maxChunkRadius * LodUtil.CHUNK_WIDTH;
boolean requestInRadius = (blockDistanceFromCenter <= maxBlockRadius);
return requestInRadius;
}
}