This commit is contained in:
s809
2023-11-03 21:05:27 +05:00
9 changed files with 151 additions and 100 deletions
@@ -46,6 +46,6 @@ public enum EThreadPreset
AGGRESSIVE,
// temporarily removed due to stability concerns
//I_PAID_FOR_THE_WHOLE_CPU;
I_PAID_FOR_THE_WHOLE_CPU,
}
@@ -101,8 +101,13 @@ public class ServerApi
{
LOGGER.debug("Server World " + SharedApi.getAbstractDhWorld() + " unloading");
SharedApi.getAbstractDhWorld().close();
SharedApi.setDhWorld(null);
// shutdown the world if it isn't already
AbstractDhWorld dhWorld = SharedApi.getAbstractDhWorld();
if (dhWorld != null)
{
dhWorld.close();
SharedApi.setDhWorld(null);
}
}
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.core.api.internal;
import com.seibel.distanthorizons.core.Initializer;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -30,6 +31,7 @@ import com.seibel.distanthorizons.core.util.objects.Pair;
import com.seibel.distanthorizons.core.util.threading.ThreadPools;
import com.seibel.distanthorizons.core.world.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger;
@@ -45,9 +47,10 @@ import java.util.concurrent.ThreadPoolExecutor;
/** Contains code and variables used by both {@link ClientApi} and {@link ServerApi} */
public class SharedApi
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final SharedApi INSTANCE = new 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();
@@ -88,6 +91,7 @@ public class SharedApi
{
ThreadPools.shutdownThreadPools();
DebugRenderer.clearRenderables();
MC_RENDER.clearTargetFrameBuffer();
// recommend that the garbage collector cleans up any objects from the old world and thread pools
System.gc();
@@ -49,7 +49,7 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EThreadPreset.LOW_IMPACT, getWorldGenDefaultThreadCount());
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.25));
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.5));
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
}});
public static double getWorldGenDefaultRunTimeRatio() { return LOW_THREAD_COUNT_CPU ? 0.5 : 0.75; }
private final ConfigEntryWithPresetOptions<EThreadPreset, Double> worldGenRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForWorldGenerationThreads,
@@ -59,7 +59,7 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EThreadPreset.LOW_IMPACT, getWorldGenDefaultRunTimeRatio());
this.put(EThreadPreset.BALANCED, LOW_THREAD_COUNT_CPU ? 0.5 : 0.75);
this.put(EThreadPreset.AGGRESSIVE, LOW_THREAD_COUNT_CPU ? 0.75 : 1.0);
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}});
@@ -71,7 +71,7 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EThreadPreset.LOW_IMPACT, getFileHandlerDefaultThreadCount());
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.2));
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.2));
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
}});
public static double getFileHandlerDefaultRunTimeRatio() { return 0.5; }
private final ConfigEntryWithPresetOptions<EThreadPreset, Double> fileHandlerRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForFileHandlerThreads,
@@ -81,7 +81,7 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EThreadPreset.LOW_IMPACT, getFileHandlerDefaultRunTimeRatio());
this.put(EThreadPreset.BALANCED, 0.75);
this.put(EThreadPreset.AGGRESSIVE, 1.0);
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}});
@@ -93,7 +93,7 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EThreadPreset.LOW_IMPACT, getLodBuilderDefaultThreadCount());
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.2));
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.4));
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
}});
public static double getLodBuilderDefaultRunTimeRatio() { return LOW_THREAD_COUNT_CPU ? 0.25 : 0.5; }
private final ConfigEntryWithPresetOptions<EThreadPreset, Double> lodBuilderRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForLodBuilderThreads,
@@ -103,7 +103,7 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EThreadPreset.LOW_IMPACT, getLodBuilderDefaultRunTimeRatio());
this.put(EThreadPreset.BALANCED, LOW_THREAD_COUNT_CPU ? 0.5 : 0.75);
this.put(EThreadPreset.AGGRESSIVE, 1.0);
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}});
@@ -82,20 +82,26 @@ public class FullDataPointIdMap
private Entry getEntry(int id)
{
this.readWriteLock.readLock().lock();
Entry entry;
try
{
entry = this.entryList.get(id);
this.readWriteLock.readLock().lock();
Entry entry;
try
{
entry = this.entryList.get(id);
}
catch (IndexOutOfBoundsException e)
{
LOGGER.error("FullData ID Map out of sync for pos: " + this.pos + ". ID: [" + id + "] greater than the number of known ID's: [" + this.entryList.size() + "].");
throw e;
}
return entry;
}
catch (IndexOutOfBoundsException e)
finally
{
LOGGER.error("FullData ID Map out of sync for pos: " + this.pos + ". ID: [" + id + "] greater than the number of known ID's: [" + this.entryList.size() + "].");
throw e;
this.readWriteLock.readLock().unlock();
}
this.readWriteLock.readLock().unlock();
return entry;
}
public IBiomeWrapper getBiomeWrapper(int id) { return this.getEntry(id).biome; }
@@ -115,33 +121,37 @@ public class FullDataPointIdMap
/** @param useWriteLocks should only be false if this method is already in a write lock to prevent unlocking at the wrong time */
private int addIfNotPresentAndGetId(Entry biomeBlockStateEntry, boolean useWriteLocks)
{
if (useWriteLocks)
try
{
this.readWriteLock.writeLock().lock();
if (useWriteLocks)
{
this.readWriteLock.writeLock().lock();
}
int id;
if (this.idMap.containsKey(biomeBlockStateEntry))
{
// use the existing ID
id = this.idMap.get(biomeBlockStateEntry);
}
else
{
// Add the new ID
id = this.entryList.size();
this.entryList.add(biomeBlockStateEntry);
this.idMap.put(biomeBlockStateEntry, id);
}
return id;
}
int id;
if (this.idMap.containsKey(biomeBlockStateEntry))
finally
{
// use the existing ID
id = this.idMap.get(biomeBlockStateEntry);
if (useWriteLocks)
{
this.readWriteLock.writeLock().unlock();
}
}
else
{
// Add the new ID
id = this.entryList.size();
this.entryList.add(biomeBlockStateEntry);
this.idMap.put(biomeBlockStateEntry, id);
}
if (useWriteLocks)
{
this.readWriteLock.writeLock().unlock();
}
return id;
}
@@ -152,26 +162,31 @@ public class FullDataPointIdMap
*/
public int[] mergeAndReturnRemappedEntityIds(FullDataPointIdMap target)
{
LOGGER.trace("merging {" + this.pos + ", " + this.entryList.size() + "} and {" + target.pos + ", " + target.entryList.size() + "}");
target.readWriteLock.readLock().lock();
this.readWriteLock.writeLock().lock();
ArrayList<Entry> entriesToMerge = target.entryList;
int[] remappedEntryIds = new int[entriesToMerge.size()];
for (int i = 0; i < entriesToMerge.size(); i++)
try
{
Entry entity = entriesToMerge.get(i);
int id = this.addIfNotPresentAndGetId(entity, false);
remappedEntryIds[i] = id;
LOGGER.trace("merging {" + this.pos + ", " + this.entryList.size() + "} and {" + target.pos + ", " + target.entryList.size() + "}");
target.readWriteLock.readLock().lock();
this.readWriteLock.writeLock().lock();
ArrayList<Entry> entriesToMerge = target.entryList;
int[] remappedEntryIds = new int[entriesToMerge.size()];
for (int i = 0; i < entriesToMerge.size(); i++)
{
Entry entity = entriesToMerge.get(i);
int id = this.addIfNotPresentAndGetId(entity, false);
remappedEntryIds[i] = id;
}
return remappedEntryIds;
}
finally
{
this.readWriteLock.writeLock().unlock();
target.readWriteLock.readLock().unlock();
LOGGER.trace("finished merging {" + this.pos + ", " + this.entryList.size() + "} and {" + target.pos + ", " + target.entryList.size() + "}");
}
this.readWriteLock.writeLock().unlock();
target.readWriteLock.readLock().unlock();
LOGGER.trace("finished merging {" + this.pos + ", " + this.entryList.size() + "} and {" + target.pos + ", " + target.entryList.size() + "}");
return remappedEntryIds;
}
/** Should only be used if this map is going to be reused, otherwise bad things will happen. */
@@ -191,33 +206,38 @@ public class FullDataPointIdMap
/** Serializes all contained entries into the given stream, formatted in UTF */
public void serialize(DhDataOutputStream outputStream) throws IOException
{
this.readWriteLock.readLock().lock();
outputStream.writeInt(this.entryList.size());
// only used when debugging
HashMap<String, FullDataPointIdMap.Entry> dataPointEntryBySerialization = new HashMap<>();
for (Entry entry : this.entryList)
try
{
String entryString = entry.serialize();
outputStream.writeUTF(entryString);
this.readWriteLock.readLock().lock();
outputStream.writeInt(this.entryList.size());
if (RUN_SERIALIZATION_DUPLICATE_VALIDATION)
// only used when debugging
HashMap<String, FullDataPointIdMap.Entry> dataPointEntryBySerialization = new HashMap<>();
for (Entry entry : this.entryList)
{
if (dataPointEntryBySerialization.containsKey(entryString))
String entryString = entry.serialize();
outputStream.writeUTF(entryString);
if (RUN_SERIALIZATION_DUPLICATE_VALIDATION)
{
LOGGER.error("Duplicate serialized entry found with serial: " + entryString);
if (dataPointEntryBySerialization.containsKey(entryString))
{
LOGGER.error("Duplicate serialized entry found with serial: " + entryString);
}
if (dataPointEntryBySerialization.containsValue(entry))
{
LOGGER.error("Duplicate serialized entry found with value: " + entry.serialize());
}
dataPointEntryBySerialization.put(entryString, entry);
}
if (dataPointEntryBySerialization.containsValue(entry))
{
LOGGER.error("Duplicate serialized entry found with value: " + entry.serialize());
}
dataPointEntryBySerialization.put(entryString, entry);
}
}
this.readWriteLock.readLock().unlock();
LOGGER.trace("serialize " + this.pos + " " + this.entryList.size());
finally
{
this.readWriteLock.readLock().unlock();
LOGGER.trace("serialize " + this.pos + " " + this.entryList.size());
}
}
/** Creates a new IdBiomeBlockStateMap from the given UTF formatted stream */
@@ -31,16 +31,16 @@ import org.apache.logging.log4j.Logger;
*
* @author coolGi
*/
public final class ModGitInfo
public final class ModJarInfo
{
private static final Logger LOGGER = LogManager.getLogger();
private static final String FILE_NAME = "build_info.json";
static
{
String gitMainBranch = "UNKNOWN";
String gitMainCommit = "UNKNOWN";
String gitCoreCommit = "UNKNOWN";
String gitBranch = "UNKNOWN";
String gitCommit = "UNKNOWN";
String buildSource = "UNKNOWN";
try
{
@@ -50,22 +50,22 @@ public final class ModGitInfo
Config jsonObject = Config.inMemory();
JsonFormat.minimalInstance().createParser().parse(jsonString, jsonObject, ParsingMode.REPLACE);
gitCoreCommit = jsonObject.get("git_main_branch");
gitMainCommit = jsonObject.get("git_main_commit");
gitMainBranch = jsonObject.get("git_core_commit");
gitBranch = jsonObject.get("info_git_branch");
gitCommit = jsonObject.get("info_git_commit");
buildSource = jsonObject.get("info_build_source");
}
catch (Exception | Error e)
{
LOGGER.warn("Unable to get the Git information from " + FILE_NAME);
}
Git_Core_Commit = gitMainBranch;
Git_Main_Commit = gitMainCommit;
Git_Main_Branch = gitCoreCommit;
Git_Commit = gitBranch;
Git_Branch = gitCommit;
Build_Source = buildSource;
}
public static final String Git_Main_Branch;
public static final String Git_Main_Commit;
public static final String Git_Core_Commit;
public static final String Git_Branch;
public static final String Git_Commit;
public static final String Build_Source;
}
@@ -22,7 +22,7 @@ package com.seibel.distanthorizons.core.jar.updater;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.JarUtils;
import com.seibel.distanthorizons.core.jar.ModGitInfo;
import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.installer.WebDownloader;
@@ -126,7 +126,7 @@ public class SelfUpdater
return false;
com.electronwill.nightconfig.core.Config pipeline = GitlabGetter.INSTANCE.projectPipelines.get(0);
if (!pipeline.get("ref").equals(ModGitInfo.Git_Main_Branch))
if (!pipeline.get("ref").equals(ModJarInfo.Git_Branch))
{
//LOGGER.warn("Latest pipeline was found for branch ["+ pipeline.get("ref") +"], but we are on branch ["+ ModGitInfo.Git_Main_Branch +"].");
return false;
@@ -134,7 +134,7 @@ public class SelfUpdater
if (!pipeline.get("status").equals("success"))
{
LOGGER.warn("Pipeline for branch ["+ ModGitInfo.Git_Main_Branch +"], commit ["+ pipeline.get("id") +"], has either failed to build, or still building.");
LOGGER.warn("Pipeline for branch ["+ ModJarInfo.Git_Branch +"], commit ["+ pipeline.get("id") +"], has either failed to build, or still building.");
return false;
}
@@ -146,7 +146,7 @@ public class SelfUpdater
String latestCommit = pipeline.get("sha");
if (ModGitInfo.Git_Main_Commit.equals(latestCommit)) // If we are already on the latest commit, then dont update
if (ModJarInfo.Git_Commit.equals(latestCommit)) // If we are already on the latest commit, then dont update
return false;
@@ -231,6 +231,12 @@ public class LodRenderer
return;
}
if (AbstractOptifineAccessor.optifinePresent() && MC_RENDER.getTargetFrameBuffer() == -1)
{
// wait for MC to finish setting up their renderer
return;
}
if (!renderLock.tryLock())
{
// never lock the render thread, if the lock isn't available don't wait for it
@@ -298,8 +304,17 @@ public class LodRenderer
// Bind LOD frame buffer
this.framebuffer.bind();
// Clear LOD framebuffer and depth buffers
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
if (this.usingMcFrameBuffer)
{
// don't clear the color texture, that removes the sky
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
else
{
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
GL32.glEnable(GL32.GL_DEPTH_TEST);
GL32.glDepthFunc(GL32.GL_LESS);
@@ -514,7 +529,7 @@ public class LodRenderer
if (AbstractOptifineAccessor.optifinePresent())
{
// use MC/Optifine's default FrameBuffer so shaders won't remove the LODs
int currentFrameBufferId = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
int currentFrameBufferId = MC_RENDER.getTargetFrameBuffer();
this.framebuffer = new DhFramebuffer(currentFrameBufferId);
this.usingMcFrameBuffer = true;
}
@@ -75,11 +75,18 @@ public interface IMinecraftRenderWrapper extends IBindable
int getScreenWidth();
int getScreenHeight();
/** @return -1 if no valid framebuffer is available yet */
int getTargetFrameBuffer();
int getDepthTextureId();
int getTargetFrameBufferViewportWidth();
int getTargetFrameBufferViewportHeight();
/**
* generally shouldn't be needed, the frame buffer should generally stay the same
* but in case something goes wrong this allows for re-getting the buffer ID.
*/
void clearTargetFrameBuffer();
/**
* This method returns the ChunkPos of all chunks that Minecraft
* is going to render this frame.