Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core
This commit is contained in:
@@ -1,13 +1,9 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnRenderLoader;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
|
||||
public class Initializer {
|
||||
public static void init() {
|
||||
ColumnRenderLoader columnRenderLoader = new ColumnRenderLoader();
|
||||
LodQuadTree.registerLayerLoader(columnRenderLoader, (byte) 7); // 7 or above
|
||||
|
||||
|
||||
ColumnRenderLoader unused = new ColumnRenderLoader(); // Auto register into the loader system
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,11 @@ public class EmptyRenderSource implements LodRenderSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DHChunkPos chunkPos, ChunkSizedData chunkData) {
|
||||
public void update(ChunkSizedData chunkData) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getRenderVersion() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,10 @@ import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderMetaFile;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
import com.seibel.lod.core.objects.DHChunkPos;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.render.LodSection;
|
||||
import com.seibel.lod.core.a7.render.LodRenderSection;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
@@ -256,7 +255,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
if (inBuildRenderBuffer == null) {
|
||||
ColumnRenderSource[] data = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length];
|
||||
for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) {
|
||||
LodSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels
|
||||
LodRenderSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels
|
||||
if (section.getRenderContainer() != null && section.getRenderContainer() instanceof ColumnRenderBuffer) {
|
||||
data[direction.ordinal()-2] = ((ColumnRenderSource) section.getRenderContainer());
|
||||
}
|
||||
|
||||
@@ -9,15 +9,18 @@ import com.seibel.lod.core.a7.render.RenderBufferHandler;
|
||||
import com.seibel.lod.core.a7.save.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.render.a7LodRenderer;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhClientLevel implements IClientLevel {
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
public final ClientOnlySaveStructure save;
|
||||
public final RemoteDataFileHandler dataFileHandler;
|
||||
@@ -29,18 +32,16 @@ public class DhClientLevel implements IClientLevel {
|
||||
|
||||
public DhClientLevel(ClientOnlySaveStructure save, ILevelWrapper level) {
|
||||
this.save = save;
|
||||
save.getDataFolder(level).mkdirs();
|
||||
save.getRenderCacheFolder(level).mkdirs();
|
||||
dataFileHandler = new RemoteDataFileHandler();
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, save.getRenderCacheFolder(level));
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level));
|
||||
tree = new LodQuadTree(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
|
||||
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler);
|
||||
renderBufferHandler = new RenderBufferHandler(tree);
|
||||
this.level = level;
|
||||
FileScanner.scanFile(save, level, dataFileHandler, renderFileHandler);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,6 +49,12 @@ public class DhClientLevel implements IClientLevel {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientTick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
|
||||
if (renderer == null) {
|
||||
@@ -74,5 +81,6 @@ public class DhClientLevel implements IClientLevel {
|
||||
@Override
|
||||
public void close() {
|
||||
renderFileHandler.close();
|
||||
LOGGER.info("Closed DHLevel for {}", level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,49 +9,62 @@ import com.seibel.lod.core.a7.render.RenderBufferHandler;
|
||||
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.render.a7LodRenderer;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhClientServerLevel implements IClientLevel, IServerLevel {
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
public final LocalSaveStructure save;
|
||||
public final LocalDataFileHandler dataFileHandler;
|
||||
public final RenderFileHandler renderFileHandler;
|
||||
public final RenderBufferHandler renderBufferHandler; //TODO: Should this be owned by renderer?
|
||||
public RenderFileHandler renderFileHandler = null;
|
||||
public RenderBufferHandler renderBufferHandler = null; //TODO: Should this be owned by renderer?
|
||||
public final ILevelWrapper level;
|
||||
public a7LodRenderer renderer = null;
|
||||
public LodQuadTree tree;
|
||||
public LodQuadTree tree = null;
|
||||
|
||||
public DhClientServerLevel(LocalSaveStructure save, ILevelWrapper level) {
|
||||
this.level = level;
|
||||
this.save = save;
|
||||
save.getDataFolder(level).mkdirs();
|
||||
save.getRenderCacheFolder(level).mkdirs();
|
||||
dataFileHandler = new LocalDataFileHandler(this, save.getDataFolder(level));
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, save.getRenderCacheFolder(level));
|
||||
tree = new LodQuadTree(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
|
||||
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler);
|
||||
renderBufferHandler = new RenderBufferHandler(tree);
|
||||
FileScanner.scanFile(save, level, dataFileHandler, renderFileHandler);
|
||||
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
|
||||
}
|
||||
|
||||
public void clientTick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
if (tree != null) tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
if (renderBufferHandler != null) renderBufferHandler.update();
|
||||
}
|
||||
|
||||
public void serverTick() {
|
||||
//TODO Update network packet and stuff or state or etc..
|
||||
}
|
||||
public void startRenderer() {
|
||||
//TODO
|
||||
if (renderBufferHandler != null) {
|
||||
LOGGER.warn("Tried to call startRenderer() on the clientServerLevel {} when renderer is already setup!", level);
|
||||
return;
|
||||
}
|
||||
renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level));
|
||||
tree = new LodQuadTree(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
|
||||
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler);
|
||||
renderBufferHandler = new RenderBufferHandler(tree);
|
||||
FileScanner.scanFile(save, level, dataFileHandler, renderFileHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
|
||||
if (renderBufferHandler == null) {
|
||||
LOGGER.error("Tried to call render() on the clientServerLevel {} when renderer has not been started!", level);
|
||||
return;
|
||||
}
|
||||
if (renderer == null) {
|
||||
renderer = new a7LodRenderer(this);
|
||||
}
|
||||
@@ -59,8 +72,16 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel {
|
||||
}
|
||||
|
||||
public void stopRenderer() {
|
||||
if (renderBufferHandler == null) {
|
||||
LOGGER.warn("Tried to call stopRenderer() on the clientServerLevel {} when renderer is already closed!", level);
|
||||
return;
|
||||
}
|
||||
renderBufferHandler.close();
|
||||
renderBufferHandler = null;
|
||||
tree = null; //TODO Close the tree
|
||||
renderFileHandler.flushAndSave(); //Ignore the completion feature so that this action is async
|
||||
//TODO
|
||||
renderFileHandler.close();
|
||||
renderFileHandler = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,14 +101,14 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> save() {
|
||||
return renderFileHandler.flushAndSave();
|
||||
return renderFileHandler == null ? dataFileHandler.flushAndSave() : renderFileHandler.flushAndSave();
|
||||
//Note: saving renderFileHandler will also save the dataFileHandler.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
renderFileHandler.close();
|
||||
//Note: Closing renderFileHandler will also close the dataFileHandler.
|
||||
dataFileHandler.close();
|
||||
LOGGER.info("Closed DHLevel for {}", level);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,11 +3,15 @@ package com.seibel.lod.core.a7.level;
|
||||
import com.seibel.lod.core.a7.util.FileScanner;
|
||||
import com.seibel.lod.core.a7.save.io.file.LocalDataFileHandler;
|
||||
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhServerLevel implements IServerLevel {
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
public final LocalSaveStructure save;
|
||||
public final LocalDataFileHandler dataFileHandler;
|
||||
public final ILevelWrapper level;
|
||||
@@ -15,8 +19,10 @@ public class DhServerLevel implements IServerLevel {
|
||||
public DhServerLevel(LocalSaveStructure save, ILevelWrapper level) {
|
||||
this.save = save;
|
||||
this.level = level;
|
||||
save.getDataFolder(level).mkdirs();
|
||||
dataFileHandler = new LocalDataFileHandler(this, save.getDataFolder(level));
|
||||
FileScanner.scanFile(save, level, dataFileHandler, null);
|
||||
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
|
||||
}
|
||||
|
||||
public void serverTick() {
|
||||
@@ -35,6 +41,7 @@ public class DhServerLevel implements IServerLevel {
|
||||
@Override
|
||||
public void close() {
|
||||
dataFileHandler.close();
|
||||
LOGGER.info("Closed DHLevel for {}", level);
|
||||
}
|
||||
@Override
|
||||
public CompletableFuture<Void> save() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider;
|
||||
@@ -10,8 +10,6 @@ import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.gridList.MovableGridRingList;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// QuadTree built from several layers of 2d ring buffers
|
||||
|
||||
/**
|
||||
@@ -29,71 +27,24 @@ public class LodQuadTree {
|
||||
* Note: all config value should be via the class that extends this class, and
|
||||
* by implementing different abstract methods
|
||||
*/
|
||||
|
||||
private static final byte LAYER_BEGINNING_OFFSET = ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
public final byte getLayerDataDetailOffset(byte sectionDetail) {
|
||||
return ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
}
|
||||
public final byte getLayerSectionDetailOffset(byte dataDetail) {
|
||||
return ColumnRenderSource.SECTION_SIZE_OFFSET;
|
||||
}
|
||||
public final byte getLayerDataDetail(byte sectionDetail) {
|
||||
return (byte) (sectionDetail - getLayerDataDetailOffset(sectionDetail));
|
||||
}
|
||||
public final byte getLayerSectionDetail(byte dataDetail) {
|
||||
return (byte) (dataDetail + getLayerSectionDetailOffset(dataDetail));
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger("LodQuadTree");
|
||||
|
||||
public final byte numbersOfSectionLevels;
|
||||
public final byte startingSectionLevel;
|
||||
private final MovableGridRingList<LodSection>[] ringLists;
|
||||
|
||||
static final ArrayList<RenderSourceLoader> layerLoaderConfig = new ArrayList<>();
|
||||
|
||||
static final Logger LOGGER = DhLoggerBuilder.getLogger("LodQuadTree");
|
||||
|
||||
public static void registerLayerLoader(RenderSourceLoader loader, byte sectionLevel) {
|
||||
LOGGER.info("Registering loader for section level " + sectionLevel + " for " + loader.getClass().getSimpleName());
|
||||
while (layerLoaderConfig.size() <= sectionLevel) {
|
||||
layerLoaderConfig.add(null);
|
||||
}
|
||||
if (layerLoaderConfig.set(sectionLevel, loader) != null) {
|
||||
throw new RuntimeException("Layer loader for level " + sectionLevel + " has a registry conflict!");
|
||||
}
|
||||
}
|
||||
|
||||
// static {
|
||||
// Collections.addAll(layerLoaderConfig,
|
||||
// null,
|
||||
// null, //1
|
||||
// null, //2
|
||||
// null, //3
|
||||
// new ContainerTypeConfigEntry(FullDatatype.class, (byte) 4), //4 -> 0
|
||||
// null, //5 force breaks down to 4 -> 0
|
||||
// null, //6 force breaks down to 4 -> 0
|
||||
// new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET), //7 -> 1
|
||||
// new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET) //8 -> 2
|
||||
// // ... And same onwards
|
||||
// );
|
||||
// }
|
||||
|
||||
static class SectionDetailLayer {
|
||||
final byte targetDataDetail;
|
||||
final RenderSourceLoader containerType;
|
||||
public SectionDetailLayer(byte targetDataDetail, RenderSourceLoader containerType) {
|
||||
this.targetDataDetail = targetDataDetail;
|
||||
this.containerType = containerType;
|
||||
}
|
||||
}
|
||||
|
||||
static void assertContainerTypeConfigCorrect() {
|
||||
boolean isInFront = true;
|
||||
for (int i = 0; i < layerLoaderConfig.size(); i++) {
|
||||
if (layerLoaderConfig.get(i) == null) continue;
|
||||
isInFront = false;
|
||||
RenderSourceLoader entry = layerLoaderConfig.get(i);
|
||||
if (i - entry.detailOffset < 0) {
|
||||
throw new RuntimeException("ContainerTypeConfigEntry " + i + " has a levelOffset of "
|
||||
+ entry.detailOffset + " which makes the dataDetail be " + (i - entry.detailOffset) + "," +
|
||||
" which is less than 0!");
|
||||
}
|
||||
if (entry.detailOffset < 0) {
|
||||
throw new RuntimeException("ContainerTypeConfigEntry " + i + " has a levelOffset of "
|
||||
+ entry.detailOffset + " which is less than 0!");
|
||||
}
|
||||
}
|
||||
if (layerLoaderConfig.get(layerLoaderConfig.size()-1) == null) {
|
||||
throw new RuntimeException("The last ContainerTypeConfigEntry is null, which is invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
final SectionDetailLayer[] sectionDetailLayers;
|
||||
private final MovableGridRingList<LodRenderSection>[] ringLists;
|
||||
public final int viewDistance;
|
||||
private final IRenderSourceProvider renderSourceProvider;
|
||||
|
||||
@@ -105,63 +56,21 @@ public class LodQuadTree {
|
||||
*/
|
||||
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ, IRenderSourceProvider provider) {
|
||||
renderSourceProvider = provider;
|
||||
|
||||
assertContainerTypeConfigCorrect();
|
||||
this.viewDistance = viewDistance;
|
||||
|
||||
//FIXME: Rework this mess of code!
|
||||
{ // Calculate the max section detail
|
||||
byte maxDetailLevel = getMaxDetailInRange(viewDistance * Math.sqrt(2));
|
||||
RenderSourceLoader finalEntry = null;
|
||||
byte topSectionLevel = 0;
|
||||
byte firstLevel = -1;
|
||||
for (; topSectionLevel < layerLoaderConfig.size(); topSectionLevel++) {
|
||||
if (layerLoaderConfig.get(topSectionLevel) == null) continue;
|
||||
finalEntry = layerLoaderConfig.get(topSectionLevel);
|
||||
if (firstLevel == -1) firstLevel = topSectionLevel;
|
||||
if (topSectionLevel - finalEntry.detailOffset >= maxDetailLevel) break;
|
||||
}
|
||||
if (finalEntry == null) throw new RuntimeException("No container type found!");
|
||||
if (topSectionLevel == layerLoaderConfig.size())
|
||||
topSectionLevel = (byte) (maxDetailLevel + finalEntry.detailOffset);
|
||||
byte maxDataDetailLevel = getMaxDetailInRange(viewDistance * Math.sqrt(2));
|
||||
byte topSectionLevel = getLayerSectionDetail(maxDataDetailLevel);
|
||||
numbersOfSectionLevels = (byte) (topSectionLevel + 1);
|
||||
startingSectionLevel = firstLevel;
|
||||
LOGGER.info("MaxLevel: " + maxDetailLevel + ", StartingLevel: " + startingSectionLevel + ", NumberOfLevels: " + numbersOfSectionLevels
|
||||
+ ", TopSectionLevel: " + topSectionLevel + ", FinalEntry: " + finalEntry);
|
||||
sectionDetailLayers = new SectionDetailLayer[numbersOfSectionLevels - startingSectionLevel];
|
||||
ringLists = new MovableGridRingList[numbersOfSectionLevels - startingSectionLevel];
|
||||
ringLists = new MovableGridRingList[numbersOfSectionLevels - LAYER_BEGINNING_OFFSET];
|
||||
}
|
||||
|
||||
{ // Fill in the sectionDetailLayers info and construct the ringLists
|
||||
byte lastNonNullEntry = -1;
|
||||
for (byte i = startingSectionLevel; i < numbersOfSectionLevels; i++) {
|
||||
byte targetDataDetail;
|
||||
RenderSourceLoader containerType;
|
||||
|
||||
if (i < layerLoaderConfig.size()) {
|
||||
if (layerLoaderConfig.get(i) == null) {
|
||||
if (lastNonNullEntry == -1) continue;
|
||||
targetDataDetail = sectionDetailLayers[lastNonNullEntry].targetDataDetail;
|
||||
containerType = null;
|
||||
} else {
|
||||
lastNonNullEntry = i;
|
||||
RenderSourceLoader entry = layerLoaderConfig.get(i);
|
||||
targetDataDetail = (byte) (i - entry.detailOffset);
|
||||
containerType = entry;
|
||||
}
|
||||
} else {
|
||||
LodUtil.assertTrue(layerLoaderConfig.get(layerLoaderConfig.size() - 1) != null,
|
||||
"The last entry must not be null!");
|
||||
RenderSourceLoader entry = layerLoaderConfig.get(layerLoaderConfig.size() - 1);
|
||||
targetDataDetail = (byte) (i - entry.detailOffset);
|
||||
containerType = entry;
|
||||
}
|
||||
|
||||
LodUtil.assertTrue(targetDataDetail >= 0, "dataDetail must be >= 0!");
|
||||
{ // Construct the ringLists
|
||||
for (byte i = LAYER_BEGINNING_OFFSET; i < numbersOfSectionLevels; i++) {
|
||||
byte targetDataDetail = getLayerDataDetail(i);
|
||||
int maxDist = getFurthestDistance(targetDataDetail);
|
||||
int halfSize = LodUtil.ceilDiv(maxDist, (1 << i) + 2);
|
||||
sectionDetailLayers[i - startingSectionLevel] = new SectionDetailLayer(targetDataDetail, containerType);
|
||||
ringLists[i - startingSectionLevel] = new MovableGridRingList<LodSection>(halfSize,
|
||||
ringLists[i - LAYER_BEGINNING_OFFSET] = new MovableGridRingList<>(halfSize,
|
||||
initialPlayerX >> i, initialPlayerZ >> i);
|
||||
}
|
||||
}
|
||||
@@ -173,29 +82,18 @@ public class LodQuadTree {
|
||||
* @param pos the section positon.
|
||||
* @return the LodSection
|
||||
*/
|
||||
public LodSection getSection(DhSectionPos pos) {
|
||||
public LodRenderSection getSection(DhSectionPos pos) {
|
||||
return getSection(pos.sectionDetail, pos.sectionX, pos.sectionZ);
|
||||
}
|
||||
|
||||
public byte getFirstSectionDetailFromDataDetail(byte dataDetail) {
|
||||
if (dataDetail <= startingSectionLevel) return startingSectionLevel;
|
||||
for (byte i = 0; i < sectionDetailLayers.length; i++) {
|
||||
if (sectionDetailLayers[i].targetDataDetail >= dataDetail) return (byte) (i + startingSectionLevel);
|
||||
}
|
||||
throw new RuntimeException("No section detail for dataDetail " + dataDetail+ " found!");
|
||||
}
|
||||
public byte getDataDetail(byte sectionDetail) {
|
||||
return sectionDetailLayers[sectionDetail - startingSectionLevel].targetDataDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the RingList of a given detail level
|
||||
* @apiNote The returned ringList should not be modified!
|
||||
* @param detailLevel the detail level
|
||||
* @return the RingList
|
||||
*/
|
||||
public MovableGridRingList<LodSection> getRingList(byte detailLevel) {
|
||||
return ringLists[detailLevel - startingSectionLevel];
|
||||
public MovableGridRingList<LodRenderSection> getRingList(byte detailLevel) {
|
||||
return ringLists[detailLevel - LAYER_BEGINNING_OFFSET];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,7 +105,7 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
public byte getStartingSectionLevel() {
|
||||
return startingSectionLevel;
|
||||
return LAYER_BEGINNING_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,8 +115,8 @@ public class LodQuadTree {
|
||||
* @param z z coordinate of the section
|
||||
* @return the LodSection
|
||||
*/
|
||||
public LodSection getSection(byte detailLevel, int x, int z) {
|
||||
return ringLists[detailLevel - startingSectionLevel].get(x, z);
|
||||
public LodRenderSection getSection(byte detailLevel, int x, int z) {
|
||||
return ringLists[detailLevel - LAYER_BEGINNING_OFFSET].get(x, z);
|
||||
}
|
||||
|
||||
|
||||
@@ -263,7 +161,7 @@ public class LodQuadTree {
|
||||
* @param pos the section positon
|
||||
* @return the parent LodSection
|
||||
*/
|
||||
public LodSection getParentSection(DhSectionPos pos) {
|
||||
public LodRenderSection getParentSection(DhSectionPos pos) {
|
||||
return getSection(pos.getParent());
|
||||
}
|
||||
|
||||
@@ -274,7 +172,7 @@ public class LodQuadTree {
|
||||
* @param child0to3 since there are 4 possible children this index identify which one we are getting
|
||||
* @return one of the child LodSection
|
||||
*/
|
||||
public LodSection getChildSection(DhSectionPos pos, int child0to3) {
|
||||
public LodRenderSection getChildSection(DhSectionPos pos, int child0to3) {
|
||||
return getSection(pos.getChild(child0to3));
|
||||
}
|
||||
|
||||
@@ -283,10 +181,10 @@ public class LodQuadTree {
|
||||
* @param playerPos the reference position for the player
|
||||
*/
|
||||
public void tick(DhBlockPos2D playerPos) {
|
||||
for (int sectLevel = startingSectionLevel; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
ringLists[sectLevel - startingSectionLevel]
|
||||
for (int sectLevel = LAYER_BEGINNING_OFFSET; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
ringLists[sectLevel - LAYER_BEGINNING_OFFSET]
|
||||
.move(playerPos.x >> sectLevel, playerPos.z >> sectLevel,
|
||||
LodSection::dispose);
|
||||
LodRenderSection::dispose);
|
||||
}
|
||||
|
||||
// First tick pass: update all sections' childCount from bottom level to top level. Step:
|
||||
@@ -318,14 +216,13 @@ public class LodQuadTree {
|
||||
// - If targetLevel < dataLevel@(sectLevel+1) && section == null: (use the next level's dataLevel)
|
||||
// - create new section with childCount = 0
|
||||
// - Parent's childCount++ (Create parent if needed)
|
||||
for (byte sectLevel = startingSectionLevel; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[sectLevel - startingSectionLevel];
|
||||
final MovableGridRingList<LodSection> childRingList =
|
||||
sectLevel == startingSectionLevel ? null : ringLists[sectLevel - startingSectionLevel - 1];
|
||||
final MovableGridRingList<LodSection> parentRingList =
|
||||
sectLevel == numbersOfSectionLevels - 1 ? null : ringLists[sectLevel - startingSectionLevel + 1];
|
||||
for (byte sectLevel = LAYER_BEGINNING_OFFSET; sectLevel < numbersOfSectionLevels; sectLevel++) {
|
||||
final MovableGridRingList<LodRenderSection> ringList = ringLists[sectLevel - LAYER_BEGINNING_OFFSET];
|
||||
final MovableGridRingList<LodRenderSection> childRingList =
|
||||
sectLevel == LAYER_BEGINNING_OFFSET ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET - 1];
|
||||
final MovableGridRingList<LodRenderSection> parentRingList =
|
||||
sectLevel == numbersOfSectionLevels - 1 ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET + 1];
|
||||
final byte f_sectLevel = sectLevel;
|
||||
RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (f_sectLevel == 0 && section != null) {
|
||||
section.childCount = 0;
|
||||
@@ -333,19 +230,19 @@ public class LodQuadTree {
|
||||
if (section != null && section.childCount != 0) {
|
||||
// Section will be in the unloaded state.
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodSection(section.pos.getParent()));
|
||||
new LodRenderSection(section.pos.getParent()));
|
||||
parent.childCount++;
|
||||
}
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
DhSectionPos childPos = section.pos.getChild(i);
|
||||
LodSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
if (child == null) {
|
||||
child = childRingList.setChained(childPos.sectionX, childPos.sectionZ,
|
||||
new LodSection(childPos));
|
||||
new LodRenderSection(childPos));
|
||||
child.childCount = 0;
|
||||
} else if (child.childCount == -1) {
|
||||
child.childCount = 0;
|
||||
@@ -357,31 +254,31 @@ public class LodQuadTree {
|
||||
byte targetLevel = calculateExpectedDetailLevel(playerPos, sectPos);
|
||||
if (f_sectLevel == numbersOfSectionLevels -1) {
|
||||
// Section is in the top level.
|
||||
if (targetLevel > getDataDetail(f_sectLevel) && section != null) {
|
||||
if (targetLevel > getLayerDataDetail(f_sectLevel) && section != null) {
|
||||
section.childCount = -1;
|
||||
}
|
||||
if (targetLevel <= getDataDetail(f_sectLevel) && section == null) {
|
||||
if (targetLevel <= getLayerDataDetail(f_sectLevel) && section == null) {
|
||||
section = ringList.setChained(pos.x, pos.y,
|
||||
new LodSection(sectPos));
|
||||
new LodRenderSection(sectPos));
|
||||
}
|
||||
} else {
|
||||
// Section is not the top level. So we also need to consider the parent.
|
||||
if (targetLevel >= getDataDetail((byte) (f_sectLevel+1)) && section != null) {
|
||||
if (targetLevel >= getLayerDataDetail((byte) (f_sectLevel+1)) && section != null) {
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodUtil.assertTrue(parent != null);
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
parent.childCount--;
|
||||
section.childCount = -1;
|
||||
}
|
||||
if (targetLevel < getDataDetail((byte) (f_sectLevel+1)) && section == null) {
|
||||
if (targetLevel < getLayerDataDetail((byte) (f_sectLevel+1)) && section == null) {
|
||||
section = ringList.setChained(pos.x, pos.y,
|
||||
new LodSection(sectPos));
|
||||
new LodRenderSection(sectPos));
|
||||
LodUtil.assertTrue(parentRingList != null);
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodSection(sectPos.getParent()));
|
||||
new LodRenderSection(sectPos.getParent()));
|
||||
}
|
||||
parent.childCount++;
|
||||
}
|
||||
@@ -397,7 +294,7 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
// Second tick pass:
|
||||
// Cascade the layers that is in Always Cascade Mode from top to bottom. (layer's containerType == null)
|
||||
// Cascade the layers that is in Always Cascade Mode from top to bottom. (Not yet exposed or used)
|
||||
// At the same time, load and unload sections (and can also be used to assert everything is working). Step:
|
||||
// ===Assertion steps===
|
||||
// assert childCount == 4 || childCount == 0 || childCount == -1
|
||||
@@ -412,26 +309,24 @@ public class LodQuadTree {
|
||||
// if childCount == -1: // (section can be loaded or unloaded, due to fast movement)
|
||||
// - set this section to null (TODO: Is this needed to be first or last or don't matter for concurrency?)
|
||||
// - If loaded unload section
|
||||
for (byte sectLevel = (byte) (numbersOfSectionLevels - 1); sectLevel >= startingSectionLevel; sectLevel--) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[sectLevel - startingSectionLevel];
|
||||
final MovableGridRingList<LodSection> childRingList =
|
||||
sectLevel == startingSectionLevel ? null : ringLists[sectLevel - startingSectionLevel - 1];
|
||||
final boolean doCacsade = sectionDetailLayers[sectLevel - startingSectionLevel].containerType == null;
|
||||
RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
|
||||
for (byte sectLevel = (byte) (numbersOfSectionLevels - 1); sectLevel >= LAYER_BEGINNING_OFFSET; sectLevel--) {
|
||||
final MovableGridRingList<LodRenderSection> ringList = ringLists[sectLevel - LAYER_BEGINNING_OFFSET];
|
||||
final MovableGridRingList<LodRenderSection> childRingList =
|
||||
sectLevel == LAYER_BEGINNING_OFFSET ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET - 1];
|
||||
final boolean doCascade = false; // TODO: Utilize this cascade mode or at least expose this option
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (section == null) return;
|
||||
|
||||
// Cascade layers
|
||||
if (doCacsade && section.childCount == 0) {
|
||||
if (doCascade && section.childCount == 0) {
|
||||
LodUtil.assertTrue(childRingList != null);
|
||||
// Create childs to cascade the layer.
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
DhSectionPos childPos = section.pos.getChild(i);
|
||||
LodSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
|
||||
if (child == null) {
|
||||
child = childRingList.setChained(childPos.sectionX, childPos.sectionZ,
|
||||
new LodSection(childPos));
|
||||
new LodRenderSection(childPos));
|
||||
child.childCount = 0;
|
||||
} else {
|
||||
LodUtil.assertTrue(child.childCount == -1,
|
||||
@@ -463,7 +358,7 @@ public class LodQuadTree {
|
||||
section.dispose();
|
||||
} else {
|
||||
if (!section.isLoaded() && !section.isLoading()) {
|
||||
section.load(renderSourceProvider, containerType);
|
||||
section.load(renderSourceProvider);
|
||||
}
|
||||
if (section.childCount == 4) section.enableRender(this);
|
||||
if (section.childCount == 0) section.disableRender();
|
||||
|
||||
+3
-6
@@ -1,15 +1,12 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class LodSection {
|
||||
public static final int SUB_REGION_DATA_WIDTH = 16*16;
|
||||
|
||||
public class LodRenderSection {
|
||||
public final DhSectionPos pos;
|
||||
|
||||
/* Following used for LodQuadTree tick() method, and ONLY for that method! */
|
||||
@@ -23,7 +20,7 @@ public class LodSection {
|
||||
private boolean isRenderEnabled = false;
|
||||
|
||||
// Create sub region
|
||||
public LodSection(DhSectionPos pos) {
|
||||
public LodRenderSection(DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
@@ -42,7 +39,7 @@ public class LodSection {
|
||||
isRenderEnabled = false;
|
||||
}
|
||||
|
||||
public void load(IRenderSourceProvider renderDataProvider, RenderSourceLoader renderDataSourceClass) {
|
||||
public void load(IRenderSourceProvider renderDataProvider) {
|
||||
if (loadFuture != null || lodRenderSource != null) throw new IllegalStateException("Reloading is not supported!");
|
||||
loadFuture = renderDataProvider.read(pos);
|
||||
}
|
||||
@@ -40,25 +40,28 @@ public class RenderBufferHandler {
|
||||
// the buffer is only unloaded if all children's buffers are ready. This will make the
|
||||
// transition between buffers no longer causing any flicker.
|
||||
public void update() {
|
||||
LodSection section = target.getSection(pos);
|
||||
LodRenderSection section = target.getSection(pos);
|
||||
// If this fails, there may be concurrent modification of the quad tree
|
||||
// (as this update() should be called from the same thread that calls update() on the quad tree)
|
||||
LodUtil.assertTrue(section != null);
|
||||
LodRenderSource container = section.getRenderContainer();
|
||||
|
||||
// Update self's render buffer state
|
||||
boolean shouldRender = section.isLoaded();
|
||||
boolean shouldRender = section.canRender();
|
||||
if (!shouldRender) {
|
||||
RenderBuffer buff = renderBufferSlot.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
//TODO: Does this really need to force the old buffer to not be rendered?
|
||||
// RenderBuffer buff = renderBufferSlot.getAndSet(null);
|
||||
// if (buff != null) {
|
||||
// buff.close();
|
||||
// }
|
||||
} else {
|
||||
LodUtil.assertTrue(container != null); // section.isLoaded() should have ensured this
|
||||
container.trySwapRenderBuffer(target, renderBufferSlot);
|
||||
}
|
||||
|
||||
// Update children's render buffer state
|
||||
// TODO: Improve this! (Checking section.isLoaded() as if its not loaded, it can only be because
|
||||
// it has children. (But this logic is... really hard to read!)
|
||||
boolean shouldHaveChildren = !section.isLoaded();
|
||||
if (shouldHaveChildren) {
|
||||
if (children == null) {
|
||||
@@ -73,6 +76,9 @@ public class RenderBufferHandler {
|
||||
}
|
||||
} else {
|
||||
if (children != null) {
|
||||
//FIXME: Concurrency issue here: If render thread is concurrently using the child's buffer,
|
||||
// and this thread got priority to close the buffer, it causes a bug wher the render thread
|
||||
// will be using a closed buffer!!!!
|
||||
RenderBufferNode[] childs = children;
|
||||
children = null;
|
||||
for (RenderBufferNode child : childs) {
|
||||
@@ -98,7 +104,7 @@ public class RenderBufferHandler {
|
||||
|
||||
public RenderBufferHandler(LodQuadTree target) {
|
||||
this.target = target;
|
||||
MovableGridRingList<LodSection> referenceList = target.getRingList((byte) (target.getNumbersOfSectionLevels() - 1));
|
||||
MovableGridRingList<LodRenderSection> referenceList = target.getRingList((byte) (target.getNumbersOfSectionLevels() - 1));
|
||||
Pos2D center = referenceList.getCenter();
|
||||
renderBufferNodes = new MovableGridRingList<>(referenceList.getHalfSize(), center);
|
||||
}
|
||||
@@ -113,12 +119,12 @@ public class RenderBufferHandler {
|
||||
|
||||
public void update() {
|
||||
byte topDetail = (byte) (target.getNumbersOfSectionLevels() - 1);
|
||||
MovableGridRingList<LodSection> referenceList = target.getRingList(topDetail);
|
||||
MovableGridRingList<LodRenderSection> referenceList = target.getRingList(topDetail);
|
||||
Pos2D center = referenceList.getCenter();
|
||||
renderBufferNodes.move(center.x, center.y, RenderBufferNode::close); // Note: may lock the list
|
||||
renderBufferNodes.forEachPosOrdered((node, pos) -> {
|
||||
DhSectionPos sectPos = new DhSectionPos(topDetail, pos.x, pos.y);
|
||||
LodSection section = target.getSection(sectPos);
|
||||
LodRenderSection section = target.getSection(sectPos);
|
||||
|
||||
if (section == null) {
|
||||
// If section is null, but node exists, remove node
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.seibel.lod.core.a7.save.io.render;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.a7.datatype.EmptyRenderSource;
|
||||
import com.seibel.lod.core.a7.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
@@ -111,7 +112,15 @@ public class RenderFileHandler implements IRenderSourceProvider {
|
||||
dataSourceProvider::isCacheValid,
|
||||
dataSourceProvider::read,
|
||||
level, computeDefaultFilePath(p), p));
|
||||
return metaFile.loadOrGetCached(renderCacheThread);
|
||||
return metaFile.loadOrGetCached(renderCacheThread).handle(
|
||||
(render, e) -> {
|
||||
if (e != null) {
|
||||
LOGGER.error("Uncaught error on {}:", pos, e);
|
||||
}
|
||||
if (render != null) return render;
|
||||
return EmptyRenderSource.INSTANCE;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -11,22 +11,27 @@ import java.io.File;
|
||||
public class LocalSaveStructure extends SaveStructure {
|
||||
private static final IMinecraftSharedWrapper MC = SingletonHandler.get(IMinecraftSharedWrapper.class);
|
||||
|
||||
private File debugPath = new File("");
|
||||
|
||||
// Fit for Client_Server & Server_Only environment
|
||||
public LocalSaveStructure() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File tryGetLevelFolder(ILevelWrapper wrapper) {
|
||||
debugPath = new File(wrapper.getSaveFolder(), "Distant_Horizons");
|
||||
return new File(wrapper.getSaveFolder(), "Distant_Horizons");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getRenderCacheFolder(ILevelWrapper level) {
|
||||
debugPath = new File(level.getSaveFolder(), "Distant_Horizons");
|
||||
return new File(new File(level.getSaveFolder(), "Distant_Horizons"), RENDER_CACHE_FOLDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder(ILevelWrapper level) {
|
||||
debugPath = new File(level.getSaveFolder(), "Distant_Horizons");
|
||||
return new File(new File(level.getSaveFolder(), "Distant_Horizons"), DATA_FOLDER);
|
||||
}
|
||||
|
||||
@@ -37,6 +42,6 @@ public class LocalSaveStructure extends SaveStructure {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[LocalSave]";
|
||||
return "[LocalSave at ["+debugPath+"] ]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class FileScanner {
|
||||
).map(Path::toFile).collect(Collectors.toList())
|
||||
);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to scan and collect data files for {} in {}", level, save);
|
||||
LOGGER.error("Failed to scan and collect data files for {} in {}", level, save, e);
|
||||
}
|
||||
}
|
||||
if (renderSource != null) {
|
||||
@@ -38,7 +38,7 @@ public class FileScanner {
|
||||
).map(Path::toFile).collect(Collectors.toList())
|
||||
);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to scan and collect data files for {} in {}", level, save);
|
||||
LOGGER.error("Failed to scan and collect data files for {} in {}", level, save, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
super(WorldEnvironment.Client_Server);
|
||||
saveStructure = new LocalSaveStructure();
|
||||
levels = new HashMap<>();
|
||||
LOGGER.info("Started DhWorld of type {}", environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,6 +87,7 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
level.close();
|
||||
}
|
||||
levels.clear();
|
||||
LOGGER.info("Closed DhWorld of type {}", environment);
|
||||
}
|
||||
|
||||
public void enableRendering(ILevelWrapper wrapper) {
|
||||
|
||||
@@ -25,6 +25,7 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
super(WorldEnvironment.Client_Only);
|
||||
saveStructure = new ClientOnlySaveStructure();
|
||||
levels = new HashMap<>();
|
||||
LOGGER.info("Started DhWorld of type {}", environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,5 +82,6 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
level.close();
|
||||
}
|
||||
levels.clear();
|
||||
LOGGER.info("Closed DhWorld of type {}", environment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
super(WorldEnvironment.Server_Only);
|
||||
saveStructure = new LocalSaveStructure();
|
||||
levels = new HashMap<>();
|
||||
LOGGER.info("Started DhWorld of type {}", environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,6 +64,7 @@ public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
level.close();
|
||||
}
|
||||
levels.clear();
|
||||
LOGGER.info("Closed DhWorld of type {}", environment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ package com.seibel.lod.core.api.internal;
|
||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
||||
import com.seibel.lod.core.builders.worldGeneration.BatchGenerator;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.enums.EWorldType;
|
||||
import com.seibel.lod.core.enums.ELevelType;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.objects.DHChunkPos;
|
||||
@@ -129,14 +129,14 @@ public class EventApi
|
||||
if (ENABLE_STACK_DUMP_LOGGING)
|
||||
LOGGER.info(
|
||||
"WorldLoadEvent called here for "
|
||||
+ (world.getWorldType() == EWorldType.ClientWorld ? "clientLevel" : "serverLevel"),
|
||||
+ (world.getLevelType() == ELevelType.ClientLevel ? "clientLevel" : "serverLevel"),
|
||||
new RuntimeException());
|
||||
// Always ignore ServerWorld event
|
||||
if (world.getWorldType() == EWorldType.ServerWorld)
|
||||
if (world.getLevelType() == ELevelType.ServerLevel)
|
||||
return;
|
||||
isCurrentlyOnSinglePlayerServer = MC.hasSinglePlayerServer();
|
||||
if (!InternalApiShared.isShuttingDown) LOGGER.warn("WorldLoadEvent called on {} while another world is loaded!",
|
||||
(world.getWorldType() == EWorldType.ClientWorld ? "clientLevel" : "serverLevel"));
|
||||
(world.getLevelType() == ELevelType.ClientLevel ? "clientLevel" : "serverLevel"));
|
||||
InternalApiShared.isShuttingDown = false;
|
||||
//DataPointUtil.WORLD_HEIGHT = world.getHeight();
|
||||
LodBuilder.MIN_WORLD_HEIGHT = world.getMinHeight(); // This updates the World height
|
||||
@@ -162,13 +162,13 @@ public class EventApi
|
||||
if (ENABLE_STACK_DUMP_LOGGING)
|
||||
LOGGER.info(
|
||||
"WorldUnloadEvent called here for "
|
||||
+ (world.getWorldType() == EWorldType.ClientWorld ? "clientLevel" : "serverLevel"),
|
||||
+ (world.getLevelType() == ELevelType.ClientLevel ? "clientLevel" : "serverLevel"),
|
||||
new RuntimeException());
|
||||
|
||||
// If it's single player, ignore the client side world unload event
|
||||
// Note: using isCurrentlyOnSinglePlayerServer as often API call unload event
|
||||
// AFTER setting MC to not be in a singlePlayerServer
|
||||
if (isCurrentlyOnSinglePlayerServer && world.getWorldType() == EWorldType.ClientWorld)
|
||||
if (isCurrentlyOnSinglePlayerServer && world.getLevelType() == ELevelType.ClientLevel)
|
||||
return;
|
||||
|
||||
// if this isn't done unfinished tasks may be left in the queue
|
||||
|
||||
@@ -179,18 +179,20 @@ public class ClientApi
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
public void renderLods(ILevelWrapper world, Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks)
|
||||
public void renderLods(ILevelWrapper levelWrapper, Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks)
|
||||
{
|
||||
IProfilerWrapper profiler = MC.getProfiler();
|
||||
profiler.pop(); // get out of "terrain"
|
||||
profiler.push("DH-RenderLevel");
|
||||
try {
|
||||
if (!MC.playerExists()) return;
|
||||
if (world == null) return;
|
||||
DhWorld DhWorld = SharedApi.currentWorld;
|
||||
if (DhWorld == null) return;
|
||||
if (levelWrapper == null) return;
|
||||
DhWorld dhWorld = SharedApi.currentWorld;
|
||||
if (dhWorld == null) return;
|
||||
if (!(SharedApi.currentWorld instanceof IClientWorld)) return;
|
||||
IClientLevel level = (IClientLevel)SharedApi.currentWorld;
|
||||
//FIXME: Improve class hierarchy of DhWorld, IClientWorld, IServerWorld to fix all this hard casting
|
||||
IClientLevel level = (IClientLevel) dhWorld.getOrLoadLevel(levelWrapper);
|
||||
if (level == null) return; //Level is not ready yet.
|
||||
|
||||
if (prefLoggerEnabled) {
|
||||
level.dumpRamUsage();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.seibel.lod.core.api.internal.a7;
|
||||
|
||||
import com.seibel.lod.core.a7.Initializer;
|
||||
import com.seibel.lod.core.a7.world.WorldEnvironment;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.a7.world.DhWorld;
|
||||
@@ -7,10 +8,14 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class SharedApi {
|
||||
public static DhWorld currentWorld;
|
||||
public static final Logger LOGGER = DhLoggerBuilder.getLogger("DH Events");
|
||||
public static IMinecraftSharedWrapper MC;
|
||||
public static Logger LOGGER = DhLoggerBuilder.getLogger("DH Events");
|
||||
public static DhWorld currentWorld;
|
||||
public static WorldEnvironment getEnvironment() {
|
||||
return currentWorld==null ? null : currentWorld.environment;
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
Initializer.init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.seibel.lod.core.config.types.AbstractConfigType;
|
||||
import com.seibel.lod.core.config.types.ConfigEntry;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
@@ -23,7 +24,7 @@ import java.nio.file.Path;
|
||||
* @version 2022-5-26
|
||||
*/
|
||||
public class ConfigFileHandling {
|
||||
public static final Path ConfigPath = SingletonHandler.get(IMinecraftClientWrapper.class).getGameDirectory().toPath().resolve("config").resolve(ModInfo.NAME+".toml");
|
||||
public static final Path ConfigPath = SingletonHandler.get(IMinecraftSharedWrapper.class).getInstallationDirectory().toPath().resolve("config").resolve(ModInfo.NAME+".toml");
|
||||
|
||||
/** Saves the config to the file */
|
||||
public static void saveToFile() {
|
||||
|
||||
+3
-3
@@ -25,9 +25,9 @@ package com.seibel.lod.core.enums;
|
||||
* @author James Seibel
|
||||
* @version 11-12-2021
|
||||
*/
|
||||
public enum EWorldType
|
||||
public enum ELevelType
|
||||
{
|
||||
ServerWorld,
|
||||
ClientWorld,
|
||||
ServerLevel,
|
||||
ClientLevel,
|
||||
Unknown
|
||||
}
|
||||
@@ -70,7 +70,7 @@ public class LodDimensionFinder
|
||||
public static final String THREAD_NAME = "Sub-Dimension-Finder";
|
||||
public static final String DEFAULT_SAVE_DIMENSION_FOLDER = "_Default-Sub-Dimension";
|
||||
|
||||
private PlayerData playerData = new PlayerData(MC);
|
||||
private PlayerData playerData = null;//new PlayerData(MC);
|
||||
private PlayerData firstSeenPlayerData = null;
|
||||
|
||||
private volatile LodDimension foundLodDimension = null;
|
||||
@@ -218,7 +218,7 @@ public class LodDimensionFinder
|
||||
if (firstSeenPlayerData == null)
|
||||
{
|
||||
firstSeenPlayerData = playerData;
|
||||
playerData = new PlayerData(MC);
|
||||
playerData = null;//new PlayerData(MC);
|
||||
}
|
||||
|
||||
// relevant positions
|
||||
@@ -571,7 +571,7 @@ public class LodDimensionFinder
|
||||
|
||||
// determine the playerData
|
||||
IMinecraftClientWrapper mc = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
PlayerData playerdata = new PlayerData(mc);
|
||||
PlayerData playerdata = null;//new PlayerData(mc);
|
||||
|
||||
// write the data to file
|
||||
CommentedFileConfig toml = CommentedFileConfig.builder(file).build();
|
||||
|
||||
+5
-2
@@ -70,8 +70,11 @@ public class SingletonHandler
|
||||
|
||||
return foundObject;
|
||||
}
|
||||
|
||||
|
||||
public static <T> T getOrNull(Class<T> interfaceClass) throws ClassCastException
|
||||
{
|
||||
return dependencyHandler.get(interfaceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be called after all Binds have been done.
|
||||
* Calls the delayedSetup method for each dependency. <br> <br>
|
||||
|
||||
@@ -41,8 +41,6 @@ public class ColorUtil
|
||||
|
||||
public static final int RED = rgbToInt(255,0,0);
|
||||
|
||||
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
|
||||
public static int rgbToInt(int red, int green, int blue)
|
||||
{
|
||||
return (0xFF << 24) | (red << 16) | (green << 8) | blue;
|
||||
|
||||
@@ -41,8 +41,11 @@ import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
/**
|
||||
* This class holds methods and constants that may be used in multiple places.
|
||||
@@ -52,11 +55,8 @@ import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
*/
|
||||
public class LodUtil
|
||||
{
|
||||
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonHandler.get(IMinecraftRenderWrapper.class);
|
||||
private static final IWrapperFactory FACTORY = SingletonHandler.get(IWrapperFactory.class);
|
||||
private static final IReflectionHandler REFLECTION_HANDLER = SingletonHandler.get(IReflectionHandler.class);
|
||||
private static final IVersionConstants VERSION_CONSTANTS = SingletonHandler.get(IVersionConstants.class);
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonHandler.getOrNull(IMinecraftClientWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonHandler.getOrNull(IMinecraftRenderWrapper.class);
|
||||
|
||||
/**
|
||||
* Vanilla render distances less than or equal to this will not allow partial
|
||||
@@ -167,10 +167,10 @@ public class LodUtil
|
||||
*/
|
||||
public static ILevelWrapper getServerWorldFromDimension(IDimensionTypeWrapper newDimension)
|
||||
{
|
||||
if(!MC.hasSinglePlayerServer())
|
||||
if(!MC_CLIENT.hasSinglePlayerServer())
|
||||
return null;
|
||||
|
||||
Iterable<ILevelWrapper> worlds = MC.getAllServerWorlds();
|
||||
Iterable<ILevelWrapper> worlds = MC_CLIENT.getAllServerWorlds();
|
||||
ILevelWrapper returnWorld = null;
|
||||
|
||||
for (ILevelWrapper world : worlds)
|
||||
@@ -202,7 +202,7 @@ public class LodUtil
|
||||
*/
|
||||
public static String getWorldID(ILevelWrapper world)
|
||||
{
|
||||
if (MC.hasSinglePlayerServer())
|
||||
if (MC_CLIENT.hasSinglePlayerServer())
|
||||
{
|
||||
// chop off the dimension ID as it is not needed/wanted
|
||||
String dimId = getDimensionIDFromWorld(world);
|
||||
@@ -231,7 +231,7 @@ public class LodUtil
|
||||
@Deprecated // FIXME: There are soooo many duplicated methods doing the same thing everywhere
|
||||
public static String getDimensionIDFromWorld(ILevelWrapper world)
|
||||
{
|
||||
if (MC.hasSinglePlayerServer())
|
||||
if (MC_CLIENT.hasSinglePlayerServer())
|
||||
{
|
||||
// this will return the world save location
|
||||
// and the dimension folder
|
||||
@@ -254,7 +254,7 @@ public class LodUtil
|
||||
public static String getServerFolderName()
|
||||
{
|
||||
// parse the current server's IP
|
||||
ParsedIp parsedIp = new ParsedIp(MC.getCurrentServerIp());
|
||||
ParsedIp parsedIp = new ParsedIp(MC_CLIENT.getCurrentServerIp());
|
||||
String serverIpCleaned = parsedIp.ip.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverPortCleaned = parsedIp.port != null ? parsedIp.port.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "") : "";
|
||||
|
||||
@@ -276,8 +276,8 @@ public class LodUtil
|
||||
}
|
||||
|
||||
|
||||
String serverName = MC.getCurrentServerName().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverMcVersion = MC.getCurrentServerVersion().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverName = MC_CLIENT.getCurrentServerName().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverMcVersion = MC_CLIENT.getCurrentServerVersion().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
|
||||
// generate the folder name
|
||||
String folderName = "";
|
||||
@@ -387,8 +387,8 @@ public class LodUtil
|
||||
return new Pos2D(pos.getX(), pos.getZ());
|
||||
}
|
||||
},
|
||||
MC.getPlayerChunkPos().getX() - renderDist,
|
||||
MC.getPlayerChunkPos().getZ() - renderDist,
|
||||
MC_CLIENT.getPlayerChunkPos().getX() - renderDist,
|
||||
MC_CLIENT.getPlayerChunkPos().getZ() - renderDist,
|
||||
renderDist * 2 + 1);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -6,7 +6,8 @@ import java.io.File;
|
||||
|
||||
//TODO: Maybe have IMCClientWrapper & IMCDedicatedWrapper extend this interface???
|
||||
public interface IMinecraftSharedWrapper extends IBindable {
|
||||
boolean isServerJar();
|
||||
boolean isDedicatedServer();
|
||||
|
||||
File getInstallationDirectory();
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ package com.seibel.lod.core.wrapperInterfaces.world;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.seibel.lod.core.enums.EWorldType;
|
||||
import com.seibel.lod.core.enums.ELevelType;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
|
||||
import com.seibel.lod.core.objects.DHChunkPos;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
@@ -36,7 +36,7 @@ public interface ILevelWrapper extends IBindable
|
||||
{
|
||||
IDimensionTypeWrapper getDimensionType();
|
||||
|
||||
EWorldType getWorldType();
|
||||
ELevelType getLevelType();
|
||||
|
||||
int getBlockLight(int x, int y, int z);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user