It... builds?
This commit is contained in:
@@ -1,13 +1,9 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnRenderLoader;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
|
||||
public class Initializer {
|
||||
public static void init() {
|
||||
ColumnRenderLoader columnRenderLoader = new ColumnRenderLoader();
|
||||
LodQuadTree.registerLayerLoader(columnRenderLoader, (byte) 7); // 7 or above
|
||||
|
||||
|
||||
ColumnRenderLoader unused = new ColumnRenderLoader(); // Auto register into the loader system
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,11 @@ public class EmptyRenderSource implements LodRenderSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DHChunkPos chunkPos, ChunkSizedData chunkData) {
|
||||
public void update(ChunkSizedData chunkData) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getRenderVersion() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,10 @@ import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderMetaFile;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
import com.seibel.lod.core.objects.DHChunkPos;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.render.LodSection;
|
||||
import com.seibel.lod.core.a7.render.LodRenderSection;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
@@ -256,7 +255,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
if (inBuildRenderBuffer == null) {
|
||||
ColumnRenderSource[] data = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length];
|
||||
for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) {
|
||||
LodSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels
|
||||
LodRenderSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels
|
||||
if (section.getRenderContainer() != null && section.getRenderContainer() instanceof ColumnRenderBuffer) {
|
||||
data[direction.ordinal()-2] = ((ColumnRenderSource) section.getRenderContainer());
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class DhClientLevel implements IClientLevel {
|
||||
public DhClientLevel(ClientOnlySaveStructure save, ILevelWrapper level) {
|
||||
this.save = save;
|
||||
dataFileHandler = new RemoteDataFileHandler();
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, save.getRenderCacheFolder(level));
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level));
|
||||
tree = new LodQuadTree(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
|
||||
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler);
|
||||
renderBufferHandler = new RenderBufferHandler(tree);
|
||||
@@ -38,16 +38,17 @@ public class DhClientLevel implements IClientLevel {
|
||||
FileScanner.scanFile(save, level, dataFileHandler, renderFileHandler);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpRamUsage() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientTick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
|
||||
if (renderer == null) {
|
||||
|
||||
@@ -31,7 +31,7 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel {
|
||||
this.level = level;
|
||||
this.save = save;
|
||||
dataFileHandler = new LocalDataFileHandler(this, save.getDataFolder(level));
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, save.getRenderCacheFolder(level));
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level));
|
||||
tree = new LodQuadTree(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
|
||||
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler);
|
||||
renderBufferHandler = new RenderBufferHandler(tree);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider;
|
||||
@@ -10,8 +10,6 @@ import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.gridList.MovableGridRingList;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// QuadTree built from several layers of 2d ring buffers
|
||||
|
||||
/**
|
||||
@@ -29,71 +27,24 @@ public class LodQuadTree {
|
||||
* Note: all config value should be via the class that extends this class, and
|
||||
* by implementing different abstract methods
|
||||
*/
|
||||
|
||||
private static final byte LAYER_BEGINNING_OFFSET = ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
public final byte getLayerDataDetailOffset(byte sectionDetail) {
|
||||
return ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
}
|
||||
public final byte getLayerSectionDetailOffset(byte dataDetail) {
|
||||
return ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
}
|
||||
public final byte getLayerDataDetail(byte sectionDetail) {
|
||||
return (byte) (sectionDetail - getLayerDataDetailOffset(sectionDetail));
|
||||
}
|
||||
public final byte getLayerSectionDetail(byte dataDetail) {
|
||||
return (byte) (dataDetail + getLayerSectionDetailOffset(dataDetail));
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger("LodQuadTree");
|
||||
|
||||
public final byte numbersOfSectionLevels;
|
||||
public final byte startingSectionLevel;
|
||||
private final MovableGridRingList<LodSection>[] ringLists;
|
||||
|
||||
static final ArrayList<RenderSourceLoader> layerLoaderConfig = new ArrayList<>();
|
||||
|
||||
static final Logger LOGGER = DhLoggerBuilder.getLogger("LodQuadTree");
|
||||
|
||||
public static void registerLayerLoader(RenderSourceLoader loader, byte sectionLevel) {
|
||||
LOGGER.info("Registering loader for section level " + sectionLevel + " for " + loader.getClass().getSimpleName());
|
||||
while (layerLoaderConfig.size() <= sectionLevel) {
|
||||
layerLoaderConfig.add(null);
|
||||
}
|
||||
if (layerLoaderConfig.set(sectionLevel, loader) != null) {
|
||||
throw new RuntimeException("Layer loader for level " + sectionLevel + " has a registry conflict!");
|
||||
}
|
||||
}
|
||||
|
||||
// static {
|
||||
// Collections.addAll(layerLoaderConfig,
|
||||
// null,
|
||||
// null, //1
|
||||
// null, //2
|
||||
// null, //3
|
||||
// new ContainerTypeConfigEntry(FullDatatype.class, (byte) 4), //4 -> 0
|
||||
// null, //5 force breaks down to 4 -> 0
|
||||
// null, //6 force breaks down to 4 -> 0
|
||||
// new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET), //7 -> 1
|
||||
// new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET) //8 -> 2
|
||||
// // ... And same onwards
|
||||
// );
|
||||
// }
|
||||
|
||||
static class SectionDetailLayer {
|
||||
final byte targetDataDetail;
|
||||
final RenderSourceLoader containerType;
|
||||
public SectionDetailLayer(byte targetDataDetail, RenderSourceLoader containerType) {
|
||||
this.targetDataDetail = targetDataDetail;
|
||||
this.containerType = containerType;
|
||||
}
|
||||
}
|
||||
|
||||
static void assertContainerTypeConfigCorrect() {
|
||||
boolean isInFront = true;
|
||||
for (int i = 0; i < layerLoaderConfig.size(); i++) {
|
||||
if (layerLoaderConfig.get(i) == null) continue;
|
||||
isInFront = false;
|
||||
RenderSourceLoader entry = layerLoaderConfig.get(i);
|
||||
if (i - entry.detailOffset < 0) {
|
||||
throw new RuntimeException("ContainerTypeConfigEntry " + i + " has a levelOffset of "
|
||||
+ entry.detailOffset + " which makes the dataDetail be " + (i - entry.detailOffset) + "," +
|
||||
" which is less than 0!");
|
||||
}
|
||||
if (entry.detailOffset < 0) {
|
||||
throw new RuntimeException("ContainerTypeConfigEntry " + i + " has a levelOffset of "
|
||||
+ entry.detailOffset + " which is less than 0!");
|
||||
}
|
||||
}
|
||||
if (layerLoaderConfig.get(layerLoaderConfig.size()-1) == null) {
|
||||
throw new RuntimeException("The last ContainerTypeConfigEntry is null, which is invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
final SectionDetailLayer[] sectionDetailLayers;
|
||||
private final MovableGridRingList<LodRenderSection>[] ringLists;
|
||||
public final int viewDistance;
|
||||
private final IRenderSourceProvider renderSourceProvider;
|
||||
|
||||
@@ -105,63 +56,21 @@ public class LodQuadTree {
|
||||
*/
|
||||
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ, IRenderSourceProvider provider) {
|
||||
renderSourceProvider = provider;
|
||||
|
||||
assertContainerTypeConfigCorrect();
|
||||
this.viewDistance = viewDistance;
|
||||
|
||||
//FIXME: Rework this mess of code!
|
||||
{ // Calculate the max section detail
|
||||
byte maxDetailLevel = getMaxDetailInRange(viewDistance * Math.sqrt(2));
|
||||
RenderSourceLoader finalEntry = null;
|
||||
byte topSectionLevel = 0;
|
||||
byte firstLevel = -1;
|
||||
for (; topSectionLevel < layerLoaderConfig.size(); topSectionLevel++) {
|
||||
if (layerLoaderConfig.get(topSectionLevel) == null) continue;
|
||||
finalEntry = layerLoaderConfig.get(topSectionLevel);
|
||||
if (firstLevel == -1) firstLevel = topSectionLevel;
|
||||
if (topSectionLevel - finalEntry.detailOffset >= maxDetailLevel) break;
|
||||
}
|
||||
if (finalEntry == null) throw new RuntimeException("No container type found!");
|
||||
if (topSectionLevel == layerLoaderConfig.size())
|
||||
topSectionLevel = (byte) (maxDetailLevel + finalEntry.detailOffset);
|
||||
byte maxDataDetailLevel = getMaxDetailInRange(viewDistance * Math.sqrt(2));
|
||||
byte topSectionLevel = getLayerSectionDetail(maxDataDetailLevel);
|
||||
numbersOfSectionLevels = (byte) (topSectionLevel + 1);
|
||||
startingSectionLevel = firstLevel;
|
||||
LOGGER.info("MaxLevel: " + maxDetailLevel + ", StartingLevel: " + startingSectionLevel + ", NumberOfLevels: " + numbersOfSectionLevels
|
||||
+ ", TopSectionLevel: " + topSectionLevel + ", FinalEntry: " + finalEntry);
|
||||
sectionDetailLayers = new SectionDetailLayer[numbersOfSectionLevels - startingSectionLevel];
|
||||
ringLists = new MovableGridRingList[numbersOfSectionLevels - startingSectionLevel];
|
||||
ringLists = new MovableGridRingList[numbersOfSectionLevels - LAYER_BEGINNING_OFFSET];
|
||||
}
|
||||
|
||||
{ // Fill in the sectionDetailLayers info and construct the ringLists
|
||||
byte lastNonNullEntry = -1;
|
||||
for (byte i = startingSectionLevel; i < numbersOfSectionLevels; i++) {
|
||||
byte targetDataDetail;
|
||||
RenderSourceLoader containerType;
|
||||
|
||||
if (i < layerLoaderConfig.size()) {
|
||||
if (layerLoaderConfig.get(i) == null) {
|
||||
if (lastNonNullEntry == -1) continue;
|
||||
targetDataDetail = sectionDetailLayers[lastNonNullEntry].targetDataDetail;
|
||||
containerType = null;
|
||||
} else {
|
||||
lastNonNullEntry = i;
|
||||
RenderSourceLoader entry = layerLoaderConfig.get(i);
|
||||
targetDataDetail = (byte) (i - entry.detailOffset);
|
||||
containerType = entry;
|
||||
}
|
||||
} else {
|
||||
LodUtil.assertTrue(layerLoaderConfig.get(layerLoaderConfig.size() - 1) != null,
|
||||
"The last entry must not be null!");
|
||||
RenderSourceLoader entry = layerLoaderConfig.get(layerLoaderConfig.size() - 1);
|
||||
targetDataDetail = (byte) (i - entry.detailOffset);
|
||||
containerType = entry;
|
||||
}
|
||||
|
||||
LodUtil.assertTrue(targetDataDetail >= 0, "dataDetail must be >= 0!");
|
||||
{ // Construct the ringLists
|
||||
for (byte i = LAYER_BEGINNING_OFFSET; i < numbersOfSectionLevels; i++) {
|
||||
byte targetDataDetail = getLayerDataDetail(i);
|
||||
int maxDist = getFurthestDistance(targetDataDetail);
|
||||
int halfSize = LodUtil.ceilDiv(maxDist, (1 << i) + 2);
|
||||
sectionDetailLayers[i - startingSectionLevel] = new SectionDetailLayer(targetDataDetail, containerType);
|
||||
ringLists[i - startingSectionLevel] = new MovableGridRingList<LodSection>(halfSize,
|
||||
ringLists[i - LAYER_BEGINNING_OFFSET] = new MovableGridRingList<>(halfSize,
|
||||
initialPlayerX >> i, initialPlayerZ >> i);
|
||||
}
|
||||
}
|
||||
@@ -173,29 +82,18 @@ public class LodQuadTree {
|
||||
* @param pos the section positon.
|
||||
* @return the LodSection
|
||||
*/
|
||||
public LodSection getSection(DhSectionPos pos) {
|
||||
public LodRenderSection getSection(DhSectionPos pos) {
|
||||
return getSection(pos.sectionDetail, pos.sectionX, pos.sectionZ);
|
||||
}
|
||||
|
||||
public byte getFirstSectionDetailFromDataDetail(byte dataDetail) {
|
||||
if (dataDetail <= startingSectionLevel) return startingSectionLevel;
|
||||
for (byte i = 0; i < sectionDetailLayers.length; i++) {
|
||||
if (sectionDetailLayers[i].targetDataDetail >= dataDetail) return (byte) (i + startingSectionLevel);
|
||||
}
|
||||
throw new RuntimeException("No section detail for dataDetail " + dataDetail+ " found!");
|
||||
}
|
||||
public byte getDataDetail(byte sectionDetail) {
|
||||
return sectionDetailLayers[sectionDetail - startingSectionLevel].targetDataDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the RingList of a given detail level
|
||||
* @apiNote The returned ringList should not be modified!
|
||||
* @param detailLevel the detail level
|
||||
* @return the RingList
|
||||
*/
|
||||
public MovableGridRingList<LodSection> getRingList(byte detailLevel) {
|
||||
return ringLists[detailLevel - startingSectionLevel];
|
||||
public MovableGridRingList<LodRenderSection> getRingList(byte detailLevel) {
|
||||
return ringLists[detailLevel - LAYER_BEGINNING_OFFSET];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,7 +105,7 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
public byte getStartingSectionLevel() {
|
||||
return startingSectionLevel;
|
||||
return LAYER_BEGINNING_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,8 +115,8 @@ public class LodQuadTree {
|
||||
* @param z z coordinate of the section
|
||||
* @return the LodSection
|
||||
*/
|
||||
public LodSection getSection(byte detailLevel, int x, int z) {
|
||||
return ringLists[detailLevel - startingSectionLevel].get(x, z);
|
||||
public LodRenderSection getSection(byte detailLevel, int x, int z) {
|
||||
return ringLists[detailLevel - LAYER_BEGINNING_OFFSET].get(x, z);
|
||||
}
|
||||
|
||||
|
||||
@@ -263,7 +161,7 @@ public class LodQuadTree {
|
||||
* @param pos the section positon
|
||||
* @return the parent LodSection
|
||||
*/
|
||||
public LodSection getParentSection(DhSectionPos pos) {
|
||||
public LodRenderSection getParentSection(DhSectionPos pos) {
|
||||
return getSection(pos.getParent());
|
||||
}
|
||||
|
||||
@@ -274,7 +172,7 @@ public class LodQuadTree {
|
||||
* @param child0to3 since there are 4 possible children this index identify which one we are getting
|
||||
* @return one of the child LodSection
|
||||
*/
|
||||
public LodSection getChildSection(DhSectionPos pos, int child0to3) {
|
||||
public LodRenderSection getChildSection(DhSectionPos pos, int child0to3) {
|
||||
return getSection(pos.getChild(child0to3));
|
||||
}
|
||||
|
||||
@@ -283,10 +181,10 @@ public class LodQuadTree {
|
||||
* @param playerPos the reference position for the player
|
||||
*/
|
||||
public void tick(DhBlockPos2D playerPos) {
|
||||
for (int sectLevel = startingSectionLevel; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
ringLists[sectLevel - startingSectionLevel]
|
||||
for (int sectLevel = LAYER_BEGINNING_OFFSET; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
ringLists[sectLevel - LAYER_BEGINNING_OFFSET]
|
||||
.move(playerPos.x >> sectLevel, playerPos.z >> sectLevel,
|
||||
LodSection::dispose);
|
||||
LodRenderSection::dispose);
|
||||
}
|
||||
|
||||
// First tick pass: update all sections' childCount from bottom level to top level. Step:
|
||||
@@ -318,14 +216,13 @@ public class LodQuadTree {
|
||||
// - If targetLevel < dataLevel@(sectLevel+1) && section == null: (use the next level's dataLevel)
|
||||
// - create new section with childCount = 0
|
||||
// - Parent's childCount++ (Create parent if needed)
|
||||
for (byte sectLevel = startingSectionLevel; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[sectLevel - startingSectionLevel];
|
||||
final MovableGridRingList<LodSection> childRingList =
|
||||
sectLevel == startingSectionLevel ? null : ringLists[sectLevel - startingSectionLevel - 1];
|
||||
final MovableGridRingList<LodSection> parentRingList =
|
||||
sectLevel == numbersOfSectionLevels - 1 ? null : ringLists[sectLevel - startingSectionLevel + 1];
|
||||
for (byte sectLevel = LAYER_BEGINNING_OFFSET; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
final MovableGridRingList<LodRenderSection> ringList = ringLists[sectLevel - LAYER_BEGINNING_OFFSET];
|
||||
final MovableGridRingList<LodRenderSection> childRingList =
|
||||
sectLevel == LAYER_BEGINNING_OFFSET ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET - 1];
|
||||
final MovableGridRingList<LodRenderSection> parentRingList =
|
||||
sectLevel == numbersOfSectionLevels - 1 ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET + 1];
|
||||
final byte f_sectLevel = sectLevel;
|
||||
RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (f_sectLevel == 0 && section != null) {
|
||||
section.childCount = 0;
|
||||
@@ -333,19 +230,19 @@ public class LodQuadTree {
|
||||
if (section != null && section.childCount != 0) {
|
||||
// Section will be in the unloaded state.
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodSection(section.pos.getParent()));
|
||||
new LodRenderSection(section.pos.getParent()));
|
||||
parent.childCount++;
|
||||
}
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
DhSectionPos childPos = section.pos.getChild(i);
|
||||
LodSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
if (child == null) {
|
||||
child = childRingList.setChained(childPos.sectionX, childPos.sectionZ,
|
||||
new LodSection(childPos));
|
||||
new LodRenderSection(childPos));
|
||||
child.childCount = 0;
|
||||
} else if (child.childCount == -1) {
|
||||
child.childCount = 0;
|
||||
@@ -357,31 +254,31 @@ public class LodQuadTree {
|
||||
byte targetLevel = calculateExpectedDetailLevel(playerPos, sectPos);
|
||||
if (f_sectLevel == numbersOfSectionLevels -1) {
|
||||
// Section is in the top level.
|
||||
if (targetLevel > getDataDetail(f_sectLevel) && section != null) {
|
||||
if (targetLevel > getLayerDataDetail(f_sectLevel) && section != null) {
|
||||
section.childCount = -1;
|
||||
}
|
||||
if (targetLevel <= getDataDetail(f_sectLevel) && section == null) {
|
||||
if (targetLevel <= getLayerDataDetail(f_sectLevel) && section == null) {
|
||||
section = ringList.setChained(pos.x, pos.y,
|
||||
new LodSection(sectPos));
|
||||
new LodRenderSection(sectPos));
|
||||
}
|
||||
} else {
|
||||
// Section is not the top level. So we also need to consider the parent.
|
||||
if (targetLevel >= getDataDetail((byte) (f_sectLevel+1)) && section != null) {
|
||||
if (targetLevel >= getLayerDataDetail((byte) (f_sectLevel+1)) && section != null) {
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodUtil.assertTrue(parent != null);
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
parent.childCount--;
|
||||
section.childCount = -1;
|
||||
}
|
||||
if (targetLevel < getDataDetail((byte) (f_sectLevel+1)) && section == null) {
|
||||
if (targetLevel < getLayerDataDetail((byte) (f_sectLevel+1)) && section == null) {
|
||||
section = ringList.setChained(pos.x, pos.y,
|
||||
new LodSection(sectPos));
|
||||
new LodRenderSection(sectPos));
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodSection(sectPos.getParent()));
|
||||
new LodRenderSection(sectPos.getParent()));
|
||||
}
|
||||
parent.childCount++;
|
||||
}
|
||||
@@ -397,7 +294,7 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
// Second tick pass:
|
||||
// Cascade the layers that is in Always Cascade Mode from top to bottom. (layer's containerType == null)
|
||||
// Cascade the layers that is in Always Cascade Mode from top to bottom. (Not yet exposed or used)
|
||||
// At the same time, load and unload sections (and can also be used to assert everything is working). Step:
|
||||
// ===Assertion steps===
|
||||
// assert childCount == 4 || childCount == 0 || childCount == -1
|
||||
@@ -412,26 +309,24 @@ public class LodQuadTree {
|
||||
// if childCount == -1: // (section can be loaded or unloaded, due to fast movement)
|
||||
// - set this section to null (TODO: Is this needed to be first or last or don't matter for concurrency?)
|
||||
// - If loaded unload section
|
||||
for (byte sectLevel = (byte) (numbersOfSectionLevels - 1); sectLevel >= startingSectionLevel; sectLevel--) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[sectLevel - startingSectionLevel];
|
||||
final MovableGridRingList<LodSection> childRingList =
|
||||
sectLevel == startingSectionLevel ? null : ringLists[sectLevel - startingSectionLevel - 1];
|
||||
final boolean doCacsade = sectionDetailLayers[sectLevel - startingSectionLevel].containerType == null;
|
||||
RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
|
||||
for (byte sectLevel = (byte) (numbersOfSectionLevels - 1); sectLevel >= LAYER_BEGINNING_OFFSET; sectLevel--) {
|
||||
final MovableGridRingList<LodRenderSection> ringList = ringLists[sectLevel - LAYER_BEGINNING_OFFSET];
|
||||
final MovableGridRingList<LodRenderSection> childRingList =
|
||||
sectLevel == LAYER_BEGINNING_OFFSET ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET - 1];
|
||||
final boolean doCascade = false; // TODO: Utilize this cascade mode or at least expose this option
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (section == null) return;
|
||||
|
||||
// Cascade layers
|
||||
if (doCacsade && section.childCount == 0) {
|
||||
if (doCascade && section.childCount == 0) {
|
||||
LodUtil.assertTrue(childRingList != null);
|
||||
// Create childs to cascade the layer.
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
DhSectionPos childPos = section.pos.getChild(i);
|
||||
LodSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
if (child == null) {
|
||||
child = childRingList.setChained(childPos.sectionX, childPos.sectionZ,
|
||||
new LodSection(childPos));
|
||||
new LodRenderSection(childPos));
|
||||
child.childCount = 0;
|
||||
} else {
|
||||
LodUtil.assertTrue(child.childCount == -1,
|
||||
@@ -463,7 +358,7 @@ public class LodQuadTree {
|
||||
section.dispose();
|
||||
} else {
|
||||
if (!section.isLoaded() && !section.isLoading()) {
|
||||
section.load(renderSourceProvider, containerType);
|
||||
section.load(renderSourceProvider);
|
||||
}
|
||||
if (section.childCount == 4) section.enableRender(this);
|
||||
if (section.childCount == 0) section.disableRender();
|
||||
|
||||
+3
-6
@@ -1,15 +1,12 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class LodSection {
|
||||
public static final int SUB_REGION_DATA_WIDTH = 16*16;
|
||||
|
||||
public class LodRenderSection {
|
||||
public final DhSectionPos pos;
|
||||
|
||||
/* Following used for LodQuadTree tick() method, and ONLY for that method! */
|
||||
@@ -23,7 +20,7 @@ public class LodSection {
|
||||
private boolean isRenderEnabled = false;
|
||||
|
||||
// Create sub region
|
||||
public LodSection(DhSectionPos pos) {
|
||||
public LodRenderSection(DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
@@ -42,7 +39,7 @@ public class LodSection {
|
||||
isRenderEnabled = false;
|
||||
}
|
||||
|
||||
public void load(IRenderSourceProvider renderDataProvider, RenderSourceLoader renderDataSourceClass) {
|
||||
public void load(IRenderSourceProvider renderDataProvider) {
|
||||
if (loadFuture != null || lodRenderSource != null) throw new IllegalStateException("Reloading is not supported!");
|
||||
loadFuture = renderDataProvider.read(pos);
|
||||
}
|
||||
@@ -40,25 +40,28 @@ public class RenderBufferHandler {
|
||||
// the buffer is only unloaded if all children's buffers are ready. This will make the
|
||||
// transition between buffers no longer causing any flicker.
|
||||
public void update() {
|
||||
LodSection section = target.getSection(pos);
|
||||
LodRenderSection section = target.getSection(pos);
|
||||
// If this fails, there may be concurrent modification of the quad tree
|
||||
// (as this update() should be called from the same thread that calls update() on the quad tree)
|
||||
LodUtil.assertTrue(section != null);
|
||||
LodRenderSource container = section.getRenderContainer();
|
||||
|
||||
// Update self's render buffer state
|
||||
boolean shouldRender = section.isLoaded();
|
||||
boolean shouldRender = section.canRender();
|
||||
if (!shouldRender) {
|
||||
RenderBuffer buff = renderBufferSlot.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
//TODO: Does this really need to force the old buffer to not be rendered?
|
||||
// RenderBuffer buff = renderBufferSlot.getAndSet(null);
|
||||
// if (buff != null) {
|
||||
// buff.close();
|
||||
// }
|
||||
} else {
|
||||
LodUtil.assertTrue(container != null); // section.isLoaded() should have ensured this
|
||||
container.trySwapRenderBuffer(target, renderBufferSlot);
|
||||
}
|
||||
|
||||
// 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();
|
||||
if (shouldHaveChildren) {
|
||||
if (children == null) {
|
||||
@@ -73,6 +76,9 @@ public class RenderBufferHandler {
|
||||
}
|
||||
} else {
|
||||
if (children != null) {
|
||||
//FIXME: Concurrency issue here: If render thread is concurrently using the child's buffer,
|
||||
// and this thread got priority to close the buffer, it causes a bug wher the render thread
|
||||
// will be using a closed buffer!!!!
|
||||
RenderBufferNode[] childs = children;
|
||||
children = null;
|
||||
for (RenderBufferNode child : childs) {
|
||||
@@ -98,7 +104,7 @@ public class RenderBufferHandler {
|
||||
|
||||
public RenderBufferHandler(LodQuadTree target) {
|
||||
this.target = target;
|
||||
MovableGridRingList<LodSection> referenceList = target.getRingList((byte) (target.getNumbersOfSectionLevels() - 1));
|
||||
MovableGridRingList<LodRenderSection> referenceList = target.getRingList((byte) (target.getNumbersOfSectionLevels() - 1));
|
||||
Pos2D center = referenceList.getCenter();
|
||||
renderBufferNodes = new MovableGridRingList<>(referenceList.getHalfSize(), center);
|
||||
}
|
||||
@@ -113,12 +119,12 @@ public class RenderBufferHandler {
|
||||
|
||||
public void update() {
|
||||
byte topDetail = (byte) (target.getNumbersOfSectionLevels() - 1);
|
||||
MovableGridRingList<LodSection> referenceList = target.getRingList(topDetail);
|
||||
MovableGridRingList<LodRenderSection> referenceList = target.getRingList(topDetail);
|
||||
Pos2D center = referenceList.getCenter();
|
||||
renderBufferNodes.move(center.x, center.y, RenderBufferNode::close); // Note: may lock the list
|
||||
renderBufferNodes.forEachPosOrdered((node, pos) -> {
|
||||
DhSectionPos sectPos = new DhSectionPos(topDetail, pos.x, pos.y);
|
||||
LodSection section = target.getSection(sectPos);
|
||||
LodRenderSection section = target.getSection(sectPos);
|
||||
|
||||
if (section == null) {
|
||||
// If section is null, but node exists, remove node
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.seibel.lod.core.a7.save.io.render;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.a7.datatype.EmptyRenderSource;
|
||||
import com.seibel.lod.core.a7.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
@@ -111,7 +112,15 @@ public class RenderFileHandler implements IRenderSourceProvider {
|
||||
dataSourceProvider::isCacheValid,
|
||||
dataSourceProvider::read,
|
||||
level, computeDefaultFilePath(p), p));
|
||||
return metaFile.loadOrGetCached(renderCacheThread);
|
||||
return metaFile.loadOrGetCached(renderCacheThread).handle(
|
||||
(render, e) -> {
|
||||
if (e != null) {
|
||||
LOGGER.error("Uncaught error on {}:", pos, e);
|
||||
}
|
||||
if (render != null) return render;
|
||||
return EmptyRenderSource.INSTANCE;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -7,9 +7,14 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class SharedApi {
|
||||
public static DhWorld currentWorld;
|
||||
public static final Logger LOGGER = DhLoggerBuilder.getLogger("DH Events");
|
||||
public static IMinecraftSharedWrapper MC;
|
||||
public static Logger LOGGER = DhLoggerBuilder.getLogger("DH Events");
|
||||
public static DhWorld currentWorld;
|
||||
|
||||
//TODO: Should this be in core and able to be accessed by core, or should this be in common, and only effect
|
||||
// how common calls back into the internal APIs?
|
||||
public static boolean inDedicatedEnvironment;
|
||||
|
||||
public static WorldEnvironment getEnvironment() {
|
||||
return currentWorld==null ? null : currentWorld.environment;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class LodDimensionFinder
|
||||
public static final String THREAD_NAME = "Sub-Dimension-Finder";
|
||||
public static final String DEFAULT_SAVE_DIMENSION_FOLDER = "_Default-Sub-Dimension";
|
||||
|
||||
private PlayerData playerData = new PlayerData(MC);
|
||||
private PlayerData playerData = null;//new PlayerData(MC);
|
||||
private PlayerData firstSeenPlayerData = null;
|
||||
|
||||
private volatile LodDimension foundLodDimension = null;
|
||||
@@ -218,7 +218,7 @@ public class LodDimensionFinder
|
||||
if (firstSeenPlayerData == null)
|
||||
{
|
||||
firstSeenPlayerData = playerData;
|
||||
playerData = new PlayerData(MC);
|
||||
playerData = null;//new PlayerData(MC);
|
||||
}
|
||||
|
||||
// relevant positions
|
||||
@@ -571,7 +571,7 @@ public class LodDimensionFinder
|
||||
|
||||
// determine the playerData
|
||||
IMinecraftClientWrapper mc = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
PlayerData playerdata = new PlayerData(mc);
|
||||
PlayerData playerdata = null;//new PlayerData(mc);
|
||||
|
||||
// write the data to file
|
||||
CommentedFileConfig toml = CommentedFileConfig.builder(file).build();
|
||||
|
||||
Reference in New Issue
Block a user