From 03f50b168def9f16da5678e62bda3a2a80d437ab Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 12 Sep 2023 20:16:32 -0500 Subject: [PATCH 01/15] Add DataSourceReferenceTracker to automatically free unused data sources --- .../distanthorizons/core/Initializer.java | 3 + .../core/file/DataSourceReferenceTracker.java | 235 ++++++++++++++++++ .../file/fullDatafile/FullDataMetaFile.java | 9 +- .../file/renderfile/RenderMetaDataFile.java | 7 +- 4 files changed, 247 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java diff --git a/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java b/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java index 254db658e..c6b34eac1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core; +import com.seibel.distanthorizons.core.file.DataSourceReferenceTracker; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.core.world.DhApiWorldProxy; import com.seibel.distanthorizons.core.api.external.methods.config.DhApiConfig; @@ -67,6 +68,8 @@ public class Initializer DhApi.Delayed.worldProxy = DhApiWorldProxy.INSTANCE; DhApi.Delayed.renderProxy = DhApiRenderProxy.INSTANCE; + DataSourceReferenceTracker.startGarbageCollectorBackgroundThread(); + } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java b/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java new file mode 100644 index 000000000..640701b48 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java @@ -0,0 +1,235 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.file; + +import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; +import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; +import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile; +import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFile; +import com.seibel.distanthorizons.core.file.renderfile.RenderMetaDataFile; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.util.ThreadUtil; +import org.apache.logging.log4j.Logger; + +import java.io.Closeable; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; + +/** + * Keeps track of {@link FullDataMetaFile} and {@link RenderMetaDataFile}'s + * and handles freeing their underlying data sources if they go unused for a certain amount of time. + */ +public class DataSourceReferenceTracker +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + private static final boolean LOG_GARBAGE_COLLECTIONS = false; + + /** How often the garbage collector thread will run */ + private static final long MS_BETWEEN_GARBAGE_CHECKS = TimeUnit.SECONDS.toMillis(30); + /** How long a data source has to go unused before it can be freed */ + private static final long MS_TO_EXPIRE_DATA_SOURCE = TimeUnit.SECONDS.toMillis(15); + + + // these queues are populated by the JVM's garbage collector after the assigned soft reference is freed + private static final ReferenceQueue FULL_DATA_GARBAGE_COLLECTED_QUEUE = new ReferenceQueue<>(); + private static final ReferenceQueue RENDER_DATA_GARBAGE_COLLECTED_QUEUE = new ReferenceQueue<>(); + + // TODO using a ConcurrentHashMap may or may not be the best choice here + private static final Set FULL_DATA_SOFT_REFS = ConcurrentHashMap.newKeySet(); + private static final Set RENDER_DATA_SOFT_REFS = ConcurrentHashMap.newKeySet(); + + private static final ThreadPoolExecutor GARBAGE_COLLECTOR_THREAD = ThreadUtil.makeSingleThreadPool("DataSourceReferenceTracker", ThreadUtil.MINIMUM_RELATIVE_PRIORITY); + + + + //=================// + // collector logic // + //=================// + + /** Warning: this should not be called more than once. */ + public static void startGarbageCollectorBackgroundThread() { GARBAGE_COLLECTOR_THREAD.execute(() -> garbageCollectorLoop()); } + private static void garbageCollectorLoop() + { + while(true) + { + try + { + runGarbageCollection(); + Thread.sleep(MS_BETWEEN_GARBAGE_CHECKS); + } + catch (InterruptedException e) + { + LOGGER.error("Garbage collector thread interrupted.", e); + } + catch (Exception e) + { + LOGGER.error("Unexpected data source garbage collector exception: " + e.getMessage(), e); + } + } + } + + public static void runGarbageCollection() + { + removeGarbageCollectedDataSources(); + removeExpiredDataSources(); + } + private static void removeGarbageCollectedDataSources() + { + FullDataSourceSoftRef garbageCollectedFullDataSoftRef = (FullDataSourceSoftRef) FULL_DATA_GARBAGE_COLLECTED_QUEUE.poll(); + while (garbageCollectedFullDataSoftRef != null) + { + if (LOG_GARBAGE_COLLECTIONS) + { + LOGGER.info("Full Data at pos: " + garbageCollectedFullDataSoftRef.metaFile.pos + " has been soft released."); + } + garbageCollectedFullDataSoftRef.close(); + + garbageCollectedFullDataSoftRef = (FullDataSourceSoftRef) FULL_DATA_GARBAGE_COLLECTED_QUEUE.poll(); + } + + RenderDataSourceSoftRef renderSoftRef = (RenderDataSourceSoftRef) RENDER_DATA_GARBAGE_COLLECTED_QUEUE.poll(); + while (renderSoftRef != null) + { + if (LOG_GARBAGE_COLLECTIONS) + { + LOGGER.info("Render Data at pos: " + renderSoftRef.metaFile.pos + " has been soft released."); + } + renderSoftRef.close(); + + renderSoftRef = (RenderDataSourceSoftRef) RENDER_DATA_GARBAGE_COLLECTED_QUEUE.poll(); + } + } + private static void removeExpiredDataSources() + { + // TODO merge these loops + FULL_DATA_SOFT_REFS.removeIf((fullDataSoftRef) -> + { + boolean remove = fullDataSoftRef.isDataSourceExpired() || (fullDataSoftRef.silentGet() == null); + if (remove) + { + fullDataSoftRef.clear(); + fullDataSoftRef.close(); + + if (LOG_GARBAGE_COLLECTIONS) + { + LOGGER.info("Full Data at pos: " + fullDataSoftRef.metaFile.pos + " has expired and will be released at the next GC. ["+FULL_DATA_SOFT_REFS.size()+"] Full data sources remain."); + } + } + + return remove; + }); + + // TODO merge these loops + RENDER_DATA_SOFT_REFS.removeIf((renderDataSoftRef) -> + { + boolean remove = renderDataSoftRef.isDataSourceExpired() || (renderDataSoftRef.silentGet() == null); + if (remove) + { + renderDataSoftRef.clear(); + renderDataSoftRef.close(); + + if (LOG_GARBAGE_COLLECTIONS) + { + LOGGER.info("Render Data at pos: " + renderDataSoftRef.metaFile.pos + " has expired and will be released at the next GC. ["+RENDER_DATA_SOFT_REFS.size()+"] Render data sources remain."); + } + } + + return remove; + }); + } + + + + //================// + // helper classes // + //================// + + public static class FullDataSourceSoftRef extends AbstractDataSourceSoftTracker + { + public FullDataSourceSoftRef(FullDataMetaFile metaFile, IFullDataSource data) + { + super(metaFile, data, FULL_DATA_GARBAGE_COLLECTED_QUEUE); + FULL_DATA_SOFT_REFS.add(this); + } + + @Override + public void close() { FULL_DATA_SOFT_REFS.remove(this); } + } + public static class RenderDataSourceSoftRef extends AbstractDataSourceSoftTracker + { + public RenderDataSourceSoftRef(RenderMetaDataFile metaFile, ColumnRenderSource data) + { + super(metaFile, data, RENDER_DATA_GARBAGE_COLLECTED_QUEUE); + RENDER_DATA_SOFT_REFS.add(this); + } + + @Override + public void close() { RENDER_DATA_SOFT_REFS.remove(this); } + } + + /** wrapper for a {@link SoftReference} so we can track and manually remove unused sources */ + public static abstract class AbstractDataSourceSoftTracker extends SoftReference implements Closeable + { + public final TMetaFile metaFile; + public final long createdMsTime; + + private long expirationMsTime; + + + + public AbstractDataSourceSoftTracker(TMetaFile metaFile, TDataSource dataSource, ReferenceQueue referenceQueue) + { + super(dataSource, referenceQueue); + this.metaFile = metaFile; + + this.createdMsTime = System.currentTimeMillis(); + this.expirationMsTime = System.currentTimeMillis(); + } + + + + public void updateLastAccessedTime() { this.expirationMsTime = System.currentTimeMillis() + MS_TO_EXPIRE_DATA_SOURCE; } + public long getExpirationMsTime() { return this.expirationMsTime; } + public boolean isDataSourceExpired() { return this.expirationMsTime > System.currentTimeMillis(); } + + + @Override + public TDataSource get() + { + this.updateLastAccessedTime(); + return super.get(); + } + + /** + * Gets the underlying datasource without updating the {@link AbstractDataSourceSoftTracker#expirationMsTime} + * Note: this still updates {@link SoftReference}'s timestamp variable which may prevent the JVM from + * marking this reference as valid for deletion. + */ + public TDataSource silentGet() { return super.get(); } + + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java index 43fa3825a..3fa1cc495 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java @@ -33,6 +33,7 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFull import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource; +import com.seibel.distanthorizons.core.file.DataSourceReferenceTracker; import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFile; import com.seibel.distanthorizons.core.file.metaData.BaseMetaData; import com.seibel.distanthorizons.core.level.IDhLevel; @@ -84,7 +85,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I * When clearing, don't set to null, instead create a SoftReference containing null. * This makes null checks simpler. */ - private SoftReference cachedFullDataSourceRef = new SoftReference<>(null); + private DataSourceReferenceTracker.FullDataSourceSoftRef cachedFullDataSourceRef = new DataSourceReferenceTracker.FullDataSourceSoftRef(this,null); private final AtomicReference> dataSourceLoadFutureRef = new AtomicReference<>(null); // === Concurrent Write tracking === @@ -401,7 +402,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I public static void checkAndLogPhantomDataSourceLifeCycles() { DataObjTracker phantomRef = (DataObjTracker) LIFE_CYCLE_DEBUG_QUEUE.poll(); - // wait for the tracker to be garbage collected(?) + // wait for the tracker to be garbage collected while (phantomRef != null) { if (LOG_DATA_SOURCE_LIVES) @@ -563,7 +564,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I // save the updated data source - this.cachedFullDataSourceRef = new SoftReference<>(fullDataSource); + this.cachedFullDataSourceRef = new DataSourceReferenceTracker.FullDataSourceSoftRef(this, fullDataSource); // the task is complete completionFuture.complete(fullDataSource); @@ -685,7 +686,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I if (LOG_DATA_SOURCE_LIVES) { - LOGGER.info("Phantom created on {}! count: {}", data.getSectionPos(), LIFE_CYCLE_DEBUG_SET.size()); + //LOGGER.info("Phantom created on "+data.getSectionPos()+"! count: "+LIFE_CYCLE_DEBUG_SET.size()); } LIFE_CYCLE_DEBUG_SET.add(this); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java index d5e739570..7430509c3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java @@ -23,6 +23,7 @@ import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.distanthorizons.core.dataObjects.transformers.FullDataToRenderDataTransformer; +import com.seibel.distanthorizons.core.file.DataSourceReferenceTracker; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile; import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider; import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFile; @@ -68,7 +69,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements * When clearing, don't set to null, instead create a SoftReference containing null. * This makes null checks simpler. */ - private SoftReference cachedRenderDataSource = new SoftReference<>(null); + private DataSourceReferenceTracker.RenderDataSourceSoftRef cachedRenderDataSource = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, null); private final AtomicReference> renderSourceLoadFutureRef = new AtomicReference<>(null); private final IDhClientLevel clientLevel; @@ -210,7 +211,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements this.updateRenderCacheAsync(newColumnRenderSource).whenComplete((voidObj, ex) -> { - this.cachedRenderDataSource = new SoftReference<>(newColumnRenderSource); + this.cachedRenderDataSource = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, newColumnRenderSource); this.renderSourceLoadFutureRef.set(null); getSourceFuture.complete(newColumnRenderSource); @@ -258,7 +259,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements this.renderSourceLoadFutureRef.set(null); - this.cachedRenderDataSource = new SoftReference<>(renderSource); + this.cachedRenderDataSource = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, renderSource); getSourceFuture.complete(renderSource); }); } From cc933b6bd09732e261a926f304522f0bdbe7351a Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 13 Sep 2023 07:45:01 -0500 Subject: [PATCH 02/15] comment out DataSourceReferenceTracker GC logic --- .../core/file/DataSourceReferenceTracker.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java b/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java index 640701b48..089518eb1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java @@ -48,9 +48,9 @@ public class DataSourceReferenceTracker private static final boolean LOG_GARBAGE_COLLECTIONS = false; /** How often the garbage collector thread will run */ - private static final long MS_BETWEEN_GARBAGE_CHECKS = TimeUnit.SECONDS.toMillis(30); + private static final long MS_BETWEEN_GARBAGE_CHECKS = TimeUnit.SECONDS.toMillis(60); /** How long a data source has to go unused before it can be freed */ - private static final long MS_TO_EXPIRE_DATA_SOURCE = TimeUnit.SECONDS.toMillis(15); + private static final long MS_TO_EXPIRE_DATA_SOURCE = TimeUnit.SECONDS.toMillis(60); // these queues are populated by the JVM's garbage collector after the assigned soft reference is freed @@ -70,7 +70,7 @@ public class DataSourceReferenceTracker //=================// /** Warning: this should not be called more than once. */ - public static void startGarbageCollectorBackgroundThread() { GARBAGE_COLLECTOR_THREAD.execute(() -> garbageCollectorLoop()); } + public static void startGarbageCollectorBackgroundThread() { /*GARBAGE_COLLECTOR_THREAD.execute(() -> garbageCollectorLoop());*/ } private static void garbageCollectorLoop() { while(true) From a5178ceceac5c9ee426558721a6cc023f5e9b604 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 13 Sep 2023 18:29:56 -0500 Subject: [PATCH 03/15] Rename RenderMetaDataFile -> RenderDataMetaFile --- .../render/ColumnRenderLoader.java | 12 ++------ .../core/file/DataSourceReferenceTracker.java | 10 +++---- ...aDataFile.java => RenderDataMetaFile.java} | 18 ++++++------ .../renderfile/RenderSourceFileHandler.java | 28 +++++++++---------- .../core/util/MetaFileScanUtil.java | 4 +-- 5 files changed, 31 insertions(+), 41 deletions(-) rename core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/{RenderMetaDataFile.java => RenderDataMetaFile.java} (95%) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderLoader.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderLoader.java index 013f964dc..45d34b8cf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderLoader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderLoader.java @@ -20,16 +20,10 @@ package com.seibel.distanthorizons.core.dataObjects.render; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; -import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; -import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource; -import com.seibel.distanthorizons.core.file.renderfile.RenderMetaDataFile; -import com.seibel.distanthorizons.core.level.IDhClientLevel; +import com.seibel.distanthorizons.core.file.renderfile.RenderDataMetaFile; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream; -import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource; -import com.seibel.distanthorizons.core.dataObjects.transformers.FullDataToRenderDataTransformer; import org.apache.logging.log4j.Logger; import java.io.IOException; @@ -37,7 +31,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; /** - * Handles loading and parsing {@link RenderMetaDataFile}s to create {@link ColumnRenderSource}s.

+ * Handles loading and parsing {@link RenderDataMetaFile}s to create {@link ColumnRenderSource}s.

