Fix bunches of bugs. Quad tree ticks! Gen call is fired! Chunk gen works! Next to fix: File updates
This commit is contained in:
@@ -2,12 +2,15 @@ package com.seibel.lod.core.a7.datatype.transform;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.full.ChunkSizedData;
|
||||
import com.seibel.lod.core.a7.datatype.full.FullFormat;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
|
||||
public class LodDataBuilder {
|
||||
private static final IBlockStateWrapper AIR = SingletonInjector.INSTANCE.get(IWrapperFactory.class).getAirBlockStateWrapper();
|
||||
public static ChunkSizedData createChunkData(IChunkWrapper chunk) {
|
||||
if (!canGenerateLodFromChunk(chunk)) return null;
|
||||
|
||||
@@ -18,7 +21,7 @@ public class LodDataBuilder {
|
||||
LongArrayList longs = new LongArrayList(chunk.getHeight()/4);
|
||||
int lastY = chunk.getMaxBuildHeight();
|
||||
IBiomeWrapper biome = chunk.getBiome(x, lastY, z);
|
||||
IBlockStateWrapper blockState = IBlockStateWrapper.AIR;
|
||||
IBlockStateWrapper blockState = AIR;
|
||||
int mappedId = chunkData.getMapping().setAndGetId(biome, blockState);
|
||||
byte light = (byte) (chunk.getBlockLight(x,lastY,z) << 4 + chunk.getSkyLight(x,lastY,z));
|
||||
int y=chunk.getMaxY(x, z);
|
||||
@@ -42,7 +45,8 @@ public class LodDataBuilder {
|
||||
}
|
||||
}
|
||||
longs.add(FullFormat.encode(mappedId, lastY-y+1, y+1, light));
|
||||
chunkData.setSingleColumn(longs.toArray((long[]) null), x, z);
|
||||
|
||||
chunkData.setSingleColumn(longs.toArray(new long[0]), x, z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class GenerationQueue implements PlaceHolderQueue {
|
||||
@@ -29,7 +30,7 @@ public class GenerationQueue implements PlaceHolderQueue {
|
||||
}
|
||||
|
||||
public void track(PlaceHolderRenderSource source) {
|
||||
logger.info("Tracking source {} at {}", source, source.getSectionPos());
|
||||
//logger.info("Tracking source {} at {}", source, source.getSectionPos());
|
||||
trackers.put(source.getSectionPos(), new WeakReference<>(source));
|
||||
}
|
||||
|
||||
@@ -108,25 +109,31 @@ public class GenerationQueue implements PlaceHolderQueue {
|
||||
assert count > 0;
|
||||
assert granularity >= 4; // Thanks compiler. Guess having a 'always true' warning means I did it right.
|
||||
logger.info("Generating section {} of size {} with granularity {} at {}", pos, count, granularity, chunkPosMin);
|
||||
|
||||
//FIXME: Handle size != 1 case
|
||||
CompletableFuture<ArrayGridList<ChunkSizedData>> dataFuture = generator.generate(chunkPosMin, granularity);
|
||||
|
||||
dataFuture.whenComplete((data, ex) -> {
|
||||
if (ex != null) {
|
||||
logger.error("Error generating data for section " + pos + ": " + ex);
|
||||
if (ex instanceof CompletionException) {
|
||||
ex = ex.getCause();
|
||||
}
|
||||
logger.error("Error generating data for section {}", pos, ex);
|
||||
return;
|
||||
}
|
||||
assert data != null;
|
||||
if (data.gridSize != count) {
|
||||
logger.error("Generated data grid size (" + data.gridSize
|
||||
+ ") does not match expected size (" + count + ") for section " + pos);
|
||||
return;
|
||||
}
|
||||
if (data.gridSize < (1 << (granularity-4)))
|
||||
throw new IllegalStateException("Generator returned chunks of size "
|
||||
+ data.gridSize + " but requested granularity was " + granularity
|
||||
+ " (equals to chunks of : " + (1 << (granularity-4)) + ") @ " + chunkPosMin);
|
||||
|
||||
final byte sectionDetail = (byte) (dataDetail + FullDataSource.SECTION_SIZE_OFFSET);
|
||||
data.forEachPos((x,z) -> {
|
||||
ChunkSizedData chunkData = data.get(x,z);
|
||||
DhLodPos chunkDataPos = new DhLodPos((byte) (dataDetail + 4), x, z).convertUpwardsTo(sectionDetail);
|
||||
DhSectionPos sectionPos = new DhSectionPos(chunkDataPos.detail, chunkDataPos.x, chunkDataPos.z);
|
||||
logger.info("Writing chunk {} with data detail {} to section {}",
|
||||
new DHChunkPos(x+chunkPosMin.x,z+chunkPosMin.z),
|
||||
dataDetail, sectionPos);
|
||||
write(sectionPos, chunkData);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ public class DhLodPos {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "DhLodPos(" + detail + ", " + x + ", " + z + ")";
|
||||
return "[" + detail + "*" + x + "," + z + "]";
|
||||
}
|
||||
|
||||
public DhLodUnit getX() {
|
||||
|
||||
@@ -35,7 +35,7 @@ public class DhSectionPos {
|
||||
return new DhLodUnit(sectionDetail, 1 << offset);
|
||||
}
|
||||
public DhLodPos getCenter() {
|
||||
return getCenter((byte) (sectionDetail-1));
|
||||
return getCenter((byte)0);
|
||||
}
|
||||
public DhLodPos getCorner() {
|
||||
return getCorner((byte) (sectionDetail-1));
|
||||
@@ -49,7 +49,7 @@ public class DhSectionPos {
|
||||
if (sectionDetail <= 0) throw new IllegalStateException("section detail must be greater than 0");
|
||||
return new DhSectionPos((byte) (sectionDetail - 1),
|
||||
sectionX * 2 + (child0to3 & 1),
|
||||
sectionZ * 2 + (child0to3 & 2) / 2);
|
||||
sectionZ * 2 + ((child0to3 & 2) >> 1));
|
||||
}
|
||||
|
||||
public void forEachChild(Consumer<DhSectionPos> callback){
|
||||
@@ -59,7 +59,7 @@ public class DhSectionPos {
|
||||
}
|
||||
|
||||
public DhSectionPos getParent(){
|
||||
return new DhSectionPos((byte) (sectionDetail + 1), sectionX / 2, sectionZ / 2);
|
||||
return new DhSectionPos((byte) (sectionDetail + 1), sectionX >> 1, sectionZ >> 1);
|
||||
}
|
||||
|
||||
public DhSectionPos getAdjacent(ELodDirection dir) {
|
||||
@@ -79,10 +79,9 @@ public class DhSectionPos {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DhSectionPos{" +
|
||||
"sectionDetail=" + sectionDetail +
|
||||
", sectionX=" + sectionX +
|
||||
", sectionZ=" + sectionZ +
|
||||
return "{" + sectionDetail +
|
||||
"*" + sectionX +
|
||||
"," + sectionZ +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
@@ -30,6 +31,7 @@ public class LodQuadTree {
|
||||
* by implementing different abstract methods
|
||||
*/
|
||||
private static final byte LAYER_BEGINNING_OFFSET = ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
private static final boolean SUPER_VERBOSE_LOGGING = false;
|
||||
public final byte getLayerDataDetailOffset(byte sectionDetail) {
|
||||
return ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
}
|
||||
@@ -59,6 +61,7 @@ public class LodQuadTree {
|
||||
* @param initialPlayerZ player z coordinate
|
||||
*/
|
||||
public LodQuadTree(IClientLevel level, int viewDistance, int initialPlayerX, int initialPlayerZ, IRenderSourceProvider provider) {
|
||||
DetailDistanceUtil.updateSettings(); //TODO: Move this to somewhere else
|
||||
this.level = level;
|
||||
renderSourceProvider = provider;
|
||||
this.viewDistance = viewDistance;
|
||||
@@ -71,13 +74,22 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
{ // Construct the ringLists
|
||||
LOGGER.info("Creating ringLists with player center at {}", new Pos2D(initialPlayerX, initialPlayerZ));
|
||||
for (byte i = LAYER_BEGINNING_OFFSET; i < numbersOfSectionLevels; i++) {
|
||||
byte targetDataDetail = getLayerDataDetail(i);
|
||||
int maxDist = getFurthestDistance(targetDataDetail);
|
||||
int halfSize = LodUtil.ceilDiv(maxDist, (1 << i)) + 1;
|
||||
LOGGER.info("Creating ringList {} with size {}", i, halfSize*2+1);
|
||||
int halfSize = LodUtil.ceilDiv(maxDist, (1 << i)) + 2; // +2 to make sure the section is fully contained in the ringList
|
||||
{
|
||||
DhSectionPos checkerPos = new DhSectionPos(i, halfSize, halfSize);
|
||||
byte checkedDetail = calculateExpectedDetailLevel(new DhBlockPos2D(initialPlayerX, initialPlayerZ),checkerPos);
|
||||
LodUtil.assertTrue(checkedDetail > targetDataDetail,
|
||||
"in {}, getFuthestDistance return {} which would be contained in range {}, but calculateExpectedDetailLevel at {} is {} <= {}",
|
||||
i, maxDist, halfSize - 2, checkerPos, checkedDetail, targetDataDetail);
|
||||
}
|
||||
LOGGER.info("ringlist centered in {} with halfSize {} (maxDist {}, dataDetail {})", new Pos2D(initialPlayerX >> i, initialPlayerZ >> i), halfSize, maxDist, targetDataDetail);
|
||||
ringLists[i - LAYER_BEGINNING_OFFSET] = new MovableGridRingList<>(halfSize,
|
||||
initialPlayerX >> i, initialPlayerZ >> i);
|
||||
LOGGER.info("Creating ringList {}: {}", i, ringLists[i - LAYER_BEGINNING_OFFSET].toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,7 +171,8 @@ public class LodQuadTree {
|
||||
* @return the furthest distance to the center, in blocks
|
||||
*/
|
||||
public int getFurthestDistance(byte detailLevel) {
|
||||
return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel));
|
||||
return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel + 1));
|
||||
// +1 because that's the border to the next detail level, and we want to include up to it.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +194,28 @@ public class LodQuadTree {
|
||||
public LodRenderSection getChildSection(DhSectionPos pos, int child0to3) {
|
||||
return getSection(pos.getChild(child0to3));
|
||||
}
|
||||
|
||||
|
||||
private LodRenderSection _set(MovableGridRingList<LodRenderSection> list, int x, int z, LodRenderSection t) {
|
||||
LodUtil.assertTrue(t != null, "setting null at [{},{}] in {}", x, z, list.toString());
|
||||
LodUtil.assertTrue(t.pos.sectionX == x && t.pos.sectionZ == z, "pos {} != [{},{}] in {}", t.pos, x, z, list.toString());
|
||||
LodRenderSection s = list.setChained(x,z,t);
|
||||
LodUtil.assertTrue(s != null, "returned null at [{},{}]: {}", x, z, list.toString());
|
||||
LodUtil.assertTrue(s == t,"{} != {} in {}",s,t, list.toString());
|
||||
return s;
|
||||
}
|
||||
private LodRenderSection _getNotNull(MovableGridRingList<LodRenderSection> list, int x, int z) {
|
||||
LodUtil.assertTrue(list.inRange(x,z), "[{},{}] not in range of {}", x, z, list.toString());
|
||||
LodRenderSection s = list.get(x,z);
|
||||
LodUtil.assertTrue(s != null, "getting null at [{},{}] in {}", x, z, list.toString());
|
||||
LodUtil.assertTrue(s.pos.sectionX == x && s.pos.sectionZ == z, "obj {} != [{},{}] in {}", s, x, z, list.toString());
|
||||
return s;
|
||||
}
|
||||
private LodRenderSection _get(MovableGridRingList<LodRenderSection> list, int x, int z) {
|
||||
LodRenderSection s = list.get(x,z);
|
||||
LodUtil.assertTrue(s == null || (s.pos.sectionX == x && s.pos.sectionZ == z), "obj {} != [{},{}] in {}", s, x, z, list.toString());
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function update the quadTree based on the playerPos and the current game configs (static and global)
|
||||
* @param playerPos the reference position for the player
|
||||
@@ -207,7 +241,7 @@ public class LodQuadTree {
|
||||
// - set childCount to 0
|
||||
// If section != null && child != 0: //TODO: Should I move this createChild steps to Second tick pass?
|
||||
// - // Section will be in the unloaded state.
|
||||
// - create parent if it doesn't exist, with childCount = 1
|
||||
// - create parent if not at final level and if it doesn't exist, with childCount = 1
|
||||
// - for each child:
|
||||
// - if null, create new with childCount = 0 (force load due to neighboring issues)
|
||||
// - else if childCount == -1, set childCount = 0 (rescue it)
|
||||
@@ -241,71 +275,77 @@ public class LodQuadTree {
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (f_sectLevel == LAYER_BEGINNING_OFFSET && section != null) {
|
||||
section.childCount = 0;
|
||||
//LOGGER.info("sect {} in first layer with non-null. Reset childCount", section.pos);
|
||||
}
|
||||
if (section != null && section.childCount != 0) {
|
||||
// Section will be in the unloaded state.
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodRenderSection(section.pos.getParent()));
|
||||
LodUtil.assertTrue(parent != null, "tried to set section at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList);
|
||||
parent.childCount++;
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} has child", section.pos);
|
||||
if (parentRingList != null) {
|
||||
LodRenderSection parent = _get(parentRingList, pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing parent. Creating at {}", section.pos, section.pos.getParent());
|
||||
parent = _set(parentRingList, pos.x >> 1, pos.y >> 1, new LodRenderSection(section.pos.getParent()));
|
||||
parent.childCount++;
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} childs.", section.pos.getParent(), parent.childCount);
|
||||
}
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
}
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
DhSectionPos childPos = section.pos.getChild(i);
|
||||
LodUtil.assertTrue(childRingList != null);
|
||||
LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
LodRenderSection child = _get(childRingList, childPos.sectionX, childPos.sectionZ);
|
||||
if (child == null) {
|
||||
child = childRingList.setChained(childPos.sectionX, childPos.sectionZ,
|
||||
new LodRenderSection(childPos));
|
||||
LodUtil.assertTrue(child != null, "tried to set section at " + childPos.sectionX + "," + childPos.sectionZ + ", list is " + childRingList);
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing child at {}. Creating.", section.pos, childPos);
|
||||
child = _set(childRingList, childPos.sectionX, childPos.sectionZ, new LodRenderSection(childPos));
|
||||
child.childCount = 0;
|
||||
} else if (child.childCount == -1) {
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} rescued child at {}.", section.pos, childPos);
|
||||
child.childCount = 0;
|
||||
}
|
||||
}
|
||||
section.childCount = 4;
|
||||
} else {
|
||||
DhSectionPos sectPos = section != null ? section.pos : new DhSectionPos(f_sectLevel, pos.x, pos.y);
|
||||
final DhSectionPos sectPos = section != null ? section.pos : new DhSectionPos(f_sectLevel, pos.x, pos.y);
|
||||
LodUtil.assertTrue(sectPos.sectionDetail == f_sectLevel
|
||||
&& sectPos.sectionX == pos.x && sectPos.sectionZ == pos.y,
|
||||
"sectPos: " + sectPos + ", pos: " + pos + ", sectLevel: " + f_sectLevel);
|
||||
"sectPos {} != {} @ {}", sectPos, pos, f_sectLevel);
|
||||
|
||||
byte targetLevel = calculateExpectedDetailLevel(playerPos, sectPos);
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("0 child sect {}(null?{}) - target:{}/{} (parent:{})", sectPos, section == null,
|
||||
targetLevel, getLayerDataDetail(f_sectLevel),
|
||||
f_sectLevel == numbersOfSectionLevels-1 ? "N/A" : getLayerDataDetail((byte) (f_sectLevel+1)));
|
||||
if (f_sectLevel == numbersOfSectionLevels -1) {
|
||||
// Section is in the top level.
|
||||
if (targetLevel > getLayerDataDetail(f_sectLevel) && section != null) {
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} in top & target>current. Mark as free.", sectPos);
|
||||
section.childCount = -1;
|
||||
}
|
||||
if (targetLevel <= getLayerDataDetail(f_sectLevel) && section == null) {
|
||||
section = ringList.setChained(pos.x, pos.y,
|
||||
new LodRenderSection(sectPos));
|
||||
LodUtil.assertTrue(section != null, "tried to set section at " + pos.x + "," + pos.y +", list is " + ringList);
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("null sect {} in top & target<=current. Creating.", sectPos);
|
||||
section = _set(ringList, pos.x, pos.y, new LodRenderSection(sectPos));
|
||||
}
|
||||
} else {
|
||||
// Section is not the top level. So we also need to consider the parent.
|
||||
if (targetLevel >= getLayerDataDetail((byte) (f_sectLevel+1)) && section != null) {
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} target>=nextLevel. Mark as free.", sectPos);
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodUtil.assertTrue(parent != null, "fail to get parent setion at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList);
|
||||
LodRenderSection parent = _getNotNull(parentRingList, pos.x >> 1, pos.y >> 1);
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
parent.childCount--;
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} child.", sectPos, parent.childCount);
|
||||
section.childCount = -1;
|
||||
}
|
||||
if (targetLevel < getLayerDataDetail((byte) (f_sectLevel+1)) && section == null) {
|
||||
section = ringList.setChained(pos.x, pos.y,
|
||||
new LodRenderSection(sectPos));
|
||||
LodUtil.assertTrue(section != null, "tried to set section at " + pos.x + "," + pos.y +", list is " + ringList);
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("null sect {} target<nextLevel. Creating.", sectPos);
|
||||
section = _set(ringList, pos.x, pos.y, new LodRenderSection(sectPos));
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodRenderSection parent = _get(parentRingList, pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodRenderSection(sectPos.getParent()));
|
||||
LodUtil.assertTrue(parent != null, "tried to set section at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList);
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing parent. Creating at {}", sectPos, sectPos.getParent());
|
||||
parent = _set(parentRingList, pos.x >> 1, pos.y >> 1, new LodRenderSection(sectPos.getParent()));
|
||||
}
|
||||
parent.childCount++;
|
||||
if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} childs.", sectPos.getParent(), parent.childCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,21 +402,6 @@ public class LodQuadTree {
|
||||
section.childCount = 4;
|
||||
}
|
||||
|
||||
// Assertion steps
|
||||
LodUtil.assertTrue(section.childCount == 4 || section.childCount == 0 || section.childCount == -1);
|
||||
if (section.childCount == 4) LodUtil.assertTrue(
|
||||
getChildSection(section.pos, 0) != null &&
|
||||
getChildSection(section.pos, 1) != null &&
|
||||
getChildSection(section.pos, 2) != null &&
|
||||
getChildSection(section.pos, 3) != null);
|
||||
if (section.childCount == 0) LodUtil.assertTrue(
|
||||
getChildSection(section.pos, 0) == null &&
|
||||
getChildSection(section.pos, 1) == null &&
|
||||
getChildSection(section.pos, 2) == null &&
|
||||
getChildSection(section.pos, 3) == null);
|
||||
if (section.childCount == -1) LodUtil.assertTrue(
|
||||
getParentSection(section.pos).childCount == 0);
|
||||
|
||||
// Call load on new sections, and tick on existing ones, and dispose old sections
|
||||
if (section.childCount == -1) {
|
||||
ringList.set(pos.x, pos.y, null);
|
||||
@@ -387,10 +412,26 @@ public class LodQuadTree {
|
||||
} else if (section.isOutdated()) {
|
||||
section.reload(renderSourceProvider);
|
||||
}
|
||||
if (section.childCount == 4) section.enableRender(level, this);
|
||||
if (section.childCount == 0) section.disableRender();
|
||||
if (section.childCount == 4) section.disableRender();
|
||||
if (section.childCount == 0) section.enableRender(level, this);
|
||||
section.tick(this);
|
||||
}
|
||||
|
||||
// Assertion steps
|
||||
LodUtil.assertTrue(section.childCount == 4 || section.childCount == 0 || section.childCount == -1);
|
||||
if (section.pos.sectionDetail == LAYER_BEGINNING_OFFSET) LodUtil.assertTrue(section.childCount == 0);
|
||||
if (section.childCount == 4) LodUtil.assertTrue(
|
||||
getChildSection(section.pos, 0) != null &&
|
||||
getChildSection(section.pos, 1) != null &&
|
||||
getChildSection(section.pos, 2) != null &&
|
||||
getChildSection(section.pos, 3) != null);
|
||||
if (section.childCount == 0 && section.pos.sectionDetail > LAYER_BEGINNING_OFFSET) LodUtil.assertTrue(
|
||||
getChildSection(section.pos, 0) == null &&
|
||||
getChildSection(section.pos, 1) == null &&
|
||||
getChildSection(section.pos, 2) == null &&
|
||||
getChildSection(section.pos, 3) == null);
|
||||
if (section.childCount == -1 && section.pos.sectionDetail < numbersOfSectionLevels-1) LodUtil.assertTrue(
|
||||
getParentSection(section.pos).childCount == 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,11 @@ public class LodRenderSection {
|
||||
return lodRenderSource != null;
|
||||
}
|
||||
|
||||
//FIXME: Used by RenderBufferHandler
|
||||
public int FIXME_BYPASS_DONT_USE_getChildCount() {
|
||||
return childCount;
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
return loadFuture != null;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class RenderBufferHandler {
|
||||
class RenderBufferNode implements AutoCloseable {
|
||||
public final DhSectionPos pos;
|
||||
public volatile RenderBufferNode[] children = null;
|
||||
public AtomicReference<RenderBuffer> renderBufferSlot = null;
|
||||
public final AtomicReference<RenderBuffer> renderBufferSlot = new AtomicReference<>();
|
||||
|
||||
public RenderBufferNode(DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
@@ -63,7 +63,8 @@ public class RenderBufferHandler {
|
||||
// Update children's render buffer state
|
||||
// TODO: Improve this! (Checking section.isLoaded() as if its not loaded, it can only be because
|
||||
// it has children. (But this logic is... really hard to read!)
|
||||
boolean shouldHaveChildren = !section.isLoaded();
|
||||
// FIXME: Above comment is COMPLETELY WRONG! I am an idiot!
|
||||
boolean shouldHaveChildren = section.FIXME_BYPASS_DONT_USE_getChildCount() > 0;
|
||||
if (shouldHaveChildren) {
|
||||
if (children == null) {
|
||||
RenderBufferNode[] childs = new RenderBufferNode[4];
|
||||
|
||||
@@ -37,11 +37,13 @@ public class RenderMetaFile extends MetaFile {
|
||||
// Not sure if it will cause issues or not.
|
||||
public void updateChunkIfNeeded(ChunkSizedData chunkData) {
|
||||
CompletableFuture<LodRenderSource> source = _readCached(data.get());
|
||||
if (source == null) return;
|
||||
if (source.isDone()) source.join().update(chunkData);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> flushAndSave(ExecutorService renderCacheThread) {
|
||||
CompletableFuture<LodRenderSource> source = _readCached(data.get());
|
||||
if (source == null) return CompletableFuture.completedFuture(null);
|
||||
return source.thenAccept((a)->{});
|
||||
//TODO: Should we save the data or let user re-calculate it on new load?
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
package com.seibel.lod.core.util;
|
||||
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class EventLoop { //FIXME This should have close. We are leaking stuff.
|
||||
private final boolean PAUSE_ON_ERROR = ModInfo.IS_DEV_BUILD;
|
||||
private final Logger logger = DhLoggerBuilder.getLogger();
|
||||
private final ExecutorService executorService;
|
||||
private final Runnable runnable;
|
||||
private CompletableFuture<Void> future;
|
||||
private boolean isRunning = true;
|
||||
public EventLoop(ExecutorService executorService, Runnable runnable) {
|
||||
this.executorService = executorService;
|
||||
this.runnable = runnable;
|
||||
@@ -19,11 +23,15 @@ public class EventLoop { //FIXME This should have close. We are leaking stuff.
|
||||
if (future != null && future.isDone()) {
|
||||
try {
|
||||
future.join();
|
||||
} catch (CompletionException ce) {
|
||||
logger.error("Uncaught exception in event loop", ce.getCause());
|
||||
if (PAUSE_ON_ERROR) isRunning = false;
|
||||
} catch (Exception e) {
|
||||
logger.error("Uncaught exception in event loop", e);
|
||||
logger.error("Exception in event loop", e);
|
||||
if (PAUSE_ON_ERROR) isRunning = false;
|
||||
} finally {future = null;}
|
||||
}
|
||||
if (future == null) {
|
||||
if (future == null && isRunning) {
|
||||
future = CompletableFuture.runAsync(runnable, executorService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.enums.config.EServerFolderNameMode;
|
||||
import com.seibel.lod.core.enums.config.EVanillaOverdraw;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.objects.DHChunkPos;
|
||||
import com.seibel.lod.core.objects.ParsedIp;
|
||||
import com.seibel.lod.core.objects.Pos2D;
|
||||
@@ -39,6 +40,9 @@ 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.ILevelWrapper;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.Message;
|
||||
|
||||
/**
|
||||
* This class holds methods and constants that may be used in multiple places.
|
||||
@@ -50,6 +54,7 @@ public class LodUtil
|
||||
{
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
/**
|
||||
* Vanilla render distances less than or equal to this will not allow partial
|
||||
@@ -419,7 +424,20 @@ public class LodUtil
|
||||
public static void checkInterruptsUnchecked() {
|
||||
if (Thread.interrupted()) throw new RuntimeException(new InterruptedException());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format a given string with params using log4j's MessageFormat
|
||||
*
|
||||
* @apiNote <b>This 'format' SHOULD ONLY be used for logging and debugging purposes!
|
||||
* Do not use it for deserialization or naming of objects.</b>
|
||||
* @param str The string to format
|
||||
* @param param The parameters to use in the string
|
||||
* @return A message object. Call .toString() to get the string.
|
||||
* @author leetom
|
||||
*/
|
||||
public static String formatLog(String str, Object... param) {
|
||||
return LOGGER.getMessageFactory().newMessage(str, param).getFormattedMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shortened version of the given string that is no longer than maxLength. <br>
|
||||
@@ -441,14 +459,20 @@ public class LodUtil
|
||||
if (!condition) throw new RuntimeException("Assertion failed");
|
||||
}
|
||||
public static void assertTrue(boolean condition, String message) {
|
||||
if (!condition) throw new RuntimeException("Assertion failed: " + message);
|
||||
if (!condition) throw new RuntimeException("Assertion failed:\n " + message);
|
||||
}
|
||||
public static void assertNotReach(String message) {
|
||||
throw new RuntimeException("Assert Not Reach failed: " + message);
|
||||
public static void assertTrue(boolean condition, String message, Object... args) {
|
||||
if (!condition) throw new RuntimeException("Assertion failed:\n " + formatLog(message, args));
|
||||
}
|
||||
public static void assertNotReach() {
|
||||
throw new RuntimeException("Assert Not Reach failed");
|
||||
}
|
||||
public static void assertNotReach(String message) {
|
||||
throw new RuntimeException("Assert Not Reach failed:\n " + message);
|
||||
}
|
||||
public static void assertNotReach(String message, Object... args) {
|
||||
throw new RuntimeException("Assert Not Reach failed:\n " + formatLog(message, args));
|
||||
}
|
||||
public static ExecutorService makeSingleThreadPool(String name, int relativePriority) {
|
||||
return Executors.newSingleThreadExecutor(new LodThreadFactory(name, Thread.NORM_PRIORITY+relativePriority));
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.function.Consumer;
|
||||
|
||||
public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
|
||||
private AtomicReference<Pos2D> pos = new AtomicReference<Pos2D>();
|
||||
private final AtomicReference<Pos2D> pos = new AtomicReference<>();
|
||||
|
||||
private final int halfSize;
|
||||
private final int size;
|
||||
@@ -329,7 +329,7 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
@Override
|
||||
public String toString() {
|
||||
Pos2D p = pos.get();
|
||||
return "MovabeGridRingList[" + p.x+halfSize + "," + p.y+halfSize + "] " + size + "*" + size + "[" + size() + "]";
|
||||
return "MovabeGridRingList[" + (p.x+halfSize) + "," + (p.y+halfSize) + "] " + size + "*" + size + "[" + size() + "]";
|
||||
}
|
||||
|
||||
public String toDetailString() {
|
||||
|
||||
@@ -36,4 +36,5 @@ public interface IWrapperFactory extends IBindable
|
||||
AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(ILevel targetLevel);
|
||||
IBiomeWrapper deserializeBiomeWrapper(String str);
|
||||
IBlockStateWrapper deserializeBlockStateWrapper(String str);
|
||||
IBlockStateWrapper getAirBlockStateWrapper();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.seibel.lod.core.wrapperInterfaces.block;
|
||||
|
||||
public interface IBlockStateWrapper {
|
||||
IBlockStateWrapper AIR = null;
|
||||
|
||||
String serialize();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user