Use level keys

This commit is contained in:
s809
2024-06-13 16:44:37 +05:00
parent bcb21be848
commit 7c705015e6
16 changed files with 72 additions and 93 deletions
@@ -33,8 +33,8 @@ public final class ModInfo
// region Protocol versions
// Incremented every time any packets are added, changed or removed, with a few exceptions.
public static final int PROTOCOL_VERSION = 2;
public static final String PLUGIN_CHANNEL_PATH = "plugin_channel";
public static final String WRAPPER_PACKET_PATH = "wrapper";
public static final String PLUGIN_CHANNEL_PATH = "main";
public static final String WRAPPER_PACKET_PATH = "message";
// endregion
@@ -50,7 +50,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrap
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import io.netty.buffer.ByteBuf;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
@@ -132,6 +131,8 @@ public class ClientApi
DhClientWorld world = new DhClientWorld();
SharedApi.setDhWorld(world);
this.pluginChannelApi.onJoin(world.networkState.getSession());
world.networkState.sendConfigMessage();
LOGGER.info("Loading [" + this.waitingClientLevels.size() + "] waiting client level wrappers.");
for (IClientLevelWrapper level : this.waitingClientLevels)
@@ -140,8 +141,6 @@ public class ClientApi
}
this.waitingClientLevels.clear();
this.pluginChannelApi.onJoin(world.networkState.getSession());
}
}
@@ -206,17 +205,20 @@ public class ClientApi
{
try
{
if (!this.pluginChannelApi.allowLoadingLevel())
{
LOGGER.info("Levels in this connection are managed by the server and loading is not allowed, ignoring auto-load.");
return;
}
LOGGER.info("Loading client level [" + level + "]-["+level.getDimensionType().getDimensionName()+"].");
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null)
{
if (!this.pluginChannelApi.allowLevelAutoload())
{
LOGGER.info("Levels in this connection are managed by the server, skipping auto-load.");
// Instead of attempting to load themselves, send config and wait for level key.
((DhClientWorld) world).networkState.sendConfigMessage();
return;
}
world.getOrLoadLevel(level);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level));
@@ -7,18 +7,17 @@ import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
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.ClientHelloMessage;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelSession;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import io.netty.buffer.ByteBuf;
import org.apache.logging.log4j.LogManager;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.function.Consumer;
/**
* This class is used to manage the level keys.
* Its purpose is to separate MC's and plugin channel's event handling.
*/
public class ClientPluginChannelApi
{
@@ -33,7 +32,7 @@ public class ClientPluginChannelApi
public PluginChannelSession session;
public boolean allowLoadingLevel()
public boolean allowLevelAutoload()
{
return (KEYED_CLIENT_LEVEL_MANAGER.isEnabled() && KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel() != null)
|| !KEYED_CLIENT_LEVEL_MANAGER.isEnabled();
@@ -44,15 +43,12 @@ public class ClientPluginChannelApi
{
this.levelUnloadHandler = levelUnloadHandler;
this.multiverseLevelLoadHandler = levelLoadHandler;
}
public void onJoin(PluginChannelSession session)
public void onJoin(@NonNull PluginChannelSession session)
{
Objects.requireNonNull(session);
this.session = session;
this.session.sendMessage(new ClientHelloMessage());
this.session.registerHandler(CurrentLevelKeyMessage.class, this::onCurrentLevelKeyMessage);
this.session.registerHandler(PluginCloseEvent.class, this::onClose);
}
@@ -71,7 +67,9 @@ public class ClientPluginChannelApi
if (clientLevel != null)
{
// In either case only one of them will have an effect.
this.levelUnloadHandler.accept(clientLevel);
this.levelUnloadHandler.accept(KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel());
}
IServerKeyedClientLevel keyedLevel = KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel, msg.levelKey);
@@ -899,6 +899,28 @@ public class Config
.build();
public static ConfigEntry<Boolean> sendLevelKeys = new ConfigEntry.Builder<Boolean>()
.setServersideShortName("sendLevelKeys")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.set(true)
.comment(""
+ "Makes the server send level keys for each world.\n"
+ "Disable this if you use alternative ways to send level keys.\n"
+ "")
.build();
public static ConfigEntry<String> levelKeyPrefix = new ConfigEntry.Builder<String>()
.setServersideShortName("levelKeyPrefix")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.set("")
.comment(""
+ "Prefix of the level keys sent to the clients.\n"
+ "Should be set to a unique value for each backend server behind a proxy,\n"
+ "or empty if you don't use a proxy.\n"
+ "")
.build();
public static ConfigUIComment generationSectionNote = new ConfigUIComment();
public static ConfigEntry<Integer> generationRequestRCLimit = new ConfigEntry.Builder<Integer>()
.setServersideShortName("generationRequestRCLimit")
@@ -24,7 +24,7 @@ public class ClientNetworkState implements Closeable
public MultiplayerConfig config = new MultiplayerConfig();
private volatile boolean configReceived = false;
private final MultiplayerConfigChangeListener configChangeListener = new MultiplayerConfigChangeListener(this::onConfigChanged);
private final MultiplayerConfigChangeListener configChangeListener = new MultiplayerConfigChangeListener(this::sendConfigMessage);
public boolean isReady() { return this.configReceived; }
private final F3Screen.NestedMessage f3Message = new F3Screen.NestedMessage(this::f3Log);
@@ -55,7 +55,7 @@ public class ClientNetworkState implements Closeable
});
}
private void onConfigChanged()
public void sendConfigMessage()
{
this.configReceived = false;
this.getSession().sendMessage(new RemotePlayerConfigMessage(new MultiplayerConfig()));
@@ -9,7 +9,6 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject
public abstract int getRenderDistanceRadius();
public abstract boolean isDistantGenerationEnabled();
public abstract int getFullDataRequestConcurrencyLimit();
public abstract int getGenTaskPriorityRequestRateLimit();
public abstract boolean isRealTimeUpdatesEnabled();
public abstract boolean isLoginDataSyncEnabled();
public abstract int getLoginDataSyncRCLimit();
@@ -20,7 +19,6 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject
out.writeInt(this.getRenderDistanceRadius());
out.writeBoolean(this.isDistantGenerationEnabled());
out.writeInt(this.getFullDataRequestConcurrencyLimit());
out.writeInt(this.getGenTaskPriorityRequestRateLimit());
out.writeBoolean(this.isRealTimeUpdatesEnabled());
out.writeBoolean(this.isLoginDataSyncEnabled());
out.writeInt(this.getLoginDataSyncRCLimit());
@@ -34,7 +32,6 @@ public abstract class AbstractMultiplayerConfig implements INetworkObject
.add("renderDistanceRadius", this.getRenderDistanceRadius())
.add("distantGenerationEnabled", this.isDistantGenerationEnabled())
.add("fullDataRequestConcurrencyLimit", this.getFullDataRequestConcurrencyLimit())
.add("genTaskPriorityRequestRateLimit", this.getGenTaskPriorityRequestRateLimit())
.add("realTimeUpdatesEnabled", this.isRealTimeUpdatesEnabled())
.add("loginDataSyncEnabled", this.isLoginDataSyncEnabled())
.add("loginDataSyncRCLimit", this.getLoginDataSyncRCLimit())
@@ -16,9 +16,6 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig
public int fullDataRequestConcurrencyLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit.get();
@Override public int getFullDataRequestConcurrencyLimit() { return this.fullDataRequestConcurrencyLimit; }
public int genTaskPriorityRequestRateLimit = Config.Client.Advanced.Multiplayer.ServerNetworking.genTaskPriorityRequestRateLimit.get();
@Override public int getGenTaskPriorityRequestRateLimit() { return this.genTaskPriorityRequestRateLimit; }
public boolean realTimeUpdatesEnabled = Config.Client.Advanced.Multiplayer.ServerNetworking.enableRealTimeUpdates.get();
@Override public boolean isRealTimeUpdatesEnabled() { return this.realTimeUpdatesEnabled; }
@@ -35,7 +32,6 @@ public class MultiplayerConfig extends AbstractMultiplayerConfig
this.renderDistanceRadius = in.readInt();
this.distantGenerationEnabled = in.readBoolean();
this.fullDataRequestConcurrencyLimit = in.readInt();
this.genTaskPriorityRequestRateLimit = in.readInt();
this.realTimeUpdatesEnabled = in.readBoolean();
this.loginDataSyncEnabled = in.readBoolean();
this.loginDataSyncRCLimit = in.readInt();
@@ -30,12 +30,6 @@ public class ConstrainedMultiplayerConfig extends AbstractMultiplayerConfig
return Math.min(this.clientConfig.fullDataRequestConcurrencyLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.generationRequestRCLimit.get());
}
@Override
public int getGenTaskPriorityRequestRateLimit()
{
return Math.min(this.clientConfig.genTaskPriorityRequestRateLimit, Config.Client.Advanced.Multiplayer.ServerNetworking.genTaskPriorityRequestRateLimit.get());
}
@Override
public boolean isRealTimeUpdatesEnabled()
{
@@ -1,20 +1,14 @@
package com.seibel.distanthorizons.core.multiplayer.server;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelMessage;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelSession;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import org.apache.logging.log4j.LogManager;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class RemotePlayerConnectionHandler
{
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
private final ConcurrentMap<IServerPlayerWrapper, ServerPlayerState> connectedPlayers = new ConcurrentHashMap<>();
@@ -5,9 +5,9 @@ import com.seibel.distanthorizons.core.level.DhServerLevel;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfig;
import com.seibel.distanthorizons.core.multiplayer.config.MultiplayerConfigChangeListener;
import com.seibel.distanthorizons.core.network.messages.plugin.CurrentLevelKeyMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.session.RemotePlayerConfigMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.PluginCloseEvent;
import com.seibel.distanthorizons.core.network.messages.plugin.base.ClientHelloMessage;
import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException;
import com.seibel.distanthorizons.core.network.messages.plugin.fullData.FullDataSourceRequestMessage;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelSession;
@@ -22,9 +22,6 @@ import static com.seibel.distanthorizons.core.config.Config.Client.Advanced.Mult
public class ServerPlayerState
{
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
public final PluginChannelSession session;
public IServerPlayerWrapper serverPlayer() { return this.session.serverPlayer; }
@@ -51,11 +48,28 @@ public class ServerPlayerState
this.session.registerHandler(RemotePlayerConfigMessage.class, remotePlayerConfigMessage ->
{
this.config.clientConfig = (MultiplayerConfig) remotePlayerConfigMessage.payload;
if (ServerNetworking.sendLevelKeys.get())
{
String levelKeyPrefix = ServerNetworking.levelKeyPrefix.get();
String dimensionName = serverPlayer.getLevel().getDimensionType().getDimensionName();
String levelKey;
if (!levelKeyPrefix.isEmpty())
{
levelKey = levelKeyPrefix + "_" + dimensionName;
}
else
{
levelKey = dimensionName;
}
this.session.sendMessage(new CurrentLevelKeyMessage(levelKey));
}
this.session.sendMessage(new RemotePlayerConfigMessage(this.config));
});
this.session.registerHandler(ClientHelloMessage.class, msg -> this.onConfigChanged());
this.session.registerHandler(PluginCloseEvent.class, event -> {
// Noop
});
@@ -22,7 +22,6 @@ package com.seibel.distanthorizons.core.network.messages;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.seibel.distanthorizons.core.network.messages.plugin.CurrentLevelKeyMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.base.ClientHelloMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.base.CancelMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.base.CloseReasonMessage;
import com.seibel.distanthorizons.core.network.messages.plugin.base.ExceptionMessage;
@@ -49,20 +48,19 @@ public class PluginMessageRegistry
{
// Note: Messages must have parameterless constructors
// Always sent by the client
this.registerMessage(ClientHelloMessage.class, ClientHelloMessage::new);
// When the communication is about to be stopped, either side can send this message
this.registerMessage(CloseReasonMessage.class, CloseReasonMessage::new);
// Multiverse support
// Level keys
this.registerMessage(CurrentLevelKeyMessage.class, CurrentLevelKeyMessage::new);
// Core
// Config (for full DH support)
this.registerMessage(RemotePlayerConfigMessage.class, RemotePlayerConfigMessage::new);
// Requests
this.registerMessage(CancelMessage.class, CancelMessage::new);
this.registerMessage(ExceptionMessage.class, ExceptionMessage::new);
// ID & config
this.registerMessage(RemotePlayerConfigMessage.class, RemotePlayerConfigMessage::new);
// Full data requests & updates
this.registerMessage(FullDataSourceRequestMessage.class, FullDataSourceRequestMessage::new);
this.registerMessage(FullDataSourceResponseMessage.class, FullDataSourceResponseMessage::new);
@@ -7,27 +7,23 @@ import io.netty.buffer.ByteBuf;
public class CurrentLevelKeyMessage extends PluginChannelMessage
{
public String levelKey;
public boolean deleteExistingData;
public CurrentLevelKeyMessage() { }
public CurrentLevelKeyMessage(String levelKey, boolean deleteExistingData)
public CurrentLevelKeyMessage(String levelKey)
{
this.levelKey = levelKey;
this.deleteExistingData = deleteExistingData;
}
@Override
public void encode(ByteBuf out)
{
this.writeString(this.levelKey, out);
out.writeBoolean(this.deleteExistingData);
}
@Override
public void decode(ByteBuf in)
{
this.levelKey = this.readString(in);
this.deleteExistingData = in.readBoolean();
}
@@ -35,8 +31,7 @@ public class CurrentLevelKeyMessage extends PluginChannelMessage
public MoreObjects.ToStringHelper toStringHelper()
{
return super.toStringHelper()
.add("levelKey", this.levelKey)
.add("deleteExistingData", this.deleteExistingData);
.add("levelKey", this.levelKey);
}
}
@@ -1,22 +0,0 @@
package com.seibel.distanthorizons.core.network.messages.plugin.base;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelMessage;
import io.netty.buffer.ByteBuf;
/**
* Serves as a trigger for the server to send some useful data to the client.
* Not integral to establishing a session.
*/
public class ClientHelloMessage extends PluginChannelMessage
{
@Override
public void encode(ByteBuf out)
{
}
@Override
public void decode(ByteBuf in)
{
}
}
@@ -74,12 +74,6 @@ public class PluginChannelSession extends NetworkEventSource
{
LOGGER.debug("Sending message: {}", message);
Consumer<ByteBuf> encoder = buffer -> {
buffer.writeShort(ModInfo.PROTOCOL_VERSION);
buffer.writeShort(PluginMessageRegistry.INSTANCE.getMessageId(message));
message.encode(buffer);
};
if (this.serverPlayer != null)
{
PACKET_SENDER.sendPluginPacketServer(this.serverPlayer, message);
@@ -19,7 +19,6 @@
package com.seibel.distanthorizons.core.world;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.level.DhClientLevel;
import com.seibel.distanthorizons.core.level.IDhLevel;
@@ -24,12 +24,10 @@ import com.seibel.distanthorizons.core.level.DhServerLevel;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.multiplayer.server.RemotePlayerConnectionHandler;
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
import com.seibel.distanthorizons.core.network.plugin.PluginChannelMessage;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import io.netty.buffer.ByteBuf;
import org.jetbrains.annotations.NotNull;
import java.io.File;