Improve F3 menu logic and visuals

This commit is contained in:
James Seibel
2024-06-15 19:20:20 -05:00
parent ad38722304
commit 67819b30eb
16 changed files with 375 additions and 311 deletions
@@ -65,23 +65,13 @@ public class SharedApi
private static int lastWorldGenTickDelta = 0;
private static long lastOverloadedLogMessageMsTime = 0;
public F3Screen.DynamicMessage f3Message;
//=============//
// constructor //
//=============//
private 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_POS_SET.size() + " / " + maxUpdateCount);
});
}
private SharedApi() { }
public static void init() { Initializer.init(); }
@@ -381,4 +371,18 @@ public class SharedApi
}
//=========//
// F3 Menu //
//=========//
public String getDebugMenuString()
{
int maxUpdateCount = MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get();
String updatingCountStr = F3Screen.NUMBER_FORMAT.format(UPDATING_CHUNK_POS_SET.size());
String maxUpdateCountStr = F3Screen.NUMBER_FORMAT.format(maxUpdateCount);
return "Queued chunk updates: "+updatingCountStr+" / "+maxUpdateCountStr;
}
}
@@ -92,6 +92,7 @@ public class FullDataSourceProviderV2
protected long legacyDeletionCount = -1;
protected long migrationCount = -1;
protected boolean migrationStoppedWithError = false;
/**
* Tracks which positions are currently being updated
@@ -386,82 +387,94 @@ public class FullDataSourceProviderV2
{
this.showMigrationStartMessage();
// keep going until every data source has been migrated
int progressCount = 0;
while (!legacyDataSourceList.isEmpty() && this.migrationThreadRunning.get())
try
{
LOGGER.info("Migrating [" + dimensionName + "] - [" + progressCount + "/" + totalMigrationCount + "]...");
ArrayList<CompletableFuture<Void>> updateFutureList = new ArrayList<>();
for (int i = 0; i < legacyDataSourceList.size() && this.migrationThreadRunning.get(); i++)
// keep going until every data source has been migrated
int progressCount = 0;
while (!legacyDataSourceList.isEmpty() && this.migrationThreadRunning.get())
{
FullDataSourceV1 legacyDataSource = legacyDataSourceList.get(i);
LOGGER.info("Migrating [" + dimensionName + "] - [" + progressCount + "/" + totalMigrationCount + "]...");
ArrayList<CompletableFuture<Void>> updateFutureList = new ArrayList<>();
for (int i = 0; i < legacyDataSourceList.size() && this.migrationThreadRunning.get(); i++)
{
FullDataSourceV1 legacyDataSource = legacyDataSourceList.get(i);
try
{
// convert the legacy data source to the new format,
// this is a relatively cheap operation
FullDataSourceV2 newDataSource = FullDataSourceV2.createFromLegacyDataSourceV1(legacyDataSource);
newDataSource.applyToParent = true;
// the actual update process can be moderately expensive due to having to update
// the render data along with the full data, so running it async on the update threads gains us a good bit of speed
CompletableFuture<Void> future = this.updateDataSourceAsync(newDataSource);
updateFutureList.add(future);
future.thenRun(() ->
{
// after the update finishes the legacy data source can be safely deleted
this.legacyFileHandler.repo.deleteWithKey(legacyDataSource.getPos());
try
{
newDataSource.close();
}
catch (Exception ignore)
{
}
});
}
catch (Exception e)
{
Long migrationPos = legacyDataSource.getPos();
LOGGER.warn("Unexpected issue migrating data source at pos " + migrationPos + ". Error: " + e.getMessage(), e);
this.legacyFileHandler.markMigrationFailed(migrationPos);
}
}
try
{
// convert the legacy data source to the new format,
// this is a relatively cheap operation
FullDataSourceV2 newDataSource = FullDataSourceV2.createFromLegacyDataSourceV1(legacyDataSource);
newDataSource.applyToParent = true;
// the actual update process can be moderately expensive due to having to update
// the render data along with the full data, so running it async on the update threads gains us a good bit of speed
CompletableFuture<Void> future = this.updateDataSourceAsync(newDataSource);
updateFutureList.add(future);
future.thenRun(() ->
{
// after the update finishes the legacy data source can be safely deleted
this.legacyFileHandler.repo.deleteWithKey(legacyDataSource.getPos());
try
{
newDataSource.close();
}
catch (Exception ignore){ }
});
// wait for each thread to finish updating
CompletableFuture<Void> combinedFutures = CompletableFuture.allOf(updateFutureList.toArray(new CompletableFuture[0]));
combinedFutures.get(MIGRATION_MAX_UPDATE_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);
}
catch (Exception e)
catch (InterruptedException | TimeoutException e)
{
Long migrationPos = legacyDataSource.getPos();
LOGGER.warn("Unexpected issue migrating data source at pos " + migrationPos + ". Error: " + e.getMessage(), e);
this.legacyFileHandler.markMigrationFailed(migrationPos);
LOGGER.warn("Migration update timed out after [" + MIGRATION_MAX_UPDATE_TIMEOUT_IN_MS + "] milliseconds. Migration will re-try the same positions again in a moment..", e);
}
catch (ExecutionException e)
{
LOGGER.warn("Migration update failed. Migration will re-try the same positions again. Error:" + e.getMessage(), e);
}
legacyDataSourceList = this.legacyFileHandler.getDataSourcesToMigrate(MIGRATION_BATCH_COUNT);
progressCount += legacyDataSourceList.size();
this.migrationCount -= legacyDataSourceList.size();
}
try
{
// wait for each thread to finish updating
CompletableFuture<Void> combinedFutures = CompletableFuture.allOf(updateFutureList.toArray(new CompletableFuture[0]));
combinedFutures.get(MIGRATION_MAX_UPDATE_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);
}
catch (InterruptedException | TimeoutException e)
{
LOGGER.warn("Migration update timed out after ["+MIGRATION_MAX_UPDATE_TIMEOUT_IN_MS+"] milliseconds. Migration will re-try the same positions again in a moment..", e);
}
catch (ExecutionException e)
{
LOGGER.warn("Migration update failed. Migration will re-try the same positions again. Error:"+e.getMessage(), e);
}
legacyDataSourceList = this.legacyFileHandler.getDataSourcesToMigrate(MIGRATION_BATCH_COUNT);
progressCount += legacyDataSourceList.size();
this.migrationCount -= legacyDataSourceList.size();
}
if (this.migrationThreadRunning.get())
catch (Exception e)
{
LOGGER.info("migration complete for: ["+dimensionName+"]-["+this.saveDir+"].");
this.showMigrationEndMessage(true);
this.migrationCount = 0;
}
else
{
LOGGER.info("migration stopped for: ["+dimensionName+"]-["+this.saveDir+"].");
LOGGER.info("migration stopped due to error for: ["+dimensionName+"]-["+this.saveDir+"], error: ["+e.getMessage()+"].", e);
this.showMigrationEndMessage(false);
this.migrationStoppedWithError = true;
}
finally
{
if (this.migrationThreadRunning.get())
{
LOGGER.info("migration complete for: ["+dimensionName+"]-["+this.saveDir+"].");
this.showMigrationEndMessage(true);
this.migrationCount = 0;
}
else
{
LOGGER.info("migration stopped for: ["+dimensionName+"]-["+this.saveDir+"].");
this.showMigrationEndMessage(false);
this.migrationStoppedWithError = true;
}
}
}
else
@@ -474,6 +487,7 @@ public class FullDataSourceProviderV2
public long getLegacyDeletionCount() { return this.legacyDeletionCount; }
public long getTotalMigrationCount() { return this.migrationCount; }
public boolean getMigrationStoppedWithError() { return this.migrationStoppedWithError; }
private void showMigrationStartMessage()
@@ -57,8 +57,6 @@ public class ClientLevelModule implements Closeable, AbstractDataSourceHandler.I
public final FullDataSourceProviderV2 fullDataSourceProvider;
public final AtomicReference<ClientRenderState> ClientRenderStateRef = new AtomicReference<>();
public final F3Screen.NestedMessage f3Message;
//=============//
@@ -68,7 +66,6 @@ public class ClientLevelModule implements Closeable, AbstractDataSourceHandler.I
public ClientLevelModule(IDhClientLevel clientLevel)
{
this.clientLevel = clientLevel;
this.f3Message = new F3Screen.NestedMessage(this::f3Log);
this.fullDataSourceProvider = this.clientLevel.getFullDataProvider();
this.fullDataSourceProvider.dateSourceUpdateListeners.add(this);
@@ -246,8 +243,6 @@ public class ClientLevelModule implements Closeable, AbstractDataSourceHandler.I
}
this.fullDataSourceProvider.dateSourceUpdateListeners.remove(this);
this.f3Message.close();
}
@@ -256,53 +251,6 @@ public class ClientLevelModule implements Closeable, AbstractDataSourceHandler.I
// misc helper functions //
//=======================//
private String[] f3Log()
{
String dimName = this.clientLevel.getLevelWrapper().getDimensionType().getDimensionName();
boolean rendererActive = this.ClientRenderStateRef.get() != null;
ThreadPoolExecutor fileExecutor = ThreadPoolUtil.getFileHandlerExecutor();
String fileQueueSize = (fileExecutor != null) ? fileExecutor.getQueue().size()+"" : "-";
String fileCompletedTaskSize = (fileExecutor != null) ? fileExecutor.getCompletedTaskCount()+"" : "-";
ThreadPoolExecutor updateExecutor = ThreadPoolUtil.getUpdatePropagatorExecutor();
String updateQueueSize = (updateExecutor != null) ? updateExecutor.getQueue().size()+"" : "-";
String updateCompletedTaskSize = (updateExecutor != null) ? updateExecutor.getCompletedTaskCount()+"" : "-";
int unsavedDataSourceCount = this.fullDataSourceProvider.getUnsavedDataSourceCount();
long legacyDeletionCount = this.fullDataSourceProvider.getLegacyDeletionCount();
long migrationCount = this.fullDataSourceProvider.getTotalMigrationCount();
ArrayList<String> lines = new ArrayList<>();
lines.add("");
lines.add("level [" + dimName + "] rendering: " + (rendererActive ? "Active" : "Inactive"));
// TODO a lot of these items only need to be rendered once, but we don't currently have a way of doing that, so only add them for the rendered level
if (rendererActive)
{
lines.add("File Handler [" + dimName + "]");
lines.add(" File thread pool tasks: " + fileQueueSize + " (completed: " + fileCompletedTaskSize + ")");
if (legacyDeletionCount > 0)
{
lines.add(" Legacy Deletion #: " + legacyDeletionCount);
}
if (migrationCount > 0)
{
lines.add(" Legacy Migration #: " + migrationCount);
}
lines.add(" Update thread pool tasks: " + updateQueueSize + " (completed: " + updateCompletedTaskSize + ")");
lines.add(" Level Unsaved #: " + this.clientLevel.getUnsavedDataSourceCount());
if (unsavedDataSourceCount != -1)
{
lines.add(" File Handler Unsaved #: " + unsavedDataSourceCount);
}
lines.add(" Parent Update #: " + this.fullDataSourceProvider.parentUpdatingPosSet.size());
}
return lines.toArray(new String[0]);
}
public void clearRenderCache()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
@@ -35,6 +35,8 @@ import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/** The level used when connected to a server */
@@ -122,6 +124,34 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
@Override
public int getMinY() { return this.levelWrapper.getMinHeight(); }
@Override
public void addDebugMenuStringsToList(List<String> messageList)
{
String dimName = this.levelWrapper.getDimensionType().getDimensionName();
boolean rendering = this.clientside.isRendering();
messageList.add("["+dimName+"] rendering: "+(rendering ? "yes" : "no"));
boolean migrationErrored = this.dataFileHandler.getMigrationStoppedWithError();
if (!migrationErrored)
{
long legacyDeletionCount = this.dataFileHandler.getLegacyDeletionCount();
if (legacyDeletionCount > 0)
{
messageList.add(" Migrating - Deleting #: " + legacyDeletionCount);
}
long migrationCount = this.dataFileHandler.getTotalMigrationCount();
if (migrationCount > 0)
{
messageList.add(" Migrating - Conversion #: " + migrationCount);
}
}
else
{
messageList.add(" Migration Failed");
}
}
@Override
public void close()
{
@@ -23,6 +23,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV2;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -38,6 +39,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp
import org.apache.logging.log4j.Logger;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/** The level used on a singleplayer world */
@@ -191,6 +194,51 @@ public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLev
//===========//
// debugging //
//===========//
@Override
public void addDebugMenuStringsToList(List<String> messageList)
{
// header
String dimName = this.serverLevelWrapper.getDimensionType().getDimensionName();
boolean rendering = this.clientside.isRendering();
messageList.add("["+dimName+"] rendering: "+(rendering ? "yes" : "no"));
// migration
boolean migrationErrored = this.serverside.fullDataFileHandler.getMigrationStoppedWithError();
if (!migrationErrored)
{
long legacyDeletionCount = this.serverside.fullDataFileHandler.getLegacyDeletionCount();
if (legacyDeletionCount > 0)
{
messageList.add(" Migrating - Deleting #: " + F3Screen.NUMBER_FORMAT.format(legacyDeletionCount));
}
long migrationCount = this.serverside.fullDataFileHandler.getTotalMigrationCount();
if (migrationCount > 0)
{
messageList.add(" Migrating - Conversion #: " + F3Screen.NUMBER_FORMAT.format(migrationCount));
}
}
else
{
messageList.add(" Migration Failed");
}
// world gen
WorldGenModule worldGenState = this.serverside.worldGenModule;
String worldGenDisplayString = worldGenState.getDebugMenuString();
if (worldGenDisplayString != null)
{
messageList.add(worldGenDisplayString);
}
}
//===============//
// data handling //
//===============//
@@ -28,6 +28,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel
@@ -115,4 +117,17 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel
//TODO: Send packet to client
}
//===========//
// debugging //
//===========//
@Override
public void addDebugMenuStringsToList(List<String> messageList)
{
String dimName = this.serverLevelWrapper.getDimensionType().getDimensionName();
messageList.add("["+dimName+"]");
}
}
@@ -22,7 +22,6 @@ package com.seibel.distanthorizons.core.level;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public interface IDhLevel extends AutoCloseable
@@ -57,4 +58,7 @@ public interface IDhLevel extends AutoCloseable
*/
int getUnsavedDataSourceCount();
void addDebugMenuStringsToList(List<String> messageList);
}
@@ -37,30 +37,16 @@ public class WorldGenModule implements Closeable
private final GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener;
private final AtomicReference<AbstractWorldGenState> worldGenStateRef = new AtomicReference<>();
private final F3Screen.DynamicMessage worldGenF3Message;
//=============//
// constructor //
//=============//
public WorldGenModule(GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener)
{
this.onWorldGenCompleteListener = onWorldGenCompleteListener;
this.worldGenF3Message = new F3Screen.DynamicMessage(() ->
{
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
if (worldGenState != null)
{
int waitingCount = worldGenState.worldGenerationQueue.getWaitingTaskCount();
int inProgressCount = worldGenState.worldGenerationQueue.getInProgressTaskCount();
int totalCountEstimate = worldGenState.worldGenerationQueue.getEstimatedTotalTaskCount();
return "World Gen Tasks: "+waitingCount+"/"+totalCountEstimate+", (in progress: "+inProgressCount+")";
}
else
{
return "World Gen Disabled";
}
});
}
@@ -114,6 +100,12 @@ public class WorldGenModule implements Closeable
}
}
//=======================//
// base method overrides //
//=======================//
@Override
public void close()
{
@@ -135,8 +127,6 @@ public class WorldGenModule implements Closeable
worldGenState.closeAsync(true).join(); //TODO: Make it async.
}
}
this.worldGenF3Message.close();
}
@@ -147,6 +137,22 @@ public class WorldGenModule implements Closeable
public boolean isWorldGenRunning() { return this.worldGenStateRef.get() != null; }
public String getDebugMenuString()
{
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
if (worldGenState == null)
{
return null;
}
String waitingCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getWaitingTaskCount());
String inProgressCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getInProgressTaskCount());
String totalCountEstimateStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getEstimatedTotalTaskCount());
return "World Gen Tasks: "+waitingCountStr+"/"+totalCountEstimateStr+" (in progress: "+inProgressCountStr+")";
}
//================//
@@ -19,159 +19,127 @@
package com.seibel.distanthorizons.core.logging.f3;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.render.RenderBufferHandler;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.world.AbstractDhWorld;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.io.Closeable;
import java.lang.ref.WeakReference;
import java.text.NumberFormat;
import java.util.*;
import java.util.function.Supplier;
import java.util.concurrent.ThreadPoolExecutor;
public class F3Screen
{
private static final Logger LOGGER = LogManager.getLogger();
private static final String[] DEFAULT_STRING = {
"", // blank line for spacing
ModInfo.READABLE_NAME + " version: " + ModInfo.VERSION
};
private static final List<Message> SELF_UPDATE_MESSAGE_LIST = Collections.synchronizedList(new LinkedList<>());
public static final NumberFormat NUMBER_FORMAT = NumberFormat.getIntegerInstance();
public static void addStringToDisplay(List<String> list)
//============//
// properties //
//============//
private static WeakReference<RenderBufferHandler> renderBufferHandlerRef = new WeakReference<>(null);
public static void setRenderBufferHandler(@Nullable RenderBufferHandler renderBufferHandler)
{
list.addAll(Arrays.asList(DEFAULT_STRING));
synchronized (SELF_UPDATE_MESSAGE_LIST)
if (renderBufferHandler != null && renderBufferHandlerRef.get() != null)
{
Iterator<Message> iterator = SELF_UPDATE_MESSAGE_LIST.iterator();
while (iterator.hasNext())
LOGGER.warn("multiple RenderBufferHandlers are active at once, the F3 menu may not be accurate.");
}
renderBufferHandlerRef = new WeakReference<>(renderBufferHandler);
}
//=================//
// injection point //
//=================//
/**
* F3 menu example: <br>
<code>
Distant Horizons v: 2.1.1-a-dev <br><br>
Queued chunk updates: 0 / 1000 <br>
World Gen Tasks: 40/5304, (in progress: 7) <br><br>
File thread pool tasks: 0 (complete: 759) <br>
Update thread pool tasks: 10 (complete: 24) <br>
Level Unsaved #: 0 <br>
File Handler Unsaved #: 0 <br>
Parent Update #: 12 <br><br>
Client_Server World with 3 levels <br>
[overworld] rendering: Active <br>
[the_end] rendering: Inactive <br>
[the_nether] rendering: Inactive <br><br>
VBO Render Count: 199/374 <br>
</code>
*/
public static void addStringToDisplay(List<String> messageList)
{
ThreadPoolExecutor worldGenPool = ThreadPoolUtil.getWorldGenExecutor();
ThreadPoolExecutor fileHandlerPool = ThreadPoolUtil.getFileHandlerExecutor();
ThreadPoolExecutor updatePool = ThreadPoolUtil.getUpdatePropagatorExecutor();
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
Iterable<? extends IDhLevel> levelIterator = world.getAllLoadedLevels();
messageList.add("");
messageList.add(ModInfo.READABLE_NAME+": "+ModInfo.VERSION);
messageList.add("");
// thread pools
messageList.add(getThreadPoolStatString("World Gen", worldGenPool));//"World Gen Tasks: 40/5304, (in progress: 7)");
messageList.add(getThreadPoolStatString("File Handler", fileHandlerPool));
messageList.add(getThreadPoolStatString("Update Propagator", updatePool));
messageList.add("");
// chunk updates
messageList.add(SharedApi.INSTANCE.getDebugMenuString());
messageList.add("");
// rendering
RenderBufferHandler renderBufferHandler = renderBufferHandlerRef.get();
if (renderBufferHandler != null)
{
messageList.add(renderBufferHandler.getVboRenderDebugMenuString());
String showPassString = renderBufferHandler.getShadowPassRenderDebugMenuString();
if (showPassString != null)
{
Message message = iterator.next();
if (message == null)
{
iterator.remove();
}
else
{
message.printTo(list);
}
messageList.add(showPassString);
}
messageList.add("");
}
// world / levels
messageList.add(world.GetDebugMenuString());
for (IDhLevel level : levelIterator)
{
level.addDebugMenuStringsToList(messageList);
}
}
//================//
// helper classes //
// helper methods //
//================//
// we are using Closeable instead of AutoCloseable because the close method should never throw exceptions
// and because this class shouldn't be used in a try {} block.
public static abstract class Message implements Closeable
private static String getThreadPoolStatString(String name, ThreadPoolExecutor pool)
{
protected Message()
{
SELF_UPDATE_MESSAGE_LIST.add(this);
}
public abstract void printTo(List<String> output);
@Override
public void close()
{
boolean removed = SELF_UPDATE_MESSAGE_LIST.remove(this);
}
String queueSize = (pool != null) ? NUMBER_FORMAT.format(pool.getQueue().size()) : "-";
String completedCount = (pool != null) ? NUMBER_FORMAT.format(pool.getCompletedTaskCount()) : "-";
return name+", tasks: "+queueSize+", complete: "+completedCount;
}
public static class StaticMessage extends Message
{
private final String[] lines;
public StaticMessage(String... lines) { this.lines = lines; }
@Override
public void printTo(List<String> output) { output.addAll(Arrays.asList(this.lines)); }
}
public static class DynamicMessage extends Message
{
private final Supplier<String> supplier;
public DynamicMessage(Supplier<String> message) { this.supplier = message; }
public void printTo(List<String> list)
{
try
{
String message = this.supplier.get();
if (message != null)
{
list.add(message);
}
}
catch (Exception e)
{
LOGGER.error("Unexpected Exception in F3 ["+DynamicMessage.class.getSimpleName()+"], error: "+e.getMessage(), e);
}
}
}
public static class MultiDynamicMessage extends Message
{
private final Supplier<String>[] supplierList;
@SafeVarargs
public MultiDynamicMessage(Supplier<String>... suppliers) { this.supplierList = suppliers; }
public void printTo(List<String> list)
{
for (Supplier<String> supplier : this.supplierList)
{
try
{
String message = supplier.get();
if (message != null)
{
list.add(message);
}
}
catch (Exception e)
{
LOGGER.error("Unexpected Exception in F3 ["+DynamicMessage.class.getSimpleName()+"], error: "+e.getMessage(), e);
}
}
}
}
public static class NestedMessage extends Message
{
private final Supplier<String[]> supplier;
public NestedMessage(Supplier<String[]> message)
{
this.supplier = message;
}
public void printTo(List<String> list)
{
try
{
String[] message = this.supplier.get();
if (message != null)
{
list.addAll(Arrays.asList(message));
}
}
catch (Exception e)
{
LOGGER.error("Unexpected Exception in F3 ["+DynamicMessage.class.getSimpleName()+"], error: "+e.getMessage(), e);
}
}
}
}
@@ -73,8 +73,6 @@ public class RenderBufferHandler implements AutoCloseable
private final AtomicBoolean rebuildAllBuffers = new AtomicBoolean(false);
public F3Screen.MultiDynamicMessage f3Message;
private int visibleBufferCount;
private int culledBufferCount;
private int shadowVisibleBufferCount;
@@ -104,31 +102,7 @@ public class RenderBufferHandler implements AutoCloseable
}
this.f3Message = new F3Screen.MultiDynamicMessage(
() ->
{
String countText = this.visibleBufferCount + "";
if (!Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get())
{
countText += "/" + (this.visibleBufferCount + this.culledBufferCount);
}
return LodUtil.formatLog("Rendered Buffer Count: " + countText);
},
() ->
{
boolean hasIrisShaders = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isShaderPackInUse());
if (!hasIrisShaders)
{
return null;
}
String countText = this.shadowVisibleBufferCount + "";
if (!Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get())
{
countText += "/" + (this.shadowVisibleBufferCount + this.shadowCulledBufferCount);
}
return LodUtil.formatLog("Shadow Buffer Count: " + countText);
});
F3Screen.setRenderBufferHandler(this);
}
@@ -396,6 +370,37 @@ public class RenderBufferHandler implements AutoCloseable
//=========//
// F3 menu //
//=========//
public String getVboRenderDebugMenuString()
{
String countText = F3Screen.NUMBER_FORMAT.format(this.visibleBufferCount);
if (!Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get())
{
countText += "/" + F3Screen.NUMBER_FORMAT.format(this.visibleBufferCount + this.culledBufferCount);
}
return LodUtil.formatLog("VBO Render Count: " + countText);
}
public String getShadowPassRenderDebugMenuString()
{
boolean hasIrisShaders = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isShaderPackInUse());
if (!hasIrisShaders)
{
return null;
}
String countText = F3Screen.NUMBER_FORMAT.format(this.shadowVisibleBufferCount);
if (!Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get())
{
countText += "/" + F3Screen.NUMBER_FORMAT.format(this.shadowVisibleBufferCount + this.shadowCulledBufferCount);
}
return LodUtil.formatLog("Shadow VBO Render Count: " + countText);
}
//=========//
// cleanup //
//=========//
@@ -413,7 +418,7 @@ public class RenderBufferHandler implements AutoCloseable
}
}
this.f3Message.close();
F3Screen.setRenderBufferHandler(null);
}
@@ -20,6 +20,7 @@
package com.seibel.distanthorizons.core.world;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import org.apache.logging.log4j.Logger;
import java.io.Closeable;
@@ -36,11 +37,22 @@ public abstract class AbstractDhWorld implements IDhWorld, Closeable
// constructor //
protected AbstractDhWorld(EWorldEnvironment environment) { this.environment = environment; }
// remove the "throws IOException"
// abstract methods //
// removes the "throws IOException"
@Override
public abstract void close();
// helper methods //
public String GetDebugMenuString() { return this.environment + " World with " + F3Screen.NUMBER_FORMAT.format(this.getLoadedLevelCount()) + " levels"; }
}
@@ -46,8 +46,6 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
public ExecutorService dhTickerThread = ThreadUtil.makeSingleThreadPool("Client Server World Ticker Thread", 2);
public EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick); //TODO: Rate-limit the loop
public F3Screen.DynamicMessage f3Message;
//=============//
@@ -57,10 +55,7 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
public DhClientServerWorld()
{
super(EWorldEnvironment.Client_Server);
LOGGER.info("Started DhWorld of type " + this.environment);
this.f3Message = new F3Screen.DynamicMessage(() -> LodUtil.formatLog(this.environment + " World with " + this.dhLevels.size() + " levels"));
}
@@ -113,6 +108,8 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
@Override
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.dhLevels; }
@Override
public int getLoadedLevelCount() { return this.dhLevels.size(); }
@Override
public void unloadLevel(@NotNull ILevelWrapper wrapper)
@@ -154,13 +151,16 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
public void doWorldGen() { this.dhLevels.forEach(DhClientServerLevel::doWorldGen); }
//================//
// base overrides //
//================//
/** synchronized to prevent a rare issue where the server tries closing the same world multiple times in rapid succession. */
@Override
public synchronized void close()
{
this.f3Message.close();
// clear dhLevels to prevent concurrent modification errors
HashSet<DhClientServerLevel> levelsToClose = new HashSet<>(this.dhLevels);
this.dhLevels.clear();
@@ -145,6 +145,8 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
@Override
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.levels.values(); }
@Override
public int getLoadedLevelCount() { return this.levels.size(); }
@Override
public void unloadLevel(@NotNull ILevelWrapper wrapper)
@@ -167,6 +167,8 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
@Override
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.levels.values(); }
@Override
public int getLoadedLevelCount() { return this.levels.size(); }
@Override
public void unloadLevel(@NotNull ILevelWrapper wrapper)
@@ -188,6 +190,12 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
public void doWorldGen() { this.levels.values().forEach(DhServerLevel::doWorldGen); }
//================//
// base overrides //
//================//
@Override
public void close()
{
@@ -31,6 +31,7 @@ public interface IDhWorld
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
IDhLevel getLevel(@NotNull ILevelWrapper wrapper);
Iterable<? extends IDhLevel> getAllLoadedLevels();
int getLoadedLevelCount();
void unloadLevel(@NotNull ILevelWrapper levelWrapper);