2nd Refactor started. Split to 3 type world structure

This commit is contained in:
TomTheFurry
2022-06-22 20:43:00 +08:00
parent 976e36e80c
commit dc1c130fb9
48 changed files with 700 additions and 329 deletions
@@ -0,0 +1,7 @@
package com.seibel.lod.core.a7;
public enum WorldEnvironment {
Client_Only,
Client_Server,
Server_Only
}
@@ -2,7 +2,7 @@ package com.seibel.lod.core.a7.data;
import com.google.common.collect.HashMultimap;
import com.seibel.lod.core.a7.RenderDataProvider;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.datatype.column.DataSourceSaver;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.render.RenderDataSource;
@@ -1,7 +1,7 @@
package com.seibel.lod.core.a7.data;
import com.google.common.collect.HashMultimap;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.io.file.DataMetaFile;
import java.io.File;
@@ -1,6 +1,6 @@
package com.seibel.lod.core.a7.data;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import java.io.File;
import java.util.List;
@@ -5,7 +5,7 @@ import com.seibel.lod.core.a7.data.LodDataSource;
import com.seibel.lod.core.a7.data.OldFileConverter;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.enums.config.EVerticalQuality;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.objects.a7.data.*;
import com.seibel.lod.core.a7.io.file.DataMetaFile;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
@@ -6,7 +6,7 @@ import com.seibel.lod.core.a7.io.MetaFile;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.enums.config.EVerticalQuality;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.io.file.DataMetaFile;
import java.io.*;
@@ -5,7 +5,7 @@ import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.render.RenderBuffer;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.objects.LodDataView;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.LodQuadTree;
import com.seibel.lod.core.a7.LodSection;
import com.seibel.lod.core.a7.render.RenderDataSource;
@@ -5,7 +5,7 @@ import com.seibel.lod.core.a7.datatype.full.FullDatatype;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.render.RenderDataSource;
import com.seibel.lod.core.a7.render.RenderDataSourceLoader;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.objects.a7.data.DataFile;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.LodUtil;
@@ -5,7 +5,7 @@ import com.seibel.lod.core.a7.data.DataSourceLoader;
import com.seibel.lod.core.a7.data.LodDataSource;
import com.seibel.lod.core.a7.io.MetaFile;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import java.io.File;
import java.io.IOException;
@@ -3,7 +3,7 @@ package com.seibel.lod.core.a7.datatype.column;
import com.seibel.lod.core.a7.data.DataSourceLoader;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.objects.LodDataView;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import java.io.DataInputStream;
import java.io.IOException;
@@ -44,30 +44,6 @@ public class DHFolderHandler {
throw new RuntimeException("Critical error: Unable to get world folder directory", e);
}
// move any old data folders if they exist
File[] subFolders = dimensionFolder.listFiles();
if (subFolders != null) {
for (File folder : subFolders)
{
//FIXME: Errr... What to do here?
/*
if (VerticalQuality.getByName(folder.getName()) != null)
{
// this is a LOD save folder
// create a new sub dimension and move the data into it
File newDimension = GetDimensionFolder(dimensionType, subDimensionName);
newDimension.mkdirs();
File oldDataNewPath = new File(newDimension.getPath() + File.separatorChar + folder.getName());
Files.move(folder.toPath(), oldDataNewPath.toPath());
}
else
{
// ignore this folder
}
*/
}
}
return dimensionFolder;
}
private static String getServerFolderName()
@@ -1,5 +1,6 @@
package com.seibel.lod.core.a7.io;
import com.seibel.lod.core.a7.world.DhClientWorld;
import com.seibel.lod.core.api.internal.InternalApiShared;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
@@ -14,49 +15,53 @@ import com.seibel.lod.core.handlers.dimensionFinder.SubDimCompare;
import com.seibel.lod.core.logging.ConfigBasedLogger;
import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.objects.DHRegionPos;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.DHWorld;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.objects.lod.LodRegion;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.LogManager;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
public class LevelToFileMatcher {
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
public class LevelToFileMatcher implements AutoCloseable {
private static final IMinecraftClientWrapper MC_CLIENT = SingletonHandler.get(IMinecraftClientWrapper.class);
public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(LodDimensionFinder.class),
() -> Config.Client.Advanced.Debugging.DebugSwitch.logFileSubDimEvent.get());
/** Increasing this will increase accuracy but increase calculation time */
private static final EVerticalQuality VERTICAL_QUALITY_TO_TEST_WITH = EVerticalQuality.LOW;
private final ExecutorService matcherThread = LodUtil.makeSingleThreadPool("Level-To-File-Matcher");
public static final String THREAD_NAME = "Level-To-File-Matcher";
private PlayerData playerData = new PlayerData(MC);
private PlayerData playerData = null;
private PlayerData firstSeenPlayerData = null;
private volatile DHLevel foundLevel = null;
/** If true the LodDimensionFileHelper is attempting to determine the folder for this dimension */
private final AtomicBoolean determiningWorldFolder = new AtomicBoolean(false);
private final ILevelWrapper currentLevel;
private final DhClientWorld world;
private volatile DHLevel foundLevel = null;
private final File[] potentialFiles;
private final File levelsFolder;
private final IWorldWrapper currentWorld;
private final File worldFolder;
private final DHWorld dhWorld;
public LevelToFileMatcher(DHWorld dhWorld, File worldFolder, IWorldWrapper targetWorld) {
this.currentWorld = targetWorld;
this.worldFolder = worldFolder;
this.dhWorld = dhWorld;
public LevelToFileMatcher(DhClientWorld DhWorld, ILevelWrapper targetWorld, File levelsFolder, File[] potentialFiles) {
this.currentLevel = targetWorld;
this.world = DhWorld;
this.potentialFiles = potentialFiles;
this.levelsFolder = levelsFolder;
if (potentialFiles.length == 0) {
String newId = UUID.randomUUID().toString();
LOGGER.info("No potential level files found. Creating a new sub dimension with ID {}...",
LodUtil.shortenString(newId, 8));
File folder = new File(levelsFolder, newId);
foundLevel = new DHLevel(world, folder, targetWorld);
}
}
// May return null, where at this moment the level is not yet known
@@ -65,87 +70,30 @@ public class LevelToFileMatcher {
return foundLevel;
}
public IWorldWrapper getTargetWorld() {
return currentWorld;
public boolean isFindingLevel(ILevelWrapper level) {
return Objects.equals(level, currentLevel);
}
private void tick() {
if (foundLevel != null) return;
// prevent multiple threads running at the same time
if (Config.Client.Multiplayer.multiDimensionRequiredSimilarity.get() == 0 || MC.hasSinglePlayerServer()) {
File saveDir = getLevelFolderWithoutSimilarityMatching();
foundLevel = new DHLevel(dhWorld, saveDir, currentWorld);
} else {
if (determiningWorldFolder.getAndSet(true)) return;
//FIXME: Use a thread pool
Thread thread = new Thread(() ->
{
try {
// attempt to get the file handler
File saveDir = attemptToDetermineSubDimensionFolder();
if (saveDir == null) return;
foundLevel = new DHLevel(dhWorld, saveDir, currentWorld);
} catch (IOException e) {
LOGGER.error("Unable to set the dimension file handler for level [" + currentWorld + "]. Error: ", e);
} finally {
// make sure we unlock this method
determiningWorldFolder.set(false);
}
});
thread.setName(THREAD_NAME);
thread.start();
}
}
/**
* Returns the default save folder if it exists
* otherwise the first valid subDimension folder lexicographically.
*/
private File getLevelFolderWithoutSimilarityMatching()
{
File[] subDirs = worldFolder.listFiles();
File levelFolder = null;
// check if a sub dimension folder exists
if (subDirs != null)
if (determiningWorldFolder.getAndSet(true)) return;
matcherThread.submit(() ->
{
// at least one folder exists
LOGGER.info("Potential Sub Dimension folders: [" + subDirs.length + "]");
Arrays.sort(subDirs); // listFiles isn't necessarily sorted
for (File potentialFolder : subDirs)
{
if (isValidLevelFolder(potentialFolder))
{
if (potentialFolder.getName().equals(currentWorld.getDimensionType().getDimensionName()))
{
// use the default save folder if possible
levelFolder = potentialFolder;
break;
}
else if (levelFolder == null)
{
// only get the first non-default sub folder
levelFolder = potentialFolder;
}
}
try {
// attempt to get the file handler
File saveDir = attemptToDetermineSubDimensionFolder();
if (saveDir == null) return;
foundLevel = new DHLevel(world, saveDir, currentLevel);
} catch (IOException e) {
LOGGER.error("Unable to set the dimension file handler for level [" + currentLevel + "]. Error: ", e);
} finally {
// make sure we unlock this method
determiningWorldFolder.set(false);
}
}
// if no valid sub dimension was found, create a new one
if (levelFolder == null)
{
levelFolder = new File(worldFolder, currentWorld.getDimensionType().getDimensionName());
levelFolder.mkdirs();
LOGGER.info("Default Sub Dimension not found. Creating: [" + currentWorld.getDimensionType().getDimensionName() + "]");
}
else
{
LOGGER.info("Default Sub Dimension set to: [" + LodUtil.shortenString(levelFolder.getName(), 8) + "...]");
}
return levelFolder;
});
}
/**
* Currently this method checks a single chunk (where the player is)
* and compares it against the same chunk position in the other dimension worlds to
@@ -155,36 +103,36 @@ public class LevelToFileMatcher {
*/
public File attemptToDetermineSubDimensionFolder() throws IOException
{
if (firstSeenPlayerData == null)
{
firstSeenPlayerData = playerData;
playerData = new PlayerData(MC);
{ // Update PlayerData
PlayerData data = PlayerData.tryGetPlayerData(MC_CLIENT);
if (data != null) {
if (firstSeenPlayerData == null) {
firstSeenPlayerData = data;
}
playerData = data;
}
}
// relevant positions
DHChunkPos playerChunkPos = new DHChunkPos(playerData.playerBlockPos);
int startingBlockPosX = playerChunkPos.getMinBlockX();
int startingBlockPosZ = playerChunkPos.getMinBlockZ();
DHRegionPos playerRegionPos = new DHRegionPos(playerChunkPos);
// chunk from the newly loaded level
IChunkWrapper newlyLoadedChunk = MC.getWrappedClientWorld().tryGetChunk(playerChunkPos);
IChunkWrapper newlyLoadedChunk = MC_CLIENT.getWrappedClientWorld().tryGetChunk(playerChunkPos);
// check if this chunk is valid to test
if (!CanDetermineLevelFolder(newlyLoadedChunk))
return null;
// create a temporary dimension to store the test LOD
LodDimension newlyLoadedDim = new LodDimension(MC.getCurrentDimension(), 1, null, false);
newlyLoadedDim.move(playerRegionPos);
newlyLoadedDim.regions.set(playerRegionPos.x, playerRegionPos.z, new LodRegion(LodUtil.BLOCK_DETAIL_LEVEL, playerRegionPos, VERTICAL_QUALITY_TO_TEST_WITH));
//TODO: Compute a ChunkData from current chunk.
/*
// generate a LOD to test against
boolean lodGenerated = InternalApiShared.lodBuilder.generateLodNodeFromChunk(newlyLoadedDim, newlyLoadedChunk, new LodBuilderConfig(EDistanceGenerationMode.FULL), true, true);
if (!lodGenerated)
return null;
// log the start of this attempt
LOGGER.info("Attempting to determine sub-dimension for [" + MC.getCurrentDimension().getDimensionName() + "]");
LOGGER.info("Attempting to determine sub-dimension for [" + MC_CLIENT.getCurrentDimension().getDimensionName() + "]");
LOGGER.info("Player block pos in dimension: [" + playerData.playerBlockPos.getX() + "," + playerData.playerBlockPos.getY() + "," + playerData.playerBlockPos.getZ() + "]");
// new chunk data
@@ -215,21 +163,23 @@ public class LevelToFileMatcher {
LOGGER.warn(message);
}
return null;
}
}*/
// compare each world with the newly loaded one
SubDimCompare mostSimilarSubDim = null;
File[] levelFolders = worldFolder.listFiles(File::isDirectory);
File[] levelFolders = potentialFiles;
LOGGER.info("Potential Sub Dimension folders: [" + levelFolders.length + "]");
for (File testLevelFolder : levelFolders)
{
//FIXME: Err... what? The filter should have already filtered this out... Is this needed?
if (!testLevelFolder.isDirectory()) continue;
if (!isValidLevelFolder(testLevelFolder)) continue;
LOGGER.info("Testing level folder: [" + LodUtil.shortenString(testLevelFolder.getName(), 8) + "]");
try
{
// TODO: Try load a data file overlapping the playerChunkPos from ClientOnlySaveStructure,
// and then use it to compare chunk data to current chunk.
/*
// get a LOD from this dimension folder
LodDimension tempLodDim = new LodDimension(null, 1, null, false);
tempLodDim.move(playerRegionPos);
@@ -291,6 +241,7 @@ public class LevelToFileMatcher {
}
LOGGER.info("Sub dimension [" + LodUtil.shortenString(testLevelFolder.getName(), 8) + "...] is current dimension probability: " + LodUtil.shortenString(subDimCompare.getPercentEqual() + "", 5) + " (" + equalDataPoints + "/" + totalDataPointCount + ")");
*/
}
catch (Exception e)
{
@@ -299,7 +250,7 @@ public class LevelToFileMatcher {
}
}
// TODO if two sub dimensions contain the same LODs merge them
// TODO if two sub dimensions contain the same LODs merge them???
// the first seen player data is no longer needed, the sub dimension has been determined
firstSeenPlayerData = null;
@@ -320,7 +271,7 @@ public class LevelToFileMatcher {
String newId = UUID.randomUUID().toString();
String message = "No suitable sub dimension found. The highest equality was [" + LodUtil.shortenString(highestEqualityPercent + "", 5) + "]. Creating a new sub dimension with ID: " + LodUtil.shortenString(newId, 8) + "...";
LOGGER.info(message);
File folder = new File(worldFolder, newId);
File folder = new File(levelsFolder, newId);
folder.mkdirs();
return folder;
}
@@ -333,49 +284,8 @@ public class LevelToFileMatcher {
return LodBuilder.canGenerateLodFromChunk(chunk);
}
/** Used for debugging, returns true if every data point is 0 */
private static boolean isDataEmpty(long[][][] chunkData)
{
for (long[][] xArray : chunkData)
{
for (long[] zArray : xArray)
{
for (long dataPoint : zArray)
{
if (dataPoint != 0)
{
return false;
}
}
}
}
return true;
@Override
public void close() {
matcherThread.shutdownNow();
}
/** Returns true if the given folder holds valid Lod Dimension data */
public static boolean isValidLevelFolder(File potentialFolder)
{
if (!potentialFolder.isDirectory())
// it needs to be a folder
return false;
if (potentialFolder.listFiles() == null)
// it needs to have folders in it
return false;
// check if there is at least one VerticalQuality folder in this directory
for (File internalFolder : potentialFolder.listFiles())
{
if (EVerticalQuality.getByName(internalFolder.getName()) != null)
{
// one of the internal folders is a VerticalQuality folder
return true;
}
}
return false;
}
}
@@ -17,7 +17,7 @@ import com.seibel.lod.core.a7.datatype.full.FullDatatype;
import com.seibel.lod.core.a7.io.MetaFile;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.datatype.column.DataSourceSaver;
import com.seibel.lod.core.a7.datatype.column.OldDataSourceLoader;
import com.seibel.lod.core.util.LodUtil;
@@ -1,4 +1,4 @@
package com.seibel.lod.core.a7.io;
package com.seibel.lod.core.a7.io.file;
import com.seibel.lod.core.a7.data.LodDataSource;
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
@@ -3,10 +3,9 @@ package com.seibel.lod.core.a7.io.file;
import com.google.common.collect.HashMultimap;
import com.seibel.lod.core.a7.data.LodDataSource;
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
import com.seibel.lod.core.a7.io.DataSourceProvider;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.util.LodUtil;
import org.apache.logging.log4j.Logger;
@@ -2,7 +2,7 @@ package com.seibel.lod.core.a7.io.render;
import com.seibel.lod.core.a7.RenderDataProvider;
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
import com.seibel.lod.core.a7.io.DataSourceProvider;
import com.seibel.lod.core.a7.io.file.DataSourceProvider;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.a7.render.RenderDataSource;
@@ -25,7 +25,6 @@ public class RenderFileHandler implements RenderDataProvider {
this.renderCacheFolder = renderCacheFolder;
}
@Override
public CompletableFuture<RenderDataSource> createRenderData(RenderDataSourceLoader renderSourceLoader, DhSectionPos pos) {
return null;
@@ -36,6 +35,6 @@ public class RenderFileHandler implements RenderDataProvider {
}
public void write(DhSectionPos sectionPos, FullDatatype chunkData) {
`
}
}
@@ -0,0 +1,14 @@
package com.seibel.lod.core.a7.io.render;
import com.seibel.lod.core.a7.data.LodDataSource;
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.render.RenderDataSource;
import java.util.concurrent.CompletableFuture;
public interface RenderSourceProvider {
CompletableFuture<RenderDataSource> get(DhSectionPos pos);
void write(DhSectionPos sectionPos, FullDatatype chunkData);
CompletableFuture<Void> flushAndSave();
}
@@ -1,5 +1,8 @@
package com.seibel.lod.core.a7;
package com.seibel.lod.core.a7.level;
import com.seibel.lod.core.a7.world.DhWorld;
import com.seibel.lod.core.a7.LodQuadTree;
import com.seibel.lod.core.a7.RenderDataProvider;
import com.seibel.lod.core.a7.data.DataFileHandler;
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
import com.seibel.lod.core.a7.render.RenderBufferHandler;
@@ -11,7 +14,7 @@ import com.seibel.lod.core.util.EventLoop;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import java.io.Closeable;
import java.io.File;
@@ -25,13 +28,12 @@ public class DHLevel extends LodQuadTree implements Closeable {
public final RenderBufferHandler renderBufferHandler;
public final ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHLevelTickerThread", 2);
private final AtomicBoolean isRunning = new AtomicBoolean(false);
public final IWorldWrapper level;
public final ILevelWrapper level;
public a7LodRenderer renderer;
public final DHWorld world;
public final DhWorld world;
public EventLoop eventLoop;
public DHLevel(DHWorld world, File saveFolder, IWorldWrapper level) {
public DHLevel(DhWorld world, File saveFolder, ILevelWrapper level) {
super(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
MC.getPlayerBlockPos().x,
MC.getPlayerBlockPos().z);
@@ -2,8 +2,8 @@ package com.seibel.lod.core.a7.render;
import com.seibel.lod.core.a7.data.LodDataSource;
import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.objects.a7.data.DataFile;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.data.DataFile;
import java.util.*;
import java.util.stream.Collectors;
@@ -0,0 +1,174 @@
package com.seibel.lod.core.a7.save.structure;
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.world.DhClientWorld;
import com.seibel.lod.core.a7.world.DhWorld;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.enums.config.EServerFolderNameMode;
import com.seibel.lod.core.enums.config.EVerticalQuality;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.objects.ParsedIp;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import javax.annotation.Nullable;
import java.io.File;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ClientOnlySaveStructure extends SaveStructure {
final File folder;
private static final IMinecraftClientWrapper MC_CLIENT = SingletonHandler.get(IMinecraftClientWrapper.class);
public static final String INVALID_FILE_CHARACTERS_REGEX = "[\\\\/:*?\"<>|]";
private static String getServerFolderName()
{
// parse the current server's IP
ParsedIp parsedIp = new ParsedIp(MC_CLIENT.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
EServerFolderNameMode folderNameMode = Config.Client.Multiplayer.serverFolderNameMode.get();
if (folderNameMode == EServerFolderNameMode.AUTO)
{
if (parsedIp.isLan())
{
// LAN
folderNameMode = EServerFolderNameMode.NAME_IP;
}
else
{
// normal multiplayer
folderNameMode = EServerFolderNameMode.NAME_IP_PORT;
}
}
String serverName = MC_CLIENT.getCurrentServerName().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
String serverMcVersion = MC_CLIENT.getCurrentServerVersion().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
// 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 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;
}
LevelToFileMatcher fileMatcher = null;
final DhClientWorld world;
// Fit for Client_Only environment
public ClientOnlySaveStructure(DhClientWorld world) {
folder = new File(MC_CLIENT.getGameDirectory().getPath() +
File.separatorChar + "Distant_Horizons_server_data" + File.separatorChar + getServerFolderName());
if (!folder.exists()) folder.mkdirs(); //TODO: Deal with errors
this.world = world;
}
@Override
public DHLevel tryGetLevel(ILevelWrapper wrapper) {
if (Config.Client.Multiplayer.multiDimensionRequiredSimilarity.get() == 0) {
if (fileMatcher != null) {
fileMatcher.close();
fileMatcher = null;
}
return new DHLevel(world, getLevelFolderWithoutSimilarityMatching(wrapper), wrapper);
}
if (fileMatcher == null || !fileMatcher.isFindingLevel(wrapper)) {
LOGGER.info("Loading level for world " + wrapper.getDimensionType().getDimensionName());
fileMatcher = new LevelToFileMatcher(world, wrapper, folder,
(File[]) getMatchingLevelFolders(wrapper).toArray());
}
DHLevel level = fileMatcher.tryGetLevel();
if (level != null) {
fileMatcher.close();
fileMatcher = null;
}
return level;
}
private File getLevelFolderWithoutSimilarityMatching(ILevelWrapper level)
{
Stream<File> folders = getMatchingLevelFolders(level);
Optional<File> first = folders.findFirst();
if (first.isPresent())
{
LOGGER.info("Default Sub Dimension set to: [" + LodUtil.shortenString(first.get().getName(), 8) + "...]");
return first.get();
} else { // if no valid sub dimension was found, create a new one
LOGGER.info("Default Sub Dimension not found. Creating: [" + level.getDimensionType().getDimensionName() + "]");
return new File(folder, level.getDimensionType().getDimensionName());
}
}
public Stream<File> getMatchingLevelFolders(@Nullable ILevelWrapper level) {
File[] folders = folder.listFiles();
if (folders==null) return Stream.empty();
return Arrays.stream(folders).filter(
(f) -> {
if (!isValidLevelFolder(f)) return false;
return level==null || f.getName().equalsIgnoreCase(level.getDimensionType().getDimensionName());
}
).sorted();
}
/** Returns true if the given folder holds valid Lod Dimension data */
private static boolean isValidLevelFolder(File potentialFolder)
{
if (!potentialFolder.isDirectory())
// it needs to be a folder
return false;
if (potentialFolder.listFiles() == null)
// it needs to have folders in it
return false;
// check if there is at least one VerticalQuality folder in this directory
for (File internalFolder : potentialFolder.listFiles())
{
if (EVerticalQuality.getByName(internalFolder.getName()) != null)
{
// one of the internal folders is a VerticalQuality folder
return true;
}
}
return false;
}
@Override
public File getRenderCacheFolder(ILevelWrapper world) {
return null;
}
@Override
public File getDataFolder(ILevelWrapper world) {
return null;
}
@Override
public void close() {
fileMatcher.close();
}
}
@@ -0,0 +1,29 @@
package com.seibel.lod.core.a7.save.structure;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import java.io.File;
public class LocalSaveStructure extends SaveStructure {
private static final IMinecraftSharedWrapper MC = SingletonHandler.get(IMinecraftSharedWrapper.class);
private final File folder;
// Fit for Client_Server & Server_Only environment
public LocalSaveStructure() {
folder = MC.getInstallationDirectory();
}
@Override
public File getRenderCacheFolder(ILevelWrapper world) {
return null;
}
@Override
public File getDataFolder(ILevelWrapper world) {
return null;
}
}
@@ -0,0 +1,21 @@
package com.seibel.lod.core.a7.save.structure;
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger;
import java.io.File;
public abstract class SaveStructure implements AutoCloseable {
protected static final Logger LOGGER = DhLoggerBuilder.getLogger();
public abstract DHLevel tryGetLevel(ILevelWrapper wrapper);
protected abstract File getRenderCacheFolder(ILevelWrapper world);
protected abstract File getDataFolder(ILevelWrapper world);
}
@@ -0,0 +1,85 @@
package com.seibel.lod.core.a7.world;
import com.seibel.lod.core.a7.WorldEnvironment;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import java.util.HashMap;
import java.util.Iterator;
public class DhClientServerWorld extends DhWorld implements IClientWorld, IServerWorld {
private final HashMap<ILevelWrapper, DHLevel> levels;
public final LocalSaveStructure saveStructure;
public DhClientServerWorld() {
super(WorldEnvironment.Client_Server);
saveStructure = new LocalSaveStructure();
levels = new HashMap<>();
}
@Override
public DHLevel getOrLoadLevel(ILevelWrapper wrapper) {
if (!levels.containsKey(wrapper)) {
DHLevel level = saveStructure.tryGetLevel(wrapper);
if (level != null) {
levels.put(wrapper, level);
}
return level;
} else return levels.get(wrapper);
}
@Override
public DHLevel getLevel(ILevelWrapper wrapper) {
return levels.get(wrapper);
}
@Override
public void unloadLevel(ILevelWrapper wrapper) {
if (levels.containsKey(wrapper)) {
LOGGER.info("Unloading level for world " + wrapper.getDimensionType().getDimensionName());
levels.get(wrapper).close();
levels.remove(wrapper).close();
}
}
public void tick() {
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
Iterator<DHLevel> iterator = levels.values().iterator();
while (iterator.hasNext()) {
DHLevel level = iterator.next();
if (level.viewDistance != newViewDistance) {
level.close();
iterator.remove();
}
}
DetailDistanceUtil.updateSettings();
}
public void doWorldGen() {
}
@Override
public void saveAndFlush() {
for (DHLevel level : levels.values()) {
level.saveFlush();
}
}
@Override
public void close() {
for (DHLevel level : levels.values()) {
LOGGER.info("Unloading level for world " + level.level.getDimensionType().getDimensionName());
level.close();
}
levels.clear();
}
@Override
public void render() {
}
}
@@ -1,67 +1,60 @@
package com.seibel.lod.core.a7;
package com.seibel.lod.core.a7.world;
import com.seibel.lod.core.a7.io.DHFolderHandler;
import com.seibel.lod.core.a7.WorldEnvironment;
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.save.structure.ClientOnlySaveStructure;
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.EventLoop;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import org.apache.logging.log4j.Logger;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import java.io.Closeable;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
public class DHWorld implements Closeable {
private static final Logger LOGGER = DhLoggerBuilder.getLogger("DHWorld");
public class DhClientWorld extends DhWorld implements IClientWorld {
private final File saveDir;
private final HashMap<IWorldWrapper, DHLevel> levels;
private LevelToFileMatcher levelToFileMatcher = null;
private final HashMap<ILevelWrapper, DHLevel> levels;
public final ClientOnlySaveStructure saveStructure;
public ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHTickerThread", 2);
public EventLoop eventLoop = new EventLoop(dhTickerThread, this::tick);
public DHWorld() {
//Note: this changes the singleplayer lod save location.
saveDir = DHFolderHandler.getCurrentWorldFolder();
public DhClientWorld() {
super(WorldEnvironment.Client_Only);
saveStructure = new ClientOnlySaveStructure(this);
levels = new HashMap<>();
}
public DHLevel getOrLoadLevel(IWorldWrapper wrapper) {
@Override
public DHLevel getOrLoadLevel(ILevelWrapper wrapper) {
if (!levels.containsKey(wrapper)) {
if (levelToFileMatcher == null || levelToFileMatcher.getTargetWorld() != wrapper) {
LOGGER.info("Loading level for world " + wrapper.getDimensionType().getDimensionName());
levelToFileMatcher = new LevelToFileMatcher(this, saveDir, wrapper);
}
DHLevel level = levelToFileMatcher.tryGetLevel();
DHLevel level = saveStructure.tryGetLevel(wrapper);
if (level != null) {
levels.put(wrapper, level);
levelToFileMatcher = null;
return level;
} else {
return null;
}
return level;
} else return levels.get(wrapper);
}
public DHLevel getLevel(IWorldWrapper wrapper) {
@Override
public DHLevel getLevel(ILevelWrapper wrapper) {
return levels.get(wrapper);
}
public void unloadLevel(IWorldWrapper wrapper) {
@Override
public void unloadLevel(ILevelWrapper wrapper) {
if (levels.containsKey(wrapper)) {
LOGGER.info("Unloading level for world " + wrapper.getDimensionType().getDimensionName());
levels.get(wrapper).close();
levels.remove(wrapper);
levels.remove(wrapper).close();
}
}
public void tick() {
private void tick() {
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
Iterator<DHLevel> iterator = levels.values().iterator();
while (iterator.hasNext()) {
@@ -73,13 +66,13 @@ public class DHWorld implements Closeable {
}
DetailDistanceUtil.updateSettings();
}
public void doWorldGen() {
}
public void asyncTick() {
eventLoop.tick();
}
public void save() {
@Override
public void saveAndFlush() {
for (DHLevel level : levels.values()) {
level.saveFlush();
}
@@ -94,4 +87,9 @@ public class DHWorld implements Closeable {
}
levels.clear();
}
@Override
public void render() {
}
}
@@ -0,0 +1,85 @@
package com.seibel.lod.core.a7.world;
import com.seibel.lod.core.a7.WorldEnvironment;
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.save.structure.ClientOnlySaveStructure;
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import java.util.HashMap;
import java.util.Iterator;
public class DhServerWorld extends DhWorld implements IServerWorld {
private final HashMap<ILevelWrapper, DHLevel> levels;
public final LocalSaveStructure saveStructure;
public DhServerWorld() {
super(WorldEnvironment.Server_Only);
saveStructure = new LocalSaveStructure();
levels = new HashMap<>();
}
@Override
public DHLevel getOrLoadLevel(ILevelWrapper wrapper) {
if (!levels.containsKey(wrapper)) {
DHLevel level = saveStructure.tryGetLevel(wrapper);
if (level != null) {
levels.put(wrapper, level);
}
return level;
} else return levels.get(wrapper);
}
@Override
public DHLevel getLevel(ILevelWrapper wrapper) {
return levels.get(wrapper);
}
@Override
public void unloadLevel(ILevelWrapper wrapper) {
if (levels.containsKey(wrapper)) {
LOGGER.info("Unloading level for world " + wrapper.getDimensionType().getDimensionName());
levels.get(wrapper).close();
levels.remove(wrapper).close();
}
}
public void tick() {
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
Iterator<DHLevel> iterator = levels.values().iterator();
while (iterator.hasNext()) {
DHLevel level = iterator.next();
if (level.viewDistance != newViewDistance) {
level.close();
iterator.remove();
}
}
DetailDistanceUtil.updateSettings();
}
public void doWorldGen() {
}
@Override
public void saveAndFlush() {
for (DHLevel level : levels.values()) {
level.saveFlush();
}
}
@Override
public void close() {
for (DHLevel level : levels.values()) {
LOGGER.info("Unloading level for world " + level.level.getDimensionType().getDimensionName());
level.close();
}
levels.clear();
}
}
@@ -0,0 +1,34 @@
package com.seibel.lod.core.a7.world;
import com.seibel.lod.core.a7.WorldEnvironment;
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.save.structure.SaveStructure;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.EventLoop;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger;
import java.io.Closeable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
public abstract class DhWorld implements Closeable {
protected static final Logger LOGGER = DhLoggerBuilder.getLogger();
public final WorldEnvironment environment;
protected DhWorld(WorldEnvironment environment) {
this.environment = environment;
}
public abstract DHLevel getOrLoadLevel(ILevelWrapper wrapper);
public abstract DHLevel getLevel(ILevelWrapper wrapper);
public abstract void unloadLevel(ILevelWrapper wrapper);
public abstract void saveAndFlush();
}
@@ -0,0 +1,5 @@
package com.seibel.lod.core.a7.world;
public interface IClientWorld {
void render();
}
@@ -0,0 +1,5 @@
package com.seibel.lod.core.a7.world;
public interface IServerWorld {
void doWorldGen();
}
@@ -30,6 +30,7 @@ import com.seibel.lod.core.logging.ConfigBasedLogger;
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.render.RenderSystemTest;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Level;
import com.seibel.lod.core.handlers.LodDimensionFinder;
import org.apache.logging.log4j.LogManager;
@@ -51,7 +52,6 @@ import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
/**
* This holds the methods that should be called
@@ -142,7 +142,7 @@ public class ClientApi
private final ConcurrentHashMap.KeySetView<DHChunkPos,Boolean> generating = ConcurrentHashMap.newKeySet();
public final ConcurrentHashMap.KeySetView<DHChunkPos,Boolean> toBeLoaded = ConcurrentHashMap.newKeySet();
public void clientChunkLoadEvent(IChunkWrapper chunk, IWorldWrapper world)
public void clientChunkLoadEvent(IChunkWrapper chunk, ILevelWrapper world)
{
LagSpikeCatcher clientChunkLoad = new LagSpikeCatcher();
//ApiShared.LOGGER.info("Lod Generating add: "+chunk.getLongChunkPos());
@@ -187,7 +187,7 @@ public class ClientApi
if (!MC.playerExists() || InternalApiShared.lodWorld.getIsWorldNotLoaded())
return;
IWorldWrapper world = MC.getWrappedClientWorld();
ILevelWrapper world = MC.getWrappedClientWorld();
if (world == null)
return;
LodDimension lodDim = InternalApiShared.lodWorld.getLodDimension(world.getDimensionType());
@@ -36,7 +36,7 @@ import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger;
import java.lang.invoke.MethodHandles;
@@ -124,7 +124,7 @@ public class EventApi
}
/** This is also called when a new dimension loads */
public void worldLoadEvent(IWorldWrapper world)
public void worldLoadEvent(ILevelWrapper world)
{
if (ENABLE_STACK_DUMP_LOGGING)
LOGGER.info(
@@ -157,7 +157,7 @@ public class EventApi
}
/** This is also called when the user disconnects from a server+ */
public void worldUnloadEvent(IWorldWrapper world)
public void worldUnloadEvent(ILevelWrapper world)
{
if (ENABLE_STACK_DUMP_LOGGING)
LOGGER.info(
@@ -27,8 +27,8 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.logging.ConfigBasedLogger;
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
import com.seibel.lod.core.logging.SpamReducedLogger;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.DHWorld;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.world.DhWorld;
import com.seibel.lod.core.a7.Server;
import com.seibel.lod.core.objects.math.Mat4f;
import com.seibel.lod.core.render.GLProxy;
@@ -37,7 +37,7 @@ import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -116,7 +116,7 @@ public class ClientApi
public void clientServerConnected() {
SharedApi.currentServer = new Server(false);
SharedApi.currentWorld = new DHWorld();
SharedApi.currentWorld = new DhWorld(enviroment);
}
public void clientServerDisconnected() {
SharedApi.currentWorld.close();
@@ -124,22 +124,22 @@ public class ClientApi
SharedApi.currentServer = null;
}
public void clientChunkLoadEvent(IChunkWrapper chunk, IWorldWrapper world)
public void clientChunkLoadEvent(IChunkWrapper chunk, ILevelWrapper world)
{
//TODO: Implement
}
public void clientChunkSaveEvent(IChunkWrapper chunk, IWorldWrapper world)
public void clientChunkSaveEvent(IChunkWrapper chunk, ILevelWrapper world)
{
//TODO: Implement
}
public void clientLevelUnloadEvent(IWorldWrapper world)
public void clientLevelUnloadEvent(ILevelWrapper world)
{
if (SharedApi.currentWorld != null) {
SharedApi.currentWorld.unloadLevel(world);
}
}
public void clientLevelLoadEvent(IWorldWrapper world)
public void clientLevelLoadEvent(ILevelWrapper world)
{
//TODO: Maybe make DHLevel init no longer depend on needing player entity in single player
if (SharedApi.currentWorld != null) {
@@ -189,7 +189,7 @@ public class ClientApi
profiler.pop();
}
public void renderLods(IWorldWrapper world, Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks)
public void renderLods(ILevelWrapper world, Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks)
{
IProfilerWrapper profiler = MC.getProfiler();
profiler.pop(); // get out of "terrain"
@@ -197,9 +197,9 @@ public class ClientApi
try {
if (!MC.playerExists()) return;
if (world == null) return;
DHWorld dhWorld = SharedApi.currentWorld;
if (dhWorld == null) return;
DHLevel level = (SharedApi.currentServer == null) ? dhWorld.getOrLoadLevel(world) : dhWorld.getLevel(world);
DhWorld DhWorld = SharedApi.currentWorld;
if (DhWorld == null) return;
DHLevel level = (SharedApi.currentServer == null) ? DhWorld.getOrLoadLevel(world) : DhWorld.getLevel(world);
if (level == null) return;
if (prefLoggerEnabled) {
@@ -21,11 +21,11 @@ package com.seibel.lod.core.api.internal.a7;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.a7.DHWorld;
import com.seibel.lod.core.a7.world.DhWorld;
import com.seibel.lod.core.a7.Server;
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger;
import java.lang.invoke.MethodHandles;
@@ -60,15 +60,15 @@ public class ServerApi
lastWorldGenTickDelta--;
if (SharedApi.currentWorld != null && lastWorldGenTickDelta <= 0) {
lastWorldGenTickDelta = 20;
DHWorld dhWorld = SharedApi.currentWorld;
dhWorld.tick();
DhWorld DhWorld = SharedApi.currentWorld;
DhWorld.tick();
}
}
//TODO: rename to serverLoadEvent
public void serverWorldLoadEvent() {
SharedApi.currentServer = new Server(!SharedApi.inDedicatedEnvironment);
SharedApi.currentWorld = new DHWorld();
SharedApi.currentWorld = new DhWorld(enviroment);
//TODO: Setup the network handler
}
@@ -80,12 +80,12 @@ public class ServerApi
SharedApi.currentServer = null;
}
public void serverLevelLoadEvent(IWorldWrapper world) {
public void serverLevelLoadEvent(ILevelWrapper world) {
//TODO: Maybe make DHLevel init no longer depend on needing player entity in single player
if (SharedApi.currentServer.isSinglePlayer) return;
SharedApi.currentWorld.getOrLoadLevel(world);
}
public void serverLevelUnloadEvent(IWorldWrapper world) {
public void serverLevelUnloadEvent(ILevelWrapper world) {
SharedApi.currentWorld.unloadLevel(world);
}
@@ -96,12 +96,12 @@ public class ServerApi
public void chunkSaveEvent(IChunkWrapper chunk, IWorldWrapper world) {
public void chunkSaveEvent(IChunkWrapper chunk, ILevelWrapper world) {
//TODO
}
public void serverChunkLoadEvent(IChunkWrapper chunk, IWorldWrapper world) {
public void serverChunkLoadEvent(IChunkWrapper chunk, ILevelWrapper world) {
}
public void serverChunkSaveEvent(IChunkWrapper chunk, IWorldWrapper world) {
public void serverChunkSaveEvent(IChunkWrapper chunk, ILevelWrapper world) {
}
}
@@ -1,13 +1,13 @@
package com.seibel.lod.core.api.internal.a7;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.a7.DHWorld;
import com.seibel.lod.core.a7.world.DhWorld;
import com.seibel.lod.core.a7.Server;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import org.apache.logging.log4j.Logger;
public class SharedApi {
public static DHWorld currentWorld;
public static DhWorld currentWorld;
public static Server currentServer;
public static IMinecraftSharedWrapper MC;
public static Logger LOGGER = DhLoggerBuilder.getLogger("DH Events");
@@ -43,7 +43,7 @@ import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.LogManager;
/**
@@ -493,7 +493,7 @@ public class LodBuilder
if (blockLight == -1 || skyLight == -1)
{
IWorldWrapper world = MC.getWrappedServerWorld();
ILevelWrapper world = MC.getWrappedServerWorld();
if (world != null)
{
@@ -31,7 +31,7 @@ import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper.Steps;
import org.apache.logging.log4j.Logger;
@@ -54,7 +54,7 @@ public class BatchGenerator
private int estimatedPointsToQueue = 1;
public BatchGenerator(LodBuilder newLodBuilder, LodDimension newLodDimension) {
IWorldWrapper world = LodUtil.getServerWorldFromDimension(newLodDimension.dimension);
ILevelWrapper world = LodUtil.getServerWorldFromDimension(newLodDimension.dimension);
targetLodDim = newLodDimension;
generationGroup = FACTORY.createBatchGenerator(newLodBuilder, newLodDimension, world);
MC.sendChatMessage("NOTE: You are currently using Distant Horizon's Batch Chunk Pre-Generator.");
@@ -65,7 +65,7 @@ public class BatchGenerator
public void queueGenerationRequests(LodDimension lodDim, LodBuilder lodBuilder) {
if (lodDim != targetLodDim) {
stop(false);
IWorldWrapper dim = LodUtil.getServerWorldFromDimension(lodDim.dimension);
ILevelWrapper dim = LodUtil.getServerWorldFromDimension(lodDim.dimension);
generationGroup = FACTORY.createBatchGenerator(lodBuilder, lodDim, dim);
targetLodDim = lodDim;
LOGGER.info("1.18 Experimental Chunk Generator reinitialized");
@@ -41,7 +41,7 @@ import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.LogManager;
import java.io.File;
@@ -437,7 +437,7 @@ public class LodDimensionFinder
{
// local world
IWorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(newDimensionType);
ILevelWrapper serverWorld = LodUtil.getServerWorldFromDimension(newDimensionType);
return new File(serverWorld.getSaveFolder().getCanonicalFile().getPath() + File.separatorChar + "lod" + File.separatorChar + worldId);
}
else
@@ -25,7 +25,9 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.objects.DHBlockPos;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import org.lwjgl.system.CallbackI;
import javax.annotation.Nullable;
import java.io.File;
/**
@@ -55,10 +57,18 @@ public class PlayerData
* I'm not sure what this will look like for worlds that don't have a spawn point.
*/
public DHBlockPos worldSpawnPointBlockPos;
@Nullable
public static PlayerData tryGetPlayerData(IMinecraftClientWrapper mcClient) {
if (!mcClient.playerExists()) return null;
try {
return new PlayerData(mcClient);
} catch (RuntimeException e) {
// Player no longer exists due to concurrency. FIXME: Remember here is called not on main thread!!!
return null;
}
}
public PlayerData(IMinecraftClientWrapper mc)
private PlayerData(IMinecraftClientWrapper mc)
{
updateData(mc);
}
@@ -66,24 +76,23 @@ public class PlayerData
public PlayerData(File dimensionFolder)
{
File file = getFileForDimensionFolder(dimensionFolder);
CommentedFileConfig toml = CommentedFileConfig.builder(file).build();
toml.load();
// get the player block pos if it is specified
if (toml.contains(PLAYER_BLOCK_POS_X_PATH)
&& toml.contains(PLAYER_BLOCK_POS_Y_PATH)
&& toml.contains(PLAYER_BLOCK_POS_Z_PATH))
{
int x = toml.getIntOrElse(PLAYER_BLOCK_POS_X_PATH, 0);
int y = toml.getIntOrElse(PLAYER_BLOCK_POS_Y_PATH, 0);
int z = toml.getIntOrElse(PLAYER_BLOCK_POS_Z_PATH, 0);
this.playerBlockPos = new DHBlockPos(x, y, z);
}
else
{
this.playerBlockPos = new DHBlockPos(0, 0, 0);
try (CommentedFileConfig toml = CommentedFileConfig.builder(file).build()) {
toml.load();
// get the player block pos if it is specified
if (toml.contains(PLAYER_BLOCK_POS_X_PATH)
&& toml.contains(PLAYER_BLOCK_POS_Y_PATH)
&& toml.contains(PLAYER_BLOCK_POS_Z_PATH))
{
int x = toml.getIntOrElse(PLAYER_BLOCK_POS_X_PATH, 0);
int y = toml.getIntOrElse(PLAYER_BLOCK_POS_Y_PATH, 0);
int z = toml.getIntOrElse(PLAYER_BLOCK_POS_Z_PATH, 0);
this.playerBlockPos = new DHBlockPos(x, y, z);
}
else
{
this.playerBlockPos = new DHBlockPos(0, 0, 0);
}
}
}
@@ -98,10 +107,8 @@ public class PlayerData
/** Should be called often to make sure this object is up to date with the player's info */
public void updateData(IMinecraftClientWrapper mc)
{
if (mc.playerExists())
{
this.playerBlockPos = mc.getPlayerBlockPos();
}
this.playerBlockPos = mc.getPlayerBlockPos();
if (playerBlockPos == null) throw new RuntimeException("No player block pos!");
}
/** Writes everything from this object to the file given. */
@@ -31,4 +31,22 @@ public class DhLoggerBuilder
{
return LogManager.getLogger(ModInfo.NAME + "-" + className);
}
public static Logger getLogger(Class<?> clazz)
{
return LogManager.getLogger(ModInfo.NAME + "-" + clazz.getSimpleName());
}
public static Logger getLogger()
{
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
String callerClassName = "??";
for (int i=1; i<stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (!ste.getClassName().equals(DhLoggerBuilder.class.getName())
&& ste.getClassName().indexOf("java.lang.Thread")!=0) {
callerClassName = ste.getClassName();
break;
}
}
return LogManager.getLogger(ModInfo.NAME + "-" + callerClassName);
}
}
@@ -35,6 +35,7 @@ import com.seibel.lod.core.render.objects.GLState;
import com.seibel.lod.core.util.*;
import com.seibel.lod.core.util.gridList.*;
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.LogManager;
import org.lwjgl.opengl.GL32;
@@ -51,7 +52,6 @@ import com.seibel.lod.core.objects.opengl.RenderRegion;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
/**
* This is where all the magic happens. <br>
@@ -526,7 +526,7 @@ public class LodRenderer
// returns whether anything changed
private boolean updateVanillaRenderedChunks(LodDimension lodDim) {
// if the player is high enough, draw all LODs
IWorldWrapper world = MC.getWrappedClientWorld();
ILevelWrapper world = MC.getWrappedClientWorld();
if (lastUpdatedPos.getY() > world.getHeight()-world.getMinHeight() ||
Config.Client.Advanced.lodOnlyMode.get()) {
if (vanillaChunks != null) {
@@ -28,7 +28,7 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.logging.ConfigBasedLogger;
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
import com.seibel.lod.core.objects.DHBlockPos;
import com.seibel.lod.core.a7.DHLevel;
import com.seibel.lod.core.a7.level.DHLevel;
import com.seibel.lod.core.a7.render.RenderBufferHandler;
import com.seibel.lod.core.objects.math.Mat4f;
import com.seibel.lod.core.objects.math.Vec3d;
@@ -42,7 +42,7 @@ import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
/**
* This class holds methods and constants that may be used in multiple places.
@@ -165,15 +165,15 @@ public class LodUtil
* Gets the ServerWorld for the relevant dimension.
* @return null if there is no ServerWorld for the given dimension
*/
public static IWorldWrapper getServerWorldFromDimension(IDimensionTypeWrapper newDimension)
public static ILevelWrapper getServerWorldFromDimension(IDimensionTypeWrapper newDimension)
{
if(!MC.hasSinglePlayerServer())
return null;
Iterable<IWorldWrapper> worlds = MC.getAllServerWorlds();
IWorldWrapper returnWorld = null;
Iterable<ILevelWrapper> worlds = MC.getAllServerWorlds();
ILevelWrapper returnWorld = null;
for (IWorldWrapper world : worlds)
for (ILevelWrapper world : worlds)
{
if (world.getDimensionType() == newDimension)
{
@@ -200,7 +200,7 @@ public class LodUtil
* world, if in multiplayer it will return the server name, IP,
* and game version.
*/
public static String getWorldID(IWorldWrapper world)
public static String getWorldID(ILevelWrapper world)
{
if (MC.hasSinglePlayerServer())
{
@@ -229,14 +229,14 @@ public class LodUtil
* dimension.
*/
@Deprecated // FIXME: There are soooo many duplicated methods doing the same thing everywhere
public static String getDimensionIDFromWorld(IWorldWrapper world)
public static String getDimensionIDFromWorld(ILevelWrapper world)
{
if (MC.hasSinglePlayerServer())
{
// this will return the world save location
// and the dimension folder
IWorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(world.getDimensionType());
ILevelWrapper serverWorld = LodUtil.getServerWorldFromDimension(world.getDimensionType());
if (serverWorld == null)
throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the WorldWrapper for the dimension " + world.getDimensionType().getDimensionName());
@@ -21,10 +21,8 @@ package com.seibel.lod.core.wrapperInterfaces;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
import com.seibel.lod.core.objects.DHBlockPos;
import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
/**
@@ -36,5 +34,5 @@ import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenera
public interface IWrapperFactory extends IBindable
{
AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(LodBuilder newLodBuilder,
LodDimension newLodDimension, IWorldWrapper worldWrapper);
LodDimension newLodDimension, ILevelWrapper worldWrapper);
}
@@ -27,7 +27,7 @@ import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
import com.seibel.lod.core.objects.DHBlockPos;
import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
/**
* Contains everything related to the Minecraft object.
@@ -86,9 +86,9 @@ public interface IMinecraftClientWrapper extends IBindable
* the user is currently in.
* @return null if no ServerWorld is available
*/
IWorldWrapper getWrappedServerWorld();
ILevelWrapper getWrappedServerWorld();
IWorldWrapper getWrappedClientWorld();
ILevelWrapper getWrappedClientWorld();
File getGameDirectory();
@@ -101,7 +101,7 @@ public interface IMinecraftClientWrapper extends IBindable
int getPlayerSkylight();
/** Returns all worlds available to the server */
ArrayList<IWorldWrapper> getAllServerWorlds();
ArrayList<ILevelWrapper> getAllServerWorlds();
@@ -34,7 +34,7 @@ import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
/**
* Contains everything related to
@@ -105,7 +105,7 @@ public interface IMinecraftRenderWrapper extends IBindable
IWrapperFactory factory = SingletonHandler.get(IWrapperFactory.class);
IVersionConstants versionConstants = SingletonHandler.get(IVersionConstants.class);
IMinecraftClientWrapper minecraft = SingletonHandler.get(IMinecraftClientWrapper.class);
IWorldWrapper clientWorld = minecraft.getWrappedClientWorld();
ILevelWrapper clientWorld = minecraft.getWrappedClientWorld();
int chunkDist = this.getRenderDistance() + 1; // For some reason having '+1' is actually closer to real value
@@ -1,7 +1,12 @@
package com.seibel.lod.core.wrapperInterfaces.minecraft;
public interface IMinecraftSharedWrapper {
boolean isServerJar();
import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
import java.io.File;
//TODO: Maybe have IMCClientWrapper & IMCDedicatedWrapper extend this interface???
public interface IMinecraftSharedWrapper extends IBindable {
boolean isServerJar();
File getInstallationDirectory();
}
@@ -33,7 +33,7 @@ public interface IBiomeColorWrapperSingleton extends IBindable
{
IBiomeColorWrapperSingleton getInstance();
int getGrassColor(IWorldWrapper world, DHBlockPos blockPos);
int getWaterColor(IWorldWrapper world, DHBlockPos blockPos);
int getFoliageColor(IWorldWrapper world, DHBlockPos blockPos);
int getGrassColor(ILevelWrapper world, DHBlockPos blockPos);
int getWaterColor(ILevelWrapper world, DHBlockPos blockPos);
int getFoliageColor(ILevelWrapper world, DHBlockPos blockPos);
}
@@ -32,7 +32,7 @@ import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
* @author James Seibel
* @version 3-5-2022
*/
public interface IWorldWrapper extends IBindable
public interface ILevelWrapper extends IBindable
{
IDimensionTypeWrapper getDimensionType();
@@ -21,15 +21,15 @@ package com.seibel.lod.core.wrapperInterfaces.worldGeneration;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
public abstract class AbstractBatchGenerationEnvionmentWrapper {
public static enum Steps {
Empty, StructureStart, StructureReference, Biomes, Noise, Surface, Carvers, LiquidCarvers, Features, Light,
}
public AbstractBatchGenerationEnvionmentWrapper(IWorldWrapper serverLevel, LodBuilder lodBuilder,
LodDimension lodDim) {
public AbstractBatchGenerationEnvionmentWrapper(ILevelWrapper serverLevel, LodBuilder lodBuilder,
LodDimension lodDim) {
}
public abstract void resizeThreadPool(int newThreadCount);