Add/Fix issue with writeData and Cut causing data loss

This commit is contained in:
tom lee
2022-01-15 18:58:07 +08:00
parent 4c122512ac
commit 0c4de076ca
8 changed files with 83 additions and 81 deletions
@@ -23,6 +23,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.enums.config.HorizontalResolution;
import com.seibel.lod.core.objects.lod.LodDimension;
@@ -228,42 +229,35 @@ public class LodBuilder
if (MC.getWrappedClientWorld() == null)
return false;
// determine how many LODs to generate horizontally
byte minDetailLevel = region.getMinDetailLevel();
HorizontalResolution detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel);
// determine how many LODs to generate vertically
//VerticalQuality verticalQuality = LodConfig.CLIENT.graphics.qualityOption.verticalQuality.get();
byte detailLevel = detail.detailLevel;
// generate the LODs
int posX;
int posZ;
for (int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++)
{
startX = detail.startX[i];
startZ = detail.startZ[i];
region.isWriting++;
try {
LodRegion newRegion = lodDim.getRegionFromFile(region, (byte)0, region.getGenerationMode(), region.getVerticalQuality());
assert(region==newRegion);
long[] data;
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
//lodDim.clear(detailLevel, posX, posZ);
if (data != null && data.length != 0)
// generate the LODs
int posX;
int posZ;
for (int i = 0; i < 16*16; i++)
{
posX = LevelPosUtil.convert((byte) 0, chunk.getChunkPosX() * 16 + startX, minDetailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getChunkPosZ() * 16 + startZ, minDetailLevel);
long oldData = lodDim.getSingleData(minDetailLevel, posX, posZ);
if (override || !DataPointUtil.doesItExist(oldData) ||
DataPointUtil.getGenerationMode(oldData)<config.distanceGenerationMode.complexity) {
lodDim.addVerticalData(minDetailLevel, posX, posZ, data);
lodDim.updateData(minDetailLevel, posX, posZ);
startX = i/16;
startZ = i%16;
long[] data;
long[] dataToMergeVertical = createVerticalDataToMerge((byte)0, chunk, config, startX, startZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData((byte)0));
if (data != null && data.length != 0)
{
posX = chunk.getChunkPosX() * 16 + startX;
posZ = chunk.getChunkPosZ() * 16 + startZ;
if (region.addVerticalData((byte)0, posX, posZ, data, override))
region.updateArea((byte)0, posX, posZ);
}
}
} finally {
region.isWriting--;
}
return true;
//executeTime = System.currentTimeMillis() - executeTime;
@@ -271,12 +265,12 @@ public class LodBuilder
}
/** creates a vertical DataPoint */
private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunkWrapper chunk, LodBuilderConfig config, int startX, int startZ)
private long[] createVerticalDataToMerge(byte detail, IChunkWrapper chunk, LodBuilderConfig config, int startX, int startZ)
{
// equivalent to 2^detailLevel
int size = 1 << detail.detailLevel;
int size = 1 << detail;
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(detail.detailLevel);
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(detail);
int verticalData = DataPointUtil.WORLD_HEIGHT / 2 + 1;
int height;
int depth;
@@ -235,10 +235,11 @@ public class LodDimensionFileHandler
for (int j = 0; j < lodDimension.getWidth(); j++)
{
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
if (r != null && r.needSaving)
{
r.needSaving = false;
regionToSave.put(r.getRegionPos(), r);
}
}
@@ -288,10 +289,12 @@ public class LodDimensionFileHandler
// this for loop should be safe and loop until all values are gone.
while (!regionToSave.isEmpty()) {
for (LodRegion r : regionToSave.values()) {
//Check if the data has been swapped out right under me. Otherwise remove it from the entry
if (!regionToSave.remove(r.getRegionPos(), r)) continue;
try
{
r.isWriting++;
try {
if (r.isWriting>1) continue;
//Check if the data has been swapped out right under me. Otherwise remove it from the entry
if (!regionToSave.remove(r.getRegionPos(), r)) continue;
r.needSaving = false;
Instant i = Instant.now();
ClientApi.LOGGER.info("Lod: Saving Region "+r.getRegionPos());
saveRegionToFile(r);
@@ -302,6 +305,8 @@ public class LodDimensionFileHandler
catch (Exception e)
{
e.printStackTrace();
} finally {
r.isWriting--;
}
}
}
@@ -45,7 +45,7 @@ public interface LevelContainer
* @param posZ z position in the detail level
* @return true if correctly added, false otherwise
*/
boolean addVerticalData(long[] data, int posX, int posZ);
boolean addVerticalData(long[] data, int posX, int posZ, boolean override);
/**
* With this you can add data to the level container
@@ -354,19 +354,18 @@ public class LodDimension
int regionZ;
int minDistance;
byte detail;
byte minAllowedDetailLevel;
regionX = (x + center.x) - halfWidth;
regionZ = (z + center.z) - halfWidth;
LodRegion region = regions[x][z];
if (region != null) {
if (region != null && !region.needSaving && region.isWriting==0) {
// check what detail level this region should be
// and cut it if it is higher then that
minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ,
playerPosX, playerPosZ);
detail = DetailDistanceUtil.getTreeCutDetailFromDistance(minDistance);
minAllowedDetailLevel = DetailDistanceUtil.getCutLodDetail(detail);
if (region.getMinDetailLevel() < minAllowedDetailLevel) {
region.cutTree(minAllowedDetailLevel);
if (region.getMinDetailLevel() < detail) {
if (region.needSaving) return; // FIXME: A crude attempt at lowering chance of race condition!
region.cutTree(detail);
region.needRegenBuffer = 2;
regenDimensionBuffers = true;
}
@@ -408,6 +407,7 @@ public class LodDimension
regionZ = (z + center.z) - halfWidth;
final RegionPos regionPos = new RegionPos(regionX, regionZ);
region = regions[x][z];
if (region != null && region.isWriting!=0) return; // FIXME: A crude attempt at lowering chance of race condition!
minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX,
playerPosZ);
@@ -451,7 +451,7 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten.
*/
public Boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data)
public Boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data, boolean override)
{
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
@@ -461,10 +461,8 @@ public class LodDimension
if (region == null)
return false;
boolean nodeAdded = region.addVerticalData(detailLevel, posX, posZ, data);
boolean nodeAdded = region.addVerticalData(detailLevel, posX, posZ, data, override);
if (nodeAdded) {
region.needRegenBuffer = 2;
region.needSaving = true;
regenDimensionBuffers = true;
}
return nodeAdded;
@@ -575,22 +573,6 @@ public class LodDimension
return region.getSingleData(detailLevel, posX, posZ);
}
/** Clears the given region */
public void clear(byte detailLevel, int posX, int posZ)
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
int xRegion = LevelPosUtil.getRegion(detailLevel, posX);
int zRegion = LevelPosUtil.getRegion(detailLevel, posZ);
LodRegion region = getRegion(xRegion, zRegion);
if (region == null)
return;
region.clear(detailLevel, posX, posZ);
region.needRegenBuffer = 2;
regenDimensionBuffers = true;
}
/**
* Returns if the buffer at the given array index needs
* to have its buffer regenerated. Also decrease the state by 1
@@ -70,6 +70,7 @@ public class LodRegion {
public volatile int needRegenBuffer = 2;
public volatile boolean needSaving = false;
public volatile int isWriting = 0;
public LodRegion(byte minDetailLevel, RegionPos regionPos, DistanceGenerationMode generationMode,
VerticalQuality verticalQuality) {
@@ -94,6 +95,7 @@ public class LodRegion {
* @return true if the data was added successfully
*/
public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data) {
assert(isWriting!=0);
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
@@ -114,7 +116,8 @@ public class LodRegion {
*
* @return true if the data was added successfully
*/
public boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data) {
public boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data, boolean override) {
assert(isWriting!=0);
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
@@ -123,7 +126,12 @@ public class LodRegion {
if (this.dataContainer[detailLevel] == null)
return false;// this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
return this.dataContainer[detailLevel].addVerticalData(data, posX, posZ);
boolean updated = this.dataContainer[detailLevel].addVerticalData(data, posX, posZ, override);
if (updated) {
needRegenBuffer = 2;
needSaving = true;
}
return updated;
}
/**
@@ -150,15 +158,6 @@ public class LodRegion {
return dataContainer[detailLevel].getSingleData(posX, posZ);
}
/**
* Clears the datapoint at the given relative position
*/
public void clear(byte detailLevel, int posX, int posZ) {
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[detailLevel].clear(posX, posZ);
}
/**
* This method will fill the posToGenerate array with all levelPos that are
* render-able.
@@ -28,6 +28,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.LongBuffer;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.dataFormat.*;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.util.*;
@@ -92,10 +93,17 @@ public class VerticalLevelContainer implements LevelContainer
}
@Override
public boolean addVerticalData(long[] data, int posX, int posZ)
public boolean addVerticalData(long[] data, int posX, int posZ, boolean override)
{
int index = posX * size * verticalSize + posZ * verticalSize;
int compare = DataPointUtil.compareDatapointPriority(data[0], dataContainer[index]);
if (override) {
if (compare<0) return false;
} else {
if (compare<=0) return false;
}
for (int verticalIndex = 0; verticalIndex < verticalSize; verticalIndex++)
dataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = data[verticalIndex];
dataContainer[index + verticalIndex] = data[verticalIndex];
return true;
}
@@ -1131,7 +1139,7 @@ public class VerticalLevelContainer implements LevelContainer
}
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getVerticalSize());
addVerticalData(data, posX, posZ);
addVerticalData(data, posX, posZ, true);
}
public void newUpdateData(VerticalLevelContainer lowerLevelContainer, int posX, int posZ)
@@ -267,6 +267,18 @@ public class DataPointUtil
}
}
/** Return (>0) if dataA should replace dataB, (0) if equal, (<0) if dataB should replace dataA */
public static int compareDatapointPriority(long dataA, long dataB) {
if (dataA==0 || dataB==0) {
if (dataA!=0) dataA = Integer.MAX_VALUE;
if (dataB!=0) dataB = Integer.MAX_VALUE;
return (int)(dataA-dataB);
}
int genA = (int)getGenerationMode(dataA);
int genB = (int)getGenerationMode(dataB);
return genA-genB;
}
/**
* This method merge column of multiple data together
* @param dataToMerge one or more columns of data
@@ -44,7 +44,7 @@ public class DetailDistanceUtil
private static int minDetailDistance = (int) (MC_RENDER.getRenderDistance()*16 * 1.42f);
private static int maxDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * 16 * 2;
@Deprecated
private static final HorizontalResolution[] lodGenDetails = {
HorizontalResolution.BLOCK,
HorizontalResolution.TWO_BLOCKS,
@@ -150,6 +150,7 @@ public class DetailDistanceUtil
return detail;
}
@Deprecated
public static HorizontalResolution getLodGenDetail(int detail)
{
if (detail < minGenDetail)
@@ -158,7 +159,8 @@ public class DetailDistanceUtil
return lodGenDetails[detail];
}
@Deprecated
public static byte getCutLodDetail(int detail)
{
if (detail < minGenDetail)