From 3932ea21c28365ebae04deda60f6efcc971d4f96 Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Mon, 29 Jan 2024 22:36:13 +0500 Subject: [PATCH] Limit rate+concurrency instead of only concurrency Rename post-relog update to Login sync --- .editorconfig | 2 +- .../distanthorizons/core/config/Config.java | 62 ++++++++----------- .../WorldRemoteGenerationQueue.java | 2 +- .../core/level/DhServerLevel.java | 10 +-- .../client/AbstractFullDataRequestQueue.java | 12 +++- .../client/FullDataRefreshQueue.java | 4 +- .../config/AbstractMultiplayerConfig.java | 8 +-- .../multiplayer/config/MultiplayerConfig.java | 20 +++--- .../MultiplayerConfigChangeListener.java | 6 +- .../multiplayer/server/ServerPlayerState.java | 16 ++--- .../server/ServersideMultiplayerConfig.java | 11 ++-- ...upplierBasedRateAndConcurrencyLimiter.java | 39 ++++++++++++ .../SupplierBasedRateLimiter.java | 23 +++++-- .../assets/distanthorizons/lang/en_us.json | 31 +++++----- 14 files changed, 146 insertions(+), 100 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateAndConcurrencyLimiter.java diff --git a/.editorconfig b/.editorconfig index 2228be96c..4661e28bb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -537,7 +537,7 @@ ij_groovy_wrap_chain_calls_after_dot = false ij_groovy_wrap_long_lines = false [{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}] -indent_size = 4 +indent_size = 2 ij_json_array_wrapping = split_into_lines ij_json_keep_blank_lines_in_code = 0 ij_json_keep_indents_on_empty_lines = false 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 211508450..62c339f4c 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 @@ -845,7 +845,6 @@ public class Config + "") .build(); - // TODO Write strings public static class ServerNetworking { public static ConfigEntry enableServerNetworking = new ConfigEntry.Builder() @@ -862,23 +861,6 @@ public class Config + "Note: This requires DH to be installed on the server in order to function. \n" + "") .build(); - - public static ConfigEntry enableRealTimeUpdates = new ConfigEntry.Builder() - .setServersideShortName("enableRealTimeUpdates") - .set(false) - .comment("" - + "Enables real time updates from server." - + "") - .build(); - - public static ConfigEntry enablePostRelogUpdate = new ConfigEntry.Builder() - .setServersideShortName("enablePostRelogUpdate") - .set(false) - .comment("" - + "Enables updating of LODs after relog." - + "") - .build(); - public static ConfigEntry serverPort = new ConfigEntry.Builder() .setServersideShortName("serverPort") .setMinDefaultMax(1, 25049, 65535) @@ -893,16 +875,16 @@ public class Config .setMinDefaultMax(1, 10, 100) .comment("" + "Amount of rate/concurrency limit hits in one second before disconnecting the offending clients. \n" - + "Warning: too low values can cause slower clients to disconnect prematurely.\n" - + "This setting is server-only; it does not have effect on client.\n" + + "This setting is server-only; it does not have effect on the client.\n" + "") .build(); - public static ConfigEntry fullDataRequestConcurrencyLimit = new ConfigEntry.Builder() - .setServersideShortName("fullDataRequestConcurrencyLimit") + + public static ConfigEntry generationRequestRCLimit = new ConfigEntry.Builder() + .setServersideShortName("generationRequestRCLimit") .setMinDefaultMax(1, 20, 100) .comment("" - + "Limits the amount of sent/processed LOD *generation* requests concurrently on server, per player. \n" + + "Limits the amount of generation requests sent by client and processed by server. \n" + "") .build(); @@ -914,7 +896,7 @@ public class Config + "") .build(); - public static ConfigEntry fullDataRequestBeginDelay = new ConfigEntry.Builder() + public static ConfigEntry generationRequestBeginDelay = new ConfigEntry.Builder() .setMinDefaultMax(0, 3, 10) .comment("" + "Adds a delay in seconds before sending LOD requests, when generation is enabled. \n" @@ -922,25 +904,31 @@ public class Config + "") .build(); - public static ConfigEntry postRelogUpdateConcurrencyLimit = new ConfigEntry.Builder() - .setServersideShortName("postRelogUpdateConcurrencyLimit") - .setMinDefaultMax(1, 50, 100) + + public static ConfigEntry enableRealTimeUpdates = new ConfigEntry.Builder() + .setServersideShortName("enableRealTimeUpdates") + .set(false) .comment("" - + "Limits the amount of sent/processed LOD *update* requests concurrently on server, per player. \n" + + "Enables real time updates from server." + "") .build(); - /** - * Intentionally disabled. - * @see #enablePostRelogUpdate - */ - private static final ConfigEntry fullDataChangeSummaryRequestRateLimit = new ConfigEntry.Builder() - .setServersideShortName("fullDataChangeSummaryRequestRateLimit") - .setMinDefaultMax(1, 20, 100) + + public static ConfigEntry enableLoginDataSync = new ConfigEntry.Builder() + .setServersideShortName("enableLoginDataSync") + .set(false) .comment("" - + "Limits the amount of LOD updates the client can check within a second. \n" + + "Enables updating of saved LODs after login." + "") - .build(); + .build(); + + public static ConfigEntry loginDataSyncRCLimit = new ConfigEntry.Builder() + .setServersideShortName("loginDataSyncRCLimit") + .setMinDefaultMax(1, 50, 100) + .comment("" + + "Limits the amount of sent/processed LOD *update* requests concurrently, per player. \n" + + "") + .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 ee6766f38..197c5e0c5 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 @@ -30,7 +30,7 @@ public class WorldRemoteGenerationQueue extends AbstractFullDataRequestQueue imp // Used to prevent requests for section very far away, as result of request list not completely filled. // Kinda a hack, since queue is not notified when file handler is done with feeding sections to generate - private static final ConfigEntry REQUEST_BEGIN_DELAY = Config.Client.Advanced.Multiplayer.ServerNetworking.fullDataRequestBeginDelay; + private static final ConfigEntry REQUEST_BEGIN_DELAY = Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestBeginDelay; private final Stopwatch requestBeginStopwatch = Stopwatch.createStarted(); private CompletableFuture genTaskPriorityRequest = CompletableFuture.completedFuture(null); 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 be4003021..2d868fb06 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 @@ -127,15 +127,15 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel } else { - // Post-relog update + // Sync only - if (!serverPlayerState.config.isPostRelogUpdateEnabled()) + if (!serverPlayerState.config.isLoginDataSyncEnabled()) { msg.sendResponse(new RequestRejectedException("Operation is disabled from config.")); return; } - if (!serverPlayerState.postRelogUpdateRequestConcurrencyLimiter.tryAcquire(msg)) + if (!serverPlayerState.loginDataSyncRCLimiter.tryAcquire(msg)) { return; } @@ -143,14 +143,14 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel Integer serverChecksum = this.serverside.dataFileHandler.repo.getChecksumForSection(msg.sectionPos); if (serverChecksum == null || serverChecksum.equals(msg.checksum)) { - serverPlayerState.postRelogUpdateRequestConcurrencyLimiter.release(); + serverPlayerState.loginDataSyncRCLimiter.release(); msg.sendResponse(new FullDataSourceResponseMessage(null, this)); return; } this.serverside.dataFileHandler.getAsync(msg.sectionPos).thenAccept(fullDataSource -> { - serverPlayerState.postRelogUpdateRequestConcurrencyLimiter.release(); + serverPlayerState.loginDataSyncRCLimiter.release(); msg.sendResponse(new FullDataSourceResponseMessage((CompleteFullDataSource) fullDataSource, this)); }); } 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 67755ff15..b0e9d1b77 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 @@ -16,6 +16,7 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable; import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.ratelimiting.SupplierBasedRateLimiter; import io.netty.channel.ChannelException; import org.apache.logging.log4j.Logger; @@ -51,6 +52,8 @@ public abstract class AbstractFullDataRequestQueue implements IDebugRenderable, private final Set alreadyRequestedPositions = ConcurrentHashMap.newKeySet(); + private final SupplierBasedRateLimiter rateLimiter = new SupplierBasedRateLimiter<>(this::getRequestConcurrencyLimit); + protected abstract int getRequestConcurrencyLimit(); @@ -104,6 +107,12 @@ public abstract class AbstractFullDataRequestQueue implements IDebugRenderable, && this.getInProgressTaskCount() < this.getRequestConcurrencyLimit() && this.pendingTasksSemaphore.tryAcquire()) { + if (!this.rateLimiter.tryAcquire()) + { + this.pendingTasksSemaphore.release(); + break; + } + this.sendNewRequest(targetPos); } @@ -277,8 +286,7 @@ public abstract class AbstractFullDataRequestQueue implements IDebugRenderable, public RequestQueueEntry( Consumer chunkDataConsumer, - @Nullable - Integer currentChecksum) + @Nullable Integer currentChecksum) { this.chunkDataConsumer = chunkDataConsumer; this.currentChecksum = currentChecksum; 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 8e92afd4c..862ababaf 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,7 +12,7 @@ public class FullDataRefreshQueue extends AbstractFullDataRequestQueue } @Override - protected int getRequestConcurrencyLimit() { return this.networkState.config.postRelogUpdateConcurrencyLimit; } + protected int getRequestConcurrencyLimit() { return this.networkState.config.loginDataSyncRCLimit; } @Override protected String getQueueName() { return "Data Refresh Queue"; } @@ -20,7 +20,7 @@ public class FullDataRefreshQueue extends AbstractFullDataRequestQueue @Override public boolean tick(DhBlockPos2D targetPos) { - if (!this.networkState.config.postRelogUpdateEnabled) + if (!this.networkState.config.loginDataSyncEnabled) { 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 7086c7ac3..5c62b7187 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 @@ -10,8 +10,8 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject public abstract int getFullDataRequestConcurrencyLimit(); public abstract int getGenTaskPriorityRequestRateLimit(); public abstract boolean isRealTimeUpdatesEnabled(); - public abstract boolean isPostRelogUpdateEnabled(); - public abstract int getPostRelogUpdateConcurrencyLimit(); + public abstract boolean isLoginDataSyncEnabled(); + public abstract int getLoginDataSyncRCLimit(); @Override public void encode(ByteBuf out) @@ -21,8 +21,8 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject out.writeInt(this.getFullDataRequestConcurrencyLimit()); out.writeInt(this.getGenTaskPriorityRequestRateLimit()); out.writeBoolean(this.isRealTimeUpdatesEnabled()); - out.writeBoolean(this.isPostRelogUpdateEnabled()); - out.writeInt(this.getPostRelogUpdateConcurrencyLimit()); + out.writeBoolean(this.isLoginDataSyncEnabled()); + out.writeInt(this.getLoginDataSyncRCLimit()); } } 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 578e84fac..680ef3ef2 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,7 +13,7 @@ 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.fullDataRequestConcurrencyLimit.get(); + public int fullDataRequestConcurrencyLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit.get(); @Override public int getFullDataRequestConcurrencyLimit() { return this.fullDataRequestConcurrencyLimit; } public int genTaskPriorityRequestRateLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.genTaskPriorityRequestRateLimit.get(); @@ -22,11 +22,11 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig public boolean realTimeUpdatesEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates.get(); @Override public boolean isRealTimeUpdatesEnabled() { return this.realTimeUpdatesEnabled; } - public boolean postRelogUpdateEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate.get(); - @Override public boolean isPostRelogUpdateEnabled() { return this.postRelogUpdateEnabled; } + public boolean loginDataSyncEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enableLoginDataSync.get(); + @Override public boolean isLoginDataSyncEnabled() { return this.loginDataSyncEnabled; } - public int postRelogUpdateConcurrencyLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.postRelogUpdateConcurrencyLimit.get(); - @Override public int getPostRelogUpdateConcurrencyLimit() { return this.postRelogUpdateConcurrencyLimit; } + public int loginDataSyncRCLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.loginDataSyncRCLimit.get(); + @Override public int getLoginDataSyncRCLimit() { return this.loginDataSyncRCLimit; } @Override public void decode(ByteBuf in) @@ -36,20 +36,20 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig this.fullDataRequestConcurrencyLimit = in.readInt(); this.genTaskPriorityRequestRateLimit = in.readInt(); this.realTimeUpdatesEnabled = in.readBoolean(); - this.postRelogUpdateEnabled = in.readBoolean(); - this.postRelogUpdateConcurrencyLimit = in.readInt(); + this.loginDataSyncEnabled = in.readBoolean(); + this.loginDataSyncRCLimit = in.readInt(); } @Override public String toString() { return "MultiplayerConfig{" + - "renderDistance=" + this.renderDistanceRadius + + "renderDistanceRadius=" + this.renderDistanceRadius + ", distantGenerationEnabled=" + this.distantGenerationEnabled + ", fullDataRequestConcurrencyLimit=" + this.fullDataRequestConcurrencyLimit + ", genTaskPriorityRequestRateLimit=" + this.genTaskPriorityRequestRateLimit + ", realTimeUpdatesEnabled=" + this.realTimeUpdatesEnabled + - ", postRelogUpdatesEnabled=" + this.postRelogUpdateEnabled + - ", postRelogUpdateConcurrencyLimit=" + this.postRelogUpdateConcurrencyLimit + + ", loginDataSyncEnabled=" + this.loginDataSyncEnabled + + ", loginDataSyncRCLimit=" + this.loginDataSyncRCLimit + '}'; } 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 76ba40c7a..3624c2ed4 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,11 +13,11 @@ 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.fullDataRequestConcurrencyLimit, + Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.genTaskPriorityRequestRateLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates, - Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate, - Config.Client.Advanced.Multiplayer.ServerNetworking.postRelogUpdateConcurrencyLimit, + Config.Client.Advanced.Multiplayer.ServerNetworking.enableLoginDataSync, + Config.Client.Advanced.Multiplayer.ServerNetworking.loginDataSyncRCLimit, }; private final ArrayList changeListeners = new ArrayList<>(); 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 3ab07416f..97c75df92 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 @@ -4,7 +4,7 @@ import com.seibel.distanthorizons.core.network.IConnection; import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException; import com.seibel.distanthorizons.core.network.messages.fullData.generation.FullDataSourceRequestMessage; import com.seibel.distanthorizons.core.network.messages.fullData.generation.priority.GenTaskPriorityRequestMessage; -import com.seibel.distanthorizons.core.util.ratelimiting.SupplierBasedConcurrencyLimiter; +import com.seibel.distanthorizons.core.util.ratelimiting.SupplierBasedRateAndConcurrencyLimiter; import com.seibel.distanthorizons.core.util.ratelimiting.SupplierBasedRateLimiter; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import org.jetbrains.annotations.NotNull; @@ -24,10 +24,10 @@ public class ServerPlayerState ignored -> this.connection.disconnect("You have been repeatedly exceeding rate/concurrency limits.") ); - public final SupplierBasedConcurrencyLimiter fullDataRequestConcurrencyLimiter = new SupplierBasedConcurrencyLimiter<>( - () -> ServerNetworking.fullDataRequestConcurrencyLimit.get(), + public final SupplierBasedRateAndConcurrencyLimiter fullDataRequestConcurrencyLimiter = new SupplierBasedRateAndConcurrencyLimiter<>( + () -> ServerNetworking.generationRequestRCLimit.get(), msg -> { - msg.sendResponse(new RateLimitedException("Max concurrent full data requests: " + this.config.getFullDataRequestConcurrencyLimit())); + msg.sendResponse(new RateLimitedException("Full data request rate/concurrency limit: " + this.config.getFullDataRequestConcurrencyLimit())); this.rateLimitKickTrigger.tryAcquire(null); } ); @@ -35,15 +35,15 @@ public class ServerPlayerState public final SupplierBasedRateLimiter genTaskPriorityRequestRateLimiter = new SupplierBasedRateLimiter<>( () -> ServerNetworking.genTaskPriorityRequestRateLimit.get(), msg -> { - msg.sendResponse(new RateLimitedException("Max section checks per second: " + this.config.getFullDataRequestConcurrencyLimit())); + msg.sendResponse(new RateLimitedException("Generation task priority check rate limit: " + this.config.getFullDataRequestConcurrencyLimit())); this.rateLimitKickTrigger.tryAcquire(null); } ); - public final SupplierBasedConcurrencyLimiter postRelogUpdateRequestConcurrencyLimiter = new SupplierBasedConcurrencyLimiter<>( - () -> ServerNetworking.postRelogUpdateConcurrencyLimit.get(), + public final SupplierBasedRateAndConcurrencyLimiter loginDataSyncRCLimiter = new SupplierBasedRateAndConcurrencyLimiter<>( + () -> ServerNetworking.loginDataSyncRCLimit.get(), msg -> { - msg.sendResponse(new RateLimitedException("Max concurrent post-relog update requests: " + this.config.getPostRelogUpdateConcurrencyLimit())); + msg.sendResponse(new RateLimitedException("Data sync rate/concurrency limit: " + this.config.getLoginDataSyncRCLimit())); this.rateLimitKickTrigger.tryAcquire(null); } ); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServersideMultiplayerConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServersideMultiplayerConfig.java index e16ccac79..58a9b8f64 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServersideMultiplayerConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServersideMultiplayerConfig.java @@ -27,7 +27,7 @@ public class ServersideMultiplayerConfig extends AbstractMultiplayerConfig @Override public int getFullDataRequestConcurrencyLimit() { - return Math.min(this.clientConfig.fullDataRequestConcurrencyLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.fullDataRequestConcurrencyLimit.get()); + return Math.min(this.clientConfig.fullDataRequestConcurrencyLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit.get()); } @Override @@ -43,14 +43,15 @@ public class ServersideMultiplayerConfig extends AbstractMultiplayerConfig } @Override - public boolean isPostRelogUpdateEnabled() { - return this.clientConfig.postRelogUpdateEnabled && Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate.get(); + public boolean isLoginDataSyncEnabled() + { + return this.clientConfig.loginDataSyncEnabled && Config.Client.Advanced.Multiplayer.ServerNetworking.enableLoginDataSync.get(); } @Override - public int getPostRelogUpdateConcurrencyLimit() + public int getLoginDataSyncRCLimit() { - return Math.min(this.clientConfig.postRelogUpdateConcurrencyLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.postRelogUpdateConcurrencyLimit.get()); + return Math.min(this.clientConfig.loginDataSyncRCLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.loginDataSyncRCLimit.get()); } @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateAndConcurrencyLimiter.java b/core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateAndConcurrencyLimiter.java new file mode 100644 index 000000000..e41b28f92 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateAndConcurrencyLimiter.java @@ -0,0 +1,39 @@ +package com.seibel.distanthorizons.core.util.ratelimiting; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class SupplierBasedRateAndConcurrencyLimiter +{ + private final SupplierBasedRateLimiter rateLimiter; + private final SupplierBasedConcurrencyLimiter concurrencyLimiter; + + public SupplierBasedRateAndConcurrencyLimiter(Supplier maxRateSupplier, Consumer onFailureConsumer) + { + this.rateLimiter = new SupplierBasedRateLimiter<>(maxRateSupplier, onFailureConsumer); + this.concurrencyLimiter = new SupplierBasedConcurrencyLimiter<>(maxRateSupplier, onFailureConsumer); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean tryAcquire(T context) + { + if (!this.concurrencyLimiter.tryAcquire(context)) + { + return false; + } + + if (!this.rateLimiter.tryAcquire(context)) + { + this.concurrencyLimiter.release(); + return false; + } + + return true; + } + + public void release() + { + this.concurrencyLimiter.release(); + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateLimiter.java b/core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateLimiter.java index 99ec05b58..bc7e2ff05 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateLimiter.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/ratelimiting/SupplierBasedRateLimiter.java @@ -18,6 +18,7 @@ public class SupplierBasedRateLimiter private final RateLimiter rateLimiter = RateLimiter.create(1); + public SupplierBasedRateLimiter(Supplier maxRateSupplier) { this(maxRateSupplier, ignored -> { }); } public SupplierBasedRateLimiter(Supplier maxRateSupplier, Consumer onFailureConsumer) { this.maxRateSupplier = maxRateSupplier; @@ -27,30 +28,40 @@ public class SupplierBasedRateLimiter @SuppressWarnings("BooleanMethodIsAlwaysInverted") public boolean tryAcquire(T context) { - return tryAcquire(context, 1); + return this.tryAcquire(context, 1); + } + + public boolean tryAcquire() + { + return this.tryAcquire(null, 1); } public int acquireOrDrain(int permits) { - rateLimiter.setRate(maxRateSupplier.get()); + this.rateLimiter.setRate(this.maxRateSupplier.get()); - if (rateLimiter.tryAcquire(permits)) + if (this.rateLimiter.tryAcquire(permits)) + { return permits; + } int acquired = 0; while ((permits /= 2) > 0) { - if (rateLimiter.tryAcquire(permits)) + if (this.rateLimiter.tryAcquire(permits)) + { acquired += permits; + } } + return acquired; } public boolean tryAcquire(T context, int permits) { - rateLimiter.setRate(maxRateSupplier.get()); + this.rateLimiter.setRate(this.maxRateSupplier.get()); - if (!rateLimiter.tryAcquire(permits)) + if (!this.rateLimiter.tryAcquire(permits)) { this.onFailureConsumer.accept(context); return false; 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 391e77989..7365919ba 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -345,15 +345,23 @@ "Multiplayer", "distanthorizons.config.client.advanced.multiplayer.serverNetworking": "Server Networking", - + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableServerNetworking": "Enable Server Networking", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.fullDataRequestConcurrencyLimit": "Sections - request concurrency limit", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.genTaskPriorityRequestRateLimit": "Generation task priority - request rate limit", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.fullDataRequestBeginDelay": "Generation request begin delay", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableRealTimeUpdates": "Enable Real Time Updates", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enablePostRelogUpdates": "Enable Post Relog Updates", + "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.serverPort": "Server Port", - + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.serverPort.@tooltip": "The port on the server that's used for sending LOD data.", + "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.genTaskPriorityRequestRateLimit": "Gen task priority check rate limit", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.genTaskPriorityRequestRateLimit.@tooltip": "Limits the amount of LOD sections that the client can request states for, per second.", + "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.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.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.serverFolderNameMode": "Server Folder Mode", "distanthorizons.config.client.advanced.multiplayer.serverFolderNameMode.@tooltip": @@ -366,15 +374,6 @@ "Networked Multiverse Support", "distanthorizons.config.client.advanced.multiplayer.enableMultiverseNetworking.@tooltip": "If true Distant Horizons will attempt to communicate with the connected \nserver in order to improve multiverse support.", - "distanthorizons.config.client.advanced.multiplayer.enableServerNetworking": - "§4Partially implemented§r - Server Support", - "distanthorizons.config.client.advanced.multiplayer.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.serverNetworkingRateLimit": - "Server Support - Request Rate Limit", - "distanthorizons.config.client.advanced.multiplayer.serverNetworkingRateLimit.@tooltip": - "Limits the amount of sent/processed LOD requests concurrently. \n\nNote: Server can set its own rate limit.", - "distanthorizons.config.client.advanced.multiThreading":