diff --git a/src/main/java/com/seibel/lod/core/enums/config/ServerFolderNameMode.java b/src/main/java/com/seibel/lod/core/enums/config/ServerFolderNameMode.java
new file mode 100644
index 000000000..cb57c14b7
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/enums/config/ServerFolderNameMode.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the Distant Horizon mod (formerly the LOD Mod),
+ * licensed under the GNU GPL v3 License.
+ *
+ * Copyright (C) 2022 Tom Lee (TomTheFurry)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.core.enums.config;
+
+/**
+ * AUTO
+ * NAME_ONLY
+ * NAME_IP
+ * NAME_IP_PORT
+ *
+ * Determines how the multiplayer folders should be named.
+ *
+ * @author James Seibel
+ * @version 3-7-2022
+ */
+public enum ServerFolderNameMode
+{
+ /**
+ * NAME_IP for LAN connections
+ * NAME_IP_PORT for all others
+ */
+ AUTO,
+
+ /** Only use the server name */
+ NAME_ONLY,
+
+ /**
+ * {SERVER_NAME} IP {IP}
+ * Minecraft Server IP 192.168.1.40
+ */
+ NAME_IP,
+
+ /**
+ * {SERVER_NAME} IP {IP}
+ * Minecraft Server IP 192.168.1.40:25565
+ */
+ NAME_IP_PORT,
+
+ /**
+ * {SERVER_NAME} IP {IP}
+ * Minecraft Server IP 192.168.1.40:25565 GameVersion 1.16.5
+ *
+ * Not normally recommended, since the game version can change if the
+ * server installs paper or some other jar.
+ * This is just here to provide backwards compatibility.
+ *
+ * TODO add this to config desc
+ */
+ NAME_IP_PORT_MC_VERSION;
+
+}
diff --git a/src/main/java/com/seibel/lod/core/objects/ParsedIp.java b/src/main/java/com/seibel/lod/core/objects/ParsedIp.java
new file mode 100644
index 000000000..24e243f91
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/objects/ParsedIp.java
@@ -0,0 +1,90 @@
+package com.seibel.lod.core.objects;
+
+
+/**
+ * Represents an IP and includes a couple helper methods.
+ *
+ * @author James Seibel
+ * @version 3-7-2022
+ */
+public class ParsedIp
+{
+ /** can be used to find numeric IPs, IE: "192.168.1.19" */
+ public static final String NUMERIC_IP_REGEX = "^[0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*(:[0-9]*)?$";
+
+ /**
+ * Can be used to find if a numeric IP is a LAN IP
+ *
+ * Ip list source:
+ * https://networkengineering.stackexchange.com/questions/5825/why-192-168-for-local-addresses
+ */
+ public static final String LAN_IP_REGEX = "(10|172\\.16|192\\.168).*";
+
+
+ /** Examples: "192.168.1.19", "mc.hypixel.net", or "localhost" */
+ public final String ip;
+ /**
+ * null if the ip isn't numeric (IE: "mc.hypixel.net" or "localhost")
+ * Example: "25586"
+ */
+ public final String port;
+ public final boolean isNumeric;
+
+
+ /** parses a standard IP string */
+ public ParsedIp(String fullIp)
+ {
+ fullIp = fullIp.trim();
+
+ isNumeric = fullIp.matches(NUMERIC_IP_REGEX);
+ if (isNumeric)
+ {
+ // attempt to separate the IP and the Port
+ String[] list = fullIp.split(":");
+ if (list.length == 2)
+ {
+ // IP and Port successfully separated
+ ip = list[0];
+ port = list[1];
+ }
+ else
+ {
+ // this IP must not have a port
+ ip = fullIp;
+ port = null;
+ }
+ }
+ else
+ {
+ // text based IP, IE: "localhost"
+ ip = fullIp;
+ port = null;
+ }
+ }
+
+ public ParsedIp(String newIp, String newPort)
+ {
+ ip = newIp;
+ port = newPort;
+ isNumeric = ip.matches(NUMERIC_IP_REGEX);
+ }
+
+
+
+
+ /** Returns if this IP is for a Local Area Network connection */
+ public boolean isLan()
+ {
+ return ip.toLowerCase().equals("localhost") || ip.matches(LAN_IP_REGEX);
+ }
+
+ @Override
+ public String toString()
+ {
+ return ip +
+ // only print the ":port" if a port is present
+ (port != null ? (":" + port) : "");
+ }
+}
+
+
diff --git a/src/main/java/com/seibel/lod/core/util/LodUtil.java b/src/main/java/com/seibel/lod/core/util/LodUtil.java
index 964248275..6f6abfc6f 100644
--- a/src/main/java/com/seibel/lod/core/util/LodUtil.java
+++ b/src/main/java/com/seibel/lod/core/util/LodUtil.java
@@ -25,9 +25,11 @@ import java.util.HashSet;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.config.HorizontalResolution;
+import com.seibel.lod.core.enums.config.ServerFolderNameMode;
import com.seibel.lod.core.enums.config.VanillaOverdraw;
import com.seibel.lod.core.handlers.IReflectionHandler;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
+import com.seibel.lod.core.objects.ParsedIp;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.objects.lod.RegionPos;
import com.seibel.lod.core.objects.opengl.DefaultLodVertexFormats;
@@ -46,7 +48,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
* This class holds methods and constants that may be used in multiple places.
*
* @author James Seibel
- * @version 12-14-2021
+ * @version 3-7-2022
*/
public class LodUtil
{
@@ -208,7 +210,7 @@ public class LodUtil
}
else
{
- return getServerId();
+ return getServerFolderName();
}
}
@@ -236,18 +238,63 @@ public class LodUtil
}
else
{
- return getServerId() + File.separatorChar + "dim_" + world.getDimensionType().getDimensionName() + File.separatorChar;
+ return getServerFolderName() + File.separatorChar + "dim_" + world.getDimensionType().getDimensionName() + File.separatorChar;
}
}
/** returns the server name, IP and game version. */
- public static String getServerId()
+ public static String getServerFolderName()
{
+ // parse the current server's IP
+ ParsedIp parsedIp = new ParsedIp(MC.getCurrentServerIp());
+ String serverIpCleaned = parsedIp.ip.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
+ String serverPortCleaned = parsedIp.port != null ? parsedIp.port.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "") : "";
+
+
+ // determine the format of the folder name
+ ServerFolderNameMode folderNameMode = CONFIG.client().multiplayer().getServerFolderNameMode();
+ if (folderNameMode == ServerFolderNameMode.AUTO)
+ {
+ if (parsedIp.isLan())
+ {
+ // LAN
+ folderNameMode = ServerFolderNameMode.NAME_IP;
+ }
+ else
+ {
+ // normal multiplayer
+ folderNameMode = ServerFolderNameMode.NAME_IP_PORT;
+ }
+ }
+
+
String serverName = MC.getCurrentServerName().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
- String serverIp = MC.getCurrentServerIp().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
String serverMcVersion = MC.getCurrentServerVersion().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
- return serverName + ", IP " + serverIp + ", GameVersion " + serverMcVersion;
+ // generate the folder name
+ String folderName = "";
+ switch (folderNameMode)
+ {
+ // default and auto shouldn't be used
+ // and are just here to make the compiler happy
+ default:
+ case AUTO:
+ case NAME_ONLY:
+ folderName = serverName;
+ break;
+
+ case NAME_IP:
+ folderName = serverName + ", IP " + serverIpCleaned;
+ break;
+ case NAME_IP_PORT:
+ folderName = serverName + ", IP " + serverIpCleaned + (serverPortCleaned.length() != 0 ? (":" + serverPortCleaned) : "");
+ break;
+ case NAME_IP_PORT_MC_VERSION:
+ folderName = serverName + ", IP " + serverIpCleaned + (serverPortCleaned.length() != 0 ? (":" + serverPortCleaned) : "") + ", GameVersion " + serverMcVersion;
+ break;
+ }
+
+ return folderName;
}
diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java
index 06742065d..7dfd25a75 100644
--- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java
+++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java
@@ -28,6 +28,7 @@ import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.enums.config.HorizontalQuality;
import com.seibel.lod.core.enums.config.HorizontalResolution;
import com.seibel.lod.core.enums.config.LightGenerationMode;
+import com.seibel.lod.core.enums.config.ServerFolderNameMode;
import com.seibel.lod.core.enums.config.VanillaOverdraw;
import com.seibel.lod.core.enums.config.VerticalQuality;
import com.seibel.lod.core.enums.rendering.DebugMode;
@@ -47,7 +48,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
* the options that should be implemented in a configWrapperSingleton.
*
* @author James Seibel
- * @version 3-5-2022
+ * @version 3-7-2022
*/
public interface ILodConfigWrapperSingleton extends IBindable
{
@@ -58,6 +59,7 @@ public interface ILodConfigWrapperSingleton extends IBindable
{
IGraphics graphics();
IWorldGenerator worldGenerator();
+ IMultiplayer multiplayer();
IAdvanced advanced();
@@ -314,6 +316,30 @@ public interface ILodConfigWrapperSingleton extends IBindable
+ //=====================//
+ // Multiplayer Configs //
+ //=====================//
+ interface IMultiplayer
+ {
+ String DESC = "These settings control how different systems work when connected to a multiplayer world.";
+
+ ServerFolderNameMode SERVER_FOLDER_NAME_MODE_DEFAULT = ServerFolderNameMode.AUTO;
+ String SERVER_FOLDER_NAME_MODE_DESC = ""
+ + " What multiplayer save folders should be named. \n"
+ + "\n"
+ + " " + ServerFolderNameMode.AUTO.toString() + ": " + ServerFolderNameMode.NAME_IP.toString() + " for LAN connections, " + ServerFolderNameMode.NAME_IP_PORT.toString() + " for all others. \n"
+ + " " + ServerFolderNameMode.NAME_ONLY.toString() + ": Example: \"Minecraft Server\" \n"
+ + " " + ServerFolderNameMode.NAME_IP.toString() + ": Example: \"Minecraft Server IP 192.168.1.40\" \n"
+ + " " + ServerFolderNameMode.NAME_IP_PORT.toString() + ": Example: \"Minecraft Server IP 192.168.1.40:25565\" \n"
+ + "\n";
+ ServerFolderNameMode getServerFolderNameMode();
+ void setServerFolderNameMode(ServerFolderNameMode newServerFolderNameMode);
+ }
+
+
+
+
+
//========================//
// WorldGenerator Configs //
//========================//
diff --git a/src/main/resources/assets/lod/lang/en_us.json b/src/main/resources/assets/lod/lang/en_us.json
index aa5bd5a6a..0ecbeacfd 100644
--- a/src/main/resources/assets/lod/lang/en_us.json
+++ b/src/main/resources/assets/lod/lang/en_us.json
@@ -107,6 +107,12 @@
"Light Generation Mode",
"DistantHorizons.config.client.worldGenerator.lightGenerationMode.@tooltip":
"§6Fancy:§r use Minecraft's lighting engine, gives accurate lighting.\n§6Fast:§r estimate block lighting, shadows won't be as smooth.\n\nIf the fake chunks appear black, set this to §6Fast:§r.",
+ "DistantHorizons.config.client.multiplayer":
+ "Multiplayer",
+ "DistantHorizons.config.client.multiplayer.serverFolderNameMode":
+ "Server Folder Mode",
+ "DistantHorizons.config.client.multiplayer.serverFolderNameMode.@tooltip":
+ "Determines the folder format for local multiplayer data.\n\n§6Auto:§r\nUses \"Name, IP\" for LAN worlds and \"Name, IP, Port\" for standard multiplayer.\n§6Name Only:§r\nUses the server browser name. Ex: \"Minecraft Server\"\n§6Name IP:§r\n\"Minecraft Server, IP 192.168.1.40\"\n§6Name, IP, Port:§r\n\"Minecraft Server, IP 192.168.1.40:25565\"\n§6Name, IP, Port, MC Version:§r\n\"Minecraft Server, IP 192.168.1.40:25565, GameVersion 1.18.1\"\n\n§c§lCaution:§r changing while connected to a multiplayer server may cause glitches.",
"DistantHorizons.config.client.advanced":
"Advance options",
"DistantHorizons.config.client.advanced.threading":
@@ -274,5 +280,15 @@
"DistantHorizons.config.enum.LightGenerationMode.FAST":
"Fast",
"DistantHorizons.config.enum.LightGenerationMode.FANCY":
- "Fancy"
+ "Fancy",
+ "DistantHorizons.config.enum.ServerFolderNameMode.AUTO":
+ "Auto",
+ "DistantHorizons.config.enum.ServerFolderNameMode.NAME_ONLY":
+ "Name Only",
+ "DistantHorizons.config.enum.ServerFolderNameMode.NAME_IP":
+ "Name and IP",
+ "DistantHorizons.config.enum.ServerFolderNameMode.NAME_IP_PORT":
+ "Name, IP, Port",
+ "DistantHorizons.config.enum.ServerFolderNameMode.NAME_IP_PORT_MC_VERSION":
+ "Name, IP, Port, MC version"
}