Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 034ec7d656 | |||
| fb5e15a2f1 |
@@ -31,7 +31,7 @@ public final class ModInfo
|
||||
public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial";
|
||||
|
||||
/** Incremented every time any packets are added, changed or removed, with a few exceptions. */
|
||||
public static final int PROTOCOL_VERSION = 11;
|
||||
public static final int PROTOCOL_VERSION = 12;
|
||||
public static final String WRAPPER_PACKET_PATH = "message";
|
||||
|
||||
/** The internal mod name */
|
||||
|
||||
+10
-3
@@ -75,7 +75,12 @@ public class ClientPluginChannelApi
|
||||
|
||||
private void onLevelInitMessage(LevelInitMessage msg)
|
||||
{
|
||||
if (!msg.levelKey.matches(LevelInitMessage.VALIDATION_REGEX))
|
||||
if (!msg.serverKey.matches(LevelInitMessage.SERVER_KEY_REGEX))
|
||||
{
|
||||
throw new IllegalArgumentException("Server sent invalid server key.");
|
||||
}
|
||||
|
||||
if (!msg.levelKey.matches(LevelInitMessage.LEVEL_KEY_REGEX))
|
||||
{
|
||||
throw new IllegalArgumentException("Server sent invalid level key.");
|
||||
}
|
||||
@@ -105,10 +110,12 @@ public class ClientPluginChannelApi
|
||||
this.levelUnloadHandler.accept(clientLevel);
|
||||
}
|
||||
|
||||
if (existingKeyedClientLevel == null || !existingKeyedClientLevel.getServerLevelKey().equals(msg.levelKey))
|
||||
if (existingKeyedClientLevel == null
|
||||
|| !existingKeyedClientLevel.getServerKey().equals(msg.serverKey)
|
||||
|| !existingKeyedClientLevel.getServerLevelKey().equals(msg.levelKey))
|
||||
{
|
||||
LOGGER.info("Loading level with key: [" + msg.levelKey + "].");
|
||||
IServerKeyedClientLevel keyedLevel = KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel, msg.levelKey);
|
||||
IServerKeyedClientLevel keyedLevel = KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel, msg.serverKey, msg.levelKey);
|
||||
this.levelLoadHandler.accept(keyedLevel);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1599,6 +1599,28 @@ public class Config
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Integer> serverId = new ConfigEntry.Builder<Integer>()
|
||||
.set(new Random().nextInt())
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
|
||||
.comment(""
|
||||
+ "DO NOT CHANGE UNLESS YOU KNOW WHAT YOU'RE DOING.\n"
|
||||
+ "Autogenerated ID used to prevent multiple independent servers from accidentally\n"
|
||||
+ "writing over each other's LODs when the same serverKey is set on both.\n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<String> serverKey = new ConfigEntry.Builder<String>()
|
||||
.setChatCommandName("levelKeys.serverKey")
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
|
||||
.set("")
|
||||
.comment(""
|
||||
+ "Custom server key used which can be used to always reuse the same LOD data folder,\n"
|
||||
+ "for cases when the server doesn't have a static IP for some reason.\n"
|
||||
+ "If this value is empty, the client itself decides which folder name to use.\n"
|
||||
+ "Requires rejoining the server to apply after changing.\n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<String> levelKeyPrefix = new ConfigEntry.Builder<String>()
|
||||
.setChatCommandName("levelKeys.prefix")
|
||||
.set("")
|
||||
|
||||
+13
-6
@@ -81,13 +81,20 @@ public class ClientOnlySaveStructure implements ISaveStructure
|
||||
{
|
||||
IServerKeyedClientLevel keyedClientLevel = (IServerKeyedClientLevel) newLevelWrapper;
|
||||
LOGGER.info("Loading level [" + newLevelWrapper.getDhIdentifier() + "] with key: [" + keyedClientLevel.getServerLevelKey() + "].");
|
||||
// This world was identified by the server directly, so we can know for sure which folder to use.
|
||||
saveFolder = getSaveFolderByLevelId(keyedClientLevel.getServerLevelKey());
|
||||
|
||||
String serverKey = keyedClientLevel.getServerKey();
|
||||
if (serverKey.isEmpty())
|
||||
{
|
||||
serverKey = getServerFolderName();
|
||||
}
|
||||
|
||||
// This world was identified by the server directly, so we can know for sure which folder to use.
|
||||
saveFolder = getSaveFolderByLevelId(serverKey, keyedClientLevel.getServerLevelKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the default folder
|
||||
saveFolder = getSaveFolderByLevelId(levelWrapper.getDhIdentifier());
|
||||
saveFolder = getSaveFolderByLevelId(getServerFolderName(), levelWrapper.getDhIdentifier());
|
||||
}
|
||||
|
||||
// Allow API users to override the save folder
|
||||
@@ -116,7 +123,7 @@ public class ClientOnlySaveStructure implements ISaveStructure
|
||||
return this.getSaveFolder(levelWrapper);
|
||||
}
|
||||
|
||||
return getSaveFolderByLevelId(levelWrapper.getDimensionType().getName());
|
||||
return getSaveFolderByLevelId(getServerFolderName(), levelWrapper.getDimensionType().getName());
|
||||
}
|
||||
|
||||
|
||||
@@ -173,11 +180,11 @@ public class ClientOnlySaveStructure implements ISaveStructure
|
||||
}
|
||||
|
||||
|
||||
private static File getSaveFolderByLevelId(String dimensionName)
|
||||
private static File getSaveFolderByLevelId(String folderName, String dimensionName)
|
||||
{
|
||||
String path = MC_SHARED.getInstallationDirectory().getPath() + File.separatorChar
|
||||
+ SERVER_DATA_FOLDER_NAME + File.separatorChar
|
||||
+ getServerFolderName() + File.separatorChar
|
||||
+ folderName + File.separatorChar
|
||||
+ dimensionName.replaceAll(":", "@@");
|
||||
|
||||
return new File(path);
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ public interface IKeyedClientLevelManager extends IBindable
|
||||
{
|
||||
IServerKeyedClientLevel getServerKeyedLevel();
|
||||
/** Called when a client level is wrapped by a ServerEnhancedClientLevel, for integration into mod internals. */
|
||||
IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String levelKey);
|
||||
IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String serverKey, String levelKey);
|
||||
|
||||
void clearKeyedLevel();
|
||||
boolean isEnabled();
|
||||
|
||||
@@ -24,6 +24,9 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp
|
||||
/** Enhances a {@link IClientLevelWrapper} with server provided level information. */
|
||||
public interface IServerKeyedClientLevel extends IClientLevelWrapper
|
||||
{
|
||||
/** Returns the folder name the server wants the player to use. */
|
||||
String getServerKey();
|
||||
|
||||
/** Returns the level key, which is used to select the correct folder on the client. */
|
||||
String getServerLevelKey();
|
||||
|
||||
|
||||
+5
-1
@@ -27,6 +27,10 @@ public class ServerPlayerState implements Closeable
|
||||
private final SessionConfig.AnyChangeListener configAnyChangeListener = new SessionConfig.AnyChangeListener(this::sendConfigMessage);
|
||||
|
||||
|
||||
private final String serverKeyWithoutId = Config.Server.serverKey.get();
|
||||
private final String serverKey = (this.serverKeyWithoutId.isEmpty() ? "" : Config.Server.serverId.get() + "_" + this.serverKeyWithoutId.trim())
|
||||
.replaceAll("[^" + LevelInitMessage.PART_ALLOWED_CHARS_REGEX + " ]", "")
|
||||
.replaceAll(" ", "_");
|
||||
private String lastLevelKey = "";
|
||||
|
||||
|
||||
@@ -89,7 +93,7 @@ public class ServerPlayerState implements Closeable
|
||||
if (!levelKey.equals(this.lastLevelKey))
|
||||
{
|
||||
this.lastLevelKey = levelKey;
|
||||
this.networkSession.sendMessage(new LevelInitMessage(levelKey));
|
||||
this.networkSession.sendMessage(new LevelInitMessage(this.serverKey, levelKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-2
@@ -10,12 +10,18 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
|
||||
public static final String PART_ALLOWED_CHARS_REGEX = "a-zA-Z0-9-_";
|
||||
|
||||
// A plain string of characters
|
||||
// 1-150 characters in total
|
||||
public static final String SERVER_KEY_REGEX = String.format("^(?=.{1,%s}$)[%s]+$",
|
||||
MAX_LENGTH, PART_ALLOWED_CHARS_REGEX);
|
||||
|
||||
// prefix@namespace:path
|
||||
// 1-150 characters in total, all parts except namespace can be omitted
|
||||
public static final String VALIDATION_REGEX = String.format("^(?=.{1,%s}$)([%s]+@)?[%s]+(:[%s]+)?$",
|
||||
public static final String LEVEL_KEY_REGEX = String.format("^(?=.{1,%s}$)([%s]+@)?[%s]+(:[%s]+)?$",
|
||||
MAX_LENGTH, PART_ALLOWED_CHARS_REGEX, PART_ALLOWED_CHARS_REGEX, PART_ALLOWED_CHARS_REGEX);
|
||||
|
||||
|
||||
public String serverKey;
|
||||
public String levelKey;
|
||||
public long serverTime;
|
||||
|
||||
@@ -26,8 +32,9 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
//==============//
|
||||
|
||||
public LevelInitMessage() { }
|
||||
public LevelInitMessage(String levelKey)
|
||||
public LevelInitMessage(String serverKey, String levelKey)
|
||||
{
|
||||
this.serverKey = serverKey;
|
||||
this.levelKey = levelKey;
|
||||
this.serverTime = System.currentTimeMillis();
|
||||
}
|
||||
@@ -41,6 +48,7 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
@Override
|
||||
public void encode(ByteBuf out)
|
||||
{
|
||||
this.writeString(this.serverKey, out);
|
||||
this.writeString(this.levelKey, out);
|
||||
out.writeLong(this.serverTime);
|
||||
}
|
||||
@@ -48,6 +56,7 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
@Override
|
||||
public void decode(ByteBuf in)
|
||||
{
|
||||
this.serverKey = this.readString(in);
|
||||
this.levelKey = this.readString(in);
|
||||
this.serverTime = in.readLong();
|
||||
}
|
||||
@@ -62,6 +71,7 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
public MoreObjects.ToStringHelper toStringHelper()
|
||||
{
|
||||
return super.toStringHelper()
|
||||
.add("serverKey", this.serverKey)
|
||||
.add("levelKey", this.levelKey)
|
||||
.add("serverTime", this.serverTime);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user