diff --git a/api/src/main/java/com/seibel/lod/api/DhApiMain.java b/api/src/main/java/com/seibel/lod/api/DhApiMain.java
index 941696fbd..a2aa5502e 100644
--- a/api/src/main/java/com/seibel/lod/api/DhApiMain.java
+++ b/api/src/main/java/com/seibel/lod/api/DhApiMain.java
@@ -3,6 +3,7 @@ package com.seibel.lod.api;
import com.seibel.lod.api.interfaces.config.IDhApiConfig;
import com.seibel.lod.api.interfaces.override.IDhApiOverrideable;
import com.seibel.lod.api.interfaces.override.worldGenerator.IDhApiWorldGeneratorOverrideRegister;
+import com.seibel.lod.api.interfaces.world.IDhApiWorldProxy;
import com.seibel.lod.api.methods.override.DhApiWorldGeneratorOverrideRegister;
import com.seibel.lod.core.DependencyInjection.DhApiEventInjector;
import com.seibel.lod.core.DependencyInjection.OverrideInjector;
@@ -24,7 +25,7 @@ import com.seibel.lod.core.interfaces.dependencyInjection.IOverrideInjector;
* the concrete object we replaced, there would be issues.
*
* @author James Seibel
- * @version 2022-11-12
+ * @version 2022-11-20
*/
public class DhApiMain
{
@@ -52,6 +53,19 @@ public class DhApiMain
*/
public static IDhApiTerrainDataRepo terrainRepo = null;
+ /**
+ * WARNING: will be null until after DH initializes for the first time.
+ *
+ * Use a {@link com.seibel.lod.api.methods.events.abstractEvents.DhApiAfterDhInitEvent DhApiAfterDhInitEvent}
+ * along with the {@link DhApiMain#events ApiCoreInjectors.events} to be notified when this can
+ * be safely used.
+ *
+ * Used to interact with Distant Horizons' currently loaded world and
+ * get levels to use with the {@link DhApiMain#terrainRepo}.
+ */
+ public static IDhApiWorldProxy worldProxy = null;
+
+
// always available //
diff --git a/api/src/main/java/com/seibel/lod/api/interfaces/world/IDhApiLevelWrapper.java b/api/src/main/java/com/seibel/lod/api/interfaces/world/IDhApiLevelWrapper.java
index d0ed8ea6c..a0669f23e 100644
--- a/api/src/main/java/com/seibel/lod/api/interfaces/world/IDhApiLevelWrapper.java
+++ b/api/src/main/java/com/seibel/lod/api/interfaces/world/IDhApiLevelWrapper.java
@@ -43,7 +43,7 @@ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper
/**
* Returns the lowest possible block position for the level.
- * For MC versions before 1.19 this will return 0.
+ * For MC versions before 1.18 this will return 0.
*/
default int getMinHeight() { return 0; }
diff --git a/api/src/main/java/com/seibel/lod/api/interfaces/world/IDhApiWorldProxy.java b/api/src/main/java/com/seibel/lod/api/interfaces/world/IDhApiWorldProxy.java
new file mode 100644
index 000000000..7724ea203
--- /dev/null
+++ b/api/src/main/java/com/seibel/lod/api/interfaces/world/IDhApiWorldProxy.java
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the Distant Horizons mod (formerly the LOD Mod),
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2022 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.api.interfaces.world;
+
+import com.seibel.lod.api.interfaces.IDhApiUnsafeWrapper;
+
+/**
+ * Used to interact with Distant Horizons current world.
+ *
+ * @author James Seibel
+ * @version 2022-11-20
+ */
+public interface IDhApiWorldProxy
+{
+ /** Returns true if a world is loaded. */
+ boolean worldLoaded();
+
+
+ /**
+ * In singleplayer this will return the level the player is currently in.
+ * In multiplayer this will return null.
+ *
+ * @throws IllegalStateException if no world is loaded
+ */
+ IDhApiLevelWrapper getSinglePlayerLevel() throws IllegalStateException;
+
+ /** @throws IllegalStateException if no world is loaded */
+ Iterable getAllLoadedLevelWrappers() throws IllegalStateException;
+
+ /**
+ * In the case of servers running multiverse there may be multiple levels for the same dimensionType.
+ *
+ * @throws IllegalStateException if no world is loaded
+ */
+ Iterable getAllLoadedLevelsForDimensionType(IDhApiDimensionTypeWrapper dimensionTypeWrapper) throws IllegalStateException;
+
+ /**
+ * Returns any dimensions that have names containing the given string (case-insensitive).
+ * In the case of servers running multiverse there may be multiple levels for the same dimensionType.
+ *
+ * @throws IllegalStateException if no world is loaded
+ */
+ Iterable getAllLoadedLevelsWithDimensionNameLike(String dimensionName) throws IllegalStateException;
+
+}
diff --git a/core/src/main/java/com/seibel/lod/core/Initializer.java b/core/src/main/java/com/seibel/lod/core/Initializer.java
index 7790d6c9a..bfa188fe2 100644
--- a/core/src/main/java/com/seibel/lod/core/Initializer.java
+++ b/core/src/main/java/com/seibel/lod/core/Initializer.java
@@ -7,12 +7,13 @@ import com.seibel.lod.core.datatype.full.FullDataLoader;
import com.seibel.lod.core.datatype.full.SparseDataLoader;
import com.seibel.lod.api.DhApiMain;
import com.seibel.lod.core.datatype.full.SpottyDataLoader;
+import com.seibel.lod.core.world.DhApiWorldProxy;
/**
* Handles first time Core setup.
*
* @author Leetom
- * @version 2022-11-12
+ * @version 2022-11-20
*/
public class Initializer
{
@@ -26,6 +27,7 @@ public class Initializer
// link Core's config to the API
DhApiMain.configs = DhApiConfig.INSTANCE;
DhApiMain.terrainRepo = DhApiTerrainDataRepo.INSTANCE;
+ DhApiMain.worldProxy = DhApiWorldProxy.INSTANCE;
}
}
diff --git a/core/src/main/java/com/seibel/lod/core/world/AbstractDhWorld.java b/core/src/main/java/com/seibel/lod/core/world/AbstractDhWorld.java
index 8c94d8f36..e5667a92c 100644
--- a/core/src/main/java/com/seibel/lod/core/world/AbstractDhWorld.java
+++ b/core/src/main/java/com/seibel/lod/core/world/AbstractDhWorld.java
@@ -1,13 +1,21 @@
package com.seibel.lod.core.world;
+import com.seibel.lod.api.interfaces.world.IDhApiDimensionTypeWrapper;
+import com.seibel.lod.api.interfaces.world.IDhApiLevelWrapper;
+import com.seibel.lod.api.interfaces.world.IDhApiWorldProxy;
import com.seibel.lod.core.level.IDhLevel;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger;
import java.io.Closeable;
+import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
+/**
+ * Represents an entire world (aka server) and
+ * contains every level in that world.
+ */
public abstract class AbstractDhWorld implements Closeable
{
protected static final Logger LOGGER = DhLoggerBuilder.getLogger();
diff --git a/core/src/main/java/com/seibel/lod/core/world/DhApiWorldProxy.java b/core/src/main/java/com/seibel/lod/core/world/DhApiWorldProxy.java
new file mode 100644
index 000000000..cf3526303
--- /dev/null
+++ b/core/src/main/java/com/seibel/lod/core/world/DhApiWorldProxy.java
@@ -0,0 +1,126 @@
+package com.seibel.lod.core.world;
+
+import com.seibel.lod.api.interfaces.world.IDhApiDimensionTypeWrapper;
+import com.seibel.lod.api.interfaces.world.IDhApiLevelWrapper;
+import com.seibel.lod.api.interfaces.world.IDhApiWorldProxy;
+import com.seibel.lod.core.api.internal.SharedApi;
+import com.seibel.lod.core.dependencyInjection.SingletonInjector;
+import com.seibel.lod.core.level.IDhLevel;
+import com.seibel.lod.core.logging.DhLoggerBuilder;
+import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
+import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
+import org.apache.logging.log4j.Logger;
+
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Used to interact with the currently loaded world.
+ * This is separate from the world itself to prevent issues
+ * with API implementors referencing said world when it needs
+ * to be loaded/unloaded.
+ *
+ * @author James Seibel
+ * @version 2022-11-20
+ */
+public class DhApiWorldProxy implements IDhApiWorldProxy
+{
+ public static DhApiWorldProxy INSTANCE = new DhApiWorldProxy();
+
+ private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
+ private static final String NO_WORLD_EXCEPTION_STRING = "No world loaded";
+
+
+
+ private DhApiWorldProxy() { }
+
+
+
+ @Override
+ public boolean worldLoaded() { return SharedApi.currentWorld != null; }
+
+ @Override
+ public IDhApiLevelWrapper getSinglePlayerLevel()
+ {
+ if (SharedApi.currentWorld == null)
+ {
+ throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
+ }
+
+
+ if (!SharedApi.MC.isDedicatedServer())
+ {
+ return MC.getWrappedClientWorld();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ @Override
+ public Iterable getAllLoadedLevelWrappers()
+ {
+ if (SharedApi.currentWorld == null)
+ {
+ throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
+ }
+
+
+ ArrayList returnList = new ArrayList<>();
+ for (IDhLevel dhLevel : SharedApi.currentWorld.getAllLoadedLevels())
+ {
+ returnList.add(dhLevel.getLevelWrapper());
+ }
+ return returnList;
+ }
+
+ @Override
+ public Iterable getAllLoadedLevelsForDimensionType(IDhApiDimensionTypeWrapper dimensionTypeWrapper)
+ {
+ if (SharedApi.currentWorld == null)
+ {
+ throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
+ }
+
+
+ ArrayList returnList = new ArrayList<>();
+ for (IDhLevel dhLevel : SharedApi.currentWorld.getAllLoadedLevels())
+ {
+ ILevelWrapper levelWrapper = dhLevel.getLevelWrapper();
+ if (levelWrapper.getDimensionType().equals(dimensionTypeWrapper))
+ {
+ returnList.add(levelWrapper);
+ }
+ }
+ return returnList;
+ }
+
+ @Override
+ public Iterable getAllLoadedLevelsWithDimensionNameLike(String dimensionName)
+ {
+ if (SharedApi.currentWorld == null)
+ {
+ throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
+ }
+
+
+ String soughtDimName = dimensionName.toLowerCase();
+
+ ArrayList returnList = new ArrayList<>();
+ for (IDhLevel dhLevel : SharedApi.currentWorld.getAllLoadedLevels())
+ {
+ ILevelWrapper levelWrapper = dhLevel.getLevelWrapper();
+ String levelDimName = levelWrapper.getDimensionType().getDimensionName().toLowerCase();
+ if (levelDimName.contains(soughtDimName))
+ {
+ returnList.add(levelWrapper);
+ }
+ }
+
+ return returnList;
+ }
+
+}