Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core
This commit is contained in:
+11
-1
@@ -24,9 +24,14 @@ package com.seibel.distanthorizons.api.enums.config;
|
||||
* LIGHT <br>
|
||||
* MEDIUM <br>
|
||||
* HEAVY <br>
|
||||
*
|
||||
* CUSTOM <br>
|
||||
*
|
||||
* @since API 1.0.0
|
||||
* @deprecated will be removed when DH updates to MC 1.21 <br>
|
||||
* After removal a float value will be used to control overdraw instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum EOverdrawPrevention
|
||||
{
|
||||
// Reminder:
|
||||
@@ -36,6 +41,11 @@ public enum EOverdrawPrevention
|
||||
NONE,
|
||||
LIGHT,
|
||||
MEDIUM,
|
||||
HEAVY;
|
||||
HEAVY,
|
||||
|
||||
/**
|
||||
* Should not be passed in. <br>
|
||||
* Is returned if the overdraw value doesn't match any of the enums defined here.
|
||||
*/
|
||||
CUSTOM;
|
||||
}
|
||||
|
||||
+4
-2
@@ -53,8 +53,10 @@ public interface IDhApiConfigValue<T>
|
||||
* Sets the config's value. <br>
|
||||
* If the newValue is set to null then the config
|
||||
* will revert to using the True Value.<br>
|
||||
* If the config cannot be set via the API this method will return false.
|
||||
*
|
||||
* If the config cannot be set via the API this method will return false. <br><br>
|
||||
*
|
||||
* To unset the config's value pass in Null. <br>
|
||||
*
|
||||
* @return true if the value was set, false otherwise.
|
||||
*/
|
||||
boolean setValue(T newValue);
|
||||
|
||||
+19
-2
@@ -113,13 +113,30 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
|
||||
//===========================//
|
||||
|
||||
/**
|
||||
* If enabled the near clip plane is extended to reduce
|
||||
* overdraw and improve Z-fighting at extreme render distances. <br>
|
||||
* Sets the distance used by the near clip plane to reduce
|
||||
* overdraw. <br>
|
||||
* Disabling this reduces holes in the world due to the near clip plane
|
||||
* being too close to the camera and the terrain not being covered by vanilla terrain.
|
||||
*
|
||||
* @deprecated Use {@link IDhApiGraphicsConfig#overdrawPreventionRadius()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
IDhApiConfigValue<EOverdrawPrevention> overdrawPrevention();
|
||||
|
||||
/**
|
||||
* Sets the radius used by the near clip shader to reduce
|
||||
* overdraw. <br>
|
||||
* Measured in percentages of the render distance, IE: <br>
|
||||
* 0.5 = 50% vanilla render distance <br>
|
||||
* 0.1 = 10% vanilla render distance <br>
|
||||
* <br>
|
||||
* Setting this to 0 will reduce/prevent holes in the world due to clipping to close to the camera
|
||||
* but may cause overdraw issues with transparent or non-full blocks.
|
||||
*
|
||||
* @since API 1.1.0
|
||||
*/
|
||||
IDhApiConfigValue<Double> overdrawPreventionRadius();
|
||||
|
||||
/**
|
||||
* Modifies how bright fake chunks are. <br>
|
||||
* This is done when generating the vertex data and is applied before any shaders.
|
||||
|
||||
@@ -34,14 +34,14 @@ public final class ModInfo
|
||||
public static final String NAME = "DistantHorizons";
|
||||
/** Human-readable version of NAME */
|
||||
public static final String READABLE_NAME = "Distant Horizons";
|
||||
public static final String VERSION = "2.0.1-a-dev";
|
||||
public static final String VERSION = "2.0.2-a-dev";
|
||||
/** Returns true if the current build is an unstable developer build, false otherwise. */
|
||||
public static boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
|
||||
|
||||
/** This version should only be updated when breaking changes are introduced to the DH API */
|
||||
public static final int API_MAJOR_VERSION = 1;
|
||||
/** This version should be updated whenever new methods are added to the DH API */
|
||||
public static final int API_MINOR_VERSION = 0;
|
||||
public static final int API_MINOR_VERSION = 1;
|
||||
/** This version should be updated whenever non-breaking fixes are added to the DH API */
|
||||
public static final int API_PATH_VERSION = 0;
|
||||
|
||||
|
||||
+6
-1
@@ -109,9 +109,14 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
|
||||
// public IDhApiConfigValue<Boolean> getDisableDirectionalCulling()
|
||||
// { return new DhApiConfigValue<Boolean, Boolean>(AdvancedGraphics.disableDirectionalCulling); }
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public IDhApiConfigValue<EOverdrawPrevention> overdrawPrevention()
|
||||
{ return new DhApiConfigValue<EOverdrawPrevention, EOverdrawPrevention>(Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPrevention); }
|
||||
{ return new DhApiConfigValue<EOverdrawPrevention, EOverdrawPrevention>(Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPreventionPreset); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Double> overdrawPreventionRadius()
|
||||
{ return new DhApiConfigValue<Double, Double>(Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPrevention); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Double> brightnessMultiplier()
|
||||
|
||||
@@ -49,6 +49,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -161,46 +162,73 @@ public class ClientApi
|
||||
// level events //
|
||||
//==============//
|
||||
|
||||
public void clientLevelUnloadEvent(IClientLevelWrapper level)
|
||||
public void clientLevelUnloadEvent(@Nullable IClientLevelWrapper level)
|
||||
{
|
||||
LOGGER.info("Unloading client level [" + level + "].");
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
try
|
||||
{
|
||||
world.unloadLevel(level);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level));
|
||||
if (level == null)
|
||||
{
|
||||
// can happen on certain multiverse servers
|
||||
return;
|
||||
}
|
||||
LOGGER.info("Unloading client level [" + level + "].");
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
{
|
||||
world.unloadLevel(level);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.waitingClientLevels.remove(level);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
this.waitingClientLevels.remove(level);
|
||||
// handle errors here to prevent blowing up a mixin or API up stream
|
||||
LOGGER.error("Unexpected error in ClientApi.clientLevelUnloadEvent(), error: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void clientLevelLoadEvent(IClientLevelWrapper level) { this.clientLevelLoadEvent(level, false); }
|
||||
public void multiverseClientLevelLoadEvent(IClientLevelWrapper level) { this.clientLevelLoadEvent(level, true); }
|
||||
private void clientLevelLoadEvent(IClientLevelWrapper level, boolean isServerCommunication)
|
||||
public void clientLevelLoadEvent(@Nullable IClientLevelWrapper level) { this.clientLevelLoadEvent(level, false); }
|
||||
public void multiverseClientLevelLoadEvent(@Nullable IClientLevelWrapper level) { this.clientLevelLoadEvent(level, true); }
|
||||
private void clientLevelLoadEvent(@Nullable IClientLevelWrapper level, boolean isServerCommunication)
|
||||
{
|
||||
if (this.isServerCommunicationEnabled && !isServerCommunication)
|
||||
try
|
||||
{
|
||||
LOGGER.info("Server supports communication, deferring loading.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LOGGER.info("Loading " + (isServerCommunication ? "Multiverse" : "") + " client level [" + level + "].");
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
{
|
||||
world.getOrLoadLevel(level);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level));
|
||||
if (this.isServerCommunicationEnabled && !isServerCommunication)
|
||||
{
|
||||
LOGGER.info("Server supports communication, deferring loading.");
|
||||
return;
|
||||
}
|
||||
if (level == null)
|
||||
{
|
||||
// can happen on certain multiverse servers
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadWaitingChunksForLevel(level);
|
||||
|
||||
|
||||
LOGGER.info("Loading " + (isServerCommunication ? "Multiverse" : "") + " client level [" + level + "].");
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
{
|
||||
world.getOrLoadLevel(level);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level));
|
||||
|
||||
this.loadWaitingChunksForLevel(level);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.waitingClientLevels.add(level);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
this.waitingClientLevels.add(level);
|
||||
// handle errors here to prevent blowing up a mixin or API up stream
|
||||
LOGGER.error("Unexpected error in ClientApi.clientLevelLoadEvent(), error: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
private void loadWaitingChunksForLevel(IClientLevelWrapper level)
|
||||
@@ -258,26 +286,35 @@ public class ClientApi
|
||||
IProfilerWrapper profiler = MC.getProfiler();
|
||||
profiler.push("DH-ClientTick");
|
||||
|
||||
boolean doFlush = System.nanoTime() - this.lastFlushNanoTime >= SPAM_LOGGER_FLUSH_NS;
|
||||
if (doFlush)
|
||||
try
|
||||
{
|
||||
this.lastFlushNanoTime = System.nanoTime();
|
||||
SpamReducedLogger.flushAll();
|
||||
}
|
||||
ConfigBasedLogger.updateAll();
|
||||
ConfigBasedSpamLogger.updateAll(doFlush);
|
||||
|
||||
IDhClientWorld clientWorld = SharedApi.getIDhClientWorld();
|
||||
if (clientWorld != null)
|
||||
{
|
||||
clientWorld.clientTick();
|
||||
|
||||
// Ignore local world gen, as it's managed by server ticking
|
||||
if (!(clientWorld instanceof DhClientServerWorld))
|
||||
boolean doFlush = System.nanoTime() - this.lastFlushNanoTime >= SPAM_LOGGER_FLUSH_NS;
|
||||
if (doFlush)
|
||||
{
|
||||
SharedApi.worldGenTick(clientWorld::doWorldGen);
|
||||
this.lastFlushNanoTime = System.nanoTime();
|
||||
SpamReducedLogger.flushAll();
|
||||
}
|
||||
ConfigBasedLogger.updateAll();
|
||||
ConfigBasedSpamLogger.updateAll(doFlush);
|
||||
|
||||
IDhClientWorld clientWorld = SharedApi.getIDhClientWorld();
|
||||
if (clientWorld != null)
|
||||
{
|
||||
clientWorld.clientTick();
|
||||
|
||||
// Ignore local world gen, as it's managed by server ticking
|
||||
if (!(clientWorld instanceof DhClientServerWorld))
|
||||
{
|
||||
SharedApi.worldGenTick(clientWorld::doWorldGen);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// handle errors here to prevent blowing up a mixin or API up stream
|
||||
LOGGER.error("Unexpected error in ClientApi.clientTickEvent(), error: "+e.getMessage(), e);
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ 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 int MAX_UPDATING_CHUNK_COUNT_PER_THREAD = 100;
|
||||
|
||||
|
||||
|
||||
private static AbstractDhWorld currentWorld;
|
||||
@@ -226,6 +228,13 @@ public class SharedApi
|
||||
}
|
||||
private static void bakeChunkLightingAndSendToLevelAsync(IChunkWrapper chunkWrapper, @Nullable ArrayList<IChunkWrapper> neighbourChunkList, IDhLevel dhLevel)
|
||||
{
|
||||
if (UPDATING_CHUNK_SET.size() >= MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get())
|
||||
{
|
||||
// The maximum number of chunks are already queued, don't add more.
|
||||
// This is done to prevent overloading the system if the user flys extremely fast and queues too many chunks
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent duplicate update requests
|
||||
if (UPDATING_CHUNK_SET.contains(chunkWrapper.getChunkPos()))
|
||||
{
|
||||
@@ -237,6 +246,11 @@ public class SharedApi
|
||||
|
||||
// lighting the chunk needs to be done on a separate thread to prevent lagging any of the event threads
|
||||
ThreadPoolExecutor executor = ThreadPools.getLightPopulatorExecutor();
|
||||
if (executor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
executor.execute(() ->
|
||||
{
|
||||
LOGGER.trace(chunkWrapper.getChunkPos() + " " + executor.getActiveCount() + " / " + executor.getQueue().size() + " - " + executor.getCompletedTaskCount());
|
||||
@@ -245,7 +259,8 @@ public class SharedApi
|
||||
{
|
||||
// Save or populate the chunk wrapper's lighting
|
||||
// this is done so we don't have to worry about MC unloading the lighting data for this chunk
|
||||
if (chunkWrapper.isLightCorrect())
|
||||
boolean onlyUseDhLighting = Config.Client.Advanced.LodBuilding.onlyUseDhLightingEngine.get();
|
||||
if (!onlyUseDhLighting && chunkWrapper.isLightCorrect())
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -547,17 +547,29 @@ public class Config
|
||||
// + "Disable this if you see LODs disappearing at the corners of your vision.")
|
||||
// .build();
|
||||
|
||||
public static ConfigEntry<EOverdrawPrevention> overdrawPrevention = new ConfigEntry.Builder<EOverdrawPrevention>()
|
||||
/**
|
||||
* @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>
|
||||
*/
|
||||
@Deprecated
|
||||
public static ConfigEntry<EOverdrawPrevention> overdrawPreventionPreset = new ConfigEntry.Builder<EOverdrawPrevention>()
|
||||
.set(EOverdrawPrevention.MEDIUM)
|
||||
.comment("")
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_API)
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Double> overdrawPrevention = new ConfigEntry.Builder<Double>()
|
||||
.setMinDefaultMax(0.0, 0.4, 1.0)
|
||||
.comment(""
|
||||
+ "Determines how far Distant Horizon's near clip plane will render. \n"
|
||||
+ "Determines how far from the camera Distant Horizons will start rendering. \n"
|
||||
+ "Measured as a percentage of the vanilla render distance.\n"
|
||||
+ "\n"
|
||||
+ "Higher values will prevent LODs from rendering behind vanilla blocks at a higher distance,\n"
|
||||
+ "but may cause holes to appear in the LODs. \n"
|
||||
+ "Holes are most likely at the left and right edges of the screen \n"
|
||||
+ "when flying through unloaded terrain. \n"
|
||||
+ "Holes are most likely to appear when flying through unloaded terrain. \n"
|
||||
+ "\n"
|
||||
+ "Increasing the vanilla render distance increases the effectiveness of these options."
|
||||
+ "Increasing the vanilla render distance increases the effectiveness of this setting."
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
@@ -769,6 +781,19 @@ public class Config
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> onlyUseDhLightingEngine = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "If false LODs will be lit by Minecraft's lighting engine when possible \n"
|
||||
+ "and fall back to the DH lighting engine only when necessary. \n"
|
||||
+ "\n"
|
||||
+ "If true LODs will only be lit using Distant Horizons' lighting engine. \n"
|
||||
+ "\n"
|
||||
+ "Generally it is best to leave this disabled and should only be enabled \n"
|
||||
+ "if there are lighting issues or for debugging. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
public static class Multiplayer
|
||||
@@ -1447,14 +1472,26 @@ public class Config
|
||||
|
||||
try
|
||||
{
|
||||
// listener can only be added after the config has finished initializing
|
||||
Client.Advanced.Graphics.AdvancedGraphics.overdrawPreventionPreset.addListener(OverdrawPreventionPresetConfigEventHandler.INSTANCE);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected exception when running config delayed listener setup. Error: [" + e.getMessage() + "].", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// TODO automatically get all instances of AbstractPresetConfigEventHandler and fire "setUiOnlyConfigValues"
|
||||
ThreadPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||
RenderQualityPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||
QuickRenderToggleConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||
OverdrawPreventionPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||
RenderCacheConfigEventHandler.getInstance();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected exception when setting up complicated config listeners. Error: [" + e.getMessage() + "].", e);
|
||||
LOGGER.error("Unexpected exception when running config delayed UI setup. Error: [" + e.getMessage() + "].", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.presets;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EMaxHorizontalResolution;
|
||||
import com.seibel.distanthorizons.api.enums.config.EOverdrawPrevention;
|
||||
import com.seibel.distanthorizons.api.enums.config.quickOptions.EQualityPreset;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.ConfigEntryWithPresetOptions;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
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 OverdrawPreventionPresetConfigEventHandler extends AbstractPresetConfigEventHandler<EOverdrawPrevention>
|
||||
{
|
||||
public static final OverdrawPreventionPresetConfigEventHandler INSTANCE = new OverdrawPreventionPresetConfigEventHandler();
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
|
||||
private final ConfigEntryWithPresetOptions<EOverdrawPrevention, Double> overdrawPrevention = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPrevention,
|
||||
new HashMap<EOverdrawPrevention, Double>()
|
||||
{{
|
||||
this.put(EOverdrawPrevention.HEAVY, 0.6);
|
||||
this.put(EOverdrawPrevention.MEDIUM, 0.4);
|
||||
this.put(EOverdrawPrevention.LIGHT, 0.25);
|
||||
this.put(EOverdrawPrevention.NONE, 0.0);
|
||||
}});
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
/** private since we only ever need one handler at a time */
|
||||
private OverdrawPreventionPresetConfigEventHandler()
|
||||
{
|
||||
// add each config used by this preset
|
||||
this.configList.add(this.overdrawPrevention);
|
||||
|
||||
|
||||
for (ConfigEntryWithPresetOptions<EOverdrawPrevention, ?> config : this.configList)
|
||||
{
|
||||
// ignore try-using, the listener should only ever be added once and should never be removed
|
||||
new ConfigChangeListener<>(config.configEntry, (val) -> { this.onConfigValueChanged(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// enum getters //
|
||||
//==============//
|
||||
|
||||
@Override
|
||||
protected IConfigEntry<EOverdrawPrevention> getPresetConfigEntry() { return Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPreventionPreset; }
|
||||
|
||||
@Override
|
||||
protected List<EOverdrawPrevention> getPresetEnumList() { return Arrays.asList(EOverdrawPrevention.values()); }
|
||||
@Override
|
||||
protected EOverdrawPrevention getCustomPresetEnum() { return EOverdrawPrevention.CUSTOM; }
|
||||
|
||||
}
|
||||
+15
-4
@@ -25,7 +25,6 @@ import com.seibel.distanthorizons.core.config.ConfigBase;
|
||||
import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -112,7 +111,7 @@ public class ConfigFileHandling
|
||||
// Attempt to get the version number
|
||||
currentCfgVersion = (Integer) tmpNightConfig.get("_version");
|
||||
tmpNightConfig.close();
|
||||
} catch (Exception e) {e.printStackTrace();}
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
if (currentCfgVersion == configBase.configVersion)
|
||||
{}
|
||||
@@ -227,9 +226,21 @@ public class ConfigFileHandling
|
||||
return;
|
||||
}
|
||||
|
||||
entry.pureSet((T) ConfigTypeConverters.attemptToConvertFromString(entry.getType(), nightConfig.get(entry.getNameWCategory())));
|
||||
// try converting the value if necessary
|
||||
Class<?> expectedValueClass = entry.getType();
|
||||
Object value = nightConfig.get(entry.getNameWCategory());
|
||||
Object convertedValue = ConfigTypeConverters.attemptToConvertFromString(expectedValueClass, value);
|
||||
if (!convertedValue.getClass().equals(expectedValueClass))
|
||||
{
|
||||
LOGGER.error("Unable to convert config value ["+value+"] from ["+(value != null ? value.getClass() : "NULL")+"] to ["+expectedValueClass+"] for config ["+entry.name+"], " +
|
||||
"the default config value will be used instead ["+entry.getDefaultValue()+"]. " +
|
||||
"Make sure a converter is defined in ["+ConfigTypeConverters.class.getSimpleName()+"].");
|
||||
convertedValue = entry.getDefaultValue();
|
||||
}
|
||||
entry.pureSet((T) convertedValue);
|
||||
|
||||
if (entry.getTrueValue() == null) {
|
||||
if (entry.getTrueValue() == null)
|
||||
{
|
||||
LOGGER.warn("Entry [" + entry.getNameWCategory() + "] returned as null from the config. Using default value.");
|
||||
entry.pureSet(entry.getDefaultValue());
|
||||
}
|
||||
|
||||
+17
-9
@@ -37,12 +37,13 @@ public class ConfigTypeConverters
|
||||
// Once you've made a converter add it to here where the first value is the type you want to convert and the 2nd value is the converter
|
||||
public static final Map<Class<?>, ConverterBase> convertObjects = new HashMap<Class<?>, ConverterBase>()
|
||||
{{
|
||||
put(Short.class, new ShortConverter());
|
||||
put(Long.class, new LongConverter());
|
||||
put(Float.class, new FloatConverter());
|
||||
put(Byte.class, new ByteConverter());
|
||||
this.put(Short.class, new ShortConverter());
|
||||
this.put(Long.class, new LongConverter());
|
||||
this.put(Float.class, new FloatConverter());
|
||||
this.put(Double.class, new DoubleConverter());
|
||||
this.put(Byte.class, new ByteConverter());
|
||||
|
||||
put(Map.class, new MapConverter());
|
||||
this.put(Map.class, new MapConverter());
|
||||
}};
|
||||
|
||||
public static Class<?> isClassConvertable(Class<?> clazz)
|
||||
@@ -73,10 +74,12 @@ public class ConfigTypeConverters
|
||||
{
|
||||
return attemptToConvertFromString(value.getClass(), value);
|
||||
}
|
||||
public static Object attemptToConvertFromString(Class<?> clazz, Object value)
|
||||
public static Object attemptToConvertFromString(Class<?> outputClass, Object value)
|
||||
{
|
||||
Class<?> convertablClass = isClassConvertable(clazz);
|
||||
if (convertablClass != null) {
|
||||
boolean valueNeedsConverting = (value == null || value.getClass().equals(String.class));
|
||||
Class<?> convertablClass = isClassConvertable(outputClass);
|
||||
if (valueNeedsConverting && convertablClass != null)
|
||||
{
|
||||
return convertFromString(convertablClass, (String) value);
|
||||
}
|
||||
return value;
|
||||
@@ -140,7 +143,12 @@ public class ConfigTypeConverters
|
||||
{
|
||||
@Override public String convertToString(Object item) { return ((Float) item).toString(); }
|
||||
@Override public Float convertFromString(String s) { return Float.valueOf(s); }
|
||||
|
||||
}
|
||||
|
||||
public static class DoubleConverter extends ConverterBase
|
||||
{
|
||||
@Override public String convertToString(Object item) { return ((Double) item).toString(); }
|
||||
@Override public Double convertFromString(String s) { return Double.valueOf(s); }
|
||||
}
|
||||
|
||||
public static class ByteConverter extends ConverterBase
|
||||
|
||||
+3
-1
@@ -32,7 +32,9 @@ public enum EConfigEntryAppearance
|
||||
/** Will only show the option in the UI. The option will be reverted on game restart */
|
||||
ONLY_IN_GUI(true, false),
|
||||
/** Only show the option in the file. There would be no way to access it using the UI */
|
||||
ONLY_IN_FILE(true, false);
|
||||
ONLY_IN_FILE(true, false),
|
||||
/** The option is only available via code. Generally this is only used for deprecated options. */
|
||||
ONLY_IN_API(false, false);
|
||||
|
||||
/** Sets whether the option should show in the UI */
|
||||
public final boolean showInGui;
|
||||
|
||||
+13
-1
@@ -52,6 +52,8 @@ public class ColumnBox
|
||||
|
||||
// if there isn't any data below this LOD, make this LOD's color opaque to prevent seeing void through transparent blocks
|
||||
// Note: this LOD should still be considered transparent for this method's checks, otherwise rendering bugs may occur
|
||||
// FIXME this transparency change should be applied before this point since this could affect other areas
|
||||
// This may also be better than handling the LOD as transparent, but that is TBD
|
||||
if (!RenderDataPointUtil.doesDataPointExist(bottomData))
|
||||
{
|
||||
color = ColorUtil.setAlpha(color, 255);
|
||||
@@ -269,7 +271,17 @@ public class ColumnBox
|
||||
adjIndex++)
|
||||
{
|
||||
long adjPoint = adjColumnView.get(adjIndex);
|
||||
boolean adjTransparent = RenderDataPointUtil.getAlpha(adjPoint) < 255 && LodRenderer.transparencyEnabled;
|
||||
|
||||
// if the adjacent data point is over the void
|
||||
// don't consider it as transparent
|
||||
// FIXME this transparency change should be applied before this point since this could affect other areas
|
||||
boolean adjOverVoid = false;
|
||||
if (adjIndex > 0)
|
||||
{
|
||||
long adjBellowPoint = adjColumnView.get(adjIndex-1);
|
||||
adjOverVoid = !RenderDataPointUtil.doesDataPointExist(adjBellowPoint);
|
||||
}
|
||||
boolean adjTransparent = !adjOverVoid && RenderDataPointUtil.getAlpha(adjPoint) < 255 && LodRenderer.transparencyEnabled;
|
||||
|
||||
|
||||
// continue if this data point is transparent or the adjacent point is not
|
||||
|
||||
+20
-5
@@ -39,6 +39,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* Used to populate the buffers in a {@link ColumnRenderSource} object.
|
||||
@@ -66,6 +67,17 @@ public class ColumnRenderBufferBuilder
|
||||
IDhClientLevel clientLevel, Reference<ColumnRenderBuffer> renderBufferRef,
|
||||
ColumnRenderSource renderSource, ColumnRenderSource[] adjData)
|
||||
{
|
||||
ThreadPoolExecutor bufferBuilderExecutor = ThreadPools.getBufferBuilderExecutor();
|
||||
ThreadPoolExecutor bufferUploaderExecutor = ThreadPools.getBufferUploaderExecutor();
|
||||
if ((bufferBuilderExecutor == null || bufferBuilderExecutor.isTerminated()) ||
|
||||
(bufferUploaderExecutor == null || bufferUploaderExecutor.isTerminated()))
|
||||
{
|
||||
// one or more of the thread pools has been shut down
|
||||
CompletableFuture<ColumnRenderBuffer> future = new CompletableFuture<>();
|
||||
future.cancel(true);
|
||||
return future;
|
||||
}
|
||||
|
||||
//LOGGER.info("RenderRegion startBuild @ "+renderSource.sectionPos);
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
@@ -101,7 +113,7 @@ public class ColumnRenderBufferBuilder
|
||||
LOGGER.error("\"LodNodeBufferBuilder\" was unable to build quads: ", e3);
|
||||
throw e3;
|
||||
}
|
||||
}, ThreadPools.getBufferBuilderExecutor())
|
||||
}, bufferBuilderExecutor)
|
||||
.thenApplyAsync((quadBuilder) ->
|
||||
{
|
||||
try
|
||||
@@ -136,7 +148,7 @@ public class ColumnRenderBufferBuilder
|
||||
LOGGER.error("\"LodNodeBufferBuilder\" was unable to upload buffer: ", e3);
|
||||
throw e3;
|
||||
}
|
||||
}, ThreadPools.getBufferUploaderExecutor())
|
||||
}, bufferUploaderExecutor)
|
||||
.handle((columnRenderBuffer, ex) ->
|
||||
{
|
||||
//LOGGER.info("RenderRegion endBuild @ {}", renderSource.sectionPos);
|
||||
@@ -168,10 +180,11 @@ 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
|
||||
// useful when debugging a specific section
|
||||
// if (renderSource.sectionPos.sectionDetailLevel == 6
|
||||
// && renderSource.sectionPos.sectionZ == 0 && renderSource.sectionPos.sectionX == 0)
|
||||
// if (renderSource.sectionPos.getDetailLevel() == 6
|
||||
// && renderSource.sectionPos.getZ() == 0 && renderSource.sectionPos.getX() == 0)
|
||||
// {
|
||||
// int test = 0;
|
||||
// }
|
||||
@@ -185,10 +198,11 @@ public class ColumnRenderBufferBuilder
|
||||
{
|
||||
for (int z = 0; z < ColumnRenderSource.SECTION_SIZE; z++)
|
||||
{
|
||||
// TODO make a config for this
|
||||
// can be uncommented to limit the buffer building to a specific
|
||||
// relative position in this section.
|
||||
// useful for debugging a single column's rendering
|
||||
// if (x != 1 || z != 1)
|
||||
// if (x != 0 || (z != 0 && z != 1))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
@@ -304,6 +318,7 @@ public class ColumnRenderBufferBuilder
|
||||
// We only stop when we find a block that is void or non-existing block
|
||||
for (int i = 0; i < columnRenderData.size(); i++)
|
||||
{
|
||||
// TODO make a config for this
|
||||
// can be uncommented to limit which vertical LOD is generated
|
||||
// if (i != 0)
|
||||
// {
|
||||
|
||||
+3
@@ -25,6 +25,7 @@ public interface IColumnDataView
|
||||
{
|
||||
long get(int index);
|
||||
|
||||
// FIXME probably horizontal size in blocks?
|
||||
int size();
|
||||
|
||||
default Iterator<Long> iterator()
|
||||
@@ -43,8 +44,10 @@ public interface IColumnDataView
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME measured in blocks?
|
||||
int verticalSize();
|
||||
|
||||
// FIXME how many datapoints in this LOD?
|
||||
int dataCount();
|
||||
|
||||
IColumnDataView subView(int dataIndexStart, int dataCount);
|
||||
|
||||
+7
-1
@@ -100,6 +100,12 @@ public class ChunkToLodBuilder implements AutoCloseable
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadPoolExecutor lodBuilderExecutor = ThreadPools.getChunkToLodBuilderExecutor();
|
||||
if (lodBuilderExecutor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < threadCount; i++)
|
||||
{
|
||||
@@ -114,7 +120,7 @@ public class ChunkToLodBuilder implements AutoCloseable
|
||||
{
|
||||
this.runningCount.decrementAndGet();
|
||||
}
|
||||
}, ThreadPools.getChunkToLodBuilderExecutor());
|
||||
}, lodBuilderExecutor);
|
||||
}
|
||||
}
|
||||
private void tickThreadTask()
|
||||
|
||||
+1
-1
@@ -280,7 +280,7 @@ public class FullDataToRenderDataTransformer
|
||||
|
||||
|
||||
// solid block check
|
||||
if (avoidSolidBlocks && !block.isSolid() && !block.isLiquid())
|
||||
if (avoidSolidBlocks && !block.isSolid() && !block.isLiquid() && block.getOpacity() != IBlockStateWrapper.FULLY_OPAQUE)
|
||||
{
|
||||
if (colorBelowWithAvoidedBlocks)
|
||||
{
|
||||
|
||||
+23
-5
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.core.dataObjects.transformers;
|
||||
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
@@ -28,12 +29,15 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class LodDataBuilder
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IBlockStateWrapper AIR = SingletonInjector.INSTANCE.get(IWrapperFactory.class).getAirBlockStateWrapper();
|
||||
|
||||
private static boolean getTopErrorLogged = false;
|
||||
|
||||
|
||||
public static ChunkSizedFullDataAccessor createChunkData(IChunkWrapper chunkWrapper)
|
||||
{
|
||||
@@ -65,10 +69,24 @@ public class LodDataBuilder
|
||||
IBlockStateWrapper topBlockState = chunkWrapper.getBlockState(x, y, z);
|
||||
while (!topBlockState.isAir() && y < chunkWrapper.getMaxBuildHeight())
|
||||
{
|
||||
// This is necessary in some edge cases with snow layers and some other blocks that may not appear in the height map but do block light.
|
||||
// Interestingly this doesn't appear to be the case in the DhLightingEngine, if this same logic is added there the lighting breaks for the affected blocks.
|
||||
y++;
|
||||
topBlockState = chunkWrapper.getBlockState(x, y, z);
|
||||
try
|
||||
{
|
||||
// This is necessary in some edge cases with snow layers and some other blocks that may not appear in the height map but do block light.
|
||||
// Interestingly this doesn't appear to be the case in the DhLightingEngine, if this same logic is added there the lighting breaks for the affected blocks.
|
||||
y++;
|
||||
topBlockState = chunkWrapper.getBlockState(x, y, z);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!getTopErrorLogged)
|
||||
{
|
||||
LOGGER.warn("Unexpected issue in LodDataBuilder, future errors won't be logged. Chunk [" + chunkWrapper.getChunkPos() + "] with max height: [" + chunkWrapper.getMaxBuildHeight() + "] had issue getting block at pos [" + x + "," + y + "," + z + "] error: " + e.getMessage(), e);
|
||||
getTopErrorLogged = true;
|
||||
}
|
||||
|
||||
y--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -247,7 +247,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
|
||||
|
||||
ThreadPoolExecutor executor = ThreadPools.getFileHandlerExecutor();
|
||||
if (!executor.isTerminated())
|
||||
if (executor != null && !executor.isTerminated())
|
||||
{
|
||||
// load the data source
|
||||
|
||||
@@ -344,7 +344,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
else
|
||||
{
|
||||
ThreadPoolExecutor executor = ThreadPools.getFileHandlerExecutor();
|
||||
if (!executor.isTerminated())
|
||||
if (executor != null && !executor.isTerminated())
|
||||
{
|
||||
// wait for the update to finish before returning the data source
|
||||
|
||||
|
||||
+5
-2
@@ -104,7 +104,7 @@ public class RenderSourceFileHandler implements IRenderSourceProvider
|
||||
{
|
||||
// don't continue if the handler has been shut down
|
||||
ThreadPoolExecutor executor = ThreadPools.getFileHandlerExecutor();
|
||||
if (executor.isTerminated())
|
||||
if (executor != null && executor.isTerminated())
|
||||
{
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
@@ -266,11 +266,14 @@ public class RenderSourceFileHandler implements IRenderSourceProvider
|
||||
private String[] f3Log()
|
||||
{
|
||||
ThreadPoolExecutor executor = ThreadPools.getFileHandlerExecutor();
|
||||
String queueSize = executor != null ? executor.getQueue().size()+"" : "-";
|
||||
String completedTaskSize = executor != null ? executor.getCompletedTaskCount()+"" : "-";
|
||||
|
||||
|
||||
ArrayList<String> lines = new ArrayList<>();
|
||||
lines.add("Render Source File Handler [" + this.clientLevel.getClientLevelWrapper().getDimensionType().getDimensionName() + "]");
|
||||
lines.add(" Loaded files: " + this.loadedMetaFileBySectionPos.size());
|
||||
lines.add(" Thread pool tasks: " + executor.getQueue().size() + " (completed: " + executor.getCompletedTaskCount() + ")");
|
||||
lines.add(" Thread pool tasks: " + queueSize + " (completed: " + completedTaskSize + ")");
|
||||
|
||||
int totalFutures = this.taskTracker.size();
|
||||
EnumMap<ETaskType, Integer> tasksOutstanding = new EnumMap<>(ETaskType.class);
|
||||
|
||||
+5
-2
@@ -57,7 +57,7 @@ public class SubDimCompare implements Comparable<SubDimCompare>
|
||||
}
|
||||
|
||||
/** returns a number between 0 (no equal datapoint) and 1 (totally equal) */
|
||||
public double getPercentEqual() { return (double) equalDataPoints / (double) totalDataPoints; }
|
||||
public double getPercentEqual() { return (double) this.equalDataPoints / (double) this.totalDataPoints; }
|
||||
|
||||
|
||||
@Override
|
||||
@@ -66,7 +66,7 @@ public class SubDimCompare implements Comparable<SubDimCompare>
|
||||
if (this.equalDataPoints != other.equalDataPoints)
|
||||
{
|
||||
// compare based on data points
|
||||
return Integer.compare(this.equalDataPoints, other.equalDataPoints);
|
||||
return Double.compare(this.getPercentEqual(), other.getPercentEqual());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -83,4 +83,7 @@ public class SubDimCompare implements Comparable<SubDimCompare>
|
||||
|| this.playerPosDist <= MAX_SIMILAR_PLAYER_POS_DISTANCE_IN_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return this.equalDataPoints + "/" + this.totalDataPoints + ": " + this.getPercentEqual() + " playerPos: " + this.playerPosDist; }
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -332,7 +332,7 @@ public class SubDimensionLevelMatcher implements AutoCloseable
|
||||
|
||||
|
||||
String subDimShortName = LodUtil.shortenString(testLevelFolder.getName(), 8); // variables are separated out for easier debugging
|
||||
String equalPercent = LodUtil.shortenString(subDimCompare.getPercentEqual()+"", 5);
|
||||
String equalPercent = LodUtil.shortenString(mostSimilarSubDim.getPercentEqual()+"", 5);
|
||||
LOGGER.info("Sub dimension ["+subDimShortName+"...] is current dimension probability: "+equalPercent+" ("+equalDataPoints+"/"+totalDataPointCount+")");
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
+21
-16
@@ -72,6 +72,8 @@ public class DhLightingEngine
|
||||
DhChunkPos centerChunkPos = centerChunk.getChunkPos();
|
||||
AdjacentChunkHolder adjacentChunkHolder = new AdjacentChunkHolder(centerChunk);
|
||||
|
||||
long startTimeNs = System.nanoTime();
|
||||
|
||||
|
||||
// try-finally to handle the stableArray resources
|
||||
StableLightPosStack blockLightPosQueue = null;
|
||||
@@ -143,25 +145,25 @@ public class DhLightingEngine
|
||||
{
|
||||
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||
{
|
||||
// get the light
|
||||
int maxY = chunk.getLightBlockingHeightMapValue(relX, relZ);
|
||||
DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinBlockX() + relX, maxY, chunk.getMinBlockZ() + relZ);
|
||||
if (skyLightPos.y < chunk.getMinBuildHeight() || skyLightPos.y > chunk.getMaxBuildHeight())
|
||||
// set each pos' sky light all the way down until a opaque block is hit
|
||||
for (int y = chunk.getMaxBuildHeight(); y >= chunk.getMinBuildHeight(); y--)
|
||||
{
|
||||
// this shouldn't normally happen
|
||||
if (!warningLogged)
|
||||
IBlockStateWrapper block = chunk.getBlockState(relX, y, relZ);
|
||||
if (block != null && block.getOpacity() != IBlockStateWrapper.FULLY_TRANSPARENT)
|
||||
{
|
||||
warningLogged = true;
|
||||
LOGGER.debug("Lighting chunk at pos " + chunk.getChunkPos() + " may have a missing or incomplete heightmap. Chunk min/max [" + chunk.getMinBuildHeight() + "/" + chunk.getMaxBuildHeight() + "], skylight pos: " + skyLightPos);
|
||||
// keep moving down until we find a non-transparent block
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
|
||||
// add sky light to the queue
|
||||
DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinBlockX() + relX, y, chunk.getMinBlockZ() + relZ);
|
||||
skyLightPosQueue.push(skyLightPos.x, skyLightPos.y, skyLightPos.z, maxSkyLight);
|
||||
|
||||
// set the chunk's sky light
|
||||
skyLightPos.mutateToChunkRelativePos(relBlockPos);
|
||||
chunk.setDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, maxSkyLight);
|
||||
}
|
||||
skyLightPosQueue.push(skyLightPos.x, skyLightPos.y, skyLightPos.z, maxSkyLight);
|
||||
|
||||
|
||||
// set the light
|
||||
skyLightPos.mutateToChunkRelativePos(relBlockPos);
|
||||
chunk.setDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, maxSkyLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,7 +201,10 @@ public class DhLightingEngine
|
||||
|
||||
centerChunk.setIsDhLightCorrect(true);
|
||||
centerChunk.setUseDhLighting(true);
|
||||
LOGGER.trace("Finished generating lighting for chunk: [" + centerChunkPos + "]");
|
||||
|
||||
long endTimeNs = System.nanoTime();
|
||||
float totalTimeMs = (endTimeNs - startTimeNs) / 1_000_000.0f;
|
||||
LOGGER.trace("Finished generating lighting for chunk: [" + centerChunkPos + "] in ["+totalTimeMs+"] milliseconds");
|
||||
}
|
||||
|
||||
/** Applies each {@link LightPos} from the queue to the given set of {@link IChunkWrapper}'s. */
|
||||
|
||||
+2
-1
@@ -518,7 +518,8 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
try
|
||||
{
|
||||
int waitTimeInSeconds = 3;
|
||||
if (!ThreadPools.getWorldGenExecutor().awaitTermination(waitTimeInSeconds, TimeUnit.SECONDS))
|
||||
ThreadPoolExecutor executor = ThreadPools.getWorldGenExecutor();
|
||||
if (executor != null && !executor.awaitTermination(waitTimeInSeconds, TimeUnit.SECONDS))
|
||||
{
|
||||
LOGGER.warn("World generator thread pool shutdown didn't complete after [" + waitTimeInSeconds + "] seconds. Some world generator requests may still be running.");
|
||||
}
|
||||
|
||||
@@ -74,13 +74,19 @@ public class WebDownloader
|
||||
fos, 1024))
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
int i;
|
||||
int i, percent = -1;
|
||||
while ((i = in.read(data, 0, 1024)) >= 0)
|
||||
{
|
||||
totalDataRead = totalDataRead + i;
|
||||
bout.write(data, 0, i);
|
||||
// int percent = (int) ((totalDataRead * 100) / filesize);
|
||||
// System.out.println(percent);
|
||||
|
||||
// TODO: Link this to an atomic integer rather than printing it to log
|
||||
int newPercent = (int) ((totalDataRead * 100) / filesize);
|
||||
if (percent != newPercent)
|
||||
{
|
||||
percent = newPercent;
|
||||
System.out.println(String.valueOf(percent) +"% downloaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class SelfUpdater
|
||||
|
||||
|
||||
LOGGER.info("New version (" + ModrinthGetter.getLatestNameForVersion(mcVersion) + ") of " + ModInfo.READABLE_NAME + " is available");
|
||||
newFileLocation = JarUtils.jarFile.getParentFile().toPath().resolve("update").resolve(ModInfo.NAME + "-" + ModrinthGetter.getLatestNameForVersion(mcVersion) + ".jar").toFile();
|
||||
newFileLocation = JarUtils.jarFile.getParentFile().toPath().resolve("update").resolve(ModInfo.NAME + "-" + ModrinthGetter.getLatestNameForVersion(mcVersion) + "-" + mcVersion + ".jar").toFile();
|
||||
if (Config.Client.Advanced.AutoUpdater.enableSilentUpdates.get())
|
||||
{
|
||||
// Auto-update mod
|
||||
@@ -141,7 +141,7 @@ public class SelfUpdater
|
||||
|
||||
if (!pipeline.get("status").equals("success"))
|
||||
{
|
||||
LOGGER.warn("Pipeline for branch ["+ ModJarInfo.Git_Branch +"], commit ["+ pipeline.get("id") +"], has either failed to build, or still building.");
|
||||
LOGGER.warn("Pipeline for branch ["+ ModJarInfo.Git_Branch +"], pipeline ID ["+ pipeline.get("id") +"], has either failed to build, or is still building.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,8 +138,15 @@ public class DhClientLevel extends DhLevel implements IDhClientLevel
|
||||
@Override
|
||||
public void clientTick()
|
||||
{
|
||||
this.chunkToLodBuilder.tick();
|
||||
this.clientside.clientTick();
|
||||
try
|
||||
{
|
||||
this.chunkToLodBuilder.tick();
|
||||
this.clientside.clientTick();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected clientTick Exception: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void doWorldGen()
|
||||
|
||||
@@ -324,10 +324,10 @@ public class LodRenderSection implements IDebugRenderable
|
||||
if (showRenderSectionStatus && this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
{
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(this.pos, 32f, 64f, 0.2f, Color.yellow),
|
||||
0.5, 16f
|
||||
)
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(this.pos, 32f, 64f, 0.2f, Color.yellow),
|
||||
0.5, 16f
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -30,6 +30,7 @@ import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAtt
|
||||
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.render.fog.LodFogConfig;
|
||||
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||
@@ -54,7 +55,8 @@ public class LodRenderProgram extends ShaderProgram
|
||||
|
||||
public final int lightMapUniform;
|
||||
|
||||
// Fog Uniforms
|
||||
// Fog/Clip Uniforms
|
||||
public final int clipDistanceUniform;
|
||||
|
||||
// Noise Uniforms
|
||||
public final int noiseEnabledUniform;
|
||||
@@ -84,6 +86,8 @@ public class LodRenderProgram extends ShaderProgram
|
||||
|
||||
lightMapUniform = getUniformLocation("lightMap");
|
||||
|
||||
// Fog/Clip Uniforms
|
||||
clipDistanceUniform = getUniformLocation("clipDistance");
|
||||
|
||||
// Noise Uniforms
|
||||
noiseEnabledUniform = getUniformLocation("noiseEnabled");
|
||||
@@ -166,10 +170,10 @@ public class LodRenderProgram extends ShaderProgram
|
||||
vao.unbindBuffersFromAllBindingPoint();
|
||||
}
|
||||
|
||||
public void fillUniformData(Mat4f combinedMatrix, int lightmapBindPoint, int worldYOffset, int vanillaDrawDistance)
|
||||
public void fillUniformData(Mat4f combinedMatrix, int lightmapBindPoint, int worldYOffset, float partialTicks)
|
||||
{
|
||||
super.bind();
|
||||
vanillaDrawDistance += 32; // Give it a 2 chunk boundary for near fog.
|
||||
|
||||
// uniforms
|
||||
setUniform(combinedMatUniform, combinedMatrix);
|
||||
setUniform(mircoOffsetUniform, 0.01f); // 0.01 block offset
|
||||
@@ -182,6 +186,9 @@ public class LodRenderProgram extends ShaderProgram
|
||||
// Debug
|
||||
setUniform(whiteWorldUniform, Config.Client.Advanced.Debugging.enableWhiteWorld.get());
|
||||
|
||||
// Fog/Clip Uniforms
|
||||
float dhNearClipDistance = RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks);
|
||||
setUniform(clipDistanceUniform, dhNearClipDistance);
|
||||
}
|
||||
|
||||
public void setModelPos(Vec3f modelPos)
|
||||
|
||||
@@ -254,7 +254,7 @@ public class LodRenderer
|
||||
// and often do change the projection entirely, as well as the output usage.
|
||||
|
||||
//EVENT_LOGGER.debug("Skipping shadow pass render.");
|
||||
//return;
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: Since lightmapTexture is changing every frame, it's faster to recreate it than to reuse the old one.
|
||||
@@ -365,7 +365,7 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
/*---------Get required data--------*/
|
||||
int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
|
||||
//int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
|
||||
//Mat4f modelViewProjectionMatrix = RenderUtil.createCombinedModelViewProjectionMatrix(baseProjectionMatrix, baseModelViewMatrix, partialTicks);
|
||||
|
||||
Mat4f projectionMatrix = RenderUtil.createLodProjectionMatrix(baseProjectionMatrix, partialTicks);
|
||||
@@ -375,7 +375,7 @@ public class LodRenderer
|
||||
|
||||
/*---------Fill uniform data--------*/
|
||||
this.shaderProgram.fillUniformData(modelViewProjectionMatrix, /*Light map = GL_TEXTURE0*/ 0,
|
||||
MC.getWrappedClientLevel().getMinHeight(), vanillaBlockRenderedDistance);
|
||||
MC.getWrappedClientLevel().getMinHeight(), partialTicks);
|
||||
|
||||
lightmap.bind();
|
||||
if (ENABLE_IBO)
|
||||
|
||||
+1049
File diff suppressed because it is too large
Load Diff
@@ -256,12 +256,17 @@ public class RenderDataPointUtil
|
||||
// TODO this should probably be moved
|
||||
|
||||
// TODO what is the purpose of these?
|
||||
//these were needed by the old logic for mergeMultiData(),
|
||||
//which has now been replaced by RenderDataPointReducingList.
|
||||
//so, these are no longer necessary, but left here for the same
|
||||
//reason the old logic is left here: in case it's ever needed again.
|
||||
/*
|
||||
private static final ThreadLocal<int[]> tLocalIndices = new ThreadLocal<>();
|
||||
private static final ThreadLocal<boolean[]> tLocalIncreaseIndex = new ThreadLocal<>();
|
||||
private static final ThreadLocal<boolean[]> tLocalIndexHandled = new ThreadLocal<>();
|
||||
private static final ThreadLocal<short[]> tLocalHeightAndDepth = new ThreadLocal<>();
|
||||
private static final ThreadLocal<int[]> tDataIndexCache = new ThreadLocal<>();
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* This method merge column of multiple data together
|
||||
@@ -271,6 +276,32 @@ public class RenderDataPointUtil
|
||||
*/
|
||||
public static void mergeMultiData(IColumnDataView sourceData, ColumnArrayView output)
|
||||
{
|
||||
int target = output.verticalSize();
|
||||
if (target <= 0)
|
||||
{
|
||||
// I expect this to never be the case,
|
||||
// but RenderDataPointReducingList handles it sanely,
|
||||
// so I might as well handle it sanely here too.
|
||||
output.fill(EMPTY_DATA);
|
||||
}
|
||||
else if (target == 1)
|
||||
{
|
||||
output.set(0, RenderDataPointReducingList.reduceToOne(sourceData));
|
||||
for (int index = 1, size = output.size(); index < size; index++)
|
||||
{
|
||||
output.set(index, EMPTY_DATA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderDataPointReducingList list = new RenderDataPointReducingList(sourceData);
|
||||
list.reduce(output.verticalSize());
|
||||
list.copyTo(output);
|
||||
}
|
||||
|
||||
|
||||
//old logic left here in case it's ever needed again.
|
||||
/*
|
||||
if (output.dataCount() != 1)
|
||||
{
|
||||
throw new IllegalArgumentException("output must be only reserved for one datapoint!");
|
||||
@@ -612,6 +643,7 @@ public class RenderDataPointUtil
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
@@ -145,16 +145,21 @@ public class RenderUtil
|
||||
*/
|
||||
public static Mat4f createLodProjectionMatrix(Mat4f mcProjMat, float partialTicks)
|
||||
{
|
||||
// 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);
|
||||
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
|
||||
{
|
||||
nearClipDist = 0.1f;
|
||||
}
|
||||
|
||||
int farPlaneDistanceInBlocks = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||
float farClipDist = (float) ((farPlaneDistanceInBlocks + LodUtil.REGION_WIDTH) * Math.sqrt(2));
|
||||
|
||||
// Create a copy of the current matrix, so it won't be modified.
|
||||
Mat4f lodProj = mcProjMat.copy();
|
||||
|
||||
// Set new far and near clip plane values.
|
||||
lodProj.setClipPlanes(
|
||||
getNearClipPlaneDistanceInBlocks(partialTicks),
|
||||
(float) ((farPlaneDistanceInBlocks + LodUtil.REGION_WIDTH) * Math.sqrt(2)));
|
||||
|
||||
lodProj.setClipPlanes(nearClipDist, farClipDist);
|
||||
return lodProj;
|
||||
}
|
||||
|
||||
@@ -198,34 +203,21 @@ public class RenderUtil
|
||||
else
|
||||
{
|
||||
// TODO make this option dependent on player speed.
|
||||
// if the player is flying quickly, lower the near clip plane to account for slow chunk loading.
|
||||
// If the player is flying quickly, lower the near clip plane to account for slow chunk loading.
|
||||
// If the player is moving quickly they are less likely to notice overdraw.
|
||||
|
||||
EOverdrawPrevention clipPlaneDistance = Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPrevention.get();
|
||||
switch (clipPlaneDistance)
|
||||
nearClipPlane = Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPrevention.get().floatValue();
|
||||
nearClipPlane *= vanillaBlockRenderedDistance;
|
||||
|
||||
// the near clip plane should never be closer than 1/10th of a block,
|
||||
// otherwise Z-fighting and other issues may occur
|
||||
if (nearClipPlane < 0.1f)
|
||||
{
|
||||
default: // shouldn't be necessary, just here to make the compiler happy
|
||||
case NONE:
|
||||
nearClipPlane = 0.1f;
|
||||
break;
|
||||
|
||||
case LIGHT:
|
||||
nearClipPlane = vanillaBlockRenderedDistance * 0.25f;
|
||||
break;
|
||||
|
||||
case MEDIUM:
|
||||
nearClipPlane = vanillaBlockRenderedDistance * 0.4f;
|
||||
break;
|
||||
|
||||
|
||||
case HEAVY:
|
||||
// recommend render distance ot 6 or higher, otherwise holes may appear
|
||||
nearClipPlane = vanillaBlockRenderedDistance * 0.6f;
|
||||
break;
|
||||
nearClipPlane = 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
// modify the based on the player's FOV
|
||||
// modify based on the player's FOV
|
||||
double fov = MC_RENDER.getFov(partialTicks);
|
||||
double aspectRatio = (double) MC_RENDER.getScreenWidth() / MC_RENDER.getScreenHeight();
|
||||
|
||||
|
||||
+1
-2
@@ -90,9 +90,8 @@ public class ConfigThreadPool
|
||||
{
|
||||
if (this.executor != null)
|
||||
{
|
||||
//LOGGER.info("Stopping File Handler");
|
||||
//LOGGER.info("Stopping thread pool");
|
||||
this.executor.shutdownNow();
|
||||
this.executor = null;
|
||||
}
|
||||
|
||||
this.threadCount = 0;
|
||||
|
||||
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.core.util.threading;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
@@ -42,13 +43,16 @@ public class ThreadPools
|
||||
|
||||
public static final DhThreadFactory FILE_HANDLER_THREAD_FACTORY = new DhThreadFactory("File Handler", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool fileHandlerThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getFileHandlerExecutor() { return fileHandlerThreadPool.executor; }
|
||||
|
||||
public static final DhThreadFactory WORLD_GEN_THREAD_FACTORY = new DhThreadFactory("World Gen", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool worldGenThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getWorldGenExecutor() { return worldGenThreadPool.executor; }
|
||||
|
||||
private static ThreadPoolExecutor bufferUploaderThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getBufferUploaderExecutor() { return bufferUploaderThreadPool; }
|
||||
|
||||
|
||||
@@ -63,14 +67,17 @@ public class ThreadPools
|
||||
|
||||
public static final DhThreadFactory LIGHT_POPULATOR_THREAD_FACTORY = new DhThreadFactory("LOD Builder - Light Populator", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool lightPopulatorThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getLightPopulatorExecutor() { return lightPopulatorThreadPool.executor; }
|
||||
|
||||
public static final DhThreadFactory CHUNK_TO_LOD_BUILDER_THREAD_FACTORY = new DhThreadFactory("LOD Builder - Chunk to Lod Builder", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool chunkToLodBuilderThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getChunkToLodBuilderExecutor() { return chunkToLodBuilderThreadPool.executor; }
|
||||
|
||||
public static final DhThreadFactory BUFFER_BUILDER_THREAD_FACTORY = new DhThreadFactory("LOD Builder - Buffer Builder", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool bufferBuilderThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getBufferBuilderExecutor() { return bufferBuilderThreadPool.executor; }
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
@@ -69,7 +70,7 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public DhClientServerLevel getOrLoadLevel(ILevelWrapper wrapper)
|
||||
public DhClientServerLevel getOrLoadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (wrapper instanceof IServerLevelWrapper)
|
||||
{
|
||||
@@ -105,13 +106,13 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhClientServerLevel getLevel(ILevelWrapper wrapper) { return this.levelWrapperByDhLevel.get(wrapper); }
|
||||
public DhClientServerLevel getLevel(@NotNull ILevelWrapper wrapper) { return this.levelWrapperByDhLevel.get(wrapper); }
|
||||
|
||||
@Override
|
||||
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.dhLevels; }
|
||||
|
||||
@Override
|
||||
public void unloadLevel(ILevelWrapper wrapper)
|
||||
public void unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (this.levelWrapperByDhLevel.containsKey(wrapper))
|
||||
{
|
||||
@@ -160,7 +161,12 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
|
||||
this.saveAndFlush();
|
||||
this.f3Message.close();
|
||||
|
||||
for (DhClientServerLevel level : this.dhLevels)
|
||||
|
||||
// clear dhLevels to prevent concurrent modification errors
|
||||
HashSet<DhClientServerLevel> levelsToClose = new HashSet<>(this.dhLevels);
|
||||
this.dhLevels.clear();
|
||||
// close each level
|
||||
for (DhClientServerLevel level : levelsToClose)
|
||||
{
|
||||
LOGGER.info("Unloading level " + level.getServerLevelWrapper().getDimensionType().getDimensionName());
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.seibel.distanthorizons.core.util.objects.EventLoop;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
import java.io.File;
|
||||
@@ -84,7 +85,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public DhClientLevel getOrLoadLevel(ILevelWrapper wrapper)
|
||||
public DhClientLevel getOrLoadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IClientLevelWrapper))
|
||||
{
|
||||
@@ -105,7 +106,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhClientLevel getLevel(ILevelWrapper wrapper)
|
||||
public DhClientLevel getLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IClientLevelWrapper))
|
||||
{
|
||||
@@ -119,7 +120,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.levels.values(); }
|
||||
|
||||
@Override
|
||||
public void unloadLevel(ILevelWrapper wrapper)
|
||||
public void unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IClientLevelWrapper))
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
@@ -48,7 +49,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
public DhServerWorld()
|
||||
{
|
||||
super(EWorldEnvironment.Server_Only);
|
||||
|
||||
|
||||
this.saveStructure = new LocalSaveStructure();
|
||||
this.levels = new HashMap<>();
|
||||
|
||||
@@ -57,7 +58,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
|
||||
LOGGER.info("Started "+DhServerWorld.class.getSimpleName()+" of type "+this.environment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
@@ -79,15 +80,15 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
this.getLevel(dest).addPlayer(player);
|
||||
this.getLevel(origin).removePlayer(player);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DhServerLevel getOrLoadLevel(ILevelWrapper wrapper)
|
||||
public DhServerLevel getOrLoadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IServerLevelWrapper))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return this.levels.computeIfAbsent((IServerLevelWrapper) wrapper, (serverLevelWrapper) ->
|
||||
{
|
||||
File levelFile = this.saveStructure.getLevelFolder(wrapper);
|
||||
@@ -95,29 +96,29 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
return new DhServerLevel(this.saveStructure, serverLevelWrapper, this.remotePlayerConnectionHandler);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DhServerLevel getLevel(ILevelWrapper wrapper)
|
||||
public DhServerLevel getLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IServerLevelWrapper))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return this.levels.get(wrapper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.levels.values(); }
|
||||
|
||||
|
||||
@Override
|
||||
public void unloadLevel(ILevelWrapper wrapper)
|
||||
public void unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IServerLevelWrapper))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (this.levels.containsKey(wrapper))
|
||||
{
|
||||
LOGGER.info("Unloading level {} ", this.levels.get(wrapper));
|
||||
@@ -133,18 +134,18 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
public void doWorldGen() {
|
||||
this.levels.values().forEach(DhServerLevel::doWorldGen);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> saveAndFlush()
|
||||
{
|
||||
return CompletableFuture.allOf(this.levels.values().stream().map(DhServerLevel::saveAsync).toArray(CompletableFuture[]::new));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
this.remotePlayerConnectionHandler.close();
|
||||
|
||||
|
||||
for (DhServerLevel level : this.levels.values())
|
||||
{
|
||||
LOGGER.info("Unloading level " + level.getLevelWrapper().getDimensionType().getDimensionName());
|
||||
@@ -158,7 +159,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
|
||||
|
||||
level.close();
|
||||
}
|
||||
|
||||
|
||||
this.levels.clear();
|
||||
LOGGER.info("Closed DhWorld of type " + this.environment);
|
||||
}
|
||||
|
||||
@@ -21,17 +21,18 @@ package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface IDhWorld
|
||||
{
|
||||
|
||||
IDhLevel getOrLoadLevel(ILevelWrapper levelWrapper);
|
||||
IDhLevel getLevel(ILevelWrapper wrapper);
|
||||
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||
IDhLevel getLevel(@NotNull ILevelWrapper wrapper);
|
||||
Iterable<? extends IDhLevel> getAllLoadedLevels();
|
||||
|
||||
void unloadLevel(ILevelWrapper levelWrapper);
|
||||
void unloadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||
|
||||
CompletableFuture<Void> saveAndFlush();
|
||||
|
||||
|
||||
+5
@@ -25,6 +25,11 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
/** A Minecraft version independent way of handling Blocks. */
|
||||
public interface IBlockStateWrapper extends IDhApiBlockStateWrapper
|
||||
{
|
||||
int FULLY_TRANSPARENT = 0;
|
||||
int FULLY_OPAQUE = 16;
|
||||
|
||||
|
||||
|
||||
String getSerialString();
|
||||
|
||||
/**
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.overdrawPrevention":
|
||||
"Overdraw Prevention",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.overdrawPrevention.@tooltip":
|
||||
"Enabling this will prevent some overdraw issues,\nbut may cause nearby LODs to render incorrectly, especially when near fancy leaves or non-full blocks.\nLess noticeable with a longer vanilla render distance.",
|
||||
"Determines how far from the camera Distant Horizons will start rendering. \nMeasured as a percentage of the vanilla render distance.\n\nHigher values will prevent LODs from rendering behind vanilla blocks at a higher distance,\nbut may cause holes to appear in the LODs. \nHoles are most likely to appear when flying through unloaded terrain. \n\nIncreasing the vanilla render distance increases the effectiveness of this setting.",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.seamlessOverdraw":
|
||||
"(Experimental) Seamless Overdraw",
|
||||
"distanthorizons.config.client.advanced.graphics.advancedGraphics.seamlessOverdraw.@tooltip":
|
||||
@@ -335,6 +335,10 @@
|
||||
"Minimum Time Between Chunk Updates In Seconds",
|
||||
"distanthorizons.config.client.advanced.lodBuilding.minTimeBetweenChunkUpdatesInSeconds.@tooltip":
|
||||
"Determines how long must pass between LOD chunk updates before another. \nupdate can occur\n\nIncreasing this value will reduce CPU load but may may cause \nLODs to become outdated more frequently or for longer.",
|
||||
"distanthorizons.config.client.advanced.lodBuilding.onlyUseDhLightingEngine":
|
||||
"Only Use DH Lighting Engine",
|
||||
"distanthorizons.config.client.advanced.lodBuilding.onlyUseDhLightingEngine.@tooltip":
|
||||
"If false LODs will be lit by Minecraft's lighting engine when possible \nand fall back to the DH lighting engine only when necessary. \n\nIf true LODs will only be lit using Distant Horizons' lighting engine. \n\nGenerally it is best to leave this disabled and should only be enabled \nif there are lighting issues or for debugging.",
|
||||
|
||||
|
||||
"distanthorizons.config.client.advanced.multiplayer":
|
||||
|
||||
@@ -8,6 +8,9 @@ in vec4 vPos;
|
||||
out vec4 fragColor;
|
||||
|
||||
|
||||
// Fog/Clip Uniforms
|
||||
uniform float clipDistance = 0.0;
|
||||
|
||||
// Noise Uniforms
|
||||
uniform bool noiseEnabled;
|
||||
uniform int noiseSteps;
|
||||
@@ -24,47 +27,53 @@ float rand(vec3 co) { return rand(co.xy + rand(co.z)); }
|
||||
// EG. setting stepSize to 4 then this would be the result of this function
|
||||
// In: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, ..., 1.1, 1.2, 1.3
|
||||
// Out: 0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, ..., 1.0, 1.0, 1.25
|
||||
vec3 quantize(vec3 val, int stepSize) {
|
||||
vec3 quantize(vec3 val, int stepSize)
|
||||
{
|
||||
return floor(val * stepSize) / stepSize;
|
||||
}
|
||||
|
||||
void applyNoise(inout vec4 fragColor, const in float viewDist)
|
||||
{
|
||||
vec3 vertexNormal = normalize(cross(dFdy(vPos.xyz), dFdx(vPos.xyz)));
|
||||
// This bit of code is required to fix the vertex position problem cus of floats in the verted world position varuable
|
||||
vec3 fixedVPos = vPos.xyz + vertexNormal * 0.001;
|
||||
|
||||
float noiseAmplification = noiseIntensity * 0.01;
|
||||
float lum = (fragColor.r + fragColor.g + fragColor.b) / 3.0;
|
||||
noiseAmplification = (1.0 - pow(lum * 2.0 - 1.0, 2.0)) * noiseAmplification; // Lessen the effect on depending on how dark the object is, equasion for this is -(2x-1)^{2}+1
|
||||
noiseAmplification *= fragColor.a; // The effect would lessen on transparent objects
|
||||
|
||||
// Random value for each position
|
||||
float randomValue = rand(quantize(fixedVPos, noiseSteps))
|
||||
* 2.0 * noiseAmplification - noiseAmplification;
|
||||
|
||||
// Modifies the color
|
||||
// A value of 0 on the randomValue will result in the original color, while a value of 1 will result in a fully bright color
|
||||
vec3 newCol = fragColor.rgb + (1.0 - fragColor.rgb) * randomValue;
|
||||
newCol = clamp(newCol, 0.0, 1.0);
|
||||
|
||||
if (noiseDropoff != 0) {
|
||||
float distF = min(viewDist / noiseDropoff, 1.0);
|
||||
newCol = mix(newCol, fragColor.rgb, distF); // The further away it gets, the less noise gets applied
|
||||
}
|
||||
|
||||
fragColor.rgb = newCol;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fragment Shader
|
||||
*
|
||||
* author: James Seibel
|
||||
* author: coolGi
|
||||
* version: 7-2-2023
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
fragColor = vertexColor;
|
||||
|
||||
// TODO: Move into its own function instead of in an if statement
|
||||
if (noiseEnabled) {
|
||||
vec3 vertexNormal = normalize(cross(dFdy(vPos.xyz), dFdx(vPos.xyz)));
|
||||
// This bit of code is required to fix the vertex position problem cus of floats in the verted world position varuable
|
||||
vec3 fixedVPos = vPos.xyz + vertexNormal * 0.001;
|
||||
|
||||
float noiseAmplification = noiseIntensity * 0.01;
|
||||
float lum = (fragColor.r + fragColor.g + fragColor.b) / 3.0;
|
||||
noiseAmplification = (1.0 - pow(lum * 2.0 - 1.0, 2.0)) * noiseAmplification; // Lessen the effect on depending on how dark the object is, equasion for this is -(2x-1)^{2}+1
|
||||
noiseAmplification *= fragColor.a; // The effect would lessen on transparent objects
|
||||
|
||||
// Random value for each position
|
||||
float randomValue = rand(quantize(fixedVPos, noiseSteps))
|
||||
* 2.0 * noiseAmplification - noiseAmplification;
|
||||
|
||||
// Modifies the color
|
||||
// A value of 0 on the randomValue will result in the original color, while a value of 1 will result in a fully bright color
|
||||
vec3 newCol = fragColor.rgb + (1.0 - fragColor.rgb) * randomValue;
|
||||
newCol = clamp(newCol, 0.0, 1.0);
|
||||
|
||||
if (noiseDropoff != 0) {
|
||||
float distF = min(length(vertexWorldPos) / noiseDropoff, 1.0);
|
||||
newCol = mix(newCol, fragColor.rgb, distF); // The further away it gets, the less noise gets applied
|
||||
}
|
||||
|
||||
fragColor.rgb = newCol;
|
||||
float viewDist = length(vertexWorldPos);
|
||||
if (viewDist < clipDistance && clipDistance > 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
if (noiseEnabled)
|
||||
{
|
||||
applyNoise(fragColor, viewDist);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user