Improve logging and potentially fix a few substring crashes
This commit is contained in:
@@ -27,6 +27,7 @@ import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.seibel.lod.core.handlers.LodDimensionFileHelper;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
@@ -100,11 +101,17 @@ public class ClientApi
|
||||
public boolean rendererDisabledBecauseOfExceptions = false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private ClientApi()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void flushSpamLoggersState() {
|
||||
synchronized(spamReducedLoggers) {
|
||||
spamReducedLoggers.removeIf((logger) -> logger.get()==null);
|
||||
@@ -158,9 +165,13 @@ public class ClientApi
|
||||
return;
|
||||
|
||||
IWorldWrapper world = MC.getWrappedClientWorld();
|
||||
if (world == null) return;
|
||||
if (world == null)
|
||||
return;
|
||||
LodDimension lodDim = ApiShared.lodWorld.getLodDimension(world.getDimensionType());
|
||||
|
||||
// Make sure the player's data is up-to-date
|
||||
LodDimensionFileHelper.updatePlayerData();
|
||||
|
||||
// Make the LodDim if it does not exist
|
||||
if (lodDim == null)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package com.seibel.lod.core.api;
|
||||
|
||||
import com.seibel.lod.core.api.ClientApi.LagSpikeCatcher;
|
||||
import com.seibel.lod.core.handlers.LodDimensionFileHelper;
|
||||
import com.seibel.lod.core.objects.opengl.builders.lodBuilding.LodBuilder;
|
||||
import com.seibel.lod.core.objects.opengl.builders.worldGeneration.BatchGenerator;
|
||||
import com.seibel.lod.core.enums.WorldType;
|
||||
@@ -59,6 +60,9 @@ public class EventApi
|
||||
*/
|
||||
private boolean recalculateWidths = false;
|
||||
|
||||
private boolean isCurrentlyOnSinglePlayerServer = false;
|
||||
|
||||
|
||||
private EventApi()
|
||||
{
|
||||
|
||||
@@ -113,8 +117,6 @@ public class EventApi
|
||||
ApiShared.lodWorld.saveAllDimensions(false); // Do an async save.
|
||||
}
|
||||
|
||||
private boolean isCurrentlyOnSinglePlayerServer = false;
|
||||
|
||||
/** This is also called when a new dimension loads */
|
||||
public void worldLoadEvent(IWorldWrapper world)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream;
|
||||
@@ -48,6 +49,8 @@ import com.seibel.lod.core.util.LodThreadFactory;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.SpamReducedLogger;
|
||||
import com.seibel.lod.core.util.UnitBytes;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/**
|
||||
@@ -61,6 +64,8 @@ import com.seibel.lod.core.util.UnitBytes;
|
||||
*/
|
||||
public class LodDimensionFileHandler
|
||||
{
|
||||
public static final Logger LOGGER = LogManager.getLogger("LodDimensionFileHandler");
|
||||
|
||||
public static final boolean ENABLE_SAVE_THREAD_LOGGING = true;
|
||||
public static final boolean ENABLE_SAVE_REGION_LOGGING = false;
|
||||
|
||||
@@ -147,26 +152,26 @@ public class LodDimensionFileHandler
|
||||
subFile.getName().equals(DistanceGenerationMode.BIOME_ONLY.toString()) ||
|
||||
subFile.getName().equals(DistanceGenerationMode.NONE.toString()))
|
||||
{
|
||||
ApiShared.LOGGER.info("Noticed old save structure files. Starting merge process...");
|
||||
LOGGER.info("Noticed old save structure files. Starting merge process...");
|
||||
LodDimensionOldFileStructureHandler oldFileStructHandler = new LodDimensionOldFileStructureHandler(this);
|
||||
if (mergeOldFileLock.tryLock())
|
||||
{
|
||||
// I got the lock to merge file.
|
||||
ApiShared.LOGGER.info("Updating VerticalQuality LOW...");
|
||||
LOGGER.info("Updating VerticalQuality LOW...");
|
||||
oldFileStructHandler.mergeOldFileStructureForVertQuality(VerticalQuality.LOW);
|
||||
ApiShared.LOGGER.info("Updating VerticalQuality MEDIUM...");
|
||||
LOGGER.info("Updating VerticalQuality MEDIUM...");
|
||||
oldFileStructHandler.mergeOldFileStructureForVertQuality(VerticalQuality.MEDIUM);
|
||||
ApiShared.LOGGER.info("Updating VerticalQuality HIGH...");
|
||||
LOGGER.info("Updating VerticalQuality HIGH...");
|
||||
oldFileStructHandler.mergeOldFileStructureForVertQuality(VerticalQuality.HIGH);
|
||||
ApiShared.LOGGER.info("Update completed.");
|
||||
LOGGER.info("Update completed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Someone is already doing it. I just need to wait until he is done.
|
||||
// Someone is already doing it. I just need to wait until they are done.
|
||||
mergeOldFileLock.lock();
|
||||
mergeOldFileLock.unlock();
|
||||
}
|
||||
ApiShared.LOGGER.info("Merge process completed.");
|
||||
LOGGER.info("Merge process completed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -238,7 +243,7 @@ public class LodDimensionFileHandler
|
||||
// close the reader and delete the file.
|
||||
inputStream.close();
|
||||
file.delete();
|
||||
ApiShared.LOGGER.info("Outdated LOD region file for region: (" + regionX + "," + regionZ + ")"
|
||||
LOGGER.info("Outdated LOD region file for region: (" + regionX + "," + regionZ + ")"
|
||||
+ " version found: " + fileVersion
|
||||
+ ", version requested: " + LOD_SAVE_FILE_VERSION
|
||||
+ ". File has been deleted.");
|
||||
@@ -251,7 +256,7 @@ public class LodDimensionFileHandler
|
||||
// close the reader and ignore the file, we don't
|
||||
// want to accidentally delete anything the user may want.
|
||||
inputStream.close();
|
||||
ApiShared.LOGGER.info("Newer LOD region file for region: (" + regionX + "," + regionZ + ")"
|
||||
LOGGER.info("Newer LOD region file for region: (" + regionX + "," + regionZ + ")"
|
||||
+ " version found: " + fileVersion
|
||||
+ ", version requested: " + LOD_SAVE_FILE_VERSION
|
||||
+ " this region will not be written to in order to protect the newer file.");
|
||||
@@ -260,7 +265,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
else if (fileVersion < LOD_SAVE_FILE_VERSION)
|
||||
{
|
||||
ApiShared.LOGGER.debug("Old LOD region file for region: (" + regionX + "," + regionZ + ")"
|
||||
LOGGER.debug("Old LOD region file for region: (" + regionX + "," + regionZ + ")"
|
||||
+ " version found: " + fileVersion
|
||||
+ ", version requested: " + LOD_SAVE_FILE_VERSION
|
||||
+ ". File will be loaded and updated to new format in next save.");
|
||||
@@ -283,7 +288,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException ioEx)
|
||||
{
|
||||
ApiShared.LOGGER.error("LOD file read error. Unable to read xz compressed file [" + file + "]: ", ioEx);
|
||||
LOGGER.error("LOD file read error. Unable to read xz compressed file [" + file + "]: ", ioEx);
|
||||
region.addLevelContainer(new VerticalLevelContainer(tempDetailLevel));
|
||||
}
|
||||
} // for each detail level
|
||||
@@ -303,7 +308,7 @@ public class LodDimensionFileHandler
|
||||
FILE_NAME_PREFIX + "." + posX + "." + posZ + FILE_EXTENSION);
|
||||
if (file.exists())
|
||||
{
|
||||
ApiShared.LOGGER.warn("LOD file write warn. Unable to write [" + file + "] because the newer version file already exist! Skipping this position...");
|
||||
LOGGER.warn("LOD file write warn. Unable to write [" + file + "] because the newer version file already exist! Skipping this position...");
|
||||
return;
|
||||
}
|
||||
if (!file.getParentFile().exists())
|
||||
@@ -314,7 +319,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.error("LOD file write error. Unable to create parent directory for [" + file + "]: ", e);
|
||||
LOGGER.error("LOD file write error. Unable to create parent directory for [" + file + "]: ", e);
|
||||
return;
|
||||
}
|
||||
try (FileOutputStream fileOutStream = new FileOutputStream(file))
|
||||
@@ -330,7 +335,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.error("LOD file write error. Unable to write to temp file [" + file + "]: ", e);
|
||||
LOGGER.error("LOD file write error. Unable to write to temp file [" + file + "]: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +372,7 @@ public class LodDimensionFileHandler
|
||||
LevelContainer[] container = r.debugGetDataContainers().clone();
|
||||
if (container == null || container.length != LodUtil.DETAIL_OPTIONS)
|
||||
{
|
||||
ApiShared.LOGGER.warn("DumpRamUsage encountered an invalid region!");
|
||||
LOGGER.warn("DumpRamUsage encountered an invalid region!");
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < LodUtil.DETAIL_OPTIONS; i++)
|
||||
@@ -395,6 +400,7 @@ public class LodDimensionFileHandler
|
||||
/** Save all dirty regions in this LodDimension to file */
|
||||
public void saveDirtyRegionsToFile(boolean blockUntilFinished)
|
||||
{
|
||||
// determine the regions to save
|
||||
for (int i = 0; i < lodDimension.getWidth(); i++)
|
||||
{
|
||||
for (int j = 0; j < lodDimension.getWidth(); j++)
|
||||
@@ -402,28 +408,34 @@ public class LodDimensionFileHandler
|
||||
LodRegion r = lodDimension.getRegionByArrayIndex(i, j);
|
||||
|
||||
// FIXME: Note that the isWriting is a crude attempt at syncing. It won't work.
|
||||
// It just reduce the chance of race condition
|
||||
// It just reduces the chance of a race condition
|
||||
if (r != null && r.needSaving)
|
||||
{
|
||||
regionToSave.put(r.getRegionPos(), r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save the dimension data
|
||||
LodDimensionFileHelper.saveDimensionPlayerData(this.dimensionDataSaveFolder);
|
||||
trySaveRegionsToBeSaved();
|
||||
|
||||
// wait for the saving to finish if requested
|
||||
if (blockUntilFinished)
|
||||
{
|
||||
if (ENABLE_SAVE_THREAD_LOGGING)
|
||||
ApiShared.LOGGER.info("Blocking until lod file save finishes!");
|
||||
LOGGER.info("Blocking until lod file save finishes!");
|
||||
|
||||
try
|
||||
{
|
||||
fileWritingThreadPool.shutdown();
|
||||
boolean worked = fileWritingThreadPool.awaitTermination(30, TimeUnit.SECONDS);
|
||||
if (!worked)
|
||||
ApiShared.LOGGER.error("File writing timed out! File data may not be saved correctly and may cause corruptions!!!");
|
||||
LOGGER.error("File writing timed out! File data may not be saved correctly and may cause corruptions!!!");
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
ApiShared.LOGGER.error("File writing wait is interrupted! File data may not be saved correctly and may cause corruptions!!!: ", e);
|
||||
LOGGER.error("File writing wait is interrupted! File data may not be saved correctly and may cause corruptions!!!: ", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -461,7 +473,7 @@ public class LodDimensionFileHandler
|
||||
throw new ConcurrentModificationException("WriterMain Triggered but the thead state is not started!?");
|
||||
|
||||
if (ENABLE_SAVE_THREAD_LOGGING)
|
||||
ApiShared.LOGGER.info("Lod File Writer started. To-be-written-regions: " + regionToSave.size());
|
||||
LOGGER.info("Lod File Writer started. To-be-written-regions: " + regionToSave.size());
|
||||
|
||||
Instant start = Instant.now();
|
||||
// Note: Since regionToSave is a ConcurrentHashMap, and the .values() return one that support concurrency,
|
||||
@@ -481,16 +493,16 @@ public class LodDimensionFileHandler
|
||||
r.needSaving = false;
|
||||
Instant i = Instant.now();
|
||||
if (ENABLE_SAVE_REGION_LOGGING)
|
||||
ApiShared.LOGGER.info("Lod: Saving Region " + r.getRegionPos());
|
||||
LOGGER.info("Lod: Saving Region " + r.getRegionPos());
|
||||
saveRegionToFile(r);
|
||||
Instant j = Instant.now();
|
||||
Duration d = Duration.between(i, j);
|
||||
if (ENABLE_SAVE_REGION_LOGGING)
|
||||
ApiShared.LOGGER.info("Lod: Region " + r.getRegionPos() + " save finish. Took " + d);
|
||||
LOGGER.info("Lod: Region " + r.getRegionPos() + " save finish. Took " + d);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ApiShared.LOGGER.error("Lod: UNCAUGHT exception when saving region " + r.getRegionPos() + ": ", e);
|
||||
LOGGER.error("Lod: UNCAUGHT exception when saving region " + r.getRegionPos() + ": ", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -501,7 +513,7 @@ public class LodDimensionFileHandler
|
||||
Instant end = Instant.now();
|
||||
|
||||
if (ENABLE_SAVE_THREAD_LOGGING)
|
||||
ApiShared.LOGGER.info("Lod File Writer completed. Took " + Duration.between(start, end));
|
||||
LOGGER.info("Lod File Writer completed. Took " + Duration.between(start, end));
|
||||
|
||||
// Use Memory order Release to release any memory changes on setting this boolean
|
||||
// (Corresponding call is the this::saveRegions(...)::...compareAndExchangeAcquire(false, true);)
|
||||
@@ -525,7 +537,7 @@ public class LodDimensionFileHandler
|
||||
// Get the old file
|
||||
File oldFile = getRegionFile(region.regionPosX, region.regionPosZ, detailLevel, region.getVerticalQuality());
|
||||
if (ENABLE_SAVE_REGION_LOGGING)
|
||||
ApiShared.LOGGER.debug("saving region [" + region.regionPosX + ", " + region.regionPosZ + "] detail " + detailLevel + " to file.");
|
||||
LOGGER.debug("saving region [" + region.regionPosX + ", " + region.regionPosZ + "] detail " + detailLevel + " to file.");
|
||||
|
||||
boolean isFileFullyGened = false;
|
||||
// make sure the file and folder exists
|
||||
@@ -542,7 +554,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.error("LOD file write error. Unable to create parent directory for [" + oldFile + "] error [" + e.getMessage() + "]: ");
|
||||
LOGGER.error("LOD file write error. Unable to create parent directory for [" + oldFile + "] error [" + e.getMessage() + "]: ");
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
@@ -564,7 +576,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.warn("LOD file write warning. Unable to read existing file [" + oldFile + "] version. Treating it as latest version. [" + e.getMessage() + "]: ");
|
||||
LOGGER.warn("LOD file write warning. Unable to read existing file [" + oldFile + "] version. Treating it as latest version. [" + e.getMessage() + "]: ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -598,7 +610,7 @@ public class LodDimensionFileHandler
|
||||
// existing file is complete while new one is only partially generate
|
||||
// this can happen is for some reason loading failed
|
||||
// this doesn't fix the bug, but at least protects old data
|
||||
ApiShared.LOGGER.error("LOD file write error. Attempted to overwrite complete region with incomplete one [" + oldFile + "]");
|
||||
LOGGER.error("LOD file write error. Attempted to overwrite complete region with incomplete one [" + oldFile + "]");
|
||||
try
|
||||
{
|
||||
tempFile.delete();
|
||||
@@ -612,7 +624,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.error("LOD file write error. Unable to write to temp file [" + tempFile + "]: ", e);
|
||||
LOGGER.error("LOD file write error. Unable to write to temp file [" + tempFile + "]: ", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -623,7 +635,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.error("LOD file write error. Unable to update file [" + oldFile + "]: ", e);
|
||||
LOGGER.error("LOD file write error. Unable to update file [" + oldFile + "]: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -645,7 +657,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.warn("Unable to get the base save file path. One possible cause is that"
|
||||
LOGGER.warn("Unable to get the base save file path. One possible cause is that"
|
||||
+ " the process failed to read the current path location due to security configs.");
|
||||
throw new RuntimeException("DistantHorizons Get Save File Path Failure");
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.seibel.lod.core.handlers;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
|
||||
import com.seibel.lod.core.objects.opengl.builders.lodBuilding.LodBuilder;
|
||||
import com.seibel.lod.core.objects.opengl.builders.lodBuilding.LodBuilderConfig;
|
||||
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
|
||||
import com.seibel.lod.core.enums.config.VerticalQuality;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
@@ -10,6 +11,8 @@ import com.seibel.lod.core.objects.lod.LodDimension;
|
||||
import com.seibel.lod.core.objects.lod.LodRegion;
|
||||
import com.seibel.lod.core.objects.lod.RegionPos;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||
@@ -30,9 +33,15 @@ public class LodDimensionFileHelper
|
||||
{
|
||||
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||
private static final IWrapperFactory FACTORY = SingletonHandler.get(IWrapperFactory.class);
|
||||
|
||||
/** Increasing this will increase accuracy but increase calculation time */
|
||||
private static final VerticalQuality VERTICAL_QUALITY_TO_TEST_WITH = VerticalQuality.LOW;
|
||||
private static final VerticalQuality VERTICAL_QUALITY_TO_TEST_WITH = VerticalQuality.MEDIUM;
|
||||
|
||||
|
||||
private static LodDimensionFileHelper.PlayerData PLAYER_DATA = new LodDimensionFileHelper.PlayerData(MC);
|
||||
private static LodDimensionFileHelper.PlayerData FIRST_SEEN_PLAYER_DATA = null;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,13 +51,21 @@ public class LodDimensionFileHelper
|
||||
* @return the new or existing folder for this dimension, null if there was a problem
|
||||
* @throws IOException if the folder doesn't exist or can't be accessed
|
||||
*/
|
||||
public static File determineSaveFolder() throws IOException
|
||||
public static File determineSubDimensionFolder() throws IOException
|
||||
{
|
||||
if (FIRST_SEEN_PLAYER_DATA == null)
|
||||
{
|
||||
FIRST_SEEN_PLAYER_DATA = PLAYER_DATA;
|
||||
PLAYER_DATA = new LodDimensionFileHelper.PlayerData(MC);
|
||||
}
|
||||
|
||||
|
||||
// relevant positions
|
||||
AbstractChunkPosWrapper playerChunkPos = MC.getPlayerChunkPos();
|
||||
AbstractChunkPosWrapper playerChunkPos = FACTORY.createChunkPos(FIRST_SEEN_PLAYER_DATA.playerBlockPos);
|
||||
int startingBlockPosX = playerChunkPos.getMinBlockX();
|
||||
int startingBlockPosZ = playerChunkPos.getMinBlockZ();
|
||||
RegionPos playerRegionPos = new RegionPos(MC.getPlayerChunkPos());
|
||||
RegionPos playerRegionPos = new RegionPos(playerChunkPos);
|
||||
|
||||
|
||||
// chunk from the newly loaded dimension
|
||||
IChunkWrapper newlyLoadedChunk = MC.getWrappedClientWorld().tryGetChunk(playerChunkPos);
|
||||
@@ -56,7 +73,7 @@ public class LodDimensionFileHelper
|
||||
if (!LodDimensionFileHelper.CanDetermineDimensionFolder(newlyLoadedChunk))
|
||||
return null;
|
||||
|
||||
// create a temporary dimension to store the new LOD
|
||||
// create a temporary dimension to store the test LOD
|
||||
LodDimension newlyLoadedDim = new LodDimension(MC.getCurrentDimension(), null, 1);
|
||||
newlyLoadedDim.move(playerRegionPos);
|
||||
newlyLoadedDim.regions.set(playerRegionPos.x, playerRegionPos.z, new LodRegion(LodUtil.BLOCK_DETAIL_LEVEL, playerRegionPos, VERTICAL_QUALITY_TO_TEST_WITH));
|
||||
@@ -66,6 +83,12 @@ public class LodDimensionFileHelper
|
||||
if (!lodGenerated)
|
||||
return null;
|
||||
|
||||
|
||||
// log the start of this attempt
|
||||
ApiShared.LOGGER.info("Attempting to determine sub-dimension for [" + MC.getCurrentDimension().getDimensionName() + "]");
|
||||
ApiShared.LOGGER.info("First seen player block pos in dimension: [" + FIRST_SEEN_PLAYER_DATA.playerBlockPos.getX() + "," + FIRST_SEEN_PLAYER_DATA.playerBlockPos.getY() + "," + FIRST_SEEN_PLAYER_DATA.playerBlockPos.getZ() + "]");
|
||||
|
||||
|
||||
// new chunk data
|
||||
long[][][] newChunkData = new long[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH][];
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
@@ -77,9 +100,6 @@ public class LodDimensionFileHelper
|
||||
}
|
||||
}
|
||||
boolean newChunkHasData = isDataEmpty(newChunkData);
|
||||
// String message = "new chunk data " + (newChunkHasData ? newChunkData[0][0][0] : "[NULL]");
|
||||
// MC.sendChatMessage(message);
|
||||
// ApiShared.LOGGER.info(message);
|
||||
|
||||
// check if the chunk is actually empty
|
||||
if (!newChunkHasData)
|
||||
@@ -88,16 +108,16 @@ public class LodDimensionFileHelper
|
||||
{
|
||||
// the chunk isn't empty but the LOD is...
|
||||
|
||||
// String message = "Error: the chunk at (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") has a height of [" + newlyLoadedChunk.getHeight() + "] but the LOD generated is empty!";
|
||||
// MC.sendChatMessage(message);
|
||||
// ApiShared.LOGGER.info(message);
|
||||
String message = "Error: the chunk at (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") has a height of [" + newlyLoadedChunk.getHeight() + "] but the LOD generated is empty!";
|
||||
MC.sendChatMessage(message);
|
||||
ApiShared.LOGGER.error(message);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// String message = "The chunk at (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") is empty.";
|
||||
String message = "Warning: The chunk at (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") is empty.";
|
||||
// MC.sendChatMessage(message);
|
||||
// ApiShared.LOGGER.info(message);
|
||||
ApiShared.LOGGER.warn(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,21 +134,23 @@ public class LodDimensionFileHelper
|
||||
// create the directory since it doesn't exist
|
||||
dimensionFolder.mkdirs();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move any old files if they exist
|
||||
|
||||
|
||||
|
||||
// compare each world with the newly loaded one
|
||||
File mostSimilarWorldFolder = null;
|
||||
int mostEqualLines = 0;
|
||||
boolean oneDimensionIsValid = false;
|
||||
double highestEqualityPercent = 0.0;
|
||||
double minimumSimilarityRequired = CONFIG.client().multiplayer().getMultiDimensionRequiredSimilarity();
|
||||
|
||||
ApiShared.LOGGER.info("Known Sub Dimensions: [" + dimensionFolder.listFiles().length + "]");
|
||||
for (File testDimFolder : dimensionFolder.listFiles())
|
||||
{
|
||||
ApiShared.LOGGER.info("Testing sub dimension: [" + LodUtil.shortenString(testDimFolder.getName(), 8) + "]");
|
||||
|
||||
// get a LOD from this dimension folder
|
||||
LodDimension tempLodDim = new LodDimension(null, null, 1);
|
||||
tempLodDim.move(playerRegionPos);
|
||||
@@ -145,15 +167,28 @@ public class LodDimensionFileHelper
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get the player data for this dimension folder
|
||||
PlayerData testPlayerData = new PlayerData(testDimFolder);
|
||||
ApiShared.LOGGER.info("Last known player pos: [" + testPlayerData.playerBlockPos.getX() + "," + testPlayerData.playerBlockPos.getY() + "," + testPlayerData.playerBlockPos.getZ() + "]");
|
||||
|
||||
// check if the block positions are close
|
||||
int distance = testPlayerData.playerBlockPos.getManhattanDistance(FIRST_SEEN_PLAYER_DATA.playerBlockPos);
|
||||
ApiShared.LOGGER.info("Player block position distance between saved sub dimension and first seen is [" + distance + "]");
|
||||
// if (distance <= 2) // TODO make this number a config
|
||||
// {
|
||||
// // TODO do something with this information
|
||||
// }
|
||||
|
||||
|
||||
// check if the chunk is actually empty
|
||||
if (!isDataEmpty(newChunkData))
|
||||
{
|
||||
// String message = "The test chunk for dimension folder [" + testDimFolder.getName() + "] and chunk pos (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") is empty. Is that correct?";
|
||||
String message = "The test chunk for dimension folder [" + LodUtil.shortenString(testDimFolder.getName(), 8) + "] and chunk pos (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") is empty. Is that correct?";
|
||||
// MC.sendChatMessage(message);
|
||||
// ApiShared.LOGGER.info(message);
|
||||
ApiShared.LOGGER.info(message);
|
||||
continue;
|
||||
}
|
||||
oneDimensionIsValid = true;
|
||||
|
||||
|
||||
// compare the two LODs
|
||||
@@ -177,28 +212,31 @@ public class LodDimensionFileHelper
|
||||
|
||||
// determine if this world is closer to the newly loaded world
|
||||
double percentEqual = (double) equalLines / (double) totalLineCount;
|
||||
if (equalLines > mostEqualLines && percentEqual >= minimumSimilarityRequired)
|
||||
if (equalLines > mostEqualLines)
|
||||
{
|
||||
mostEqualLines = equalLines;
|
||||
mostSimilarWorldFolder = testDimFolder;
|
||||
highestEqualityPercent = percentEqual;
|
||||
|
||||
if (percentEqual >= minimumSimilarityRequired)
|
||||
{
|
||||
mostSimilarWorldFolder = testDimFolder;
|
||||
}
|
||||
}
|
||||
// String message = "test data [" + testDimFolder.getName().substring(0, 6) + "...] " + testChunkData[0][0][0] + " equal lines: " + equalLines + "/" + totalLineCount + " = " + percentEqual;
|
||||
// MC.sendChatMessage(message);
|
||||
// ApiShared.LOGGER.info(message);
|
||||
String message = "Sub dimension [" + LodUtil.shortenString(testDimFolder.getName(), 8) + "...] is current dimension probability: " + LodUtil.shortenString(percentEqual + "", 5) + " (" + equalLines + "/" + totalLineCount + ")";
|
||||
MC.sendChatMessage(message);
|
||||
ApiShared.LOGGER.info(message);
|
||||
}
|
||||
|
||||
|
||||
if (!oneDimensionIsValid && dimensionFolder.listFiles().length != 0)
|
||||
// all the world folders were empty, and there was at least one world folder that we tested
|
||||
return null;
|
||||
// the first seen player data is no longer needed, the sub dimension has been determined
|
||||
FIRST_SEEN_PLAYER_DATA = null;
|
||||
|
||||
|
||||
if (mostSimilarWorldFolder != null)
|
||||
{
|
||||
// we found a world folder that is similar, use it
|
||||
|
||||
String message = "Dimension folder set to: [" + mostSimilarWorldFolder.getName().substring(0, 8) + "...]";
|
||||
// MC.sendChatMessage(message);
|
||||
String message = "Sub Dimension set to: [" + LodUtil.shortenString(mostSimilarWorldFolder.getName(), 8) + "...] with an equality of [" + highestEqualityPercent + "]";
|
||||
MC.sendChatMessage(message);
|
||||
ApiShared.LOGGER.info(message);
|
||||
return mostSimilarWorldFolder;
|
||||
}
|
||||
@@ -207,8 +245,8 @@ public class LodDimensionFileHelper
|
||||
// no world folder was found, create a new one
|
||||
|
||||
String newId = UUID.randomUUID().toString();
|
||||
String message = "No dimension folder found. Creating a new one with ID: " + newId.substring(0, 8) + "...";
|
||||
// MC.sendChatMessage(message);
|
||||
String message = "No suitable sub dimension found. The highest equality was [" + highestEqualityPercent + "]. Creating a new sub dimension with ID: " + LodUtil.shortenString(newId, 8) + "...";
|
||||
MC.sendChatMessage(message);
|
||||
ApiShared.LOGGER.info(message);
|
||||
return GetDimensionFolder(newlyLoadedDim.dimension, newId);
|
||||
}
|
||||
@@ -276,4 +314,144 @@ public class LodDimensionFileHelper
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static final String playerDataFileName = "_playerData.toml";
|
||||
|
||||
private static PlayerData getPlayerData(File worldFolder)
|
||||
{
|
||||
File file = PlayerData.getFileForDimensionFolder(worldFolder);
|
||||
if (!file.exists())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
CommentedFileConfig toml = CommentedFileConfig.builder(file).build();
|
||||
toml.add("path", "test");
|
||||
toml.save();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void updatePlayerData()
|
||||
{
|
||||
PLAYER_DATA.updateData(MC);
|
||||
}
|
||||
|
||||
/** saves any necessary player data to the given world folder */
|
||||
public static void saveDimensionPlayerData(File worldFolder)
|
||||
{
|
||||
// get and create the file and path if they don't exist
|
||||
File file = PlayerData.getFileForDimensionFolder(worldFolder);
|
||||
if (!file.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ApiShared.LOGGER.error("Unable to save player dimension data for world folder [" + worldFolder.getPath() + "].", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// determine the playerData
|
||||
IMinecraftClientWrapper mc = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
PlayerData playerdata = new PlayerData(mc);
|
||||
|
||||
// write the data to file
|
||||
CommentedFileConfig toml = CommentedFileConfig.builder(file).build();
|
||||
playerdata.toTomlFile(toml);
|
||||
}
|
||||
|
||||
|
||||
/** Data container for any player data we can use to differentiate one dimension from another. */
|
||||
private static class PlayerData
|
||||
{
|
||||
public static final IWrapperFactory FACTORY = SingletonHandler.get(IWrapperFactory.class);
|
||||
|
||||
public static final String PLAYER_BLOCK_POS_X_PATH = "playerBlockPosX";
|
||||
public static final String PLAYER_BLOCK_POS_Y_PATH = "playerBlockPosY";
|
||||
public static final String PLAYER_BLOCK_POS_Z_PATH = "playerBlockPosZ";
|
||||
AbstractBlockPosWrapper playerBlockPos;
|
||||
|
||||
// not implemented yet
|
||||
public static final String WORLD_SPAWN_POS_X_PATH = "worldSpawnBlockPosX";
|
||||
public static final String WORLD_SPAWN_POS_Y_PATH = "worldSpawnBlockPosY";
|
||||
public static final String WORLD_SPAWN_POS_Z_PATH = "worldSpawnBlockPosZ";
|
||||
/**
|
||||
* The client world has access to a spawn point, so this should be possible to fill in.
|
||||
* I'm not sure what this will look like for worlds that don't have a spawn point.
|
||||
*/
|
||||
AbstractBlockPosWrapper worldSpawnPointBlockPos;
|
||||
|
||||
|
||||
|
||||
public PlayerData(IMinecraftClientWrapper mc)
|
||||
{
|
||||
updateData(mc);
|
||||
}
|
||||
|
||||
public PlayerData(File dimensionFolder)
|
||||
{
|
||||
File file = getFileForDimensionFolder(dimensionFolder);
|
||||
CommentedFileConfig toml = CommentedFileConfig.builder(file).build();
|
||||
|
||||
// player block pos
|
||||
try
|
||||
{
|
||||
toml.load();
|
||||
|
||||
// TODO this is crashing...
|
||||
int x = toml.getInt(PLAYER_BLOCK_POS_X_PATH);
|
||||
int y = toml.getInt(PLAYER_BLOCK_POS_Y_PATH);
|
||||
int z = toml.getInt(PLAYER_BLOCK_POS_Z_PATH);
|
||||
this.playerBlockPos = FACTORY.createBlockPos(x, y, z);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
ApiShared.LOGGER.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static File getFileForDimensionFolder(File file)
|
||||
{
|
||||
return new File(file.getPath() + File.separatorChar + playerDataFileName);
|
||||
}
|
||||
|
||||
|
||||
/** */
|
||||
public void updateData(IMinecraftClientWrapper mc)
|
||||
{
|
||||
this.playerBlockPos = mc.getPlayerBlockPos();
|
||||
}
|
||||
|
||||
/** Writes everything from this object to the file given. */
|
||||
public void toTomlFile(CommentedFileConfig toml)
|
||||
{
|
||||
// player block pos
|
||||
toml.add(PLAYER_BLOCK_POS_X_PATH, playerBlockPos.getX());
|
||||
toml.add(PLAYER_BLOCK_POS_Y_PATH, playerBlockPos.getY());
|
||||
toml.add(PLAYER_BLOCK_POS_Z_PATH, playerBlockPos.getZ());
|
||||
|
||||
|
||||
toml.save();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "PlayerBlockPos: [" + playerBlockPos.getX() + "," + playerBlockPos.getY() + "," + playerBlockPos.getZ() + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,12 +131,12 @@ public class LodDimension
|
||||
|
||||
|
||||
// run asynchronously since this could take a while
|
||||
new Thread(() ->
|
||||
Thread thread =new Thread(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
// attempt to get the file handler
|
||||
File saveDir = LodDimensionFileHelper.determineSaveFolder();
|
||||
File saveDir = LodDimensionFileHelper.determineSubDimensionFolder();
|
||||
if (saveDir == null)
|
||||
return;
|
||||
|
||||
@@ -155,7 +155,9 @@ public class LodDimension
|
||||
// make sure we unlock this method
|
||||
this.determiningWorldFolder = false;
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
thread.setName("Sub-Dimension-Finder");
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -414,4 +414,22 @@ public class LodUtil
|
||||
public static void checkInterruptsUnchecked() {
|
||||
if (Thread.interrupted()) throw new RuntimeException(new InterruptedException());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a shortened version of the given string that is no longer than maxLength. <br>
|
||||
* If null returns the empty string.
|
||||
*/
|
||||
public static String shortenString(String str, int maxLength)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return str.substring(0, Math.min(str.length(), maxLength));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,4 +45,10 @@ public abstract class AbstractBlockPosWrapper
|
||||
|
||||
/** returns itself */
|
||||
public abstract AbstractBlockPosWrapper offset(int x, int y, int z);
|
||||
|
||||
|
||||
public int getManhattanDistance(AbstractBlockPosWrapper otherPos)
|
||||
{
|
||||
return Math.abs(this.getX() - otherPos.getX()) + Math.abs(this.getY() - otherPos.getY()) + Math.abs(this.getZ() - otherPos.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user