Start impl the dynamic section data detail offset

This commit is contained in:
TomTheFurry
2022-05-12 19:08:28 +08:00
parent cb85e396f0
commit 3ea3df62e9
3 changed files with 98 additions and 31 deletions
@@ -1,11 +1,16 @@
package com.seibel.lod.core.objects.a7;
import com.seibel.lod.core.objects.a7.datatype.column.ColumnDatatype;
import com.seibel.lod.core.objects.a7.pos.DhBlockPos2D;
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.gridList.MovableGridRingList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// QuadTree built from several layers of 2d ring buffers
/**
@@ -30,6 +35,37 @@ public abstract class LodQuadTree {
public final int numbersOfDetailLevels;
private final MovableGridRingList<LodSection>[] ringLists;
static class ContainerTypeConfigEntry {
final Class<?> containerType;
final int levelOffset;
public ContainerTypeConfigEntry(Class<?> containerType, int levelOffset) {
this.containerType = containerType;
this.levelOffset = levelOffset;
}
}
static final ArrayList<ContainerTypeConfigEntry> containerTypeConfig = new ArrayList<>();
static {
Collections.addAll(containerTypeConfig,
null,
null, //1
null, //2
null, //3
new ContainerTypeConfigEntry(FullDatatype.class, 4), //4 -> 0
null, //5 breaks down to 4
null, //6 breaks down to 4
new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET), //7 -> 1
new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET), //8 -> 2
new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET), //9 -> 3
new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET), //10 -> 4
new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET) //11 -> 5...
);
}
final ContainerTypeConfigEntry[] containerTypeConfigs;
//public static final
/**
* Constructor of the quadTree
@@ -38,13 +74,35 @@ public abstract class LodQuadTree {
* @param initialPlayerZ player z coordinate
*/
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ) {
numbersOfDetailLevels = DetailDistanceUtil.getDetailLevelFromDistance(viewDistance*Math.sqrt(2));
byte maxDetailLevel = DetailDistanceUtil.getDetailLevelFromDistance(viewDistance*Math.sqrt(2));
ContainerTypeConfigEntry finalEntry = null;
byte topSectionLevel = 0;
for (; topSectionLevel < containerTypeConfig.size(); topSectionLevel++) {
if (containerTypeConfig.get(topSectionLevel) == null) continue;
finalEntry = containerTypeConfig.get(topSectionLevel);
if (topSectionLevel - finalEntry.levelOffset >= maxDetailLevel) break;
}
if (finalEntry == null) throw new RuntimeException("No container type found!");
if (topSectionLevel == containerTypeConfig.size())
topSectionLevel = (byte) (maxDetailLevel - finalEntry.levelOffset);
numbersOfDetailLevels = topSectionLevel + 1;
containerTypeConfigs = new ContainerTypeConfigEntry[numbersOfDetailLevels];
finalEntry = null;
for (byte i = 0; i < numbersOfDetailLevels; i++) {
if (containerTypeConfig.get(i) == null) continue; //TODO: Next here
}
ringLists = new MovableGridRingList[numbersOfDetailLevels];
int size;
for (byte detailLevel = 0; detailLevel < numbersOfDetailLevels; detailLevel++) {
double distance = DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel);
int sectionCount = LodUtil.ceilDiv((int) Math.ceil(distance),
DhSectionPos.getWidth(detailLevel).toBlock()) + 1; // +1 for the border during move
int distance = getFurthestPoint(detailLevel);
ContainerTypeConfigEntry configEntry = containerTypeConfig.get(detailLevel);
if (configEntry == null) {
continue;
}
int sectionCount = LodUtil.ceilDiv(distance, DhSectionPos.getWidth(detailLevel).toBlock()) + 1; // +1 for the border during move
ringLists[detailLevel] = new MovableGridRingList<LodSection>(sectionCount,
initialPlayerX >> detailLevel, initialPlayerZ >> detailLevel);
}
@@ -88,10 +146,10 @@ public abstract class LodQuadTree {
return ringLists[detailLevel].get(x, z);
}
// Overridable
/**
* This method will compute the detail level based on player position and section pos
* Override this method if you want to use a different algorithm
* @param playerPos player position as a reference for calculating the detail level
* @param sectionPos section position
* @return detail level of this section pos
@@ -101,6 +159,17 @@ public abstract class LodQuadTree {
playerPos.dist(sectionPos.getCenter().getCenter()));
}
/**
* The method will return the furthest distance to the center for the given detail level
* Override this method if you want to use a different algorithm
* Note: the returned distance should always be the ceiling estimation of the distance
* @param detailLevel detail level
* @return the furthest distance to the center, in blocks
*/
public int getFurthestPoint(byte detailLevel) {
return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel));
}
public abstract RenderDataProvider getRenderDataProvider();
/**
@@ -21,7 +21,8 @@ import java.util.concurrent.atomic.AtomicReference;
public class ColumnDatatype implements LodDataSource, RenderDataSource {
public static final boolean DO_SAFETY_CHECKS = true;
public static final int SECTION_SIZE = DhSectionPos.DATA_WIDTH_PER_SECTION;
public static final int SECTION_SIZE_OFFSET = 6;
public static final int SECTION_SIZE = 1 << SECTION_SIZE_OFFSET;
public static final int LATEST_VERSION = 9;
public final int AIR_LODS_SIZE = 16;
public final int AIR_SECTION_SIZE = SECTION_SIZE/AIR_LODS_SIZE;
@@ -5,52 +5,48 @@ import com.seibel.lod.core.enums.LodDirection;
import java.util.function.Consumer;
public class DhSectionPos {
public static final byte SECTION_DETAIL_LEVEL_OFFSET = 6;
public static final int DATA_WIDTH_PER_SECTION = 1 << SECTION_DETAIL_LEVEL_OFFSET;
public final byte detail;
public final int x;
public final int z;
public final int yOffset;
public final byte dataDetailOffset;
public DhSectionPos(byte detail, int x, int z) {
this.detail = detail;
this.x = x;
this.z = z;
this.yOffset = 0;
}
public DhSectionPos(byte detail, int x, int z, int yOffset) {
public DhSectionPos(byte detail, int x, int z, int yOffset, byte dataDetailOffset) {
this.detail = detail;
this.x = x;
this.z = z;
this.yOffset = yOffset;
this.dataDetailOffset = dataDetailOffset;
}
public DhSectionPos withOffset(int yOffset) {
return new DhSectionPos(detail, x, z, yOffset);
public DhSectionPos withYOffset(int yOffset) {
return new DhSectionPos(detail, x, z, yOffset, dataDetailOffset);
}
public DhSectionPos withDataOffset(byte dataDetailOffset) {
return new DhSectionPos(detail, x, z, yOffset, dataDetailOffset);
}
public DhLodPos getCenter() {
return new DhLodPos(detail, x * DATA_WIDTH_PER_SECTION + DATA_WIDTH_PER_SECTION / 2, z * DATA_WIDTH_PER_SECTION + DATA_WIDTH_PER_SECTION / 2);
if (dataDetailOffset == 0) return new DhLodPos(detail, x, z);
return new DhLodPos(detail, (x << dataDetailOffset)+(1 << (dataDetailOffset-1)), (z << dataDetailOffset)+(1 << (dataDetailOffset-1)));
}
public DhLodPos getCorner() {
return new DhLodPos(detail, x * DATA_WIDTH_PER_SECTION, z * DATA_WIDTH_PER_SECTION);
return new DhLodPos(detail, x << dataDetailOffset, z << dataDetailOffset);
}
public DhLodUnit getWidth() {
return new DhLodUnit(detail, DATA_WIDTH_PER_SECTION);
return new DhLodUnit(detail, 1 << dataDetailOffset);
}
public static DhLodUnit getWidth(byte detail) {
return new DhLodUnit(detail, DATA_WIDTH_PER_SECTION);
public static DhLodUnit getWidth(byte detail, byte dataDetailOffset){
return new DhLodUnit(detail, 1 << dataDetailOffset);
}
public DhSectionPos getChild(int child0to3){
if (child0to3 < 0 || child0to3 > 3) throw new IllegalArgumentException("child0to3 must be between 0 and 3");
if (detail == 0) throw new IllegalStateException("detail must be greater than 0");
return new DhSectionPos((byte) (detail - 1), x * 2 + (child0to3 & 1), z * 2 + (child0to3 & 2) / 2, yOffset);
if (detail-dataDetailOffset <= 0) throw new IllegalStateException("detail or data detail must be greater than 0");
return new DhSectionPos((byte) (detail - 1), x * 2 + (child0to3 & 1), z * 2 + (child0to3 & 2) / 2, yOffset, dataDetailOffset);
}
public void forEachChild(Consumer<DhSectionPos> callback){
@@ -60,21 +56,22 @@ public class DhSectionPos {
}
public DhSectionPos getParent(){
return new DhSectionPos((byte) (detail + 1), x / 2, z / 2, yOffset);
return new DhSectionPos((byte) (detail + 1), x / 2, z / 2, yOffset, dataDetailOffset);
}
public DhSectionPos getAdjacent(LodDirection dir) {
return new DhSectionPos(detail, x + dir.getNormal().x, z + dir.getNormal().z, yOffset);
return new DhSectionPos(detail, x + dir.getNormal().x, z + dir.getNormal().z, yOffset, dataDetailOffset);
}
public DhSectionPos convertUpwardsTo(byte newDetail){
if (detail == newDetail) return this;
if (detail > newDetail) return new DhSectionPos(newDetail, x >> (detail - newDetail), z >> (detail - newDetail), yOffset);
if (detail > newDetail) return
new DhSectionPos(newDetail, x >> (detail - newDetail), z >> (detail - newDetail), yOffset, dataDetailOffset);
throw new IllegalArgumentException("newDetail must be greater than detail");
}
/**
* NOTE: This equals() does not consider yOffset!
* NOTE: This equals() does not consider yOffset or dataDetailOffset!
*/
public boolean equals(Object o){
@@ -85,7 +82,7 @@ public class DhSectionPos {
}
/**
* NOTE: This does not consider yOffset!
* NOTE: This does not consider yOffset! (dataDetailOffset is also ignored since, well, it doesn't effect the outcome)
*/
public boolean overlaps(DhSectionPos other){
if (this.equals(other))