diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index d3deec96c..710bcc2c6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -165,7 +165,7 @@ public class Config .setMinDefaultMax(32, 128, 4096) .comment("" + "The radius of the mod's render distance. (measured in chunks)\n" + - "On server changes the distance players will receive real time updates for, if enabled." + + "On server changes the distance players will receive real-time updates for, if enabled." + "\n" + "Note for servers:\n" + "This setting does not prevent players from generating farther out.\n" + @@ -1013,11 +1013,12 @@ public class Config public static ConfigUIComment generationSectionNote = new ConfigUIComment(); - public static ConfigEntry generationRequestRCLimit = new ConfigEntry.Builder() - .setServersideShortName("generationRequestRCLimit") + public static ConfigEntry generationRequestRateLimit = new ConfigEntry.Builder() + .setServersideShortName("generationRequestRateLimit") .setMinDefaultMax(1, 20, 100) .comment("" - + "Limits the amount of generation requests the server will handle." + + "How many LOD generation requests per second should a client send? \n" + + "Also limits the amount of player's requests allowed to stay in the server's queue." + "") .build(); @@ -1032,20 +1033,21 @@ public class Config .build(); - public static ConfigUIComment loginDataSyncSectionNote = new ConfigUIComment(); - public static ConfigEntry enableLoginDataSync = new ConfigEntry.Builder() - .setServersideShortName("enableLoginDataSync") + public static ConfigUIComment syncOnLoginSectionNote = new ConfigUIComment(); + public static ConfigEntry synchronizeOnLogin = new ConfigEntry.Builder() + .setServersideShortName("synchronizeOnLogin") .set(false) .comment("" - + "If true, clients will receive updated LODs on join if any changes occured since last join." + + "If true, clients will receive updated LODs on join if any changes occurred since last join." + "") .build(); - public static ConfigEntry loginDataSyncRCLimit = new ConfigEntry.Builder() - .setServersideShortName("loginDataSyncRCLimit") + public static ConfigEntry syncOnLoginRateLimit = new ConfigEntry.Builder() + .setServersideShortName("syncOnLoginRateLimit") .setMinDefaultMax(1, 50, 100) .comment("" - + "Limits the amount of sent/processed LOD *update* requests concurrently, per player." + + "How many LOD sync requests per second should a client send? \n" + + "Also limits the amount of player's requests allowed to stay in the server's queue." + "") .build(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldRemoteGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldRemoteGenerationQueue.java index 239a5eee1..eb7eba17e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldRemoteGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldRemoteGenerationQueue.java @@ -22,7 +22,7 @@ public class WorldRemoteGenerationQueue extends AbstractFullDataRequestQueue imp @Override - protected int getRequestConcurrencyLimit() { return this.networkState.config.fullDataRequestConcurrencyLimit; } + protected int getRequestRateLimit() { return this.networkState.config.generationRequestRateLimit; } @Override protected String getQueueName() { return "World Remote Generation Queue"; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index e14272c28..84f577c08 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -117,7 +117,7 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel return; } - if (!rateLimiterSet.fullDataRequestConcurrencyLimiter.tryAcquire(msg)) + if (!rateLimiterSet.generationRequestRateLimiter.tryAcquire(msg)) { return; } @@ -149,13 +149,13 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel { // Sync only - if (!serverPlayerState.config.isLoginDataSyncEnabled()) + if (!serverPlayerState.config.getSynchronizeOnLogin()) { msg.sendResponse(new RequestRejectedException("Operation is disabled from config.")); return; } - if (!rateLimiterSet.loginDataSyncRCLimiter.tryAcquire(msg)) + if (!rateLimiterSet.syncOnLoginRateLimiter.tryAcquire(msg)) { return; } @@ -163,7 +163,7 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel Long serverTimestamp = this.serverside.fullDataFileHandler.getTimestampForPos(msg.sectionPos); if (serverTimestamp == null || serverTimestamp <= msg.clientTimestamp) { - rateLimiterSet.loginDataSyncRCLimiter.release(); + rateLimiterSet.syncOnLoginRateLimiter.release(); msg.sendResponse(new FullDataSourceResponseMessage(null)); return; } @@ -176,7 +176,7 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel } this.serverside.fullDataFileHandler.getAsync(msg.sectionPos).thenAcceptAsync(fullDataSource -> { - rateLimiterSet.loginDataSyncRCLimiter.release(); + rateLimiterSet.syncOnLoginRateLimiter.release(); FullDataPayload payload = new FullDataPayload(fullDataSource); payload.acceptInChunkMessages(FULL_DATA_CHUNK_SIZE, msg.getSession()::sendMessage); @@ -200,7 +200,7 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel requestGroup.requestAddSemaphore.acquireUninterruptibly(Short.MAX_VALUE); requestGroup.requestRemoveSemaphore.release(); - serverPlayerState.getRateLimiterSet(this).fullDataRequestConcurrencyLimiter.release(); + serverPlayerState.getRateLimiterSet(this).generationRequestRateLimiter.release(); FullDataSourceRequestMessage requestMessage = requestGroup.requestMessages.remove(msg.futureId); if (requestGroup.requestMessages.isEmpty()) @@ -305,7 +305,7 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel continue; } - serverPlayerState.getRateLimiterSet(this).fullDataRequestConcurrencyLimiter.release(); + serverPlayerState.getRateLimiterSet(this).generationRequestRateLimiter.release(); payload.acceptInChunkMessages(FULL_DATA_CHUNK_SIZE, msg.getSession()::sendMessage); msg.sendResponse(new FullDataSourceResponseMessage(payload)); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataRequestQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataRequestQueue.java index 7455b9b15..aea3b836d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataRequestQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataRequestQueue.java @@ -54,7 +54,7 @@ public abstract class AbstractFullDataRequestQueue implements IDebugRenderable, private final AtomicInteger failedRequests = new AtomicInteger(); private final ConfigEntry showDebugWireframeConfig; - private final SupplierBasedRateLimiter rateLimiter = new SupplierBasedRateLimiter<>(this::getRequestConcurrencyLimit); + private final SupplierBasedRateLimiter rateLimiter = new SupplierBasedRateLimiter<>(this::getRequestRateLimit); private final ScheduledExecutorService taskFinishScheduler = Executors.newScheduledThreadPool(1); @@ -62,7 +62,7 @@ public abstract class AbstractFullDataRequestQueue implements IDebugRenderable, @SuppressWarnings("BooleanMethodIsAlwaysInverted") protected boolean showInDebug() { return true; } - protected abstract int getRequestConcurrencyLimit(); + protected abstract int getRequestRateLimit(); protected abstract String getQueueName(); @@ -104,7 +104,7 @@ public abstract class AbstractFullDataRequestQueue implements IDebugRenderable, } while (this.getWaitingTaskCount() > this.getInProgressTaskCount() - && this.getInProgressTaskCount() < this.getRequestConcurrencyLimit() + && this.getInProgressTaskCount() < this.getRequestRateLimit() && this.pendingTasksSemaphore.tryAcquire()) { if (!this.rateLimiter.tryAcquire()) @@ -244,7 +244,7 @@ public abstract class AbstractFullDataRequestQueue implements IDebugRenderable, } messageList.add(this.getQueueName() + " [" + this.level.getClientLevelWrapper().getDimensionName() + "]"); - messageList.add("Requests: " + this.finishedRequests + " / " + (this.getWaitingTaskCount() + this.finishedRequests.get()) + " (failed: " + this.failedRequests + ", rate limit: " + this.getRequestConcurrencyLimit() + ")"); + messageList.add("Requests: " + this.finishedRequests + " / " + (this.getWaitingTaskCount() + this.finishedRequests.get()) + " (failed: " + this.failedRequests + ", rate limit: " + this.getRequestRateLimit() + ")"); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/FullDataRefreshQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/FullDataRefreshQueue.java index 58bc21d9a..17a51ad0c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/FullDataRefreshQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/FullDataRefreshQueue.java @@ -12,10 +12,10 @@ public class FullDataRefreshQueue extends AbstractFullDataRequestQueue } @Override - protected boolean showInDebug() { return this.networkState.config.loginDataSyncEnabled; } + protected boolean showInDebug() { return this.networkState.config.synchronizeOnLogin; } @Override - protected int getRequestConcurrencyLimit() { return this.networkState.config.loginDataSyncRCLimit; } + protected int getRequestRateLimit() { return this.networkState.config.syncOnLoginRateLimit; } @Override protected String getQueueName() { return "Data Refresh Queue"; } @@ -23,7 +23,7 @@ public class FullDataRefreshQueue extends AbstractFullDataRequestQueue @Override public boolean tick(DhBlockPos2D targetPos) { - if (!this.networkState.config.loginDataSyncEnabled) + if (!this.networkState.config.synchronizeOnLogin) { return false; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/AbstractMultiplayerConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/AbstractMultiplayerConfig.java index 444a53464..6bda9948e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/AbstractMultiplayerConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/AbstractMultiplayerConfig.java @@ -8,20 +8,20 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject { public abstract int getRenderDistanceRadius(); public abstract boolean isDistantGenerationEnabled(); - public abstract int getFullDataRequestConcurrencyLimit(); + public abstract int getGenerationRequestRateLimit(); public abstract boolean isRealTimeUpdatesEnabled(); - public abstract boolean isLoginDataSyncEnabled(); - public abstract int getLoginDataSyncRCLimit(); + public abstract boolean getSynchronizeOnLogin(); + public abstract int getSyncOnLoginRateLimit(); @Override public void encode(ByteBuf out) { out.writeInt(this.getRenderDistanceRadius()); out.writeBoolean(this.isDistantGenerationEnabled()); - out.writeInt(this.getFullDataRequestConcurrencyLimit()); + out.writeInt(this.getGenerationRequestRateLimit()); out.writeBoolean(this.isRealTimeUpdatesEnabled()); - out.writeBoolean(this.isLoginDataSyncEnabled()); - out.writeInt(this.getLoginDataSyncRCLimit()); + out.writeBoolean(this.getSynchronizeOnLogin()); + out.writeInt(this.getSyncOnLoginRateLimit()); } @@ -31,10 +31,10 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject return MoreObjects.toStringHelper(this) .add("renderDistanceRadius", this.getRenderDistanceRadius()) .add("distantGenerationEnabled", this.isDistantGenerationEnabled()) - .add("fullDataRequestConcurrencyLimit", this.getFullDataRequestConcurrencyLimit()) + .add("generationRequestRateLimit", this.getGenerationRequestRateLimit()) .add("realTimeUpdatesEnabled", this.isRealTimeUpdatesEnabled()) - .add("loginDataSyncEnabled", this.isLoginDataSyncEnabled()) - .add("loginDataSyncRCLimit", this.getLoginDataSyncRCLimit()) + .add("synchronizeOnLogin", this.getSynchronizeOnLogin()) + .add("syncOnLoginRateLimit", this.getSyncOnLoginRateLimit()) .toString(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfig.java index 9fef9e5d4..03f479cc1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfig.java @@ -13,17 +13,17 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig public boolean distantGenerationEnabled = Config.Client.Advanced.WorldGenerator.enableDistantGeneration.get(); @Override public boolean isDistantGenerationEnabled() { return this.distantGenerationEnabled; } - public int fullDataRequestConcurrencyLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit.get(); - @Override public int getFullDataRequestConcurrencyLimit() { return this.fullDataRequestConcurrencyLimit; } + public int generationRequestRateLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRateLimit.get(); + @Override public int getGenerationRequestRateLimit() { return this.generationRequestRateLimit; } public boolean realTimeUpdatesEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates.get(); @Override public boolean isRealTimeUpdatesEnabled() { return this.realTimeUpdatesEnabled; } - public boolean loginDataSyncEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enableLoginDataSync.get(); - @Override public boolean isLoginDataSyncEnabled() { return this.loginDataSyncEnabled; } + public boolean synchronizeOnLogin = Config.Client.Advanced.Multiplayer.ServerNetworking.synchronizeOnLogin.get(); + @Override public boolean getSynchronizeOnLogin() { return this.synchronizeOnLogin; } - public int loginDataSyncRCLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.loginDataSyncRCLimit.get(); - @Override public int getLoginDataSyncRCLimit() { return this.loginDataSyncRCLimit; } + public int syncOnLoginRateLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.syncOnLoginRateLimit.get(); + @Override public int getSyncOnLoginRateLimit() { return this.syncOnLoginRateLimit; } @Override @@ -31,10 +31,10 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig { this.renderDistanceRadius = in.readInt(); this.distantGenerationEnabled = in.readBoolean(); - this.fullDataRequestConcurrencyLimit = in.readInt(); + this.generationRequestRateLimit = in.readInt(); this.realTimeUpdatesEnabled = in.readBoolean(); - this.loginDataSyncEnabled = in.readBoolean(); - this.loginDataSyncRCLimit = in.readInt(); + this.synchronizeOnLogin = in.readBoolean(); + this.syncOnLoginRateLimit = in.readInt(); } } \ No newline at end of file diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfigChangeListener.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfigChangeListener.java index 693f97353..e035cfbf9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfigChangeListener.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/config/MultiplayerConfigChangeListener.java @@ -13,10 +13,10 @@ public class MultiplayerConfigChangeListener implements Closeable private static final ConfigEntry[] CONFIG_ENTRIES = new ConfigEntry[] { Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius, Config.Client.Advanced.WorldGenerator.enableDistantGeneration, - Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit, + Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRateLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates, - Config.Client.Advanced.Multiplayer.ServerNetworking.enableLoginDataSync, - Config.Client.Advanced.Multiplayer.ServerNetworking.loginDataSyncRCLimit, + Config.Client.Advanced.Multiplayer.ServerNetworking.synchronizeOnLogin, + Config.Client.Advanced.Multiplayer.ServerNetworking.syncOnLoginRateLimit, }; private final ArrayList changeListeners; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ConstrainedMultiplayerConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ConstrainedMultiplayerConfig.java index 544cc3963..6ab030b82 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ConstrainedMultiplayerConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ConstrainedMultiplayerConfig.java @@ -25,9 +25,9 @@ public class ConstrainedMultiplayerConfig extends AbstractMultiplayerConfig } @Override - public int getFullDataRequestConcurrencyLimit() + public int getGenerationRequestRateLimit() { - return Math.min(this.clientConfig.fullDataRequestConcurrencyLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit.get()); + return Math.min(this.clientConfig.generationRequestRateLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRateLimit.get()); } @Override @@ -37,15 +37,15 @@ public class ConstrainedMultiplayerConfig extends AbstractMultiplayerConfig } @Override - public boolean isLoginDataSyncEnabled() + public boolean getSynchronizeOnLogin() { - return this.clientConfig.loginDataSyncEnabled && Config.Client.Advanced.Multiplayer.ServerNetworking.enableLoginDataSync.get(); + return this.clientConfig.synchronizeOnLogin && Config.Client.Advanced.Multiplayer.ServerNetworking.synchronizeOnLogin.get(); } @Override - public int getLoginDataSyncRCLimit() + public int getSyncOnLoginRateLimit() { - return Math.min(this.clientConfig.loginDataSyncRCLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.loginDataSyncRCLimit.get()); + return Math.min(this.clientConfig.syncOnLoginRateLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.syncOnLoginRateLimit.get()); } @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java index 2d798bf86..106498ac7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java @@ -88,17 +88,17 @@ public class ServerPlayerState public class RateLimiterSet { - public final SupplierBasedRateAndConcurrencyLimiter fullDataRequestConcurrencyLimiter = new SupplierBasedRateAndConcurrencyLimiter<>( - () -> ServerNetworking.generationRequestRCLimit.get(), + public final SupplierBasedRateAndConcurrencyLimiter generationRequestRateLimiter = new SupplierBasedRateAndConcurrencyLimiter<>( + () -> ServerNetworking.generationRequestRateLimit.get(), msg -> { - msg.sendResponse(new RateLimitedException("Full data request rate/concurrency limit: " + ServerPlayerState.this.config.getFullDataRequestConcurrencyLimit())); + msg.sendResponse(new RateLimitedException("Full data request rate/concurrency limit: " + ServerPlayerState.this.config.getGenerationRequestRateLimit())); } ); - public final SupplierBasedRateAndConcurrencyLimiter loginDataSyncRCLimiter = new SupplierBasedRateAndConcurrencyLimiter<>( - () -> ServerNetworking.loginDataSyncRCLimit.get(), + public final SupplierBasedRateAndConcurrencyLimiter syncOnLoginRateLimiter = new SupplierBasedRateAndConcurrencyLimiter<>( + () -> ServerNetworking.syncOnLoginRateLimit.get(), msg -> { - msg.sendResponse(new RateLimitedException("Data sync rate/concurrency limit: " + ServerPlayerState.this.config.getLoginDataSyncRCLimit())); + msg.sendResponse(new RateLimitedException("Data sync rate/concurrency limit: " + ServerPlayerState.this.config.getSyncOnLoginRateLimit())); } ); diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index a05a5d2ec..e8eb64b03 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -395,24 +395,17 @@ "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generalSectionNote": " \u25cf General", "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableServerNetworking": "Enable Server Networking", "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableServerNetworking.@tooltip": "§6Attention:§r this feature is not fully implemented. \n\nIf true Distant Horizons will attempt to communicate with the connected \nserver in order to load LODs outside your vanilla render distance. \n\nNote: This requires DH to be installed on the server in order to function.", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.maxThreadPoolTasks": "Max Thread Pool Tasks", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.maxThreadPoolTasks.@tooltip": "Pauses the generation if amount of thread pool tasks is too high. \nDecrease this value if LODs don't show up for too long.\nIncrease this value if thread pool tasks often get drained completely.\nSetting this value to 0 will allow thread pool tasks to build up indefinitely.", "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationSectionNote": " \u25cf Generation", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestRCLimit": "Gen Task Rate/Concurrency Limit", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestRCLimit.@tooltip": "Limits the amount of generation requests sent by client and processed by server.", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestBeginDelay": "Generation Request Begin Delay", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestBeginDelay.@tooltip": "Adds a delay in seconds before sending LOD requests, when generation is enabled. \nIncrease this value if initial generation starts too far away.", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.realTimeUpdatesSectionNote": " \u25cf Real Time Updates", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableRealTimeUpdates": "Enable Real Time Updates", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableRealTimeUpdates.@tooltip": "Enables real time updates from server.", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.loginDataSyncSectionNote": " \u25cf Login Data Sync", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableLoginDataSync": "Synchronize LODs on Login", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableLoginDataSync.@tooltip": "Enables updating of saved LODs after login.", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.loginDataSyncRCLimit": "Login Sync Rate/Concurrency Limit", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.loginDataSyncRCLimit.@tooltip": "Limits the amount of sent/processed LOD *update* requests concurrently, per player.", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.immersivePortalsSectionNote": " \u25cf Immersive Portals", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generateMultipleDimensions": "Generate Multiple Dimensions", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generateMultipleDimensions.@tooltip": "Controls whether the players should be allowed to generate in multiple dimensions at once. \n\nFor server owners: \nAll dimensions share the same thread pool. This means that empty dimensions (i.e. without players in them) \nmay slow down the generation of non-empty ones.", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestRateLimit": "Rate Limit for Generation Requests", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestRateLimit.@tooltip": "How many LOD generation requests per second should a client send? \nAlso limits the amount of player's requests allowed to stay in the server's queue.", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.realTimeUpdatesSectionNote": " \u25cf Real-time Updates", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableRealTimeUpdates": "Enable Real-time Updates", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableRealTimeUpdates.@tooltip": "If true, the client will receive real-time LOD updates for chunks outside the client's render distance.", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.syncOnLoginSectionNote": " \u25cf Synchronization on Login", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.synchronizeOnLogin": "Synchronize LODs on Login", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.synchronizeOnLogin.@tooltip": "If true, clients will receive updated LODs on join if any changes occurred since last join.", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.syncOnLoginRateLimit": "Rate Limit for Sync on Login", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.syncOnLoginRateLimit.@tooltip": "How many LOD sync requests per second should a client send? \nAlso limits the amount of player's requests allowed to stay in the server's queue.", "distanthorizons.config.client.advanced.multiplayer.serverFolderNameMode": "Server Folder Mode", "distanthorizons.config.client.advanced.multiplayer.serverFolderNameMode.@tooltip":