diff --git a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java
index 830ae7230..3c1362425 100644
--- a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java
+++ b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java
@@ -192,8 +192,8 @@ public class LodDimensionFileHandler
+ " version found: " + fileVersion
+ ", version requested: " + LOD_SAVE_FILE_VERSION
+ ". File was been deleted.");
-
- break;
+ // This should not break, but be continue to see whether other versions can be loaded or updated
+ continue;
}
else if (fileVersion > LOD_SAVE_FILE_VERSION)
{
@@ -205,26 +205,21 @@ public class LodDimensionFileHandler
+ " version found: " + fileVersion
+ ", version requested: " + LOD_SAVE_FILE_VERSION
+ " this region will not be written to in order to protect the newer file.");
-
- break;
+ // This should not break, but be continue to see whether other versions can be loaded or updated
+ continue;
}
else if (fileVersion < LOD_SAVE_FILE_VERSION)
{
- //this is old, but readable version
- byte[] data = ThreadMapUtil.getSaveContainer(tempDetailLevel);
- inputStream.read(data);
+ // this is old, but readable version
+ // read and add the data to our region
+ region.addLevelContainer(new VerticalLevelContainer(new DataInputStream(inputStream), fileVersion));
inputStream.close();
- // add the data to our region
- region.addLevelContainer(new VerticalLevelContainer(data, fileVersion));
} else
{
// this file is a readable version,
- // read the file
- byte[] data = ThreadMapUtil.getSaveContainer(tempDetailLevel);
- inputStream.read(data);
+ // read and add the data to our region
+ region.addLevelContainer(new VerticalLevelContainer(new DataInputStream(inputStream), LOD_SAVE_FILE_VERSION));
inputStream.close();
- // add the data to our region
- region.addLevelContainer(new VerticalLevelContainer(data, LOD_SAVE_FILE_VERSION));
}
}
catch (IOException ioEx)
@@ -305,10 +300,11 @@ public class LodDimensionFileHandler
}
File oldFile = new File(fileName);
//ClientProxy.LOGGER.info("saving region [" + region.regionPosX + ", " + region.regionPosZ + "] to file.");
- byte[] temp = region.getLevel(detailLevel).toDataString();
+ //byte[] temp = region.getLevel(detailLevel).toDataString();
try
{
+ boolean isFileFullyGened = false;
// make sure the file and folder exists
if (!oldFile.exists())
{
@@ -325,12 +321,11 @@ public class LodDimensionFileHandler
// (to make sure we don't overwrite a newer
// version file if it exists)
int fileVersion = LOD_SAVE_FILE_VERSION;
- int isFull = 0;
try (XZCompressorInputStream inputStream = new XZCompressorInputStream(new FileInputStream(oldFile)))
{
fileVersion = inputStream.read();
inputStream.skip(1);
- isFull = inputStream.read() & 0b10000000;
+ isFileFullyGened = (inputStream.read() & 0b10000000) != 0;
inputStream.close();
}
catch (IOException ex)
@@ -344,15 +339,7 @@ public class LodDimensionFileHandler
// the file we are reading is a newer version,
// don't write anything, we don't want to accidentally
// delete anything the user may want.
- return;
- }
- if ((temp[1] & 0b10000000) != 0b10000000 && isFull == 0b10000000)
- {
- // 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
- ClientApi.LOGGER.error("LOD file write error. Attempted to overwrite complete region with incomplete one [" + fileName + "]");
- return;
+ continue;
}
// if we got this far then we are good
// to overwrite the old file
@@ -365,9 +352,23 @@ public class LodDimensionFileHandler
outputStream.write(LOD_SAVE_FILE_VERSION);
// add each LodChunk to the file
- outputStream.write(temp);
+ boolean isLocalFullyGened = region.getLevel(detailLevel).writeData(new DataOutputStream(outputStream));
outputStream.close();
+ if (!isLocalFullyGened && isFileFullyGened)
+ {
+ // 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
+ ClientApi.LOGGER.error("LOD file write error. Attempted to overwrite complete region with incomplete one [" + fileName + "]");
+ try {
+ newFile.delete();
+ } catch (SecurityException e) {
+ // Failed to delete temp file... just continue.
+ }
+ continue;
+ }
+
// overwrite the old file with the new one
Files.move(newFile.toPath(), oldFile.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
}
@@ -384,73 +385,10 @@ public class LodDimensionFileHandler
}
}
-
- public void saveRegionFile (byte[] regionFile, RegionPos regionPos, DistanceGenerationMode generationMode, byte detailLevel, VerticalQuality verticalQuality)
- {
- int regionX = regionPos.x;
- int regionZ = regionPos.z;
- String fileName = getFileNameAndPathForRegion(regionX, regionZ, generationMode, detailLevel, verticalQuality);
-
- if (fileName != null)
- {
- File oldFile = new File(fileName);
- File newFile = new File(fileName + TMP_FILE_EXTENSION);
- try (OutputStream os = new FileOutputStream(newFile))
- {
- os.write(regionFile);
- Files.move(newFile.toPath(), oldFile.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
- os.close();
- }
- catch (IOException ioEx)
- {
- ClientApi.LOGGER.error("LOD file write error. Unable to write to [" + fileName + "] error [" + ioEx.getMessage() + "]: ");
- ioEx.printStackTrace();
- }
- }
- }
-
- public byte[] getRegionFile (RegionPos regionPos, DistanceGenerationMode generationMode, byte detailLevel, VerticalQuality verticalQuality)
- {
- int regionX = regionPos.x;
- int regionZ = regionPos.z;
- String fileName = getFileNameAndPathForRegion(regionX, regionZ, generationMode, detailLevel, verticalQuality);
- if (fileName != null)
- {
- File file = new File(fileName);
- try (InputStream is = new FileInputStream(file))
- {
- byte[] data = ThreadMapUtil.getSaveContainer(detailLevel);
- is.read(data);
- is.close();
- return Arrays.copyOf(data, (int) file.length());
- }
- catch (IOException ioEx)
- {
- ClientApi.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + ioEx.getMessage() + "]: ");
- ioEx.printStackTrace();
- }
- }
- return new byte[0];
- }
-
-
//================//
// helper methods //
//================//
- public int getHashFromFile(RegionPos regionPos, DistanceGenerationMode generationMode, byte detailLevel, VerticalQuality verticalQuality)
- {
- int regionX = regionPos.x;
- int regionZ = regionPos.z;
- String fileName = getFileNameAndPathForRegion(regionX, regionZ, generationMode, detailLevel, verticalQuality);
- if (fileName == null)
- return 0;
-
- File file = new File(fileName);
- return file.hashCode();
- }
-
-
/**
* Return the name of the file that should contain the
* region at the given x and z.
@@ -476,7 +414,8 @@ public class LodDimensionFileHandler
}
catch (IOException | SecurityException e)
{
- ClientApi.LOGGER.warn("Unable to get the filename for the region [" + regionX + ", " + regionZ + "], error: [" + e.getMessage() + "], stacktrace: ");
+ ClientApi.LOGGER.warn("Unable to get the filename for the region [" + regionX + ", " + regionZ + "], error: [" + e.getMessage() + "].\n"
+ + "One possible cause is that the process failed to read the current path location due to security config. Stacktrace: ");
e.printStackTrace();
return null;
}
diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java b/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java
index 84f965589..59e809b82 100644
--- a/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java
+++ b/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java
@@ -19,6 +19,10 @@
package com.seibel.lod.core.objects.lod;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
/**
* A level container is a quad tree level
*/
@@ -99,13 +103,15 @@ public interface LevelContainer
* @param posZ z position in the detail level to update
*/
void updateData(LevelContainer lowerLevelContainer, int posX, int posZ);
-
+
/**
- * This will give the data to save in the file
- * @return data as a String
+ * This will write the raw data without metadata to the output stream
+ * @return isAllGenerated whether the data is all generated
+ * @throws IOException
*/
- byte[] toDataString();
-
+ default boolean writeData(DataOutputStream output) throws IOException {
+ throw new UnsupportedOperationException();
+ }
/**
* This will give the data to save in the file
diff --git a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java
index eba985ea0..3d1fb9844 100644
--- a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java
+++ b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java
@@ -19,6 +19,12 @@
package com.seibel.lod.core.objects.lod;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
import com.seibel.lod.core.dataFormat.*;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.util.*;
@@ -165,6 +171,122 @@ public class VerticalLevelContainer implements LevelContainer
return DataPointUtil.doesItExist(getSingleData(posX, posZ));
}
+ private long[] readDataVersion6(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
+ int x = size * size * tempMaxVerticalData;
+ long[] tempDataContainer = new long[x];
+ for (int i = 0; i < tempDataContainer.length; i++)
+ {
+ long newData = Long.reverseBytes(inputData.readLong());
+ newData = DataPointUtil.createDataPoint(
+ DataPointUtil.getAlpha(newData),
+ DataPointUtil.getRed(newData),
+ DataPointUtil.getGreen(newData),
+ DataPointUtil.getBlue(newData),
+ DataPointUtil.getHeight(newData) - minHeight,
+ DataPointUtil.getDepth(newData) - minHeight,
+ DataPointUtil.getLightSky(newData),
+ DataPointUtil.getLightBlock(newData),
+ DataPointUtil.getGenerationMode(newData),
+ DataPointUtil.getFlag(newData));
+
+ tempDataContainer[i] = newData;
+ }
+ return tempDataContainer;
+ }
+ private long[] readDataVersion7(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
+ int x = size * size * tempMaxVerticalData;
+ long[] tempDataContainer = new long[x];
+ for (int i = 0; i < tempDataContainer.length; i++)
+ {
+ long newData = Long.reverseBytes(inputData.readLong());
+ newData = DataPointUtil.createDataPoint(
+ DataPointUtil.getAlpha(newData),
+ DataPointUtil.getRed(newData),
+ DataPointUtil.getGreen(newData),
+ DataPointUtil.getBlue(newData),
+ DataPointUtil.getHeight(newData) - 64 - minHeight,
+ DataPointUtil.getDepth(newData) - 64 - minHeight,
+ DataPointUtil.getLightSky(newData),
+ DataPointUtil.getLightBlock(newData),
+ DataPointUtil.getGenerationMode(newData),
+ DataPointUtil.getFlag(newData));
+ tempDataContainer[i] = newData;
+ }
+ return tempDataContainer;
+ }
+
+ private long[] readDataVersion8(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
+ int x = size * size * tempMaxVerticalData;
+ long[] tempDataContainer = new long[x];
+ short tempMinHeight = Short.reverseBytes(inputData.readShort());
+ if (tempMinHeight != minHeight) {
+ for (int i = 0; i < tempDataContainer.length; i++) {
+ long newData = Long.reverseBytes(inputData.readLong());
+ newData = DataPointUtil.createDataPoint(
+ DataPointUtil.getAlpha(newData),
+ DataPointUtil.getRed(newData),
+ DataPointUtil.getGreen(newData),
+ DataPointUtil.getBlue(newData),
+ DataPointUtil.getHeight(newData) + tempMinHeight - minHeight,
+ DataPointUtil.getDepth(newData) + tempMinHeight - minHeight,
+ DataPointUtil.getLightSky(newData),
+ DataPointUtil.getLightBlock(newData),
+ DataPointUtil.getGenerationMode(newData),
+ DataPointUtil.getFlag(newData));
+ tempDataContainer[i] = newData;
+ }
+ } else {
+ for (int i = 0; i < tempDataContainer.length; i++) {
+ tempDataContainer[i] = Long.reverseBytes(inputData.readLong());
+ }
+ }
+ return tempDataContainer;
+ }
+
+ public VerticalLevelContainer(DataInputStream inputData, int version) throws IOException {
+ minHeight = SingletonHandler.get(IMinecraftWrapper.class).getWrappedClientWorld().getMinHeight();
+ detailLevel = inputData.readByte();
+ size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
+ int fileMaxVerticalData = inputData.readByte() & 0b01111111;
+ long[] tempDataContainer = null;
+
+ switch (version) {
+ case 6:
+ tempDataContainer = readDataVersion6(inputData, fileMaxVerticalData);
+ break;
+ case 7:
+ tempDataContainer = readDataVersion7(inputData, fileMaxVerticalData);
+ break;
+ case 8:
+ tempDataContainer = readDataVersion8(inputData, fileMaxVerticalData);
+ break;
+ default:
+ assert false;
+ }
+
+ int targetMaxVerticalData = DetailDistanceUtil.getMaxVerticalData(detailLevel);
+ if (fileMaxVerticalData > targetMaxVerticalData)
+ {
+ long[] dataToMerge = new long[fileMaxVerticalData];
+ long[] tempDataContainer2 = new long[size * size * targetMaxVerticalData];
+ for (int i = 0; i < size * size; i++)
+ {
+ System.arraycopy(tempDataContainer, i * fileMaxVerticalData, dataToMerge, 0, fileMaxVerticalData);
+ dataToMerge = DataPointUtil.mergeMultiData(dataToMerge, fileMaxVerticalData, targetMaxVerticalData);
+ System.arraycopy(dataToMerge, 0, tempDataContainer2, i * targetMaxVerticalData, targetMaxVerticalData);
+ }
+ verticalSize = targetMaxVerticalData;
+ this.dataContainer = tempDataContainer2;
+ }
+ else
+ {
+ verticalSize = fileMaxVerticalData;
+ this.dataContainer = tempDataContainer;
+ }
+ }
+
+ // Deprecated. Please use the DataInputStream version.
+ @Deprecated
public VerticalLevelContainer(byte[] inputData, int version)
{
minHeight = SingletonHandler.get(IMinecraftWrapper.class).getWrappedClientWorld().getMinHeight();
@@ -1062,40 +1184,24 @@ public class VerticalLevelContainer implements LevelContainer
}
@Override
- public byte[] toDataString()
- {
- int index = 0;
- int x = size * size;
- int tempIndex;
- long current;
+ public boolean writeData(DataOutputStream output) throws IOException {
+ output.writeByte(detailLevel);
+ output.writeByte((byte) verticalSize);
+ output.writeByte((byte) (minHeight & 0xFF));
+ output.writeByte((byte) ((minHeight >> 8) & 0xFF));
boolean allGenerated = true;
- byte[] tempData = ThreadMapUtil.getSaveContainer(detailLevel);
-
- tempData[index] = detailLevel;
- index++;
- tempData[index] = (byte) verticalSize;
- index++;
- tempData[index] = (byte) (minHeight & 0xFF);
- index++;
- tempData[index] = (byte) ((minHeight >> 8) & 0xFF);
- index++;
-
- int j;
+ int x = size * size;
for (int i = 0; i < x; i++)
{
- for (j = 0; j < verticalSize; j++)
+ for (int j = 0; j < verticalSize; j++)
{
- current = dataContainer[i * verticalSize + j];
- for (tempIndex = 0; tempIndex < 8; tempIndex++)
- tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex));
- index += 8;
+ long current = dataContainer[i * verticalSize + j];
+ output.writeLong(Long.reverseBytes(current));
}
if (!DataPointUtil.doesItExist(dataContainer[i]))
allGenerated = false;
}
- if (allGenerated)
- tempData[1] |= 0b10000000;
- return tempData;
+ return allGenerated;
}
@Override
diff --git a/src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java b/src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java
index f2bc10781..9c2012f6c 100644
--- a/src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java
+++ b/src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java
@@ -42,7 +42,6 @@ public class ThreadMapUtil
public static final ConcurrentMap threadBuilderArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap threadBuilderVerticalArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap threadVerticalAddDataMap = new ConcurrentHashMap<>();
- public static final ConcurrentMap saveContainer = new ConcurrentHashMap<>();
public static final ConcurrentMap projectionArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap heightAndDepthMap = new ConcurrentHashMap<>();
public static final ConcurrentMap singleDataToMergeMap = new ConcurrentHashMap<>();
@@ -136,25 +135,6 @@ public class ThreadMapUtil
return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel];
}
- /** returns the array NOT cleared every time */
- public static byte[] getSaveContainer(int detailLevel)
- {
- if (!saveContainer.containsKey(Thread.currentThread().getName()) || (saveContainer.get(Thread.currentThread().getName()) == null))
- {
- byte[][] array = new byte[LodUtil.DETAIL_OPTIONS][];
- int size = 1;
- for (int i = LodUtil.DETAIL_OPTIONS - 1; i >= 0; i--)
- {
- array[i] = new byte[4 + 8 * size * size * DetailDistanceUtil.getMaxVerticalData(i)];
- size = size << 1;
- }
- saveContainer.put(Thread.currentThread().getName(), array);
- }
- //Arrays.fill(threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel], 0);
- return saveContainer.get(Thread.currentThread().getName())[detailLevel];
- }
-
-
/** returns the array filled with 0's */
public static long[] getVerticalDataArray(int arrayLength)
{
@@ -209,7 +189,6 @@ public class ThreadMapUtil
threadBuilderArrayMap.clear();
threadBuilderVerticalArrayMap.clear();
threadVerticalAddDataMap.clear();
- saveContainer.clear();
projectionArrayMap.clear();
heightAndDepthMap.clear();
singleDataToMergeMap.clear();