diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java
index 3bc48f29c..658a483b0 100644
--- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java
+++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java
@@ -23,6 +23,8 @@ import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
+import java.io.File;
+
/**
* Can be either a Server or Client level.
* A level is equivalent to a dimension in vanilla Minecraft.
@@ -72,4 +74,15 @@ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper
*/
IDhApiCustomRenderRegister getRenderRegister();
+ /**
+ * Returns the folder Distant Horizons uses to save
+ * data associated with this level.
+ * Will return null if the level is not loaded.
+ *
+ * @since API 4.0.0
+ */
+ File getDhSaveFolder();
+
+
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java
index 610f504df..c90e21408 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java
@@ -22,7 +22,6 @@ package com.seibel.distanthorizons.core.file.structure;
import com.google.common.net.PercentEscaper;
import com.seibel.distanthorizons.api.interfaces.override.levelHandling.IDhApiSaveStructure;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
-import com.seibel.distanthorizons.core.file.subDimMatching.SubDimensionLevelMatcher;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.api.enums.config.EDhApiServerFolderNameMode;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
@@ -30,7 +29,6 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.objects.ParsedIp;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
-import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import com.seibel.distanthorizons.coreapi.util.StringUtil;
@@ -38,6 +36,7 @@ import org.apache.logging.log4j.Logger;
import java.io.File;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Designed for the Client_Only environment.
@@ -54,8 +53,7 @@ public class ClientOnlySaveStructure implements ISaveStructure
private static final IMinecraftSharedWrapper MC_SHARED = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class);
- private final File folder;
- private final HashMap levelWrapperToFileMap = new HashMap<>();
+ private final ConcurrentHashMap levelWrapperToFileMap = new ConcurrentHashMap<>();
@@ -63,21 +61,7 @@ public class ClientOnlySaveStructure implements ISaveStructure
// constructor //
//=============//
- public ClientOnlySaveStructure()
- {
-
-
- this.folder = new File(getSaveStructureFolderPath());
-
- if (!this.folder.exists())
- {
- if (!this.folder.mkdirs())
- {
- LOGGER.warn("Unable to create folder [" + this.folder.getPath() + "]");
- //TODO: Deal with errors
- }
- }
- }
+ public ClientOnlySaveStructure() { }
@@ -85,47 +69,6 @@ public class ClientOnlySaveStructure implements ISaveStructure
// folder methods //
//================//
- private File getLevelFolderWithoutSimilarityMatching(ILevelWrapper level)
- {
- List folders = this.getDhDataFoldersForLevel(level);
- if (!folders.isEmpty() && folders.get(0) != null)
- {
- // use the first existing sub-dimension
- String folderName = folders.get(0).getName();
- LOGGER.info("Default Sub Dimension set to: [" + StringUtil.shortenString(folderName, 8) + "...]");
- return folders.get(0);
- }
- else
- {
- // no valid sub dimension was found, create a new one
- LOGGER.info("Default Sub Dimension not found. Creating: [" + level.getDimensionName() + "]");
- return new File(this.folder, level.getDimensionName().replaceAll(":", "@@"));
- }
- }
-
- public List getDhDataFoldersForLevel(ILevelWrapper level)
- {
- File[] folders = this.folder.listFiles();
- if (folders == null)
- {
- return new ArrayList<>(0);
- }
-
- // filter by dimension name
- String expectedDimName = level.getDimensionName();
- ArrayList possibleDimFolders = new ArrayList<>();
- for (File dimFolder : folders)
- {
- if (dimFolder.isDirectory() && dimFolder.getName().equals(expectedDimName))
- {
- possibleDimFolders.addAll(getValidDhDimensionFolders(dimFolder));
- }
- }
-
- return possibleDimFolders;
- }
-
-
@Override
public File getSaveFolder(ILevelWrapper levelWrapper)
{
@@ -139,12 +82,12 @@ public class ClientOnlySaveStructure implements ISaveStructure
IServerKeyedClientLevel keyedClientLevel = (IServerKeyedClientLevel) newLevelWrapper;
LOGGER.info("Loading level [" + newLevelWrapper.getDimensionName() + "] with key: [" + keyedClientLevel.getServerLevelKey() + "].");
// This world was identified by the server directly, so we can know for sure which folder to use.
- saveFolder = new File(getSaveStructureFolderPath() + File.separatorChar + keyedClientLevel.getServerLevelKey().replaceAll(":", "@@"));
+ saveFolder = new File(getDefaultSaveStructureFolderPath() + File.separatorChar + keyedClientLevel.getServerLevelKey().replaceAll(":", "@@"));
}
else
{
// get the default folder
- saveFolder = this.getLevelFolderWithoutSimilarityMatching(newLevelWrapper);;
+ saveFolder = new File(getDefaultSaveStructureFolderPath());
}
// Allow API users to override the save folder
@@ -217,7 +160,7 @@ public class ClientOnlySaveStructure implements ISaveStructure
}
- private static String getSaveStructureFolderPath()
+ private static String getDefaultSaveStructureFolderPath()
{
String path = MC_SHARED.getInstallationDirectory().getPath() + File.separatorChar
+ SERVER_DATA_FOLDER_NAME + File.separatorChar
@@ -286,6 +229,6 @@ public class ClientOnlySaveStructure implements ISaveStructure
public void close() { }
@Override
- public String toString() { return "[" + this.getClass().getSimpleName() + "@" + this.folder.getName() + "]"; }
+ public String toString() { return "[" + this.getClass().getSimpleName() + "@(" + StringUtil.join(";", this.levelWrapperToFileMap.values()) + ")]"; }
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/LocalSaveStructure.java b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/LocalSaveStructure.java
index 9889f7e73..2e35b775a 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/LocalSaveStructure.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/LocalSaveStructure.java
@@ -25,20 +25,20 @@ import com.seibel.distanthorizons.core.world.EWorldEnvironment;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
+import com.seibel.distanthorizons.coreapi.util.StringUtil;
import org.apache.logging.log4j.Logger;
import java.io.File;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Designed for {@link EWorldEnvironment#CLIENT_SERVER} & {@link EWorldEnvironment#SERVER_ONLY} environments.
- *
- * @version 2022-12-17
*/
public class LocalSaveStructure implements ISaveStructure
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
- private File debugPath = new File("");
+ private final ConcurrentHashMap levelWrapperToFileMap = new ConcurrentHashMap<>();
@@ -53,24 +53,26 @@ public class LocalSaveStructure implements ISaveStructure
@Override
public File getSaveFolder(ILevelWrapper levelWrapper)
{
- IServerLevelWrapper serverLevelWrapper = (IServerLevelWrapper) levelWrapper;
- this.debugPath = serverLevelWrapper.getSaveFolder();
- File saveFolder = serverLevelWrapper.getSaveFolder();
-
-
- // Allow API users to override the save folder
- IDhApiSaveStructure saveStructureOverride = OverrideInjector.INSTANCE.get(IDhApiSaveStructure.class);
- if (saveStructureOverride != null)
+ return this.levelWrapperToFileMap.computeIfAbsent(levelWrapper, (newLevelWrapper) ->
{
- File overrideFile = saveStructureOverride.overrideFilePath(saveFolder, levelWrapper);
- if (overrideFile != null)
+ IServerLevelWrapper serverLevelWrapper = (IServerLevelWrapper) levelWrapper;
+ File saveFolder = serverLevelWrapper.getMcSaveFolder();
+
+
+ // Allow API users to override the save folder
+ IDhApiSaveStructure saveStructureOverride = OverrideInjector.INSTANCE.get(IDhApiSaveStructure.class);
+ if (saveStructureOverride != null)
{
- LOGGER.info("Save folder overridden from ["+saveFolder.getPath()+"] -> ["+overrideFile.getPath()+"].");
- saveFolder = overrideFile;
+ File overrideFile = saveStructureOverride.overrideFilePath(saveFolder, levelWrapper);
+ if (overrideFile != null)
+ {
+ LOGGER.info("Save folder overridden from [" + saveFolder.getPath() + "] -> [" + overrideFile.getPath() + "].");
+ saveFolder = overrideFile;
+ }
}
- }
-
- return saveFolder;
+
+ return saveFolder;
+ });
}
@@ -83,6 +85,7 @@ public class LocalSaveStructure implements ISaveStructure
public void close() throws Exception { }
@Override
- public String toString() { return "[" + this.getClass().getSimpleName() + "@" + this.debugPath + "]"; }
+ public String toString()
+ { return "[" + this.getClass().getSimpleName() + "@(" + StringUtil.join(";", this.levelWrapperToFileMap.values()) + ")]"; }
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java
index dcc1ed1e5..64577497d 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java
@@ -24,7 +24,7 @@ import java.io.File;
public interface IServerLevelWrapper extends ILevelWrapper
{
- File getSaveFolder();
+ File getMcSaveFolder();
default String getKeyedLevelDimensionName()
{
diff --git a/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java b/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java
index 0bcbcaa8d..334670bdc 100644
--- a/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java
+++ b/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java
@@ -24,6 +24,8 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist
import com.seibel.distanthorizons.api.interfaces.world.IDhApiDimensionTypeWrapper;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
+import java.io.File;
+
/**
* Stub implementation of a Level wrapper for basic unit testing.
*
@@ -59,6 +61,10 @@ public class LevelWrapperTest implements IDhApiLevelWrapper
@Override
public IDhApiCustomRenderRegister getRenderRegister() { return null; }
+ @Override
+ public File getDhSaveFolder()
+ { return null; }
+
}