* * Please see the {@link ColumnRenderLoader#loadRenderSource} method to see what * file versions this class can handle. @@ -54,7 +48,7 @@ public class ColumnRenderLoader - public ColumnRenderSource loadRenderSource(RenderMetaDataFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException + public ColumnRenderSource loadRenderSource(RenderDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException { int dataFileVersion = dataFile.baseMetaData.binaryDataFormatVersion; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java b/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java index 089518eb1..2e7f7d51a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/DataSourceReferenceTracker.java @@ -23,7 +23,7 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.I import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile; import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFile; -import com.seibel.distanthorizons.core.file.renderfile.RenderMetaDataFile; +import com.seibel.distanthorizons.core.file.renderfile.RenderDataMetaFile; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.ThreadUtil; import org.apache.logging.log4j.Logger; @@ -31,15 +31,13 @@ import org.apache.logging.log4j.Logger; import java.io.Closeable; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; -import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; /** - * Keeps track of {@link FullDataMetaFile} and {@link RenderMetaDataFile}'s + * Keeps track of {@link FullDataMetaFile} and {@link RenderDataMetaFile}'s * and handles freeing their underlying data sources if they go unused for a certain amount of time. */ public class DataSourceReferenceTracker @@ -178,9 +176,9 @@ public class DataSourceReferenceTracker @Override public void close() { FULL_DATA_SOFT_REFS.remove(this); } } - public static class RenderDataSourceSoftRef extends AbstractDataSourceSoftTracker + public static class RenderDataSourceSoftRef extends AbstractDataSourceSoftTracker { - public RenderDataSourceSoftRef(RenderMetaDataFile metaFile, ColumnRenderSource data) + public RenderDataSourceSoftRef(RenderDataMetaFile metaFile, ColumnRenderSource data) { super(metaFile, data, RENDER_DATA_GARBAGE_COLLECTED_QUEUE); RENDER_DATA_SOFT_REFS.add(this); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java similarity index 95% rename from core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java rename to core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java index 7430509c3..4c4cef87b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java @@ -28,7 +28,6 @@ import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile; import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider; import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFile; import com.seibel.distanthorizons.core.file.metaData.BaseMetaData; -import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.pos.DhLodPos; @@ -48,13 +47,12 @@ import java.awt.*; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.lang.ref.SoftReference; import java.util.Random; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; /** Represents a File that contains a {@link ColumnRenderSource}. */ -public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements IDebugRenderable +public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements IDebugRenderable { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -83,10 +81,10 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements //=============// /** - * Can be used instead of {@link RenderMetaDataFile#createFromExistingFile} or {@link RenderMetaDataFile#createNewFileForPos}, + * Can be used instead of {@link RenderDataMetaFile#createFromExistingFile} or {@link RenderDataMetaFile#createNewFileForPos}, * if we are uncertain whether a file exists or not. */ - public static RenderMetaDataFile createFromExistingOrNewFile(IDhClientLevel clientLevel, IFullDataSourceProvider fullDataSourceProvider, DhSectionPos pos, File file) throws IOException + public static RenderDataMetaFile createFromExistingOrNewFile(IDhClientLevel clientLevel, IFullDataSourceProvider fullDataSourceProvider, DhSectionPos pos, File file) throws IOException { if (file.exists()) { @@ -103,8 +101,8 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements * NOTE: should only be used if there is NOT an existing file. * @throws IOException if a file already exists for this position */ - public static RenderMetaDataFile createNewFileForPos(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, DhSectionPos pos, File file) throws IOException { return new RenderMetaDataFile(fullDataSourceProvider, clientLevel, pos, file); } - private RenderMetaDataFile(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, DhSectionPos pos, File file) throws IOException + public static RenderDataMetaFile createNewFileForPos(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, DhSectionPos pos, File file) throws IOException { return new RenderDataMetaFile(fullDataSourceProvider, clientLevel, pos, file); } + private RenderDataMetaFile(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, DhSectionPos pos, File file) throws IOException { super(file, pos); this.fullDataSourceProvider = fullDataSourceProvider; @@ -119,8 +117,8 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements * NOTE: should only be used if there IS an existing file. * @throws IOException if no file exists for this position */ - public static RenderMetaDataFile createFromExistingFile(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, File file) throws IOException { return new RenderMetaDataFile(fullDataSourceProvider, clientLevel, file); } - private RenderMetaDataFile(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, File file) throws IOException + public static RenderDataMetaFile createFromExistingFile(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, File file) throws IOException { return new RenderDataMetaFile(fullDataSourceProvider, clientLevel, file); } + private RenderDataMetaFile(IFullDataSourceProvider fullDataSourceProvider, IDhClientLevel clientLevel, File file) throws IOException { super(file); this.fullDataSourceProvider = fullDataSourceProvider; @@ -466,7 +464,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements // helper methods // //================// - /** @return returns null if {@link RenderMetaDataFile#renderSourceLoadFutureRef} is empty and no cached {@link ColumnRenderSource} exists. */ + /** @return returns null if {@link RenderDataMetaFile#renderSourceLoadFutureRef} is empty and no cached {@link ColumnRenderSource} exists. */ @Nullable private CompletableFuture getCachedDataSourceAsync(boolean updateRenderSourceCache) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java index 40cb1eae8..db67a2ca4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java @@ -50,8 +50,8 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider private final F3Screen.NestedMessage threadPoolMsg; private final ConcurrentHashMap unloadedFileBySectionPos = new ConcurrentHashMap<>(); - /** contains the loaded {@link RenderMetaDataFile}'s */ - private final ConcurrentHashMap metaFileBySectionPos = new ConcurrentHashMap<>(); + /** contains the loaded {@link RenderDataMetaFile}'s */ + private final ConcurrentHashMap metaFileBySectionPos = new ConcurrentHashMap<>(); private final IDhClientLevel clientLevel; private final File saveDir; @@ -93,7 +93,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider @Override public void addScannedFiles(Collection detectedFiles) { - MetaFileScanUtil.ICreateMetadataFunc createMetadataFunc = (file) -> RenderMetaDataFile.createFromExistingFile(this.fullDataSourceProvider, this.clientLevel, file); + MetaFileScanUtil.ICreateMetadataFunc createMetadataFunc = (file) -> RenderDataMetaFile.createFromExistingFile(this.fullDataSourceProvider, this.clientLevel, file); MetaFileScanUtil.IAddUnloadedFileFunc addUnloadedFileFunc = (pos, file) -> { @@ -103,11 +103,11 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider MetaFileScanUtil.IAddLoadedMetaFileFunc addLoadedMetaFileFunc = (pos, loadedMetaFile) -> { this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); - this.metaFileBySectionPos.put(pos, (RenderMetaDataFile) loadedMetaFile); + this.metaFileBySectionPos.put(pos, (RenderDataMetaFile) loadedMetaFile); }; - MetaFileScanUtil.addScannedFiles(detectedFiles, USE_LAZY_LOADING, RenderMetaDataFile.FILE_SUFFIX, + MetaFileScanUtil.addScannedFiles(detectedFiles, USE_LAZY_LOADING, RenderDataMetaFile.FILE_SUFFIX, createMetadataFunc, addUnloadedFileFunc, addLoadedMetaFileFunc); } @@ -130,7 +130,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider - RenderMetaDataFile metaFile = this.getLoadOrMakeFile(pos); + RenderDataMetaFile metaFile = this.getLoadOrMakeFile(pos); if (metaFile == null) { return CompletableFuture.completedFuture(ColumnRenderSource.createEmptyRenderSource(pos)); @@ -154,9 +154,9 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider return getDataSourceFuture; } /** @return null if there was an issue */ - private RenderMetaDataFile getLoadOrMakeFile(DhSectionPos pos) + private RenderDataMetaFile getLoadOrMakeFile(DhSectionPos pos) { - RenderMetaDataFile metaFile = this.metaFileBySectionPos.get(pos); + RenderDataMetaFile metaFile = this.metaFileBySectionPos.get(pos); if (metaFile != null) { // return the loaded file @@ -194,7 +194,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider // attempt to load the file try { - metaFile = RenderMetaDataFile.createFromExistingFile(this.fullDataSourceProvider, this.clientLevel, fileToLoad); + metaFile = RenderDataMetaFile.createFromExistingFile(this.fullDataSourceProvider, this.clientLevel, fileToLoad); this.topDetailLevelRef.updateAndGet(currentTopDetailLevel -> Math.max(currentTopDetailLevel, pos.sectionDetailLevel)); this.metaFileBySectionPos.put(pos, metaFile); return metaFile; @@ -219,12 +219,12 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider { // createFromExistingOrNewFile() is used instead of createFromExistingFile() // due to a rare issue where the file may already exist but isn't in the file list - metaFile = RenderMetaDataFile.createFromExistingOrNewFile(this.clientLevel, this.fullDataSourceProvider, pos, this.computeRenderFilePath(pos)); + metaFile = RenderDataMetaFile.createFromExistingOrNewFile(this.clientLevel, this.fullDataSourceProvider, pos, this.computeRenderFilePath(pos)); this.topDetailLevelRef.updateAndGet(newDetailLevel -> Math.max(newDetailLevel, pos.sectionDetailLevel)); // Compare And Swap to handle a concurrency issue where multiple threads created the same Meta File at the same time - RenderMetaDataFile metaFileCas = this.metaFileBySectionPos.putIfAbsent(pos, metaFile); + RenderDataMetaFile metaFileCas = this.metaFileBySectionPos.putIfAbsent(pos, metaFile); return (metaFileCas == null) ? metaFile : metaFileCas; } catch (IOException e) @@ -262,7 +262,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider for (int zOffset = 0; zOffset < width; zOffset++) { DhSectionPos sectionPos = new DhSectionPos(sectionDetailLevel, minSectionPos.x + xOffset, minSectionPos.z + zOffset); - RenderMetaDataFile metaFile = this.metaFileBySectionPos.get(sectionPos); // bypass the getLoadOrMakeFile() since we only want cached files. + RenderDataMetaFile metaFile = this.metaFileBySectionPos.get(sectionPos); // bypass the getLoadOrMakeFile() since we only want cached files. if (metaFile != null) { metaFile.updateChunkIfSourceExistsAsync(chunk); @@ -284,7 +284,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider LOGGER.info("Shutting down " + RenderSourceFileHandler.class.getSimpleName() + "..."); ArrayList> futures = new ArrayList<>(); - for (RenderMetaDataFile metaFile : this.metaFileBySectionPos.values()) + for (RenderDataMetaFile metaFile : this.metaFileBySectionPos.values()) { futures.add(metaFile.flushAndSaveAsync()); } @@ -378,7 +378,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider // helper methods // //================// - public File computeRenderFilePath(DhSectionPos pos) { return new File(this.saveDir, pos.serialize() + RenderMetaDataFile.FILE_SUFFIX); } + public File computeRenderFilePath(DhSectionPos pos) { return new File(this.saveDir, pos.serialize() + RenderDataMetaFile.FILE_SUFFIX); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/MetaFileScanUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/MetaFileScanUtil.java index 3b17c65f5..726c92d0a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/MetaFileScanUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/MetaFileScanUtil.java @@ -25,7 +25,7 @@ import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile; import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider; import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFile; import com.seibel.distanthorizons.core.file.renderfile.ILodRenderSourceProvider; -import com.seibel.distanthorizons.core.file.renderfile.RenderMetaDataFile; +import com.seibel.distanthorizons.core.file.renderfile.RenderDataMetaFile; import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhSectionPos; @@ -81,7 +81,7 @@ public class MetaFileScanUtil try (Stream pathStream = Files.walk(saveStructure.getRenderCacheFolder(levelWrapper).toPath(), MAX_SCAN_DEPTH)) { List files = pathStream.filter( - path -> path.toFile().getName().endsWith(RenderMetaDataFile.FILE_SUFFIX) && path.toFile().isFile() + path -> path.toFile().getName().endsWith(RenderDataMetaFile.FILE_SUFFIX) && path.toFile().isFile() ).map(Path::toFile).collect(Collectors.toList()); LOGGER.info("Found " + files.size() + " render cache files for " + levelWrapper + " in " + saveStructure); renderSourceProvider.addScannedFiles(files); From 5ee1bea7c0f0c05d6d6587cf4803c9c375da28f6 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 13 Sep 2023 21:37:31 -0500 Subject: [PATCH 04/15] reformat DhSectionPos --- .../core/pos/DhSectionPos.java | 132 ++++++++++++------ 1 file changed, 93 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 380c22aa2..895dd9a65 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -105,7 +105,32 @@ public class DhSectionPos } - /** Returns the center for the highest detail level (0) */ + + //============// + // converters // + //============// + + /** + * uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels + * + * @return the new position closest to negative infinity with the new detail level + */ + public DhSectionPos convertToDetailLevel(byte newSectionDetailLevel) + { + DhLodPos lodPos = new DhLodPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); + lodPos = lodPos.convertToDetailLevel(newSectionDetailLevel); + + DhSectionPos newPos = new DhSectionPos(newSectionDetailLevel, lodPos); + return newPos; + } + + + + //=========// + // getters // + //=========// + + /** Returns the center for detail level 0 */ public DhLodPos getCenter() { return this.getCenter((byte) 0); } // TODO why does this use detail level 0 instead of this object's detail level? public DhLodPos getCenter(byte returnDetailLevel) { @@ -136,6 +161,7 @@ public class DhSectionPos public DhLodPos getCorner(byte returnDetailLevel) { LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); + byte offset = (byte) (this.sectionDetailLevel - returnDetailLevel); return new DhLodPos(returnDetailLevel, this.sectionX * BitShiftUtil.powerOfTwo(offset), @@ -150,19 +176,11 @@ public class DhSectionPos return new DhLodUnit(this.sectionDetailLevel, BitShiftUtil.powerOfTwo(offset)); } - /** - * uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels - * - * @return the new position closest to negative infinity with the new detail level - */ - public DhSectionPos convertToDetailLevel(byte newSectionDetailLevel) - { - DhLodPos lodPos = new DhLodPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); - lodPos = lodPos.convertToDetailLevel(newSectionDetailLevel); - - DhSectionPos newPos = new DhSectionPos(newSectionDetailLevel, lodPos); - return newPos; - } + + + //==================// + // parent child pos // + //==================// /** * Returns the DhLodPos 1 detail level lower

@@ -178,9 +196,13 @@ public class DhSectionPos public DhSectionPos getChildByIndex(int child0to3) throws IllegalArgumentException, IllegalStateException { if (child0to3 < 0 || child0to3 > 3) + { throw new IllegalArgumentException("child0to3 must be between 0 and 3"); + } if (this.sectionDetailLevel <= 0) + { throw new IllegalStateException("section detail must be greater than 0"); + } return new DhSectionPos((byte) (this.sectionDetailLevel - 1), this.sectionX * 2 + (child0to3 & 1), @@ -189,6 +211,48 @@ public class DhSectionPos /** Returns this position's child index in its parent */ public int getChildIndexOfParent() { return (this.sectionX & 1) + BitShiftUtil.square(this.sectionZ & 1); } + public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.sectionDetailLevel + 1), BitShiftUtil.half(this.sectionX), BitShiftUtil.half(this.sectionZ)); } + + + + + public DhSectionPos getAdjacentPos(EDhDirection dir) + { + return new DhSectionPos(this.sectionDetailLevel, + this.sectionX + dir.getNormal().x, + this.sectionZ + dir.getNormal().z); + } + + public DhLodPos getSectionBBoxPos() { return new DhLodPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); } + + + + //=============// + // comparisons // + //=============// + + /** NOTE: This does not consider yOffset! */ + public boolean overlaps(DhSectionPos other) { return this.getSectionBBoxPos().overlapsExactly(other.getSectionBBoxPos()); } + + /** NOTE: This does not consider yOffset! */ + public boolean contains(DhSectionPos otherPos) + { + DhBlockPos2D thisMinBlockPos = this.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); + DhBlockPos2D otherCornerBlockPos = otherPos.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); + + int thisBlockWidth = this.getWidth().toBlockWidth() - 1; // minus 1 to account for zero based positional indexing + DhBlockPos2D thisMaxBlockPos = new DhBlockPos2D(thisMinBlockPos.x + thisBlockWidth, thisMinBlockPos.z + thisBlockWidth); + + return thisMinBlockPos.x <= otherCornerBlockPos.x && otherCornerBlockPos.x <= thisMaxBlockPos.x && + thisMinBlockPos.z <= otherCornerBlockPos.z && otherCornerBlockPos.z <= thisMaxBlockPos.z; + } + + + + //===========// + // iterators // + //===========// + /** Applies the given consumer to all 4 of this position's children. */ public void forEachChild(Consumer callback) { @@ -206,38 +270,18 @@ public class DhSectionPos callback.accept(this); return; } + for (int i = 0; i < 4; i++) { this.getChildByIndex(i).forEachChildAtLevel(sectionDetailLevel, callback); } } - public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.sectionDetailLevel + 1), BitShiftUtil.half(this.sectionX), BitShiftUtil.half(this.sectionZ)); } - public DhSectionPos getAdjacentPos(EDhDirection dir) - { - return new DhSectionPos(this.sectionDetailLevel, - this.sectionX + dir.getNormal().x, - this.sectionZ + dir.getNormal().z); - } - public DhLodPos getSectionBBoxPos() { return new DhLodPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); } - - /** NOTE: This does not consider yOffset! */ - public boolean overlaps(DhSectionPos other) { return this.getSectionBBoxPos().overlapsExactly(other.getSectionBBoxPos()); } - - /** NOTE: This does not consider yOffset! */ - public boolean contains(DhSectionPos otherPos) - { - DhBlockPos2D thisMinBlockPos = this.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); - DhBlockPos2D otherCornerBlockPos = otherPos.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); - - int thisBlockWidth = this.getWidth().toBlockWidth() - 1; // minus 1 to account for zero based positional indexing - DhBlockPos2D thisMaxBlockPos = new DhBlockPos2D(thisMinBlockPos.x + thisBlockWidth, thisMinBlockPos.z + thisBlockWidth); - - return thisMinBlockPos.x <= otherCornerBlockPos.x && otherCornerBlockPos.x <= thisMaxBlockPos.x && - thisMinBlockPos.z <= otherCornerBlockPos.z && otherCornerBlockPos.z <= thisMaxBlockPos.z; - } + //===============// + // serialization // + //===============// /** Serialize() is different from toString() as it must NEVER be changed, and should be in a short format */ public String serialize() { return "[" + this.sectionDetailLevel + ',' + this.sectionX + ',' + this.sectionZ + ']'; } @@ -252,6 +296,12 @@ public class DhSectionPos } + + + //===========// + // overrides // + //===========// + @Override public String toString() { return "{" + this.sectionDetailLevel + "*" + this.sectionX + "," + this.sectionZ + "}"; } @@ -259,9 +309,13 @@ public class DhSectionPos public boolean equals(Object obj) { if (this == obj) + { return true; - if (obj == null || this.getClass() != obj.getClass()) + } + if (obj == null || obj.getClass() != DhSectionPos.class) + { return false; + } DhSectionPos that = (DhSectionPos) obj; return this.sectionDetailLevel == that.sectionDetailLevel && From 84236e7a31a134ac7d60eed09c643b26a774ebe2 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 13 Sep 2023 21:52:56 -0500 Subject: [PATCH 05/15] Add additional DhSectionPos unit tests --- .../src/test/java/tests/DhSectionPosTest.java | 147 +++++++++++++++++- 1 file changed, 145 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/tests/DhSectionPosTest.java b/core/src/test/java/tests/DhSectionPosTest.java index 6728db56e..eb36fd675 100644 --- a/core/src/test/java/tests/DhSectionPosTest.java +++ b/core/src/test/java/tests/DhSectionPosTest.java @@ -19,8 +19,7 @@ package tests; -import com.seibel.distanthorizons.core.pos.DhLodPos; -import com.seibel.distanthorizons.core.pos.DhSectionPos; +import com.seibel.distanthorizons.core.pos.*; import org.junit.Assert; import org.junit.Test; @@ -159,4 +158,148 @@ public class DhSectionPosTest } + @Test + public void CreateFromBlockPos() + { + // origin pos // + + DhBlockPos originBlockPos = new DhBlockPos(0, 0, 0); + DhSectionPos originSectionPos = new DhSectionPos(originBlockPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); + + + // offset pos // + + DhBlockPos offsetBlockPos = new DhBlockPos(1000, 0, 42000); + DhSectionPos offsetSectionPos = new DhSectionPos(offsetBlockPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 15, 656), offsetSectionPos); + + offsetBlockPos = new DhBlockPos(-987654, 0, 46); + offsetSectionPos = new DhSectionPos(offsetBlockPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); + + } + + @Test + public void CreateFromBlockPos2D() + { + // origin pos // + + DhBlockPos2D originBlockPos = new DhBlockPos2D(0, 0); + DhSectionPos originSectionPos = new DhSectionPos(originBlockPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); + + + // offset pos // + + DhBlockPos2D offsetBlockPos = new DhBlockPos2D(1000, 42000); + DhSectionPos offsetSectionPos = new DhSectionPos(offsetBlockPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 15, 656), offsetSectionPos); + + offsetBlockPos = new DhBlockPos2D(-987654, 46); + offsetSectionPos = new DhSectionPos(offsetBlockPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); + + } + + @Test + public void CreateFromChunkPos() + { + // origin pos // + + DhChunkPos originChunkPos = new DhChunkPos(0,0); + DhSectionPos originSectionPos = new DhSectionPos(originChunkPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, 0, 0), originSectionPos); + + + // offset pos // + + DhChunkPos offsetChunkPos = new DhChunkPos(1000, 42000); + DhSectionPos offsetSectionPos = new DhSectionPos(offsetChunkPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, 15, 656), offsetSectionPos); + + offsetChunkPos = new DhChunkPos(-987654, 46); + offsetSectionPos = new DhSectionPos(offsetChunkPos); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); + + } + + @Test + public void ConvertToDetailLevel() + { + // origin pos // + + DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); + + originSectionPos = originSectionPos.convertToDetailLevel((byte) 1); + Assert.assertEquals(new DhSectionPos((byte) 1, 0, 0), originSectionPos); + + originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); + + originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, 0, 0), originSectionPos); + + + // offset pos // + + DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); + + sectionPos = sectionPos.convertToDetailLevel((byte) 1); + Assert.assertEquals(new DhSectionPos((byte) 1, -5000, 2500), sectionPos); + + sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -157, 78), sectionPos); + + sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, -1, 0), sectionPos); + + } + + @Test + public void GetDefaultWidth() + { + DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); + DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); + + // widths should be the same regardless of position in the world + originSectionPos = originSectionPos.convertToDetailLevel((byte) 1); + Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); + sectionPos = sectionPos.convertToDetailLevel((byte) 1); + Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); + + originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); + sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); + + originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); + sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); + + } + @Test + public void GetOffsetWidth() + { + DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); + DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); + + originSectionPos = originSectionPos.convertToDetailLevel((byte) 1); + Assert.assertEquals(2, originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + sectionPos = sectionPos.convertToDetailLevel((byte) 1); + Assert.assertEquals(2, sectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + + originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(64, originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(64, sectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + + originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(4096, originSectionPos.getWidth((byte) 3).numberOfLodSectionsWide); + sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(4096, sectionPos.getWidth((byte) 3).numberOfLodSectionsWide); + + } + } From 00806933e06e4add7f323ece1b0817bfcd855fbb Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 07:21:01 -0500 Subject: [PATCH 06/15] Optimize DhSectionPos constructors and add convertSelfToDetailLevel() --- .../sources/interfaces/IFullDataSource.java | 4 +- .../core/pos/DhSectionPos.java | 57 ++++++++++++------- .../core/util/objects/quadTree/QuadNode.java | 2 +- .../core/util/objects/quadTree/QuadTree.java | 6 +- .../src/test/java/tests/DhSectionPosTest.java | 44 +++++++------- 5 files changed, 63 insertions(+), 50 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java index 6e2845800..622c67d04 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java @@ -144,7 +144,7 @@ public interface IFullDataSource int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); int relWidthForSecPos = sourceRelWidth / widthInSecPos; - DhSectionPos minSecPos = this.getSectionPos().convertToDetailLevel(childDetailLevel); + DhSectionPos minSecPos = this.getSectionPos().convertNewToDetailLevel(childDetailLevel); DhSectionPos inputPos = quadrantPos; @@ -195,7 +195,7 @@ public interface IFullDataSource int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); int relWidthForSecPos = sourceRelWidth / widthInSecPos; - DhSectionPos minSecPos = this.getSectionPos().convertToDetailLevel(childDetailLevel); + DhSectionPos minSecPos = this.getSectionPos().convertNewToDetailLevel(childDetailLevel); DhSectionPos inputPos = quadrantPos.getChildByIndex(i); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 895dd9a65..b908d89ad 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -56,12 +56,12 @@ public class DhSectionPos public final static byte SECTION_REGION_DETAIL_LEVEL = SECTION_MINIMUM_DETAIL_LEVEL + LodUtil.REGION_DETAIL_LEVEL; - public final byte sectionDetailLevel; + public byte sectionDetailLevel; /** in a sectionDetailLevel grid */ - public final int sectionX; + public int sectionX; /** in a sectionDetailLevel grid */ - public final int sectionZ; + public int sectionZ; @@ -76,25 +76,21 @@ public class DhSectionPos this.sectionZ = sectionZ; } - public DhSectionPos(DhBlockPos blockPos) { this(new DhBlockPos2D(blockPos)); } + public DhSectionPos(DhBlockPos blockPos) + { + this(LodUtil.BLOCK_DETAIL_LEVEL, blockPos.x, blockPos.z); + this.convertSelfToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + } public DhSectionPos(DhBlockPos2D blockPos) { - DhLodPos lodPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPos.x, blockPos.z); - lodPos = lodPos.convertToDetailLevel(SECTION_BLOCK_DETAIL_LEVEL); - - this.sectionDetailLevel = SECTION_BLOCK_DETAIL_LEVEL; - this.sectionX = lodPos.x; - this.sectionZ = lodPos.z; + this(LodUtil.BLOCK_DETAIL_LEVEL, blockPos.x, blockPos.z); + this.convertSelfToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); } public DhSectionPos(DhChunkPos chunkPos) { - DhLodPos lodPos = new DhLodPos(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.x, chunkPos.z); - lodPos = lodPos.convertToDetailLevel(SECTION_CHUNK_DETAIL_LEVEL); - - this.sectionDetailLevel = SECTION_CHUNK_DETAIL_LEVEL; - this.sectionX = lodPos.x; - this.sectionZ = lodPos.z; + this(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.x, chunkPos.z); + this.convertSelfToDetailLevel(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL); } public DhSectionPos(byte detailLevel, DhLodPos dhLodPos) @@ -110,17 +106,34 @@ public class DhSectionPos // converters // //============// + /** uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels. */ + public void convertSelfToDetailLevel(byte newDetailLevel) + { + // logic originally taken from DhLodPos + if (newDetailLevel >= this.sectionDetailLevel) + { + this.sectionX = Math.floorDiv(this.sectionX, BitShiftUtil.powerOfTwo(newDetailLevel - this.sectionDetailLevel)); + this.sectionZ = Math.floorDiv(this.sectionZ, BitShiftUtil.powerOfTwo(newDetailLevel - this.sectionDetailLevel)); + } + else + { + this.sectionX = this.sectionX * BitShiftUtil.powerOfTwo(this.sectionDetailLevel - newDetailLevel); + this.sectionZ = this.sectionZ * BitShiftUtil.powerOfTwo(this.sectionDetailLevel - newDetailLevel); + } + + this.sectionDetailLevel = newDetailLevel; + } + /** - * uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels + * uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels. * * @return the new position closest to negative infinity with the new detail level */ - public DhSectionPos convertToDetailLevel(byte newSectionDetailLevel) + public DhSectionPos convertNewToDetailLevel(byte newSectionDetailLevel) { - DhLodPos lodPos = new DhLodPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); - lodPos = lodPos.convertToDetailLevel(newSectionDetailLevel); + DhSectionPos newPos = new DhSectionPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); + newPos.convertSelfToDetailLevel(newSectionDetailLevel); - DhSectionPos newPos = new DhSectionPos(newSectionDetailLevel, lodPos); return newPos; } @@ -168,7 +181,7 @@ public class DhSectionPos this.sectionZ * BitShiftUtil.powerOfTwo(offset)); } - public DhLodUnit getWidth() { return this.getWidth(this.sectionDetailLevel); } + public DhLodUnit getWidth() { return this.getWidth(this.sectionDetailLevel); } // this always returns 1... public DhLodUnit getWidth(byte returnDetailLevel) { LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java index e2b585c40..8f4d2ba45 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java @@ -180,7 +180,7 @@ public class QuadNode if (!this.sectionPos.contains(inputSectionPos)) { LOGGER.error((replaceValue ? "set " : "get ") + inputSectionPos + " center block: " + inputSectionPos.getCenter().getCornerBlockPos() + ", this pos: " + this.sectionPos + " this center block: " + this.sectionPos.getCenter().getCornerBlockPos()); - throw new IllegalArgumentException("Input section pos " + inputSectionPos + " outside of this quadNode's pos: " + this.sectionPos + ", this node's blockPos: " + this.sectionPos.convertToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " block width: " + this.sectionPos.getWidth().toBlockWidth() + " input detail level: " + inputSectionPos.convertToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " width: " + inputSectionPos.getWidth().toBlockWidth()); + throw new IllegalArgumentException("Input section pos " + inputSectionPos + " outside of this quadNode's pos: " + this.sectionPos + ", this node's blockPos: " + this.sectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " block width: " + this.sectionPos.getWidth().toBlockWidth() + " input detail level: " + inputSectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " width: " + inputSectionPos.getWidth().toBlockWidth()); } if (inputSectionPos.sectionDetailLevel > this.sectionPos.sectionDetailLevel) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java index 2014e4039..9913d3905 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java @@ -121,7 +121,7 @@ public class QuadTree { if (!runBoundaryChecks || this.isSectionPosInBounds(pos)) { - DhSectionPos rootPos = pos.convertToDetailLevel(this.treeMinDetailLevel); + DhSectionPos rootPos = pos.convertNewToDetailLevel(this.treeMinDetailLevel); int ringListPosX = rootPos.sectionX; int ringListPosZ = rootPos.sectionZ; @@ -156,7 +156,7 @@ public class QuadTree int radius = this.diameterInBlocks() / 2; DhBlockPos2D minPos = this.getCenterBlockPos().add(new DhBlockPos2D(-radius, -radius)); DhBlockPos2D maxPos = this.getCenterBlockPos().add(new DhBlockPos2D(radius, radius)); - throw new IndexOutOfBoundsException("QuadTree GetOrSet failed. Position out of bounds, min pos: " + minPos + ", max pos: " + maxPos + ", min detail level: " + this.treeMaxDetailLevel + ", max detail level: " + this.treeMinDetailLevel + ". Given Position: " + pos + " = block pos: " + pos.convertToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL)); + throw new IndexOutOfBoundsException("QuadTree GetOrSet failed. Position out of bounds, min pos: " + minPos + ", max pos: " + maxPos + ", min detail level: " + this.treeMaxDetailLevel + ", max detail level: " + this.treeMinDetailLevel + ". Given Position: " + pos + " = block pos: " + pos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL)); } } @@ -174,7 +174,7 @@ public class QuadTree DhBlockPos2D treeBlockCorner = this.centerBlockPos.add(new DhBlockPos2D(-this.widthInBlocks / 2, -this.widthInBlocks / 2)); DhLodPos treeCornerPos = new DhLodPos((byte) 0, treeBlockCorner.x, treeBlockCorner.z); - DhSectionPos inputSectionCorner = testPos.convertToDetailLevel((byte) 0); + DhSectionPos inputSectionCorner = testPos.convertNewToDetailLevel((byte) 0); DhLodPos inputCornerPos = new DhLodPos((byte) 0, inputSectionCorner.sectionX, inputSectionCorner.sectionZ); int inputBlockWidth = BitShiftUtil.powerOfTwo(testPos.sectionDetailLevel); diff --git a/core/src/test/java/tests/DhSectionPosTest.java b/core/src/test/java/tests/DhSectionPosTest.java index eb36fd675..3d37e5239 100644 --- a/core/src/test/java/tests/DhSectionPosTest.java +++ b/core/src/test/java/tests/DhSectionPosTest.java @@ -83,22 +83,22 @@ public class DhSectionPosTest public void ParentPosTest() { DhSectionPos leaf = new DhSectionPos((byte) 0, 0, 0); - DhSectionPos convert = leaf.convertToDetailLevel((byte) 1); + DhSectionPos convert = leaf.convertNewToDetailLevel((byte) 1); DhSectionPos parent = leaf.getParentPos(); Assert.assertEquals("get parent at 0,0 fail", convert, parent); leaf = new DhSectionPos((byte) 0, 1, 1); - convert = leaf.convertToDetailLevel((byte) 1); + convert = leaf.convertNewToDetailLevel((byte) 1); parent = leaf.getParentPos(); Assert.assertEquals("get parent at 1,1 fail", convert, parent); leaf = new DhSectionPos((byte) 1, 2, 2); - convert = leaf.convertToDetailLevel((byte) 2); + convert = leaf.convertNewToDetailLevel((byte) 2); parent = leaf.getParentPos(); Assert.assertEquals("parent upscale fail", convert, parent); - convert = leaf.convertToDetailLevel((byte) 0); + convert = leaf.convertNewToDetailLevel((byte) 0); DhSectionPos childIndex = leaf.getChildByIndex(0); Assert.assertEquals("child detail fail", convert, childIndex); @@ -231,13 +231,13 @@ public class DhSectionPosTest DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); - originSectionPos = originSectionPos.convertToDetailLevel((byte) 1); + originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); Assert.assertEquals(new DhSectionPos((byte) 1, 0, 0), originSectionPos); - originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); - originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, 0, 0), originSectionPos); @@ -245,13 +245,13 @@ public class DhSectionPosTest DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); - sectionPos = sectionPos.convertToDetailLevel((byte) 1); + sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); Assert.assertEquals(new DhSectionPos((byte) 1, -5000, 2500), sectionPos); - sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -157, 78), sectionPos); - sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); Assert.assertEquals(new DhSectionPos(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, -1, 0), sectionPos); } @@ -263,19 +263,19 @@ public class DhSectionPosTest DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); // widths should be the same regardless of position in the world - originSectionPos = originSectionPos.convertToDetailLevel((byte) 1); + originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); - sectionPos = sectionPos.convertToDetailLevel((byte) 1); + sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); - originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); - sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); - originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); - sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); } @@ -285,19 +285,19 @@ public class DhSectionPosTest DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); - originSectionPos = originSectionPos.convertToDetailLevel((byte) 1); + originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); Assert.assertEquals(2, originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide); - sectionPos = sectionPos.convertToDetailLevel((byte) 1); + sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); Assert.assertEquals(2, sectionPos.getWidth((byte) 0).numberOfLodSectionsWide); - originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); Assert.assertEquals(64, originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide); - sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); Assert.assertEquals(64, sectionPos.getWidth((byte) 0).numberOfLodSectionsWide); - originSectionPos = originSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); Assert.assertEquals(4096, originSectionPos.getWidth((byte) 3).numberOfLodSectionsWide); - sectionPos = sectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); Assert.assertEquals(4096, sectionPos.getWidth((byte) 3).numberOfLodSectionsWide); } From 269b763b735501eb201f3f9b35ab5462c4db187d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 07:52:04 -0500 Subject: [PATCH 07/15] Add DhSectionPos.getNumberOfLodSectionsWide() --- .../coreapi/util/BitShiftUtil.java | 2 +- .../core/pos/DhSectionPos.java | 8 ++++ .../src/test/java/tests/DhSectionPosTest.java | 47 ++++++++++++++----- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/coreapi/util/BitShiftUtil.java b/api/src/main/java/com/seibel/distanthorizons/coreapi/util/BitShiftUtil.java index 9ad2e34f8..8bd3b2512 100644 --- a/api/src/main/java/com/seibel/distanthorizons/coreapi/util/BitShiftUtil.java +++ b/api/src/main/java/com/seibel/distanthorizons/coreapi/util/BitShiftUtil.java @@ -30,7 +30,7 @@ public class BitShiftUtil { /** * Equivalent to:
- * {@literal 1 << value0, }
+ * {@literal 1 << value, }
* 2^value,
* Math.pow(2, value)

* diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index b908d89ad..e7ecbb0a6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -189,6 +189,14 @@ public class DhSectionPos return new DhLodUnit(this.sectionDetailLevel, BitShiftUtil.powerOfTwo(offset)); } + public int getNumberOfLodSectionsWide() { return this.getNumberOfLodSectionsWide(this.sectionDetailLevel); } // TODO this always returns 1... + public int getNumberOfLodSectionsWide(byte returnDetailLevel) + { + LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); // TODO add something to the method name stating this + byte offset = (byte) (this.sectionDetailLevel - returnDetailLevel); + return BitShiftUtil.powerOfTwo(offset); + } + //==================// diff --git a/core/src/test/java/tests/DhSectionPosTest.java b/core/src/test/java/tests/DhSectionPosTest.java index 3d37e5239..37b0c7109 100644 --- a/core/src/test/java/tests/DhSectionPosTest.java +++ b/core/src/test/java/tests/DhSectionPosTest.java @@ -264,19 +264,30 @@ public class DhSectionPosTest // widths should be the same regardless of position in the world originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); + Assert.assertEquals(1, originSectionPos.getNumberOfLodSectionsWide()); + Assert.assertEquals(originSectionPos.getWidth().numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide()); + sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); + Assert.assertEquals(1, sectionPos.getNumberOfLodSectionsWide()); + Assert.assertEquals(sectionPos.getWidth().numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide()); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); + Assert.assertEquals(1, originSectionPos.getNumberOfLodSectionsWide()); + Assert.assertEquals(originSectionPos.getWidth().numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide()); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); + Assert.assertEquals(1, sectionPos.getNumberOfLodSectionsWide()); + Assert.assertEquals(sectionPos.getWidth().numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide()); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(1, originSectionPos.getWidth().numberOfLodSectionsWide); + Assert.assertEquals(1, originSectionPos.getNumberOfLodSectionsWide()); + Assert.assertEquals(originSectionPos.getWidth().numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide()); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(1, sectionPos.getWidth().numberOfLodSectionsWide); + Assert.assertEquals(1, sectionPos.getNumberOfLodSectionsWide()); + Assert.assertEquals(sectionPos.getWidth().numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide()); } @Test @@ -285,20 +296,32 @@ public class DhSectionPosTest DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); + originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + Assert.assertEquals(2, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); + sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, sectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + Assert.assertEquals(2, sectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(sectionPos.getWidth((byte) 0).numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide((byte) 0)); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + Assert.assertEquals(64, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, sectionPos.getWidth((byte) 0).numberOfLodSectionsWide); + Assert.assertEquals(64, sectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(sectionPos.getWidth((byte) 0).numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide((byte) 0)); + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(4096, originSectionPos.getWidth((byte) 3).numberOfLodSectionsWide); + Assert.assertEquals(4096, originSectionPos.getNumberOfLodSectionsWide((byte) 3)); + Assert.assertEquals(originSectionPos.getWidth((byte) 3).numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide((byte) 3)); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(4096, sectionPos.getWidth((byte) 3).numberOfLodSectionsWide); + Assert.assertEquals(4096, sectionPos.getNumberOfLodSectionsWide((byte) 3)); + Assert.assertEquals(sectionPos.getWidth((byte) 3).numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide((byte) 3)); } From 9a89731a59b4625ab7ba3e02c8b9b3147ebaff4d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 19:16:05 -0500 Subject: [PATCH 08/15] Add DhSectionPos getBlockWidth() and getWidthCountForLowerDetailedSection() --- .../HighDetailIncompleteFullDataSource.java | 2 +- .../LowDetailIncompleteFullDataSource.java | 12 +-- .../render/ColumnRenderSource.java | 2 +- .../FullDataToRenderDataTransformer.java | 8 +- .../core/pos/DhSectionPos.java | 25 ++--- .../core/util/objects/quadTree/QuadNode.java | 2 +- .../src/test/java/tests/DhSectionPosTest.java | 96 ++++++++++--------- 7 files changed, 77 insertions(+), 70 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java index 6ac6de517..5ced11d40 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java @@ -523,7 +523,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo DhLodPos basePos = this.sectionPos.getCorner(SPARSE_UNIT_DETAIL); DhLodPos dataPos = pos.getCorner(SPARSE_UNIT_DETAIL); - int coveredChunks = pos.getWidth(SPARSE_UNIT_DETAIL).numberOfLodSectionsWide; + int coveredChunks = pos.getWidthCountForLowerDetailedSection(SPARSE_UNIT_DETAIL); int sourceDataPerChunk = SPARSE_UNIT_SIZE >>> completeDataSource.getDataDetailLevel(); LodUtil.assertTrue((coveredChunks * sourceDataPerChunk) == CompleteFullDataSource.WIDTH); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java index b518316f8..8fa306dc2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java @@ -398,7 +398,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp LodUtil.assertTrue(offsetX >= 0 && offsetX < WIDTH && offsetZ >= 0 && offsetZ < WIDTH); int chunksPerData = 1 << (this.getDataDetailLevel() - HighDetailIncompleteFullDataSource.SPARSE_UNIT_DETAIL); - int dataSpan = this.sectionPos.getWidth(this.getDataDetailLevel()).numberOfLodSectionsWide; + int dataSpan = this.sectionPos.getWidthCountForLowerDetailedSection(this.getDataDetailLevel()); for (int xOffset = 0; xOffset < dataSpan; xOffset++) { @@ -419,7 +419,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp else { DhLodPos dataLodPos = pos.getSectionBBoxPos(); - int lowerSectionsPerData = this.sectionPos.getWidth(dataLodPos.detailLevel).numberOfLodSectionsWide; + int lowerSectionsPerData = this.sectionPos.getWidthCountForLowerDetailedSection(dataLodPos.detailLevel); if (dataLodPos.x % lowerSectionsPerData != 0 || dataLodPos.z % lowerSectionsPerData != 0) { return; @@ -452,7 +452,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp int offsetX = dataLodPos.x - thisLodPos.x; int offsetZ = dataLodPos.z - thisLodPos.z; - int dataWidth = this.sectionPos.getWidth(this.getDataDetailLevel()).numberOfLodSectionsWide; + int dataWidth = this.sectionPos.getWidthCountForLowerDetailedSection(this.getDataDetailLevel()); for (int xOffset = 0; xOffset < dataWidth; xOffset++) { @@ -465,7 +465,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp else { DhLodPos dataPos = pos.getSectionBBoxPos(); - int lowerSectionsPerData = this.sectionPos.getWidth(dataPos.detailLevel).numberOfLodSectionsWide; + int lowerSectionsPerData = this.sectionPos.getWidthCountForLowerDetailedSection(dataPos.detailLevel); if (dataPos.x % lowerSectionsPerData != 0 || dataPos.z % lowerSectionsPerData != 0) { return; @@ -495,7 +495,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp int offsetX = dataLodPos.x - thisLodPos.x; int offsetZ = dataLodPos.z - thisLodPos.z; - int dataWidth = this.sectionPos.getWidth(this.getDataDetailLevel()).numberOfLodSectionsWide; + int dataWidth = this.sectionPos.getWidthCountForLowerDetailedSection(this.getDataDetailLevel()); for (int xOffset = 0; xOffset < dataWidth; xOffset++) { @@ -508,7 +508,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp else { DhLodPos dataPos = pos.getSectionBBoxPos(); - int lowerSectionsPerData = this.sectionPos.getWidth(dataPos.detailLevel).numberOfLodSectionsWide; + int lowerSectionsPerData = this.sectionPos.getWidthCountForLowerDetailedSection(dataPos.detailLevel); if (dataPos.x % lowerSectionsPerData != 0 || dataPos.z % lowerSectionsPerData != 0) { return; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java index 0fc4ea570..fca21859b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java @@ -526,7 +526,7 @@ public class ColumnRenderSource stringBuilder.append(this.sectionPos); stringBuilder.append(LINE_DELIMITER); - int size = this.sectionPos.getWidth().numberOfLodSectionsWide; + int size = 1; for (int z = 0; z < size; z++) { for (int x = 0; x < size; x++) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java index 40e707746..bacfea010 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java @@ -135,9 +135,9 @@ public class FullDataToRenderDataTransformer int baseX = pos.getCorner().getCornerBlockPos().x; int baseZ = pos.getCorner().getCornerBlockPos().z; - for (int x = 0; x < pos.getWidth(dataDetail).numberOfLodSectionsWide; x++) + for (int x = 0; x < pos.getWidthCountForLowerDetailedSection(dataDetail); x++) { - for (int z = 0; z < pos.getWidth(dataDetail).numberOfLodSectionsWide; z++) + for (int z = 0; z < pos.getWidthCountForLowerDetailedSection(dataDetail); z++) { throwIfThreadInterrupted(); @@ -184,9 +184,9 @@ public class FullDataToRenderDataTransformer { int baseX = pos.getCorner().getCornerBlockPos().x; int baseZ = pos.getCorner().getCornerBlockPos().z; - for (int x = 0; x < pos.getWidth(dataDetail).numberOfLodSectionsWide; x++) + for (int x = 0; x < pos.getWidthCountForLowerDetailedSection(dataDetail); x++) { - for (int z = 0; z < pos.getWidth(dataDetail).numberOfLodSectionsWide; z++) + for (int z = 0; z < pos.getWidthCountForLowerDetailedSection(dataDetail); z++) { throwIfThreadInterrupted(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index e7ecbb0a6..57fff321c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -181,22 +181,25 @@ public class DhSectionPos this.sectionZ * BitShiftUtil.powerOfTwo(offset)); } - public DhLodUnit getWidth() { return this.getWidth(this.sectionDetailLevel); } // this always returns 1... - public DhLodUnit getWidth(byte returnDetailLevel) + /** + * A detail level of X lower than this section's detail level will return:
+ * 0 -> 1
+ * 1 -> 2
+ * 2 -> 4
+ * 3 -> 8
+ * etc. + * + * @return how many {@link DhSectionPos}'s at the given detail level it would take to span the width of this section. + */ + public int getWidthCountForLowerDetailedSection(byte returnDetailLevel) { LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); byte offset = (byte) (this.sectionDetailLevel - returnDetailLevel); - return new DhLodUnit(this.sectionDetailLevel, BitShiftUtil.powerOfTwo(offset)); - } - - public int getNumberOfLodSectionsWide() { return this.getNumberOfLodSectionsWide(this.sectionDetailLevel); } // TODO this always returns 1... - public int getNumberOfLodSectionsWide(byte returnDetailLevel) - { - LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); // TODO add something to the method name stating this - byte offset = (byte) (this.sectionDetailLevel - returnDetailLevel); return BitShiftUtil.powerOfTwo(offset); } + /** @return how wide this section is in blocks */ + public int getBlockWidth() { return BitShiftUtil.powerOfTwo(this.sectionDetailLevel); } //==================// @@ -261,7 +264,7 @@ public class DhSectionPos DhBlockPos2D thisMinBlockPos = this.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); DhBlockPos2D otherCornerBlockPos = otherPos.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); - int thisBlockWidth = this.getWidth().toBlockWidth() - 1; // minus 1 to account for zero based positional indexing + int thisBlockWidth = this.getBlockWidth() - 1; // minus 1 to account for zero based positional indexing DhBlockPos2D thisMaxBlockPos = new DhBlockPos2D(thisMinBlockPos.x + thisBlockWidth, thisMinBlockPos.z + thisBlockWidth); return thisMinBlockPos.x <= otherCornerBlockPos.x && otherCornerBlockPos.x <= thisMaxBlockPos.x && diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java index 8f4d2ba45..d3666a9cc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java @@ -180,7 +180,7 @@ public class QuadNode if (!this.sectionPos.contains(inputSectionPos)) { LOGGER.error((replaceValue ? "set " : "get ") + inputSectionPos + " center block: " + inputSectionPos.getCenter().getCornerBlockPos() + ", this pos: " + this.sectionPos + " this center block: " + this.sectionPos.getCenter().getCornerBlockPos()); - throw new IllegalArgumentException("Input section pos " + inputSectionPos + " outside of this quadNode's pos: " + this.sectionPos + ", this node's blockPos: " + this.sectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " block width: " + this.sectionPos.getWidth().toBlockWidth() + " input detail level: " + inputSectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " width: " + inputSectionPos.getWidth().toBlockWidth()); + throw new IllegalArgumentException("Input section pos " + inputSectionPos + " outside of this quadNode's pos: " + this.sectionPos + ", this node's blockPos: " + this.sectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " block width: " + this.sectionPos.getBlockWidth() + " input detail level: " + inputSectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " width: " + inputSectionPos.getBlockWidth()); } if (inputSectionPos.sectionDetailLevel > this.sectionPos.sectionDetailLevel) diff --git a/core/src/test/java/tests/DhSectionPosTest.java b/core/src/test/java/tests/DhSectionPosTest.java index 37b0c7109..2c305a3cf 100644 --- a/core/src/test/java/tests/DhSectionPosTest.java +++ b/core/src/test/java/tests/DhSectionPosTest.java @@ -256,40 +256,6 @@ public class DhSectionPosTest } - @Test - public void GetDefaultWidth() - { - DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); - DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); - - // widths should be the same regardless of position in the world - originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(1, originSectionPos.getNumberOfLodSectionsWide()); - Assert.assertEquals(originSectionPos.getWidth().numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide()); - - sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(1, sectionPos.getNumberOfLodSectionsWide()); - Assert.assertEquals(sectionPos.getWidth().numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide()); - - - originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(1, originSectionPos.getNumberOfLodSectionsWide()); - Assert.assertEquals(originSectionPos.getWidth().numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide()); - - sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(1, sectionPos.getNumberOfLodSectionsWide()); - Assert.assertEquals(sectionPos.getWidth().numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide()); - - - originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(1, originSectionPos.getNumberOfLodSectionsWide()); - Assert.assertEquals(originSectionPos.getWidth().numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide()); - - sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(1, sectionPos.getNumberOfLodSectionsWide()); - Assert.assertEquals(sectionPos.getWidth().numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide()); - - } @Test public void GetOffsetWidth() { @@ -297,32 +263,70 @@ public class DhSectionPosTest DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); + + // 1 -> 0 + byte returnDetailLevel = 0; originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); - Assert.assertEquals(originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(2, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, sectionPos.getNumberOfLodSectionsWide((byte) 0)); - Assert.assertEquals(sectionPos.getWidth((byte) 0).numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(2, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + + // 2 -> 1 + returnDetailLevel = 1; + originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 2); + Assert.assertEquals(2, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + + sectionPos = sectionPos.convertNewToDetailLevel((byte) 2); + Assert.assertEquals(2, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + + + + // Block -> 0 + returnDetailLevel = 0; originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); - Assert.assertEquals(originSectionPos.getWidth((byte) 0).numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(64, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, sectionPos.getNumberOfLodSectionsWide((byte) 0)); - Assert.assertEquals(sectionPos.getWidth((byte) 0).numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide((byte) 0)); + Assert.assertEquals(64, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + // Region -> 3 + returnDetailLevel = 3; originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(4096, originSectionPos.getNumberOfLodSectionsWide((byte) 3)); - Assert.assertEquals(originSectionPos.getWidth((byte) 3).numberOfLodSectionsWide, originSectionPos.getNumberOfLodSectionsWide((byte) 3)); + Assert.assertEquals(4096, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(4096, sectionPos.getNumberOfLodSectionsWide((byte) 3)); - Assert.assertEquals(sectionPos.getWidth((byte) 3).numberOfLodSectionsWide, sectionPos.getNumberOfLodSectionsWide((byte) 3)); + Assert.assertEquals(4096, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); } + @Test + public void GetBlockWidth() + { + DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); + DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); + + + Assert.assertEquals(1, originSectionPos.getBlockWidth()); + Assert.assertEquals(1, sectionPos.getBlockWidth()); + + originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); + Assert.assertEquals(2, originSectionPos.getBlockWidth()); + sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); + Assert.assertEquals(2, sectionPos.getBlockWidth()); + + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(64, originSectionPos.getBlockWidth()); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(64, sectionPos.getBlockWidth()); + + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(32768, originSectionPos.getBlockWidth()); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(32768, sectionPos.getBlockWidth()); + + } } From 96a39bce695394b12f3bbaa78a02bd672d111936 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 19:56:48 -0500 Subject: [PATCH 09/15] reformat DhBlockPos2D --- .../core/pos/DhBlockPos2D.java | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java index 7ea8b68e6..86a8b247f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java @@ -26,6 +26,13 @@ public class DhBlockPos2D public static final DhBlockPos2D ZERO = new DhBlockPos2D(0, 0); public final int x; public final int z; + + + + //==============// + // constructors // + //==============// + public DhBlockPos2D(int x, int z) { this.x = x; @@ -38,44 +45,40 @@ public class DhBlockPos2D this.z = blockPos.z; } - public DhBlockPos2D add(DhBlockPos2D other) - { - return new DhBlockPos2D(x + other.x, z + other.z); - } + public static DhBlockPos2D fromPos2D(Pos2D pos) { return new DhBlockPos2D(pos.x, pos.y); } - public DhBlockPos2D add(int offsetX, int offsetZ) - { - return new DhBlockPos2D(x + offsetX, z + offsetZ); - } - 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 MathUtil.pow2((long) x - other.x) + MathUtil.pow2((long) z - other.z); - } - public Pos2D toPos2D() - { - return new Pos2D(x, z); - } + //==========// + // mutators // + //==========// - public static DhBlockPos2D fromPos2D(Pos2D pos) - { - return new DhBlockPos2D(pos.x, pos.y); - } + public DhBlockPos2D add(DhBlockPos2D other) { return new DhBlockPos2D(this.x + other.x, this.z + other.z); } + + public DhBlockPos2D add(int offsetX, int offsetZ) { return new DhBlockPos2D(this.x + offsetX, this.z + offsetZ); } + + public DhBlockPos2D subtract(DhBlockPos2D other) { return new DhBlockPos2D(this.x - other.x, this.z - other.z); } + + public Pos2D toPos2D() { return new Pos2D(this.x, this.z); } + + + + //==============// + // calculations // + //==============// + + public double dist(DhBlockPos2D other) { return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.z - other.z, 2)); } + + public long distSquared(DhBlockPos2D other) { return MathUtil.pow2((long) this.x - other.x) + MathUtil.pow2((long) this.z - other.z); } + + + + //===========// + // overrides // + //===========// @Override - public String toString() - { - return "(" + x + ", " + z + ")"; - } + public String toString() { return "(" + this.x + ", " + this.z + ")"; } @Override public boolean equals(Object obj) @@ -83,15 +86,13 @@ public class DhBlockPos2D if (obj instanceof DhBlockPos2D) { DhBlockPos2D other = (DhBlockPos2D) obj; - return x == other.x && z == other.z; + return this.x == other.x && this.z == other.z; } + return false; } @Override - public int hashCode() - { - return Integer.hashCode(x) ^ Integer.hashCode(z); - } + public int hashCode() { return Integer.hashCode(this.x) ^ Integer.hashCode(this.z); } } From 4d863adac50f06341671271d47dd5d0d9ffa5b86 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 20:07:25 -0500 Subject: [PATCH 10/15] replace DhSectionPos getCenter() with getCenterBlockPos() --- .../fullDatafile/FullDataFileHandler.java | 1 - .../core/pos/DhBlockPos2D.java | 6 +- .../core/pos/DhSectionPos.java | 51 ++++++++--------- .../core/render/LodQuadTree.java | 2 +- .../core/render/RenderBufferHandler.java | 6 +- .../core/util/objects/quadTree/QuadNode.java | 2 +- .../src/test/java/tests/DhSectionPosTest.java | 56 ++++++++++++++----- 7 files changed, 78 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java index b892bc185..a3f4231bb 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java @@ -44,7 +44,6 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; -import java.util.function.Function; public class FullDataFileHandler implements IFullDataSourceProvider { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java index 86a8b247f..c6f8c1906 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos2D.java @@ -67,9 +67,11 @@ public class DhBlockPos2D // calculations // //==============// - public double dist(DhBlockPos2D other) { return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.z - other.z, 2)); } + public double dist(DhBlockPos2D other) { return this.dist(other.x, other.z); } + public double dist(int x, int z) { return Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.z - z, 2)); } - public long distSquared(DhBlockPos2D other) { return MathUtil.pow2((long) this.x - other.x) + MathUtil.pow2((long) this.z - other.z); } + public long distSquared(DhBlockPos2D other) { return this.distSquared(other.x, other.z); } + public long distSquared(int x, int z) { return MathUtil.pow2((long) this.x - x) + MathUtil.pow2((long) this.z - z); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 57fff321c..396d5c7eb 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -143,31 +143,6 @@ public class DhSectionPos // getters // //=========// - /** Returns the center for detail level 0 */ - public DhLodPos getCenter() { return this.getCenter((byte) 0); } // TODO why does this use detail level 0 instead of this object's detail level? - public DhLodPos getCenter(byte returnDetailLevel) - { - LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); - - if (returnDetailLevel == this.sectionDetailLevel) - { - return new DhLodPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); - } - - byte detailLevelOffset = (byte) (this.sectionDetailLevel - returnDetailLevel); - - // we can't get the center of the position at block level, only attempt to get the position offset for detail levels above 0 // TODO should this also apply to detail level 1 or is it fine? - int positionOffset = 0; - if (this.sectionDetailLevel != 1 || returnDetailLevel != 0) - { - positionOffset = BitShiftUtil.powerOfTwo(detailLevelOffset - 1); - } - - return new DhLodPos(returnDetailLevel, - (this.sectionX * BitShiftUtil.powerOfTwo(detailLevelOffset)) + positionOffset, - (this.sectionZ * BitShiftUtil.powerOfTwo(detailLevelOffset)) + positionOffset); - } - /** @return the corner with the smallest X and Z coordinate */ public DhLodPos getCorner() { return this.getCorner((byte) (this.sectionDetailLevel - 1)); } /** @return the corner with the smallest X and Z coordinate */ @@ -202,6 +177,32 @@ public class DhSectionPos public int getBlockWidth() { return BitShiftUtil.powerOfTwo(this.sectionDetailLevel); } + public DhBlockPos2D getCenterBlockPos() { return new DhBlockPos2D(this.getCenterBlockPosX(), this.getCenterBlockPosZ()); } + + public int getCenterBlockPosX() { return this.getCenterBlockPos(true); } + public int getCenterBlockPosZ() { return this.getCenterBlockPos(false); } + private int getCenterBlockPos(boolean returnX) + { + int centerBlockPos = returnX ? this.sectionX : this.sectionZ; + + if (this.sectionDetailLevel == 0) + { + // already at block detail level, no conversion necessary + return centerBlockPos; + } + + // we can't get the center of the position at block level, only attempt to get the position offset for detail levels above 0 + int positionOffset = 0; + if (this.sectionDetailLevel != 1) + { + positionOffset = BitShiftUtil.powerOfTwo(this.sectionDetailLevel - 1); + } + + return (centerBlockPos * BitShiftUtil.powerOfTwo(this.sectionDetailLevel)) + positionOffset; + } + + + //==================// // parent child pos // //==================// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index 0a81cc761..8caa1641e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -320,7 +320,7 @@ public class LodQuadTree extends QuadTree implements AutoClose * @param sectionPos section position * @return detail level of this section pos */ - public byte calculateExpectedDetailLevel(DhBlockPos2D playerPos, DhSectionPos sectionPos) { return this.getDetailLevelFromDistance(playerPos.dist(sectionPos.getCenter().getCenterBlockPos())); } + public byte calculateExpectedDetailLevel(DhBlockPos2D playerPos, DhSectionPos sectionPos) { return this.getDetailLevelFromDistance(playerPos.dist(sectionPos.getCenterBlockPosX(), sectionPos.getCenterBlockPosZ())); } private byte getDetailLevelFromDistance(double distance) { // special case, never drop the quality diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java index db50ae3fa..c4f51f256 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java @@ -118,13 +118,13 @@ public class RenderBufferHandler } } - Pos2D cPos = lodQuadTree.getCenterBlockPos().toPos2D(); + Pos2D cPos = this.lodQuadTree.getCenterBlockPos().toPos2D(); // Now that we have the axis directions, we can sort the render list Comparator farToNearComparator = (loadedBufferA, loadedBufferB) -> { - Pos2D aPos = loadedBufferA.pos.getCenter().getCenterBlockPos().toPos2D(); - Pos2D bPos = loadedBufferB.pos.getCenter().getCenterBlockPos().toPos2D(); + Pos2D aPos = loadedBufferA.pos.getCenterBlockPos().toPos2D(); + Pos2D bPos = loadedBufferB.pos.getCenterBlockPos().toPos2D(); if (true) { int aManhattanDistance = aPos.manhattanDist(cPos); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java index d3666a9cc..70aa58e97 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java @@ -179,7 +179,7 @@ public class QuadNode if (!this.sectionPos.contains(inputSectionPos)) { - LOGGER.error((replaceValue ? "set " : "get ") + inputSectionPos + " center block: " + inputSectionPos.getCenter().getCornerBlockPos() + ", this pos: " + this.sectionPos + " this center block: " + this.sectionPos.getCenter().getCornerBlockPos()); + LOGGER.error((replaceValue ? "set " : "get ") + inputSectionPos + " center block: " + inputSectionPos.getCenterBlockPos() + ", this pos: " + this.sectionPos + " this center block: " + this.sectionPos.getCenterBlockPos()); throw new IllegalArgumentException("Input section pos " + inputSectionPos + " outside of this quadNode's pos: " + this.sectionPos + ", this node's blockPos: " + this.sectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " block width: " + this.sectionPos.getBlockWidth() + " input detail level: " + inputSectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " width: " + inputSectionPos.getBlockWidth()); } diff --git a/core/src/test/java/tests/DhSectionPosTest.java b/core/src/test/java/tests/DhSectionPosTest.java index 2c305a3cf..ff2419d1b 100644 --- a/core/src/test/java/tests/DhSectionPosTest.java +++ b/core/src/test/java/tests/DhSectionPosTest.java @@ -130,17 +130,17 @@ public class DhSectionPosTest public void GetCenterTest() { DhSectionPos node = new DhSectionPos((byte) 1, 2303, 0); - DhLodPos centerNode = node.getCenter(); - DhLodPos expectedCenterNode = new DhLodPos((byte) 0, 4606, 0); - Assert.assertEquals("", expectedCenterNode, centerNode); + DhBlockPos2D centerBlockPos = node.getCenterBlockPos(); + DhBlockPos2D expectedCenterNode = new DhBlockPos2D(4606, 0); + Assert.assertEquals("", expectedCenterNode, centerBlockPos); node = new DhSectionPos((byte) 10, 0, 0); // 1024 blocks wide - centerNode = node.getCenter(); - expectedCenterNode = new DhLodPos((byte) 0, 1024 / 2, 1024 / 2); - Assert.assertEquals("", expectedCenterNode, centerNode); - + centerBlockPos = node.getCenterBlockPos(); + expectedCenterNode = new DhBlockPos2D(1024 / 2, 1024 / 2); + Assert.assertEquals("", expectedCenterNode, centerBlockPos); + } @Test @@ -150,11 +150,11 @@ public class DhSectionPosTest DhSectionPos inputPos = new DhSectionPos((byte) 0, 4606, 0); // width 1 block Assert.assertTrue(parentNode.contains(inputPos)); - DhLodPos parentCenter = parentNode.getCenter(); - DhLodPos inputCenter = inputPos.getCenter(); + DhBlockPos2D parentCenter = parentNode.getCenterBlockPos(); + DhBlockPos2D inputCenter = inputPos.getCenterBlockPos(); - Assert.assertEquals(new DhLodPos((byte) 0, 4606, 2), parentCenter); - Assert.assertEquals(new DhLodPos((byte) 0, 4606, 0), inputCenter); + Assert.assertEquals(new DhBlockPos2D(4606, 2), parentCenter); + Assert.assertEquals(new DhBlockPos2D(4606, 0), inputCenter); } @@ -273,7 +273,6 @@ public class DhSectionPosTest Assert.assertEquals(2, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); - // 2 -> 1 returnDetailLevel = 1; originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 2); @@ -283,7 +282,6 @@ public class DhSectionPosTest Assert.assertEquals(2, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); - // Block -> 0 returnDetailLevel = 0; originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); @@ -329,4 +327,36 @@ public class DhSectionPosTest Assert.assertEquals(32768, sectionPos.getBlockWidth()); } + + @Test + public void GetCenterBlockPos() + { + DhSectionPos originSectionPos = new DhSectionPos((byte) 0,0,0); + DhSectionPos sectionPos = new DhSectionPos((byte) 0,-10000,5000); + + + Assert.assertEquals(new DhBlockPos2D(0, 0), originSectionPos.getCenterBlockPos()); + Assert.assertEquals(new DhBlockPos2D(-10000, 5000), sectionPos.getCenterBlockPos()); + + + originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); + Assert.assertEquals(new DhBlockPos2D(0, 0), originSectionPos.getCenterBlockPos()); + sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); + Assert.assertEquals(new DhBlockPos2D(-10000, 5000), sectionPos.getCenterBlockPos()); + + + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(new DhBlockPos2D(32, 32), originSectionPos.getCenterBlockPos()); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); + Assert.assertEquals(new DhBlockPos2D(-10016, 5024), sectionPos.getCenterBlockPos()); + + + originSectionPos = originSectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(new DhBlockPos2D(16384, 16384), originSectionPos.getCenterBlockPos()); + sectionPos = sectionPos.convertNewToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL); + Assert.assertEquals(new DhBlockPos2D(-16384, 16384), sectionPos.getCenterBlockPos()); + + } + + } From 1c247e0da282e6e8557bb592d9b35b05918079eb Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 20:11:09 -0500 Subject: [PATCH 11/15] Rename DhSectionPos.getMinCornerLodPos() --- .../fullData/FullDataDownSampler.java | 4 ++-- .../sources/CompleteFullDataSource.java | 8 ++++---- .../HighDetailIncompleteFullDataSource.java | 12 ++++++------ .../LowDetailIncompleteFullDataSource.java | 18 +++++++++--------- .../dataObjects/render/ColumnRenderSource.java | 8 ++++---- .../ColumnRenderBufferBuilder.java | 2 +- .../FullDataToRenderDataTransformer.java | 8 ++++---- .../file/fullDatafile/FullDataFileHandler.java | 2 +- .../distanthorizons/core/pos/DhLodPos.java | 1 - .../distanthorizons/core/pos/DhSectionPos.java | 10 ++++------ 10 files changed, 35 insertions(+), 38 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java index 513f2594c..7969498cf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java @@ -115,7 +115,7 @@ public class FullDataDownSampler { return; } - DhLodPos trgOffset = trgPos.getCorner(target.getDataDetailLevel()); + DhLodPos trgOffset = trgPos.getMinCornerLodPos(target.getDataDetailLevel()); DhLodPos srcOffset = srcPos.getSectionBBoxPos().convertToDetailLevel(target.getDataDetailLevel()); int offsetX = trgOffset.x - srcOffset.x; int offsetZ = trgOffset.z - srcOffset.z; @@ -131,7 +131,7 @@ public class FullDataDownSampler int srcDataPerTrgData = 1 << detailDiff; int overlappedTrgDataSize = CompleteFullDataSource.WIDTH / srcDataPerTrgData; - DhLodPos trgOffset = trgPos.getCorner(target.getDataDetailLevel()); + DhLodPos trgOffset = trgPos.getMinCornerLodPos(target.getDataDetailLevel()); DhLodPos srcOffset = srcPos.getSectionBBoxPos().getCornerLodPos(target.getDataDetailLevel()); int offsetX = trgOffset.x - srcOffset.x; int offsetZ = trgOffset.z - srcOffset.z; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java index 38f32c24e..586648c87 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java @@ -281,7 +281,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu if (this.getDataDetailLevel() == LodUtil.BLOCK_DETAIL_LEVEL) { DhBlockPos2D chunkBlockPos = new DhBlockPos2D(chunkDataView.pos.x * LodUtil.CHUNK_WIDTH, chunkDataView.pos.z * LodUtil.CHUNK_WIDTH); - DhBlockPos2D blockOffset = chunkBlockPos.subtract(this.sectionPos.getCorner().getCornerBlockPos()); + DhBlockPos2D blockOffset = chunkBlockPos.subtract(this.sectionPos.getMinCornerLodPos().getCornerBlockPos()); LodUtil.assertTrue(blockOffset.x >= 0 && blockOffset.x < WIDTH && blockOffset.z >= 0 && blockOffset.z < WIDTH); this.isEmpty = false; @@ -304,7 +304,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu int dataPerFull = 1 << this.getDataDetailLevel(); int fullSize = LodUtil.CHUNK_WIDTH / dataPerFull; DhLodPos dataOffset = chunkDataView.getLodPos().getCornerLodPos(this.getDataDetailLevel()); - DhLodPos baseOffset = this.sectionPos.getCorner(this.getDataDetailLevel()); + DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); int offsetX = dataOffset.x - baseOffset.x; int offsetZ = dataOffset.z - baseOffset.z; @@ -329,7 +329,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu return; } - DhLodPos baseOffset = this.sectionPos.getCorner(this.getDataDetailLevel()); + DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); DhLodPos dataOffset = chunkDataView.getLodPos().convertToDetailLevel(this.getDataDetailLevel()); int offsetX = dataOffset.x - baseOffset.x; @@ -428,7 +428,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu DhSectionPos lowerSectPos = subData.sectionPos; byte detailDiff = (byte) (this.sectionPos.sectionDetailLevel - subData.sectionPos.sectionDetailLevel); byte targetDataDetail = this.getDataDetailLevel(); - DhLodPos minDataPos = this.sectionPos.getCorner(targetDataDetail); + DhLodPos minDataPos = this.sectionPos.getMinCornerLodPos(targetDataDetail); if (detailDiff <= SECTION_SIZE_OFFSET) { int count = 1 << detailDiff; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java index 5ced11d40..4ca3c4600 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java @@ -104,7 +104,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo this.dataPointsPerSection = SECTION_SIZE / this.sectionCount; this.sparseData = new FullDataArrayAccessor[this.sectionCount * this.sectionCount]; - this.chunkPos = sectionPos.getCorner(SPARSE_UNIT_DETAIL); + this.chunkPos = sectionPos.getMinCornerLodPos(SPARSE_UNIT_DETAIL); this.mapping = new FullDataPointIdMap(sectionPos); } @@ -119,7 +119,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo LodUtil.assertTrue(this.sectionCount * this.sectionCount == data.length); this.sparseData = data; - this.chunkPos = sectionPos.getCorner(SPARSE_UNIT_DETAIL); + this.chunkPos = sectionPos.getMinCornerLodPos(SPARSE_UNIT_DETAIL); this.isEmpty = false; this.mapping = mapping; } @@ -520,8 +520,8 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo DhSectionPos pos = completeDataSource.getSectionPos(); this.isEmpty = false; - DhLodPos basePos = this.sectionPos.getCorner(SPARSE_UNIT_DETAIL); - DhLodPos dataPos = pos.getCorner(SPARSE_UNIT_DETAIL); + DhLodPos basePos = this.sectionPos.getMinCornerLodPos(SPARSE_UNIT_DETAIL); + DhLodPos dataPos = pos.getMinCornerLodPos(SPARSE_UNIT_DETAIL); int coveredChunks = pos.getWidthCountForLowerDetailedSection(SPARSE_UNIT_DETAIL); int sourceDataPerChunk = SPARSE_UNIT_SIZE >>> completeDataSource.getDataDetailLevel(); @@ -547,8 +547,8 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo DhSectionPos pos = sparseDataSource.getSectionPos(); this.isEmpty = false; - DhLodPos basePos = this.sectionPos.getCorner(SPARSE_UNIT_DETAIL); - DhLodPos dataPos = pos.getCorner(SPARSE_UNIT_DETAIL); + DhLodPos basePos = this.sectionPos.getMinCornerLodPos(SPARSE_UNIT_DETAIL); + DhLodPos dataPos = pos.getMinCornerLodPos(SPARSE_UNIT_DETAIL); int offsetX = dataPos.x - basePos.x; int offsetZ = dataPos.z - basePos.z; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java index 8fa306dc2..799d4518e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java @@ -329,7 +329,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp return; } - DhLodPos baseOffset = this.sectionPos.getCorner(this.getDataDetailLevel()); + DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); DhLodPos dataOffset = data.getLodPos().convertToDetailLevel(this.getDataDetailLevel()); int offsetX = dataOffset.x - baseOffset.x; int offsetZ = dataOffset.z - baseOffset.z; @@ -384,14 +384,14 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp private void sampleFrom(HighDetailIncompleteFullDataSource sparseSource) { - DhLodPos thisLodPos = this.sectionPos.getCorner(this.getDataDetailLevel()); + DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); DhSectionPos pos = sparseSource.getSectionPos(); this.isEmpty = false; if (this.getDataDetailLevel() > this.sectionPos.sectionDetailLevel) { - DhLodPos dataLodPos = pos.getCorner(this.getDataDetailLevel()); + DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel()); int offsetX = dataLodPos.x - thisLodPos.x; int offsetZ = dataLodPos.z - thisLodPos.z; @@ -447,8 +447,8 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp if (this.getDataDetailLevel() > this.sectionPos.sectionDetailLevel) // TODO what does this mean? { - DhLodPos thisLodPos = this.sectionPos.getCorner(this.getDataDetailLevel()); - DhLodPos dataLodPos = pos.getCorner(this.getDataDetailLevel()); + DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); + DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel()); int offsetX = dataLodPos.x - thisLodPos.x; int offsetZ = dataLodPos.z - thisLodPos.z; @@ -472,7 +472,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp } - DhLodPos basePos = this.sectionPos.getCorner(this.getDataDetailLevel()); + DhLodPos basePos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); dataPos = dataPos.convertToDetailLevel(this.getDataDetailLevel()); int offsetX = dataPos.x - basePos.x; int offsetZ = dataPos.z - basePos.z; @@ -490,8 +490,8 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp if (this.getDataDetailLevel() > this.sectionPos.sectionDetailLevel) { - DhLodPos thisLodPos = this.sectionPos.getCorner(this.getDataDetailLevel()); - DhLodPos dataLodPos = pos.getCorner(this.getDataDetailLevel()); + DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); + DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel()); int offsetX = dataLodPos.x - thisLodPos.x; int offsetZ = dataLodPos.z - thisLodPos.z; @@ -515,7 +515,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp } - DhLodPos basePos = this.sectionPos.getCorner(this.getDataDetailLevel()); + DhLodPos basePos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); dataPos = dataPos.convertToDetailLevel(this.getDataDetailLevel()); int offsetX = dataPos.x - basePos.x; int offsetZ = dataPos.z - basePos.z; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java index fca21859b..9b9d1a8c6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java @@ -312,8 +312,8 @@ public class ColumnRenderSource final DhSectionPos renderSourcePos = this.getSectionPos(); - final int sourceBlockX = renderSourcePos.getCorner().getCornerBlockPos().x; - final int sourceBlockZ = renderSourcePos.getCorner().getCornerBlockPos().z; + final int sourceBlockX = renderSourcePos.getMinCornerLodPos().getCornerBlockPos().x; + final int sourceBlockZ = renderSourcePos.getMinCornerLodPos().getCornerBlockPos().z; // offset between the incoming chunk data and this render source final int blockOffsetX = (chunkDataView.pos.x * LodUtil.CHUNK_WIDTH) - sourceBlockX; @@ -365,7 +365,7 @@ public class ColumnRenderSource this.markNotEmpty(); // multiple chunk data points converting to 1 column data point DhLodPos dataCornerPos = chunkDataView.getLodPos().getCornerLodPos(chunkDataView.detailLevel); - DhLodPos sourceCornerPos = renderSourcePos.getCorner(this.getDataDetail()); + DhLodPos sourceCornerPos = renderSourcePos.getMinCornerLodPos(this.getDataDetail()); DhLodPos sourceStartingChangePos = dataCornerPos.convertToDetailLevel(this.getDataDetail()); int relStartX = Math.floorMod(sourceStartingChangePos.x, this.getWidthInDataPoints()); int relStartZ = Math.floorMod(sourceStartingChangePos.z, this.getWidthInDataPoints()); @@ -394,7 +394,7 @@ public class ColumnRenderSource { // The entire chunk is being converted to a single column data point, possibly. DhLodPos dataCornerPos = chunkDataView.getLodPos().getCornerLodPos(chunkDataView.detailLevel); - DhLodPos sourceCornerPos = renderSourcePos.getCorner(this.getDataDetail()); + DhLodPos sourceCornerPos = renderSourcePos.getMinCornerLodPos(this.getDataDetail()); DhLodPos sourceStartingChangePos = dataCornerPos.convertToDetailLevel(this.getDataDetail()); int chunksPerColumn = sourceStartingChangePos.getWidthAtDetail(chunkDataView.getLodPos().detailLevel); if (chunkDataView.getLodPos().x % chunksPerColumn != 0 || chunkDataView.getLodPos().z % chunksPerColumn != 0) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java index 168c3e283..a5b25e158 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java @@ -125,7 +125,7 @@ public class ColumnRenderBufferBuilder if (buffer == null) { - buffer = new ColumnRenderBuffer(new DhBlockPos(renderSource.sectionPos.getCorner().getCornerBlockPos(), clientLevel.getMinY()), renderSource.sectionPos); + buffer = new ColumnRenderBuffer(new DhBlockPos(renderSource.sectionPos.getMinCornerLodPos().getCornerBlockPos(), clientLevel.getMinY()), renderSource.sectionPos); } try diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java index bacfea010..1438996ab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java @@ -132,8 +132,8 @@ public class FullDataToRenderDataTransformer if (dataDetail == columnSource.getDataDetail()) { - int baseX = pos.getCorner().getCornerBlockPos().x; - int baseZ = pos.getCorner().getCornerBlockPos().z; + int baseX = pos.getMinCornerLodPos().getCornerBlockPos().x; + int baseZ = pos.getMinCornerLodPos().getCornerBlockPos().z; for (int x = 0; x < pos.getWidthCountForLowerDetailedSection(dataDetail); x++) { @@ -182,8 +182,8 @@ public class FullDataToRenderDataTransformer if (dataDetail == columnSource.getDataDetail()) { - int baseX = pos.getCorner().getCornerBlockPos().x; - int baseZ = pos.getCorner().getCornerBlockPos().z; + int baseX = pos.getMinCornerLodPos().getCornerBlockPos().x; + int baseZ = pos.getMinCornerLodPos().getCornerBlockPos().z; for (int x = 0; x < pos.getWidthCountForLowerDetailedSection(dataDetail); x++) { for (int z = 0; z < pos.getWidthCountForLowerDetailedSection(dataDetail); z++) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java index a3f4231bb..1b3f4a4d8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java @@ -232,7 +232,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider outerLoop: while (--sectionDetail >= this.minDetailLevel) { - DhLodPos minPos = posAreaToGet.getCorner().getCornerLodPos(sectionDetail); + DhLodPos minPos = posAreaToGet.getMinCornerLodPos().getCornerLodPos(sectionDetail); int count = posAreaToGet.getSectionBBoxPos().getWidthAtDetail(sectionDetail); for (int xOffset = 0; xOffset < count; xOffset++) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java index f3aa7df76..bc2b38426 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java @@ -51,7 +51,6 @@ public class DhLodPos implements Comparable - //=========// // getters // //=========// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 396d5c7eb..77e2646a1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -144,9 +144,9 @@ public class DhSectionPos //=========// /** @return the corner with the smallest X and Z coordinate */ - public DhLodPos getCorner() { return this.getCorner((byte) (this.sectionDetailLevel - 1)); } + public DhLodPos getMinCornerLodPos() { return this.getMinCornerLodPos((byte) (this.sectionDetailLevel - 1)); } /** @return the corner with the smallest X and Z coordinate */ - public DhLodPos getCorner(byte returnDetailLevel) + public DhLodPos getMinCornerLodPos(byte returnDetailLevel) { LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); @@ -256,14 +256,12 @@ public class DhSectionPos // comparisons // //=============// - /** NOTE: This does not consider yOffset! */ public boolean overlaps(DhSectionPos other) { return this.getSectionBBoxPos().overlapsExactly(other.getSectionBBoxPos()); } - /** NOTE: This does not consider yOffset! */ public boolean contains(DhSectionPos otherPos) { - DhBlockPos2D thisMinBlockPos = this.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); - DhBlockPos2D otherCornerBlockPos = otherPos.getCorner(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); + DhBlockPos2D thisMinBlockPos = this.getMinCornerLodPos(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); + DhBlockPos2D otherCornerBlockPos = otherPos.getMinCornerLodPos(LodUtil.BLOCK_DETAIL_LEVEL).getCornerBlockPos(); int thisBlockWidth = this.getBlockWidth() - 1; // minus 1 to account for zero based positional indexing DhBlockPos2D thisMaxBlockPos = new DhBlockPos2D(thisMinBlockPos.x + thisBlockWidth, thisMinBlockPos.z + thisBlockWidth); From db58aa117a828eeab28ddd9fd77561b1d3e5c6ed Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 20:19:02 -0500 Subject: [PATCH 12/15] Minor QuadTree refactor --- .../core/util/objects/quadTree/QuadTree.java | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java index 9913d3905..c372fd203 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java @@ -119,45 +119,45 @@ public class QuadTree /** @param runBoundaryChecks should only ever be set to true internally for removing out of bound nodes */ protected final QuadNode getOrSetNode(DhSectionPos pos, boolean setNewValue, T newValue, boolean runBoundaryChecks) throws IndexOutOfBoundsException { - if (!runBoundaryChecks || this.isSectionPosInBounds(pos)) - { - DhSectionPos rootPos = pos.convertNewToDetailLevel(this.treeMinDetailLevel); - int ringListPosX = rootPos.sectionX; - int ringListPosZ = rootPos.sectionZ; - - QuadNode topQuadNode = this.topRingList.get(ringListPosX, ringListPosZ); - if (topQuadNode == null) - { - if (!setNewValue) - { - return null; - } - - topQuadNode = new QuadNode(rootPos, this.treeMaxDetailLevel); - boolean successfullyAdded = this.topRingList.set(ringListPosX, ringListPosZ, topQuadNode); - LodUtil.assertTrue(successfullyAdded, "Failed to add top quadTree node at position: " + rootPos); - } - - if (!topQuadNode.sectionPos.contains(pos)) - { - LodUtil.assertNotReach("failed to get a root node that contains the input position: " + pos + " root node pos: " + topQuadNode.sectionPos); - } - - - QuadNode returnNode = topQuadNode.getNode(pos); - if (setNewValue) - { - topQuadNode.setValue(pos, newValue); - } - return returnNode; - } - else + if (runBoundaryChecks && !this.isSectionPosInBounds(pos)) { int radius = this.diameterInBlocks() / 2; DhBlockPos2D minPos = this.getCenterBlockPos().add(new DhBlockPos2D(-radius, -radius)); DhBlockPos2D maxPos = this.getCenterBlockPos().add(new DhBlockPos2D(radius, radius)); throw new IndexOutOfBoundsException("QuadTree GetOrSet failed. Position out of bounds, min pos: " + minPos + ", max pos: " + maxPos + ", min detail level: " + this.treeMaxDetailLevel + ", max detail level: " + this.treeMinDetailLevel + ". Given Position: " + pos + " = block pos: " + pos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL)); } + + + + DhSectionPos rootPos = pos.convertNewToDetailLevel(this.treeMinDetailLevel); + int ringListPosX = rootPos.sectionX; + int ringListPosZ = rootPos.sectionZ; + + QuadNode topQuadNode = this.topRingList.get(ringListPosX, ringListPosZ); + if (topQuadNode == null) + { + if (!setNewValue) + { + return null; + } + + topQuadNode = new QuadNode(rootPos, this.treeMaxDetailLevel); + boolean successfullyAdded = this.topRingList.set(ringListPosX, ringListPosZ, topQuadNode); + LodUtil.assertTrue(successfullyAdded, "Failed to add top quadTree node at position: " + rootPos); + } + + if (!topQuadNode.sectionPos.contains(pos)) + { + LodUtil.assertNotReach("failed to get a root node that contains the input position: " + pos + " root node pos: " + topQuadNode.sectionPos); + } + + + QuadNode returnNode = topQuadNode.getNode(pos); + if (setNewValue) + { + topQuadNode.setValue(pos, newValue); + } + return returnNode; } public boolean isSectionPosInBounds(DhSectionPos testPos) From 2cee805645bb8c5a01471f650445f4c4627974ec Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 14 Sep 2023 22:04:52 -0500 Subject: [PATCH 13/15] Optimize some DhSectionPos via mutating the pos and removing duplicate DhLodPos allocations --- .../fullData/FullDataDownSampler.java | 16 +++++---- .../accessor/ChunkSizedFullDataAccessor.java | 16 +++++---- .../sources/CompleteFullDataSource.java | 18 +++++----- .../HighDetailIncompleteFullDataSource.java | 4 +-- .../LowDetailIncompleteFullDataSource.java | 14 ++++---- .../render/ColumnRenderSource.java | 30 ++++++++--------- .../fullDatafile/FullDataFileHandler.java | 14 ++++---- .../file/fullDatafile/FullDataMetaFile.java | 2 +- .../GeneratedFullDataFileHandler.java | 2 +- .../file/renderfile/RenderDataMetaFile.java | 7 ++-- .../renderfile/RenderSourceFileHandler.java | 12 ++++--- .../core/level/ClientLevelModule.java | 6 ++-- .../core/level/DhServerLevel.java | 5 +-- .../distanthorizons/core/pos/DhLodPos.java | 9 +++-- .../core/pos/DhSectionPos.java | 33 ++++++++++++++++++- .../core/util/objects/quadTree/QuadTree.java | 1 + 16 files changed, 116 insertions(+), 73 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java index 7969498cf..c99e77597 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java @@ -47,15 +47,17 @@ public class FullDataDownSampler ArrayList> futures; DhLodPos basePos = target.getSectionPos().getSectionBBoxPos().getCornerLodPos(CompleteFullDataSource.SECTION_SIZE_OFFSET); + + if (sectionSizeNeeded <= CompleteFullDataSource.SECTION_SIZE_OFFSET) { futures = new ArrayList<>(sectionSizeNeeded * sectionSizeNeeded); - for (int ox = 0; ox < sectionSizeNeeded; ox++) + for (int xOffset = 0; xOffset < sectionSizeNeeded; xOffset++) { - for (int oz = 0; oz < sectionSizeNeeded; oz++) + for (int zOffset = 0; zOffset < sectionSizeNeeded; zOffset++) { CompletableFuture future = provider.readAsync(new DhSectionPos( - CompleteFullDataSource.SECTION_SIZE_OFFSET, basePos.x + ox, basePos.z + oz)); + CompleteFullDataSource.SECTION_SIZE_OFFSET, basePos.x + xOffset, basePos.z + zOffset)); future = future.whenComplete((source, ex) -> { if (ex == null && source != null && source instanceof CompleteFullDataSource) { @@ -74,12 +76,12 @@ public class FullDataDownSampler { futures = new ArrayList<>(CompleteFullDataSource.WIDTH * CompleteFullDataSource.WIDTH); int multiplier = sectionSizeNeeded / CompleteFullDataSource.WIDTH; - for (int ox = 0; ox < CompleteFullDataSource.WIDTH; ox++) + for (int xOffset = 0; xOffset < CompleteFullDataSource.WIDTH; xOffset++) { - for (int oz = 0; oz < CompleteFullDataSource.WIDTH; oz++) + for (int zOffset = 0; zOffset < CompleteFullDataSource.WIDTH; zOffset++) { CompletableFuture future = provider.readAsync(new DhSectionPos( - CompleteFullDataSource.SECTION_SIZE_OFFSET, basePos.x + ox * multiplier, basePos.z + oz * multiplier)); + CompleteFullDataSource.SECTION_SIZE_OFFSET, basePos.x + xOffset * multiplier, basePos.z + zOffset * multiplier)); future = future.whenComplete((source, ex) -> { if (ex == null && source != null && source instanceof CompleteFullDataSource) { @@ -99,7 +101,7 @@ public class FullDataDownSampler public static void downSample(CompleteFullDataSource target, CompleteFullDataSource source) { - LodUtil.assertTrue(target.getSectionPos().overlaps(source.getSectionPos())); + LodUtil.assertTrue(target.getSectionPos().overlapsExactly(source.getSectionPos())); LodUtil.assertTrue(target.getDataDetailLevel() > source.getDataDetailLevel()); byte detailDiff = (byte) (target.getDataDetailLevel() - source.getDataDetailLevel()); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java index 5f6fb61b5..350fe155e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java @@ -20,7 +20,6 @@ package com.seibel.distanthorizons.core.dataObjects.fullData.accessor; import com.seibel.distanthorizons.core.pos.DhChunkPos; -import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.dataObjects.fullData.FullDataPointIdMap; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.util.FullDataPointUtil; @@ -34,19 +33,22 @@ import com.seibel.distanthorizons.core.util.LodUtil; */ public class ChunkSizedFullDataAccessor extends FullDataArrayAccessor { - public final DhChunkPos pos; + public final DhChunkPos chunkPos; + public final DhSectionPos sectionPos; + // TODO replace this var with LodUtil.BLOCK_DETAIL_LEVEL public final byte detailLevel = LodUtil.BLOCK_DETAIL_LEVEL; - public ChunkSizedFullDataAccessor(DhChunkPos pos) + public ChunkSizedFullDataAccessor(DhChunkPos chunkPos) { - super(new FullDataPointIdMap(new DhSectionPos(pos)), + super(new FullDataPointIdMap(new DhSectionPos(chunkPos)), new long[LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH][0], LodUtil.CHUNK_WIDTH); - this.pos = pos; + this.chunkPos = chunkPos; + this.sectionPos = new DhSectionPos(LodUtil.CHUNK_DETAIL_LEVEL, this.chunkPos.x, this.chunkPos.z); } @@ -68,9 +70,9 @@ public class ChunkSizedFullDataAccessor extends FullDataArrayAccessor public long emptyCount() { return (LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH) - this.nonEmptyCount(); } - public DhLodPos getLodPos() { return new DhLodPos(LodUtil.CHUNK_DETAIL_LEVEL, this.pos.x, this.pos.z); } + public DhSectionPos getSectionPos() { return this.sectionPos; } @Override - public String toString() { return this.pos + " " + this.nonEmptyCount(); } + public String toString() { return this.chunkPos + " " + this.nonEmptyCount(); } } \ No newline at end of file diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java index 586648c87..dbf5b573c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java @@ -277,10 +277,10 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu @Override public void update(ChunkSizedFullDataAccessor chunkDataView) { - LodUtil.assertTrue(this.sectionPos.getSectionBBoxPos().overlapsExactly(chunkDataView.getLodPos())); + LodUtil.assertTrue(this.sectionPos.overlapsExactly(chunkDataView.getSectionPos())); if (this.getDataDetailLevel() == LodUtil.BLOCK_DETAIL_LEVEL) { - DhBlockPos2D chunkBlockPos = new DhBlockPos2D(chunkDataView.pos.x * LodUtil.CHUNK_WIDTH, chunkDataView.pos.z * LodUtil.CHUNK_WIDTH); + DhBlockPos2D chunkBlockPos = new DhBlockPos2D(chunkDataView.chunkPos.x * LodUtil.CHUNK_WIDTH, chunkDataView.chunkPos.z * LodUtil.CHUNK_WIDTH); DhBlockPos2D blockOffset = chunkBlockPos.subtract(this.sectionPos.getMinCornerLodPos().getCornerBlockPos()); LodUtil.assertTrue(blockOffset.x >= 0 && blockOffset.x < WIDTH && blockOffset.z >= 0 && blockOffset.z < WIDTH); this.isEmpty = false; @@ -303,7 +303,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu { int dataPerFull = 1 << this.getDataDetailLevel(); int fullSize = LodUtil.CHUNK_WIDTH / dataPerFull; - DhLodPos dataOffset = chunkDataView.getLodPos().getCornerLodPos(this.getDataDetailLevel()); + DhLodPos dataOffset = chunkDataView.getSectionPos().getMinCornerLodPos(this.getDataDetailLevel()); DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); int offsetX = dataOffset.x - baseOffset.x; @@ -324,16 +324,16 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu { //FIXME: TEMPORARY int chunkPerFull = 1 << (this.getDataDetailLevel() - LodUtil.CHUNK_DETAIL_LEVEL); - if (chunkDataView.pos.x % chunkPerFull != 0 || chunkDataView.pos.z % chunkPerFull != 0) + if (chunkDataView.chunkPos.x % chunkPerFull != 0 || chunkDataView.chunkPos.z % chunkPerFull != 0) { return; } DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); - DhLodPos dataOffset = chunkDataView.getLodPos().convertToDetailLevel(this.getDataDetailLevel()); + DhSectionPos dataOffset = chunkDataView.getSectionPos().convertNewToDetailLevel(this.getDataDetailLevel()); - int offsetX = dataOffset.x - baseOffset.x; - int offsetZ = dataOffset.z - baseOffset.z; + int offsetX = dataOffset.sectionX - baseOffset.x; + int offsetZ = dataOffset.sectionZ - baseOffset.z; LodUtil.assertTrue(offsetX >= 0 && offsetX < WIDTH && offsetZ >= 0 && offsetZ < WIDTH); this.isEmpty = false; @@ -356,7 +356,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu /** Returns whether data at the given posToWrite can effect the target region file at posToTest. */ public static boolean firstDataPosCanAffectSecond(DhSectionPos posToWrite, DhSectionPos posToTest) { - if (!posToWrite.overlaps(posToTest)) + if (!posToWrite.overlapsExactly(posToTest)) { // the testPosition is outside the writePosition return false; @@ -418,7 +418,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu public void updateFromLowerCompleteSource(CompleteFullDataSource subData) { - LodUtil.assertTrue(this.sectionPos.overlaps(subData.sectionPos)); + LodUtil.assertTrue(this.sectionPos.overlapsExactly(subData.sectionPos)); LodUtil.assertTrue(subData.sectionPos.sectionDetailLevel < this.sectionPos.sectionDetailLevel); if (!firstDataPosCanAffectSecond(this.sectionPos, subData.sectionPos)) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java index 4ca3c4600..5d0e76eca 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java @@ -456,7 +456,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo @Override public void update(ChunkSizedFullDataAccessor chunkDataView) { - int arrayOffset = this.calculateOffset(chunkDataView.pos.x, chunkDataView.pos.z); + int arrayOffset = this.calculateOffset(chunkDataView.chunkPos.x, chunkDataView.chunkPos.z); FullDataArrayAccessor newArray = new FullDataArrayAccessor(this.mapping, new long[this.dataPointsPerSection * this.dataPointsPerSection][], this.dataPointsPerSection); if (this.getDataDetailLevel() == chunkDataView.detailLevel) { @@ -489,7 +489,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo { DhSectionPos pos = fullDataSource.getSectionPos(); LodUtil.assertTrue(pos.sectionDetailLevel < this.sectionPos.sectionDetailLevel); - LodUtil.assertTrue(pos.overlaps(this.sectionPos)); + LodUtil.assertTrue(pos.overlapsExactly(this.sectionPos)); if (fullDataSource.isEmpty()) { return; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java index 799d4518e..9a43898ba 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java @@ -318,21 +318,21 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp @Override public void update(ChunkSizedFullDataAccessor data) { - LodUtil.assertTrue(this.sectionPos.getSectionBBoxPos().overlapsExactly(data.getLodPos())); + LodUtil.assertTrue(this.sectionPos.overlapsExactly(data.getSectionPos())); if (this.getDataDetailLevel() >= 4) { //FIXME: TEMPORARY int chunkPerFull = 1 << (this.getDataDetailLevel() - 4); - if (data.pos.x % chunkPerFull != 0 || data.pos.z % chunkPerFull != 0) + if (data.chunkPos.x % chunkPerFull != 0 || data.chunkPos.z % chunkPerFull != 0) { return; } DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); - DhLodPos dataOffset = data.getLodPos().convertToDetailLevel(this.getDataDetailLevel()); - int offsetX = dataOffset.x - baseOffset.x; - int offsetZ = dataOffset.z - baseOffset.z; + DhSectionPos dataOffset = data.getSectionPos().convertNewToDetailLevel(this.getDataDetailLevel()); + int offsetX = dataOffset.sectionX - baseOffset.x; + int offsetZ = dataOffset.sectionZ - baseOffset.z; LodUtil.assertTrue(offsetX >= 0 && offsetX < WIDTH && offsetZ >= 0 && offsetZ < WIDTH); this.isEmpty = false; @@ -354,7 +354,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp { DhSectionPos pos = fullDataSource.getSectionPos(); LodUtil.assertTrue(pos.sectionDetailLevel < this.sectionPos.sectionDetailLevel); - LodUtil.assertTrue(pos.overlaps(this.sectionPos)); + LodUtil.assertTrue(pos.overlapsExactly(this.sectionPos)); if (fullDataSource.isEmpty()) { @@ -572,7 +572,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp public static boolean neededForPosition(DhSectionPos posToWrite, DhSectionPos posToTest) { - if (!posToWrite.overlaps(posToTest)) + if (!posToWrite.overlapsExactly(posToTest)) return false; if (posToTest.sectionDetailLevel > posToWrite.sectionDetailLevel) return false; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java index 9b9d1a8c6..9b42652d9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java @@ -308,7 +308,7 @@ public class ColumnRenderSource */ public boolean updateWithChunkData(ChunkSizedFullDataAccessor chunkDataView, IDhClientLevel level) { - final String errorMessagePrefix = "Unable to complete fastWrite for RenderSource pos: [" + this.sectionPos + "] and chunk pos: [" + chunkDataView.pos + "]. Error:"; + final String errorMessagePrefix = "Unable to complete fastWrite for RenderSource pos: [" + this.sectionPos + "] and chunk pos: [" + chunkDataView.chunkPos + "]. Error:"; final DhSectionPos renderSourcePos = this.getSectionPos(); @@ -316,8 +316,8 @@ public class ColumnRenderSource final int sourceBlockZ = renderSourcePos.getMinCornerLodPos().getCornerBlockPos().z; // offset between the incoming chunk data and this render source - final int blockOffsetX = (chunkDataView.pos.x * LodUtil.CHUNK_WIDTH) - sourceBlockX; - final int blockOffsetZ = (chunkDataView.pos.z * LodUtil.CHUNK_WIDTH) - sourceBlockZ; + final int blockOffsetX = (chunkDataView.chunkPos.x * LodUtil.CHUNK_WIDTH) - sourceBlockX; + final int blockOffsetZ = (chunkDataView.chunkPos.z * LodUtil.CHUNK_WIDTH) - sourceBlockZ; final int sourceDataPointBlockWidth = BitShiftUtil.powerOfTwo(this.getDataDetail()); @@ -360,27 +360,27 @@ public class ColumnRenderSource } this.fillDebugFlag(blockOffsetX, blockOffsetZ, LodUtil.CHUNK_WIDTH, LodUtil.CHUNK_WIDTH, ColumnRenderSource.DebugSourceFlag.DIRECT); } - else if (chunkDataView.detailLevel < this.getDataDetail() && this.getDataDetail() <= chunkDataView.getLodPos().detailLevel) + else if (chunkDataView.detailLevel < this.getDataDetail() && this.getDataDetail() <= chunkDataView.getSectionPos().sectionDetailLevel) { this.markNotEmpty(); // multiple chunk data points converting to 1 column data point - DhLodPos dataCornerPos = chunkDataView.getLodPos().getCornerLodPos(chunkDataView.detailLevel); + DhLodPos dataCornerPos = chunkDataView.getSectionPos().getMinCornerLodPos(chunkDataView.detailLevel); DhLodPos sourceCornerPos = renderSourcePos.getMinCornerLodPos(this.getDataDetail()); DhLodPos sourceStartingChangePos = dataCornerPos.convertToDetailLevel(this.getDataDetail()); int relStartX = Math.floorMod(sourceStartingChangePos.x, this.getWidthInDataPoints()); int relStartZ = Math.floorMod(sourceStartingChangePos.z, this.getWidthInDataPoints()); int dataToSourceScale = sourceCornerPos.getWidthAtDetail(chunkDataView.detailLevel); - int columnsInChunk = chunkDataView.getLodPos().getWidthAtDetail(this.getDataDetail()); + int columnsInChunk = chunkDataView.getSectionPos().getWidthCountForLowerDetailedSection(this.getDataDetail()); - for (int ox = 0; ox < columnsInChunk; ox++) + for (int xOffset = 0; xOffset < columnsInChunk; xOffset++) { - for (int oz = 0; oz < columnsInChunk; oz++) + for (int zOffset = 0; zOffset < columnsInChunk; zOffset++) { - int relSourceX = relStartX + ox; - int relSourceZ = relStartZ + oz; + int relSourceX = relStartX + xOffset; + int relSourceZ = relStartZ + zOffset; ColumnArrayView columnArrayView = this.getVerticalDataPointView(relSourceX, relSourceZ); int hash = columnArrayView.getDataHash(); - SingleColumnFullDataAccessor fullArrayView = chunkDataView.get(ox * dataToSourceScale, oz * dataToSourceScale); + SingleColumnFullDataAccessor fullArrayView = chunkDataView.get(xOffset * dataToSourceScale, zOffset * dataToSourceScale); FullDataToRenderDataTransformer.convertColumnData(level, sourceBlockX + sourceDataPointBlockWidth * relSourceX, sourceBlockZ + sourceDataPointBlockWidth * relSourceZ, @@ -390,14 +390,14 @@ public class ColumnRenderSource } this.fillDebugFlag(relStartX, relStartZ, columnsInChunk, columnsInChunk, ColumnRenderSource.DebugSourceFlag.DIRECT); } - else if (chunkDataView.getLodPos().detailLevel < this.getDataDetail()) + else if (chunkDataView.getSectionPos().sectionDetailLevel < this.getDataDetail()) { // The entire chunk is being converted to a single column data point, possibly. - DhLodPos dataCornerPos = chunkDataView.getLodPos().getCornerLodPos(chunkDataView.detailLevel); + DhLodPos dataCornerPos = chunkDataView.getSectionPos().getMinCornerLodPos(chunkDataView.detailLevel); DhLodPos sourceCornerPos = renderSourcePos.getMinCornerLodPos(this.getDataDetail()); DhLodPos sourceStartingChangePos = dataCornerPos.convertToDetailLevel(this.getDataDetail()); - int chunksPerColumn = sourceStartingChangePos.getWidthAtDetail(chunkDataView.getLodPos().detailLevel); - if (chunkDataView.getLodPos().x % chunksPerColumn != 0 || chunkDataView.getLodPos().z % chunksPerColumn != 0) + int chunksPerColumn = sourceStartingChangePos.getWidthAtDetail(chunkDataView.getSectionPos().sectionDetailLevel); + if (chunkDataView.getSectionPos().sectionX % chunksPerColumn != 0 || chunkDataView.getSectionPos().sectionZ % chunksPerColumn != 0) { return false; // not a multiple of the column size, so no change } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java index 1b3f4a4d8..8462c8c53 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java @@ -228,6 +228,8 @@ public class FullDataFileHandler implements IFullDataSourceProvider byte sectionDetail = posAreaToGet.sectionDetailLevel; boolean allEmpty = true; + final DhSectionPos subPos = new DhSectionPos((byte)0, 0, 0); + // get all existing files for this position outerLoop: while (--sectionDetail >= this.minDetailLevel) @@ -239,8 +241,8 @@ public class FullDataFileHandler implements IFullDataSourceProvider { for (int zOffset = 0; zOffset < count; zOffset++) { - DhSectionPos subPos = new DhSectionPos(sectionDetail, xOffset + minPos.x, zOffset + minPos.z); - LodUtil.assertTrue(posAreaToGet.overlaps(effectivePos) && subPos.overlaps(posAreaToGet)); + subPos.mutate(sectionDetail, xOffset + minPos.x, zOffset + minPos.z); + LodUtil.assertTrue(posAreaToGet.overlapsExactly(effectivePos) && subPos.overlapsExactly(posAreaToGet)); //TODO: The following check is temporary as we only sample corner points, which means // on a very different level, we may not need the entire section at all. @@ -317,11 +319,11 @@ public class FullDataFileHandler implements IFullDataSourceProvider @Override public void writeChunkDataToFile(DhSectionPos sectionPos, ChunkSizedFullDataAccessor chunkDataView) { - DhLodPos chunkPos = chunkDataView.getLodPos(); - LodUtil.assertTrue(chunkPos.overlapsExactly(sectionPos.getSectionBBoxPos()), "Chunk " + chunkPos + " does not overlap section " + sectionPos); + DhSectionPos chunkSectionPos = chunkDataView.getSectionPos(); + LodUtil.assertTrue(chunkSectionPos.overlapsExactly(sectionPos), "Chunk " + chunkSectionPos + " does not overlap section " + sectionPos); - chunkPos = chunkPos.convertToDetailLevel((byte) this.minDetailLevel); - this.writeChunkDataToMetaFile(new DhSectionPos(chunkPos.detailLevel, chunkPos.x, chunkPos.z), chunkDataView); + chunkSectionPos = chunkSectionPos.convertNewToDetailLevel((byte) this.minDetailLevel); + this.writeChunkDataToMetaFile(chunkSectionPos, chunkDataView); } private void writeChunkDataToMetaFile(DhSectionPos sectionPos, ChunkSizedFullDataAccessor chunkData) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java index 3fa1cc495..56eaf760d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java @@ -344,7 +344,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I { checkAndLogPhantomDataSourceLifeCycles(); - DhLodPos chunkLodPos = new DhLodPos(LodUtil.CHUNK_DETAIL_LEVEL, chunkAccessor.pos.x, chunkAccessor.pos.z); + DhLodPos chunkLodPos = new DhLodPos(LodUtil.CHUNK_DETAIL_LEVEL, chunkAccessor.chunkPos.x, chunkAccessor.chunkPos.z); LodUtil.assertTrue(this.pos.getSectionBBoxPos().overlapsExactly(chunkLodPos), "Chunk pos " + chunkLodPos + " doesn't exactly overlap with section " + this.pos); //LOGGER.info("Write Chunk {} to file {}", chunkPos, pos); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index c2326c3cf..cfa5c3a7e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -349,7 +349,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler return (chunkSizedFullDataSource) -> { - if (chunkSizedFullDataSource.getLodPos().overlapsExactly(this.loadedTargetFullDataSource.getSectionPos().getSectionBBoxPos())) + if (chunkSizedFullDataSource.getSectionPos().overlapsExactly(this.loadedTargetFullDataSource.getSectionPos())) { ((DhLevel) level).saveWrites(chunkSizedFullDataSource); //GeneratedFullDataFileHandler.this.write(this.loadedTargetFullDataSource.getSectionPos(), chunkSizedFullDataSource); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java index 4c4cef87b..3d4de5638 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java @@ -30,7 +30,6 @@ import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFi import com.seibel.distanthorizons.core.file.metaData.BaseMetaData; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; -import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderLoader; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; @@ -136,8 +135,8 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements public void updateChunkIfSourceExistsAsync(ChunkSizedFullDataAccessor chunkDataView) { - DhLodPos chunkPos = chunkDataView.getLodPos(); - LodUtil.assertTrue(this.pos.getSectionBBoxPos().overlapsExactly(chunkPos), "Chunk pos " + chunkPos + " doesn't overlap with section " + this.pos); + DhSectionPos chunkSectionPos = chunkDataView.getSectionPos(); + LodUtil.assertTrue(this.pos.overlapsExactly(chunkSectionPos), "Chunk pos " + chunkSectionPos + " doesn't overlap with section " + this.pos); // update the render source if one exists CompletableFuture renderSourceLoadFuture = this.getCachedDataSourceAsync(false); @@ -156,7 +155,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements Color debugColor = dataUpdated ? Color.blue : Color.red; DebugRenderer.makeParticle( new DebugRenderer.BoxParticle( - new DebugRenderer.Box(chunkDataView.getLodPos(), 32f, 64f + offset, 0.07f, debugColor), + new DebugRenderer.Box(chunkDataView.getSectionPos(), 32f, 64f + offset, 0.07f, debugColor), 2.0, 16f ) ); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java index db67a2ca4..0b5f4bb4c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java @@ -253,16 +253,18 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider } private void writeChunkDataToFileRecursively(ChunkSizedFullDataAccessor chunk, byte sectionDetailLevel) { - DhLodPos boundingPos = chunk.getLodPos(); - DhLodPos minSectionPos = boundingPos.convertToDetailLevel(sectionDetailLevel); + DhSectionPos boundingPos = chunk.getSectionPos(); + DhSectionPos minSectionPos = boundingPos.convertNewToDetailLevel(sectionDetailLevel); - int width = (sectionDetailLevel > boundingPos.detailLevel) ? 1 : boundingPos.getWidthAtDetail(sectionDetailLevel); + DhSectionPos fileSectionPos = new DhSectionPos((byte)0, 0, 0); + + int width = (sectionDetailLevel > boundingPos.sectionDetailLevel) ? 1 : boundingPos.getWidthCountForLowerDetailedSection(sectionDetailLevel); for (int xOffset = 0; xOffset < width; xOffset++) { for (int zOffset = 0; zOffset < width; zOffset++) { - DhSectionPos sectionPos = new DhSectionPos(sectionDetailLevel, minSectionPos.x + xOffset, minSectionPos.z + zOffset); - RenderDataMetaFile metaFile = this.metaFileBySectionPos.get(sectionPos); // bypass the getLoadOrMakeFile() since we only want cached files. + fileSectionPos.mutate(sectionDetailLevel, minSectionPos.sectionX + xOffset, minSectionPos.sectionZ + zOffset); + RenderDataMetaFile metaFile = this.metaFileBySectionPos.get(fileSectionPos); // bypass the getLoadOrMakeFile() since we only want cached files. if (metaFile != null) { metaFile.updateChunkIfSourceExistsAsync(chunk); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java index ac3ec177c..a75d24755 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java @@ -175,16 +175,16 @@ public class ClientLevelModule implements Closeable //===============// public void writeChunkDataToFile(ChunkSizedFullDataAccessor data) { - DhLodPos pos = data.getLodPos().convertToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET); + DhSectionPos pos = data.getSectionPos().convertNewToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET); ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); if (ClientRenderState != null) { - ClientRenderState.renderSourceFileHandler.writeChunkDataToFile(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); + ClientRenderState.renderSourceFileHandler.writeChunkDataToFile(pos, data); } else { - this.parentClientLevel.getFileHandler().writeChunkDataToFile(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); + this.parentClientLevel.getFileHandler().writeChunkDataToFile(pos, data); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index 2bee0ac1c..2fa741570 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -58,8 +58,9 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel @Override public void saveWrites(ChunkSizedFullDataAccessor data) { - DhLodPos pos = data.getLodPos().convertToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET); - getFileHandler().writeChunkDataToFile(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); + DhSectionPos pos = data.getSectionPos(); + pos.convertSelfToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET); + this.getFileHandler().writeChunkDataToFile(pos, data); } @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java index bc2b38426..76cfdb4c3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java @@ -192,11 +192,14 @@ public class DhLodPos implements Comparable public boolean overlapsExactly(DhLodPos other) { if (this.equals(other)) + { return true; - if (this.detailLevel == other.detailLevel) + } + else if (this.detailLevel == other.detailLevel) + { return false; - - if (this.detailLevel > other.detailLevel) + } + else if (this.detailLevel > other.detailLevel) { return this.equals(other.convertToDetailLevel(this.detailLevel)); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 77e2646a1..44d4019b4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -106,6 +106,18 @@ public class DhSectionPos // converters // //============// + /** + * Overwrites this section pos with the given input.
+ * Can be useful to prevent duplicate allocations in high traffic loops but should + * be used sparingly as it could accidentally cause bugs due to unexpected modifications. + */ + public void mutate(byte sectionDetailLevel, int sectionX, int sectionZ) + { + this.sectionDetailLevel = sectionDetailLevel; + this.sectionX = sectionX; + this.sectionZ = sectionZ; + } + /** uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels. */ public void convertSelfToDetailLevel(byte newDetailLevel) { @@ -256,7 +268,26 @@ public class DhSectionPos // comparisons // //=============// - public boolean overlaps(DhSectionPos other) { return this.getSectionBBoxPos().overlapsExactly(other.getSectionBBoxPos()); } + public boolean overlapsExactly(DhSectionPos other) + { + // original logic from DhLodPos + if (this.equals(other)) + { + return true; + } + else if (this.sectionDetailLevel == other.sectionDetailLevel) + { + return false; + } + else if (this.sectionDetailLevel > other.sectionDetailLevel) + { + return this.equals(other.convertNewToDetailLevel(this.sectionDetailLevel)); + } + else + { + return other.equals(this.convertNewToDetailLevel(other.sectionDetailLevel)); + } + } public boolean contains(DhSectionPos otherPos) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java index c372fd203..e40f4f2ab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java @@ -404,6 +404,7 @@ public class QuadTree { if (node != null || includeNullNodes) { + // TODO can these DhSectionPos be pooled? DhSectionPos rootPos = new DhSectionPos(QuadTree.this.treeMinDetailLevel, pos2D.x, pos2D.y); if (QuadTree.this.isSectionPosInBounds(rootPos)) { From 1ae1f1f36fdce79fdfe6b092b537ac1c9f10ff46 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Fri, 15 Sep 2023 07:34:37 -0500 Subject: [PATCH 14/15] Add a mutable DhSectionPos --- .../fullData/FullDataDownSampler.java | 2 +- .../sources/CompleteFullDataSource.java | 18 +- .../HighDetailIncompleteFullDataSource.java | 22 +- .../LowDetailIncompleteFullDataSource.java | 24 +- .../sources/interfaces/IFullDataSource.java | 22 +- .../render/ColumnRenderSource.java | 12 +- .../fullDatafile/FullDataFileHandler.java | 20 +- .../file/fullDatafile/FullDataMetaFile.java | 4 +- .../AbstractMetaDataContainerFile.java | 7 +- .../file/renderfile/RenderDataMetaFile.java | 2 +- .../renderfile/RenderSourceFileHandler.java | 15 +- .../core/generation/WorldGenerationQueue.java | 16 +- .../core/level/DhServerLevel.java | 2 +- .../distanthorizons/core/pos/DhLodPos.java | 2 +- .../core/pos/DhSectionPos.java | 214 +++++++++++------- .../core/render/LodQuadTree.java | 6 +- .../core/render/LodRenderSection.java | 4 +- .../core/render/RenderBufferHandler.java | 2 +- .../core/util/objects/quadTree/QuadNode.java | 10 +- .../core/util/objects/quadTree/QuadTree.java | 10 +- .../iterators/QuadNodeChildIndexIterator.java | 2 +- .../iterators/QuadTreeNodeIterator.java | 2 +- core/src/test/java/tests/QuadTreeTest.java | 10 +- 23 files changed, 241 insertions(+), 187 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java index c99e77597..3b333bf4a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataDownSampler.java @@ -113,7 +113,7 @@ public class FullDataDownSampler // The source occupies only 1 datapoint in the target // FIXME: TEMP method for down-sampling: take only the corner column int sourceSectionPerTargetData = 1 << (detailDiff - CompleteFullDataSource.SECTION_SIZE_OFFSET); - if (srcPos.sectionX % sourceSectionPerTargetData != 0 || srcPos.sectionZ % sourceSectionPerTargetData != 0) + if (srcPos.getX() % sourceSectionPerTargetData != 0 || srcPos.getZ() % sourceSectionPerTargetData != 0) { return; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java index dbf5b573c..1c97cc97b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java @@ -332,8 +332,8 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); DhSectionPos dataOffset = chunkDataView.getSectionPos().convertNewToDetailLevel(this.getDataDetailLevel()); - int offsetX = dataOffset.sectionX - baseOffset.x; - int offsetZ = dataOffset.sectionZ - baseOffset.z; + int offsetX = dataOffset.getX() - baseOffset.x; + int offsetZ = dataOffset.getZ() - baseOffset.z; LodUtil.assertTrue(offsetX >= 0 && offsetX < WIDTH && offsetZ >= 0 && offsetZ < WIDTH); this.isEmpty = false; @@ -361,13 +361,13 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu // the testPosition is outside the writePosition return false; } - else if (posToTest.sectionDetailLevel > posToWrite.sectionDetailLevel) + else if (posToTest.getDetailLevel() > posToWrite.getDetailLevel()) { // the testPosition is larger (aka is less detailed) than the writePosition, // more detailed sections shouldn't be updated by lower detail sections return false; } - else if (posToWrite.sectionDetailLevel - posToTest.sectionDetailLevel <= SECTION_SIZE_OFFSET) + else if (posToWrite.getDetailLevel() - posToTest.getDetailLevel() <= SECTION_SIZE_OFFSET) { // if the difference in detail levels is very large, the posToWrite // may be skipped, due to how we sample large detail levels by only @@ -380,9 +380,9 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu { // the difference in detail levels is very large, // check if the posToWrite is in a corner of posToTest - byte sectPerData = (byte) BitShiftUtil.powerOfTwo(posToWrite.sectionDetailLevel - posToTest.sectionDetailLevel - SECTION_SIZE_OFFSET); + byte sectPerData = (byte) BitShiftUtil.powerOfTwo(posToWrite.getDetailLevel() - posToTest.getDetailLevel() - SECTION_SIZE_OFFSET); LodUtil.assertTrue(sectPerData != 0); - return posToTest.sectionX % sectPerData == 0 && posToTest.sectionZ % sectPerData == 0; + return posToTest.getX() % sectPerData == 0 && posToTest.getZ() % sectPerData == 0; } } @@ -395,7 +395,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu @Override public DhSectionPos getSectionPos() { return this.sectionPos; } @Override - public byte getDataDetailLevel() { return (byte) (this.sectionPos.sectionDetailLevel - SECTION_SIZE_OFFSET); } + public byte getDataDetailLevel() { return (byte) (this.sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET); } @Override public byte getBinaryDataFormatVersion() { return DATA_FORMAT_VERSION; } @@ -419,14 +419,14 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu public void updateFromLowerCompleteSource(CompleteFullDataSource subData) { LodUtil.assertTrue(this.sectionPos.overlapsExactly(subData.sectionPos)); - LodUtil.assertTrue(subData.sectionPos.sectionDetailLevel < this.sectionPos.sectionDetailLevel); + LodUtil.assertTrue(subData.sectionPos.getDetailLevel() < this.sectionPos.getDetailLevel()); if (!firstDataPosCanAffectSecond(this.sectionPos, subData.sectionPos)) { return; } DhSectionPos lowerSectPos = subData.sectionPos; - byte detailDiff = (byte) (this.sectionPos.sectionDetailLevel - subData.sectionPos.sectionDetailLevel); + byte detailDiff = (byte) (this.sectionPos.getDetailLevel() - subData.sectionPos.getDetailLevel()); byte targetDataDetail = this.getDataDetailLevel(); DhLodPos minDataPos = this.sectionPos.getMinCornerLodPos(targetDataDetail); if (detailDiff <= SECTION_SIZE_OFFSET) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java index 5d0e76eca..3c8e7c44f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java @@ -96,11 +96,11 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo public static HighDetailIncompleteFullDataSource createEmpty(DhSectionPos pos) { return new HighDetailIncompleteFullDataSource(pos); } private HighDetailIncompleteFullDataSource(DhSectionPos sectionPos) { - LodUtil.assertTrue(sectionPos.sectionDetailLevel > SPARSE_UNIT_DETAIL); - LodUtil.assertTrue(sectionPos.sectionDetailLevel <= MAX_SECTION_DETAIL); + LodUtil.assertTrue(sectionPos.getDetailLevel() > SPARSE_UNIT_DETAIL); + LodUtil.assertTrue(sectionPos.getDetailLevel() <= MAX_SECTION_DETAIL); this.sectionPos = sectionPos; - this.sectionCount = BitShiftUtil.powerOfTwo(sectionPos.sectionDetailLevel - SPARSE_UNIT_DETAIL); + this.sectionCount = BitShiftUtil.powerOfTwo(sectionPos.getDetailLevel() - SPARSE_UNIT_DETAIL); this.dataPointsPerSection = SECTION_SIZE / this.sectionCount; this.sparseData = new FullDataArrayAccessor[this.sectionCount * this.sectionCount]; @@ -110,11 +110,11 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo protected HighDetailIncompleteFullDataSource(DhSectionPos sectionPos, FullDataPointIdMap mapping, FullDataArrayAccessor[] data) { - LodUtil.assertTrue(sectionPos.sectionDetailLevel > SPARSE_UNIT_DETAIL); - LodUtil.assertTrue(sectionPos.sectionDetailLevel <= MAX_SECTION_DETAIL); + LodUtil.assertTrue(sectionPos.getDetailLevel() > SPARSE_UNIT_DETAIL); + LodUtil.assertTrue(sectionPos.getDetailLevel() <= MAX_SECTION_DETAIL); this.sectionPos = sectionPos; - this.sectionCount = 1 << (byte) (sectionPos.sectionDetailLevel - SPARSE_UNIT_DETAIL); + this.sectionCount = 1 << (byte) (sectionPos.getDetailLevel() - SPARSE_UNIT_DETAIL); this.dataPointsPerSection = SECTION_SIZE / this.sectionCount; LodUtil.assertTrue(this.sectionCount * this.sectionCount == data.length); @@ -144,8 +144,8 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo @Override public FullDataSourceSummaryData readSourceSummaryInfo(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException { - LodUtil.assertTrue(dataFile.pos.sectionDetailLevel > SPARSE_UNIT_DETAIL); - LodUtil.assertTrue(dataFile.pos.sectionDetailLevel <= MAX_SECTION_DETAIL); + LodUtil.assertTrue(dataFile.pos.getDetailLevel() > SPARSE_UNIT_DETAIL); + LodUtil.assertTrue(dataFile.pos.getDetailLevel() <= MAX_SECTION_DETAIL); int dataDetail = inputStream.readShort(); if (dataDetail != dataFile.baseMetaData.dataLevel) @@ -255,7 +255,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo { // calculate the number of chunks and dataPoints based on the sparseDetail and sectionSize // TODO these values should be constant, should we still be calculating them like this? - int chunks = BitShiftUtil.powerOfTwo(dataFile.pos.sectionDetailLevel - SPARSE_UNIT_DETAIL); + int chunks = BitShiftUtil.powerOfTwo(dataFile.pos.getDetailLevel() - SPARSE_UNIT_DETAIL); int dataPointsPerChunk = SECTION_SIZE / chunks; @@ -421,7 +421,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo @Override public DhSectionPos getSectionPos() { return this.sectionPos; } @Override - public byte getDataDetailLevel() { return (byte) (this.sectionPos.sectionDetailLevel - SECTION_SIZE_OFFSET); } + public byte getDataDetailLevel() { return (byte) (this.sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET); } @Override public byte getBinaryDataFormatVersion() { return DATA_FORMAT_VERSION; } @@ -488,7 +488,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo public void sampleFrom(IFullDataSource fullDataSource) { DhSectionPos pos = fullDataSource.getSectionPos(); - LodUtil.assertTrue(pos.sectionDetailLevel < this.sectionPos.sectionDetailLevel); + LodUtil.assertTrue(pos.getDetailLevel() < this.sectionPos.getDetailLevel()); LodUtil.assertTrue(pos.overlapsExactly(this.sectionPos)); if (fullDataSource.isEmpty()) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java index 9a43898ba..5b3d5a545 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java @@ -84,7 +84,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp private LowDetailIncompleteFullDataSource(DhSectionPos sectionPos) { super(new FullDataPointIdMap(sectionPos), new long[WIDTH * WIDTH][0], WIDTH); - LodUtil.assertTrue(sectionPos.sectionDetailLevel > HighDetailIncompleteFullDataSource.MAX_SECTION_DETAIL); + LodUtil.assertTrue(sectionPos.getDetailLevel() > HighDetailIncompleteFullDataSource.MAX_SECTION_DETAIL); this.sectionPos = sectionPos; this.isColumnNotEmpty = new BitSet(WIDTH * WIDTH); @@ -295,7 +295,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp @Override public DhSectionPos getSectionPos() { return this.sectionPos; } @Override - public byte getDataDetailLevel() { return (byte) (this.sectionPos.sectionDetailLevel - SECTION_SIZE_OFFSET); } + public byte getDataDetailLevel() { return (byte) (this.sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET); } @Override public byte getBinaryDataFormatVersion() { return DATA_FORMAT_VERSION; } @@ -331,8 +331,8 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); DhSectionPos dataOffset = data.getSectionPos().convertNewToDetailLevel(this.getDataDetailLevel()); - int offsetX = dataOffset.sectionX - baseOffset.x; - int offsetZ = dataOffset.sectionZ - baseOffset.z; + int offsetX = dataOffset.getX() - baseOffset.x; + int offsetZ = dataOffset.getZ() - baseOffset.z; LodUtil.assertTrue(offsetX >= 0 && offsetX < WIDTH && offsetZ >= 0 && offsetZ < WIDTH); this.isEmpty = false; @@ -353,7 +353,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp public void sampleFrom(IFullDataSource fullDataSource) { DhSectionPos pos = fullDataSource.getSectionPos(); - LodUtil.assertTrue(pos.sectionDetailLevel < this.sectionPos.sectionDetailLevel); + LodUtil.assertTrue(pos.getDetailLevel() < this.sectionPos.getDetailLevel()); LodUtil.assertTrue(pos.overlapsExactly(this.sectionPos)); if (fullDataSource.isEmpty()) @@ -389,7 +389,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp this.isEmpty = false; - if (this.getDataDetailLevel() > this.sectionPos.sectionDetailLevel) + if (this.getDataDetailLevel() > this.sectionPos.getDetailLevel()) { DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel()); @@ -445,7 +445,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp this.isEmpty = false; this.downsampleFrom(completeSource); - if (this.getDataDetailLevel() > this.sectionPos.sectionDetailLevel) // TODO what does this mean? + if (this.getDataDetailLevel() > this.sectionPos.getDetailLevel()) // TODO what does this mean? { DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel()); @@ -488,7 +488,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp this.downsampleFrom(spottySource); - if (this.getDataDetailLevel() > this.sectionPos.sectionDetailLevel) + if (this.getDataDetailLevel() > this.sectionPos.getDetailLevel()) { DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel()); DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel()); @@ -574,12 +574,12 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp { if (!posToWrite.overlapsExactly(posToTest)) return false; - if (posToTest.sectionDetailLevel > posToWrite.sectionDetailLevel) + if (posToTest.getDetailLevel() > posToWrite.getDetailLevel()) return false; - if (posToWrite.sectionDetailLevel - posToTest.sectionDetailLevel <= SECTION_SIZE_OFFSET) + if (posToWrite.getDetailLevel() - posToTest.getDetailLevel() <= SECTION_SIZE_OFFSET) return true; - byte sectPerData = (byte) (1 << (posToWrite.sectionDetailLevel - posToTest.sectionDetailLevel - SECTION_SIZE_OFFSET)); - return posToTest.sectionX % sectPerData == 0 && posToTest.sectionZ % sectPerData == 0; + byte sectPerData = (byte) (1 << (posToWrite.getDetailLevel() - posToTest.getDetailLevel() - SECTION_SIZE_OFFSET)); + return posToTest.getX() % sectPerData == 0 && posToTest.getZ() % sectPerData == 0; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java index 622c67d04..4eea2d091 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java @@ -103,7 +103,7 @@ public interface IFullDataSource while (posList.size() > 0) { DhSectionPos pos = posList.remove(); - if (pos.sectionDetailLevel > highestGeneratorDetailLevel) + if (pos.getDetailLevel() > highestGeneratorDetailLevel) { pos.forEachChild((childPos) -> { posList.push(childPos); }); } @@ -127,20 +127,20 @@ public interface IFullDataSource int sourceRelWidth = this.getWidthInDataPoints(); - if (quadrantPos.sectionDetailLevel < highestGeneratorDetailLevel) + if (quadrantPos.getDetailLevel() < highestGeneratorDetailLevel) { throw new IllegalArgumentException("detail level lower than world generator can accept."); } - else if (quadrantPos.sectionDetailLevel == highestGeneratorDetailLevel) + else if (quadrantPos.getDetailLevel() == highestGeneratorDetailLevel) { // we are at the highest detail level the world generator can accept, // we either need to generate this whole section, or not at all // TODO combine duplicate code - byte childDetailLevel = (byte) (quadrantPos.sectionDetailLevel); + byte childDetailLevel = (byte) (quadrantPos.getDetailLevel()); - int quadrantDetailLevelDiff = this.getSectionPos().sectionDetailLevel - childDetailLevel; + int quadrantDetailLevelDiff = this.getSectionPos().getDetailLevel() - childDetailLevel; int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); int relWidthForSecPos = sourceRelWidth / widthInSecPos; @@ -149,8 +149,8 @@ public interface IFullDataSource - int minRelX = inputPos.sectionX - minSecPos.sectionX; - int minRelZ = inputPos.sectionZ - minSecPos.sectionZ; + int minRelX = inputPos.getX() - minSecPos.getX(); + int minRelZ = inputPos.getZ() - minSecPos.getZ(); int maxRelX = minRelX + 1; int maxRelZ = minRelZ + 1; @@ -187,11 +187,11 @@ public interface IFullDataSource // TODO comment // TODO combine duplicate code - byte childDetailLevel = (byte) (quadrantPos.sectionDetailLevel - 1); + byte childDetailLevel = (byte) (quadrantPos.getDetailLevel() - 1); for (int i = 0; i < 4; i++) { - int quadrantDetailLevelDiff = this.getSectionPos().sectionDetailLevel - childDetailLevel; + int quadrantDetailLevelDiff = this.getSectionPos().getDetailLevel() - childDetailLevel; int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); int relWidthForSecPos = sourceRelWidth / widthInSecPos; @@ -200,8 +200,8 @@ public interface IFullDataSource - int minRelX = inputPos.sectionX - minSecPos.sectionX; - int minRelZ = inputPos.sectionZ - minSecPos.sectionZ; + int minRelX = inputPos.getX() - minSecPos.getX(); + int minRelZ = inputPos.getZ() - minSecPos.getZ(); int maxRelX = minRelX + 1; int maxRelZ = minRelZ + 1; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java index 9b42652d9..ece6027b7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java @@ -109,7 +109,7 @@ public class ColumnRenderSource */ public ColumnRenderSource(DhSectionPos sectionPos, ColumnRenderLoader.ParsedColumnData parsedColumnData, IDhLevel level) throws IOException { - if (sectionPos.sectionDetailLevel - SECTION_SIZE_OFFSET != parsedColumnData.detailLevel) + if (sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET != parsedColumnData.detailLevel) { throw new IOException("Invalid data: detail level does not match"); } @@ -360,7 +360,7 @@ public class ColumnRenderSource } this.fillDebugFlag(blockOffsetX, blockOffsetZ, LodUtil.CHUNK_WIDTH, LodUtil.CHUNK_WIDTH, ColumnRenderSource.DebugSourceFlag.DIRECT); } - else if (chunkDataView.detailLevel < this.getDataDetail() && this.getDataDetail() <= chunkDataView.getSectionPos().sectionDetailLevel) + else if (chunkDataView.detailLevel < this.getDataDetail() && this.getDataDetail() <= chunkDataView.getSectionPos().getDetailLevel()) { this.markNotEmpty(); // multiple chunk data points converting to 1 column data point @@ -390,14 +390,14 @@ public class ColumnRenderSource } this.fillDebugFlag(relStartX, relStartZ, columnsInChunk, columnsInChunk, ColumnRenderSource.DebugSourceFlag.DIRECT); } - else if (chunkDataView.getSectionPos().sectionDetailLevel < this.getDataDetail()) + else if (chunkDataView.getSectionPos().getDetailLevel() < this.getDataDetail()) { // The entire chunk is being converted to a single column data point, possibly. DhLodPos dataCornerPos = chunkDataView.getSectionPos().getMinCornerLodPos(chunkDataView.detailLevel); DhLodPos sourceCornerPos = renderSourcePos.getMinCornerLodPos(this.getDataDetail()); DhLodPos sourceStartingChangePos = dataCornerPos.convertToDetailLevel(this.getDataDetail()); - int chunksPerColumn = sourceStartingChangePos.getWidthAtDetail(chunkDataView.getSectionPos().sectionDetailLevel); - if (chunkDataView.getSectionPos().sectionX % chunksPerColumn != 0 || chunkDataView.getSectionPos().sectionZ % chunksPerColumn != 0) + int chunksPerColumn = sourceStartingChangePos.getWidthAtDetail(chunkDataView.getSectionPos().getDetailLevel()); + if (chunkDataView.getSectionPos().getX() % chunksPerColumn != 0 || chunkDataView.getSectionPos().getZ() % chunksPerColumn != 0) { return false; // not a multiple of the column size, so no change } @@ -443,7 +443,7 @@ public class ColumnRenderSource public DhSectionPos getSectionPos() { return this.sectionPos; } - public byte getDataDetail() { return (byte) (this.sectionPos.sectionDetailLevel - SECTION_SIZE_OFFSET); } + public byte getDataDetail() { return (byte) (this.sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET); } /** @return how many data points wide this {@link ColumnRenderSource} is. */ public int getWidthInDataPoints() { return BitShiftUtil.powerOfTwo(this.getDetailOffset()); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java index 8462c8c53..9fa0af4c9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java @@ -88,11 +88,11 @@ public class FullDataFileHandler implements IFullDataSourceProvider MetaFileScanUtil.IAddUnloadedFileFunc addUnloadedFileFunc = (pos, file) -> { this.unloadedFileBySectionPos.put(pos, file); - this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.getDetailLevel())); }; MetaFileScanUtil.IAddLoadedMetaFileFunc addLoadedMetaFileFunc = (pos, loadedMetaFile) -> { - this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.getDetailLevel())); this.metaFileBySectionPos.put(pos, (FullDataMetaFile) loadedMetaFile); }; @@ -119,7 +119,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider @Override public CompletableFuture readAsync(DhSectionPos pos) { - this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.getDetailLevel())); FullDataMetaFile metaFile = this.getLoadOrMakeFile(pos, true); if (metaFile == null) { @@ -173,7 +173,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider try { metaFile = FullDataMetaFile.createFromExistingFile(this, this.level, fileToLoad); - this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.getDetailLevel())); this.metaFileBySectionPos.put(pos, metaFile); return metaFile; } @@ -208,7 +208,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider return null; } - this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.getDetailLevel())); // This is a CAS with expected null value. FullDataMetaFile metaFileCas = this.metaFileBySectionPos.putIfAbsent(pos, metaFile); @@ -225,10 +225,10 @@ public class FullDataFileHandler implements IFullDataSourceProvider DhSectionPos effectivePos, DhSectionPos posAreaToGet, ArrayList preexistingFiles, ArrayList missingFilePositions) { - byte sectionDetail = posAreaToGet.sectionDetailLevel; + byte sectionDetail = posAreaToGet.getDetailLevel(); boolean allEmpty = true; - final DhSectionPos subPos = new DhSectionPos((byte)0, 0, 0); + final DhSectionPos.DhMutableSectionPos subPos = new DhSectionPos.DhMutableSectionPos((byte)0, 0, 0); // get all existing files for this position outerLoop: @@ -294,7 +294,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider // we have reached a populated leaf node in the quad tree preexistingFiles.add(metaFile); } - else if (childPos.sectionDetailLevel == this.minDetailLevel) + else if (childPos.getDetailLevel() == this.minDetailLevel) { // we have reached an empty leaf node in the quad tree missingFilePositions.add(childPos); @@ -334,7 +334,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider metaFile.addToWriteQueue(chunkData); } - if (sectionPos.sectionDetailLevel <= this.topDetailLevelRef.get()) + if (sectionPos.getDetailLevel() <= this.topDetailLevelRef.get()) { // recursively attempt to get the meta file for this position this.writeChunkDataToMetaFile(sectionPos.getParentPos(), chunkData); @@ -369,7 +369,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider protected IIncompleteFullDataSource makeEmptyDataSource(DhSectionPos pos) { - return pos.sectionDetailLevel <= HighDetailIncompleteFullDataSource.MAX_SECTION_DETAIL ? + return pos.getDetailLevel() <= HighDetailIncompleteFullDataSource.MAX_SECTION_DETAIL ? HighDetailIncompleteFullDataSource.createEmpty(pos) : LowDetailIncompleteFullDataSource.createEmpty(pos); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java index 56eaf760d..858f084e5 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java @@ -431,7 +431,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I @Override public void debugRender(DebugRenderer debugRenderer) { - if (this.pos.sectionDetailLevel > DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + if (this.pos.getDetailLevel() > DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) { return; } @@ -555,7 +555,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I new DataObjSoftTracker(this, fullDataSource); } - if (this.pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + if (this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) { DebugRenderer.makeParticle(new DebugRenderer.BoxParticle( new DebugRenderer.Box(this.pos, 64f, 72f, 0.03f, Color.green.darker()), diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/metaData/AbstractMetaDataContainerFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/metaData/AbstractMetaDataContainerFile.java index 168bae813..846e1b71c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/metaData/AbstractMetaDataContainerFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/metaData/AbstractMetaDataContainerFile.java @@ -25,7 +25,6 @@ import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.file.*; -import java.util.concurrent.locks.ReentrantLock; import java.util.zip.Adler32; import java.util.zip.CheckedOutputStream; @@ -231,11 +230,11 @@ public abstract class AbstractMetaDataContainerFile fileChannel.position(0); ByteBuffer buffer = ByteBuffer.allocate(METADATA_SIZE_IN_BYTES); buffer.putInt(METADATA_IDENTITY_BYTES); - buffer.putInt(this.pos.sectionX); + buffer.putInt(this.pos.getX()); buffer.putInt(Integer.MIN_VALUE); // Unused - y pos - buffer.putInt(this.pos.sectionZ); + buffer.putInt(this.pos.getZ()); buffer.putInt(this.baseMetaData.checksum); - buffer.put(this.pos.sectionDetailLevel); + buffer.put(this.pos.getDetailLevel()); buffer.put(this.baseMetaData.dataLevel); buffer.put(this.baseMetaData.binaryDataFormatVersion); buffer.put(this.baseMetaData.worldGenStep != null ? this.baseMetaData.worldGenStep.value : EDhApiWorldGenerationStep.EMPTY.value); // TODO this null check shouldn't be necessary diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java index 3d4de5638..60991802a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java @@ -197,7 +197,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements // create an empty render source - byte dataDetailLevel = (byte) (this.pos.sectionDetailLevel - ColumnRenderSource.SECTION_SIZE_OFFSET); + byte dataDetailLevel = (byte) (this.pos.getDetailLevel() - ColumnRenderSource.SECTION_SIZE_OFFSET); int verticalSize = Config.Client.Advanced.Graphics.Quality.verticalQuality.get().calculateMaxVerticalData(dataDetailLevel); ColumnRenderSource newColumnRenderSource = new ColumnRenderSource(this.pos, verticalSize, this.clientLevel.getMinY()); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java index 0b5f4bb4c..9dc6a8bdc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java @@ -23,7 +23,6 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedF import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.f3.F3Screen; -import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider; @@ -98,11 +97,11 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider MetaFileScanUtil.IAddUnloadedFileFunc addUnloadedFileFunc = (pos, file) -> { this.unloadedFileBySectionPos.put(pos, file); - this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.getDetailLevel())); }; MetaFileScanUtil.IAddLoadedMetaFileFunc addLoadedMetaFileFunc = (pos, loadedMetaFile) -> { - this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(oldDetailLevel -> Math.max(oldDetailLevel, pos.getDetailLevel())); this.metaFileBySectionPos.put(pos, (RenderDataMetaFile) loadedMetaFile); }; @@ -195,7 +194,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider try { metaFile = RenderDataMetaFile.createFromExistingFile(this.fullDataSourceProvider, this.clientLevel, fileToLoad); - this.topDetailLevelRef.updateAndGet(currentTopDetailLevel -> Math.max(currentTopDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(currentTopDetailLevel -> Math.max(currentTopDetailLevel, pos.getDetailLevel())); this.metaFileBySectionPos.put(pos, metaFile); return metaFile; } @@ -221,7 +220,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider // due to a rare issue where the file may already exist but isn't in the file list metaFile = RenderDataMetaFile.createFromExistingOrNewFile(this.clientLevel, this.fullDataSourceProvider, pos, this.computeRenderFilePath(pos)); - this.topDetailLevelRef.updateAndGet(newDetailLevel -> Math.max(newDetailLevel, pos.sectionDetailLevel)); + this.topDetailLevelRef.updateAndGet(newDetailLevel -> Math.max(newDetailLevel, pos.getDetailLevel())); // Compare And Swap to handle a concurrency issue where multiple threads created the same Meta File at the same time RenderDataMetaFile metaFileCas = this.metaFileBySectionPos.putIfAbsent(pos, metaFile); @@ -256,14 +255,14 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider DhSectionPos boundingPos = chunk.getSectionPos(); DhSectionPos minSectionPos = boundingPos.convertNewToDetailLevel(sectionDetailLevel); - DhSectionPos fileSectionPos = new DhSectionPos((byte)0, 0, 0); + DhSectionPos.DhMutableSectionPos fileSectionPos = new DhSectionPos.DhMutableSectionPos((byte)0, 0, 0); - int width = (sectionDetailLevel > boundingPos.sectionDetailLevel) ? 1 : boundingPos.getWidthCountForLowerDetailedSection(sectionDetailLevel); + int width = (sectionDetailLevel > boundingPos.getDetailLevel()) ? 1 : boundingPos.getWidthCountForLowerDetailedSection(sectionDetailLevel); for (int xOffset = 0; xOffset < width; xOffset++) { for (int zOffset = 0; zOffset < width; zOffset++) { - fileSectionPos.mutate(sectionDetailLevel, minSectionPos.sectionX + xOffset, minSectionPos.sectionZ + zOffset); + fileSectionPos.mutate(sectionDetailLevel, minSectionPos.getX() + xOffset, minSectionPos.getZ() + zOffset); RenderDataMetaFile metaFile = this.metaFileBySectionPos.get(fileSectionPos); // bypass the getLoadOrMakeFile() since we only want cached files. if (metaFile != null) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java index b32426a42..3cf6f863b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java @@ -28,7 +28,6 @@ import com.seibel.distanthorizons.core.generation.tasks.*; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.DhChunkPos; -import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.transformers.LodDataBuilder; @@ -45,7 +44,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import org.apache.logging.log4j.Logger; import java.awt.*; -import java.io.Closeable; import java.util.*; import java.util.concurrent.*; import java.util.function.Consumer; @@ -159,7 +157,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender } // Assert that the data at least can fill in 1 single ChunkSizedFullDataAccessor - LodUtil.assertTrue(pos.sectionDetailLevel > requiredDataDetail + LodUtil.CHUNK_DETAIL_LEVEL); + LodUtil.assertTrue(pos.getDetailLevel() > requiredDataDetail + LodUtil.CHUNK_DETAIL_LEVEL); //if (this.waitingTaskQuadTree.isSectionPosInBounds(requestPos)) @@ -393,14 +391,14 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender // split up the task and add each one to the tree LinkedList> childFutures = new LinkedList<>(); - DhSectionPos sectionPos = new DhSectionPos(closestTask.pos.sectionDetailLevel, closestTask.pos.sectionX, closestTask.pos.sectionZ); + DhSectionPos sectionPos = new DhSectionPos(closestTask.pos.getDetailLevel(), closestTask.pos.getX(), closestTask.pos.getZ()); WorldGenTask finalClosestTask = closestTask; sectionPos.forEachChild((childDhSectionPos) -> { CompletableFuture newFuture = new CompletableFuture<>(); childFutures.add(newFuture); - WorldGenTask newGenTask = new WorldGenTask(childDhSectionPos, childDhSectionPos.sectionDetailLevel, finalClosestTask.taskTracker, newFuture); + WorldGenTask newGenTask = new WorldGenTask(childDhSectionPos, childDhSectionPos.getDetailLevel(), finalClosestTask.taskTracker, newFuture); waitingTasks.put(newGenTask.pos, newGenTask); //this.waitingTaskQuadTree.setValue(new DhSectionPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ), newGenTask); @@ -421,7 +419,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender { byte taskDetailLevel = inProgressTaskGroup.group.dataDetail; DhSectionPos taskPos = inProgressTaskGroup.group.pos; - byte granularity = (byte) (taskPos.sectionDetailLevel - taskDetailLevel); + byte granularity = (byte) (taskPos.getDetailLevel() - taskDetailLevel); LodUtil.assertTrue(granularity >= this.minGranularity && granularity <= this.maxGranularity); LodUtil.assertTrue(taskDetailLevel >= this.smallestDataDetail && taskDetailLevel <= this.largestDataDetail); @@ -436,7 +434,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender //StackTraceElement[] stackTrace = this.alreadyGeneratedPosHashSet.get(inProgressTaskGroup.group.pos); // sending a success result is necessary to make sure the render sections are reloaded correctly - inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos.sectionX, taskPos.sectionZ)))); + inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos.getX(), taskPos.getZ())))); return; } this.alreadyGeneratedPosHashSet.put(inProgressTaskGroup.group.pos, Thread.currentThread().getStackTrace()); @@ -470,7 +468,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender else { //LOGGER.info("Section generation at "+pos+" completed"); - inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos.sectionX, taskPos.sectionZ)))); + inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos.getX(), taskPos.getZ())))); } boolean worked = this.inProgressGenTasksByLodPos.remove(taskPos, inProgressTaskGroup); LodUtil.assertTrue(worked); @@ -686,7 +684,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender private boolean canGeneratePos(byte worldGenTaskGroupDetailLevel /*when in doubt use 0*/ , DhSectionPos taskPos) { - byte granularity = (byte) (taskPos.sectionDetailLevel - worldGenTaskGroupDetailLevel); + byte granularity = (byte) (taskPos.getDetailLevel() - worldGenTaskGroupDetailLevel); return (granularity >= this.minGranularity && granularity <= this.maxGranularity); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index 2fa741570..ef3370411 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -59,7 +59,7 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel public void saveWrites(ChunkSizedFullDataAccessor data) { DhSectionPos pos = data.getSectionPos(); - pos.convertSelfToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET); + pos = pos.convertNewToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET); this.getFileHandler().writeChunkDataToFile(pos, data); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java index 76cfdb4c3..21273d79a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhLodPos.java @@ -47,7 +47,7 @@ public class DhLodPos implements Comparable this.x = x; this.z = z; } - public DhLodPos(DhSectionPos sectionPos) { this(sectionPos.sectionDetailLevel, sectionPos.sectionX, sectionPos.sectionZ); } + public DhLodPos(DhSectionPos sectionPos) { this(sectionPos.getDetailLevel(), sectionPos.getX(), sectionPos.getZ()); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 44d4019b4..5753e9b5b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -41,7 +41,6 @@ import java.util.function.Consumer; * With those thoughts in mind we decided on a smallest section size of 32 data points square (IE 2x2 chunks). * * @author Leetom - * @version 2022-11-6 */ public class DhSectionPos { @@ -56,12 +55,12 @@ public class DhSectionPos public final static byte SECTION_REGION_DETAIL_LEVEL = SECTION_MINIMUM_DETAIL_LEVEL + LodUtil.REGION_DETAIL_LEVEL; - public byte sectionDetailLevel; + protected byte detailLevel; /** in a sectionDetailLevel grid */ - public int sectionX; + protected int x; /** in a sectionDetailLevel grid */ - public int sectionZ; + protected int z; @@ -69,11 +68,11 @@ public class DhSectionPos // constructors // //==============// - public DhSectionPos(byte sectionDetailLevel, int sectionX, int sectionZ) + public DhSectionPos(byte detailLevel, int x, int z) { - this.sectionDetailLevel = sectionDetailLevel; - this.sectionX = sectionX; - this.sectionZ = sectionZ; + this.detailLevel = detailLevel; + this.x = x; + this.z = z; } public DhSectionPos(DhBlockPos blockPos) @@ -95,9 +94,9 @@ public class DhSectionPos public DhSectionPos(byte detailLevel, DhLodPos dhLodPos) { - this.sectionDetailLevel = detailLevel; - this.sectionX = dhLodPos.x; - this.sectionZ = dhLodPos.z; + this.detailLevel = detailLevel; + this.x = dhLodPos.x; + this.z = dhLodPos.z; } @@ -106,36 +105,6 @@ public class DhSectionPos // converters // //============// - /** - * Overwrites this section pos with the given input.
- * Can be useful to prevent duplicate allocations in high traffic loops but should - * be used sparingly as it could accidentally cause bugs due to unexpected modifications. - */ - public void mutate(byte sectionDetailLevel, int sectionX, int sectionZ) - { - this.sectionDetailLevel = sectionDetailLevel; - this.sectionX = sectionX; - this.sectionZ = sectionZ; - } - - /** uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels. */ - public void convertSelfToDetailLevel(byte newDetailLevel) - { - // logic originally taken from DhLodPos - if (newDetailLevel >= this.sectionDetailLevel) - { - this.sectionX = Math.floorDiv(this.sectionX, BitShiftUtil.powerOfTwo(newDetailLevel - this.sectionDetailLevel)); - this.sectionZ = Math.floorDiv(this.sectionZ, BitShiftUtil.powerOfTwo(newDetailLevel - this.sectionDetailLevel)); - } - else - { - this.sectionX = this.sectionX * BitShiftUtil.powerOfTwo(this.sectionDetailLevel - newDetailLevel); - this.sectionZ = this.sectionZ * BitShiftUtil.powerOfTwo(this.sectionDetailLevel - newDetailLevel); - } - - this.sectionDetailLevel = newDetailLevel; - } - /** * uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels. * @@ -143,12 +112,41 @@ public class DhSectionPos */ public DhSectionPos convertNewToDetailLevel(byte newSectionDetailLevel) { - DhSectionPos newPos = new DhSectionPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); + DhSectionPos newPos = new DhSectionPos(this.detailLevel, this.x, this.z); newPos.convertSelfToDetailLevel(newSectionDetailLevel); return newPos; } + /** uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels. */ + protected void convertSelfToDetailLevel(byte newDetailLevel) + { + // logic originally taken from DhLodPos + if (newDetailLevel >= this.detailLevel) + { + this.x = Math.floorDiv(this.x, BitShiftUtil.powerOfTwo(newDetailLevel - this.detailLevel)); + this.z = Math.floorDiv(this.z, BitShiftUtil.powerOfTwo(newDetailLevel - this.detailLevel)); + } + else + { + this.x = this.x * BitShiftUtil.powerOfTwo(this.detailLevel - newDetailLevel); + this.z = this.z * BitShiftUtil.powerOfTwo(this.detailLevel - newDetailLevel); + } + + this.detailLevel = newDetailLevel; + } + + + + //==================// + // property getters // + //==================// + + public byte getDetailLevel() { return this.detailLevel; } + + public int getX() { return this.x; } + public int getZ() { return this.z; } + //=========// @@ -156,16 +154,16 @@ public class DhSectionPos //=========// /** @return the corner with the smallest X and Z coordinate */ - public DhLodPos getMinCornerLodPos() { return this.getMinCornerLodPos((byte) (this.sectionDetailLevel - 1)); } + public DhLodPos getMinCornerLodPos() { return this.getMinCornerLodPos((byte) (this.detailLevel - 1)); } /** @return the corner with the smallest X and Z coordinate */ public DhLodPos getMinCornerLodPos(byte returnDetailLevel) { - LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); + LodUtil.assertTrue(returnDetailLevel <= this.detailLevel, "returnDetailLevel must be less than sectionDetail"); - byte offset = (byte) (this.sectionDetailLevel - returnDetailLevel); + byte offset = (byte) (this.detailLevel - returnDetailLevel); return new DhLodPos(returnDetailLevel, - this.sectionX * BitShiftUtil.powerOfTwo(offset), - this.sectionZ * BitShiftUtil.powerOfTwo(offset)); + this.x * BitShiftUtil.powerOfTwo(offset), + this.z * BitShiftUtil.powerOfTwo(offset)); } /** @@ -180,13 +178,13 @@ public class DhSectionPos */ public int getWidthCountForLowerDetailedSection(byte returnDetailLevel) { - LodUtil.assertTrue(returnDetailLevel <= this.sectionDetailLevel, "returnDetailLevel must be less than sectionDetail"); - byte offset = (byte) (this.sectionDetailLevel - returnDetailLevel); + LodUtil.assertTrue(returnDetailLevel <= this.detailLevel, "returnDetailLevel must be less than sectionDetail"); + byte offset = (byte) (this.detailLevel - returnDetailLevel); return BitShiftUtil.powerOfTwo(offset); } /** @return how wide this section is in blocks */ - public int getBlockWidth() { return BitShiftUtil.powerOfTwo(this.sectionDetailLevel); } + public int getBlockWidth() { return BitShiftUtil.powerOfTwo(this.detailLevel); } public DhBlockPos2D getCenterBlockPos() { return new DhBlockPos2D(this.getCenterBlockPosX(), this.getCenterBlockPosZ()); } @@ -195,9 +193,9 @@ public class DhSectionPos public int getCenterBlockPosZ() { return this.getCenterBlockPos(false); } private int getCenterBlockPos(boolean returnX) { - int centerBlockPos = returnX ? this.sectionX : this.sectionZ; + int centerBlockPos = returnX ? this.x : this.z; - if (this.sectionDetailLevel == 0) + if (this.detailLevel == 0) { // already at block detail level, no conversion necessary return centerBlockPos; @@ -205,12 +203,12 @@ public class DhSectionPos // we can't get the center of the position at block level, only attempt to get the position offset for detail levels above 0 int positionOffset = 0; - if (this.sectionDetailLevel != 1) + if (this.detailLevel != 1) { - positionOffset = BitShiftUtil.powerOfTwo(this.sectionDetailLevel - 1); + positionOffset = BitShiftUtil.powerOfTwo(this.detailLevel - 1); } - return (centerBlockPos * BitShiftUtil.powerOfTwo(this.sectionDetailLevel)) + positionOffset; + return (centerBlockPos * BitShiftUtil.powerOfTwo(this.detailLevel)) + positionOffset; } @@ -236,31 +234,31 @@ public class DhSectionPos { throw new IllegalArgumentException("child0to3 must be between 0 and 3"); } - if (this.sectionDetailLevel <= 0) + if (this.detailLevel <= 0) { throw new IllegalStateException("section detail must be greater than 0"); } - return new DhSectionPos((byte) (this.sectionDetailLevel - 1), - this.sectionX * 2 + (child0to3 & 1), - this.sectionZ * 2 + BitShiftUtil.half(child0to3 & 2)); + return new DhSectionPos((byte) (this.detailLevel - 1), + this.x * 2 + (child0to3 & 1), + this.z * 2 + BitShiftUtil.half(child0to3 & 2)); } /** Returns this position's child index in its parent */ - public int getChildIndexOfParent() { return (this.sectionX & 1) + BitShiftUtil.square(this.sectionZ & 1); } + public int getChildIndexOfParent() { return (this.x & 1) + BitShiftUtil.square(this.z & 1); } - public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.sectionDetailLevel + 1), BitShiftUtil.half(this.sectionX), BitShiftUtil.half(this.sectionZ)); } + public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.detailLevel + 1), BitShiftUtil.half(this.x), BitShiftUtil.half(this.z)); } public DhSectionPos getAdjacentPos(EDhDirection dir) { - return new DhSectionPos(this.sectionDetailLevel, - this.sectionX + dir.getNormal().x, - this.sectionZ + dir.getNormal().z); + return new DhSectionPos(this.detailLevel, + this.x + dir.getNormal().x, + this.z + dir.getNormal().z); } - public DhLodPos getSectionBBoxPos() { return new DhLodPos(this.sectionDetailLevel, this.sectionX, this.sectionZ); } + public DhLodPos getSectionBBoxPos() { return new DhLodPos(this.detailLevel, this.x, this.z); } @@ -275,17 +273,17 @@ public class DhSectionPos { return true; } - else if (this.sectionDetailLevel == other.sectionDetailLevel) + else if (this.detailLevel == other.detailLevel) { return false; } - else if (this.sectionDetailLevel > other.sectionDetailLevel) + else if (this.detailLevel > other.detailLevel) { - return this.equals(other.convertNewToDetailLevel(this.sectionDetailLevel)); + return this.equals(other.convertNewToDetailLevel(this.detailLevel)); } else { - return other.equals(this.convertNewToDetailLevel(other.sectionDetailLevel)); + return other.equals(this.convertNewToDetailLevel(other.detailLevel)); } } @@ -319,7 +317,7 @@ public class DhSectionPos /** Applies the given consumer to all children of the position at the given section detail level. */ public void forEachChildAtLevel(byte sectionDetailLevel, Consumer callback) { - if (sectionDetailLevel == this.sectionDetailLevel) + if (sectionDetailLevel == this.detailLevel) { callback.accept(this); return; @@ -338,7 +336,7 @@ public class DhSectionPos //===============// /** Serialize() is different from toString() as it must NEVER be changed, and should be in a short format */ - public String serialize() { return "[" + this.sectionDetailLevel + ',' + this.sectionX + ',' + this.sectionZ + ']'; } + public String serialize() { return "[" + this.detailLevel + ',' + this.x + ',' + this.z + ']'; } @Nullable public static DhSectionPos deserialize(String value) @@ -357,7 +355,7 @@ public class DhSectionPos //===========// @Override - public String toString() { return "{" + this.sectionDetailLevel + "*" + this.sectionX + "," + this.sectionZ + "}"; } + public String toString() { return "{" + this.detailLevel + "*" + this.x + "," + this.z + "}"; } @Override public boolean equals(Object obj) @@ -372,17 +370,77 @@ public class DhSectionPos } DhSectionPos that = (DhSectionPos) obj; - return this.sectionDetailLevel == that.sectionDetailLevel && - this.sectionX == that.sectionX && - this.sectionZ == that.sectionZ; + return this.detailLevel == that.detailLevel && + this.x == that.x && + this.z == that.z; } @Override public int hashCode() { - return Integer.hashCode(this.sectionDetailLevel) ^ // XOR - Integer.hashCode(this.sectionX) ^ // XOR - Integer.hashCode(this.sectionZ); + return Integer.hashCode(this.detailLevel) ^ // XOR + Integer.hashCode(this.x) ^ // XOR + Integer.hashCode(this.z); + } + + + + //=============// + // sub classes // + //=============// + + /** + * Identical to {@link DhSectionPos} except it is mutable. + * See {@link DhSectionPos} for full documentation. + * + * @see DhSectionPos + */ + public static class DhMutableSectionPos extends DhSectionPos + { + + //==============// + // constructors // + //==============// + + public DhMutableSectionPos(byte sectionDetailLevel, int sectionX, int sectionZ) { super(sectionDetailLevel, sectionX, sectionZ); } + public DhMutableSectionPos(DhBlockPos blockPos) { super(blockPos); } + public DhMutableSectionPos(DhBlockPos2D blockPos) { super(blockPos); } + public DhMutableSectionPos(DhChunkPos chunkPos) { super(chunkPos); } + public DhMutableSectionPos(byte detailLevel, DhLodPos dhLodPos) { super(detailLevel, dhLodPos); } + + + + //============// + // converters // + //============// + + /** + * Overwrites this section pos with the given input.
+ * Can be useful to prevent duplicate allocations in high traffic loops but should + * be used sparingly as it could accidentally cause bugs due to unexpected modifications. + */ + public void mutate(byte sectionDetailLevel, int sectionX, int sectionZ) + { + this.detailLevel = sectionDetailLevel; + this.x = sectionX; + this.z = sectionZ; + } + + @Override + public void convertSelfToDetailLevel(byte newDetailLevel) { super.convertSelfToDetailLevel(newDetailLevel); } + + + + //==================// + // property getters // + //==================// + + public void setDetailLevel(byte sectionDetailLevel) { this.detailLevel = sectionDetailLevel; } + + public void setX(int sectionX) { this.x = sectionX; } + + public void setZ(int sectionZ) { this.z = sectionZ; } + } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index 8caa1641e..53dee52a2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -143,7 +143,7 @@ public class LodQuadTree extends QuadTree implements AutoClose { // walk up the tree until we hit the root node // this is done so any high detail changes flow up to the lower detail render sections as well - while (pos.sectionDetailLevel <= this.treeMinDetailLevel) + while (pos.getDetailLevel() <= this.treeMinDetailLevel) { try { @@ -223,7 +223,7 @@ public class LodQuadTree extends QuadTree implements AutoClose expectedDetailLevel += DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL; - if (sectionPos.sectionDetailLevel > expectedDetailLevel) + if (sectionPos.getDetailLevel() > expectedDetailLevel) { // section detail level too high // boolean canThisPosRender = renderSection.isRenderingEnabled(); @@ -273,7 +273,7 @@ public class LodQuadTree extends QuadTree implements AutoClose } } // TODO this should only equal the expected detail level, the (expectedDetailLevel-1) is a temporary fix to prevent corners from being cut out - else if (sectionPos.sectionDetailLevel == expectedDetailLevel || sectionPos.sectionDetailLevel == expectedDetailLevel - 1) + else if (sectionPos.getDetailLevel() == expectedDetailLevel || sectionPos.getDetailLevel() == expectedDetailLevel - 1) { // this is the detail level we want to render // // prepare this section for rendering diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index 18e06d240..eaa32502e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -160,7 +160,7 @@ public class LodRenderSection implements IDebugRenderable public void reload(ILodRenderSourceProvider renderDataProvider) { // debug rendering - if (this.pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + if (this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) { DebugRenderer.makeParticle( new DebugRenderer.BoxParticle( @@ -324,7 +324,7 @@ public class LodRenderSection implements IDebugRenderable if (this.canBuildBuffer()) { // debug - if (this.pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + if (this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) { DebugRenderer.makeParticle( new DebugRenderer.BoxParticle( diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java index c4f51f256..502537ce2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java @@ -161,7 +161,7 @@ public class RenderBufferHandler return abPosDifference; } - return loadedBufferA.pos.sectionDetailLevel - loadedBufferB.pos.sectionDetailLevel; // If all else fails, sort by detail + return loadedBufferA.pos.getDetailLevel() - loadedBufferB.pos.getDetailLevel(); // If all else fails, sort by detail }; // Build the sorted list diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java index 70aa58e97..a8794be82 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadNode.java @@ -183,17 +183,17 @@ public class QuadNode throw new IllegalArgumentException("Input section pos " + inputSectionPos + " outside of this quadNode's pos: " + this.sectionPos + ", this node's blockPos: " + this.sectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " block width: " + this.sectionPos.getBlockWidth() + " input detail level: " + inputSectionPos.convertNewToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL) + " width: " + inputSectionPos.getBlockWidth()); } - if (inputSectionPos.sectionDetailLevel > this.sectionPos.sectionDetailLevel) + if (inputSectionPos.getDetailLevel() > this.sectionPos.getDetailLevel()) { - throw new IllegalArgumentException("detail level higher than this node. Node Detail level: " + this.sectionPos.sectionDetailLevel + " input detail level: " + inputSectionPos.sectionDetailLevel); + throw new IllegalArgumentException("detail level higher than this node. Node Detail level: " + this.sectionPos.getDetailLevel() + " input detail level: " + inputSectionPos.getDetailLevel()); } - if (inputSectionPos.sectionDetailLevel == this.sectionPos.sectionDetailLevel && !inputSectionPos.equals(this.sectionPos)) + if (inputSectionPos.getDetailLevel() == this.sectionPos.getDetailLevel() && !inputSectionPos.equals(this.sectionPos)) { throw new IllegalArgumentException("Node and input detail level are equal, however positions are not; this tree doesn't contain the requested position. Node pos: " + this.sectionPos + ", input pos: " + inputSectionPos); } - if (inputSectionPos.sectionDetailLevel < this.minimumDetailLevel) + if (inputSectionPos.getDetailLevel() < this.minimumDetailLevel) { throw new IllegalArgumentException("Input position is requesting a detail level lower than what this node can provide. Node minimum detail level: " + this.minimumDetailLevel + ", input pos: " + inputSectionPos); } @@ -201,7 +201,7 @@ public class QuadNode // get/set logic - if (inputSectionPos.sectionDetailLevel == this.sectionPos.sectionDetailLevel) + if (inputSectionPos.getDetailLevel() == this.sectionPos.getDetailLevel()) { // this node is the requested position if (replaceValue) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java index e40f4f2ab..9dcaf72e7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java @@ -130,8 +130,8 @@ public class QuadTree DhSectionPos rootPos = pos.convertNewToDetailLevel(this.treeMinDetailLevel); - int ringListPosX = rootPos.sectionX; - int ringListPosZ = rootPos.sectionZ; + int ringListPosX = rootPos.getX(); + int ringListPosZ = rootPos.getZ(); QuadNode topQuadNode = this.topRingList.get(ringListPosX, ringListPosZ); if (topQuadNode == null) @@ -163,7 +163,7 @@ public class QuadTree public boolean isSectionPosInBounds(DhSectionPos testPos) { // check if the testPos is within the detail level limits of the tree - boolean detailLevelWithinBounds = this.treeMaxDetailLevel <= testPos.sectionDetailLevel && testPos.sectionDetailLevel <= this.treeMinDetailLevel; + boolean detailLevelWithinBounds = this.treeMaxDetailLevel <= testPos.getDetailLevel() && testPos.getDetailLevel() <= this.treeMinDetailLevel; if (!detailLevelWithinBounds) { return false; @@ -175,8 +175,8 @@ public class QuadTree DhLodPos treeCornerPos = new DhLodPos((byte) 0, treeBlockCorner.x, treeBlockCorner.z); DhSectionPos inputSectionCorner = testPos.convertNewToDetailLevel((byte) 0); - DhLodPos inputCornerPos = new DhLodPos((byte) 0, inputSectionCorner.sectionX, inputSectionCorner.sectionZ); - int inputBlockWidth = BitShiftUtil.powerOfTwo(testPos.sectionDetailLevel); + DhLodPos inputCornerPos = new DhLodPos((byte) 0, inputSectionCorner.getX(), inputSectionCorner.getZ()); + int inputBlockWidth = BitShiftUtil.powerOfTwo(testPos.getDetailLevel()); return DoSquaresOverlap(treeCornerPos, this.widthInBlocks, inputCornerPos, inputBlockWidth); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadNodeChildIndexIterator.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadNodeChildIndexIterator.java index 77dda14d1..639f8e40a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadNodeChildIndexIterator.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadNodeChildIndexIterator.java @@ -36,7 +36,7 @@ public class QuadNodeChildIndexIterator implements Iterator public QuadNodeChildIndexIterator(QuadNode parentNode, boolean returnNullChildPos) { // only get the children if this section isn't at the bottom of the tree - if (parentNode.sectionPos.sectionDetailLevel > parentNode.minimumDetailLevel) + if (parentNode.sectionPos.getDetailLevel() > parentNode.minimumDetailLevel) { // go over each child pos for (int i = 0; i < 4; i++) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadTreeNodeIterator.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadTreeNodeIterator.java index b36b4167f..13745870e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadTreeNodeIterator.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/iterators/QuadTreeNodeIterator.java @@ -46,7 +46,7 @@ public class QuadTreeNodeIterator implements Iterator> this.onlyReturnLeafValues = onlyReturnLeafValues; // TODO the naming conversion for these are flipped in a lot of places this.highestDetailLevel = rootNode.minimumDetailLevel; - this.iteratorDetailLevel = rootNode.sectionPos.sectionDetailLevel; + this.iteratorDetailLevel = rootNode.sectionPos.getDetailLevel(); if (!this.onlyReturnLeafValues) diff --git a/core/src/test/java/tests/QuadTreeTest.java b/core/src/test/java/tests/QuadTreeTest.java index ea79698af..722dfbaec 100644 --- a/core/src/test/java/tests/QuadTreeTest.java +++ b/core/src/test/java/tests/QuadTreeTest.java @@ -649,7 +649,7 @@ public class QuadTreeTest DhSectionPos sectionPos = directChildIterator.next(); QuadNode childNode = node.getNode(sectionPos); - Assert.assertTrue("Child node recurred too low. Min detail level: " + minDetailLevel + ", node detail level: " + childNode.sectionPos.sectionDetailLevel, childNode.sectionPos.sectionDetailLevel >= minDetailLevel); + Assert.assertTrue("Child node recurred too low. Min detail level: " + minDetailLevel + ", node detail level: " + childNode.sectionPos.getDetailLevel(), childNode.sectionPos.getDetailLevel() >= minDetailLevel); recursivelyCreateNodeChildren(childNode, minDetailLevel, minimumDetailLevelReachedRef); childNodesIterated = true; @@ -657,9 +657,9 @@ public class QuadTreeTest // keep track of how far down the tree we have gone - if (node.sectionPos.sectionDetailLevel < minimumDetailLevelReachedRef.get()) + if (node.sectionPos.getDetailLevel() < minimumDetailLevelReachedRef.get()) { - minimumDetailLevelReachedRef.set(node.sectionPos.sectionDetailLevel); + minimumDetailLevelReachedRef.set(node.sectionPos.getDetailLevel()); } @@ -667,11 +667,11 @@ public class QuadTreeTest // assertions if (childNodesCreated) { - Assert.assertTrue("node children created below minimum detail level", node.sectionPos.sectionDetailLevel >= minDetailLevel); + Assert.assertTrue("node children created below minimum detail level", node.sectionPos.getDetailLevel() >= minDetailLevel); } if (childNodesIterated) { - Assert.assertTrue("node children iterated below minimum detail level", node.sectionPos.sectionDetailLevel - 1 >= minDetailLevel); + Assert.assertTrue("node children iterated below minimum detail level", node.sectionPos.getDetailLevel() - 1 >= minDetailLevel); } } From 8a0e3a710cf5da8b2aa0c0b9de020dce3c53a7c4 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 16 Sep 2023 08:03:39 -0500 Subject: [PATCH 15/15] Add GL Context creation debug configs In an attempt to fix Steam Deck crashing due to being unable to create the GL Context --- .../api/enums/config/EGlProfileMode.java | 30 +++++++++++++++++++ .../distanthorizons/core/config/Config.java | 14 +++++++++ .../core/render/glObject/GLProxy.java | 22 ++++++++++++-- .../assets/distanthorizons/lang/en_us.json | 15 ++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/com/seibel/distanthorizons/api/enums/config/EGlProfileMode.java diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EGlProfileMode.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EGlProfileMode.java new file mode 100644 index 000000000..acf2f8181 --- /dev/null +++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EGlProfileMode.java @@ -0,0 +1,30 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.api.enums.config; + +/** + * @since API 1.0.0 + */ +public enum EGlProfileMode +{ + CORE, + COMPAT, + ANY; +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index 7a5e53f08..8bce0b706 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -1165,21 +1165,35 @@ public class Config + "") .build(); + // TODO temporary test, remove me public static ConfigEntry skipChunkLoadUpdates = new ConfigEntry.Builder() .set(false) .comment("") .build(); + // TODO temporary test, remove me public static ConfigEntry skipChunkUnloadUpdates = new ConfigEntry.Builder() .set(false) .comment("") .build(); + // TODO temporary test, remove me public static ConfigEntry skipFullDataUpdateQueue = new ConfigEntry.Builder() .set(false) .comment("") .build(); + // TODO temporary test, remove me + public static ConfigEntry glProfileMode = new ConfigEntry.Builder() + .set(EGlProfileMode.CORE) + .comment("") + .build(); + // TODO temporary test, remove me + public static ConfigEntry glForwardCompatibilityMode = new ConfigEntry.Builder() + .set(true) + .comment("") + .build(); + diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java index da4d5c7fe..2403a71a3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java @@ -21,6 +21,7 @@ package com.seibel.distanthorizons.core.render.glObject; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.seibel.distanthorizons.api.enums.config.EGLErrorHandlingMode; +import com.seibel.distanthorizons.api.enums.config.EGlProfileMode; import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; @@ -160,10 +161,27 @@ public class GLProxy // DO NOT comment out the following 2 lines: they are needed for mac and creating forward compatible contexts GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3); GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2); - GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE); - GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE); + // TODO remove me + boolean useForwardCompatibility = Config.Client.Advanced.Debugging.glForwardCompatibilityMode.get(); + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, useForwardCompatibility ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE); + + // TODO remove me + EGlProfileMode profileMode = Config.Client.Advanced.Debugging.glProfileMode.get(); + if (profileMode == EGlProfileMode.CORE) + { + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); + } + else if (profileMode == EGlProfileMode.ANY) + { + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_ANY_PROFILE); + } + else + { + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_COMPAT_PROFILE); + } + // create the Lod Builder context lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, minecraftGlContext); if (lodBuilderGlContext == 0) diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index dbcfd896a..735675907 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -425,6 +425,14 @@ "OpenGL Error Handling Mode", "distanthorizons.config.client.advanced.debugging.glErrorHandlingMode.@tooltip": "Defines how OpenGL errors are handled. \nMay incorrectly catch OpenGL errors thrown by other mods.", + "distanthorizons.config.client.advanced.debugging.glProfileMode": + "OpenGL Profile Mode", + "distanthorizons.config.client.advanced.debugging.glProfileMode.@tooltip": + "Requires rebooting Minecraft to apply.", + "distanthorizons.config.client.advanced.debugging.glForwardCompatibilityMode": + "OpenGL Forward Compatibility Mode", + "distanthorizons.config.client.advanced.debugging.glForwardCompatibilityMode.@tooltip": + "Requires rebooting Minecraft to apply.", "distanthorizons.config.client.advanced.buffers": @@ -732,6 +740,13 @@ "distanthorizons.config.enum.EGLErrorHandlingMode.LOG_THROW": "Log-Throw", + "distanthorizons.config.enum.EGlProfileMode.CORE": + "Core", + "distanthorizons.config.enum.EGlProfileMode.COMPAT": + "Compat", + "distanthorizons.config.enum.EGlProfileMode.ANY": + "Any", + "distanthorizons.config.enum.ELoggerMode.DISABLED": "Disabled", "distanthorizons.config.enum.ELoggerMode.LOG_ALL_TO_FILE":