Improve F3 menu logic and visuals
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+78
-64
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+33
-28
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user