Add generation bounds

This commit is contained in:
s809
2025-01-18 16:42:57 +05:00
parent 54a7cbcb84
commit 3d8d8bc0f7
7 changed files with 68 additions and 7 deletions
@@ -31,7 +31,7 @@ public final class ModInfo
public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial"; public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial";
/** Incremented every time any packets are added, changed or removed, with a few exceptions. */ /** Incremented every time any packets are added, changed or removed, with a few exceptions. */
public static final int PROTOCOL_VERSION = 8; public static final int PROTOCOL_VERSION = 9;
public static final String WRAPPER_PACKET_PATH = "message"; public static final String WRAPPER_PACKET_PATH = "message";
/** The internal mod name */ /** The internal mod name */
@@ -1577,6 +1577,32 @@ public class Config
+ "") + "")
.build(); .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 // Real-time updates
public static ConfigEntry<Boolean> enableRealTimeUpdates = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> enableRealTimeUpdates = new ConfigEntry.Builder<Boolean>()
@@ -26,7 +26,7 @@ public class RemoteWorldRetrievalQueue extends AbstractFullDataNetworkRequestQue
private int estimatedTotalChunkCount; private int estimatedTotalChunkCount;
private final RollingAverage rollingAverageChunkGenTimeInMs = new RollingAverage(1_000); private final RollingAverage rollingAverageChunkGenTimeInMs = new RollingAverage(1_000);
public RollingAverage getRollingAverageChunkGenTimeInMs() { return this.rollingAverageChunkGenTimeInMs; } @Override public RollingAverage getRollingAverageChunkGenTimeInMs() { return this.rollingAverageChunkGenTimeInMs; }
@@ -96,7 +96,21 @@ public class RemoteWorldRetrievalQueue extends AbstractFullDataNetworkRequestQue
@Override @Override
protected int getRequestRateLimit() { return this.networkState.sessionConfig.getGenerationRequestRateLimit(); } protected int getRequestRateLimit() { return this.networkState.sessionConfig.getGenerationRequestRateLimit(); }
@Override @Override
protected int getMaxRequestDistance() { return this.networkState.sessionConfig.getMaxGenerationRequestDistance(); } protected boolean isSectionAllowedToGenerate(long sectionPos, DhBlockPos2D targetPos)
{
if (this.networkState.sessionConfig.getGenerationBoundsRadius() > 0)
{
if (DhSectionPos.getChebyshevSignedBlockDistance(sectionPos, new DhBlockPos2D(
this.networkState.sessionConfig.getGenerationBoundsX(),
this.networkState.sessionConfig.getGenerationBoundsZ()
)) > this.networkState.sessionConfig.getGenerationBoundsRadius())
{
return false;
}
}
return DhSectionPos.getChebyshevSignedBlockDistance(sectionPos, targetPos) <= this.networkState.sessionConfig.getMaxGenerationRequestDistance() * 16;
}
@Override @Override
protected String getQueueName() { return "World Remote Generation Queue"; } protected String getQueueName() { return "World Remote Generation Queue"; }
@@ -151,6 +151,17 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
return; return;
} }
if (Config.Server.generationBoundsRadius.get() > 0)
{
if (DhSectionPos.getChebyshevSignedBlockDistance(message.sectionPos, new DhBlockPos2D(
Config.Server.generationBoundsX.get(), Config.Server.generationBoundsZ.get()
)) > Config.Server.generationBoundsRadius.get())
{
message.sendResponse(new RequestOutOfRangeException("Section out of allowed bounds"));
return;
}
}
if (Config.Server.generateOnlyInHighestDetail.get() && DhSectionPos.getDetailLevel(message.sectionPos) != DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) if (Config.Server.generateOnlyInHighestDetail.get() && DhSectionPos.getDetailLevel(message.sectionPos) != DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
{ {
message.sendResponse(new SectionRequiresSplittingException("Only highest-detail sections are allowed")); message.sendResponse(new SectionRequiresSplittingException("Only highest-detail sections are allowed"));
@@ -95,7 +95,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende
//==================// //==================//
protected abstract int getRequestRateLimit(); protected abstract int getRequestRateLimit();
protected abstract int getMaxRequestDistance(); protected abstract boolean isSectionAllowedToGenerate(long sectionPos, DhBlockPos2D targetPos);
protected abstract String getQueueName(); protected abstract String getQueueName();
@@ -197,7 +197,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende
long sectionPos = mapEntry.getKey(); long sectionPos = mapEntry.getKey();
RequestQueueEntry entry = mapEntry.getValue(); RequestQueueEntry entry = mapEntry.getValue();
if (DhSectionPos.getChebyshevSignedBlockDistance(sectionPos, targetPos) > this.getMaxRequestDistance() * 16) if (!this.isSectionAllowedToGenerate(sectionPos, targetPos))
{ {
entry.future.cancel(false); entry.future.cancel(false);
this.pendingTasksSemaphore.release(); this.pendingTasksSemaphore.release();
@@ -406,7 +406,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende
{ {
renderer.renderBox(new DebugRenderer.Box(mapEntry.getKey(), -32f, 64f, 0.05f, renderer.renderBox(new DebugRenderer.Box(mapEntry.getKey(), -32f, 64f, 0.05f,
mapEntry.getValue().networkDataSourceFuture != null ? Color.red mapEntry.getValue().networkDataSourceFuture != null ? Color.red
: DhSectionPos.getChebyshevSignedBlockDistance(mapEntry.getKey(), Objects.requireNonNull(this.level.getTargetPosForGeneration())) <= this.getMaxRequestDistance() * 16 ? Color.gray : this.isSectionAllowedToGenerate(mapEntry.getKey(), Objects.requireNonNull(this.level.getTargetPosForGeneration())) ? Color.gray
: Color.darkGray : Color.darkGray
)); ));
} }
@@ -3,6 +3,7 @@ package com.seibel.distanthorizons.core.multiplayer.client;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue; import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
import com.seibel.distanthorizons.core.level.DhClientLevel; import com.seibel.distanthorizons.core.level.DhClientLevel;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
/** /**
@@ -32,7 +33,10 @@ public class SyncOnLoadRequestQueue extends AbstractFullDataNetworkRequestQueue
@Override @Override
protected int getRequestRateLimit() { return this.networkState.sessionConfig.getSyncOnLoginRateLimit(); } protected int getRequestRateLimit() { return this.networkState.sessionConfig.getSyncOnLoginRateLimit(); }
@Override @Override
protected int getMaxRequestDistance() { return this.networkState.sessionConfig.getMaxSyncOnLoadDistance(); } protected boolean isSectionAllowedToGenerate(long sectionPos, DhBlockPos2D targetPos)
{
return DhSectionPos.getChebyshevSignedBlockDistance(sectionPos, targetPos) <= this.networkState.sessionConfig.getMaxSyncOnLoadDistance() * 16;
}
@Override @Override
protected String getQueueName() { return "Sync On Login Queue"; } protected String getQueueName() { return "Sync On Login Queue"; }
@@ -33,6 +33,9 @@ public class SessionConfig implements INetworkObject
registerConfigEntry(Config.Common.WorldGenerator.enableDistantGeneration, Boolean::logicalAnd); registerConfigEntry(Config.Common.WorldGenerator.enableDistantGeneration, Boolean::logicalAnd);
registerConfigEntry(Config.Server.maxGenerationRequestDistance, Math::min); registerConfigEntry(Config.Server.maxGenerationRequestDistance, Math::min);
registerConfigEntry(Config.Server.generationBoundsX, (x, y) -> x);
registerConfigEntry(Config.Server.generationBoundsZ, (x, y) -> x);
registerConfigEntry(Config.Server.generationBoundsRadius, (x, y) -> x);
registerConfigEntry(Config.Server.generationRequestRateLimit, Math::min); registerConfigEntry(Config.Server.generationRequestRateLimit, Math::min);
registerConfigEntry(Config.Server.enableRealTimeUpdates, Boolean::logicalAnd); registerConfigEntry(Config.Server.enableRealTimeUpdates, Boolean::logicalAnd);
@@ -65,6 +68,9 @@ public class SessionConfig implements INetworkObject
public boolean isDistantGenerationEnabled() { return this.getValue(Config.Common.WorldGenerator.enableDistantGeneration); } public boolean isDistantGenerationEnabled() { return this.getValue(Config.Common.WorldGenerator.enableDistantGeneration); }
public int getMaxGenerationRequestDistance() { return this.getValue(Config.Server.maxGenerationRequestDistance); } 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 int getGenerationRequestRateLimit() { return this.getValue(Config.Server.generationRequestRateLimit); } public int getGenerationRequestRateLimit() { return this.getValue(Config.Server.generationRequestRateLimit); }
public boolean isRealTimeUpdatesEnabled() { return this.getValue(Config.Server.enableRealTimeUpdates); } public boolean isRealTimeUpdatesEnabled() { return this.getValue(Config.Server.enableRealTimeUpdates); }