Continue a7 dev focused on qTree
This commit is contained in:
@@ -19,11 +19,26 @@
|
||||
|
||||
package com.seibel.lod.core.objects;
|
||||
|
||||
public final class Pos2D {
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
|
||||
public class Pos2D {
|
||||
public final int x;
|
||||
public final int y;
|
||||
public Pos2D(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Pos2D add(Pos2D other) {
|
||||
return new Pos2D(x + other.x, y + other.y);
|
||||
}
|
||||
public Pos2D subtract(Pos2D other) {
|
||||
return new Pos2D(x - other.x, y - other.y);
|
||||
}
|
||||
public double dist(Pos2D other) {
|
||||
return Math.sqrt(Math.pow(x - other.x, 2) + Math.pow(y - other.y, 2));
|
||||
}
|
||||
public long distSquared(Pos2D other) {
|
||||
return LodUtil.pow2((long)x - other.x) + LodUtil.pow2((long)y - other.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.seibel.lod.core.objects.a7;
|
||||
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.objects.a7.data.DataHandler;
|
||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
|
||||
@@ -10,6 +11,7 @@ public class DHLevel {
|
||||
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
public final File saveFolder; // Could be null, for no saving
|
||||
public final DataHandler dataHandler; // Could be null, for no saving
|
||||
public LodQuadTree lodQuadTree;
|
||||
public DHLevel(File saveFolder) {
|
||||
this.saveFolder = saveFolder;
|
||||
@@ -18,5 +20,12 @@ public class DHLevel {
|
||||
MC.getPlayerBlockPos().x,
|
||||
MC.getPlayerBlockPos().z
|
||||
);
|
||||
if (saveFolder != null) {
|
||||
dataHandler = new DataHandler(saveFolder);
|
||||
} else {
|
||||
dataHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.seibel.lod.core.objects.a7;
|
||||
|
||||
public class IdMappingUtil {
|
||||
public static final String BLOCKSTATE_ID_AIR = "air";
|
||||
//TODO HERE
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.seibel.lod.core.objects.a7;
|
||||
|
||||
public interface LodDataSource {
|
||||
RenderDataContaioner createRenderData(byte detailLevel, int x, int z);
|
||||
|
||||
|
||||
boolean saveLodData(RenderDataContaioner levelContainer, byte detailLevel, int x, int z);
|
||||
}
|
||||
@@ -1,26 +1,124 @@
|
||||
package com.seibel.lod.core.objects.a7;
|
||||
|
||||
import com.seibel.lod.core.objects.Pos2D;
|
||||
import com.seibel.lod.core.objects.a7.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.objects.a7.pos.DhLodUnit;
|
||||
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;
|
||||
|
||||
// QuadTree built from several layers of 2d ring buffers
|
||||
public class LodQuadTree {
|
||||
|
||||
public final int maxPossibleDetailLevel;
|
||||
private final MovableGridRingList<RenderDataContaioner>[] ringLists;
|
||||
private final MovableGridRingList<LodSection>[] ringLists;
|
||||
|
||||
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ) {
|
||||
maxPossibleDetailLevel = DetailDistanceUtil.getDetailLevelFromDistance(viewDistance*Math.sqrt(2));
|
||||
ringLists = new MovableGridRingList[maxPossibleDetailLevel];
|
||||
int size;
|
||||
for (int detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
for (byte detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
double distance = DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel);
|
||||
int blockCount = ((int)Math.ceil(distance / (1 << detailLevel)));
|
||||
ringLists[detailLevel] = new MovableGridRingList<RenderDataContaioner>(blockCount, initialPlayerX >> detailLevel, initialPlayerZ >> detailLevel);
|
||||
size = ringLists[detailLevel].getSize();
|
||||
int sectionCount = LodUtil.ceilDiv((int) Math.ceil(distance),
|
||||
DhSectionPos.getWidth(detailLevel).toBlock()) + 1; // +1 for the border during move
|
||||
ringLists[detailLevel] = new MovableGridRingList<LodSection>(sectionCount,
|
||||
initialPlayerX >> detailLevel, initialPlayerZ >> detailLevel);
|
||||
}
|
||||
}
|
||||
|
||||
public LodSection getSection(DhSectionPos pos) {
|
||||
return getSection(pos.detail, pos.x, pos.z);
|
||||
}
|
||||
|
||||
public LodSection getSection(byte detailLevel, int x, int z) {
|
||||
return ringLists[detailLevel].get(x, z);
|
||||
}
|
||||
|
||||
enum LodSectionState {
|
||||
Loaded,
|
||||
Unloaded,
|
||||
Freed,
|
||||
}
|
||||
|
||||
/*
|
||||
private LodSectionState expectsState(DhBlockPos2D playerPos, DhSectionPos pos) {
|
||||
// Get state of the children
|
||||
boolean hasAnyChildren = false;
|
||||
if (pos.detail != 0) {
|
||||
hasAnyChildren = getSection(pos.getChild(0)) != null ||
|
||||
getSection(pos.getChild(1)) != null ||
|
||||
getSection(pos.getChild(2)) != null ||
|
||||
getSection(pos.getChild(3)) != null; // Do this to allow short-circuit
|
||||
}
|
||||
if (hasAnyChildren) {
|
||||
return LodSectionState.Unloaded;
|
||||
}
|
||||
// All children is in the Freed state
|
||||
|
||||
// Calculate the distance to the player
|
||||
long dist = pos.getCenter().getCenter().distSquared(playerPos);
|
||||
byte targetDetail = DetailDistanceUtil.getDetailLevelFromDistance(dist);
|
||||
}*/
|
||||
|
||||
public void tick(DhBlockPos2D playerPos) {
|
||||
for (int detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
ringLists[detailLevel].move(playerPos.x >> detailLevel, playerPos.z >> detailLevel);
|
||||
}
|
||||
|
||||
// First tick pass: update all sections' distanceBasedTargetLevel amd neighborCheckedTargetLevel
|
||||
for (byte detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[detailLevel];
|
||||
final MovableGridRingList<LodSection> childRingList = detailLevel == 0 ? null : ringLists[detailLevel - 1];
|
||||
final byte detail = detailLevel;
|
||||
ringList.forEachPosOrdered((r, pos) -> {
|
||||
DhSectionPos sectionPos = new DhSectionPos(detail, pos.x, pos.y);
|
||||
long dist = sectionPos.getCenter().getCenter().distSquared(playerPos);
|
||||
byte targetDetail = DetailDistanceUtil.getDetailLevelFromDistance(dist);
|
||||
if (r == null) {
|
||||
if (targetDetail <= detail) {
|
||||
r = ringList.setChained(pos.x, pos.y, new LodSection(sectionPos));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
r.distanceBasedTargetLevel = targetDetail;
|
||||
if (childRingList == null) {
|
||||
r.childTargetLevel = (byte) (r.distanceBasedTargetLevel - 1);
|
||||
} else {
|
||||
byte minChildLevel = Byte.MAX_VALUE;
|
||||
/* FIXME: Todo later
|
||||
DhSectionPos childPos0 = sectionPos.getChild(0);
|
||||
minChildLevel = LodUtil.min(minChildLevel, childRingList.get(childPos0.x, childPos0.z).childTargetLevel);
|
||||
DhSectionPos childPos1 = sectionPos.getChild(1);
|
||||
minChildLevel = LodUtil.min(minChildLevel, childRingList.get(childPos1.x, childPos1.z).childTargetLevel);
|
||||
DhSectionPos childPos2 = sectionPos.getChild(2);
|
||||
minChildLevel = LodUtil.min(minChildLevel, childRingList.get(childPos2.x, childPos2.z).childTargetLevel);
|
||||
DhSectionPos childPos3 = sectionPos.getChild(3);
|
||||
minChildLevel = LodUtil.min(minChildLevel, childRingList.get(childPos3.x, childPos3.z).childTargetLevel);
|
||||
r.childTargetLevel = minChildLevel + 1;*/
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Second tick pass: load, unload, and free sections
|
||||
for (byte detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[detailLevel];
|
||||
final byte detail = detailLevel;
|
||||
|
||||
}
|
||||
|
||||
// Update the tree from the bottom detail level upwards
|
||||
for (byte detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[detailLevel];
|
||||
final byte detail = detailLevel;
|
||||
ringList.forEachPosOrdered((r, pos) -> {
|
||||
DhSectionPos sectionPos = new DhSectionPos(detail, pos.x, pos.y);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
package com.seibel.lod.core.objects.a7;
|
||||
|
||||
import com.seibel.lod.core.objects.lod.VerticalLevelContainer;
|
||||
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
|
||||
|
||||
public class LodSection {
|
||||
public static final int SUB_REGION_DATA_WIDTH = 16*16;
|
||||
|
||||
public final byte detailLevel;
|
||||
public final int x;
|
||||
public final int z;
|
||||
private RenderDataContaioner levelContainer;
|
||||
public final DhSectionPos pos;
|
||||
|
||||
// Following used for LodQuadTree tick() method, and ONLY for that method!
|
||||
public byte distanceBasedTargetLevel = Byte.MAX_VALUE; // the pure distance-based target level of this section
|
||||
// what is the nearest target level for the child quadrants after making sure child quadrants use the same target level?
|
||||
public byte childTargetLevel = Byte.MAX_VALUE;
|
||||
|
||||
private RenderDataContainer levelContainer;
|
||||
private RenderContainer renderContainer = null;
|
||||
|
||||
// Create sub region
|
||||
public LodSection(byte detailLevel, int x, int z) {
|
||||
this.detailLevel = detailLevel;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
public LodSection(DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
levelContainer = null;
|
||||
}
|
||||
LodSection(byte detailLevel, int x, int z, RenderDataContaioner levelContainer) {
|
||||
this.detailLevel = detailLevel;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
LodSection(DhSectionPos pos, RenderDataContainer levelContainer) {
|
||||
this.pos = pos;
|
||||
this.levelContainer = levelContainer;
|
||||
}
|
||||
|
||||
// Return null if data does not exist
|
||||
public static LodSection loadSection(byte detailLevel, int x, int z, LodDataSource lodDataSource) {
|
||||
RenderDataContaioner data = lodDataSource.createRenderData(detailLevel, x, z);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return new LodSection(detailLevel, x, z, data);
|
||||
public boolean load(RenderDataSource renderDataSource) {
|
||||
if (isLoaded()) throw new IllegalStateException("LodSection is already loaded");
|
||||
levelContainer = renderDataSource.createRenderData(pos);
|
||||
return levelContainer != null;
|
||||
}
|
||||
public void unload() {
|
||||
if (!isLoaded()) throw new IllegalStateException("LodSection is not loaded");
|
||||
levelContainer = null;
|
||||
}
|
||||
|
||||
|
||||
public boolean isLoaded() {
|
||||
return levelContainer != null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RenderDataContaioner
|
||||
public class RenderDataContainer
|
||||
{
|
||||
public static final boolean DO_SAFETY_CHECKS = true;
|
||||
|
||||
@@ -27,7 +27,7 @@ public class RenderDataContaioner
|
||||
|
||||
public final long[] dataContainer;
|
||||
|
||||
public RenderDataContaioner(byte detailLevel)
|
||||
public RenderDataContainer(byte detailLevel)
|
||||
{
|
||||
this.detailLevel = detailLevel;
|
||||
verticalSize = DetailDistanceUtil.getMaxVerticalData(detailLevel);
|
||||
@@ -230,7 +230,7 @@ public class RenderDataContaioner
|
||||
}
|
||||
}
|
||||
|
||||
public RenderDataContaioner(DataInputStream inputData, int version, byte expectedDetailLevel) throws IOException {
|
||||
public RenderDataContainer(DataInputStream inputData, int version, byte expectedDetailLevel) throws IOException {
|
||||
minHeight = SingletonHandler.get(IMinecraftClientWrapper.class).getWrappedClientWorld().getMinHeight();
|
||||
detailLevel = inputData.readByte();
|
||||
if (detailLevel != expectedDetailLevel)
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.seibel.lod.core.objects.a7;
|
||||
|
||||
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
|
||||
|
||||
public interface RenderDataSource {
|
||||
RenderDataContainer createRenderData(DhSectionPos pos);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.seibel.lod.core.objects.a7.data;
|
||||
|
||||
import com.seibel.lod.core.objects.a7.IdMappingUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CompleteDataContainer extends LodDataSource { // 1 chunk
|
||||
ArrayList<String> idMap;
|
||||
|
||||
protected CompleteDataContainer() {
|
||||
idMap = new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<ByteBuffer, ? extends LodDataSource> getLatestLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] getData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CompleteDataContainer createNewFromChunk(IChunkWrapper chunk) {
|
||||
CompleteDataContainer dataContainer = new CompleteDataContainer();
|
||||
HashMap<String, Integer> idMap = new HashMap<String, Integer>();
|
||||
|
||||
idMap.put(IdMappingUtil.BLOCKSTATE_ID_AIR, 0);
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int y = chunk.getMaxY(x, z);
|
||||
String currentBlockState = IdMappingUtil.BLOCKSTATE_ID_AIR;
|
||||
// FIXME: Move LodBuilder code to here
|
||||
}
|
||||
}
|
||||
return dataContainer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.seibel.lod.core.objects.a7.data;
|
||||
|
||||
import com.seibel.lod.core.objects.a7.RenderDataContainer;
|
||||
import com.seibel.lod.core.objects.a7.RenderDataSource;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class DataHandler implements RenderDataSource {
|
||||
public final File folder;
|
||||
|
||||
public DataHandler(File folderPath) {
|
||||
this.folder = folderPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderDataContainer createRenderData(byte detailLevel, int x, int z) {
|
||||
|
||||
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.seibel.lod.core.objects.a7.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LodDataContainer {
|
||||
ArrayList<Integer> idMap;
|
||||
int minX;
|
||||
int minY;
|
||||
int minZ;
|
||||
int maxX;
|
||||
int maxY;
|
||||
int maxZ;
|
||||
|
||||
public LodDataContainer() {
|
||||
idMap = new ArrayList<Integer>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.seibel.lod.core.objects.a7.data;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class LodDataSource {
|
||||
private static final String REGISTER_STRING_FILTER_REGEX = "^[a-zA-Z0-9_]*$";
|
||||
public static final HashMap<String, Function<ByteBuffer,? extends LodDataSource>>
|
||||
dataSourceLoaderRegistry = new HashMap<String, Function<ByteBuffer,? extends LodDataSource>>();
|
||||
|
||||
public static void registerDataSourceLoader(String name, int version, Function<ByteBuffer,? extends LodDataSource> loader) {
|
||||
if (name == null || loader == null || name.isEmpty()) {
|
||||
throw new IllegalArgumentException("Name and loader must be non-null, and not empty");
|
||||
}
|
||||
if (!name.matches(REGISTER_STRING_FILTER_REGEX)) {
|
||||
throw new IllegalArgumentException("Name must pass the regex " + REGISTER_STRING_FILTER_REGEX);
|
||||
}
|
||||
if (dataSourceLoaderRegistry.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Data source loader already registered for " + name);
|
||||
}
|
||||
dataSourceLoaderRegistry.put(name, loader);
|
||||
}
|
||||
|
||||
public static LodDataSource loadData(String dataSourceTypeName, ByteBuffer data) {
|
||||
|
||||
Function<ByteBuffer,? extends LodDataSource> loader = dataSourceLoaderRegistry.get(dataSourceTypeName);
|
||||
if (loader == null) {
|
||||
throw new IllegalArgumentException("No loader for data source type " + dataSourceTypeName);
|
||||
}
|
||||
return loader.apply(data);
|
||||
}
|
||||
public abstract Function<ByteBuffer,? extends LodDataSource> getLatestLoader();
|
||||
|
||||
public abstract <T> T[] getData(); //TODO & FIXME: What is T?
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.seibel.lod.core.objects.a7.pos;
|
||||
|
||||
import com.seibel.lod.core.objects.Pos2D;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
|
||||
public class DhBlockPos2D {
|
||||
public final int x;
|
||||
public final int z;
|
||||
public DhBlockPos2D(int x, int z) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public DhBlockPos2D add(DhBlockPos2D other) {
|
||||
return new DhBlockPos2D(x + other.x, z + other.z);
|
||||
}
|
||||
public DhBlockPos2D subtract(DhBlockPos2D other) {
|
||||
return new DhBlockPos2D(x - other.x, z - other.z);
|
||||
}
|
||||
public double dist(DhBlockPos2D other) {
|
||||
return Math.sqrt(Math.pow(x - other.x, 2) + Math.pow(z - other.z, 2));
|
||||
}
|
||||
public long distSquared(DhBlockPos2D other) {
|
||||
return LodUtil.pow2((long)x - other.x) + LodUtil.pow2((long)z - other.z);
|
||||
}
|
||||
|
||||
public Pos2D toPos2D() {
|
||||
return new Pos2D(x, z);
|
||||
}
|
||||
|
||||
public static DhBlockPos2D fromPos2D(Pos2D pos) {
|
||||
return new DhBlockPos2D(pos.x, pos.y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.seibel.lod.core.objects.a7.pos;
|
||||
|
||||
import com.seibel.lod.core.objects.DHBlockPos;
|
||||
|
||||
public class DhLodPos {
|
||||
public final byte detail;
|
||||
public final int x;
|
||||
public final int z;
|
||||
|
||||
public DhLodPos(byte detail, int x, int z) {
|
||||
this.detail = detail;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "DhLodPos(" + detail + ", " + x + ", " + z + ")";
|
||||
}
|
||||
|
||||
public DhLodUnit getX() {
|
||||
return new DhLodUnit(detail, x);
|
||||
}
|
||||
|
||||
public DhLodUnit getZ() {
|
||||
return new DhLodUnit(detail, z);
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return 1 << detail;
|
||||
}
|
||||
public static int getWidth(byte detail) {
|
||||
return 1 << detail;
|
||||
}
|
||||
|
||||
public DhBlockPos2D getCenter() {
|
||||
return new DhBlockPos2D(getX().toBlock() + (getWidth() >> 1), getZ().toBlock() + (getWidth() >> 1));
|
||||
}
|
||||
public DhBlockPos2D getCorner() {
|
||||
return new DhBlockPos2D(getX().toBlock(), getZ().toBlock());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.seibel.lod.core.objects.a7.pos;
|
||||
|
||||
public class DhLodUnit {
|
||||
public final byte detail;
|
||||
public final int value;
|
||||
|
||||
public DhLodUnit(byte detail, int value) {
|
||||
this.detail = detail;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int toBlock() {
|
||||
return value >> detail;
|
||||
}
|
||||
|
||||
public static DhLodUnit fromBlock(int block, byte targetDetail) {
|
||||
return new DhLodUnit(targetDetail, block << targetDetail);
|
||||
}
|
||||
|
||||
public DhLodUnit convertTo(byte targetDetail) {
|
||||
if (detail == targetDetail) {
|
||||
return this;
|
||||
}
|
||||
if (detail > targetDetail) { //TODO check if this is correct
|
||||
return new DhLodUnit(targetDetail, value >> (detail - targetDetail));
|
||||
}
|
||||
return new DhLodUnit(targetDetail, value << (targetDetail - detail));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.seibel.lod.core.objects.a7.pos;
|
||||
|
||||
import com.seibel.lod.core.objects.a7.DHLevel;
|
||||
import org.lwjgl.system.CallbackI;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class DhSectionPos {
|
||||
public static final int DATA_WIDTH_PER_SECTION = 64;
|
||||
|
||||
public final byte detail;
|
||||
public final int x;
|
||||
public final int z;
|
||||
|
||||
public DhSectionPos(byte detail, int x, int z) {
|
||||
this.detail = detail;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public DhLodPos getCorner() {
|
||||
return new DhLodPos(detail, x * DATA_WIDTH_PER_SECTION, z * DATA_WIDTH_PER_SECTION);
|
||||
}
|
||||
|
||||
public DhLodUnit getWidth() {
|
||||
return new DhLodUnit(detail, DATA_WIDTH_PER_SECTION);
|
||||
}
|
||||
|
||||
public static DhLodUnit getWidth(byte detail) {
|
||||
return new DhLodUnit(detail, DATA_WIDTH_PER_SECTION);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void forEachChild(Consumer<DhSectionPos> callback){
|
||||
for (int i = 0; i < 4; i++) {
|
||||
callback.accept(getChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
public DhSectionPos getParent(){
|
||||
return new DhSectionPos((byte) (detail + 1), x / 2, z / 2);
|
||||
}
|
||||
}
|
||||
@@ -338,6 +338,14 @@ public class LodUtil
|
||||
return -Math.floorDiv(-value, divider);
|
||||
}
|
||||
|
||||
// Why is this not in the standard library?! Come on Java!
|
||||
public static byte min(byte a, byte b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
public static byte max(byte a, byte b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
public static int computeOverdrawOffset(LodDimension lodDim) {
|
||||
int chunkRenderDist = MC_RENDER.getRenderDistance() + 1;
|
||||
VanillaOverdraw overdraw = CONFIG.client().graphics().advancedGraphics().getVanillaOverdraw();
|
||||
@@ -397,6 +405,7 @@ public class LodUtil
|
||||
public static double pow2(double x) {return x*x;}
|
||||
public static int pow2(int x) {return x*x;}
|
||||
|
||||
public static long pow2(long x) {return x*x;}
|
||||
|
||||
// True if the requested threshold pass, or false otherwise
|
||||
// For details, see:
|
||||
|
||||
@@ -19,12 +19,15 @@
|
||||
|
||||
package com.seibel.lod.core.util.gridList;
|
||||
|
||||
import com.seibel.lod.core.objects.DHRegionPos;
|
||||
import com.seibel.lod.core.objects.Pos2D;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
@@ -35,6 +38,28 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
private final int size;
|
||||
private final ReentrantReadWriteLock moveLock = new ReentrantReadWriteLock();
|
||||
|
||||
private Pos2D[] ringIteratorList = null;
|
||||
|
||||
//TODO: Check if this needs to be synchronized
|
||||
private void buildRingIteratorList() {
|
||||
ringIteratorList = null;
|
||||
Pos2D[] list = new Pos2D[size*size];
|
||||
|
||||
int i = 0;
|
||||
for (int ix=-halfSize; ix<=halfSize; ix++) {
|
||||
for (int iz=-halfSize; iz<=halfSize; iz++) {
|
||||
list[i] = new Pos2D(ix, iz);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
Arrays.sort(list, (a, b) -> {
|
||||
double disSqrA = a.x* a.x+ a.y* a.y;
|
||||
double disSqrB = b.x* b.x+ b.y* b.y;
|
||||
return Double.compare(disSqrA, disSqrB);
|
||||
});
|
||||
ringIteratorList = list;
|
||||
}
|
||||
|
||||
public MovableGridRingList(int halfSize, int centerX, int centerY) {
|
||||
super((halfSize * 2 + 1) * (halfSize * 2 + 1));
|
||||
size = halfSize * 2 + 1;
|
||||
@@ -213,6 +238,57 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use MutablePos2D in the future
|
||||
public void forEachPos(BiConsumer<? super T, Pos2D> d) {
|
||||
moveLock.readLock().lock();
|
||||
try {
|
||||
Pos2D min = pos.get();
|
||||
for (int x = min.x; x < min.x + size; x++) {
|
||||
for (int y = min.y; y < min.y + size; y++) {
|
||||
T t = _getUnsafe(x, y);
|
||||
d.accept(t, new Pos2D(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use MutablePos2D in the future
|
||||
public void forEachOrdered(Consumer<? super T> d) {
|
||||
if (ringIteratorList == null) buildRingIteratorList();
|
||||
moveLock.readLock().lock();
|
||||
try {
|
||||
Pos2D min = pos.get();
|
||||
for (Pos2D offset : ringIteratorList) {
|
||||
T t = _getUnsafe(min.x + offset.x, min.y + offset.y);
|
||||
d.accept(t);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use MutablePos2D in the future
|
||||
public void forEachPosOrdered(BiConsumer<? super T, Pos2D> d) {
|
||||
if (ringIteratorList == null) buildRingIteratorList();
|
||||
moveLock.readLock().lock();
|
||||
try {
|
||||
Pos2D min = pos.get();
|
||||
for (Pos2D offset : ringIteratorList) {
|
||||
T t = _getUnsafe(min.x + offset.x, min.y + offset.y);
|
||||
d.accept(t, new Pos2D(min.x + offset.x, min.y + offset.y));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Pos2D p = pos.get();
|
||||
|
||||
Reference in New Issue
Block a user