Continue refactoring, and starting to hook up all the loose pieces
This commit is contained in:
@@ -23,17 +23,13 @@ import java.util.ArrayList;
|
||||
* -by loading from file
|
||||
* -by adding data with the lodBuilder
|
||||
*/
|
||||
public abstract class LodQuadTree {
|
||||
|
||||
public class LodQuadTree {
|
||||
|
||||
/**
|
||||
* //TODO add static configs here
|
||||
* //These configs are updated someway
|
||||
* Comment: all config value should be via the class that extends this class, and
|
||||
* by implementing different abstract methods - LeeTom
|
||||
* Note: all config value should be via the class that extends this class, and
|
||||
* by implementing different abstract methods
|
||||
*/
|
||||
|
||||
|
||||
public final byte numbersOfSectionLevels;
|
||||
public final byte startingSectionLevel;
|
||||
private final MovableGridRingList<LodSection>[] ringLists;
|
||||
@@ -99,6 +95,7 @@ public abstract class LodQuadTree {
|
||||
|
||||
final SectionDetailLayer[] sectionDetailLayers;
|
||||
public final int viewDistance;
|
||||
private final RenderDataProvider renderDataProvider;
|
||||
|
||||
/**
|
||||
* Constructor of the quadTree
|
||||
@@ -106,8 +103,9 @@ public abstract class LodQuadTree {
|
||||
* @param initialPlayerX player x coordinate
|
||||
* @param initialPlayerZ player z coordinate
|
||||
*/
|
||||
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ) {
|
||||
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ, RenderDataProvider provider) {
|
||||
ColumnDatatype.REGISTER(); //FIXME: This is a hack to make sure the datatype is registered
|
||||
renderDataProvider = provider;
|
||||
|
||||
assertContainerTypeConfigCorrect();
|
||||
this.viewDistance = viewDistance;
|
||||
@@ -260,9 +258,6 @@ public abstract class LodQuadTree {
|
||||
public int getFurthestDistance(byte detailLevel) {
|
||||
return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel));
|
||||
}
|
||||
|
||||
public abstract RenderDataProvider getRenderDataProvider();
|
||||
|
||||
|
||||
/**
|
||||
* Given a section pos at level n this method returns the parent section at level n+1
|
||||
@@ -295,10 +290,6 @@ public abstract class LodQuadTree {
|
||||
LodSection::dispose);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// First tick pass: update all sections' childCount from bottom level to top level. Step:
|
||||
// If sectLevel is bottom && section != null:
|
||||
// - set childCount to 0
|
||||
@@ -473,7 +464,7 @@ public abstract class LodQuadTree {
|
||||
section.dispose();
|
||||
} else {
|
||||
if (!section.isLoaded() && !section.isLoading()) {
|
||||
section.load(getRenderDataProvider(), containerType);
|
||||
section.load(renderDataProvider, containerType);
|
||||
}
|
||||
if (section.childCount == 4) section.enableRender(this);
|
||||
if (section.childCount == 0) section.disableRender();
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.a7.RenderDataProvider;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.datatype.column.DataSourceSaver;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSource;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSourceLoader;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DataFileHandler implements RenderDataProvider, Closeable {
|
||||
public static final List<OldFileConverter> CONVERTERS = new ArrayList<>();
|
||||
public static final String FILE_EXTENSION = ".lod";
|
||||
|
||||
public final DHLevel level;
|
||||
|
||||
public final File folder;
|
||||
// A hash map of all data files.
|
||||
|
||||
public final ExecutorService IO_MANAGER = LodUtil.makeSingleThreadPool("DataFileHandler IO Manager");
|
||||
|
||||
private byte maxDataLevel = 0;
|
||||
|
||||
private final HashMultimap<DhSectionPos, DataFile> dataFiles;
|
||||
|
||||
public static final String[] FoldersToScan = {
|
||||
"data",
|
||||
}; // TODO: Add more folders to scan
|
||||
|
||||
public DataFileHandler(File folderPath, DHLevel level) {
|
||||
this.folder = folderPath;
|
||||
this.level = level;
|
||||
dataFiles = HashMultimap.create();
|
||||
// Handle converting old files that doesn't have the meta data and stuff
|
||||
List<DataFile> oldFiles = new ArrayList<>();
|
||||
for (OldFileConverter converter : CONVERTERS) oldFiles.addAll(converter.scanAndConvert(folder, level));
|
||||
oldFiles.forEach(this::_addFile);
|
||||
|
||||
// Scan for files
|
||||
File[] foldersToScan = new File[FoldersToScan.length + 1];
|
||||
for (int i = 0; i < FoldersToScan.length; i++) {
|
||||
foldersToScan[i] = new File(folder, FoldersToScan[i]);
|
||||
}
|
||||
foldersToScan[FoldersToScan.length] = folder;
|
||||
scanFiles(foldersToScan);
|
||||
}
|
||||
private List<DataFile>[] getFilesInPos(DhSectionPos pos) {
|
||||
List<DataFile>[] files = new LinkedList[maxDataLevel + 1];
|
||||
for (DhSectionPos p : dataFiles.keySet()) {
|
||||
if (p.overlaps(pos)) {
|
||||
for (DataFile f : dataFiles.get(p)) {
|
||||
files[f.dataLevel].add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
private void _addFile(DataFile file) {
|
||||
if (dataFiles.containsKey(file.pos)) {
|
||||
Set<DataFile> fileSet = dataFiles.get(file.pos);
|
||||
if (fileSet.stream().anyMatch(f -> f.dataType.equals(file.dataType))) {
|
||||
// A file with the same type and same position already exists
|
||||
// TODO: Handle this case
|
||||
return;
|
||||
}
|
||||
}
|
||||
maxDataLevel = LodUtil.max(maxDataLevel, file.dataLevel);
|
||||
dataFiles.put(file.pos, file);
|
||||
}
|
||||
|
||||
public void scanFiles(File[] foldersToScan) {
|
||||
// Scan all files in the folder and read their metadata
|
||||
for (File folder : foldersToScan) {
|
||||
if (!folder.exists() || !folder.isDirectory()) continue;
|
||||
File[] files = folder.listFiles();
|
||||
if (files == null) throw new RuntimeException("Could not list files in folder: " + folder.getAbsolutePath());
|
||||
|
||||
for (File file : files) {
|
||||
if (file.isFile()) {
|
||||
String fileName = file.getName();
|
||||
if (fileName.endsWith(FILE_EXTENSION)) {
|
||||
DataFile dataFile;
|
||||
try {
|
||||
dataFile = DataFile.readMeta(file);
|
||||
} catch (IOException e) {
|
||||
// FIXME: Log error
|
||||
continue;
|
||||
}
|
||||
_addFile(dataFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DataFile registerNewLodDataSource(LodDataSource dataSource, DataSourceSaver saver) {
|
||||
DhSectionPos pos = dataSource.getSectionPos();
|
||||
File newFile = saver.generateFilePathAndName(folder, level, pos);
|
||||
if (!newFile.getName().endsWith(FILE_EXTENSION)) {
|
||||
//TODO: Log warning
|
||||
newFile = new File(newFile.getParentFile(), newFile.getName() + FILE_EXTENSION);
|
||||
}
|
||||
|
||||
if (newFile.exists()) {
|
||||
//TODO: Log warning
|
||||
String fileStr = newFile.getPath().substring(0, newFile.getPath().length() - FILE_EXTENSION.length());
|
||||
int i = 1;
|
||||
do {
|
||||
newFile = new File(fileStr + "_" + i + FILE_EXTENSION);
|
||||
i++;
|
||||
} while (newFile.exists());
|
||||
}
|
||||
DataFile dataFile = new DataFile(newFile, saver, dataSource);
|
||||
dataFiles.put(pos, dataFile);
|
||||
try {
|
||||
dataFile.save(level, false);
|
||||
} catch (Exception e) {
|
||||
dataFiles.remove(pos, dataFile);
|
||||
//TODO: Log error
|
||||
return null;
|
||||
}
|
||||
return dataFile;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<RenderDataSource> createRenderData(RenderDataSourceLoader renderSourceLoader, DhSectionPos pos) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
List<DataFile> files = renderSourceLoader.selectFiles(pos, level, getFilesInPos(pos));
|
||||
List<LodDataSource> dataSource = files.stream().map(f -> f.load(level)).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
return renderSourceLoader.construct(dataSource, pos, level);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
IO_MANAGER.shutdown();
|
||||
try {
|
||||
IO_MANAGER.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ignored) {}
|
||||
dataFiles.values().forEach((f) -> f.close(level));
|
||||
}
|
||||
|
||||
public void save() {
|
||||
//TODO: Make it free memory that is not needed
|
||||
dataFiles.values().forEach(f -> f.saveIfNeeded(level, false));
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.io.file.DataMetaFile;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -44,7 +45,7 @@ public abstract class DataSourceLoader {
|
||||
}
|
||||
|
||||
// Can return null as meaning the requirement is not met
|
||||
public abstract LodDataSource loadData(DataMetaFile dataFile, InputStream data, DHLevel level) throws IOException;
|
||||
public abstract LodDataSource loadData(DataMetaFile dataFile, InputStream data, ILevel level) throws IOException;
|
||||
|
||||
public List<File> foldersToScan(File levelFolderPath) {
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public interface OldFileConverter {
|
||||
List<DataFile> scanAndConvert(File levelFolder, DHLevel level);
|
||||
List<DataFile> scanAndConvert(File levelFolder, DhClientServerLevel level);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.data.OldFileConverter;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.objects.a7.data.*;
|
||||
import com.seibel.lod.core.a7.io.file.DataMetaFile;
|
||||
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
|
||||
@@ -24,7 +24,7 @@ public class Alpha6DataLoader extends OldDataSourceLoader implements OldFileConv
|
||||
}
|
||||
|
||||
@Override
|
||||
public LodDataSource loadData(DataMetaFile dataFile, InputStream data, DHLevel level) {
|
||||
public LodDataSource loadData(DataMetaFile dataFile, InputStream data, DhClientServerLevel level) {
|
||||
//TODO: Add decompressor here
|
||||
try (
|
||||
XZCompressorInputStream xzIn = new XZCompressorInputStream(data);
|
||||
@@ -70,7 +70,7 @@ public class Alpha6DataLoader extends OldDataSourceLoader implements OldFileConv
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DataFile> scanAndConvert(File levelFolder, DHLevel level) {
|
||||
public List<DataFile> scanAndConvert(File levelFolder, DhClientServerLevel level) {
|
||||
|
||||
List<DataFile> files = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.seibel.lod.core.a7.io.MetaFile;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.io.file.DataMetaFile;
|
||||
|
||||
import java.io.*;
|
||||
@@ -22,7 +22,7 @@ public class ColumnDataLoader extends DataSourceSaver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LodDataSource loadData(DataMetaFile dataFile, InputStream data, DHLevel level) {
|
||||
public LodDataSource loadData(DataMetaFile dataFile, InputStream data, DhClientServerLevel level) {
|
||||
try (
|
||||
//TODO: Add decompressor here
|
||||
DataInputStream dis = new DataInputStream(data);
|
||||
@@ -35,7 +35,7 @@ public class ColumnDataLoader extends DataSourceSaver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData(DHLevel level, LodDataSource loadedData, MetaFile file, OutputStream out) throws IOException {
|
||||
public void saveData(DhClientServerLevel level, LodDataSource loadedData, MetaFile file, OutputStream out) throws IOException {
|
||||
//TODO: Add compressor here
|
||||
try (DataOutputStream dos = new DataOutputStream(out)) {
|
||||
((ColumnDatatype) loadedData).writeData(dos);
|
||||
@@ -43,7 +43,7 @@ public class ColumnDataLoader extends DataSourceSaver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File generateFilePathAndName(File levelFolderPath, DHLevel level, DhSectionPos sectionPos) {
|
||||
public File generateFilePathAndName(File levelFolderPath, DhClientServerLevel level, DhSectionPos sectionPos) {
|
||||
return generateFilePathAndName(levelFolderPath, sectionPos, Config.Client.Graphics.Quality.verticalQuality.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.LodSection;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSource;
|
||||
@@ -70,7 +70,7 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
return result;
|
||||
}
|
||||
// Load from data stream with maxVerticalSize loaded from the data stream
|
||||
public ColumnDatatype(DhSectionPos sectionPos, DataInputStream inputData, int version, DHLevel level) throws IOException {
|
||||
public ColumnDatatype(DhSectionPos sectionPos, DataInputStream inputData, int version, DhClientServerLevel level) throws IOException {
|
||||
this.sectionPos = sectionPos;
|
||||
yOffset = level.getMinY();
|
||||
byte detailLevel = inputData.readByte();
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.seibel.lod.core.a7.datatype.full.FullDatatype;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSource;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSourceLoader;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.objects.a7.data.DataFile;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
@@ -21,7 +21,7 @@ class ColumnRenderLoader extends RenderDataSourceLoader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderDataSource construct(List<LodDataSource> dataSources, DhSectionPos sectionPos, DHLevel level) {
|
||||
public RenderDataSource construct(List<LodDataSource> dataSources, DhSectionPos sectionPos, DhClientServerLevel level) {
|
||||
if (dataSources.size() == 0) return null;
|
||||
|
||||
// Check for direct casting
|
||||
@@ -111,7 +111,7 @@ class ColumnRenderLoader extends RenderDataSourceLoader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DataFile> selectFiles(DhSectionPos sectionPos, DHLevel level, List<DataFile>[] availableFiles) {
|
||||
public List<DataFile> selectFiles(DhSectionPos sectionPos, DhClientServerLevel level, List<DataFile>[] availableFiles) {
|
||||
byte targetDataLevel = (byte) (sectionPos.sectionDetail - ColumnDatatype.SECTION_SIZE_OFFSET);
|
||||
//No support for loading higher than the target level yet.
|
||||
byte maxDataLevel = LodUtil.min((byte) (availableFiles.length - 1), targetDataLevel);
|
||||
|
||||
@@ -4,8 +4,9 @@ import com.seibel.lod.core.a7.data.DataFileHandler;
|
||||
import com.seibel.lod.core.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.io.MetaFile;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -16,10 +17,10 @@ public abstract class DataSourceSaver extends DataSourceLoader {
|
||||
super(clazz, datatypeId, loaderSupportedVersions);
|
||||
}
|
||||
|
||||
public abstract void saveData(DHLevel level, LodDataSource loadedData, MetaFile file, OutputStream dataStream) throws IOException;
|
||||
public abstract void saveData(ILevel level, LodDataSource loadedData, MetaFile file, OutputStream dataStream) throws IOException;
|
||||
// generate the default file path and file name based on various parameters.
|
||||
// Ensure the file extension is '.lod'!
|
||||
public File generateFilePathAndName(File levelFolderPath, DHLevel level, DhSectionPos sectionPos) {
|
||||
public File generateFilePathAndName(File levelFolderPath, DhClientServerLevel level, DhSectionPos sectionPos) {
|
||||
return new File(levelFolderPath, String.format("%s_v%d-%s%s", clazz.getSimpleName(), getSaverVersion(),
|
||||
sectionPos.serialize(), DataFileHandler.FILE_EXTENSION));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.seibel.lod.core.a7.datatype.column;
|
||||
import com.seibel.lod.core.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -54,7 +54,7 @@ public class OldColumnDatatype implements IColumnDatatype {
|
||||
}
|
||||
|
||||
// Load from data stream with maxVerticalSize loaded from the data stream
|
||||
public OldColumnDatatype(DhSectionPos sectionPos, DataInputStream inputData, int version, DHLevel level, int sectionSizeOffset) throws IOException {
|
||||
public OldColumnDatatype(DhSectionPos sectionPos, DataInputStream inputData, int version, DhClientServerLevel level, int sectionSizeOffset) throws IOException {
|
||||
this.sectionSizeOffset = (byte) sectionSizeOffset;
|
||||
this.sectionPos = sectionPos;
|
||||
yOffset = level.getMinY();
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
package com.seibel.lod.core.a7.io;
|
||||
|
||||
import com.seibel.lod.core.a7.world.DhClientWorld;
|
||||
import com.seibel.lod.core.api.internal.InternalApiShared;
|
||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.enums.config.EDistanceGenerationMode;
|
||||
import com.seibel.lod.core.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.core.handlers.LodDimensionFileHandler;
|
||||
import com.seibel.lod.core.handlers.LodDimensionFinder;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.handlers.dimensionFinder.PlayerData;
|
||||
import com.seibel.lod.core.handlers.dimensionFinder.SubDimCompare;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.lod.core.objects.DHChunkPos;
|
||||
import com.seibel.lod.core.objects.DHRegionPos;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.objects.lod.LodDimension;
|
||||
import com.seibel.lod.core.objects.lod.LodRegion;
|
||||
import com.seibel.lod.core.util.DataPointUtil;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
@@ -46,7 +37,7 @@ public class LevelToFileMatcher implements AutoCloseable {
|
||||
private final AtomicBoolean determiningWorldFolder = new AtomicBoolean(false);
|
||||
private final ILevelWrapper currentLevel;
|
||||
private final DhClientWorld world;
|
||||
private volatile DHLevel foundLevel = null;
|
||||
private volatile DhClientServerLevel foundLevel = null;
|
||||
private final File[] potentialFiles;
|
||||
private final File levelsFolder;
|
||||
|
||||
@@ -60,12 +51,12 @@ public class LevelToFileMatcher implements AutoCloseable {
|
||||
LOGGER.info("No potential level files found. Creating a new sub dimension with ID {}...",
|
||||
LodUtil.shortenString(newId, 8));
|
||||
File folder = new File(levelsFolder, newId);
|
||||
foundLevel = new DHLevel(world, folder, targetWorld);
|
||||
foundLevel = new DhClientServerLevel(world, folder, targetWorld);
|
||||
}
|
||||
}
|
||||
|
||||
// May return null, where at this moment the level is not yet known
|
||||
public DHLevel tryGetLevel() {
|
||||
public DhClientServerLevel tryGetLevel() {
|
||||
tick();
|
||||
return foundLevel;
|
||||
}
|
||||
@@ -84,7 +75,7 @@ public class LevelToFileMatcher implements AutoCloseable {
|
||||
// attempt to get the file handler
|
||||
File saveDir = attemptToDetermineSubDimensionFolder();
|
||||
if (saveDir == null) return;
|
||||
foundLevel = new DHLevel(world, saveDir, currentLevel);
|
||||
foundLevel = new DhClientServerLevel(world, saveDir, currentLevel);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Unable to set the dimension file handler for level [" + currentLevel + "]. Error: ", e);
|
||||
} finally {
|
||||
|
||||
@@ -15,9 +15,11 @@ import com.seibel.lod.core.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
|
||||
import com.seibel.lod.core.a7.io.MetaFile;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.level.IServerLevel;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.datatype.column.DataSourceSaver;
|
||||
import com.seibel.lod.core.a7.datatype.column.OldDataSourceLoader;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
@@ -26,7 +28,7 @@ import org.apache.logging.log4j.Logger;
|
||||
public class DataMetaFile extends MetaFile {
|
||||
public static Logger LOGGER = DhLoggerBuilder.getLogger("FileMetadata");
|
||||
|
||||
private final DHLevel level;
|
||||
private final ILevel level;
|
||||
AtomicInteger localVersion = new AtomicInteger(); // This MUST be atomic
|
||||
|
||||
// The '?' type should either be:
|
||||
@@ -72,13 +74,13 @@ public class DataMetaFile extends MetaFile {
|
||||
}
|
||||
|
||||
// Load a metaFile in this path. It also automatically read the metadata.
|
||||
public DataMetaFile(DHLevel level, File path) throws IOException {
|
||||
public DataMetaFile(ILevel level, File path) throws IOException {
|
||||
super(path);
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
// Make a new MetaFile. It doesn't load or write any metadata itself.
|
||||
public DataMetaFile(DHLevel level, File path, DhSectionPos pos) {
|
||||
public DataMetaFile(ILevel level, File path, DhSectionPos pos) {
|
||||
super(path, pos);
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface DataSourceProvider {
|
||||
public interface DataSourceProvider extends AutoCloseable {
|
||||
CompletableFuture<LodDataSource> read(DhSectionPos pos);
|
||||
void write(DhSectionPos sectionPos, FullDatatype chunkData);
|
||||
CompletableFuture<Void> flushAndSave();
|
||||
|
||||
@@ -3,9 +3,10 @@ package com.seibel.lod.core.a7.io.file;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
|
||||
import com.seibel.lod.core.a7.level.IServerLevel;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -29,8 +30,8 @@ public class LocalDataFileHandler implements DataSourceProvider {
|
||||
boolean isScanned = false;
|
||||
|
||||
File saveDir;
|
||||
final DHLevel level;
|
||||
public LocalDataFileHandler(DHLevel level, File saveRootDir) {
|
||||
final IServerLevel level;
|
||||
public LocalDataFileHandler(IServerLevel level, File saveRootDir) {
|
||||
this.saveDir = saveRootDir;
|
||||
this.level = level;
|
||||
}
|
||||
@@ -144,4 +145,9 @@ public class LocalDataFileHandler implements DataSourceProvider {
|
||||
private File computeDefaultFilePath(DhSectionPos pos) { //TODO: Temp code as we haven't decided on the file naming & location yet.
|
||||
return new File(saveDir, pos.serialize() + ".lod");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.seibel.lod.core.a7.io.file;
|
||||
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class RemoteDataFileHandler implements DataSourceProvider {
|
||||
@Override
|
||||
public CompletableFuture<LodDataSource> read(DhSectionPos pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DhSectionPos sectionPos, FullDatatype chunkData) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> flushAndSave() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import java.io.File;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class RenderFileHandler implements RenderDataProvider {
|
||||
public class RenderFileHandler implements RenderSourceProvider {
|
||||
final File renderCacheFolder;
|
||||
final DataSourceProvider dataSourceProvider;
|
||||
ExecutorService renderCacheThread = LodUtil.makeSingleThreadPool("RenderCacheThread");
|
||||
@@ -30,11 +30,18 @@ public class RenderFileHandler implements RenderDataProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
public CompletableFuture<RenderDataSource> read(DhSectionPos pos) {
|
||||
@Override
|
||||
public void write(DhSectionPos sectionPos, FullDatatype chunkData) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> flushAndSave() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void write(DhSectionPos sectionPos, FullDatatype chunkData) {
|
||||
`
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package com.seibel.lod.core.a7.io.render;
|
||||
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.RenderDataProvider;
|
||||
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSource;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface RenderSourceProvider {
|
||||
CompletableFuture<RenderDataSource> get(DhSectionPos pos);
|
||||
public interface RenderSourceProvider extends RenderDataProvider, AutoCloseable {
|
||||
void write(DhSectionPos sectionPos, FullDatatype chunkData);
|
||||
CompletableFuture<Void> flushAndSave();
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.world.DhWorld;
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.RenderDataProvider;
|
||||
import com.seibel.lod.core.a7.data.DataFileHandler;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.a7.render.RenderBufferHandler;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.render.a7LodRenderer;
|
||||
import com.seibel.lod.core.util.EventLoop;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
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 java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class DHLevel extends LodQuadTree implements Closeable {
|
||||
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
public final File saveFolder; // Could be null, for no saving
|
||||
public final DataFileHandler dataFileHandler; // Could be null, for no saving
|
||||
public final RenderBufferHandler renderBufferHandler;
|
||||
public final ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHLevelTickerThread", 2);
|
||||
private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
public final ILevelWrapper level;
|
||||
public a7LodRenderer renderer;
|
||||
public final DhWorld world;
|
||||
public EventLoop eventLoop;
|
||||
|
||||
public DHLevel(DhWorld world, File saveFolder, ILevelWrapper level) {
|
||||
super(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
|
||||
MC.getPlayerBlockPos().x,
|
||||
MC.getPlayerBlockPos().z);
|
||||
this.world = world;
|
||||
this.saveFolder = saveFolder;
|
||||
if (saveFolder != null) {
|
||||
dataFileHandler = new DataFileHandler(saveFolder, this);
|
||||
} else {
|
||||
dataFileHandler = null;
|
||||
}
|
||||
renderBufferHandler = new RenderBufferHandler(this);
|
||||
this.level = level;
|
||||
eventLoop = new EventLoop(world.dhTickerThread, this::tick);
|
||||
}
|
||||
|
||||
// Should be called by server tick thread, or called by render thread but only 20 times per second, or less?
|
||||
public void update() {
|
||||
|
||||
if (!isRunning.getAndSet(true)) {
|
||||
dhTickerThread.submit(() -> {
|
||||
try {
|
||||
tick();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
isRunning.set(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
super.tick(new DhBlockPos2D(MC.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderDataProvider getRenderDataProvider() {
|
||||
return dataFileHandler;
|
||||
}
|
||||
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
|
||||
if (renderer == null) {
|
||||
renderer = new a7LodRenderer(this);
|
||||
}
|
||||
renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
|
||||
}
|
||||
|
||||
public int getMinY() {
|
||||
return level.getMinHeight();
|
||||
}
|
||||
public void dumpRamUsage() {
|
||||
//TODO
|
||||
}
|
||||
public void asyncTick() {
|
||||
eventLoop.tick();
|
||||
}
|
||||
public void close() {
|
||||
eventLoop.halt();
|
||||
if (dataFileHandler != null) {
|
||||
dataFileHandler.close();
|
||||
}
|
||||
}
|
||||
public void saveFlush() {
|
||||
if (dataFileHandler != null) {
|
||||
dataFileHandler.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.io.file.RemoteDataFileHandler;
|
||||
import com.seibel.lod.core.a7.io.render.RenderFileHandler;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
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.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 java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhClientLevel implements IClientLevel {
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
public final ClientOnlySaveStructure save;
|
||||
public final RemoteDataFileHandler dataFileHandler;
|
||||
public final RenderFileHandler renderFileHandler;
|
||||
public final RenderBufferHandler renderBufferHandler; //TODO: Should this be owned by renderer?
|
||||
public final ILevelWrapper level;
|
||||
public a7LodRenderer renderer = null;
|
||||
public LodQuadTree tree;
|
||||
|
||||
public DhClientLevel(ClientOnlySaveStructure save, ILevelWrapper level) {
|
||||
this.save = save;
|
||||
dataFileHandler = new RemoteDataFileHandler();
|
||||
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);
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpRamUsage() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startRenderer() {
|
||||
//TODO
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
|
||||
if (renderer == null) {
|
||||
renderer = new a7LodRenderer(this);
|
||||
}
|
||||
renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRenderer() {
|
||||
//TODO
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderBufferHandler getRenderBufferHandler() {
|
||||
return renderBufferHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return level.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> save() {
|
||||
return renderFileHandler.flushAndSave();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
renderFileHandler.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.io.file.LocalDataFileHandler;
|
||||
import com.seibel.lod.core.a7.io.render.RenderFileHandler;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
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.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 java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhClientServerLevel implements IClientLevel, IServerLevel {
|
||||
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 final ILevelWrapper level;
|
||||
public a7LodRenderer renderer = null;
|
||||
public LodQuadTree tree;
|
||||
|
||||
public DhClientServerLevel(LocalSaveStructure save, ILevelWrapper level) {
|
||||
this.level = level;
|
||||
this.save = save;
|
||||
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);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startRenderer() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
|
||||
if (renderer == null) {
|
||||
renderer = new a7LodRenderer(this);
|
||||
}
|
||||
renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRenderer() {
|
||||
renderFileHandler.flushAndSave(); //Ignore the completion feature so that this action is async
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderBufferHandler getRenderBufferHandler() {
|
||||
return renderBufferHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpRamUsage() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return level.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> save() {
|
||||
return renderFileHandler.flushAndSave();
|
||||
//Note: saving renderFileHandler will also save the dataFileHandler.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
renderFileHandler.close();
|
||||
//Note: Closing renderFileHandler will also close the dataFileHandler.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.io.file.LocalDataFileHandler;
|
||||
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhServerLevel implements IServerLevel {
|
||||
public final LocalSaveStructure save;
|
||||
public final LocalDataFileHandler dataFileHandler;
|
||||
public final ILevelWrapper level;
|
||||
|
||||
public DhServerLevel(LocalSaveStructure save, ILevelWrapper level) {
|
||||
this.save = save;
|
||||
this.level = level;
|
||||
dataFileHandler = new LocalDataFileHandler(this, save.getDataFolder(level));
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
//Nothing for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return level.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpRamUsage() {
|
||||
//TODO
|
||||
}
|
||||
@Override
|
||||
public void close() {
|
||||
dataFileHandler.close();
|
||||
}
|
||||
@Override
|
||||
public CompletableFuture<Void> save() {
|
||||
return dataFileHandler.flushAndSave();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.io.render.RenderSourceProvider;
|
||||
import com.seibel.lod.core.a7.render.RenderBufferHandler;
|
||||
import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
|
||||
public interface IClientLevel extends ILevel {
|
||||
void startRenderer();
|
||||
void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler);
|
||||
void stopRenderer();
|
||||
|
||||
RenderBufferHandler getRenderBufferHandler();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface ILevel extends AutoCloseable {
|
||||
int getMinY();
|
||||
CompletableFuture<Void> save();
|
||||
|
||||
void dumpRamUsage();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
public interface IServerLevel extends ILevel {
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.data.DataFile;
|
||||
|
||||
import java.util.*;
|
||||
@@ -14,9 +14,9 @@ public abstract class RenderDataSourceLoader {
|
||||
this.detailOffset = detailOffset;
|
||||
}
|
||||
|
||||
public abstract RenderDataSource construct(List<LodDataSource> dataSources, DhSectionPos sectionPos, DHLevel level);
|
||||
public abstract RenderDataSource construct(List<LodDataSource> dataSources, DhSectionPos sectionPos, DhClientServerLevel level);
|
||||
|
||||
public List<DataFile> selectFiles(DhSectionPos sectionPos, DHLevel level, List<DataFile>[] availableFiles) {
|
||||
public List<DataFile> selectFiles(DhSectionPos sectionPos, DhClientServerLevel level, List<DataFile>[] availableFiles) {
|
||||
return Arrays.stream(availableFiles).flatMap(Collection::stream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.seibel.lod.core.a7.save.structure;
|
||||
|
||||
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.level.IServerLevel;
|
||||
import com.seibel.lod.core.a7.world.DhClientWorld;
|
||||
import com.seibel.lod.core.a7.world.DhWorld;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.enums.config.EServerFolderNameMode;
|
||||
import com.seibel.lod.core.enums.config.EVerticalQuality;
|
||||
@@ -17,7 +17,6 @@ import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ClientOnlySaveStructure extends SaveStructure {
|
||||
@@ -83,14 +82,15 @@ public class ClientOnlySaveStructure extends SaveStructure {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
//FIXME: how do i deal with either creating a ClientServerLevel, or a ServerLevel here???
|
||||
@Override
|
||||
public DHLevel tryGetLevel(ILevelWrapper wrapper) {
|
||||
public IServerLevel tryGetLevel(ILevelWrapper wrapper) {
|
||||
if (Config.Client.Multiplayer.multiDimensionRequiredSimilarity.get() == 0) {
|
||||
if (fileMatcher != null) {
|
||||
fileMatcher.close();
|
||||
fileMatcher = null;
|
||||
}
|
||||
return new DHLevel(world, getLevelFolderWithoutSimilarityMatching(wrapper), wrapper);
|
||||
return new DhClientServerLevel(world, getLevelFolderWithoutSimilarityMatching(wrapper), wrapper);
|
||||
}
|
||||
|
||||
if (fileMatcher == null || !fileMatcher.isFindingLevel(wrapper)) {
|
||||
@@ -99,7 +99,7 @@ public class ClientOnlySaveStructure extends SaveStructure {
|
||||
(File[]) getMatchingLevelFolders(wrapper).toArray());
|
||||
}
|
||||
|
||||
DHLevel level = fileMatcher.tryGetLevel();
|
||||
DhClientServerLevel level = fileMatcher.tryGetLevel();
|
||||
if (level != null) {
|
||||
fileMatcher.close();
|
||||
fileMatcher = null;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.seibel.lod.core.a7.save.structure;
|
||||
|
||||
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -13,7 +11,7 @@ public abstract class SaveStructure implements AutoCloseable {
|
||||
|
||||
protected static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
public abstract DHLevel tryGetLevel(ILevelWrapper wrapper);
|
||||
public abstract DhClientServerLevel tryGetLevel(ILevelWrapper wrapper);
|
||||
|
||||
protected abstract File getRenderCacheFolder(ILevelWrapper world);
|
||||
protected abstract File getDataFolder(ILevelWrapper world);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.a7.WorldEnvironment;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
@@ -9,9 +9,10 @@ import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhClientServerWorld extends DhWorld implements IClientWorld, IServerWorld {
|
||||
private final HashMap<ILevelWrapper, DHLevel> levels;
|
||||
private final HashMap<ILevelWrapper, DhClientServerLevel> levels;
|
||||
public final LocalSaveStructure saveStructure;
|
||||
|
||||
public DhClientServerWorld() {
|
||||
@@ -21,9 +22,9 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
}
|
||||
|
||||
@Override
|
||||
public DHLevel getOrLoadLevel(ILevelWrapper wrapper) {
|
||||
public DhClientServerLevel getOrLoadLevel(ILevelWrapper wrapper) {
|
||||
if (!levels.containsKey(wrapper)) {
|
||||
DHLevel level = saveStructure.tryGetLevel(wrapper);
|
||||
DhClientServerLevel level = saveStructure.tryGetLevel(wrapper);
|
||||
if (level != null) {
|
||||
levels.put(wrapper, level);
|
||||
}
|
||||
@@ -32,7 +33,7 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
}
|
||||
|
||||
@Override
|
||||
public DHLevel getLevel(ILevelWrapper wrapper) {
|
||||
public DhClientServerLevel getLevel(ILevelWrapper wrapper) {
|
||||
return levels.get(wrapper);
|
||||
}
|
||||
|
||||
@@ -47,10 +48,10 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
|
||||
public void tick() {
|
||||
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
|
||||
Iterator<DHLevel> iterator = levels.values().iterator();
|
||||
Iterator<DhClientServerLevel> iterator = levels.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DHLevel level = iterator.next();
|
||||
if (level.viewDistance != newViewDistance) {
|
||||
DhClientServerLevel level = iterator.next();
|
||||
if (level.tree.viewDistance != newViewDistance) {
|
||||
level.close();
|
||||
iterator.remove();
|
||||
}
|
||||
@@ -63,23 +64,17 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAndFlush() {
|
||||
for (DHLevel level : levels.values()) {
|
||||
level.saveFlush();
|
||||
}
|
||||
public CompletableFuture<Void> saveAndFlush() {
|
||||
return CompletableFuture.allOf(levels.values().stream().map(DhClientServerLevel::save).toArray(CompletableFuture[]::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (DHLevel level : levels.values()) {
|
||||
saveAndFlush().join();
|
||||
for (DhClientServerLevel level : levels.values()) {
|
||||
LOGGER.info("Unloading level for world " + level.level.getDimensionType().getDimensionName());
|
||||
level.close();
|
||||
}
|
||||
levels.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.a7.WorldEnvironment;
|
||||
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.save.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.EventLoop;
|
||||
@@ -13,11 +11,12 @@ import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
|
||||
private final HashMap<ILevelWrapper, DHLevel> levels;
|
||||
private final HashMap<ILevelWrapper, DhClientWorld> levels;
|
||||
public final ClientOnlySaveStructure saveStructure;
|
||||
|
||||
public ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHTickerThread", 2);
|
||||
@@ -30,9 +29,9 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DHLevel getOrLoadLevel(ILevelWrapper wrapper) {
|
||||
public DhClientServerLevel getOrLoadLevel(ILevelWrapper wrapper) {
|
||||
if (!levels.containsKey(wrapper)) {
|
||||
DHLevel level = saveStructure.tryGetLevel(wrapper);
|
||||
DhClientWorld level = saveStructure.tryGetLevel(wrapper);
|
||||
if (level != null) {
|
||||
levels.put(wrapper, level);
|
||||
}
|
||||
@@ -41,7 +40,7 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DHLevel getLevel(ILevelWrapper wrapper) {
|
||||
public DhClientServerLevel getLevel(ILevelWrapper wrapper) {
|
||||
return levels.get(wrapper);
|
||||
}
|
||||
|
||||
@@ -56,9 +55,9 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
|
||||
private void tick() {
|
||||
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
|
||||
Iterator<DHLevel> iterator = levels.values().iterator();
|
||||
Iterator<DhClientWorld> iterator = levels.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DHLevel level = iterator.next();
|
||||
DhClientWorld level = iterator.next();
|
||||
if (level.viewDistance != newViewDistance) {
|
||||
level.close();
|
||||
iterator.remove();
|
||||
@@ -72,24 +71,17 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAndFlush() {
|
||||
for (DHLevel level : levels.values()) {
|
||||
level.saveFlush();
|
||||
}
|
||||
public CompletableFuture<Void> saveAndFlush() {
|
||||
return CompletableFuture.allOf(levels.values().stream().map(DhClientServerLevel::save).toArray(CompletableFuture[]::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
eventLoop.halt();
|
||||
for (DHLevel level : levels.values()) {
|
||||
saveAndFlush().join();
|
||||
for (DhClientServerLevel level : levels.values()) {
|
||||
LOGGER.info("Unloading level for world " + level.level.getDimensionType().getDimensionName());
|
||||
level.close();
|
||||
}
|
||||
levels.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.a7.WorldEnvironment;
|
||||
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.save.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
@@ -13,7 +11,7 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
private final HashMap<ILevelWrapper, DHLevel> levels;
|
||||
private final HashMap<ILevelWrapper, DhClientServerLevel> levels;
|
||||
public final LocalSaveStructure saveStructure;
|
||||
|
||||
public DhServerWorld() {
|
||||
@@ -23,9 +21,9 @@ public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DHLevel getOrLoadLevel(ILevelWrapper wrapper) {
|
||||
public DhClientServerLevel getOrLoadLevel(ILevelWrapper wrapper) {
|
||||
if (!levels.containsKey(wrapper)) {
|
||||
DHLevel level = saveStructure.tryGetLevel(wrapper);
|
||||
DhClientServerLevel level = saveStructure.tryGetLevel(wrapper);
|
||||
if (level != null) {
|
||||
levels.put(wrapper, level);
|
||||
}
|
||||
@@ -34,7 +32,7 @@ public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DHLevel getLevel(ILevelWrapper wrapper) {
|
||||
public DhClientServerLevel getLevel(ILevelWrapper wrapper) {
|
||||
return levels.get(wrapper);
|
||||
}
|
||||
|
||||
@@ -49,9 +47,9 @@ public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
|
||||
public void tick() {
|
||||
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
|
||||
Iterator<DHLevel> iterator = levels.values().iterator();
|
||||
Iterator<DhClientServerLevel> iterator = levels.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DHLevel level = iterator.next();
|
||||
DhClientServerLevel level = iterator.next();
|
||||
if (level.viewDistance != newViewDistance) {
|
||||
level.close();
|
||||
iterator.remove();
|
||||
@@ -66,14 +64,14 @@ public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
|
||||
@Override
|
||||
public void saveAndFlush() {
|
||||
for (DHLevel level : levels.values()) {
|
||||
for (DhClientServerLevel level : levels.values()) {
|
||||
level.saveFlush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (DHLevel level : levels.values()) {
|
||||
for (DhClientServerLevel level : levels.values()) {
|
||||
LOGGER.info("Unloading level for world " + level.level.getDimensionType().getDimensionName());
|
||||
level.close();
|
||||
}
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.a7.WorldEnvironment;
|
||||
import com.seibel.lod.core.a7.io.LevelToFileMatcher;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.save.structure.SaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.EventLoop;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public abstract class DhWorld implements Closeable {
|
||||
protected static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
@@ -25,10 +17,10 @@ public abstract class DhWorld implements Closeable {
|
||||
protected DhWorld(WorldEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
public abstract DHLevel getOrLoadLevel(ILevelWrapper wrapper);
|
||||
public abstract DhClientServerLevel getOrLoadLevel(ILevelWrapper wrapper);
|
||||
|
||||
public abstract DHLevel getLevel(ILevelWrapper wrapper);
|
||||
public abstract DhClientServerLevel getLevel(ILevelWrapper wrapper);
|
||||
|
||||
public abstract void unloadLevel(ILevelWrapper wrapper);
|
||||
public abstract void saveAndFlush();
|
||||
public abstract CompletableFuture<Void> saveAndFlush();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
public interface IClientWorld {
|
||||
void render();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
|
||||
import com.seibel.lod.core.logging.SpamReducedLogger;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.world.DhWorld;
|
||||
import com.seibel.lod.core.a7.Server;
|
||||
import com.seibel.lod.core.objects.math.Mat4f;
|
||||
@@ -199,7 +199,7 @@ public class ClientApi
|
||||
if (world == null) return;
|
||||
DhWorld DhWorld = SharedApi.currentWorld;
|
||||
if (DhWorld == null) return;
|
||||
DHLevel level = (SharedApi.currentServer == null) ? DhWorld.getOrLoadLevel(world) : DhWorld.getLevel(world);
|
||||
DhClientServerLevel level = (SharedApi.currentServer == null) ? DhWorld.getOrLoadLevel(world) : DhWorld.getLevel(world);
|
||||
if (level == null) return;
|
||||
|
||||
if (prefLoggerEnabled) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.lod.core.render;
|
||||
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodBufferBuilderFactory;
|
||||
import com.seibel.lod.core.config.types.ConfigEntry;
|
||||
@@ -28,7 +29,7 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
|
||||
import com.seibel.lod.core.objects.DHBlockPos;
|
||||
import com.seibel.lod.core.a7.level.DHLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.render.RenderBufferHandler;
|
||||
import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.objects.math.Vec3d;
|
||||
@@ -82,14 +83,14 @@ public class a7LodRenderer
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonHandler.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
public EDebugMode previousDebugMode = null;
|
||||
public final DHLevel level;
|
||||
public final IClientLevel level;
|
||||
|
||||
// The shader program
|
||||
LodRenderProgram shaderProgram = null;
|
||||
public QuadElementBuffer quadIBO = null;
|
||||
public boolean isSetupComplete = false;
|
||||
|
||||
public a7LodRenderer(DHLevel level)
|
||||
public a7LodRenderer(IClientLevel level)
|
||||
{
|
||||
this.level = level;
|
||||
}
|
||||
@@ -127,7 +128,7 @@ public class a7LodRenderer
|
||||
MC_RENDER.tryDisableVanillaFog();
|
||||
|
||||
// The Buffer manager
|
||||
RenderBufferHandler bufferHandler = level.renderBufferHandler;
|
||||
RenderBufferHandler bufferHandler = level.getRenderBufferHandler();
|
||||
|
||||
//===================//
|
||||
// draw params setup //
|
||||
|
||||
Reference in New Issue
Block a user