Use ConfigBasedLogger
Add sub-sectioning to server networking section
This commit is contained in:
@@ -802,8 +802,6 @@ 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(""
|
||||
@@ -849,8 +847,11 @@ public class Config
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigCategory serverNetworking = new ConfigCategory.Builder().set(ServerNetworking.class).build();
|
||||
|
||||
public static class ServerNetworking
|
||||
{
|
||||
public static ConfigUIComment generalSectionNote = new ConfigUIComment();
|
||||
public static ConfigEntry<Boolean> enableServerNetworking = new ConfigEntry.Builder<Boolean>()
|
||||
.setServersideShortName("enableServerNetworking")
|
||||
.set(true)
|
||||
@@ -884,6 +885,7 @@ public class Config
|
||||
.build();
|
||||
|
||||
|
||||
public static ConfigUIComment generationSectionNote = new ConfigUIComment();
|
||||
public static ConfigEntry<Integer> generationRequestRCLimit = new ConfigEntry.Builder<Integer>()
|
||||
.setServersideShortName("generationRequestRCLimit")
|
||||
.setMinDefaultMax(1, 20, 100)
|
||||
@@ -909,6 +911,7 @@ public class Config
|
||||
.build();
|
||||
|
||||
|
||||
public static ConfigUIComment realTimeUpdatesSectionNote = new ConfigUIComment();
|
||||
public static ConfigEntry<Boolean> enableRealTimeUpdates = new ConfigEntry.Builder<Boolean>()
|
||||
.setServersideShortName("enableRealTimeUpdates")
|
||||
.set(false)
|
||||
@@ -918,6 +921,7 @@ public class Config
|
||||
.build();
|
||||
|
||||
|
||||
public static ConfigUIComment loginDataSyncSectionNote = new ConfigUIComment();
|
||||
public static ConfigEntry<Boolean> enableLoginDataSync = new ConfigEntry.Builder<Boolean>()
|
||||
.setServersideShortName("enableLoginDataSync")
|
||||
.set(false)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.seibel.distanthorizons.core.network;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
|
||||
import com.seibel.distanthorizons.core.network.protocol.FutureTrackableNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.network.protocol.NetworkMessage;
|
||||
@@ -7,14 +9,14 @@ import io.netty.channel.ChannelException;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface IConnection
|
||||
{
|
||||
Logger LOGGER = LogManager.getLogger();
|
||||
ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
|
||||
|
||||
ChannelHandlerContext getChannelContext();
|
||||
NetworkEventSource getRequestHandler();
|
||||
@@ -26,7 +28,7 @@ public interface IConnection
|
||||
|
||||
default CompletableFuture<Void> sendMessage(NetworkMessage message)
|
||||
{
|
||||
LOGGER.trace("Sending message: " + message);
|
||||
LOGGER.debug("Sending message: " + message);
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
|
||||
ChannelHandlerContext ctx = this.getChannelContext();
|
||||
|
||||
@@ -19,19 +19,19 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.network;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.HelloMessage;
|
||||
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;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.EnumSet;
|
||||
@@ -40,7 +40,8 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class NetworkClient extends NetworkEventSource implements IConnection, AutoCloseable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
|
||||
|
||||
private enum EConnectionState
|
||||
{
|
||||
@@ -67,7 +68,7 @@ public class NetworkClient extends NetworkEventSource implements IConnection, Au
|
||||
public boolean isClosed() { return closedStates.contains(this.connectionState); }
|
||||
private boolean ready;
|
||||
/** Indicates whether the connection is established and first message is sent. */
|
||||
public boolean isReady() { return ready; }
|
||||
public boolean isReady() { return this.ready; }
|
||||
|
||||
private final EventLoopGroup workerGroup = new NioEventLoopGroup(0, new DefaultThreadFactory("DH-Network - Client Thread"));
|
||||
private final Bootstrap clientBootstrap = new Bootstrap()
|
||||
@@ -98,7 +99,7 @@ public class NetworkClient extends NetworkEventSource implements IConnection, Au
|
||||
{
|
||||
this.registerHandler(CloseReasonMessage.class, closeReasonMessage ->
|
||||
{
|
||||
LOGGER.info(closeReasonMessage.reason);
|
||||
LOGGER.warn(closeReasonMessage.reason);
|
||||
this.connectionState = EConnectionState.CLOSING;
|
||||
});
|
||||
|
||||
@@ -114,7 +115,10 @@ public class NetworkClient extends NetworkEventSource implements IConnection, Au
|
||||
|
||||
public void startConnecting()
|
||||
{
|
||||
if (!isInitialState()) return;
|
||||
if (!this.isInitialState())
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.connect();
|
||||
}
|
||||
|
||||
@@ -123,8 +127,6 @@ public class NetworkClient extends NetworkEventSource implements IConnection, Au
|
||||
LOGGER.info("Connecting to server: "+this.address);
|
||||
this.connectionState = EConnectionState.OPEN;
|
||||
|
||||
// FIXME sometimes this causes the MC connection to crash
|
||||
// this might happen if the URL can't be converted to a IP (IE UnknownHostException)
|
||||
ChannelFuture connectFuture = this.clientBootstrap.connect(this.address);
|
||||
this.channel = connectFuture.channel();
|
||||
|
||||
@@ -132,23 +134,25 @@ public class NetworkClient extends NetworkEventSource implements IConnection, Au
|
||||
{
|
||||
if (!channelFuture.isSuccess())
|
||||
{
|
||||
LOGGER.warn("Connection failed: "+channelFuture.cause());
|
||||
LOGGER.info("Connection failed: " + channelFuture.cause());
|
||||
return;
|
||||
}
|
||||
|
||||
sendMessage(new HelloMessage());
|
||||
ready = true;
|
||||
this.sendMessage(new HelloMessage());
|
||||
this.ready = true;
|
||||
});
|
||||
|
||||
this.channel.closeFuture().addListener((ChannelFuture channelFuture) ->
|
||||
{
|
||||
ready = false;
|
||||
this.ready = false;
|
||||
this.completeAllFuturesExceptionally(channelFuture.cause() != null
|
||||
? channelFuture.cause()
|
||||
: new ChannelException("Channel is closed."));
|
||||
|
||||
if (this.connectionState != EConnectionState.OPEN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.reconnectAttempts--;
|
||||
LOGGER.info("Reconnection attempts left: [" + this.reconnectAttempts + "] of [" + FAILURE_RECONNECT_ATTEMPTS + "].");
|
||||
|
||||
+35
-11
@@ -19,7 +19,8 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.network;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CancelMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.ExceptionMessage;
|
||||
@@ -27,7 +28,7 @@ import com.seibel.distanthorizons.core.network.protocol.FutureTrackableNetworkMe
|
||||
import com.seibel.distanthorizons.core.network.protocol.MessageRegistry;
|
||||
import com.seibel.distanthorizons.core.network.protocol.NetworkMessage;
|
||||
import io.netty.channel.ChannelException;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.io.InvalidClassException;
|
||||
import java.util.HashSet;
|
||||
@@ -40,7 +41,8 @@ import java.util.function.Consumer;
|
||||
|
||||
public abstract class NetworkEventSource
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
|
||||
protected final ConcurrentMap<Class<? extends NetworkMessage>, Set<Consumer<NetworkMessage>>> handlers = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<IConnection, ConcurrentMap<Long, FutureResponseData>> pendingFutures = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -67,7 +69,7 @@ public abstract class NetworkEventSource
|
||||
if (message instanceof FutureTrackableNetworkMessage)
|
||||
{
|
||||
FutureTrackableNetworkMessage trackableMessage = (FutureTrackableNetworkMessage)message;
|
||||
ConcurrentMap<Long, FutureResponseData> subMap = pendingFutures.get(message.getConnection());
|
||||
ConcurrentMap<Long, FutureResponseData> subMap = this.pendingFutures.get(message.getConnection());
|
||||
if (subMap != null)
|
||||
{
|
||||
FutureResponseData responseData = subMap.get(trackableMessage.futureId);
|
||||
@@ -76,17 +78,25 @@ public abstract class NetworkEventSource
|
||||
handled = true;
|
||||
|
||||
if (message instanceof ExceptionMessage)
|
||||
{
|
||||
responseData.future.completeExceptionally(((ExceptionMessage) message).exception);
|
||||
}
|
||||
else if (message.getClass() != responseData.responseClass)
|
||||
{
|
||||
responseData.future.completeExceptionally(new InvalidClassException("Response with invalid type: expected " + responseData.responseClass.getSimpleName() + ", got:" + message));
|
||||
}
|
||||
else
|
||||
{
|
||||
responseData.future.complete(trackableMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled && message.warnWhenUnhandled())
|
||||
{
|
||||
LOGGER.warn("Unhandled message: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addNewConnection(IConnection connection)
|
||||
@@ -101,7 +111,9 @@ public abstract class NetworkEventSource
|
||||
{
|
||||
// Will throw if the handler class is not found
|
||||
if (handlerClass != CloseEvent.class)
|
||||
{
|
||||
MessageRegistry.INSTANCE.getMessageId(handlerClass);
|
||||
}
|
||||
return new HashSet<>();
|
||||
})
|
||||
.add((Consumer<NetworkMessage>) handlerImplementation);
|
||||
@@ -123,16 +135,20 @@ public abstract class NetworkEventSource
|
||||
{
|
||||
if (!(throwable instanceof ChannelException))
|
||||
{
|
||||
ConcurrentMap<Long, FutureResponseData> subMap = pendingFutures.get(connection);
|
||||
ConcurrentMap<Long, FutureResponseData> subMap = this.pendingFutures.get(connection);
|
||||
if (subMap != null)
|
||||
{
|
||||
subMap.remove(msg.futureId);
|
||||
}
|
||||
}
|
||||
|
||||
if (throwable instanceof CancellationException)
|
||||
{
|
||||
msg.sendResponse(new CancelMessage());
|
||||
}
|
||||
});
|
||||
|
||||
ConcurrentMap<Long, FutureResponseData> subMap = pendingFutures.get(connection);
|
||||
ConcurrentMap<Long, FutureResponseData> subMap = this.pendingFutures.get(connection);
|
||||
if (subMap == null)
|
||||
{
|
||||
// Was deleted before adding
|
||||
@@ -140,9 +156,10 @@ public abstract class NetworkEventSource
|
||||
return responseFuture;
|
||||
}
|
||||
subMap.put(msg.futureId, new FutureResponseData(responseClass, responseFuture));
|
||||
if (!pendingFutures.containsKey(connection))
|
||||
if (!this.pendingFutures.containsKey(connection))
|
||||
{
|
||||
// Was deleted while adding
|
||||
// Note: removal from subMap will happen in whenComplete above
|
||||
responseFuture.completeExceptionally(connection.getCloseReason());
|
||||
return responseFuture;
|
||||
}
|
||||
@@ -153,23 +170,30 @@ public abstract class NetworkEventSource
|
||||
|
||||
protected final void completeAllFuturesExceptionally(IConnection connection, Throwable cause)
|
||||
{
|
||||
ConcurrentMap<Long, FutureResponseData> map = pendingFutures.remove(connection);
|
||||
if (map == null) return;
|
||||
ConcurrentMap<Long, FutureResponseData> map = this.pendingFutures.remove(connection);
|
||||
if (map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (FutureResponseData responseData : map.values())
|
||||
{
|
||||
responseData.future.completeExceptionally(cause);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void completeAllFuturesExceptionally(Throwable cause)
|
||||
{
|
||||
for (IConnection connection : pendingFutures.keySet())
|
||||
for (IConnection connection : this.pendingFutures.keySet())
|
||||
{
|
||||
this.completeAllFuturesExceptionally(connection, cause);
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
this.handlers.clear();
|
||||
completeAllFuturesExceptionally(new ChannelException(this.getClass().getSimpleName()+" is closed."));
|
||||
this.completeAllFuturesExceptionally(new ChannelException(this.getClass().getSimpleName() + " is closed."));
|
||||
}
|
||||
|
||||
private static class FutureResponseData
|
||||
|
||||
@@ -20,28 +20,32 @@
|
||||
package com.seibel.distanthorizons.core.network;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.HelloMessage;
|
||||
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 com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class NetworkServer extends NetworkEventSource implements AutoCloseable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
|
||||
|
||||
private final int port;
|
||||
|
||||
|
||||
+5
-3
@@ -19,12 +19,13 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.network.protocol;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseEvent;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -33,7 +34,8 @@ import java.util.function.Consumer;
|
||||
@ChannelHandler.Sharable
|
||||
public class MessageHandler extends SimpleChannelInboundHandler<NetworkMessage>
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
|
||||
|
||||
private final BiConsumer<ChannelHandlerContext, NetworkMessage> messageConsumer;
|
||||
private final Consumer<ChannelHandlerContext> channelActiveConsumer;
|
||||
@@ -47,7 +49,7 @@ public class MessageHandler extends SimpleChannelInboundHandler<NetworkMessage>
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext channelContext, NetworkMessage message)
|
||||
{
|
||||
LOGGER.trace("Received message: " + message);
|
||||
LOGGER.debug("Received message: " + message);
|
||||
this.messageConsumer.accept(channelContext, message);
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -19,14 +19,16 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.network.protocol;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
public class NetworkExceptionHandler extends ChannelInboundHandlerAdapter
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext channelContext, Throwable cause)
|
||||
|
||||
@@ -345,19 +345,22 @@
|
||||
"Multiplayer",
|
||||
|
||||
"distanthorizons.config.client.advanced.multiplayer.serverNetworking": "Server Networking",
|
||||
|
||||
"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.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.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.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.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",
|
||||
|
||||
Reference in New Issue
Block a user