Allow section state requests to be controlled separately

This commit is contained in:
s809
2023-12-19 22:52:19 +05:00
parent b4ea632b93
commit 02aca6f044
11 changed files with 60 additions and 14 deletions
@@ -907,6 +907,14 @@ public class Config
+ "")
.build();
public static ConfigEntry<Integer> genTaskPriorityRequestRateLimit = new ConfigEntry.Builder<Integer>()
.setServersideShortName("genTaskPriorityRequestRateLimit")
.setMinDefaultMax(1, 50, 200)
.comment(""
+ "Limits the amount of LOD sections that the client can request states for, per second. \n"
+ "")
.build();
/**
* Intentionally disabled.
* @see #enablePostRelogUpdate
@@ -112,7 +112,7 @@ public class WorldRemoteGenerationQueue implements IWorldGenerationQueue, IDebug
List<DhSectionPos> posList = waitingTasks.entrySet().stream()
.filter(task -> task.getValue().request == null && task.getValue().priority == 0)
.sorted((x, y) -> posDistanceSquared(targetPos, x.getKey()) - posDistanceSquared(targetPos, y.getKey()))
.limit(this.networkState.config.fullDataRequestConcurrencyLimit)
.limit(this.networkState.config.genTaskPriorityRequestRateLimit)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
if (posList.isEmpty()) {
@@ -135,7 +135,7 @@ public class WorldRemoteGenerationQueue implements IWorldGenerationQueue, IDebug
entry.priority = mapEntry.getValue();
}
}
catch (ChannelException | CancellationException ignored)
catch (ChannelException | CancellationException | RateLimitedException ignored)
{
}
catch (Throwable e)
@@ -24,22 +24,18 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedF
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource;
import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile;
import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider;
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
import com.seibel.distanthorizons.core.multiplayer.server.RemotePlayerConnectionHandler;
import com.seibel.distanthorizons.core.network.ScopedNetworkEventSource;
import com.seibel.distanthorizons.core.network.NetworkServer;
import com.seibel.distanthorizons.core.network.exceptions.InvalidSectionPosException;
import com.seibel.distanthorizons.core.network.exceptions.RequestRejectedException;
import com.seibel.distanthorizons.core.network.messages.base.CancelMessage;
import com.seibel.distanthorizons.core.network.messages.fullData.generation.FullDataSourceRequestMessage;
import com.seibel.distanthorizons.core.network.messages.fullData.generation.FullDataSourceResponseMessage;
import com.seibel.distanthorizons.core.network.messages.fullData.generation.priority.GenTaskPriorityRequestMessage;
import com.seibel.distanthorizons.core.network.messages.fullData.generation.priority.GenTaskPriorityResponseMessage;
import com.seibel.distanthorizons.core.network.messages.fullData.updates.FullDataChangeSummaryRequestMessage;
import com.seibel.distanthorizons.core.network.messages.fullData.updates.FullDataChangeSummaryResponseMessage;
import com.seibel.distanthorizons.core.network.messages.fullData.updates.FullDataPartialUpdateMessage;
import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
@@ -54,7 +50,6 @@ import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
import org.apache.logging.log4j.Logger;
import javax.annotation.CheckForNull;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.*;
@@ -128,7 +123,9 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
this.eventSource.registerHandler(GenTaskPriorityRequestMessage.class, remotePlayerConnectionHandler.currentLevelOnly(this, (msg, serverPlayerState) ->
{
msg.sendResponse(new GenTaskPriorityResponseMessage(
this.serverside.dataFileHandler.getLoadStates(msg.posList)
this.serverside.dataFileHandler.getLoadStates(msg.posList.stream()
.limit(serverPlayerState.genTaskPriorityRequestRateLimiter.acquireOrDrain(msg.posList.size()))
::iterator)
));
}));
@@ -8,6 +8,7 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject
public abstract int getRenderDistanceRadius();
public abstract boolean isDistantGenerationEnabled();
public abstract int getFullDataRequestConcurrencyLimit();
public abstract int getGenTaskPriorityRequestRateLimit();
public abstract boolean isRealTimeUpdatesEnabled();
public abstract boolean isPostRelogUpdateEnabled();
@@ -17,6 +18,7 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject
out.writeInt(this.getRenderDistanceRadius());
out.writeBoolean(this.isDistantGenerationEnabled());
out.writeInt(this.getFullDataRequestConcurrencyLimit());
out.writeInt(this.getGenTaskPriorityRequestRateLimit());
out.writeBoolean(this.isRealTimeUpdatesEnabled());
out.writeBoolean(this.isPostRelogUpdateEnabled());
}
@@ -16,6 +16,9 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig
public int fullDataRequestConcurrencyLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.fullDataRequestConcurrencyLimit.get();
@Override public int getFullDataRequestConcurrencyLimit() { return fullDataRequestConcurrencyLimit; }
public int genTaskPriorityRequestRateLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.genTaskPriorityRequestRateLimit.get();
@Override public int getGenTaskPriorityRequestRateLimit() { return genTaskPriorityRequestRateLimit; }
public boolean realTimeUpdatesEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates.get();
@Override public boolean isRealTimeUpdatesEnabled() { return realTimeUpdatesEnabled; }
@@ -28,6 +31,7 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig
this.renderDistanceRadius = in.readInt();
this.distantGenerationEnabled = in.readBoolean();
this.fullDataRequestConcurrencyLimit = in.readInt();
this.genTaskPriorityRequestRateLimit = in.readInt();
this.realTimeUpdatesEnabled = in.readBoolean();
this.postRelogUpdateEnabled = in.readBoolean();
}
@@ -38,6 +42,7 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig
"renderDistance=" + renderDistanceRadius +
", distantGenerationEnabled=" + distantGenerationEnabled +
", fullDataRequestConcurrencyLimit=" + fullDataRequestConcurrencyLimit +
", genTaskPriorityRequestRateLimit=" + genTaskPriorityRequestRateLimit +
", realTimeUpdatesEnabled=" + realTimeUpdatesEnabled +
", postRelogUpdatesEnabled=" + postRelogUpdateEnabled +
'}';
@@ -14,6 +14,7 @@ public class MultiplayerConfigChangeListener implements Closeable
Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius,
Config.Client.Advanced.WorldGenerator.enableDistantGeneration,
Config.Client.Advanced.Multiplayer.ServerNetworking.fullDataRequestConcurrencyLimit,
Config.Client.Advanced.Multiplayer.ServerNetworking.genTaskPriorityRequestRateLimit,
Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates,
//Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate
};
@@ -3,7 +3,7 @@ package com.seibel.distanthorizons.core.multiplayer.server;
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.updates.FullDataChangeSummaryRequestMessage;
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.SupplierBasedRateLimiter;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
@@ -27,11 +27,20 @@ public class ServerPlayerState
public final SupplierBasedConcurrencyLimiter<FullDataSourceRequestMessage> fullDataRequestConcurrencyLimiter = new SupplierBasedConcurrencyLimiter<>(
() -> ServerNetworking.fullDataRequestConcurrencyLimit.get(),
msg -> {
msg.sendResponse(new RateLimitedException("Max concurrent requests: " + config.getFullDataRequestConcurrencyLimit()));
msg.sendResponse(new RateLimitedException("Max concurrent full data requests: " + config.getFullDataRequestConcurrencyLimit()));
this.rateLimitKickTrigger.tryAcquire(null);
}
);
public final SupplierBasedRateLimiter<GenTaskPriorityRequestMessage> genTaskPriorityRequestRateLimiter = new SupplierBasedRateLimiter<>(
() -> ServerNetworking.genTaskPriorityRequestRateLimit.get(),
msg -> {
// Shouldn't be called, but it's here just in case
msg.sendResponse(new RateLimitedException("Max section checks per second: " + config.getFullDataRequestConcurrencyLimit()));
this.rateLimitKickTrigger.tryAcquire(null);
}
);
public ServerPlayerState(IServerPlayerWrapper serverPlayer) { this.serverPlayer = serverPlayer; }
@@ -30,6 +30,12 @@ public class ServersideMultiplayerConfig extends AbstractMultiplayerConfig
return Math.min(clientConfig.fullDataRequestConcurrencyLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.fullDataRequestConcurrencyLimit.get());
}
@Override
public int getGenTaskPriorityRequestRateLimit()
{
return Math.min(clientConfig.genTaskPriorityRequestRateLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.genTaskPriorityRequestRateLimit.get());
}
@Override
public boolean isRealTimeUpdatesEnabled()
{
@@ -43,7 +43,7 @@ public class NetworkChannelInitializer extends ChannelInitializer<SocketChannel>
pipeline.addLast(new NetworkOutboundExceptionRouter());
// Decoder
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, Integer.BYTES, 0, Integer.BYTES));
pipeline.addLast(new LengthFieldBasedFrameDecoder(4194304 /* 4 MiB */, 0, Integer.BYTES, 0, Integer.BYTES));
pipeline.addLast(new MessageDecoder());
// Handler
@@ -27,12 +27,29 @@ public class SupplierBasedRateLimiter<T>
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean tryAcquire(T context)
{
return tryAcquire(1, context);
return tryAcquire(context, 1);
}
public boolean tryAcquire(int permits, T context)
public int acquireOrDrain(int permits)
{
rateLimiter.setRate(maxRateSupplier.get());
if (rateLimiter.tryAcquire(permits))
return permits;
int acquired = 0;
while ((permits /= 2) > 0)
{
if (rateLimiter.tryAcquire(permits))
acquired += permits;
}
return acquired;
}
public boolean tryAcquire(T context, int permits)
{
rateLimiter.setRate(maxRateSupplier.get());
if (!rateLimiter.tryAcquire(permits))
{
this.onFailureConsumer.accept(context);
@@ -347,7 +347,8 @@
"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": "Full data request concurrency limit",
"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.enableRealTimeUpdates": "Enable Real Time Updates",
"distanthorizons.config.client.advanced.multiplayer.serverNetworking.enablePostRelogUpdates": "Enable Post Relog Updates",
"distanthorizons.config.client.advanced.multiplayer.serverNetworking.serverPort": "Server Port",