Add config for a few slow features
This commit is contained in:
@@ -755,6 +755,8 @@ public class Config
|
||||
|
||||
public static class Multiplayer
|
||||
{
|
||||
public static ConfigCategory serverNetworking = new ConfigCategory.Builder().set(ServerNetworking.class).build();
|
||||
|
||||
public static ConfigEntry<EServerFolderNameMode> serverFolderNameMode = new ConfigEntry.Builder<EServerFolderNameMode>()
|
||||
.set(EServerFolderNameMode.NAME_ONLY)
|
||||
.comment(""
|
||||
@@ -800,29 +802,46 @@ public class Config
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
// not currently implemented
|
||||
public static ConfigEntry<Boolean> enableServerNetworking = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "Attention: \n"
|
||||
+ " 1. This feature is not fully implemented. \n"
|
||||
+ " 2. If you really want to use it, enable it only on trusted server/with trusted players. \n"
|
||||
+ "\n"
|
||||
+ "If true Distant Horizons will attempt to communicate with the connected \n"
|
||||
+ "server in order to load LODs outside your vanilla render distance. \n"
|
||||
+ "\n"
|
||||
+ "Note: This requires DH to be installed on the server in order to function. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Integer> serverNetworkingRateLimit = new ConfigEntry.Builder<Integer>()
|
||||
.setMinDefaultMax(1, 20, 100)
|
||||
.comment(""
|
||||
+ "Limits the amount of sent/processed LOD requests concurrently. \n"
|
||||
+ "\n"
|
||||
+ "Note: Server can set its own rate limit. \n"
|
||||
+ "")
|
||||
.build();
|
||||
// TODO Write strings
|
||||
public static class ServerNetworking
|
||||
{
|
||||
public static ConfigEntry<Boolean> enableServerNetworking = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "Attention: \n"
|
||||
+ " 1. This feature is not fully implemented. \n"
|
||||
+ " 2. If you really want to use it, enable it only on trusted server/with trusted players. \n"
|
||||
+ "\n"
|
||||
+ "If true Distant Horizons will attempt to communicate with the connected \n"
|
||||
+ "server in order to load LODs outside your vanilla render distance. \n"
|
||||
+ "\n"
|
||||
+ "Note: This requires DH to be installed on the server in order to function. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Integer> requestRateLimit = new ConfigEntry.Builder<Integer>()
|
||||
.setMinDefaultMax(1, 20, 100)
|
||||
.comment(""
|
||||
+ "Limits the amount of sent/processed LOD requests concurrently. \n"
|
||||
+ "\n"
|
||||
+ "Note: Server can set its own rate limit. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> enableRealTimeUpdates = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "Enables real time updates from server."
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> enablePostRelogUpdate = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "Enables updating of LODs after relog."
|
||||
+ "")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1081,6 +1100,7 @@ public class Config
|
||||
|
||||
}
|
||||
|
||||
// TODO write strings
|
||||
public static class Debugging
|
||||
{
|
||||
public static ConfigCategory debugWireframeRendering = new ConfigCategory.Builder().set(DebugWireframeRendering.class).build();
|
||||
|
||||
+5
-5
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.file.fullDatafile;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource;
|
||||
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
|
||||
@@ -26,12 +27,12 @@ import com.seibel.distanthorizons.core.generation.IWorldGenerationQueue;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.multiplayer.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.InvalidLevelException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.InvalidSectionPosException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.RequestRejectedException;
|
||||
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.pos.DhLodPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -144,11 +145,10 @@ public class RemoteFullDataFileHandler extends GeneratedFullDataFileHandler
|
||||
@Override
|
||||
public FullDataMetaFile getFileIfExist(DhSectionPos pos)
|
||||
{
|
||||
// This feature is broken - same data may produce different hashes, apparently
|
||||
if (true)
|
||||
if (this.networkState == null || !this.isFileUnloaded(pos))
|
||||
return super.getFileIfExist(pos);
|
||||
|
||||
if (this.networkState == null || !this.isFileUnloaded(pos))
|
||||
if (!this.networkState.config.postRelogUpdateEnabled)
|
||||
return super.getFileIfExist(pos);
|
||||
|
||||
FullDataMetaFile metaFile = super.getFileIfExist(pos);
|
||||
|
||||
+7
-7
@@ -8,7 +8,8 @@ import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult;
|
||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.multiplayer.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.InvalidLevelException;
|
||||
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.FullDataSourceResponseMessage;
|
||||
@@ -178,13 +179,8 @@ public class WorldRemoteGenerationQueue implements IWorldGenerationQueue, IDebug
|
||||
|
||||
waitingTasks.remove(sectionPos);
|
||||
LOGGER.debug("FullDataSourceResponseMessage " + sectionPos);
|
||||
|
||||
CompleteFullDataSource fullDataSource = response.getFullDataSource(sectionPos, level);
|
||||
|
||||
// FIXME Add dimension context to request instead
|
||||
// Check is dimension has been switched - received data may no longer be relevant
|
||||
if (fullDataSource == null)
|
||||
throw new CancellationException();
|
||||
|
||||
Consumer<ChunkSizedFullDataAccessor> chunkDataConsumer = entry.tracker.getChunkDataConsumer();
|
||||
|
||||
// FIXME Why keeping a reference in first place
|
||||
@@ -193,6 +189,10 @@ public class WorldRemoteGenerationQueue implements IWorldGenerationQueue, IDebug
|
||||
|
||||
fullDataSource.splitIntoChunkSizedAccessors(chunkDataConsumer);
|
||||
}
|
||||
catch (InvalidLevelException ignored)
|
||||
{
|
||||
// We're too late
|
||||
}
|
||||
catch (ChannelException | RateLimitedException e)
|
||||
{
|
||||
if (e instanceof RateLimitedException)
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataFileHandl
|
||||
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
|
||||
import com.seibel.distanthorizons.core.generation.WorldRemoteGenerationQueue;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.multiplayer.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.network.NetworkClient;
|
||||
import com.seibel.distanthorizons.core.network.ScopedNetworkEventSource;
|
||||
import com.seibel.distanthorizons.core.network.messages.fullData.updates.FullDataPartialUpdateMessage;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.level;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.AppliedConfigState;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource;
|
||||
@@ -28,13 +27,13 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.I
|
||||
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.ServerPlayerState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.RemotePlayerConnectionHandler;
|
||||
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.InvalidLevelException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.InvalidSectionPosException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException;
|
||||
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;
|
||||
@@ -72,7 +71,6 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
|
||||
private final LinkedBlockingQueue<IServerPlayerWrapper> worldGenLoopingQueue = new LinkedBlockingQueue<>();
|
||||
private final ConcurrentMap<DhSectionPos, IncompleteDataSourceEntry> incompleteDataSources = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Long, IncompleteDataSourceEntry> fullDataRequests = new ConcurrentHashMap<>();
|
||||
private final AppliedConfigState<Integer> rateLimitConfig = new AppliedConfigState<>(Config.Client.Advanced.Multiplayer.serverNetworkingRateLimit);
|
||||
|
||||
|
||||
public DhServerLevel(AbstractSaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper, RemotePlayerConnectionHandler remotePlayerConnectionHandler)
|
||||
@@ -94,10 +92,10 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
|
||||
{
|
||||
this.eventSource.registerHandler(FullDataSourceRequestMessage.class, remotePlayerConnectionHandler.currentLevelOnly(this, (msg, serverPlayerState) ->
|
||||
{
|
||||
if (serverPlayerState.pendingFullDataRequests.incrementAndGet() > rateLimitConfig.get())
|
||||
if (serverPlayerState.pendingFullDataRequests.incrementAndGet() > serverPlayerState.config.getFullDataRequestRateLimit())
|
||||
{
|
||||
serverPlayerState.pendingFullDataRequests.decrementAndGet();
|
||||
msg.sendResponse(new RateLimitedException("Max concurrent requests: " + rateLimitConfig.get()));
|
||||
msg.sendResponse(new RateLimitedException("Max concurrent requests: " + serverPlayerState.config.getFullDataRequestRateLimit()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,7 +108,7 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
|
||||
});
|
||||
return newEntry;
|
||||
});
|
||||
// If this fails, current entry is being drained and need create another one
|
||||
// If this fails, current entry is being drained and need to create another one
|
||||
if (entry.requestCollectionSemaphore.tryAcquire())
|
||||
{
|
||||
fullDataRequests.put(msg.futureId, entry);
|
||||
@@ -130,6 +128,12 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
|
||||
|
||||
this.eventSource.registerHandler(FullDataChangeSummaryRequestMessage.class, remotePlayerConnectionHandler.currentLevelOnly(this, (msg, serverPlayerState) ->
|
||||
{
|
||||
if (!Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate.get())
|
||||
{
|
||||
msg.sendResponse(new RequestRejectedException("Operation is disabled from config."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Load files and check checksums
|
||||
HashSet<DhSectionPos> changedPosList = new HashSet<>();
|
||||
for (Map.Entry<DhSectionPos, Integer> entry : msg.checksums.entrySet())
|
||||
@@ -226,11 +230,16 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
|
||||
if (future == null)
|
||||
return null;
|
||||
|
||||
if (!Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates.get())
|
||||
return future;
|
||||
|
||||
future.thenAccept(chunkSizedFullDataAccessor ->
|
||||
{
|
||||
for (ServerPlayerState serverPlayerState : remotePlayerConnectionHandler.getConnectedPlayers())
|
||||
{
|
||||
if (chunk.getChunkPos().distance(new DhChunkPos(serverPlayerState.serverPlayer.getPosition())) <= serverPlayerState.config.renderDistance)
|
||||
if (serverPlayerState.config.isRealTimeUpdatesEnabled()) continue;
|
||||
|
||||
if (chunk.getChunkPos().distance(new DhChunkPos(serverPlayerState.serverPlayer.getPosition())) <= serverPlayerState.config.getRenderDistance())
|
||||
serverPlayerState.channelContext.writeAndFlush(new FullDataPartialUpdateMessage(chunkSizedFullDataAccessor, this));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer;
|
||||
|
||||
import com.seibel.distanthorizons.core.network.protocol.INetworkObject;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class MultiplayerConfig implements INetworkObject
|
||||
{
|
||||
public int renderDistance;
|
||||
public int fullDataRequestRateLimit;
|
||||
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf out)
|
||||
{
|
||||
out.writeInt(this.renderDistance);
|
||||
out.writeInt(this.fullDataRequestRateLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf in)
|
||||
{
|
||||
this.renderDistance = in.readInt();
|
||||
this.fullDataRequestRateLimit = in.readInt();
|
||||
}
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
return "MultiplayerConfig{" +
|
||||
"renderDistance=" + renderDistance +
|
||||
", fullDataRequestRateLimit=" + fullDataRequestRateLimit +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
+19
-11
@@ -1,7 +1,8 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer;
|
||||
package com.seibel.distanthorizons.core.multiplayer.client;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfig;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.network.ScopedNetworkEventSource;
|
||||
import com.seibel.distanthorizons.core.network.NetworkClient;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.AckMessage;
|
||||
@@ -20,6 +21,7 @@ public class ClientNetworkState implements Closeable
|
||||
private final NetworkClient client;
|
||||
private final UUID playerUUID;
|
||||
public MultiplayerConfig config = new MultiplayerConfig();
|
||||
private final MultiplayerConfigChangeListener configChangeListener = new MultiplayerConfigChangeListener(this::onConfigChanged);
|
||||
|
||||
/**
|
||||
* Returns the client used by this instance. <p>
|
||||
@@ -31,12 +33,13 @@ public class ClientNetworkState implements Closeable
|
||||
* Constructs a new instance.
|
||||
*
|
||||
* @param networkClient Client to use. It is assumed that this client will be at full control by this instance.
|
||||
* @param playerUUID UUID of a player connected
|
||||
* @param playerUUID UUID of a player connected.
|
||||
*/
|
||||
public ClientNetworkState(NetworkClient networkClient, UUID playerUUID)
|
||||
{
|
||||
this.client = networkClient;
|
||||
this.playerUUID = playerUUID;
|
||||
|
||||
this.registerNetworkHandlers();
|
||||
this.client.startConnecting();
|
||||
}
|
||||
@@ -48,23 +51,28 @@ public class ClientNetworkState implements Closeable
|
||||
LOGGER.info("Connected to server: "+helloMessage.getChannelContext().channel().remoteAddress());
|
||||
|
||||
this.getClient().sendRequest(new PlayerUUIDMessage(playerUUID), AckMessage.class)
|
||||
.thenCompose(ack -> this.getClient().sendRequest(new RemotePlayerConfigMessage(new MultiplayerConfig()
|
||||
{{
|
||||
renderDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get();
|
||||
fullDataRequestRateLimit = Config.Client.Advanced.Multiplayer.serverNetworkingRateLimit.get();
|
||||
}}), RemotePlayerConfigMessage.class))
|
||||
.thenAccept(msg -> {
|
||||
this.config = msg.payload;
|
||||
})
|
||||
.thenAccept(ack -> this.getClient().sendMessage(new RemotePlayerConfigMessage(new MultiplayerConfig())))
|
||||
.exceptionally(throwable -> {
|
||||
LOGGER.error("Error while fetching server's config", throwable);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
this.client.registerHandler(RemotePlayerConfigMessage.class, msg ->
|
||||
{
|
||||
LOGGER.info("Connection config was changed: " + msg.payload);
|
||||
this.config = (MultiplayerConfig) msg.payload;
|
||||
});
|
||||
}
|
||||
|
||||
private void onConfigChanged()
|
||||
{
|
||||
this.getClient().sendMessage(new RemotePlayerConfigMessage(new MultiplayerConfig()));
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
this.configChangeListener.close();
|
||||
this.client.close();
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.config;
|
||||
|
||||
import com.seibel.distanthorizons.core.network.protocol.INetworkObject;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public abstract class AbstractMultiplayerConfig implements INetworkObject
|
||||
{
|
||||
public abstract int getRenderDistance();
|
||||
public abstract int getFullDataRequestRateLimit();
|
||||
public abstract boolean isRealTimeUpdatesEnabled();
|
||||
public abstract boolean isPostRelogUpdateEnabled();
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf out)
|
||||
{
|
||||
out.writeInt(this.getRenderDistance());
|
||||
out.writeInt(this.getFullDataRequestRateLimit());
|
||||
out.writeBoolean(this.isRealTimeUpdatesEnabled());
|
||||
out.writeBoolean(this.isPostRelogUpdateEnabled());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.config;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class MultiplayerConfig extends AbstractMultiplayerConfig
|
||||
{
|
||||
public int renderDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get();
|
||||
@Override public int getRenderDistance() { return renderDistance; }
|
||||
|
||||
public int fullDataRequestRateLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.requestRateLimit.get();
|
||||
@Override public int getFullDataRequestRateLimit() { return fullDataRequestRateLimit; }
|
||||
|
||||
public boolean realTimeUpdatesEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates.get();
|
||||
@Override public boolean isRealTimeUpdatesEnabled() { return realTimeUpdatesEnabled; }
|
||||
|
||||
public boolean postRelogUpdateEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate.get();
|
||||
@Override public boolean isPostRelogUpdateEnabled() { return postRelogUpdateEnabled; }
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf in)
|
||||
{
|
||||
this.renderDistance = in.readInt();
|
||||
this.fullDataRequestRateLimit = in.readInt();
|
||||
this.realTimeUpdatesEnabled = in.readBoolean();
|
||||
this.postRelogUpdateEnabled = in.readBoolean();
|
||||
}
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
return "MultiplayerConfig{" +
|
||||
"renderDistance=" + renderDistance +
|
||||
", fullDataRequestRateLimit=" + fullDataRequestRateLimit +
|
||||
", realTimeUpdatesEnabled=" + realTimeUpdatesEnabled +
|
||||
", postRelogUpdatesEnabled=" + postRelogUpdateEnabled +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.config;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
public class MultiplayerConfigChangeListener implements Closeable
|
||||
{
|
||||
private final ConfigChangeListener<Integer> renderDistance;
|
||||
private final ConfigChangeListener<Integer> rateLimit;
|
||||
private final ConfigChangeListener<Boolean> enableRealTimeUpdates;
|
||||
private final ConfigChangeListener<Boolean> enablePostRelogUpdate;
|
||||
|
||||
public MultiplayerConfigChangeListener(Runnable runnable)
|
||||
{
|
||||
renderDistance = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance, ignored -> runnable.run());
|
||||
rateLimit = new ConfigChangeListener<>(Config.Client.Advanced.Multiplayer.ServerNetworking.requestRateLimit, ignored -> runnable.run());
|
||||
enableRealTimeUpdates = new ConfigChangeListener<>(Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates, ignored -> runnable.run());
|
||||
enablePostRelogUpdate = new ConfigChangeListener<>(Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate, ignored -> runnable.run());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
renderDistance.close();
|
||||
rateLimit.close();
|
||||
enableRealTimeUpdates.close();
|
||||
enablePostRelogUpdate.close();
|
||||
}
|
||||
|
||||
}
|
||||
+19
-1
@@ -1,14 +1,17 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer;
|
||||
package com.seibel.distanthorizons.core.multiplayer.server;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfig;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.network.ScopedNetworkEventSource;
|
||||
import com.seibel.distanthorizons.core.network.NetworkServer;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.ILevelRelatedMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.AckMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.session.PlayerUUIDMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.session.RemotePlayerConfigMessage;
|
||||
import com.seibel.distanthorizons.core.network.protocol.NetworkMessage;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -26,6 +29,8 @@ public class RemotePlayerConnectionHandler implements Closeable
|
||||
private final HashMap<UUID, ServerPlayerState> playersByUUID = new HashMap<>();
|
||||
private final BiMap<ChannelHandlerContext, ServerPlayerState> playersByConnection = HashBiMap.create();
|
||||
|
||||
private final MultiplayerConfigChangeListener configChangeListener = new MultiplayerConfigChangeListener(this::onConfigChanged);
|
||||
|
||||
public NetworkServer server() { return this.eventSource.parent; }
|
||||
|
||||
public RemotePlayerConnectionHandler(NetworkServer networkServer)
|
||||
@@ -59,6 +64,12 @@ public class RemotePlayerConnectionHandler implements Closeable
|
||||
playerUUIDMessage.sendResponse(new AckMessage());
|
||||
});
|
||||
|
||||
this.eventSource.registerHandler(RemotePlayerConfigMessage.class, this.connectedPlayersOnly((remotePlayerConfigMessage, serverPlayerState) ->
|
||||
{
|
||||
serverPlayerState.config.clientConfig = (MultiplayerConfig) remotePlayerConfigMessage.payload;
|
||||
serverPlayerState.channelContext.writeAndFlush(new RemotePlayerConfigMessage(serverPlayerState.config));
|
||||
}));
|
||||
|
||||
this.eventSource.registerHandler(CloseEvent.class, closeEvent ->
|
||||
{
|
||||
ServerPlayerState dhPlayer = this.playersByConnection.remove(closeEvent.getChannelContext());
|
||||
@@ -69,6 +80,12 @@ public class RemotePlayerConnectionHandler implements Closeable
|
||||
});
|
||||
}
|
||||
|
||||
private void onConfigChanged()
|
||||
{
|
||||
for (ServerPlayerState serverPlayerState : this.getConnectedPlayers())
|
||||
serverPlayerState.channelContext.writeAndFlush(new RemotePlayerConfigMessage(serverPlayerState.config));
|
||||
}
|
||||
|
||||
public <T extends NetworkMessage> Consumer<T> connectedPlayersOnly(BiConsumer<T, ServerPlayerState> next)
|
||||
{
|
||||
return msg ->
|
||||
@@ -131,6 +148,7 @@ public class RemotePlayerConnectionHandler implements Closeable
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
this.configChangeListener.close();
|
||||
this.eventSource.close();
|
||||
this.server().close();
|
||||
}
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer;
|
||||
package com.seibel.distanthorizons.core.multiplayer.server;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -8,8 +8,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public class ServerPlayerState
|
||||
{
|
||||
public IServerPlayerWrapper serverPlayer;
|
||||
public MultiplayerConfig config;
|
||||
public ChannelHandlerContext channelContext;
|
||||
|
||||
public ServersideMultiplayerConfig config = new ServersideMultiplayerConfig();
|
||||
public final AtomicInteger pendingFullDataRequests = new AtomicInteger();
|
||||
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.server;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.AbstractMultiplayerConfig;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfig;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* Used for constraining the client config to the server config.
|
||||
*/
|
||||
public class ServersideMultiplayerConfig extends AbstractMultiplayerConfig
|
||||
{
|
||||
public MultiplayerConfig clientConfig = new MultiplayerConfig();
|
||||
|
||||
@Override
|
||||
public int getRenderDistance()
|
||||
{
|
||||
return Math.min(clientConfig.renderDistance, Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFullDataRequestRateLimit()
|
||||
{
|
||||
return Math.min(clientConfig.fullDataRequestRateLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.requestRateLimit.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTimeUpdatesEnabled()
|
||||
{
|
||||
return clientConfig.realTimeUpdatesEnabled && Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostRelogUpdateEnabled() {
|
||||
return clientConfig.postRelogUpdateEnabled && Config.Client.Advanced.Multiplayer.ServerNetworking.enablePostRelogUpdate.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf in)
|
||||
{
|
||||
throw new UnsupportedOperationException("Decoding is not supported for server-only class.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.core.network.messages.base.HelloMessage;
|
||||
import com.seibel.distanthorizons.core.network.protocol.FutureTrackableNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.network.protocol.MessageHandler;
|
||||
import com.seibel.distanthorizons.core.network.protocol.NetworkChannelInitializer;
|
||||
import com.seibel.distanthorizons.core.network.protocol.NetworkMessage;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
@@ -131,7 +132,7 @@ public class NetworkClient extends NetworkEventSource implements AutoCloseable
|
||||
return;
|
||||
}
|
||||
|
||||
channel.writeAndFlush(new HelloMessage());
|
||||
sendMessage(new HelloMessage());
|
||||
ready = true;
|
||||
});
|
||||
|
||||
@@ -168,6 +169,11 @@ public class NetworkClient extends NetworkEventSource implements AutoCloseable
|
||||
});
|
||||
}
|
||||
|
||||
public final void sendMessage(NetworkMessage msg)
|
||||
{
|
||||
this.channel.writeAndFlush(msg);
|
||||
}
|
||||
|
||||
public final <TResponse extends FutureTrackableNetworkMessage> CompletableFuture<TResponse> sendRequest(FutureTrackableNetworkMessage msg, Class<TResponse> responseClass)
|
||||
{
|
||||
return this.sendRequest(this.channel.pipeline().context(MessageHandler.class), msg, responseClass);
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.seibel.distanthorizons.core.network.exceptions;
|
||||
|
||||
public class RequestRejectedException extends Exception
|
||||
{
|
||||
public RequestRejectedException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.core.network.messages.base;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.InvalidLevelException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.InvalidSectionPosException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.RequestRejectedException;
|
||||
import com.seibel.distanthorizons.core.network.protocol.FutureTrackableNetworkMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
@@ -36,6 +37,7 @@ public class ExceptionMessage extends FutureTrackableNetworkMessage
|
||||
add(RateLimitedException.class);
|
||||
add(InvalidLevelException.class);
|
||||
add(InvalidSectionPosException.class);
|
||||
add(RequestRejectedException.class);
|
||||
}};
|
||||
|
||||
public Exception exception;
|
||||
|
||||
-2
@@ -73,10 +73,8 @@ public class FullDataSourceResponseMessage extends FutureTrackableNetworkMessage
|
||||
this.dataBuffer = in.readBytes(in.readInt());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CompleteFullDataSource getFullDataSource(DhSectionPos pos, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
|
||||
try (ByteBufInputStream inputStream = new ByteBufInputStream(dataBuffer))
|
||||
{
|
||||
return fullDataSourceLoader.loadData(pos, new DhDataInputStream(inputStream), level);
|
||||
|
||||
+8
-7
@@ -19,23 +19,24 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.network.messages.session;
|
||||
|
||||
import com.seibel.distanthorizons.core.multiplayer.MultiplayerConfig;
|
||||
import com.seibel.distanthorizons.core.network.protocol.FutureTrackableNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.AbstractMultiplayerConfig;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfig;
|
||||
import com.seibel.distanthorizons.core.network.protocol.INetworkObject;
|
||||
import com.seibel.distanthorizons.core.network.protocol.NetworkMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class RemotePlayerConfigMessage extends FutureTrackableNetworkMessage
|
||||
public class RemotePlayerConfigMessage extends NetworkMessage
|
||||
{
|
||||
public MultiplayerConfig payload;
|
||||
public AbstractMultiplayerConfig payload;
|
||||
|
||||
public RemotePlayerConfigMessage() { }
|
||||
public RemotePlayerConfigMessage(MultiplayerConfig payload) { this.payload = payload; }
|
||||
public RemotePlayerConfigMessage(AbstractMultiplayerConfig payload) { this.payload = payload; }
|
||||
|
||||
@Override
|
||||
public void encode0(ByteBuf out) { this.payload.encode(out); }
|
||||
public void encode(ByteBuf out) { this.payload.encode(out); }
|
||||
|
||||
@Override
|
||||
public void decode0(ByteBuf in) { this.payload = INetworkObject.decodeStatic(new MultiplayerConfig(), in); }
|
||||
public void decode(ByteBuf in) { this.payload = INetworkObject.decodeStatic(new MultiplayerConfig(), in); }
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.multiplayer.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.network.NetworkClient;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.EventLoop;
|
||||
@@ -63,7 +63,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
this.saveStructure = new ClientOnlySaveStructure();
|
||||
this.levels = new ConcurrentHashMap<>();
|
||||
|
||||
if (Config.Client.Advanced.Multiplayer.enableServerNetworking.get())
|
||||
if (Config.Client.Advanced.Multiplayer.ServerNetworking.enableServerNetworking.get())
|
||||
{
|
||||
// TODO server specific configs
|
||||
NetworkClient networkClient = new NetworkClient(MC_CLIENT.getCurrentServerIp(), 25049);
|
||||
|
||||
@@ -19,15 +19,11 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.AppliedConfigState;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.file.structure.LocalSaveStructure;
|
||||
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.multiplayer.ServerPlayerState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.RemotePlayerConnectionHandler;
|
||||
import com.seibel.distanthorizons.core.multiplayer.server.RemotePlayerConnectionHandler;
|
||||
import com.seibel.distanthorizons.core.network.NetworkServer;
|
||||
import com.seibel.distanthorizons.core.network.messages.session.RemotePlayerConfigMessage;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
@@ -41,10 +37,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
{
|
||||
private final HashMap<IServerLevelWrapper, DhServerLevel> levels;
|
||||
public final LocalSaveStructure saveStructure;
|
||||
|
||||
private final RemotePlayerConnectionHandler remotePlayerConnectionHandler;
|
||||
private final AppliedConfigState<Integer> rateLimitConfig = new AppliedConfigState<>(Config.Client.Advanced.Multiplayer.serverNetworkingRateLimit);
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
@@ -61,21 +54,9 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
// TODO move to global payload once server specific configs are implemented
|
||||
NetworkServer networkServer = new NetworkServer(25049);
|
||||
this.remotePlayerConnectionHandler = new RemotePlayerConnectionHandler(networkServer);
|
||||
this.registerNetworkHandlers();
|
||||
|
||||
LOGGER.info("Started "+DhServerWorld.class.getSimpleName()+" of type "+this.environment);
|
||||
}
|
||||
|
||||
private void registerNetworkHandlers()
|
||||
{
|
||||
this.remotePlayerConnectionHandler.server().registerHandler(RemotePlayerConfigMessage.class, remotePlayerConfigMessage ->
|
||||
{
|
||||
this.remotePlayerConnectionHandler.getConnectedPlayer(remotePlayerConfigMessage).config = remotePlayerConfigMessage.payload;
|
||||
|
||||
remotePlayerConfigMessage.payload.fullDataRequestRateLimit = Math.min(rateLimitConfig.get(), remotePlayerConfigMessage.payload.fullDataRequestRateLimit);
|
||||
remotePlayerConfigMessage.sendResponse(remotePlayerConfigMessage);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -95,8 +76,8 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
}
|
||||
public void changePlayerLevel(IServerPlayerWrapper player, IServerLevelWrapper origin, IServerLevelWrapper dest)
|
||||
{
|
||||
this.getLevel(origin).removePlayer(player);
|
||||
this.getLevel(dest).addPlayer(player);
|
||||
this.getLevel(origin).removePlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,15 +128,6 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
|
||||
public void serverTick() {
|
||||
this.levels.values().forEach(DhServerLevel::serverTick);
|
||||
|
||||
if (rateLimitConfig.pollNewValue())
|
||||
{
|
||||
for (ServerPlayerState serverPlayerState : this.remotePlayerConnectionHandler.getConnectedPlayers())
|
||||
{
|
||||
serverPlayerState.config.fullDataRequestRateLimit = rateLimitConfig.get();
|
||||
serverPlayerState.channelContext.writeAndFlush(new RemotePlayerConfigMessage(serverPlayerState.config));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void doWorldGen() {
|
||||
|
||||
Reference in New Issue
Block a user