Add a config entry and refactor
This commit is contained in:
@@ -1713,6 +1713,15 @@ public class Config
|
||||
+ "Value of 0 disables the limit."
|
||||
+ "")
|
||||
.build();
|
||||
public static ConfigEntry<Boolean> enableAdaptiveTransferSpeed = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "Enables adaptive transfer speed based on client performance.\n"
|
||||
+ "If true, DH will automatically adjust transfer rate to minimize connection lag.\n"
|
||||
+ "If false, transfer speed will remain fixed.\n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
|
||||
public static ConfigCategory experimental = new ConfigCategory.Builder().set(Experimental.class).build();
|
||||
|
||||
|
||||
+18
-20
@@ -16,65 +16,63 @@ public class ClientCongestionControl
|
||||
private final AtomicLong bytesReceived = new AtomicLong(0);
|
||||
private volatile double lastIntervalThroughput = 0;
|
||||
|
||||
private double currentRate = 50000;
|
||||
private double desiredRate = 50000;
|
||||
private long lastAdjustTime = System.currentTimeMillis();
|
||||
|
||||
private final IntSupplier currentMaxRateSupplier;
|
||||
private final BooleanSupplier hasIncompleteBuffersSupplier;
|
||||
private final IntConsumer rateUpdateConsumer;
|
||||
private final IntSupplier currentRateSupplier;
|
||||
private final Runnable rateUpdateHandler;
|
||||
|
||||
|
||||
public ClientCongestionControl(
|
||||
IntSupplier currentMaxRateSupplier,
|
||||
BooleanSupplier hasIncompleteBuffersSupplier,
|
||||
IntConsumer rateUpdateConsumer
|
||||
IntSupplier currentRateSupplier,
|
||||
Runnable rateUpdateHandler
|
||||
)
|
||||
{
|
||||
this.currentMaxRateSupplier = currentMaxRateSupplier;
|
||||
this.hasIncompleteBuffersSupplier = hasIncompleteBuffersSupplier;
|
||||
this.rateUpdateConsumer = rateUpdateConsumer;
|
||||
this.currentRateSupplier = currentRateSupplier;
|
||||
this.rateUpdateHandler = rateUpdateHandler;
|
||||
}
|
||||
|
||||
|
||||
public void onPayloadReceived(FullDataSplitMessage message)
|
||||
{
|
||||
this.bytesReceived.addAndGet(message.buffer.readableBytes());
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - this.lastAdjustTime >= INTERVAL_MS)
|
||||
{
|
||||
this.adjustRate(now);
|
||||
}
|
||||
|
||||
this.bytesReceived.addAndGet(message.buffer.readableBytes());
|
||||
}
|
||||
|
||||
private void adjustRate(long now)
|
||||
{
|
||||
this.desiredRate = this.currentRateSupplier.getAsInt() * 1000;
|
||||
double throughput = this.bytesReceived.getAndSet(0);
|
||||
|
||||
if (throughput != 0 && throughput >= this.lastIntervalThroughput)
|
||||
{
|
||||
this.currentRate = Math.min(this.currentRate, this.currentMaxRateSupplier.getAsInt() * 1000) + ADDITIVE_INCREASE;
|
||||
this.desiredRate += ADDITIVE_INCREASE;
|
||||
}
|
||||
else if (this.hasIncompleteBuffersSupplier.getAsBoolean())
|
||||
else
|
||||
{
|
||||
this.currentRate *= MULTIPLICATIVE_DECREASE;
|
||||
this.desiredRate *= MULTIPLICATIVE_DECREASE;
|
||||
throughput *= MULTIPLICATIVE_DECREASE;
|
||||
|
||||
if (this.currentRate < 1)
|
||||
if (this.desiredRate < 1)
|
||||
{
|
||||
this.currentRate = 1;
|
||||
this.desiredRate = 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.lastIntervalThroughput = throughput;
|
||||
this.lastAdjustTime = now;
|
||||
|
||||
this.rateUpdateConsumer.accept((int) this.currentRate / 1000);
|
||||
this.rateUpdateHandler.run();
|
||||
}
|
||||
|
||||
public double getCurrentRate()
|
||||
public int getDesiredRate()
|
||||
{
|
||||
return this.currentRate;
|
||||
return (int) (this.desiredRate / 1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-3
@@ -1,6 +1,7 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.client;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.SessionConfig;
|
||||
@@ -58,9 +59,14 @@ public class ClientNetworkState implements Closeable
|
||||
|
||||
private final ClientCongestionControl congestionControl = new ClientCongestionControl(
|
||||
() -> this.sessionConfig.getMaxDataTransferSpeed(),
|
||||
this.fullDataPayloadReceiver::hasIncompleteBuffers,
|
||||
x -> this.sendConfigMessage(false)
|
||||
() -> {
|
||||
if (Config.Server.enableAdaptiveTransferSpeed.get())
|
||||
{
|
||||
this.sendConfigMessage(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
private final ConfigChangeListener<Boolean> adaptiveTransferSpeedListener = new ConfigChangeListener<>(Config.Server.enableAdaptiveTransferSpeed, this::sendConfigMessage);
|
||||
|
||||
|
||||
|
||||
@@ -138,7 +144,11 @@ public class ClientNetworkState implements Closeable
|
||||
public void sendConfigMessage(boolean blocking)
|
||||
{
|
||||
SessionConfig sessionConfig = new SessionConfig();
|
||||
sessionConfig.overrideValue(Config.Server.maxDataTransferSpeed, (int) this.congestionControl.getCurrentRate() / 1000);
|
||||
|
||||
if (Config.Server.enableAdaptiveTransferSpeed.get())
|
||||
{
|
||||
sessionConfig.constrainValue(Config.Server.maxDataTransferSpeed, this.congestionControl.getDesiredRate());
|
||||
}
|
||||
|
||||
if (blocking)
|
||||
{
|
||||
@@ -181,6 +191,7 @@ public class ClientNetworkState implements Closeable
|
||||
public void close()
|
||||
{
|
||||
this.fullDataPayloadReceiver.close();
|
||||
this.adaptiveTransferSpeedListener.close();
|
||||
this.configAnyChangeListener.close();
|
||||
this.networkSession.close();
|
||||
}
|
||||
|
||||
+5
-4
@@ -106,7 +106,7 @@ public class SessionConfig implements INetworkObject
|
||||
// internal getters //
|
||||
//==================//
|
||||
|
||||
public <T> T getValue(ConfigEntry<T> configEntry) { return this.getValue(configEntry.getChatCommandName()); }
|
||||
private <T> T getValue(ConfigEntry<T> configEntry) { return this.getValue(configEntry.getChatCommandName()); }
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getValue(String name)
|
||||
{
|
||||
@@ -123,10 +123,11 @@ public class SessionConfig implements INetworkObject
|
||||
: value);
|
||||
}
|
||||
|
||||
public <T> void overrideValue(ConfigEntry<T> configEntry, T value) { this.overrideValue(configEntry.getChatCommandName(), value); }
|
||||
private void overrideValue(String name, Object value)
|
||||
public <T> void constrainValue(ConfigEntry<T> configEntry, T value) { this.constrainValue(configEntry.getChatCommandName(), value); }
|
||||
private void constrainValue(String name, Object value)
|
||||
{
|
||||
this.values.put(name, value);
|
||||
Entry entry = CONFIG_ENTRIES.get(name);
|
||||
this.values.put(name, entry.valueConstrainer.apply(this.getValue(name), value));
|
||||
}
|
||||
|
||||
private Map<String, ?> getValues()
|
||||
|
||||
-3
@@ -34,9 +34,6 @@ public class FullDataPayloadReceiver implements AutoCloseable
|
||||
})
|
||||
.build().asMap();
|
||||
|
||||
|
||||
public boolean hasIncompleteBuffers() { return !this.buffersById.isEmpty(); }
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
|
||||
@@ -746,6 +746,10 @@
|
||||
"Maximum Data Transfer Speed, KB/s",
|
||||
"distanthorizons.config.server.maxDataTransferSpeed.@tooltip":
|
||||
"Maximum speed for uploading LODs to the clients, in KB/s.\nValue of 0 disables the limit.",
|
||||
"distanthorizons.config.server.enableAdaptiveTransferSpeed":
|
||||
"Enable Adaptive Transfer Speed",
|
||||
"distanthorizons.config.server.enableAdaptiveTransferSpeed.@tooltip":
|
||||
"Enables adaptive transfer speed based on client performance.\nIf true, DH will automatically adjust transfer rate to minimize connection lag.\nIf false, transfer speed will remain fixed.",
|
||||
|
||||
|
||||
"distanthorizons.config.server.experimental":
|
||||
|
||||
Reference in New Issue
Block a user