[skip ci] Somewhere

This commit is contained in:
s809
2024-05-22 23:18:18 +05:00
parent 44205664b5
commit 1f63bdf124
14 changed files with 87 additions and 237 deletions
@@ -139,7 +139,7 @@ public class ClientApi
this.waitingClientLevels.clear();
this.pluginChannelApi.onJoin(world.networkState);
this.pluginChannelApi.onJoin(world.networkState.getSession());
}
}
@@ -156,7 +156,6 @@ public class ClientApi
}
// clear the previous server's information
this.pluginChannelApi.close();
this.pluginChannelApi = new ClientPluginChannelApi(this::clientLevelLoadEvent, this::clientLevelUnloadEvent);
// remove any waiting items
@@ -541,4 +540,4 @@ public class ClientApi
*/
public void showChatMessageNextFrame(String chatMessage) { this.chatMessageQueueForNextFrame.add(chatMessage); }
}
}
@@ -9,7 +9,6 @@ import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
import com.seibel.distanthorizons.core.network.messages.plugin.PluginCloseEvent;
import com.seibel.distanthorizons.core.network.messages.plugin.CurrentLevelKeyMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.base.HelloMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.ServerConnectInfoMessage;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelSession;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -19,20 +18,18 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
public class ClientPluginChannelApi implements AutoCloseable
/** This class is used to manage the plugin channel session and Multiverse level keys. */
public class ClientPluginChannelApi
{
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
private final PluginChannelSession channelHandler = new PluginChannelSession();
private final Consumer<IClientLevelWrapper> levelUnloadHandler;
private final Consumer<IServerKeyedClientLevel> multiverseLevelLoadHandler;
@Nullable
private ClientNetworkState networkState;
private PluginChannelSession session;
public boolean allowLoadingLevel()
@@ -47,15 +44,16 @@ public class ClientPluginChannelApi implements AutoCloseable
this.levelUnloadHandler = levelUnloadHandler;
this.multiverseLevelLoadHandler = levelLoadHandler;
this.channelHandler.registerHandler(CurrentLevelKeyMessage.class, this::onCurrentLevelKeyMessage);
this.channelHandler.registerHandler(ServerConnectInfoMessage.class, this::onServerConnectInfoMessage);
this.channelHandler.registerHandler(PluginCloseEvent.class, this::onClose);
}
public void onJoin(@Nullable ClientNetworkState networkState)
public void onJoin(PluginChannelSession session)
{
this.networkState = networkState;
this.channelHandler.sendMessageClient(new HelloMessage());
this.session = session;
this.session.sendMessage(new HelloMessage());
this.session.registerHandler(CurrentLevelKeyMessage.class, this::onCurrentLevelKeyMessage);
this.session.registerHandler(PluginCloseEvent.class, this::onClose);
}
private void onCurrentLevelKeyMessage(CurrentLevelKeyMessage msg)
@@ -80,18 +78,6 @@ public class ClientPluginChannelApi implements AutoCloseable
});
}
private void onServerConnectInfoMessage(ServerConnectInfoMessage msg)
{
if (this.networkState != null)
{
this.networkState.getSession().resetAndConnectTo(
msg.ipOverride != null
? msg.ipOverride
: MC.getCurrentServerIp().split(":")[0],
msg.port);
}
}
public void onClientLevelUnload()
{
KEYED_CLIENT_LEVEL_MANAGER.clearServerKeyedLevel();
@@ -104,13 +90,7 @@ public class ClientPluginChannelApi implements AutoCloseable
public void handlePacket(ByteBuf buffer)
{
this.channelHandler.decodeAndHandle(buffer);
}
@Override
public void close()
{
this.channelHandler.close();
this.session.decodeAndHandle(buffer);
}
}
@@ -250,7 +250,7 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel
if (distanceFromPlayer >= serverPlayerState.serverPlayer.getViewDistance() &&
distanceFromPlayer <= serverPlayerState.config.getRenderDistanceRadius())
{
serverPlayerState.connection.sendMessage(new FullDataPartialUpdateMessage(this.serverLevelWrapper, data));
serverPlayerState.session.sendMessage(new FullDataPartialUpdateMessage(this.serverLevelWrapper, data));
}
}
@@ -6,10 +6,9 @@ import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfig;
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfigChangeListener;
import com.seibel.distanthorizons.core.network.netty.NettyClient;
import com.seibel.distanthorizons.core.network.ScopedNetworkEventSource;
import com.seibel.distanthorizons.core.network.messages.plugin.PluginCloseEvent;
import com.seibel.distanthorizons.core.network.messages.plugin.base.AckMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.base.NettyCloseEvent;
import com.seibel.distanthorizons.core.network.messages.plugin.base.HelloMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.session.PlayerUUIDMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.session.RemotePlayerConfigMessage;
@@ -18,7 +17,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli
import org.apache.logging.log4j.LogManager;
import java.io.Closeable;
import java.text.MessageFormat;
import java.util.UUID;
public class ClientNetworkState implements Closeable
@@ -27,8 +25,9 @@ public class ClientNetworkState implements Closeable
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private final PluginChannelSession session;
private final UUID playerUUID = MC_CLIENT.getPlayerUUID();
private final PluginChannelSession session = new PluginChannelSession(null);
private EServerSupportStatus serverSupportStatus = EServerSupportStatus.NONE;
public MultiplayerConfig config = new MultiplayerConfig();
@@ -47,13 +46,12 @@ public class ClientNetworkState implements Closeable
/**
* Constructs a new instance.
*/
public ClientNetworkState(PluginChannelSession session)
public ClientNetworkState()
{
this.session = session;
this.session.registerHandler(HelloMessage.class, helloMessage ->
{
LOGGER.info("Connected to server: "+helloMessage.getConnection().getRemoteAddress());
LOGGER.info("Server reported full DH support.");
serverSupportStatus = EServerSupportStatus.FULL;
this.getSession().sendRequest(new PlayerUUIDMessage(this.playerUUID), AckMessage.class)
.thenAccept(ack -> this.getSession().sendMessage(new RemotePlayerConfigMessage(new MultiplayerConfig())))
@@ -70,7 +68,7 @@ public class ClientNetworkState implements Closeable
this.configReceived = true;
});
this.session.registerHandler(NettyCloseEvent.class, msg ->
this.session.registerHandler(PluginCloseEvent.class, msg ->
{
this.configReceived = false;
});
@@ -84,27 +82,22 @@ public class ClientNetworkState implements Closeable
private String[] f3Log()
{
if (!this.session.isInitialized())
if (this.session.isClosed())
{
return new String[]{"Did not receive connection info yet..."};
return new String[]{
"Session closed: " + this.session.getCloseReason().getMessage()
};
}
if (!this.session.isClosed())
if (!this.configReceived)
{
return new String[]{
this.session.getRemoteAddress() != null
? (this.isReady() ? "Connected to server" : "Connecting to server...")
: MessageFormat.format("Disconnected, attempts left: {0} / {1}", this.session.getReconnectionAttemptsLeft(), NettyClient.RECONNECTION_ATTEMPTS)
};
}
else
{
return new String[]{
this.session.getCloseReason() != null
? "Disconnected: " + this.session.getCloseReason().getMessage()
: "Disconnected (check logs for more information)"
};
return new String[]{"Server does not support DH"};
}
if (!this.session.isClosed()) return new String[]{
"Server has full DH support"
};
return
}
@Override
@@ -114,4 +107,18 @@ public class ClientNetworkState implements Closeable
this.configChangeListener.close();
this.session.close();
}
private enum EServerSupportStatus
{
NONE("Server does not support DH"),
LEVELS_ONLY("Server supports shared level keys"),
FULL("Server has full DH support");
public final String message;
EServerSupportStatus(String message)
{
this.message = message;
}
}
}
@@ -31,7 +31,7 @@ public class RemotePlayerConnectionHandler implements Closeable
public void handlePluginMessage(IServerPlayerWrapper player, ByteBuf buffer)
{
this.connectedPlayers.get(player).connection.decodeAndHandle(buffer);
this.connectedPlayers.get(player).session.decodeAndHandle(buffer);
}
@@ -10,10 +10,8 @@ import com.seibel.distanthorizons.core.network.messages.plugin.PluginCloseEvent;
import com.seibel.distanthorizons.core.network.messages.plugin.base.HelloMessage;
import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException;
import com.seibel.distanthorizons.core.network.messages.plugin.fullData.FullDataSourceRequestMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.fullData.generation.GenTaskPriorityRequestMessage;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelSession;
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.apache.logging.log4j.LogManager;
import org.jetbrains.annotations.NotNull;
@@ -27,12 +25,11 @@ public class ServerPlayerState
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
public final IServerPlayerWrapper serverPlayer;
public final PluginChannelSession connection = new PluginChannelSession();
private final MultiplayerConfigChangeListener configChangeListener = new MultiplayerConfigChangeListener(this::onConfigChanged);
public final PluginChannelSession session;
@NotNull
public ConstrainedMultiplayerConfig config = new ConstrainedMultiplayerConfig();
private final MultiplayerConfigChangeListener configChangeListener = new MultiplayerConfigChangeListener(this::onConfigChanged);
private final ConcurrentHashMap<DhServerLevel, RateLimiterSet> rateLimiterSets = new ConcurrentHashMap<>();
public RateLimiterSet getRateLimiterSet(DhServerLevel level)
@@ -44,25 +41,29 @@ public class ServerPlayerState
this.rateLimiterSets.clear();
}
public ServerPlayerState(IServerPlayerWrapper serverPlayer)
{
this.serverPlayer = serverPlayer;
this.session = new PluginChannelSession(serverPlayer);
this.connection.registerHandler(RemotePlayerConfigMessage.class, remotePlayerConfigMessage ->
this.session.registerHandler(RemotePlayerConfigMessage.class, remotePlayerConfigMessage ->
{
this.config.clientConfig = (MultiplayerConfig) remotePlayerConfigMessage.payload;
this.connection.sendMessage(new RemotePlayerConfigMessage(this.config));
this.session.sendMessage(new RemotePlayerConfigMessage(this.config));
});
this.connection.registerHandler(HelloMessage.class, msg -> {
this.session.registerHandler(HelloMessage.class, msg -> {
this.initializeLodSession();
});
this.connection.registerHandler(PluginCloseEvent.class, event -> {
this.session.registerHandler(PluginCloseEvent.class, event -> {
// Noop
});
}
public void initializeLodSession()
{
}
@@ -70,12 +71,12 @@ public class ServerPlayerState
public void close()
{
this.configChangeListener.close();
this.connection.close();
this.session.close();
}
private void onConfigChanged()
{
this.connection.sendMessage(new RemotePlayerConfigMessage(this.config));
this.session.sendMessage(new RemotePlayerConfigMessage(this.config));
}
@@ -88,13 +89,6 @@ public class ServerPlayerState
}
);
public final SupplierBasedRateLimiter<GenTaskPriorityRequestMessage> genTaskPriorityRequestRateLimiter = new SupplierBasedRateLimiter<>(
() -> ServerNetworking.genTaskPriorityRequestRateLimit.get(),
msg -> {
msg.sendResponse(new RateLimitedException("Generation task priority check rate limit: " + ServerPlayerState.this.config.getFullDataRequestConcurrencyLimit()));
}
);
public final SupplierBasedRateAndConcurrencyLimiter<FullDataSourceRequestMessage> loginDataSyncRCLimiter = new SupplierBasedRateAndConcurrencyLimiter<>(
() -> ServerNetworking.loginDataSyncRCLimit.get(),
msg -> {
@@ -21,16 +21,15 @@ 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.PluginMessageRegistry;
import com.seibel.distanthorizons.core.network.messages.plugin.base.CancelMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.base.ExceptionMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.PluginCloseEvent;
import com.seibel.distanthorizons.core.network.messages.plugin.PluginMessageRegistry;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelMessage;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelSession;
import com.seibel.distanthorizons.core.network.plugin.TrackableMessage;
import com.seibel.distanthorizons.coreapi.ModInfo;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelHandlerContext;
import org.apache.logging.log4j.LogManager;
import java.io.InvalidClassException;
@@ -129,16 +128,16 @@ public abstract class NetworkEventSource
}
protected <TResponse extends TrackableMessage> CompletableFuture<TResponse> createRequest(PluginChannelSession connection, TrackableMessage msg, Class<TResponse> responseClass)
protected <TResponse extends TrackableMessage> CompletableFuture<TResponse> createRequest(PluginChannelSession session, TrackableMessage msg, Class<TResponse> responseClass)
{
msg.setConnection(connection);
msg.setConnection(session);
CompletableFuture<TResponse> responseFuture = new CompletableFuture<>();
responseFuture.whenComplete((response, throwable) ->
{
if (!(throwable instanceof ChannelException))
{
ConcurrentMap<Long, FutureResponseData> subMap = this.pendingFutures.get(connection);
ConcurrentMap<Long, FutureResponseData> subMap = this.pendingFutures.get(session);
if (subMap != null)
{
subMap.remove(msg.futureId);
@@ -151,19 +150,19 @@ public abstract class NetworkEventSource
}
});
ConcurrentMap<Long, FutureResponseData> subMap = this.pendingFutures.get(connection);
ConcurrentMap<Long, FutureResponseData> subMap = this.pendingFutures.get(session);
if (subMap == null)
{
// Was deleted before adding
responseFuture.completeExceptionally(connection.getCloseReason());
responseFuture.completeExceptionally(session.getCloseReason());
return responseFuture;
}
subMap.put(msg.futureId, new FutureResponseData(responseClass, responseFuture));
if (!this.pendingFutures.containsKey(connection))
if (!this.pendingFutures.containsKey(session))
{
// Was deleted while adding
// Note: removal from subMap will happen in whenComplete above
responseFuture.completeExceptionally(connection.getCloseReason());
responseFuture.completeExceptionally(session.getCloseReason());
return responseFuture;
}
// If passed until here, cancelling is up to the cleaning side
@@ -100,10 +100,10 @@ public class PluginMessageRegistry
@SuppressWarnings("unchecked")
public int getMessageId(PluginChannelMessage message)
{
return this.gePluginChannelMessageId(message.getClass());
return this.getMessageId(message.getClass());
}
public int gePluginChannelMessageId(Class<? extends PluginChannelMessage> messageClass)
public int getMessageId(Class<? extends PluginChannelMessage> messageClass)
{
try
{
@@ -1,38 +0,0 @@
package com.seibel.distanthorizons.core.network.messages.plugin;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelMessage;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nullable;
public class ServerConnectInfoMessage extends PluginChannelMessage
{
@Nullable
public String ipOverride;
public int port;
public ServerConnectInfoMessage() { }
public ServerConnectInfoMessage(@Nullable String ipOverride, int port)
{
this.ipOverride = ipOverride;
this.port = port;
}
@Override
public void encode(ByteBuf out)
{
if (this.writeOptional(out, this.ipOverride))
{
this.writeString(this.ipOverride, out);
}
out.writeShort(this.port);
}
@Override
public void decode(ByteBuf in)
{
this.ipOverride = this.readOptional(in, () -> this.readString(in));
this.port = in.readUnsignedShort();
}
}
@@ -4,60 +4,48 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.network.NetworkEventSource;
import com.seibel.distanthorizons.core.network.messages.PluginMessageRegistry;
import com.seibel.distanthorizons.core.network.messages.plugin.PluginCloseEvent;
import com.seibel.distanthorizons.core.network.messages.plugin.PluginMessageRegistry;
import com.seibel.distanthorizons.core.network.protocol.plugin.PluginMessageEncoder;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelHandlerContext;
import org.apache.logging.log4j.LogManager;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
public class PluginChannelSession extends NetworkEventSource
{
/**
* 4 MiB should be enough for any transferred data. <br>
* Currently largest transferred data is DH full data sections, which usually don't exceed 1-2 MiB in size.
*/
private static final int MAX_MESSAGE_LENGTH = 4194304;
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
private final IPluginPacketSender packetSender = SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
/**
* When set to true, any received data will be ignored. <br>
* When non-null, any received data will be ignored. <br>
* This does not include wrong versions, which are ignored without setting this flag,
* to allow multi-compat servers.
*/
private final AtomicBoolean isClosed = new AtomicBoolean();
private final AtomicReference<Throwable> closeReason = new AtomicReference<>();
public Throwable getCloseReason() { return this.closeReason.get(); }
public boolean isClosed() { return this.closeReason.get() != null; }
@Nullable
private IServerPlayerWrapper serverPlayer;
private final IServerPlayerWrapper serverPlayer;
public PluginChannelSession()
{
super(PluginMessageRegistry.INSTANCE);
}
public PluginChannelSession(@Nullable IServerPlayerWrapper serverPlayer)
{
super(PluginMessageRegistry.INSTANCE);
this.serverPlayer = serverPlayer;
}
public void decodeAndHandle(ByteBuf byteBuf)
{
if (this.isClosed.get())
if (this.closeReason.get() != null)
{
return;
}
@@ -72,7 +60,7 @@ public class PluginChannelSession extends NetworkEventSource
PluginChannelMessage msg = PluginMessageRegistry.INSTANCE.createMessage(byteBuf.readUnsignedShort());
msg.decode(byteBuf);
msg.serverPlayer = this.serverPlayer;
msg.session = this;
this.handleMessage(msg);
}
@@ -86,7 +74,7 @@ public class PluginChannelSession extends NetworkEventSource
}
}
<TResponse extends TrackableMessage> CompletableFuture<TResponse> sendRequest(TrackableMessage msg, Class<TResponse> responseClass)
public <TResponse extends TrackableMessage> CompletableFuture<TResponse> sendRequest(TrackableMessage msg, Class<TResponse> responseClass)
{
CompletableFuture<TResponse> responseFuture = this.createRequest(this, msg, responseClass);
this.sendMessage(msg);
@@ -113,10 +101,9 @@ public class PluginChannelSession extends NetworkEventSource
}
}
@Override
public void close()
public void close(Throwable closeReason)
{
if (!this.isClosed.compareAndSet(false, true))
if (!this.closeReason.compareAndSet(null, closeReason))
{
return;
}
@@ -1,70 +0,0 @@
package com.seibel.distanthorizons.core.network.plugin;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.network.messages.plugin.base.CloseReasonMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import org.apache.logging.log4j.LogManager;
import java.util.concurrent.CompletableFuture;
public class PluginChannelSessionAAAAA
{
private static final IPluginPacketSender packetSender = SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
public final IServerPlayerWrapper serverPlayer;
public boolean isClosed = false;
public PluginChannelSessionAAAAA(IServerPlayerWrapper serverPlayer)
{
this.serverPlayer = serverPlayer;
}
ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
public void sendMessage(PluginChannelMessage message)
{
this.LOGGER.debug("Sending message: " + message);
CompletableFuture<Void> future = new CompletableFuture<>();
if (this.serverPlayer != null)
{
packetSender.sendPluginPacketServer(this.serverPlayer, message);
}
return future;
}
default <TResponse extends TrackableNettyMessage> CompletableFuture<TResponse> sendRequest(TrackableNettyMessage msg, Class<TResponse> responseClass)
{
CompletableFuture<TResponse> responseFuture = this.getRequestHandler().createRequest(this, msg, responseClass);
this.sendMessage(msg).whenComplete((ignored, throwable) ->
{
if (throwable != null)
{
responseFuture.completeExceptionally(throwable);
}
});
return responseFuture;
}
default void disconnect(String reason)
{
ChannelHandlerContext ctx = this.getChannelContext();
if (ctx == null)
{
return;
}
ctx.channel().config().setAutoRead(false);
ctx.writeAndFlush(new CloseReasonMessage(reason))
.addListener(ChannelFutureListener.CLOSE);
}
}
@@ -39,8 +39,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
{
private final ConcurrentHashMap<IClientLevelWrapper, DhClientLevel> levels;
public final ClientOnlySaveStructure saveStructure;
@Nullable
public final ClientNetworkState networkState;
public final ClientNetworkState networkState = new ClientNetworkState();
public ExecutorService dhTickerThread = ThreadUtil.makeSingleThreadPool("Client World Ticker Thread");
public EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick);
@@ -58,10 +57,6 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
this.saveStructure = new ClientOnlySaveStructure();
this.levels = new ConcurrentHashMap<>();
this.networkState = Config.Client.Advanced.Multiplayer.ServerNetworking.enableServerNetworking.get()
? new ClientNetworkState()
: null;
LOGGER.info("Started DhWorld of type " + this.environment);
}
@@ -137,10 +132,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
@Override
public void close()
{
if (this.networkState != null)
{
this.networkState.close();
}
this.networkState.close();
for (DhClientLevel dhClientLevel : this.levels.values())