Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core
This commit is contained in:
+26
-13
@@ -112,19 +112,6 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
|
||||
// advanced graphic settings //
|
||||
//===========================//
|
||||
|
||||
/**
|
||||
* Sets whether LODs outside the view frustum culling will
|
||||
* be culled. <br><br>
|
||||
*
|
||||
* Disabling this will prevent LODs not rendering on the corner
|
||||
* of the users vision and may fix issues if LODs appear to
|
||||
* start/stop rendering incorrectly based on the camera direction,
|
||||
* but will also reduce FPS.
|
||||
*
|
||||
* @since API 1.1.0
|
||||
*/
|
||||
IDhApiConfigValue<Boolean> disableFrustumCulling();
|
||||
|
||||
/**
|
||||
* Sets the distance used by the near clip plane to reduce
|
||||
* overdraw. <br>
|
||||
@@ -187,4 +174,30 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
|
||||
*/
|
||||
IDhApiConfigValue<ELodShading> lodShading();
|
||||
|
||||
/**
|
||||
* Sets whether LODs outside the view frustum culling will
|
||||
* be culled. <br><br>
|
||||
*
|
||||
* Disabling this will prevent LODs not rendering on the corner
|
||||
* of the users vision and may fix issues if LODs appear to
|
||||
* start/stop rendering incorrectly based on the camera direction,
|
||||
* but will also reduce FPS.
|
||||
*
|
||||
* @since API 1.1.0
|
||||
* @see IDhApiGraphicsConfig#disableShadowFrustumCulling()
|
||||
*/
|
||||
IDhApiConfigValue<Boolean> disableFrustumCulling();
|
||||
|
||||
/**
|
||||
* Identical to the other frustum culling option, except that it is
|
||||
* only used when a shader mod is present using the DH API
|
||||
* and the shadow pass is being rendered. <br><br>
|
||||
*
|
||||
* Disable this if shadows render incorrectly.
|
||||
*
|
||||
* @since API 1.1.0
|
||||
* @see IDhApiGraphicsConfig#disableFrustumCulling()
|
||||
*/
|
||||
IDhApiConfigValue<Boolean> disableShadowFrustumCulling();
|
||||
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.api.interfaces.override.rendering;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
|
||||
/**
|
||||
* The culling frustum used during Distant Horizons' shadow pass
|
||||
* if another mod has enabled Distant Horizons' shadow
|
||||
* pass via the API. <br><br>
|
||||
*
|
||||
* If no {@link IDhApiShadowCullingFrustum} is bound then culling
|
||||
* will not be done in the shadow pass.
|
||||
*
|
||||
* @see IDhApiCullingFrustum
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2024-2-10
|
||||
* @since API 1.1.0
|
||||
*/
|
||||
public interface IDhApiShadowCullingFrustum extends IDhApiCullingFrustum
|
||||
{
|
||||
// should be identical to the parent culling frustum
|
||||
}
|
||||
+8
-4
@@ -105,10 +105,6 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
|
||||
// advanced graphic settings //
|
||||
//===========================//
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Boolean> disableFrustumCulling()
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling); }
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public IDhApiConfigValue<EOverdrawPrevention> overdrawPrevention()
|
||||
@@ -150,6 +146,14 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
|
||||
public IDhApiConfigValue<ELodShading> lodShading()
|
||||
{ return new DhApiConfigValue<ELodShading, ELodShading>(Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Boolean> disableFrustumCulling()
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Boolean> disableShadowFrustumCulling()
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.AdvancedGraphics.disableShadowPassFrustumCulling); }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
@@ -54,7 +55,7 @@ public class SharedApi
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
private static final Set<DhChunkPos> UPDATING_CHUNK_SET = ConcurrentHashMap.newKeySet();
|
||||
private static final Set<DhChunkPos> UPDATING_CHUNK_POS_SET = ConcurrentHashMap.newKeySet();
|
||||
/** how many chunks can be queued for updating per thread, used to prevent updates from infinitely pilling up if the user flys around extremely fast */
|
||||
private static final int MAX_UPDATING_CHUNK_COUNT_PER_THREAD = 500;
|
||||
private static final int MIN_MS_BETWEEN_OVERLOADED_LOG_MESSAGE = 5_000;
|
||||
@@ -79,7 +80,7 @@ public class SharedApi
|
||||
this.f3Message = new F3Screen.DynamicMessage(() ->
|
||||
{
|
||||
int maxUpdateCount = MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get();
|
||||
return LodUtil.formatLog("Queued chunk updates: " + UPDATING_CHUNK_SET.size() + " / " + maxUpdateCount);
|
||||
return LodUtil.formatLog("Queued chunk updates: " + UPDATING_CHUNK_POS_SET.size() + " / " + maxUpdateCount);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -143,6 +144,13 @@ public class SharedApi
|
||||
// chunk update //
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* Used to prevent getting a full chunk from MC if it isn't necessary. <br>
|
||||
* This is important since asking MC for a chunk is slow and may block the render thread.
|
||||
*/
|
||||
public static boolean isChunkAtBlockPosAlreadyUpdating(int blockPosX, int blockPosZ) { return UPDATING_CHUNK_POS_SET.contains(new DhChunkPos(new DhBlockPos2D(blockPosX, blockPosZ))); }
|
||||
|
||||
|
||||
/** handles both block place and break events */
|
||||
public void chunkBlockChangedEvent(IChunkWrapper chunk, ILevelWrapper level) { this.applyChunkUpdate(chunk, level, true); }
|
||||
|
||||
@@ -206,7 +214,7 @@ public class SharedApi
|
||||
// task limiting check //
|
||||
//=====================//
|
||||
|
||||
int currentQueueCount = UPDATING_CHUNK_SET.size();
|
||||
int currentQueueCount = UPDATING_CHUNK_POS_SET.size();
|
||||
int maxQueueCount = MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get();
|
||||
if (currentQueueCount >= maxQueueCount)
|
||||
{
|
||||
@@ -224,12 +232,12 @@ public class SharedApi
|
||||
}
|
||||
|
||||
// prevent duplicate update requests
|
||||
if (UPDATING_CHUNK_SET.contains(chunkWrapper.getChunkPos()))
|
||||
if (UPDATING_CHUNK_POS_SET.contains(chunkWrapper.getChunkPos()))
|
||||
{
|
||||
// this chunk is already being updated
|
||||
return;
|
||||
}
|
||||
UPDATING_CHUNK_SET.add(chunkWrapper.getChunkPos());
|
||||
UPDATING_CHUNK_POS_SET.add(chunkWrapper.getChunkPos());
|
||||
|
||||
|
||||
|
||||
@@ -343,13 +351,13 @@ public class SharedApi
|
||||
CHUNK_UPDATE_TIMER.schedule(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run() { UPDATING_CHUNK_SET.remove(chunkWrapper.getChunkPos()); }
|
||||
public void run() { UPDATING_CHUNK_POS_SET.remove(chunkWrapper.getChunkPos()); }
|
||||
}, updateTimeoutInSec * 1000L);
|
||||
}
|
||||
else
|
||||
{
|
||||
// instantly allow this chunk to be updated again
|
||||
UPDATING_CHUNK_SET.remove(chunkWrapper.getChunkPos());
|
||||
UPDATING_CHUNK_POS_SET.remove(chunkWrapper.getChunkPos());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.seibel.distanthorizons.core.config.types.*;
|
||||
import com.seibel.distanthorizons.core.config.types.enums.*;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.coreapi.util.StringUtil;
|
||||
@@ -541,18 +542,6 @@ public class Config
|
||||
|
||||
public static class AdvancedGraphics
|
||||
{
|
||||
public static ConfigEntry<Boolean> disableFrustumCulling = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "If false LODs outside the player's camera \n"
|
||||
+ "aren't drawn, increasing GPU performance. \n"
|
||||
+ "\n"
|
||||
+ "If true all LODs are drawn, even those behind \n"
|
||||
+ "the player's camera, decreasing GPU performance. \n"
|
||||
+ "\n"
|
||||
+ "Disable this if you see LODs disappearing at the corners of your vision.")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* @deprecated Use overdrawPrevention instead, will be removed when DH updates to MC 1.21 <br>
|
||||
* After removal a float value will be used to control overdraw instead. <br>
|
||||
@@ -673,6 +662,29 @@ public class Config
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> disableFrustumCulling = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "If false LODs outside the player's camera \n"
|
||||
+ "aren't drawn, increasing GPU performance. \n"
|
||||
+ "\n"
|
||||
+ "If true all LODs are drawn, even those behind \n"
|
||||
+ "the player's camera, decreasing GPU performance. \n"
|
||||
+ "\n"
|
||||
+ "Disable this if you see LODs disappearing at the corners of your vision.")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> disableShadowPassFrustumCulling = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "Identical to the other frustum culling option\n"
|
||||
+ "only used when a shader mod is present using the DH API\n"
|
||||
+ "and the shadow pass is being rendered.\n"
|
||||
+ "\n"
|
||||
+ "Disable this if shadows render incorrectly.")
|
||||
.build();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1285,6 +1297,26 @@ public class Config
|
||||
.addListener(UnsafeValuesConfigListener.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> columnBuilderDebugEnable = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
||||
.addListener(DebugColumnConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
public static ConfigEntry<Integer> columnBuilderDebugDetailLevel = new ConfigEntry.Builder<Integer>()
|
||||
.set((int) DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
||||
.addListener(DebugColumnConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
public static ConfigEntry<Integer> columnBuilderDebugXPos = new ConfigEntry.Builder<Integer>()
|
||||
.set(0)
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
||||
.addListener(DebugColumnConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
public static ConfigEntry<Integer> columnBuilderDebugZPos = new ConfigEntry.Builder<Integer>()
|
||||
.set(0)
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
||||
.addListener(DebugColumnConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.config.eventHandlers;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.api.enums.config.EHorizontalQuality;
|
||||
import com.seibel.distanthorizons.api.enums.config.EMaxHorizontalResolution;
|
||||
import com.seibel.distanthorizons.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.distanthorizons.api.enums.config.quickOptions.EQualityPreset;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.ETransparency;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.ConfigEntryWithPresetOptions;
|
||||
import com.seibel.distanthorizons.core.config.eventHandlers.presets.AbstractPresetConfigEventHandler;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.config.IConfigEntry;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class DebugColumnConfigEventHandler implements IConfigListener
|
||||
{
|
||||
public static DebugColumnConfigEventHandler INSTANCE = new DebugColumnConfigEventHandler();
|
||||
|
||||
@Override
|
||||
public void onConfigValueSet()
|
||||
{
|
||||
IDhApiRenderProxy renderProxy = DhApi.Delayed.renderProxy;
|
||||
if (renderProxy != null)
|
||||
{
|
||||
renderProxy.clearRenderDataCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+15
-11
@@ -180,18 +180,22 @@ public class ColumnRenderBufferBuilder
|
||||
// Variable initialization
|
||||
EDebugRendering debugMode = Config.Client.Advanced.Debugging.debugRendering.get();
|
||||
|
||||
// TODO make a config for this
|
||||
// can be uncommented to limit which section positions are build and thus, rendered
|
||||
// can be used to limit which section positions are build and thus, rendered
|
||||
// useful when debugging a specific section
|
||||
// if (renderSource.sectionPos.getDetailLevel() == 6
|
||||
// && renderSource.sectionPos.getZ() == 0 && renderSource.sectionPos.getX() == 0)
|
||||
// {
|
||||
// int test = 0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
boolean enableColumnBufferLimit = Config.Client.Advanced.Debugging.columnBuilderDebugEnable.get();
|
||||
if (enableColumnBufferLimit)
|
||||
{
|
||||
if (renderSource.sectionPos.getDetailLevel() == Config.Client.Advanced.Debugging.columnBuilderDebugDetailLevel.get()
|
||||
&& renderSource.sectionPos.getX() == Config.Client.Advanced.Debugging.columnBuilderDebugXPos.get()
|
||||
&& renderSource.sectionPos.getZ() == Config.Client.Advanced.Debugging.columnBuilderDebugZPos.get())
|
||||
{
|
||||
int test = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
byte detailLevel = renderSource.getDataDetailLevel();
|
||||
for (int x = 0; x < ColumnRenderSource.SECTION_SIZE; x++)
|
||||
|
||||
+20
-1
@@ -243,6 +243,21 @@ public class FullDataToRenderDataTransformer
|
||||
int id = FullDataPointUtil.getId(fullData);
|
||||
int light = FullDataPointUtil.getLight(fullData);
|
||||
|
||||
// TODO how should corrupted data be handled?
|
||||
// TODO why is the full data corrupted in the first place? FullDataPointUtil hasn't been changed in a long time, could one of the full data point objects be corrupted?
|
||||
// TODO if either of these happen the ID might also be invalid
|
||||
//if (bottomY + blockHeight > 300)
|
||||
//{
|
||||
// // this data point is too tall, it's probably a monolith
|
||||
// int k = 0;
|
||||
// throw new RuntimeException();
|
||||
//}
|
||||
//if (light > 16 || light < 0)
|
||||
//{
|
||||
// // light is out of range
|
||||
// throw new RuntimeException();
|
||||
//}
|
||||
|
||||
IBiomeWrapper biome;
|
||||
IBlockStateWrapper block;
|
||||
try
|
||||
@@ -257,7 +272,11 @@ public class FullDataToRenderDataTransformer
|
||||
{
|
||||
brokenPos.add(fullDataMapping.getPos());
|
||||
String dimName = level.getLevelWrapper().getDimensionType().getDimensionName();
|
||||
LOGGER.warn("Unable to get data point with id ["+id+"] (Max possible ID: ["+fullDataMapping.getMaxValidId()+"]) for pos ["+fullDataMapping.getPos()+"] in dimension ["+dimName+"]. Error: ["+e.getMessage()+"]. Further errors for this position won't be logged.");
|
||||
LOGGER.warn("Unable to get data point with id ["+id+"] " +
|
||||
"(Max possible ID: ["+fullDataMapping.getMaxValidId()+"]) " +
|
||||
"for pos ["+fullDataMapping.getPos()+"] in dimension ["+dimName+"]. " +
|
||||
"Error: ["+e.getMessage()+"]. " +
|
||||
"Further errors for this position won't be logged.");
|
||||
}
|
||||
|
||||
// skip rendering broken data
|
||||
|
||||
+10
-23
@@ -17,6 +17,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
@@ -187,8 +188,6 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
@Override
|
||||
public CompletableFuture<Void> updateDataSourcesWithChunkDataAsync(ChunkSizedFullDataAccessor chunkDataView)
|
||||
{
|
||||
DhSectionPos pos = chunkDataView.getSectionPos().convertNewToDetailLevel(DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||
|
||||
ThreadPoolExecutor executor = ThreadPools.getFileHandlerExecutor();
|
||||
if (executor == null || executor.isTerminated())
|
||||
{
|
||||
@@ -199,7 +198,15 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
try
|
||||
{
|
||||
// run file handling on a separate thread
|
||||
return CompletableFuture.runAsync(() -> this.updateDataSourcesRecursively(pos, chunkDataView), executor);
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
DhSectionPos bottomPos = chunkDataView.getSectionPos().convertNewToDetailLevel(DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||
|
||||
bottomPos.forEachPosUpToDetailLevel(
|
||||
this.topSectionDetailLevelRef.byteValue(),
|
||||
(pos) -> this.updateDataSourceAtPos(pos, chunkDataView) );
|
||||
|
||||
}, executor);
|
||||
}
|
||||
catch (RejectedExecutionException ignore)
|
||||
{
|
||||
@@ -207,26 +214,6 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
/** Updates every data source from this position up to {@link AbstractDataSourceHandler#topSectionDetailLevelRef} */
|
||||
private void updateDataSourcesRecursively(DhSectionPos pos, ChunkSizedFullDataAccessor chunkDataView)
|
||||
{
|
||||
// update up until we reach the highest available data source
|
||||
if (pos.getDetailLevel() > this.topSectionDetailLevelRef.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DhSectionPos chunkSectionPos = chunkDataView.getSectionPos();
|
||||
LodUtil.assertTrue(chunkSectionPos.overlapsExactly(pos), "Update failed, chunk [" + chunkSectionPos + "] does not overlap section [" + pos + "].");
|
||||
|
||||
// update this pos
|
||||
this.updateDataSourceAtPos(pos, chunkDataView);
|
||||
|
||||
// recursively update the parent pos
|
||||
DhSectionPos parentPos = pos.getParentPos();
|
||||
this.updateDataSourcesRecursively(parentPos, chunkDataView);
|
||||
}
|
||||
protected void updateDataSourceAtPos(DhSectionPos pos, ChunkSizedFullDataAccessor chunkData)
|
||||
{
|
||||
// a lock is necessary to prevent two threads from writing to the same position at once,
|
||||
|
||||
+7
-1
@@ -106,7 +106,11 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
protected IFullDataSource createNewDataSourceFromExistingDtos(DhSectionPos pos)
|
||||
{
|
||||
IIncompleteFullDataSource newFullDataSource = this.makeEmptyDataSource(pos);
|
||||
|
||||
return this.updateFromDataSourceFromExistingDtos(newFullDataSource);
|
||||
}
|
||||
protected IFullDataSource updateFromDataSourceFromExistingDtos(IIncompleteFullDataSource newFullDataSource)
|
||||
{
|
||||
DhSectionPos pos = newFullDataSource.getSectionPos();
|
||||
|
||||
boolean showFullDataFileSampling = Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileStatus.get();
|
||||
if (showFullDataFileSampling)
|
||||
@@ -180,6 +184,8 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
return newFullDataSource.tryPromotingToCompleteDataSource();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected IIncompleteFullDataSource makeEmptyDataSource(DhSectionPos pos)
|
||||
{
|
||||
|
||||
+35
-57
@@ -22,11 +22,10 @@ package com.seibel.distanthorizons.core.file.fullDatafile;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
|
||||
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
|
||||
import com.seibel.distanthorizons.core.generation.MissingWorldGenPositionFinder;
|
||||
import com.seibel.distanthorizons.core.generation.IWorldGenerationQueue;
|
||||
import com.seibel.distanthorizons.core.generation.MissingWorldGenPositionFinder;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult;
|
||||
import com.seibel.distanthorizons.core.level.DhLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
@@ -35,7 +34,6 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -50,8 +48,8 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
|
||||
private final ArrayList<IOnWorldGenCompleteListener> onWorldGenTaskCompleteListeners = new ArrayList<>();
|
||||
|
||||
/** Used to prevent data sources from being garbage collected before their world gen finishes. */
|
||||
private final ConcurrentHashMap<DhSectionPos, IFullDataSource> generatingDataSourceByPos = new ConcurrentHashMap<>();
|
||||
/** Used to prevent world gen tasks from being queued multiple times. */
|
||||
private final Set<DhSectionPos> generatingDataPos = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
|
||||
|
||||
@@ -69,16 +67,20 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
//===========//
|
||||
|
||||
@Override
|
||||
public IFullDataSource get(DhSectionPos pos)
|
||||
public IFullDataSource get(DhSectionPos pos) { return this.get(pos, true); }
|
||||
public IFullDataSource get(DhSectionPos pos, boolean runWorldGenCheck)
|
||||
{
|
||||
IFullDataSource dataSource = super.get(pos);
|
||||
|
||||
// add world gen tasks for missing columns in the data source
|
||||
// if this position hasn't already been queued for generation
|
||||
IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null && !this.generatingDataSourceByPos.containsKey(pos))
|
||||
if (runWorldGenCheck)
|
||||
{
|
||||
this.queueWorldGenForMissingColumnsInDataSource(worldGenQueue, pos, dataSource);
|
||||
// add world gen tasks for missing columns in the data source
|
||||
// if this position hasn't already been queued for generation
|
||||
IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null && !this.generatingDataPos.contains(pos))
|
||||
{
|
||||
this.queueWorldGenForMissingColumnsInDataSource(worldGenQueue, pos, dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
return dataSource;
|
||||
@@ -104,7 +106,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
public void clearGenerationQueue()
|
||||
{
|
||||
this.worldGenQueueRef.set(null);
|
||||
this.generatingDataSourceByPos.clear(); // clear the incomplete data sources
|
||||
this.generatingDataPos.clear(); // clear the incomplete data sources
|
||||
}
|
||||
|
||||
/** Can be used to remove positions that are outside the player's render distance. */
|
||||
@@ -112,11 +114,11 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
HashSet<DhSectionPos> removedRequests = new HashSet<>();
|
||||
|
||||
this.generatingDataSourceByPos.forEach((pos, dataSource) ->
|
||||
this.generatingDataPos.forEach((pos) ->
|
||||
{
|
||||
if (removeIf.apply(pos))
|
||||
{
|
||||
this.generatingDataSourceByPos.remove(pos);
|
||||
this.generatingDataPos.remove(pos);
|
||||
removedRequests.add(pos);
|
||||
}
|
||||
});
|
||||
@@ -139,35 +141,33 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
// events //
|
||||
//========//
|
||||
|
||||
private void onWorldGenTaskComplete(WorldGenResult genTaskResult, Throwable exception, GenTask genTask, DhSectionPos pos)
|
||||
private void onWorldGenTaskComplete(WorldGenResult genTaskResult, Throwable exception)
|
||||
{
|
||||
if (exception != null)
|
||||
{
|
||||
// don't log shutdown exceptions
|
||||
if (!(exception instanceof CancellationException || exception.getCause() instanceof CancellationException))
|
||||
{
|
||||
LOGGER.error("Uncaught Gen Task Exception at " + pos + ":", exception);
|
||||
LOGGER.error("Uncaught Gen Task Exception at [" + genTaskResult.pos + "], error: ["+ exception.getMessage() + "].", exception);
|
||||
}
|
||||
}
|
||||
else if (genTaskResult.success)
|
||||
{
|
||||
this.fireOnGenPosSuccessListeners(pos);
|
||||
this.fireOnGenPosSuccessListeners(genTaskResult.pos);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// generation didn't complete
|
||||
LOGGER.debug("Gen Task Failed at " + pos);
|
||||
LOGGER.debug("Gen Task Failed at " + genTaskResult.pos);
|
||||
}
|
||||
|
||||
|
||||
// if the generation task was split up into smaller positions, add the on-complete event to them
|
||||
for (CompletableFuture<WorldGenResult> siblingFuture : genTaskResult.childFutures)
|
||||
{
|
||||
siblingFuture.whenComplete((siblingGenTaskResult, siblingEx) -> this.onWorldGenTaskComplete(siblingGenTaskResult, siblingEx, genTask, pos));
|
||||
siblingFuture.whenComplete((siblingGenTaskResult, siblingEx) -> this.onWorldGenTaskComplete(siblingGenTaskResult, siblingEx));
|
||||
}
|
||||
|
||||
genTask.releaseStrongReference();
|
||||
}
|
||||
|
||||
private void fireOnGenPosSuccessListeners(DhSectionPos pos)
|
||||
@@ -196,20 +196,21 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
for (DhSectionPos genPos : genPosList)
|
||||
{
|
||||
// try not to re-queue already generating tasks
|
||||
if (this.generatingDataSourceByPos.containsKey(genPos))
|
||||
if (this.generatingDataPos.contains(genPos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.repo.existsWithPrimaryKey(genPos.serialize()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// queue each new gen task
|
||||
GenTask genTask = new GenTask(dataSource.getSectionPos(), new WeakReference<>(dataSource));
|
||||
GenTask genTask = new GenTask(dataSource.getSectionPos());
|
||||
CompletableFuture<WorldGenResult> worldGenFuture = worldGenQueue.submitGenTask(genPos, dataSource.getDataDetailLevel(), genTask);
|
||||
worldGenFuture.whenComplete((genTaskResult, ex) ->
|
||||
{
|
||||
this.onWorldGenTaskComplete(genTaskResult, ex, genTask, genPos);
|
||||
this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos);
|
||||
});
|
||||
worldGenFuture.whenComplete((genTaskResult, ex) -> this.onWorldGenTaskComplete(genTaskResult, ex));
|
||||
|
||||
taskFutureList.add(worldGenFuture);
|
||||
}
|
||||
@@ -218,11 +219,11 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
// mark the data source as generating if necessary
|
||||
if (taskFutureList.size() != 0)
|
||||
{
|
||||
this.generatingDataSourceByPos.put(pos, dataSource);
|
||||
this.generatingDataPos.add(pos);
|
||||
CompletableFuture.allOf(taskFutureList.toArray(new CompletableFuture[0]))
|
||||
.whenComplete((voidObj, ex) ->
|
||||
{
|
||||
this.generatingDataSourceByPos.remove(pos);
|
||||
this.generatingDataPos.remove(pos);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -233,52 +234,29 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
// TODO may not be needed
|
||||
private class GenTask implements IWorldGenTaskTracker
|
||||
{
|
||||
private final DhSectionPos pos;
|
||||
|
||||
// weak reference (probably) used to prevent overloading the GC when lots of gen tasks are created? // TODO do we still need a weak reference here?
|
||||
private final WeakReference<IFullDataSource> targetFullDataSourceRef;
|
||||
// the target data source is where the generated chunk data will be put when completed
|
||||
private IFullDataSource loadedTargetFullDataSource = null;
|
||||
|
||||
|
||||
|
||||
public GenTask(DhSectionPos pos, WeakReference<IFullDataSource> targetFullDataSourceRef)
|
||||
public GenTask(DhSectionPos pos)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.targetFullDataSourceRef = targetFullDataSourceRef;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isMemoryAddressValid() { return this.targetFullDataSourceRef.get() != null; }
|
||||
public boolean isMemoryAddressValid() { return true; }
|
||||
|
||||
@Override
|
||||
public Consumer<ChunkSizedFullDataAccessor> getChunkDataConsumer()
|
||||
{
|
||||
if (this.loadedTargetFullDataSource == null)
|
||||
{
|
||||
this.loadedTargetFullDataSource = this.targetFullDataSourceRef.get();
|
||||
}
|
||||
if (this.loadedTargetFullDataSource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (chunkSizedFullDataSource) ->
|
||||
{
|
||||
if (chunkSizedFullDataSource.getSectionPos().overlapsExactly(this.loadedTargetFullDataSource.getSectionPos()))
|
||||
{
|
||||
((DhLevel) GeneratedFullDataFileHandler.this.level).updateDataSourcesWithChunkData(chunkSizedFullDataSource);
|
||||
}
|
||||
GeneratedFullDataFileHandler.this.level.updateDataSourcesWithChunkData(chunkSizedFullDataSource);
|
||||
};
|
||||
}
|
||||
|
||||
public void releaseStrongReference() { this.loadedTargetFullDataSource = null; }
|
||||
|
||||
}
|
||||
|
||||
/** used by external event listeners */
|
||||
|
||||
+12
-7
@@ -27,18 +27,23 @@ import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public abstract class DhLevel implements IDhLevel
|
||||
public abstract class AbstractDhLevel implements IDhLevel
|
||||
{
|
||||
|
||||
public final ChunkToLodBuilder chunkToLodBuilder;
|
||||
|
||||
protected DhLevel() { this.chunkToLodBuilder = new ChunkToLodBuilder(); }
|
||||
|
||||
public abstract void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor data);
|
||||
|
||||
|
||||
@Override
|
||||
public int getMinY() { return 0; }
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
protected AbstractDhLevel() { this.chunkToLodBuilder = new ChunkToLodBuilder(); }
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// default methods //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ChunkSizedFullDataAccessor> updateChunkAsync(IChunkWrapper chunk)
|
||||
@@ -52,7 +52,7 @@ import java.awt.*;
|
||||
import java.io.File;
|
||||
|
||||
/** The level used when connected to a server */
|
||||
public class DhClientLevel extends DhLevel implements IDhClientLevel
|
||||
public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
|
||||
@@ -38,14 +38,13 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Iterator;
|
||||
|
||||
/** The level used on a singleplayer world */
|
||||
public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhServerLevel
|
||||
public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLevel, IDhServerLevel
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
|
||||
@@ -53,7 +53,7 @@ import javax.annotation.CheckForNull;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class DhServerLevel extends DhLevel implements IDhServerLevel
|
||||
public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
|
||||
@@ -49,5 +49,6 @@ public interface IDhLevel extends AutoCloseable
|
||||
|
||||
boolean hasSkyLight();
|
||||
|
||||
void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor data);
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The position object used to define LOD objects in the quad trees. <br><br>
|
||||
@@ -318,6 +319,21 @@ public class DhSectionPos implements INetworkObject
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies the given consumer to all children of the position at the given section detail level. */
|
||||
public void forEachChildDownToDetailLevel(byte minSectionDetailLevel, Function<DhSectionPos, Boolean> callback)
|
||||
{
|
||||
boolean stop = callback.apply(this);
|
||||
if (stop || minSectionDetailLevel == this.detailLevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this.getChildByIndex(i).forEachChildDownToDetailLevel(minSectionDetailLevel, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies the given consumer to all children of the position at the given section detail level. */
|
||||
public void forEachChildAtLevel(byte sectionDetailLevel, Consumer<DhSectionPos> callback)
|
||||
{
|
||||
@@ -333,6 +349,20 @@ public class DhSectionPos implements INetworkObject
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies the given consumer to all children of the position at the given section detail level. */
|
||||
public void forEachPosUpToDetailLevel(byte maxSectionDetailLevel, Consumer<DhSectionPos> callback)
|
||||
{
|
||||
callback.accept(this);
|
||||
if (maxSectionDetailLevel == this.detailLevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.getParentPos().forEachPosUpToDetailLevel(maxSectionDetailLevel, callback);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.distanthorizons.core.pos;
|
||||
package com.seibel.distanthorizons.core.render;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.seibel.distanthorizons.core.render;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
|
||||
/**
|
||||
* Dummy {@link IDhApiCullingFrustum} that allows everything through. <br>
|
||||
* Useful when a frustum is required, but culling shouldn't be done.
|
||||
*/
|
||||
public class NeverCullFrustum implements IDhApiCullingFrustum, IDhApiShadowCullingFrustum
|
||||
{
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public NeverCullFrustum() { }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public void update(int worldMinBlockY, int worldMaxBlockY, Mat4f dhWorldViewProjection) { /* update isn't needed */ }
|
||||
|
||||
@Override
|
||||
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) { return true; }
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// overridable methods //
|
||||
//=====================//
|
||||
|
||||
@Override
|
||||
public int getPriority() { return IOverrideInjector.CORE_PRIORITY; }
|
||||
|
||||
}
|
||||
@@ -21,13 +21,14 @@ package com.seibel.distanthorizons.core.render;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.pos.DhFrustumBounds;
|
||||
import com.seibel.distanthorizons.core.pos.DhLodPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.pos.Pos2D;
|
||||
@@ -35,12 +36,15 @@ import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
|
||||
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
|
||||
import java.util.Comparator;
|
||||
@@ -56,6 +60,8 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||
|
||||
/** contains all relevant data */
|
||||
@@ -82,14 +88,20 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
public RenderBufferHandler(LodQuadTree lodQuadTree)
|
||||
{
|
||||
this.lodQuadTree = lodQuadTree;
|
||||
this.culledBufferCount = 0;
|
||||
|
||||
IDhApiCullingFrustum coreFrustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY);
|
||||
if (coreFrustum == null)
|
||||
IDhApiCullingFrustum coreCameraFrustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY);
|
||||
if (coreCameraFrustum == null)
|
||||
{
|
||||
DhApi.overrides.bind(IDhApiCullingFrustum.class, new DhFrustumBounds());
|
||||
}
|
||||
|
||||
// by default the shadow pass shouldn't have any frustum culling
|
||||
IDhApiShadowCullingFrustum coreShadowFrustum = DhApi.overrides.get(IDhApiShadowCullingFrustum.class, IOverrideInjector.CORE_PRIORITY);
|
||||
if (coreShadowFrustum == null)
|
||||
{
|
||||
DhApi.overrides.bind(IDhApiShadowCullingFrustum.class, new NeverCullFrustum());
|
||||
}
|
||||
|
||||
|
||||
this.f3Message = new F3Screen.MultiDynamicMessage(
|
||||
() ->
|
||||
@@ -131,7 +143,7 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
* TODO: This might get locked by update() causing move() call. Is there a way to avoid this?
|
||||
* Maybe dupe the base list and use atomic swap on render? Or is this not worth it?
|
||||
*/
|
||||
public void buildRenderListAndUpdateSections(IClientLevelWrapper clientLevelWrapper, Matrix4fc matWorldViewProjection, Vec3f lookForwardVector)
|
||||
public void buildRenderListAndUpdateSections(IClientLevelWrapper clientLevelWrapper, DhApiRenderParam renderEventParam, Vec3f lookForwardVector)
|
||||
{
|
||||
EDhDirection[] axisDirections = new EDhDirection[3];
|
||||
|
||||
@@ -236,14 +248,42 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
|
||||
|
||||
|
||||
//====================================//
|
||||
// get and update the culling frustum //
|
||||
//====================================//
|
||||
|
||||
// get the culling frustum
|
||||
boolean enableFrustumCulling;
|
||||
IDhApiCullingFrustum frustum;
|
||||
boolean isShadowPass = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isRenderingShadowPass());
|
||||
if (isShadowPass)
|
||||
{
|
||||
enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableShadowPassFrustumCulling.get();
|
||||
frustum = DhApi.overrides.get(IDhApiShadowCullingFrustum.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get();
|
||||
frustum = DhApi.overrides.get(IDhApiCullingFrustum.class);
|
||||
}
|
||||
|
||||
|
||||
// update the frustum if necessary
|
||||
boolean enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get();
|
||||
IDhApiCullingFrustum frustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY);
|
||||
if (enableFrustumCulling)
|
||||
{
|
||||
int worldMinY = clientLevelWrapper.getMinHeight();
|
||||
int worldHeight = clientLevelWrapper.getHeight();
|
||||
|
||||
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
|
||||
|
||||
Matrix4fc matWorldView = new Matrix4f()
|
||||
.setTransposed(renderEventParam.mcModelViewMatrix.getValuesAsArray())
|
||||
.translate(-(float) cameraPos.x, -(float) cameraPos.y, -(float) cameraPos.z);
|
||||
|
||||
Matrix4fc matWorldViewProjection = new Matrix4f()
|
||||
.setTransposed(renderEventParam.dhProjectionMatrix.getValuesAsArray())
|
||||
.mul(matWorldView);
|
||||
|
||||
frustum.update(worldMinY, worldMinY + worldHeight, new Mat4f(matWorldViewProjection));
|
||||
}
|
||||
|
||||
@@ -253,7 +293,6 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
// Update the section list //
|
||||
//=========================//
|
||||
|
||||
boolean isShadowPass = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isRenderingShadowPass());
|
||||
if (isShadowPass)
|
||||
{
|
||||
this.shadowCulledBufferCount = 0;
|
||||
|
||||
@@ -351,14 +351,7 @@ public class LodRenderer
|
||||
|
||||
if (renderingFirstPass)
|
||||
{
|
||||
Matrix4f matWorldView = new Matrix4f()
|
||||
.setTransposed(MC_RENDER.getWorldViewMatrix().getValuesAsArray());
|
||||
|
||||
Matrix4fc matWorldViewProjection = new Matrix4f()
|
||||
.setTransposed(renderEventParam.dhProjectionMatrix.getValuesAsArray())
|
||||
.mul(matWorldView);
|
||||
|
||||
this.bufferHandler.buildRenderListAndUpdateSections(clientLevelWrapper, matWorldViewProjection, MC_RENDER.getLookAtVector());
|
||||
this.bufferHandler.buildRenderListAndUpdateSections(clientLevelWrapper, renderEventParam, MC_RENDER.getLookAtVector());
|
||||
|
||||
transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled;
|
||||
fakeOceanFloor = Config.Client.Advanced.Graphics.Quality.transparency.get().fakeTransparencyEnabled;
|
||||
|
||||
+2
-2
@@ -96,8 +96,8 @@ public class SSAOApplyShader extends AbstractShaderRenderer
|
||||
|
||||
if (this.gFarUniform >= 0)
|
||||
{
|
||||
float far = (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2));
|
||||
GL32.glUniform1f(this.gFarUniform, far);
|
||||
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||
GL32.glUniform1f(this.gFarUniform, farClipPlane);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ public class DbConnectionClosedException extends SQLException
|
||||
{
|
||||
// TODO long term we should prevent using repos that are closed, but for now this is the easier solution
|
||||
String message = e.getMessage().toLowerCase();
|
||||
return message.contains("connection closed") || message.contains("pointer is closed");
|
||||
return message.contains("connection closed") || message.contains("pointer is closed") || message.contains("database has been closed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-8
@@ -832,8 +832,8 @@ public class RenderDataPointReducingList
|
||||
return RenderDataPointUtil.createVoidDataPoint();
|
||||
}
|
||||
|
||||
long highest;
|
||||
int lowest;
|
||||
long highestDataPoint;
|
||||
long lowestDataPoint;
|
||||
int index = 0;
|
||||
//first loop: find the first visible segment.
|
||||
foundVisible:
|
||||
@@ -843,8 +843,8 @@ public class RenderDataPointReducingList
|
||||
long dataPoint = view.get(index);
|
||||
if (isDataVisible(dataPoint))
|
||||
{
|
||||
highest = dataPoint;
|
||||
lowest = RenderDataPointUtil.getYMin(dataPoint);
|
||||
highestDataPoint = dataPoint;
|
||||
lowestDataPoint = dataPoint;
|
||||
break foundVisible;
|
||||
}
|
||||
}
|
||||
@@ -858,13 +858,15 @@ public class RenderDataPointReducingList
|
||||
long dataPoint = view.get(index);
|
||||
if (isDataVisible(dataPoint))
|
||||
{
|
||||
int y = RenderDataPointUtil.getYMin(dataPoint);
|
||||
if (y > highest) highest = dataPoint;
|
||||
else if (y < lowest) lowest = y;
|
||||
int yMax = RenderDataPointUtil.getYMax(dataPoint);
|
||||
int yMin = RenderDataPointUtil.getYMin(dataPoint);
|
||||
|
||||
if (yMax > RenderDataPointUtil.getYMax(highestDataPoint)) highestDataPoint = dataPoint;
|
||||
else if (yMin < RenderDataPointUtil.getYMin(lowestDataPoint)) lowestDataPoint = dataPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return (highest & ~RenderDataPointUtil.DEPTH_SHIFTED_MASK) | ((lowest & RenderDataPointUtil.DEPTH_MASK) << RenderDataPointUtil.DEPTH_SHIFT);
|
||||
return (highestDataPoint & ~RenderDataPointUtil.DEPTH_SHIFTED_MASK) | (RenderDataPointUtil.getYMin(lowestDataPoint) << RenderDataPointUtil.DEPTH_SHIFT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.util;
|
||||
|
||||
import com.seibel.distanthorizons.core.level.DhLevel;
|
||||
import com.seibel.distanthorizons.core.level.AbstractDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.SpamReducedLogger;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.columnViews.IColumnDataView;
|
||||
@@ -174,9 +174,9 @@ public class RenderDataPointUtil
|
||||
return dataPoint & ~(HEIGHT_SHIFTED_MASK | DEPTH_SHIFTED_MASK) | height | depth;
|
||||
}
|
||||
|
||||
/** AKA the ending/top/highest Y value above {@link DhLevel#getMinY()} */
|
||||
/** AKA the ending/top/highest Y value above {@link AbstractDhLevel#getMinY()} */
|
||||
public static short getYMax(long dataPoint) { return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK); }
|
||||
/** AKA the starting/bottom/lowest Y value above {@link DhLevel#getMinY()} */
|
||||
/** AKA the starting/bottom/lowest Y value above {@link AbstractDhLevel#getMinY()} */
|
||||
public static short getYMin(long dataPoint) { return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK); }
|
||||
|
||||
public static short getAlpha(long dataPoint) { return (short) ((((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT) | 0b1111); }
|
||||
|
||||
@@ -147,14 +147,13 @@ public class RenderUtil
|
||||
{
|
||||
// in James' testing a near clip plane distance of 2 blocks is enough to allow the fragment
|
||||
// culling to take effect instead of seeing the near clip plane.
|
||||
float nearClipDist = 2f; //MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH / 4.0f; //getNearClipPlaneDistanceInBlocks(partialTicks);
|
||||
float nearClipDist = RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks);
|
||||
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
|
||||
{
|
||||
nearClipDist = 0.1f;
|
||||
}
|
||||
|
||||
int farPlaneDistanceInBlocks = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||
float farClipDist = (float) ((farPlaneDistanceInBlocks + LodUtil.REGION_WIDTH) * Math.sqrt(2));
|
||||
float farClipDist = (float) RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||
|
||||
// Create a copy of the current matrix, so it won't be modified.
|
||||
Mat4f lodProj = mcProjMat.copy();
|
||||
@@ -228,7 +227,9 @@ public class RenderUtil
|
||||
public static int getFarClipPlaneDistanceInBlocks()
|
||||
{
|
||||
int lodChunkDist = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get();
|
||||
return lodChunkDist * LodUtil.CHUNK_WIDTH;
|
||||
int lodBlockDist = lodChunkDist * LodUtil.CHUNK_WIDTH;
|
||||
// sqrt 2 to prevent the corners from being cut off
|
||||
return (int)((lodBlockDist + LodUtil.REGION_WIDTH) * Math.sqrt(2));
|
||||
}
|
||||
|
||||
/** @return false if LODs shouldn't be rendered for any reason */
|
||||
|
||||
@@ -265,10 +265,6 @@
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics":
|
||||
"Advanced Graphics Options",
|
||||
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling":
|
||||
"Disable Frustum Culling",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling.@tooltip":
|
||||
"If false LODs outside the player's camera \naren't drawn, increasing GPU performance. \n\nIf true all LODs are drawn, even those behind \nthe player's camera, decreasing GPU performance. \n\nDisable this if you see LODs disappearing at the corners of your vision.",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.overdrawPrevention":
|
||||
"Overdraw Prevention",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.overdrawPrevention.@tooltip":
|
||||
@@ -305,7 +301,15 @@
|
||||
"LOD Shading",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.lodShading.@tooltip":
|
||||
"Defines how LODs should be shaded. \nCan be used to improve shader compatibility.",
|
||||
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling":
|
||||
"Disable Frustum Culling",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling.@tooltip":
|
||||
"If false LODs outside the player's camera \naren't drawn, increasing GPU performance. \n\nIf true all LODs are drawn, even those behind \nthe player's camera, decreasing GPU performance. \n\nDisable this if you see LODs disappearing at the corners of your vision.",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.disableShadowPassFrustumCulling":
|
||||
"Disable Shadow Pass Frustum Culling",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.disableShadowPassFrustumCulling.@tooltip":
|
||||
"Identical to the other frustum culling option except that it is \nonly used when a shader mod is present using the DH API \nand the shadow pass is being rendered. \n\nDisable this if shadows render incorrectly.",
|
||||
|
||||
|
||||
"distanthorizons.config.client.advanced.worldGenerator":
|
||||
"World Generator",
|
||||
@@ -454,6 +458,15 @@
|
||||
"distanthorizons.config.client.advanced.debugging.allowUnsafeValues.@tooltip":
|
||||
"If enabled, very limited config input validation will be performed. \n\nWarning: enabling this can cause instability or crashing, use at your own risk. \nNote: this option isn't saved between sessions.",
|
||||
|
||||
"distanthorizons.config.client.advanced.debugging.columnBuilderDebugEnable":
|
||||
"Enable Column Builder Limiting",
|
||||
"distanthorizons.config.client.advanced.debugging.columnBuilderDebugDetailLevel":
|
||||
"Column Builder Limit - Detail Level",
|
||||
"distanthorizons.config.client.advanced.debugging.columnBuilderDebugXPos":
|
||||
"Column Builder Limit - X Pos",
|
||||
"distanthorizons.config.client.advanced.debugging.columnBuilderDebugZPos":
|
||||
"Column Builder Limit - Z Pos",
|
||||
|
||||
|
||||
"distanthorizons.config.client.advanced.buffers":
|
||||
"Buffers",
|
||||
|
||||
Reference in New Issue
Block a user