Finish up the level split of 3 type of levels: ClientOnly, ClientServer, and ServerOnly
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
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
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
|
||||
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 java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface RenderDataProvider {
|
||||
CompletableFuture<RenderDataSource> createRenderData(RenderDataSourceLoader renderSourceLoader, DhSectionPos pos);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
|
||||
@Deprecated // Use the DhXXXWorld
|
||||
public class Server {
|
||||
public final boolean isSinglePlayer;
|
||||
|
||||
public Server(boolean isSinglePlayer) {
|
||||
this.isSinglePlayer = isSinglePlayer;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
|
||||
public interface LodDataSource {
|
||||
DataSourceLoader getLatestLoader();
|
||||
DhSectionPos getSectionPos();
|
||||
byte getDataDetail();
|
||||
void setLocalVersion(int localVer);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public interface OldFileConverter {
|
||||
List<DataFile> scanAndConvert(File levelFolder, DhClientServerLevel level);
|
||||
}
|
||||
+16
-17
@@ -1,34 +1,42 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
package com.seibel.lod.core.a7.datatype;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class DataSourceLoader {
|
||||
|
||||
public static final HashMultimap<Long, DataSourceLoader> loaderRegistry = HashMultimap.create();
|
||||
public static final HashMultimap<Class<? extends LodDataSource>, DataSourceLoader> loaderRegistry = HashMultimap.create();
|
||||
public final Class<? extends LodDataSource> clazz;
|
||||
public static final HashMap<Long, Class<? extends LodDataSource>> datatypeIdRegistry = new HashMap<>();
|
||||
public static DataSourceLoader getLoader(long dataTypeId, byte dataVersion) {
|
||||
return loaderRegistry.get(datatypeIdRegistry.get(dataTypeId)).stream()
|
||||
.filter(l -> Arrays.binarySearch(l.loaderSupportedVersions, dataVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
public static DataSourceLoader getLoader(Class<? extends LodDataSource> clazz, byte dataVersion) {
|
||||
return loaderRegistry.get(clazz).stream()
|
||||
.filter(l -> Arrays.binarySearch(l.loaderSupportedVersions, dataVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public final long datatypeId;
|
||||
public final byte[] loaderSupportedVersions;
|
||||
public final Class<? extends LodDataSource> clazz;
|
||||
|
||||
public DataSourceLoader(Class<? extends LodDataSource> clazz, long datatypeId, byte[] loaderSupportedVersions) {
|
||||
this.datatypeId = datatypeId;
|
||||
this.loaderSupportedVersions = loaderSupportedVersions;
|
||||
Arrays.sort(loaderSupportedVersions); // sort to allow fast access
|
||||
this.clazz = clazz;
|
||||
|
||||
if (datatypeIdRegistry.containsKey(datatypeId) && datatypeIdRegistry.get(datatypeId) != clazz) {
|
||||
throw new IllegalArgumentException("Loader for datatypeId " + datatypeId + " already registered with different class: "
|
||||
+ datatypeIdRegistry.get(datatypeId) + " != " + clazz);
|
||||
}
|
||||
Set<DataSourceLoader> loaders = loaderRegistry.get(datatypeId);
|
||||
Set<DataSourceLoader> loaders = loaderRegistry.get(clazz);
|
||||
if (loaders.stream().anyMatch(other -> {
|
||||
// see if any loaderSupportsVersion conflicts with this one
|
||||
for (byte otherVer : other.loaderSupportedVersions) {
|
||||
@@ -40,20 +48,11 @@ public abstract class DataSourceLoader {
|
||||
+ Arrays.toString(loaderSupportedVersions) + " already registered!");
|
||||
}
|
||||
datatypeIdRegistry.put(datatypeId, clazz);
|
||||
loaderRegistry.put(datatypeId, this);
|
||||
loaderRegistry.put(clazz, this);
|
||||
}
|
||||
|
||||
// Can return null as meaning the requirement is not met
|
||||
public abstract LodDataSource loadData(DataMetaFile dataFile, InputStream data, ILevel level) throws IOException;
|
||||
|
||||
public List<File> foldersToScan(File levelFolderPath) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static DataSourceLoader getLoader(long dataTypeId, byte loaderVersion) {
|
||||
return loaderRegistry.get(dataTypeId).stream()
|
||||
.filter(l -> Arrays.binarySearch(l.loaderSupportedVersions, loaderVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.seibel.lod.core.a7.datatype;
|
||||
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderMetaFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class EmptyRenderSource implements LodRenderSource {
|
||||
public static final EmptyRenderSource INSTANCE = new EmptyRenderSource();
|
||||
|
||||
@Override
|
||||
public void enableRender(LodQuadTree quadTree) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableRender() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDetailOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRender(IClientLevel level, RenderMetaFile file, OutputStream dataStream) throws IOException {
|
||||
throw new UnsupportedOperationException("EmptyRenderSource should NEVER be saved!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.seibel.lod.core.a7.datatype;
|
||||
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
|
||||
import com.seibel.lod.core.a7.util.IOUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface LodDataSource {
|
||||
DhSectionPos getSectionPos();
|
||||
byte getDataDetail();
|
||||
void setLocalVersion(int localVer);
|
||||
byte getDataVersion();
|
||||
|
||||
|
||||
// Saving related
|
||||
void saveData(ILevel level, DataMetaFile file, OutputStream dataStream) throws IOException;
|
||||
default File generateFilePathAndName(File levelFolderPath, ILevel level, DhSectionPos sectionPos) {
|
||||
return new File(levelFolderPath, String.format("%s_v%d-%s%s", getClass().getSimpleName(), getDataVersion(),
|
||||
sectionPos.serialize(), IOUtil.LOD_FILE_EXTENSION));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.seibel.lod.core.a7.datatype;
|
||||
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderMetaFile;
|
||||
import com.seibel.lod.core.objects.DHRegionPos;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Example on how to register a loader:
|
||||
* <pre>
|
||||
public static RenderDataSource testAndConstruct(LodDataSource dataSource, DhSectionPos sectionPos) {
|
||||
ColumnRenderContainer container = new ColumnRenderContainer(10, -100);
|
||||
container.startFillData(dataSource);
|
||||
return container;
|
||||
}
|
||||
static {
|
||||
RenderDataSource.registorLoader(ColumnRenderContainer::testAndConstruct, 0);
|
||||
}
|
||||
</pre>
|
||||
*/
|
||||
public interface LodRenderSource {
|
||||
void enableRender(LodQuadTree quadTree);
|
||||
void disableRender();
|
||||
boolean isRenderReady();
|
||||
void dispose(); // notify the container that the parent lodSection is now disposed (can be in loaded or unloaded state)
|
||||
byte getDetailOffset();
|
||||
|
||||
/**
|
||||
* Try and swap in new render buffer for this section. Note that before this call, there should be no other
|
||||
* places storing or referencing the render buffer.
|
||||
* @param referenceSlot The slot for swapping in the new buffer.
|
||||
* @return True if the swap was successful. False if swap is not needed or if it is in progress.
|
||||
*/
|
||||
boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot);
|
||||
|
||||
void saveRender(IClientLevel level, RenderMetaFile file, OutputStream dataStream) throws IOException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.seibel.lod.core.a7.datatype;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderMetaFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class RenderSourceLoader {
|
||||
public static final HashMultimap<Class<? extends LodRenderSource>, RenderSourceLoader> loaderRegistry = HashMultimap.create();
|
||||
public static final HashMap<Long, Class<? extends LodRenderSource>> renderTypeIdRegistry = new HashMap<>();
|
||||
public static RenderSourceLoader getLoader(long renderTypeId, byte loaderVersion) {
|
||||
return loaderRegistry.get(renderTypeIdRegistry.get(renderTypeId)).stream()
|
||||
.filter(l -> Arrays.binarySearch(l.loaderSupportedVersions, loaderVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
public static RenderSourceLoader getLoader(Class<? extends LodRenderSource> clazz, byte loaderVersion) {
|
||||
return loaderRegistry.get(clazz).stream()
|
||||
.filter(l -> Arrays.binarySearch(l.loaderSupportedVersions, loaderVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public final Class<? extends LodRenderSource> clazz;
|
||||
public final long renderTypeId;
|
||||
public final byte[] loaderSupportedVersions;
|
||||
public final byte detailOffset;
|
||||
|
||||
public RenderSourceLoader(Class<? extends LodRenderSource> clazz, long renderTypeId, byte[] loaderSupportedVersions, byte detailOffset) {
|
||||
this.renderTypeId = renderTypeId;
|
||||
this.loaderSupportedVersions = loaderSupportedVersions;
|
||||
Arrays.sort(loaderSupportedVersions); // sort to allow fast access
|
||||
this.clazz = clazz;
|
||||
if (renderTypeIdRegistry.containsKey(renderTypeId) && renderTypeIdRegistry.get(renderTypeId) != clazz) {
|
||||
throw new IllegalArgumentException("Loader for renderTypeId " + renderTypeId + " already registered with different class: "
|
||||
+ renderTypeIdRegistry.get(renderTypeId) + " != " + clazz);
|
||||
}
|
||||
Set<RenderSourceLoader> loaders = loaderRegistry.get(clazz);
|
||||
if (loaders.stream().anyMatch(other -> {
|
||||
// see if any loaderSupportsVersion conflicts with this one
|
||||
for (byte otherVer : other.loaderSupportedVersions) {
|
||||
if (Arrays.binarySearch(loaderSupportedVersions, otherVer) >= 0) return true;
|
||||
}
|
||||
return false;
|
||||
})) {
|
||||
throw new IllegalArgumentException("Loader for class " + clazz + " that supports one of the version in "
|
||||
+ Arrays.toString(loaderSupportedVersions) + " already registered!");
|
||||
}
|
||||
renderTypeIdRegistry.put(renderTypeId, clazz);
|
||||
loaderRegistry.put(clazz, this);
|
||||
this.detailOffset = detailOffset;
|
||||
}
|
||||
|
||||
// Can return null as meaning the file is out of date or something
|
||||
public abstract LodRenderSource loadRender(RenderMetaFile renderFile, InputStream data, IClientLevel level) throws IOException;
|
||||
public abstract LodRenderSource createRender(LodDataSource dataSource, IClientLevel level);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
|
||||
import com.seibel.lod.core.a7.data.DataFileHandler;
|
||||
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.DhClientServerLevel;
|
||||
import com.seibel.lod.core.objects.a7.data.*;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
|
||||
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Alpha6DataLoader extends OldDataSourceLoader implements OldFileConverter {
|
||||
|
||||
public static final Alpha6DataLoader INSTANCE = new Alpha6DataLoader();
|
||||
|
||||
private Alpha6DataLoader() {
|
||||
super(OldColumnDatatype.class, OldColumnDatatype.DATA_TYPE_ID, new byte[]{0});
|
||||
DataFileHandler.CONVERTERS.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LodDataSource loadData(DataMetaFile dataFile, InputStream data, DhClientServerLevel level) {
|
||||
//TODO: Add decompressor here
|
||||
try (
|
||||
XZCompressorInputStream xzIn = new XZCompressorInputStream(data);
|
||||
DataInputStream dis = new DataInputStream(xzIn);
|
||||
) {
|
||||
return new OldColumnDatatype(dataFile.pos, dis, dataFile.loaderVersion, level, 1);
|
||||
} catch (IOException e) {
|
||||
//FIXME: Log error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceSaver getNewSaver() {
|
||||
return null; // No re-saving of old datatype as any data should be converted to new format before saving
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static DataFile convert(File file, int detailLevel, EVerticalQuality quality) {
|
||||
String oldName = file.getName();
|
||||
String regionStr = oldName.substring("lod.".length(), oldName.length() - ".xz".length());
|
||||
String[] parts = regionStr.split("\\.");
|
||||
if (parts.length != 2) return null;
|
||||
int regionX = Integer.parseInt(parts[0]);
|
||||
int regionZ = Integer.parseInt(parts[1]);
|
||||
|
||||
ColumnDatatype datatype;
|
||||
|
||||
try (FileInputStream fileInStream = new FileInputStream(file)) {
|
||||
XZCompressorInputStream inputStream = new XZCompressorInputStream(fileInStream);
|
||||
int fileVersion = inputStream.read();
|
||||
|
||||
|
||||
DhSectionPos pos;
|
||||
|
||||
//TODO: Implement
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DataFile> scanAndConvert(File levelFolder, DhClientServerLevel level) {
|
||||
|
||||
List<DataFile> files = new ArrayList<>();
|
||||
|
||||
List<File> foldersToScan = new ArrayList<>(EVerticalQuality.values().length);
|
||||
for (EVerticalQuality q : EVerticalQuality.values()) {
|
||||
File qualityFolder = new File(levelFolder, q.toString());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
foldersToScan.add(new File(qualityFolder, "detail-"+i));
|
||||
}
|
||||
}
|
||||
|
||||
for (EVerticalQuality q : EVerticalQuality.values()) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
File detailFolder = new File(levelFolder, q.toString() + File.pathSeparator + "detail-" + i);
|
||||
if (!detailFolder.exists() || !detailFolder.isDirectory()) continue;
|
||||
File[] filesToScan = detailFolder.listFiles();
|
||||
if (filesToScan == null) continue;
|
||||
for (File f : filesToScan) {
|
||||
String fileName = f.getName();
|
||||
if (!fileName.endsWith(".xz") || fileName.startsWith("lod.")) continue;
|
||||
DataFile converted = convert(f, i, q);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
|
||||
import com.seibel.lod.core.a7.data.DataFileHandler;
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.save.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.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ColumnDataLoader extends DataSourceSaver {
|
||||
private static final byte COLUMN_DATA_LOADER_VERSION = 1;
|
||||
public static final ColumnDataLoader INSTANCE = new ColumnDataLoader();
|
||||
|
||||
private ColumnDataLoader() {
|
||||
super(ColumnDatatype.class, ColumnDatatype.DATA_TYPE_ID, new byte[]{COLUMN_DATA_LOADER_VERSION});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LodDataSource loadData(DataMetaFile dataFile, InputStream data, DhClientServerLevel level) {
|
||||
try (
|
||||
//TODO: Add decompressor here
|
||||
DataInputStream dis = new DataInputStream(data);
|
||||
) {
|
||||
return new ColumnDatatype(dataFile.pos, dis, dataFile.loaderVersion, level);
|
||||
} catch (IOException e) {
|
||||
//FIXME: Log error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File generateFilePathAndName(File levelFolderPath, DhClientServerLevel level, DhSectionPos sectionPos) {
|
||||
return generateFilePathAndName(levelFolderPath, sectionPos, Config.Client.Graphics.Quality.verticalQuality.get());
|
||||
}
|
||||
|
||||
public File generateFilePathAndName(File levelFolderPath, DhSectionPos sectionPos, EVerticalQuality quality) {
|
||||
return new File(levelFolderPath, "cache" + File.separator + quality.toString() + File.separator +
|
||||
String.format("%s_v%d-%s%s", clazz.getSimpleName(), COLUMN_DATA_LOADER_VERSION,
|
||||
sectionPos.serialize(), DataFileHandler.FILE_EXTENSION));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> foldersToScan(File levelFolderPath) {
|
||||
File cacheFolder = new File(levelFolderPath, "cache");
|
||||
List<File> foldersToScan = new ArrayList<>(EVerticalQuality.values().length);
|
||||
for (EVerticalQuality q : EVerticalQuality.values()) {
|
||||
foldersToScan.add(new File(cacheFolder, q.toString()));
|
||||
}
|
||||
return foldersToScan;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -19,6 +19,8 @@
|
||||
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnDataView;
|
||||
import com.seibel.lod.core.logging.SpamReducedLogger;
|
||||
import com.seibel.lod.core.util.ColorUtil;
|
||||
|
||||
@@ -30,7 +32,7 @@ import java.util.Arrays;
|
||||
* @author Leonardo Amato
|
||||
* @version ??
|
||||
*/
|
||||
public class ColumnDataPoint
|
||||
public class ColumnFormat
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -1,190 +1,35 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
|
||||
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 com.seibel.lod.core.a7.render.RenderDataSource;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSourceLoader;
|
||||
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;
|
||||
import com.seibel.lod.core.a7.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderMetaFile;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
class ColumnRenderLoader extends RenderDataSourceLoader {
|
||||
public class ColumnRenderLoader extends RenderSourceLoader {
|
||||
public ColumnRenderLoader() {
|
||||
super(4);
|
||||
super(ColumnRenderSource.class, ColumnRenderSource.TYPE_ID, new byte[]{ColumnRenderSource.LATEST_VERSION}, ColumnRenderSource.SECTION_SIZE_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderDataSource construct(List<LodDataSource> dataSources, DhSectionPos sectionPos, DhClientServerLevel level) {
|
||||
if (dataSources.size() == 0) return null;
|
||||
|
||||
// Check for direct casting
|
||||
if (dataSources.size() == 1 && dataSources.get(0) instanceof ColumnDatatype
|
||||
&& dataSources.get(0).getSectionPos().equals(sectionPos)
|
||||
&& dataSources.get(0).getDataDetail() == sectionPos.sectionDetail - ColumnDatatype.SECTION_SIZE_OFFSET) {
|
||||
// Directly using the data source as the render data source is possible.
|
||||
return (ColumnDatatype) dataSources.get(0);
|
||||
public LodRenderSource loadRender(RenderMetaFile dataFile, InputStream data, IClientLevel level) throws IOException {
|
||||
try (
|
||||
//TODO: Add decompressor here
|
||||
DataInputStream dis = new DataInputStream(data);
|
||||
) {
|
||||
return new ColumnRenderSource(dataFile.pos, dis, dataFile.dataVersion, level);
|
||||
}
|
||||
|
||||
// Otherwise, we need to create a new render data source, and copy the data from the data sources.
|
||||
ColumnDatatype renderDataSource = new ColumnDatatype(sectionPos,
|
||||
DetailDistanceUtil.getMaxVerticalData(sectionPos.sectionDetail - ColumnDatatype.SECTION_SIZE_OFFSET),
|
||||
level.getMinY());
|
||||
boolean completeCopy = dataSources.get(0).getSectionPos().getWidth().toBlock() >= sectionPos.getWidth().toBlock();
|
||||
|
||||
if (completeCopy) {
|
||||
// If there is only one data source, we need to insure on copy, we don't copy out of bounds as we
|
||||
// may just need to copy partial section of the data source.
|
||||
LodUtil.assertTrue(dataSources.size() == 1, "Expected only one data source for complete copy");
|
||||
byte targetDataLevel = (byte) (sectionPos.sectionDetail - ColumnDatatype.SECTION_SIZE_OFFSET);
|
||||
byte sourceDataLevel = dataSources.get(0).getDataDetail();
|
||||
LodUtil.assertTrue(targetDataLevel >= sourceDataLevel);
|
||||
if (dataSources.get(0) instanceof IColumnDatatype) {
|
||||
IColumnDatatype dataSource = (IColumnDatatype) dataSources.get(0);
|
||||
DhSectionPos srcPos = dataSource.getSectionPos();
|
||||
|
||||
// Note that in here, the source data level will be always < target section level
|
||||
int trgX = sectionPos.getCorner().getX().toBlock();
|
||||
int trgZ = sectionPos.getCorner().getZ().toBlock();
|
||||
int trgMaxX = trgX + sectionPos.getWidth().toBlock() - 1;
|
||||
int trgMaxZ = trgZ + sectionPos.getWidth().toBlock() - 1;
|
||||
int trgXSizeInSrc = (trgX >> sourceDataLevel) - (trgMaxX >> sourceDataLevel) + 1;
|
||||
int trgZSizeInSrc = (trgZ >> sourceDataLevel) - (trgMaxZ >> sourceDataLevel) + 1;
|
||||
int trgXInSrc = (trgX >> sourceDataLevel) % srcPos.getWidth(sourceDataLevel).value;
|
||||
int trgZInSrc = (trgZ >> sourceDataLevel) % srcPos.getWidth(sourceDataLevel).value;
|
||||
|
||||
ColumnQuadView srcView = dataSource.getDataInQuad(trgXInSrc, trgZInSrc, trgXSizeInSrc, trgZSizeInSrc);
|
||||
ColumnQuadView trgView = renderDataSource.getFullQuad();
|
||||
trgView.mergeMultiColumnFrom(srcView);
|
||||
} else {
|
||||
if (!(dataSources.get(0) instanceof FullDatatype))
|
||||
throw new IllegalArgumentException("Unsupported data source type: " + dataSources.get(0).getClass().getName());
|
||||
FullDatatype dataSource = (FullDatatype) dataSources.get(0);
|
||||
DhSectionPos srcPos = dataSource.getSectionPos();
|
||||
//TODO: Impl this
|
||||
LodUtil.assertTrue(false, "Not implemented yet");
|
||||
}
|
||||
} else {
|
||||
// If there are multiple data sources, we need to merge them into the target data source
|
||||
for (LodDataSource dataSource : dataSources) {
|
||||
byte targetDataLevel = (byte) (sectionPos.sectionDetail - ColumnDatatype.SECTION_SIZE_OFFSET);
|
||||
byte sourceDataLevel = dataSource.getDataDetail();
|
||||
DhSectionPos srcPos = dataSource.getSectionPos();
|
||||
|
||||
if (dataSource instanceof IColumnDatatype) {
|
||||
IColumnDatatype clDataSource = (IColumnDatatype) dataSource;
|
||||
|
||||
// Note that targetDataLevel can be > source section level
|
||||
int srcX = srcPos.getCorner().getX().toBlock();
|
||||
int srcZ = srcPos.getCorner().getZ().toBlock();
|
||||
int srcMaxX = srcX + srcPos.getWidth().toBlock() - 1;
|
||||
int srcMaxZ = srcZ + srcPos.getWidth().toBlock() - 1;
|
||||
int srcXSizeInTrg = (srcX >> targetDataLevel) - (srcMaxX >> targetDataLevel) + 1;
|
||||
int srcZSizeInTrg = (srcZ >> targetDataLevel) - (srcMaxZ >> targetDataLevel) + 1;
|
||||
int srcXInTrg = (srcX >> targetDataLevel) % ColumnDatatype.SECTION_SIZE;
|
||||
int srcZInTrg = (srcZ >> targetDataLevel) % ColumnDatatype.SECTION_SIZE;
|
||||
|
||||
ColumnQuadView srcView = clDataSource.getFullQuad();
|
||||
ColumnQuadView trgView = renderDataSource.getDataInQuad(srcXInTrg, srcZInTrg, srcXSizeInTrg, srcZSizeInTrg);
|
||||
trgView.mergeMultiColumnFrom(srcView);
|
||||
} else {
|
||||
if (!(dataSource instanceof FullDatatype))
|
||||
throw new IllegalArgumentException("Unsupported data source type: " + dataSource.getClass().getName());
|
||||
FullDatatype flDataSource = (FullDatatype) dataSource;
|
||||
//TODO: Impl this
|
||||
LodUtil.assertTrue(false, "Not implemented yet");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return renderDataSource;
|
||||
}
|
||||
|
||||
private static boolean IsColumnDatatype(Class<?> clazz) {
|
||||
return IColumnDatatype.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
byte topValidDataLevel = Byte.MIN_VALUE;
|
||||
List<DataFile> selectedFiles = new LinkedList<>();
|
||||
|
||||
for (int detail = maxDataLevel; detail >= 0; detail--) {
|
||||
if (availableFiles[detail] == null) continue;
|
||||
if (topValidDataLevel == Byte.MIN_VALUE) {
|
||||
for (DataFile dataFile : availableFiles[detail]) {
|
||||
if (dataFile.dataLevel > targetDataLevel) continue;
|
||||
if (IsColumnDatatype(dataFile.dataType) || dataFile.dataType == FullDatatype.class
|
||||
|| dataFile.dataType == OldColumnDatatype.class) {
|
||||
topValidDataLevel = LodUtil.max(topValidDataLevel, dataFile.dataLevel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (topValidDataLevel == Byte.MIN_VALUE) continue;
|
||||
|
||||
|
||||
DataFile singleCoveringColumnFile = null;
|
||||
DataFile singleCoveringFullFile = null;
|
||||
|
||||
for (DataFile dataFile : availableFiles[detail]) {
|
||||
if (dataFile.pos.getWidth().toBlock() == sectionPos.getWidth().toBlock()) {
|
||||
if (IsColumnDatatype(dataFile.dataType)) {
|
||||
singleCoveringColumnFile = dataFile;
|
||||
break;
|
||||
} else if (dataFile.dataType == FullDatatype.class) {
|
||||
singleCoveringFullFile = dataFile;
|
||||
// Don't break as there may be a column file later.
|
||||
}
|
||||
} else if (dataFile.pos.getWidth().toBlock() > sectionPos.getWidth().toBlock()) {
|
||||
if (IsColumnDatatype(dataFile.dataType) && singleCoveringColumnFile == null)
|
||||
singleCoveringColumnFile = dataFile;
|
||||
else if (dataFile.dataType == FullDatatype.class && singleCoveringFullFile == null)
|
||||
singleCoveringFullFile = dataFile;
|
||||
}
|
||||
}
|
||||
|
||||
// First, try select single file that has enough width to cover the section
|
||||
if (singleCoveringColumnFile != null) return Collections.singletonList(singleCoveringColumnFile);
|
||||
if (singleCoveringFullFile != null) return Collections.singletonList(singleCoveringFullFile);
|
||||
|
||||
// If no single file covers the section, try to select all files without any duplicates
|
||||
for (DataFile dataFile : availableFiles[detail]) {
|
||||
boolean isDuplicate = false;
|
||||
boolean isSet = false;
|
||||
for (int i = 0; i < selectedFiles.size(); i++) {
|
||||
DataFile selectedFile = selectedFiles.get(i);
|
||||
if (selectedFile == null) continue;
|
||||
if (selectedFile.pos.overlaps(dataFile.pos)) {
|
||||
// Now, the already selected file muct have same or higher data level
|
||||
// so, we just select the file with a position that covers the most area.
|
||||
// Therefore, we choose the file with the higher section level.
|
||||
if (selectedFile.pos.sectionDetail < dataFile.pos.sectionDetail) {
|
||||
if (isSet) selectedFiles.set(i, null);
|
||||
else selectedFiles.set(i, dataFile);
|
||||
isSet = true;
|
||||
} else {
|
||||
LodUtil.assertTrue(!isSet); // We should not have encountered a smaller section level.
|
||||
// This mean its completely covered by the selected file, so we can skip it.
|
||||
isDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isDuplicate && !isSet) selectedFiles.add(dataFile);
|
||||
}
|
||||
}
|
||||
if (topValidDataLevel == Byte.MIN_VALUE) return Collections.emptyList();
|
||||
selectedFiles.removeIf(Objects::isNull);
|
||||
return selectedFiles;
|
||||
public LodRenderSource createRender(LodDataSource dataSource, IClientLevel level) {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+31
-39
@@ -1,29 +1,35 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
|
||||
import com.seibel.lod.core.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnQuadView;
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.IColumnDatatype;
|
||||
import com.seibel.lod.core.a7.datatype.column.render.ColumnRenderBuffer;
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
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.LodDataView;
|
||||
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;
|
||||
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.datatype.LodRenderSource;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
public static final boolean DO_SAFETY_CHECKS = true;
|
||||
public static final byte SECTION_SIZE_OFFSET = 6;
|
||||
public static final int SECTION_SIZE = 1 << SECTION_SIZE_OFFSET;
|
||||
public static final int LATEST_VERSION = 10;
|
||||
public static final long DATA_TYPE_ID = "ColumnDatatype".hashCode();
|
||||
public static final byte LATEST_VERSION = 1;
|
||||
public static final long TYPE_ID = "ColumnRenderSource".hashCode();
|
||||
public static final int AIR_LODS_SIZE = 16;
|
||||
public static final int AIR_SECTION_SIZE = SECTION_SIZE/AIR_LODS_SIZE;
|
||||
|
||||
@@ -38,7 +44,7 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
* Constructor of the ColumnDataType
|
||||
* @param maxVerticalSize the maximum vertical size of the container
|
||||
*/
|
||||
public ColumnDatatype(DhSectionPos sectionPos, int maxVerticalSize, int yOffset) {
|
||||
public ColumnRenderSource(DhSectionPos sectionPos, int maxVerticalSize, int yOffset) {
|
||||
verticalSize = maxVerticalSize;
|
||||
dataContainer = new long[SECTION_SIZE * SECTION_SIZE * verticalSize];
|
||||
airDataContainer = new int[AIR_SECTION_SIZE * AIR_SECTION_SIZE * verticalSize];
|
||||
@@ -64,13 +70,13 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
bb.asLongBuffer().get(result);
|
||||
if (tempMinHeight != yOffset) {
|
||||
for (int i=0; i<result.length; i++) {
|
||||
result[i] = ColumnDataPoint.shiftHeightAndDepth(result[i], (short) (tempMinHeight - yOffset));
|
||||
result[i] = ColumnFormat.shiftHeightAndDepth(result[i], (short) (tempMinHeight - yOffset));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Load from data stream with maxVerticalSize loaded from the data stream
|
||||
public ColumnDatatype(DhSectionPos sectionPos, DataInputStream inputData, int version, DhClientServerLevel level) throws IOException {
|
||||
public ColumnRenderSource(DhSectionPos sectionPos, DataInputStream inputData, int version, ILevel level) throws IOException {
|
||||
this.sectionPos = sectionPos;
|
||||
yOffset = level.getMinY();
|
||||
byte detailLevel = inputData.readByte();
|
||||
@@ -87,7 +93,7 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
{
|
||||
for (int verticalIndex = 0; verticalIndex < verticalSize; verticalIndex++)
|
||||
dataContainer[posX * SECTION_SIZE * verticalSize + posZ * verticalSize + verticalIndex] =
|
||||
ColumnDataPoint.EMPTY_DATA;
|
||||
ColumnFormat.EMPTY_DATA;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +115,7 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
throw new IllegalArgumentException("Z position is out of bounds");
|
||||
}
|
||||
int index = posX * SECTION_SIZE * verticalSize + posZ * verticalSize;
|
||||
int compare = ColumnDataPoint.compareDatapointPriority(data.get(0), dataContainer[index]);
|
||||
int compare = ColumnFormat.compareDatapointPriority(data.get(0), dataContainer[index]);
|
||||
if (override) {
|
||||
if (compare<0) return false;
|
||||
} else {
|
||||
@@ -158,12 +164,11 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
@Override
|
||||
public boolean doesItExist(int posX, int posZ)
|
||||
{
|
||||
return ColumnDataPoint.doesItExist(getSingleData(posX, posZ));
|
||||
return ColumnFormat.doesItExist(getSingleData(posX, posZ));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void generateData(ColumnDatatype lowerDataContainer, int posX, int posZ)
|
||||
public void generateData(IColumnDatatype lowerDataContainer, int posX, int posZ)
|
||||
{
|
||||
ColumnQuadView quadView = lowerDataContainer.getDataInQuad(posX*2, posZ*2, 2,2);
|
||||
ColumnArrayView outputView = getVerticalDataView(posX, posZ);
|
||||
@@ -185,7 +190,7 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
long current = dataContainer[i * verticalSize + j];
|
||||
output.writeLong(Long.reverseBytes(current));
|
||||
}
|
||||
if (!ColumnDataPoint.doesItExist(dataContainer[i]))
|
||||
if (!ColumnFormat.doesItExist(dataContainer[i]))
|
||||
allGenerated = false;
|
||||
}
|
||||
return allGenerated;
|
||||
@@ -228,27 +233,10 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
return (long) dataContainer.length * Long.BYTES;
|
||||
}
|
||||
|
||||
public static ColumnRenderLoader COLUMN_LAYER_LOADER;
|
||||
|
||||
private static boolean hasRendered = false;
|
||||
public static void REGISTER() { //FIXME: THIS IS A MESS
|
||||
if (hasRendered) return;
|
||||
COLUMN_LAYER_LOADER = new ColumnRenderLoader();
|
||||
LodQuadTree.registerLayerLoader(COLUMN_LAYER_LOADER, (byte) 7); // 7 or above
|
||||
hasRendered = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceLoader getLatestLoader() {
|
||||
return ColumnDataLoader.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() {
|
||||
return sectionPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDataDetail() {
|
||||
return (byte) (sectionPos.sectionDetail - SECTION_SIZE_OFFSET);
|
||||
}
|
||||
@@ -264,11 +252,11 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
|
||||
private void tryBuildBuffer(LodQuadTree quadTree) {
|
||||
if (inBuildRenderBuffer == null) {
|
||||
ColumnDatatype[] data = new ColumnDatatype[ELodDirection.ADJ_DIRECTIONS.length];
|
||||
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
|
||||
if (section.getRenderContainer() != null && section.getRenderContainer() instanceof ColumnRenderBuffer) {
|
||||
data[direction.ordinal()-2] = ((ColumnDatatype) section.getRenderContainer());
|
||||
data[direction.ordinal()-2] = ((ColumnRenderSource) section.getRenderContainer());
|
||||
}
|
||||
}
|
||||
inBuildRenderBuffer = ColumnRenderBuffer.build(usedBuffer, this, data);
|
||||
@@ -305,7 +293,7 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot) {
|
||||
if (inBuildRenderBuffer != null && inBuildRenderBuffer.isDone()) {
|
||||
RenderBuffer oldBuffer = referenceSlot.getAndSet(inBuildRenderBuffer.join());
|
||||
if (oldBuffer != null && oldBuffer instanceof ColumnRenderBuffer) usedBuffer = (ColumnRenderBuffer) oldBuffer;
|
||||
if (oldBuffer instanceof ColumnRenderBuffer) usedBuffer = (ColumnRenderBuffer) oldBuffer;
|
||||
inBuildRenderBuffer = null;
|
||||
return true;
|
||||
} else {
|
||||
@@ -314,6 +302,10 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void saveRender(IClientLevel level, RenderMetaFile file, OutputStream dataStream) throws IOException {
|
||||
try (DataOutputStream dos = new DataOutputStream(dataStream)) {
|
||||
writeData(dos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
|
||||
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.save.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.DhClientServerLevel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public abstract class DataSourceSaver extends DataSourceLoader {
|
||||
public DataSourceSaver(Class<? extends LodDataSource> clazz, long datatypeId, byte[] loaderSupportedVersions) {
|
||||
super(clazz, datatypeId, loaderSupportedVersions);
|
||||
}
|
||||
|
||||
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, DhClientServerLevel level, DhSectionPos sectionPos) {
|
||||
return new File(levelFolderPath, String.format("%s_v%d-%s%s", clazz.getSimpleName(), getSaverVersion(),
|
||||
sectionPos.serialize(), DataFileHandler.FILE_EXTENSION));
|
||||
}
|
||||
|
||||
public byte getSaverVersion() {
|
||||
return loaderSupportedVersions[loaderSupportedVersions.length - 1];
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
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.DhClientServerLevel;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class OldColumnDatatype implements IColumnDatatype {
|
||||
public static final boolean DO_SAFETY_CHECKS = true;
|
||||
public static final int LATEST_VERSION = 10;
|
||||
public static final long DATA_TYPE_ID = "OldColumnDatatype".hashCode();
|
||||
|
||||
public final byte sectionSizeOffset;
|
||||
public final int getSectSize() {
|
||||
return 1 << sectionSizeOffset;
|
||||
}
|
||||
|
||||
public final int verticalSize;
|
||||
public final DhSectionPos sectionPos;
|
||||
public final int yOffset;
|
||||
public final long[] dataContainer;
|
||||
|
||||
/**
|
||||
* Constructor of the ColumnDataType
|
||||
* @param maxVerticalSize the maximum vertical size of the container
|
||||
*/
|
||||
public OldColumnDatatype(DhSectionPos sectionPos, int maxVerticalSize, int yOffset, int sectionSizeOffset) {
|
||||
this.sectionSizeOffset = (byte) sectionSizeOffset;
|
||||
verticalSize = maxVerticalSize;
|
||||
dataContainer = new long[getSectSize() * getSectSize() * verticalSize];
|
||||
this.sectionPos = sectionPos;
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
private long[] loadData(DataInputStream inputData, int version, int verticalSize) throws IOException {
|
||||
switch (version) {
|
||||
case 6:
|
||||
return readDataVersion6(inputData, verticalSize);
|
||||
case 7:
|
||||
return readDataVersion7(inputData, verticalSize);
|
||||
case 8:
|
||||
return readDataVersion8(inputData, verticalSize);
|
||||
case 9:
|
||||
case 10:
|
||||
return readDataVersion9(inputData, verticalSize);
|
||||
default:
|
||||
throw new IOException("Invalid Data: The version of the data is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
// Load from data stream with maxVerticalSize loaded from the data stream
|
||||
public OldColumnDatatype(DhSectionPos sectionPos, DataInputStream inputData, int version, DhClientServerLevel level, int sectionSizeOffset) throws IOException {
|
||||
this.sectionSizeOffset = (byte) sectionSizeOffset;
|
||||
this.sectionPos = sectionPos;
|
||||
yOffset = level.getMinY();
|
||||
byte detailLevel = inputData.readByte();
|
||||
if (sectionPos.sectionDetail - sectionSizeOffset != detailLevel) {
|
||||
throw new IOException("Invalid data: detail level does not match");
|
||||
}
|
||||
verticalSize = inputData.readByte() & 0b01111111;
|
||||
dataContainer = loadData(inputData, version, verticalSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDetailOffset() {
|
||||
return sectionSizeOffset;
|
||||
}
|
||||
|
||||
public void clear(int posX, int posZ)
|
||||
{
|
||||
throw new UnsupportedOperationException("OldColumnDatatype only supports read-only access." +
|
||||
" Convert to ColumnDatatype first before doing any modifications.");
|
||||
}
|
||||
|
||||
public boolean addData(long data, int posX, int posZ, int verticalIndex)
|
||||
{
|
||||
throw new UnsupportedOperationException("OldColumnDatatype only supports read-only access." +
|
||||
" Convert to ColumnDatatype first before doing any modifications.");
|
||||
}
|
||||
|
||||
public boolean copyVerticalData(LodDataView data, int posX, int posZ, boolean override) {
|
||||
throw new UnsupportedOperationException("OldColumnDatatype only supports read-only access." +
|
||||
" Convert to ColumnDatatype first before doing any modifications.");
|
||||
}
|
||||
|
||||
public long getData(int posX, int posZ, int verticalIndex)
|
||||
{
|
||||
return dataContainer[posX * getSectSize() * verticalSize + posZ * verticalSize + verticalIndex];
|
||||
}
|
||||
|
||||
public long[] getAllData(int posX, int posZ)
|
||||
{
|
||||
long[] result = new long[verticalSize];
|
||||
int index = posX * getSectSize() * verticalSize + posZ * verticalSize;
|
||||
System.arraycopy(dataContainer, index, result, 0, verticalSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ColumnArrayView getVerticalDataView(int posX, int posZ) {
|
||||
return new ColumnArrayView(dataContainer, verticalSize,
|
||||
posX * getSectSize() * verticalSize + posZ * verticalSize, verticalSize);
|
||||
}
|
||||
|
||||
public ColumnQuadView getDataInQuad(int quadX, int quadZ, int quadXSize, int quadZSize) {
|
||||
return new ColumnQuadView(dataContainer, getSectSize(), verticalSize, quadX, quadZ, quadXSize, quadZSize);
|
||||
}
|
||||
public ColumnQuadView getFullQuad() {
|
||||
return new ColumnQuadView(dataContainer, getSectSize(), verticalSize, 0, 0, getSectSize(), getSectSize());
|
||||
}
|
||||
|
||||
public int getVerticalSize()
|
||||
{
|
||||
return verticalSize;
|
||||
}
|
||||
|
||||
public boolean doesItExist(int posX, int posZ)
|
||||
{
|
||||
return ColumnDataPoint.doesItExist(getSingleData(posX, posZ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateData(ColumnDatatype lowerDataContainer, int posX, int posZ) {
|
||||
throw new UnsupportedOperationException("OldColumnDatatype only supports read-only access." +
|
||||
" Convert to ColumnDatatype first before doing any modifications.");
|
||||
}
|
||||
|
||||
private long[] readDataVersion6(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
|
||||
int x = getSectSize() * getSectSize() * tempMaxVerticalData;
|
||||
byte[] data = new byte[x * Long.BYTES];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
inputData.readFully(data);
|
||||
long[] result = new long[x];
|
||||
bb.asLongBuffer().get(result);
|
||||
patchVersion9Reorder(result);
|
||||
patchHeightAndDepth(result,-yOffset);
|
||||
return result;
|
||||
}
|
||||
private long[] readDataVersion7(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
|
||||
int x = getSectSize() * getSectSize() * tempMaxVerticalData;
|
||||
byte[] data = new byte[x * Long.BYTES];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
inputData.readFully(data);
|
||||
long[] result = new long[x];
|
||||
bb.asLongBuffer().get(result);
|
||||
patchVersion9Reorder(result);
|
||||
patchHeightAndDepth(result, 64 - yOffset);
|
||||
return result;
|
||||
}
|
||||
private long[] readDataVersion8(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
|
||||
int x = getSectSize() * getSectSize() * tempMaxVerticalData;
|
||||
byte[] data = new byte[x * Long.BYTES];
|
||||
short tempMinHeight = Short.reverseBytes(inputData.readShort());
|
||||
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
inputData.readFully(data);
|
||||
long[] result = new long[x];
|
||||
bb.asLongBuffer().get(result);
|
||||
patchVersion9Reorder(result);
|
||||
if (tempMinHeight != yOffset) {
|
||||
patchHeightAndDepth(result,tempMinHeight - yOffset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private long[] readDataVersion9(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
|
||||
int x = getSectSize() * getSectSize() * tempMaxVerticalData;
|
||||
byte[] data = new byte[x * Long.BYTES];
|
||||
short tempMinHeight = Short.reverseBytes(inputData.readShort());
|
||||
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
inputData.readFully(data);
|
||||
long[] result = new long[x];
|
||||
bb.asLongBuffer().get(result);
|
||||
if (tempMinHeight != yOffset) {
|
||||
patchHeightAndDepth(result,tempMinHeight - yOffset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void patchHeightAndDepth(long[] data, int offset) {
|
||||
for (int i=0; i<data.length; i++) {
|
||||
data[i] = ColumnDataPoint.shiftHeightAndDepth(data[i], (short)offset);
|
||||
}
|
||||
}
|
||||
|
||||
private static void patchVersion9Reorder(long[] data) {
|
||||
for (int i=0; i<data.length; i++) {
|
||||
data[i] = ColumnDataPoint.version9Reorder(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String LINE_DELIMITER = "\n";
|
||||
String DATA_DELIMITER = " ";
|
||||
String SUBDATA_DELIMITER = ",";
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
int size = sectionPos.getWidth().value;
|
||||
stringBuilder.append(sectionPos);
|
||||
stringBuilder.append("(LEGACY-READ-ONLY)");
|
||||
stringBuilder.append(LINE_DELIMITER);
|
||||
for (int z = 0; z < size; z++)
|
||||
{
|
||||
for (int x = 0; x < size; x++)
|
||||
{
|
||||
for (int y = 0; y < verticalSize; y++) {
|
||||
//Converting the dataToHex
|
||||
stringBuilder.append(Long.toHexString(getData(x,z,y)));
|
||||
if (y != verticalSize-1) stringBuilder.append(SUBDATA_DELIMITER);
|
||||
}
|
||||
if (x != size-1) stringBuilder.append(DATA_DELIMITER);
|
||||
}
|
||||
if (z != size-1) stringBuilder.append(LINE_DELIMITER);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxNumberOfLods()
|
||||
{
|
||||
return getSectSize() * getSectSize() * getVerticalSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRoughRamUsage()
|
||||
{
|
||||
return (long) dataContainer.length * Long.BYTES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceLoader getLatestLoader() {
|
||||
return Alpha6DataLoader.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() {
|
||||
return sectionPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDataDetail() {
|
||||
return (byte) (sectionPos.sectionDetail - sectionSizeOffset);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
|
||||
import com.seibel.lod.core.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
|
||||
public abstract class OldDataSourceLoader extends DataSourceLoader {
|
||||
|
||||
// Note: clazz can be null if the class no longer exists, as long as
|
||||
// the datatypeId have not been changed or overwritten.
|
||||
public OldDataSourceLoader(Class<? extends LodDataSource> clazz, long datatypeId, byte[] loaderVersions) {
|
||||
super(clazz, datatypeId, loaderVersions);
|
||||
}
|
||||
abstract public DataSourceSaver getNewSaver();
|
||||
}
|
||||
+7
-5
@@ -1,6 +1,8 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
package com.seibel.lod.core.a7.datatype.column.accessor;
|
||||
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnFormat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class ColumnArrayView implements ColumnDataView {
|
||||
@@ -78,12 +80,12 @@ public final class ColumnArrayView implements ColumnDataView {
|
||||
boolean anyChange = false;
|
||||
for (int o=0; o<(source.size()*vertSize); o+=vertSize) {
|
||||
if (override) {
|
||||
if (ColumnDataPoint.compareDatapointPriority(source.get(o), get(o)) >= 0) {
|
||||
if (ColumnFormat.compareDatapointPriority(source.get(o), get(o)) >= 0) {
|
||||
anyChange = true;
|
||||
System.arraycopy(source.data, source.offset+o, data, offset+o, vertSize);
|
||||
}
|
||||
} else {
|
||||
if (ColumnDataPoint.compareDatapointPriority(source.get(o), get(o)) > 0) {
|
||||
if (ColumnFormat.compareDatapointPriority(source.get(o), get(o)) > 0) {
|
||||
anyChange = true;
|
||||
System.arraycopy(source.data, source.offset+o, data, offset+o, vertSize);
|
||||
}
|
||||
@@ -100,7 +102,7 @@ public final class ColumnArrayView implements ColumnDataView {
|
||||
copyFrom(source);
|
||||
} else {
|
||||
for (int i=0; i<dataCount(); i++) {
|
||||
ColumnDataPoint.mergeMultiData(source.subView(i, 1), subView(i, 1));
|
||||
ColumnFormat.mergeMultiData(source.subView(i, 1), subView(i, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,6 +111,6 @@ public final class ColumnArrayView implements ColumnDataView {
|
||||
if (dataCount() != 1) {
|
||||
throw new IllegalArgumentException("output dataCount must be 1");
|
||||
}
|
||||
ColumnDataPoint.mergeMultiData(source, this);
|
||||
ColumnFormat.mergeMultiData(source, this);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
package com.seibel.lod.core.a7.datatype.column.accessor;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
package com.seibel.lod.core.a7.datatype.column.accessor;
|
||||
|
||||
public class ColumnQuadView implements ColumnDataView {
|
||||
private final long[] data;
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
package com.seibel.lod.core.a7.datatype.column.accessor;
|
||||
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
|
||||
public interface IColumnDatatype extends LodDataSource {
|
||||
public interface IColumnDatatype {
|
||||
byte getDetailOffset();
|
||||
default int getDataSize() {
|
||||
return 1 << getDetailOffset();
|
||||
@@ -33,5 +32,5 @@ public interface IColumnDatatype extends LodDataSource {
|
||||
* @param override if override is true we can override data created with same generation mode
|
||||
*/
|
||||
boolean copyVerticalData(LodDataView data, int posX, int posZ, boolean override);
|
||||
void generateData(ColumnDatatype lowerDataContainer, int posX, int posZ);
|
||||
void generateData(IColumnDatatype lowerDataContainer, int posX, int posZ);
|
||||
}
|
||||
+2
-1
@@ -17,8 +17,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
package com.seibel.lod.core.a7.datatype.column.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
|
||||
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
+7
-5
@@ -1,6 +1,8 @@
|
||||
package com.seibel.lod.core.a7.datatype.column;
|
||||
package com.seibel.lod.core.a7.datatype.column.render;
|
||||
|
||||
import com.seibel.lod.core.a7.UncheckedInterruptedException;
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
|
||||
import com.seibel.lod.core.a7.util.UncheckedInterruptedException;
|
||||
import com.seibel.lod.core.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.api.internal.ClientApi;
|
||||
@@ -180,7 +182,7 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
}
|
||||
|
||||
|
||||
public static CompletableFuture<ColumnRenderBuffer> build(ColumnRenderBuffer usedBuffer, ColumnDatatype data, ColumnDatatype[] adjData) {
|
||||
public static CompletableFuture<ColumnRenderBuffer> build(ColumnRenderBuffer usedBuffer, ColumnRenderSource data, ColumnRenderSource[] adjData) {
|
||||
EVENT_LOGGER.trace("RenderRegion startBuild @ {}", data.sectionPos);
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
@@ -236,7 +238,7 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
|
||||
|
||||
|
||||
private static void makeLodRenderData(LodQuadBuilder quadBuilder, ColumnDatatype region, ColumnDatatype[] adjRegions) {
|
||||
private static void makeLodRenderData(LodQuadBuilder quadBuilder, ColumnRenderSource region, ColumnRenderSource[] adjRegions) {
|
||||
|
||||
// Variable initialization
|
||||
EDebugMode debugMode = Config.Client.Advanced.Debugging.debugMode.get();
|
||||
@@ -274,7 +276,7 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
int zAdj = z + lodDirection.getNormal().z;
|
||||
boolean isCrossRegionBoundary = (xAdj < 0 || xAdj >= dataSize) ||
|
||||
(zAdj < 0 || zAdj >= dataSize);
|
||||
ColumnDatatype adjRegion;
|
||||
ColumnRenderSource adjRegion;
|
||||
byte adjDetail;
|
||||
|
||||
//we check if the detail of the adjPos is equal to the correct one (region border fix)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
package com.seibel.lod.core.a7.datatype.full;
|
||||
|
||||
// Static class for the data format:
|
||||
// ID: blockState id Y: Height(signed) DP: Depth(signed?)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
package com.seibel.lod.core.a7.datatype.full;
|
||||
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.seibel.lod.core.a7.datatype.full;
|
||||
|
||||
import com.seibel.lod.core.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
|
||||
public class FullDatatype implements LodDataSource {
|
||||
@Override
|
||||
public DataSourceLoader getLatestLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDataDetail() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+26
-11
@@ -1,25 +1,25 @@
|
||||
package com.seibel.lod.core.a7.data;
|
||||
package com.seibel.lod.core.a7.datatype.full;
|
||||
|
||||
import com.seibel.lod.core.a7.IdMappingUtil;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
|
||||
import com.seibel.lod.core.a7.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.util.IdMappingUtil;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CompleteDataContainer implements LodDataSource { // 1 chunk
|
||||
public class FullFormat implements LodDataSource { // 1 chunk
|
||||
private DhSectionPos sectionPos;
|
||||
ArrayList<String> idMap;
|
||||
|
||||
protected CompleteDataContainer() {
|
||||
protected FullFormat() {
|
||||
idMap = new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceLoader getLatestLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() {
|
||||
return sectionPos;
|
||||
@@ -30,8 +30,23 @@ public class CompleteDataContainer implements LodDataSource { // 1 chunk
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static CompleteDataContainer createNewFromChunk(IChunkWrapper chunk) {
|
||||
CompleteDataContainer dataContainer = new CompleteDataContainer();
|
||||
@Override
|
||||
public void setLocalVersion(int localVer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDataVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData(ILevel level, DataMetaFile file, OutputStream dataStream) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
public static FullFormat createNewFromChunk(IChunkWrapper chunk) {
|
||||
FullFormat dataContainer = new FullFormat();
|
||||
HashMap<String, Integer> idMap = new HashMap<String, Integer>();
|
||||
|
||||
idMap.put(IdMappingUtil.BLOCKSTATE_ID_AIR, 0);
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
package com.seibel.lod.core.a7.datatype.full;
|
||||
|
||||
import com.seibel.lod.core.a7.render.LodSection;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.save.io.FileScanner;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.util.FileScanner;
|
||||
import com.seibel.lod.core.a7.save.io.file.RemoteDataFileHandler;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderFileHandler;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
@@ -15,7 +15,6 @@ 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.Scanner;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhClientLevel implements IClientLevel {
|
||||
@@ -49,12 +48,6 @@ public class DhClientLevel implements IClientLevel {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startRenderer() {
|
||||
//TODO
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
|
||||
if (renderer == null) {
|
||||
@@ -63,12 +56,6 @@ public class DhClientLevel implements IClientLevel {
|
||||
renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRenderer() {
|
||||
//TODO
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderBufferHandler getRenderBufferHandler() {
|
||||
return renderBufferHandler;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.save.io.FileScanner;
|
||||
import com.seibel.lod.core.a7.render.LodQuadTree;
|
||||
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.io.render.RenderFileHandler;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
@@ -38,12 +38,14 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel {
|
||||
FileScanner.scanFile(save, level, dataFileHandler, renderFileHandler);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
public void clientTick() {
|
||||
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
renderBufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverTick() {
|
||||
//TODO Update network packet and stuff or state or etc..
|
||||
}
|
||||
public void startRenderer() {
|
||||
//TODO
|
||||
}
|
||||
@@ -56,7 +58,6 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel {
|
||||
renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRenderer() {
|
||||
renderFileHandler.flushAndSave(); //Ignore the completion feature so that this action is async
|
||||
//TODO
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
import com.seibel.lod.core.a7.save.io.FileScanner;
|
||||
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.wrapperInterfaces.world.ILevelWrapper;
|
||||
@@ -19,7 +19,7 @@ public class DhServerLevel implements IServerLevel {
|
||||
FileScanner.scanFile(save, level, dataFileHandler, null);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
public void serverTick() {
|
||||
//Nothing for now
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
|
||||
public interface IClientLevel extends ILevel {
|
||||
void startRenderer();
|
||||
void clientTick();
|
||||
|
||||
void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler);
|
||||
void stopRenderer();
|
||||
|
||||
RenderBufferHandler getRenderBufferHandler();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.seibel.lod.core.a7.level;
|
||||
|
||||
public interface IServerLevel extends ILevel {
|
||||
void serverTick();
|
||||
void doWorldGen();
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class EmptyRenderContainer implements RenderDataSource {
|
||||
public static final EmptyRenderContainer INSTANCE = new EmptyRenderContainer();
|
||||
|
||||
// NOTE: No register() needed since this should never be loaded from a actual data.
|
||||
|
||||
|
||||
@Override
|
||||
public void enableRender(LodQuadTree quadTree) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableRender() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDetailOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot) {
|
||||
return false; // no swap
|
||||
}
|
||||
}
|
||||
+18
-19
@@ -1,9 +1,9 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnDatatype;
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSourceLoader;
|
||||
import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
@@ -34,11 +34,11 @@ public class LodQuadTree {
|
||||
public final byte startingSectionLevel;
|
||||
private final MovableGridRingList<LodSection>[] ringLists;
|
||||
|
||||
static final ArrayList<RenderDataSourceLoader> layerLoaderConfig = new ArrayList<>();
|
||||
static final ArrayList<RenderSourceLoader> layerLoaderConfig = new ArrayList<>();
|
||||
|
||||
static final Logger LOGGER = DhLoggerBuilder.getLogger("LodQuadTree");
|
||||
|
||||
public static void registerLayerLoader(RenderDataSourceLoader loader, byte sectionLevel) {
|
||||
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);
|
||||
@@ -65,8 +65,8 @@ public class LodQuadTree {
|
||||
|
||||
static class SectionDetailLayer {
|
||||
final byte targetDataDetail;
|
||||
final RenderDataSourceLoader containerType;
|
||||
public SectionDetailLayer(byte targetDataDetail, RenderDataSourceLoader containerType) {
|
||||
final RenderSourceLoader containerType;
|
||||
public SectionDetailLayer(byte targetDataDetail, RenderSourceLoader containerType) {
|
||||
this.targetDataDetail = targetDataDetail;
|
||||
this.containerType = containerType;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class LodQuadTree {
|
||||
for (int i = 0; i < layerLoaderConfig.size(); i++) {
|
||||
if (layerLoaderConfig.get(i) == null) continue;
|
||||
isInFront = false;
|
||||
RenderDataSourceLoader entry = layerLoaderConfig.get(i);
|
||||
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) + "," +
|
||||
@@ -95,7 +95,7 @@ public class LodQuadTree {
|
||||
|
||||
final SectionDetailLayer[] sectionDetailLayers;
|
||||
public final int viewDistance;
|
||||
private final RenderDataProvider renderDataProvider;
|
||||
private final IRenderSourceProvider renderSourceProvider;
|
||||
|
||||
/**
|
||||
* Constructor of the quadTree
|
||||
@@ -103,9 +103,8 @@ public class LodQuadTree {
|
||||
* @param initialPlayerX player x coordinate
|
||||
* @param initialPlayerZ player z coordinate
|
||||
*/
|
||||
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;
|
||||
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ, IRenderSourceProvider provider) {
|
||||
renderSourceProvider = provider;
|
||||
|
||||
assertContainerTypeConfigCorrect();
|
||||
this.viewDistance = viewDistance;
|
||||
@@ -113,7 +112,7 @@ public class LodQuadTree {
|
||||
//FIXME: Rework this mess of code!
|
||||
{ // Calculate the max section detail
|
||||
byte maxDetailLevel = getMaxDetailInRange(viewDistance * Math.sqrt(2));
|
||||
RenderDataSourceLoader finalEntry = null;
|
||||
RenderSourceLoader finalEntry = null;
|
||||
byte topSectionLevel = 0;
|
||||
byte firstLevel = -1;
|
||||
for (; topSectionLevel < layerLoaderConfig.size(); topSectionLevel++) {
|
||||
@@ -137,7 +136,7 @@ public class LodQuadTree {
|
||||
byte lastNonNullEntry = -1;
|
||||
for (byte i = startingSectionLevel; i < numbersOfSectionLevels; i++) {
|
||||
byte targetDataDetail;
|
||||
RenderDataSourceLoader containerType;
|
||||
RenderSourceLoader containerType;
|
||||
|
||||
if (i < layerLoaderConfig.size()) {
|
||||
if (layerLoaderConfig.get(i) == null) {
|
||||
@@ -146,14 +145,14 @@ public class LodQuadTree {
|
||||
containerType = null;
|
||||
} else {
|
||||
lastNonNullEntry = i;
|
||||
RenderDataSourceLoader entry = layerLoaderConfig.get(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!");
|
||||
RenderDataSourceLoader entry = layerLoaderConfig.get(layerLoaderConfig.size() - 1);
|
||||
RenderSourceLoader entry = layerLoaderConfig.get(layerLoaderConfig.size() - 1);
|
||||
targetDataDetail = (byte) (i - entry.detailOffset);
|
||||
containerType = entry;
|
||||
}
|
||||
@@ -326,7 +325,7 @@ public class LodQuadTree {
|
||||
final MovableGridRingList<LodSection> parentRingList =
|
||||
sectLevel == numbersOfSectionLevels - 1 ? null : ringLists[sectLevel - startingSectionLevel + 1];
|
||||
final byte f_sectLevel = sectLevel;
|
||||
RenderDataSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (f_sectLevel == 0 && section != null) {
|
||||
section.childCount = 0;
|
||||
@@ -418,7 +417,7 @@ public class LodQuadTree {
|
||||
final MovableGridRingList<LodSection> childRingList =
|
||||
sectLevel == startingSectionLevel ? null : ringLists[sectLevel - startingSectionLevel - 1];
|
||||
final boolean doCacsade = sectionDetailLayers[sectLevel - startingSectionLevel].containerType == null;
|
||||
RenderDataSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType;
|
||||
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (section == null) return;
|
||||
@@ -464,7 +463,7 @@ public class LodQuadTree {
|
||||
section.dispose();
|
||||
} else {
|
||||
if (!section.isLoaded() && !section.isLoading()) {
|
||||
section.load(renderDataProvider, containerType);
|
||||
section.load(renderSourceProvider, containerType);
|
||||
}
|
||||
if (section.childCount == 4) section.enableRender(this);
|
||||
if (section.childCount == 0) section.disableRender();
|
||||
+20
-19
@@ -1,8 +1,9 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
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.render.RenderDataSource;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -17,8 +18,8 @@ public class LodSection {
|
||||
public byte childCount = 0;
|
||||
|
||||
// TODO: Should I provide a way to change the render source?
|
||||
private RenderDataSource renderDataSource;
|
||||
private CompletableFuture<RenderDataSource> loadFuture;
|
||||
private LodRenderSource lodRenderSource;
|
||||
private CompletableFuture<LodRenderSource> loadFuture;
|
||||
private boolean isRenderEnabled = false;
|
||||
|
||||
// Create sub region
|
||||
@@ -28,56 +29,56 @@ public class LodSection {
|
||||
|
||||
public void enableRender(LodQuadTree quadTree) {
|
||||
if (isRenderEnabled) return;
|
||||
if (renderDataSource != null) {
|
||||
renderDataSource.enableRender(quadTree);
|
||||
if (lodRenderSource != null) {
|
||||
lodRenderSource.enableRender(quadTree);
|
||||
}
|
||||
isRenderEnabled = true;
|
||||
}
|
||||
public void disableRender() {
|
||||
if (!isRenderEnabled) return;
|
||||
if (renderDataSource != null) {
|
||||
renderDataSource.disableRender();
|
||||
if (lodRenderSource != null) {
|
||||
lodRenderSource.disableRender();
|
||||
}
|
||||
isRenderEnabled = false;
|
||||
}
|
||||
|
||||
public void load(RenderDataProvider renderDataProvider, RenderDataSourceLoader renderDataSourceClass) {
|
||||
if (loadFuture != null || renderDataSource != null) throw new IllegalStateException("Reloading is not supported!");
|
||||
public void load(IRenderSourceProvider renderDataProvider, RenderSourceLoader renderDataSourceClass) {
|
||||
if (loadFuture != null || lodRenderSource != null) throw new IllegalStateException("Reloading is not supported!");
|
||||
loadFuture = renderDataProvider.createRenderData(renderDataSourceClass, pos);
|
||||
}
|
||||
|
||||
public void tick(LodQuadTree quadTree) {
|
||||
if (loadFuture != null && loadFuture.isDone()) {
|
||||
renderDataSource = loadFuture.join();
|
||||
lodRenderSource = loadFuture.join();
|
||||
loadFuture = null;
|
||||
if (isRenderEnabled) {
|
||||
renderDataSource.enableRender(quadTree);
|
||||
lodRenderSource.enableRender(quadTree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (renderDataSource != null) {
|
||||
renderDataSource.dispose();
|
||||
if (lodRenderSource != null) {
|
||||
lodRenderSource.dispose();
|
||||
} else if (loadFuture != null) {
|
||||
loadFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canRender() {
|
||||
return isLoaded() && renderDataSource.isRenderReady();
|
||||
return isLoaded() && lodRenderSource.isRenderReady();
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return renderDataSource != null;
|
||||
return lodRenderSource != null;
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
return loadFuture != null;
|
||||
}
|
||||
|
||||
public RenderDataSource getRenderContainer() {
|
||||
return renderDataSource;
|
||||
public LodRenderSource getRenderContainer() {
|
||||
return lodRenderSource;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.objects.Pos2D;
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.a7.LodSection;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.render.LodRenderProgram;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
@@ -45,7 +44,7 @@ public class RenderBufferHandler {
|
||||
// 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);
|
||||
RenderDataSource container = section.getRenderContainer();
|
||||
LodRenderSource container = section.getRenderContainer();
|
||||
|
||||
// Update self's render buffer state
|
||||
boolean shouldRender = section.isLoaded();
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.seibel.lod.core.a7.render;
|
||||
|
||||
import com.seibel.lod.core.a7.LodQuadTree;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Example on how to register a loader:
|
||||
* <pre>
|
||||
public static RenderDataSource testAndConstruct(LodDataSource dataSource, DhSectionPos sectionPos) {
|
||||
ColumnRenderContainer container = new ColumnRenderContainer(10, -100);
|
||||
container.startFillData(dataSource);
|
||||
return container;
|
||||
}
|
||||
static {
|
||||
RenderDataSource.registorLoader(ColumnRenderContainer::testAndConstruct, 0);
|
||||
}
|
||||
</pre>
|
||||
*/
|
||||
public interface RenderDataSource {
|
||||
// Don't think this is needed with the newer quad tree structure...
|
||||
// interface RenderContainerConstructor {
|
||||
// // Can return null as meaning the requirement is not met
|
||||
// RenderDataSource testAndConstruct(LodDataSource dataSource, DhSectionPos sectionPos);
|
||||
// }
|
||||
// SortedMap<Integer, RenderContainerConstructor>
|
||||
// renderContainerLoaderRegistry = new TreeMap<Integer, RenderContainerConstructor>();
|
||||
// static void registorLoader(RenderContainerConstructor func, int priority) {
|
||||
// if (func == null) {
|
||||
// throw new IllegalArgumentException("loader must be non-null");
|
||||
// }
|
||||
// renderContainerLoaderRegistry.put(priority, func);
|
||||
// }
|
||||
//
|
||||
// static RenderDataSource tryConstruct(LodDataSource dataSource, DhSectionPos pos) {
|
||||
// for (RenderContainerConstructor func : renderContainerLoaderRegistry.values()) {
|
||||
// RenderDataSource container = func.testAndConstruct(dataSource, pos);
|
||||
// if (container != null) {
|
||||
// return container;
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
void enableRender(LodQuadTree quadTree);
|
||||
void disableRender();
|
||||
boolean isRenderReady();
|
||||
void dispose(); // notify the container that the parent lodSection is now disposed (can be in loaded or unloaded state)
|
||||
|
||||
byte getDetailOffset();
|
||||
|
||||
/**
|
||||
* Try and swap in new render buffer for this section. Note that before this call, there should be no other
|
||||
* places storing or referencing the render buffer.
|
||||
* @param referenceSlot The slot for swapping in the new buffer.
|
||||
* @return True if the swap was successful. False if swap is not needed or if it is in progress.
|
||||
*/
|
||||
boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot);
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
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.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.data.DataFile;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class RenderDataSourceLoader {
|
||||
public final int detailOffset;
|
||||
public RenderDataSourceLoader(int detailOffset) {
|
||||
this.detailOffset = detailOffset;
|
||||
}
|
||||
|
||||
public abstract RenderDataSource construct(List<LodDataSource> dataSources, DhSectionPos sectionPos, DhClientServerLevel level);
|
||||
|
||||
public List<DataFile> selectFiles(DhSectionPos sectionPos, DhClientServerLevel level, List<DataFile>[] availableFiles) {
|
||||
return Arrays.stream(availableFiles).flatMap(Collection::stream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.seibel.lod.core.a7.save.io;
|
||||
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.enums.config.EServerFolderNameMode;
|
||||
import com.seibel.lod.core.handlers.LodDimensionFinder;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.lod.core.objects.ParsedIp;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class DHFolderHandler {
|
||||
/**
|
||||
* This regex finds any characters that are invalid for use in a windows
|
||||
* (and by extension mac and linux) file path
|
||||
*/
|
||||
public static final String INVALID_FILE_CHARACTERS_REGEX = "[\\\\/:*?\"<>|]";
|
||||
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(LodDimensionFinder.class),
|
||||
() -> Config.Client.Advanced.Debugging.DebugSwitch.logFileSubDimEvent.get());
|
||||
|
||||
public static File getCurrentWorldFolder() {
|
||||
File dimensionFolder;
|
||||
try
|
||||
{
|
||||
if (MC.hasSinglePlayerServer())
|
||||
{
|
||||
// local world
|
||||
dimensionFolder = new File(MC.getSinglePlayerServerFolder(), "lod");
|
||||
}
|
||||
else
|
||||
{
|
||||
// multiplayer world
|
||||
dimensionFolder = new File(MC.getGameDirectory().getCanonicalFile().getPath() +
|
||||
File.separatorChar + "Distant_Horizons_server_data" + File.separatorChar + getServerFolderName());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.error("Unable to get world folder directory: ", e);
|
||||
throw new RuntimeException("Critical error: Unable to get world folder directory", e);
|
||||
}
|
||||
|
||||
return dimensionFolder;
|
||||
}
|
||||
private static String getServerFolderName()
|
||||
{
|
||||
// parse the current server's IP
|
||||
ParsedIp parsedIp = new ParsedIp(MC.getCurrentServerIp());
|
||||
String serverIpCleaned = parsedIp.ip.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverPortCleaned = parsedIp.port != null ? parsedIp.port.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "") : "";
|
||||
|
||||
|
||||
// determine the format of the folder name
|
||||
EServerFolderNameMode folderNameMode = Config.Client.Multiplayer.serverFolderNameMode.get();
|
||||
if (folderNameMode == EServerFolderNameMode.AUTO)
|
||||
{
|
||||
if (parsedIp.isLan())
|
||||
{
|
||||
// LAN
|
||||
folderNameMode = EServerFolderNameMode.NAME_IP;
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal multiplayer
|
||||
folderNameMode = EServerFolderNameMode.NAME_IP_PORT;
|
||||
}
|
||||
}
|
||||
String serverName = MC.getCurrentServerName().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverMcVersion = MC.getCurrentServerVersion().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
// generate the folder name
|
||||
String folderName = "";
|
||||
switch (folderNameMode)
|
||||
{
|
||||
// default and auto shouldn't be used
|
||||
// and are just here to make the compiler happy
|
||||
default:
|
||||
case AUTO:
|
||||
case NAME_ONLY:
|
||||
folderName = serverName;
|
||||
break;
|
||||
|
||||
case NAME_IP:
|
||||
folderName = serverName + ", IP " + serverIpCleaned;
|
||||
break;
|
||||
case NAME_IP_PORT:
|
||||
folderName = serverName + ", IP " + serverIpCleaned + (serverPortCleaned.length() != 0 ? ("-" + serverPortCleaned) : "");
|
||||
break;
|
||||
case NAME_IP_PORT_MC_VERSION:
|
||||
folderName = serverName + ", IP " + serverIpCleaned + (serverPortCleaned.length() != 0 ? ("-" + serverPortCleaned) : "") + ", GameVersion " + serverMcVersion;
|
||||
break;
|
||||
}
|
||||
|
||||
return folderName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import java.util.function.BiConsumer;
|
||||
import java.util.zip.Adler32;
|
||||
import java.util.zip.CheckedOutputStream;
|
||||
|
||||
import com.seibel.lod.core.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class MetaFile {
|
||||
//Loader stuff
|
||||
public DataSourceLoader loader;
|
||||
public Class<?> dataType;
|
||||
public byte loaderVersion;
|
||||
public byte dataVersion;
|
||||
|
||||
// Load a metaFile in this path. It also automatically read the metadata.
|
||||
protected MetaFile(File path) throws IOException {
|
||||
@@ -80,7 +80,7 @@ public class MetaFile {
|
||||
throw new IOException("Invalid file: Data type loader not found: " + dataTypeId + "(v" + loaderVersion + ")");
|
||||
}
|
||||
this.dataType = loader.clazz;
|
||||
this.loaderVersion = loaderVersion;
|
||||
this.dataVersion = loaderVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public class MetaFile {
|
||||
throw new IOException("Invalid file: Data type loader not found: " + dataTypeId + "(v" + loaderVersion + ")");
|
||||
}
|
||||
this.dataType = loader.clazz;
|
||||
this.loaderVersion = loaderVersion;
|
||||
this.dataVersion = loaderVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public class MetaFile {
|
||||
buff.putInt(checksum);
|
||||
buff.put(pos.sectionDetail);
|
||||
buff.put(dataLevel);
|
||||
buff.put(loaderVersion);
|
||||
buff.put(dataVersion);
|
||||
buff.put(Byte.MIN_VALUE); // Unused
|
||||
buff.putLong(loader.datatypeId);
|
||||
buff.putLong(timestamp);
|
||||
|
||||
@@ -9,17 +9,14 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
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.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.DataSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.full.Data;
|
||||
import com.seibel.lod.core.a7.save.io.MetaFile;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
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;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -39,13 +36,13 @@ public class DataMetaFile extends MetaFile {
|
||||
//TODO: use ConcurrentAppendSingleSwapContainer<LodDataSource> instead of below:
|
||||
private static class GuardedMultiAppendQueue {
|
||||
ReentrantReadWriteLock appendLock = new ReentrantReadWriteLock();
|
||||
ConcurrentLinkedQueue<FullDatatype> queue = new ConcurrentLinkedQueue<>();
|
||||
ConcurrentLinkedQueue<Data> queue = new ConcurrentLinkedQueue<>();
|
||||
}
|
||||
AtomicReference<GuardedMultiAppendQueue> writeQueue =
|
||||
new AtomicReference<>(new GuardedMultiAppendQueue());
|
||||
GuardedMultiAppendQueue _backQueue = new GuardedMultiAppendQueue();
|
||||
|
||||
public void addToWriteQueue(FullDatatype datatype) {
|
||||
public void addToWriteQueue(Data datatype) {
|
||||
GuardedMultiAppendQueue queue = writeQueue.get();
|
||||
// Using read lock is OK, because the queue's underlying data structure is thread-safe.
|
||||
// This lock is only used to insure on polling the queue, that the queue is not being
|
||||
@@ -205,25 +202,18 @@ public class DataMetaFile extends MetaFile {
|
||||
}
|
||||
|
||||
private void write(LodDataSource data) {
|
||||
DataSourceSaver saver;
|
||||
if (loader instanceof DataSourceSaver) saver = (DataSourceSaver) loader;
|
||||
else if (loader instanceof OldDataSourceLoader) saver = ((OldDataSourceLoader) loader).getNewSaver();
|
||||
else saver = null;
|
||||
if (saver == null) return;
|
||||
|
||||
BiConsumer<MetaFile, OutputStream> dataWriter = (meta, out) -> {
|
||||
meta.dataLevel = data.getDataDetail();
|
||||
meta.dataType = DataSourceLoader.datatypeIdRegistry.get(saver.datatypeId);
|
||||
meta.loader = saver;
|
||||
meta.loaderVersion = saver.getSaverVersion();
|
||||
try {
|
||||
saver.saveData(level, data, this, out);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to save data for file {}", path, e);
|
||||
}
|
||||
};
|
||||
try {
|
||||
super.writeData(dataWriter);
|
||||
super.writeData((meta, out) -> {
|
||||
meta.dataLevel = data.getDataDetail();
|
||||
meta.dataType = data.getClass();
|
||||
meta.loader = DataSourceLoader.getLoader(data.getClass(), data.getDataVersion());
|
||||
meta.dataVersion = data.getDataVersion();
|
||||
try {
|
||||
data.saveData(level, this, out);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to save data for file {}", path, e);
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to write data for file {}", path, e);
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,17 +1,17 @@
|
||||
package com.seibel.lod.core.a7.save.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.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.full.Data;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface DataSourceProvider extends AutoCloseable {
|
||||
public interface IDataSourceProvider extends AutoCloseable {
|
||||
void addScannedFile(Collection<File> detectedFiles);
|
||||
|
||||
CompletableFuture<LodDataSource> read(DhSectionPos pos);
|
||||
void write(DhSectionPos sectionPos, FullDatatype chunkData);
|
||||
void write(DhSectionPos sectionPos, Data chunkData);
|
||||
CompletableFuture<Void> flushAndSave();
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.seibel.lod.core.a7.save.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.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.full.Data;
|
||||
import com.seibel.lod.core.a7.level.IServerLevel;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
@@ -19,7 +19,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class LocalDataFileHandler implements DataSourceProvider {
|
||||
public class LocalDataFileHandler implements IDataSourceProvider {
|
||||
// Note: Single main thread only for now. May make it multi-thread later, depending on the usage.
|
||||
ExecutorService fileReaderThread = LodUtil.makeSingleThreadPool("FileReaderThread");
|
||||
Logger logger = DhLoggerBuilder.getLogger("LocalDataFileHandler");
|
||||
@@ -110,7 +110,7 @@ public class LocalDataFileHandler implements DataSourceProvider {
|
||||
* This call is concurrent. I.e. it supports multiple threads calling this method at the same time.
|
||||
*/
|
||||
@Override
|
||||
public void write(DhSectionPos sectionPos, FullDatatype chunkData) {
|
||||
public void write(DhSectionPos sectionPos, Data chunkData) {
|
||||
DataMetaFile metaFile = files.get(sectionPos);
|
||||
if (metaFile != null) { // Fast path: if there is a file for this section, just write to it.
|
||||
metaFile.addToWriteQueue(chunkData);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.seibel.lod.core.a7.save.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.datatype.LodDataSource;
|
||||
import com.seibel.lod.core.a7.datatype.full.Data;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class RemoteDataFileHandler implements DataSourceProvider {
|
||||
public class RemoteDataFileHandler implements IDataSourceProvider {
|
||||
@Override
|
||||
public void addScannedFile(Collection<File> detectedFiles) {
|
||||
|
||||
@@ -20,7 +20,7 @@ public class RemoteDataFileHandler implements DataSourceProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DhSectionPos sectionPos, FullDatatype chunkData) {
|
||||
public void write(DhSectionPos sectionPos, Data chunkData) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -1,15 +1,14 @@
|
||||
package com.seibel.lod.core.a7.save.io.render;
|
||||
|
||||
import com.seibel.lod.core.a7.RenderDataProvider;
|
||||
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
|
||||
import com.seibel.lod.core.a7.datatype.full.Data;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface RenderSourceProvider extends RenderDataProvider, AutoCloseable {
|
||||
public interface IRenderSourceProvider extends AutoCloseable {
|
||||
void addScannedFile(Collection<File> detectedFiles);
|
||||
void write(DhSectionPos sectionPos, FullDatatype chunkData);
|
||||
void write(DhSectionPos sectionPos, Data chunkData);
|
||||
CompletableFuture<Void> flushAndSave();
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.seibel.lod.core.a7.save.io.render;
|
||||
|
||||
import com.seibel.lod.core.a7.datatype.full.FullDatatype;
|
||||
import com.seibel.lod.core.a7.save.io.file.DataSourceProvider;
|
||||
import com.seibel.lod.core.a7.datatype.RenderSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.full.Data;
|
||||
import com.seibel.lod.core.a7.save.io.file.IDataSourceProvider;
|
||||
import com.seibel.lod.core.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSource;
|
||||
import com.seibel.lod.core.a7.render.RenderDataSourceLoader;
|
||||
import com.seibel.lod.core.a7.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -14,19 +14,19 @@ import java.util.Collection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class RenderFileHandler implements RenderSourceProvider {
|
||||
public class RenderFileHandler implements IRenderSourceProvider {
|
||||
final File renderCacheFolder;
|
||||
final DataSourceProvider dataSourceProvider;
|
||||
final IDataSourceProvider dataSourceProvider;
|
||||
ExecutorService renderCacheThread = LodUtil.makeSingleThreadPool("RenderCacheThread");
|
||||
Logger logger = DhLoggerBuilder.getLogger("RenderCache");
|
||||
|
||||
public RenderFileHandler(DataSourceProvider sourceProvider, File renderCacheFolder) {
|
||||
public RenderFileHandler(IDataSourceProvider sourceProvider, File renderCacheFolder) {
|
||||
this.dataSourceProvider = sourceProvider;
|
||||
this.renderCacheFolder = renderCacheFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<RenderDataSource> createRenderData(RenderDataSourceLoader renderSourceLoader, DhSectionPos pos) {
|
||||
public CompletableFuture<LodRenderSource> createRenderData(RenderSourceLoader renderSourceLoader, DhSectionPos pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class RenderFileHandler implements RenderSourceProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DhSectionPos sectionPos, FullDatatype chunkData) {
|
||||
public void write(DhSectionPos sectionPos, Data chunkData) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
package com.seibel.lod.core.a7.save.io;
|
||||
package com.seibel.lod.core.a7.util;
|
||||
|
||||
import com.seibel.lod.core.a7.save.io.file.DataSourceProvider;
|
||||
import com.seibel.lod.core.a7.save.io.render.RenderSourceProvider;
|
||||
import com.seibel.lod.core.a7.save.io.file.IDataSourceProvider;
|
||||
import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider;
|
||||
import com.seibel.lod.core.a7.save.structure.SaveStructure;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
@@ -19,8 +19,8 @@ public class FileScanner {
|
||||
public static final int MAX_SCAN_DEPTH = 5;
|
||||
public static final String LOD_FILE_POSTFIX = ".lod";
|
||||
public static void scanFile(SaveStructure save, ILevelWrapper level,
|
||||
@Nullable DataSourceProvider dataSource,
|
||||
@Nullable RenderSourceProvider renderSource) {
|
||||
@Nullable IDataSourceProvider dataSource,
|
||||
@Nullable IRenderSourceProvider renderSource) {
|
||||
if (dataSource != null) {
|
||||
try (Stream<Path> pathStream = Files.walk(save.getDataFolder(level).toPath(), MAX_SCAN_DEPTH)) {
|
||||
dataSource.addScannedFile(pathStream.filter((
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.seibel.lod.core.a7.util;
|
||||
|
||||
public class IOUtil {
|
||||
public static final String LOD_FILE_EXTENSION = ".lod";
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
package com.seibel.lod.core.a7.util;
|
||||
|
||||
public class IdMappingUtil {
|
||||
public static final String BLOCKSTATE_ID_AIR = "air";
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
package com.seibel.lod.core.a7.util;
|
||||
|
||||
public class UncheckedInterruptedException extends RuntimeException {
|
||||
public UncheckedInterruptedException(String message) {
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.a7.WorldEnvironment;
|
||||
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.EventLoop;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
|
||||
@@ -11,10 +11,13 @@ import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class DhClientServerWorld extends DhWorld implements IClientWorld, IServerWorld {
|
||||
private final HashMap<ILevelWrapper, DhClientServerLevel> levels;
|
||||
public final LocalSaveStructure saveStructure;
|
||||
public ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHTickerThread", 2);
|
||||
public EventLoop eventLoop = new EventLoop(dhTickerThread, this::_clientTick);
|
||||
|
||||
public DhClientServerWorld() {
|
||||
super(WorldEnvironment.Client_Server);
|
||||
@@ -45,18 +48,25 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
}
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
private void _clientTick() {
|
||||
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
|
||||
Iterator<DhClientServerLevel> iterator = levels.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DhClientServerLevel level = iterator.next();
|
||||
if (level.tree.viewDistance != newViewDistance) {
|
||||
level.close();
|
||||
level.close(); //FIXME: Is this fine for current logic?
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
//DetailDistanceUtil.updateSettings();
|
||||
levels.values().forEach(DhClientServerLevel::tick);
|
||||
levels.values().forEach(DhClientServerLevel::clientTick);
|
||||
}
|
||||
public void clientTick() {
|
||||
eventLoop.tick();
|
||||
}
|
||||
|
||||
public void serverTick() {
|
||||
levels.values().forEach(DhClientServerLevel::serverTick);
|
||||
}
|
||||
|
||||
public void doWorldGen() {
|
||||
@@ -77,4 +87,15 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
|
||||
}
|
||||
levels.clear();
|
||||
}
|
||||
|
||||
public void enableRendering(ILevelWrapper wrapper) {
|
||||
DhClientServerLevel level = levels.get(wrapper);
|
||||
if (level==null) return;
|
||||
level.startRenderer();
|
||||
}
|
||||
public void disableRendering(ILevelWrapper wrapper) {
|
||||
DhClientServerLevel level = levels.get(wrapper);
|
||||
if (level==null) return;
|
||||
level.stopRenderer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.DhClientLevel;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.save.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
@@ -16,12 +16,10 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
|
||||
private final HashMap<ILevelWrapper, DhClientLevel> levels;
|
||||
public final ClientOnlySaveStructure saveStructure;
|
||||
|
||||
public ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHTickerThread", 2);
|
||||
public EventLoop eventLoop = new EventLoop(dhTickerThread, this::tick);
|
||||
public EventLoop eventLoop = new EventLoop(dhTickerThread, this::_clientTick);
|
||||
|
||||
public DhClientWorld() {
|
||||
super(WorldEnvironment.Client_Only);
|
||||
@@ -52,7 +50,7 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
}
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
private void _clientTick() {
|
||||
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16;
|
||||
Iterator<DhClientLevel> iterator = levels.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
@@ -63,9 +61,10 @@ public class DhClientWorld extends DhWorld implements IClientWorld {
|
||||
}
|
||||
}
|
||||
DetailDistanceUtil.updateSettings();
|
||||
levels.values().forEach(DhClientLevel::clientTick);
|
||||
}
|
||||
|
||||
public void asyncTick() {
|
||||
public void clientTick() {
|
||||
eventLoop.tick();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.a7.WorldEnvironment;
|
||||
import com.seibel.lod.core.a7.level.DhServerLevel;
|
||||
import com.seibel.lod.core.a7.save.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
@@ -43,8 +42,8 @@ public class DhServerWorld extends DhWorld implements IServerWorld {
|
||||
}
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
levels.values().forEach(DhServerLevel::tick);
|
||||
public void serverTick() {
|
||||
levels.values().forEach(DhServerLevel::serverTick);
|
||||
}
|
||||
|
||||
public void doWorldGen() {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.a7.WorldEnvironment;
|
||||
import com.seibel.lod.core.a7.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.level.ILevel;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
@@ -24,4 +22,7 @@ public abstract class DhWorld implements Closeable {
|
||||
|
||||
public abstract void unloadLevel(ILevelWrapper wrapper);
|
||||
public abstract CompletableFuture<Void> saveAndFlush();
|
||||
|
||||
@Override
|
||||
public abstract void close();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
|
||||
public interface IClientWorld {
|
||||
void clientTick();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
public interface IServerWorld {
|
||||
void serverTick();
|
||||
void doWorldGen();
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.a7;
|
||||
package com.seibel.lod.core.a7.world;
|
||||
|
||||
public enum WorldEnvironment {
|
||||
Client_Only,
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
package com.seibel.lod.core.api.internal.a7;
|
||||
|
||||
import com.seibel.lod.core.a7.level.IClientLevel;
|
||||
import com.seibel.lod.core.a7.world.*;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.enums.rendering.EDebugMode;
|
||||
@@ -28,7 +30,6 @@ 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.DhClientServerLevel;
|
||||
import com.seibel.lod.core.a7.world.DhWorld;
|
||||
import com.seibel.lod.core.a7.Server;
|
||||
import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.render.GLProxy;
|
||||
@@ -38,6 +39,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.fabricmc.api.Environment;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -80,12 +82,6 @@ public class ClientApi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* there is some setup that should only happen once,
|
||||
* once this is true that setup has completed
|
||||
*/
|
||||
private boolean firstTimeSetupComplete = false;
|
||||
private boolean configOverrideReminderPrinted = false;
|
||||
public boolean rendererDisabledBecauseOfExceptions = false;
|
||||
private ClientApi()
|
||||
@@ -114,42 +110,46 @@ public class ClientApi
|
||||
if (MC != null) MC.sendChatMessage(prefix + str);
|
||||
}
|
||||
|
||||
public void clientServerConnected() {
|
||||
SharedApi.currentServer = new Server(false);
|
||||
SharedApi.currentWorld = new DhWorld(enviroment);
|
||||
public void onClientOnlyConnected() {
|
||||
SharedApi.currentWorld = new DhClientWorld();
|
||||
}
|
||||
public void clientServerDisconnected() {
|
||||
public void onClientOnlyDisconnected() {
|
||||
SharedApi.currentWorld.close();
|
||||
SharedApi.currentWorld = null;
|
||||
SharedApi.currentServer = null;
|
||||
}
|
||||
|
||||
public void clientChunkLoadEvent(IChunkWrapper chunk, ILevelWrapper world)
|
||||
public void clientChunkLoadEvent(IChunkWrapper chunk, ILevelWrapper level)
|
||||
{
|
||||
//TODO: Implement
|
||||
}
|
||||
public void clientChunkSaveEvent(IChunkWrapper chunk, ILevelWrapper world)
|
||||
{
|
||||
//TODO: Implement
|
||||
}
|
||||
|
||||
public void clientLevelUnloadEvent(ILevelWrapper world)
|
||||
{
|
||||
if (SharedApi.currentWorld != null) {
|
||||
SharedApi.currentWorld.unloadLevel(world);
|
||||
if (SharedApi.getEnvironment() == WorldEnvironment.Client_Only) {
|
||||
//TODO: Implement
|
||||
}
|
||||
}
|
||||
public void clientLevelLoadEvent(ILevelWrapper world)
|
||||
public void clientChunkSaveEvent(IChunkWrapper chunk, ILevelWrapper level)
|
||||
{
|
||||
//TODO: Maybe make DHLevel init no longer depend on needing player entity in single player
|
||||
if (SharedApi.currentWorld != null) {
|
||||
SharedApi.currentWorld.getOrLoadLevel(world);
|
||||
if (SharedApi.getEnvironment() == WorldEnvironment.Client_Only) {
|
||||
//TODO: Implement
|
||||
}
|
||||
}
|
||||
|
||||
public void clientLevelUnloadEvent(ILevelWrapper level)
|
||||
{
|
||||
if (SharedApi.currentWorld instanceof DhClientServerWorld) {
|
||||
((DhClientServerWorld)SharedApi.currentWorld).disableRendering(level);
|
||||
} else if (SharedApi.getEnvironment() == WorldEnvironment.Client_Only) {
|
||||
SharedApi.currentWorld.unloadLevel(level);
|
||||
}
|
||||
}
|
||||
public void clientLevelLoadEvent(ILevelWrapper level)
|
||||
{
|
||||
if (SharedApi.currentWorld instanceof DhClientServerWorld) {
|
||||
((DhClientServerWorld)SharedApi.currentWorld).enableRendering(level);
|
||||
} else if (SharedApi.getEnvironment() == WorldEnvironment.Client_Only) {
|
||||
SharedApi.currentWorld.getOrLoadLevel(level); //TODO: This may need to be delayed to after player enters the level
|
||||
}
|
||||
}
|
||||
|
||||
private long lastFlush = 0;
|
||||
|
||||
|
||||
public void rendererShutdownEvent() {
|
||||
IProfilerWrapper profiler = MC.getProfiler();
|
||||
profiler.push("DH-RendererShutdown");
|
||||
@@ -176,15 +176,8 @@ public class ClientApi
|
||||
ConfigBasedLogger.updateAll();
|
||||
ConfigBasedSpamLogger.updateAll(doFlush);
|
||||
|
||||
if (SharedApi.currentWorld != null) {
|
||||
if (ModInfo.IS_DEV_BUILD) {
|
||||
// config overrides should only be used in the developer builds
|
||||
applyDeveloperConfigOverrides();
|
||||
}
|
||||
if (SharedApi.currentServer == null) {
|
||||
// In single player. Do client-side ticking system.
|
||||
SharedApi.currentWorld.asyncTick();
|
||||
}
|
||||
if (SharedApi.currentWorld instanceof IClientWorld) {
|
||||
((IClientWorld) SharedApi.currentWorld).clientTick();
|
||||
}
|
||||
profiler.pop();
|
||||
}
|
||||
@@ -199,18 +192,13 @@ public class ClientApi
|
||||
if (world == null) return;
|
||||
DhWorld DhWorld = SharedApi.currentWorld;
|
||||
if (DhWorld == null) return;
|
||||
DhClientServerLevel level = (SharedApi.currentServer == null) ? DhWorld.getOrLoadLevel(world) : DhWorld.getLevel(world);
|
||||
if (level == null) return;
|
||||
if (!(SharedApi.currentWorld instanceof IClientWorld)) return;
|
||||
IClientLevel level = (IClientLevel)SharedApi.currentWorld;
|
||||
|
||||
if (prefLoggerEnabled) {
|
||||
level.dumpRamUsage();
|
||||
}
|
||||
|
||||
if (SharedApi.currentServer == null) {
|
||||
// In multiplayer, without access to the server-side stuff. So we need to do some extra work.
|
||||
level.asyncTick();
|
||||
}
|
||||
|
||||
if (Config.Client.Advanced.Debugging.rendererType.get() == ERendererType.DEFAULT) {
|
||||
if (MC_RENDER.playerHasBlindnessEffect()) {
|
||||
// if the player is blind, don't render LODs,
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
package com.seibel.lod.core.api.internal.a7;
|
||||
|
||||
import com.seibel.lod.core.a7.world.DhClientServerWorld;
|
||||
import com.seibel.lod.core.a7.world.DhServerWorld;
|
||||
import com.seibel.lod.core.a7.world.IServerWorld;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.a7.world.DhWorld;
|
||||
@@ -44,8 +47,6 @@ public class ServerApi
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static final IVersionConstants VERSION_CONSTANTS = SingletonHandler.get(IVersionConstants.class);
|
||||
|
||||
private boolean isCurrentlyOnSinglePlayerServer = false;
|
||||
|
||||
private ServerApi()
|
||||
{
|
||||
}
|
||||
@@ -57,51 +58,51 @@ public class ServerApi
|
||||
private int lastWorldGenTickDelta = 0;
|
||||
public void serverTickEvent()
|
||||
{
|
||||
lastWorldGenTickDelta--;
|
||||
if (SharedApi.currentWorld != null && lastWorldGenTickDelta <= 0) {
|
||||
lastWorldGenTickDelta = 20;
|
||||
DhWorld DhWorld = SharedApi.currentWorld;
|
||||
DhWorld.tick();
|
||||
if (SharedApi.currentWorld instanceof IServerWorld) {
|
||||
IServerWorld serverWorld = (IServerWorld) SharedApi.currentWorld;
|
||||
serverWorld.serverTick();
|
||||
lastWorldGenTickDelta--;
|
||||
if (lastWorldGenTickDelta <= 0) {
|
||||
serverWorld.doWorldGen();
|
||||
lastWorldGenTickDelta = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: rename to serverLoadEvent
|
||||
public void serverWorldLoadEvent() {
|
||||
SharedApi.currentServer = new Server(!SharedApi.inDedicatedEnvironment);
|
||||
SharedApi.currentWorld = new DhWorld(enviroment);
|
||||
//TODO: Setup the network handler
|
||||
public void serverWorldLoadEvent(boolean isDedicatedEnvironment) {
|
||||
if (isDedicatedEnvironment) {
|
||||
SharedApi.currentWorld = new DhServerWorld();
|
||||
} else {
|
||||
SharedApi.currentWorld = new DhClientServerWorld();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: rename to serverUnloadEvent
|
||||
public void serverWorldUnloadEvent() {
|
||||
//TODO: Close the network handler
|
||||
SharedApi.currentWorld.close();
|
||||
SharedApi.currentWorld = null;
|
||||
SharedApi.currentServer = null;
|
||||
}
|
||||
|
||||
public void serverLevelLoadEvent(ILevelWrapper world) {
|
||||
//TODO: Maybe make DHLevel init no longer depend on needing player entity in single player
|
||||
if (SharedApi.currentServer.isSinglePlayer) return;
|
||||
SharedApi.currentWorld.getOrLoadLevel(world);
|
||||
if (SharedApi.currentWorld instanceof IServerWorld)
|
||||
SharedApi.currentWorld.getOrLoadLevel(world);
|
||||
}
|
||||
public void serverLevelUnloadEvent(ILevelWrapper world) {
|
||||
SharedApi.currentWorld.unloadLevel(world);
|
||||
if (SharedApi.currentWorld instanceof IServerWorld)
|
||||
SharedApi.currentWorld.unloadLevel(world);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void serverSaveEvent() {
|
||||
SharedApi.currentWorld.save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void chunkSaveEvent(IChunkWrapper chunk, ILevelWrapper world) {
|
||||
//TODO
|
||||
if (SharedApi.currentWorld instanceof IServerWorld)
|
||||
SharedApi.currentWorld.saveAndFlush();
|
||||
}
|
||||
|
||||
public void serverChunkLoadEvent(IChunkWrapper chunk, ILevelWrapper world) {
|
||||
//TODO
|
||||
}
|
||||
public void serverChunkSaveEvent(IChunkWrapper chunk, ILevelWrapper world) {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package com.seibel.lod.core.api.internal.a7;
|
||||
|
||||
import com.seibel.lod.core.a7.world.WorldEnvironment;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.a7.world.DhWorld;
|
||||
import com.seibel.lod.core.a7.Server;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class SharedApi {
|
||||
public static DhWorld currentWorld;
|
||||
public static Server currentServer;
|
||||
public static IMinecraftSharedWrapper MC;
|
||||
public static Logger LOGGER = DhLoggerBuilder.getLogger("DH Events");
|
||||
public static boolean inDedicatedEnvironment;
|
||||
public static WorldEnvironment getEnvironment() {
|
||||
return currentWorld==null ? null : currentWorld.environment;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ package com.seibel.lod.core.builders.lodBuilding.bufferBuilding;
|
||||
import com.seibel.lod.core.enums.rendering.EDebugMode;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnArrayView;
|
||||
import com.seibel.lod.core.a7.datatype.column.ColumnBox;
|
||||
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
|
||||
import com.seibel.lod.core.a7.datatype.column.render.ColumnBox;
|
||||
import com.seibel.lod.core.objects.opengl.LodBox;
|
||||
import com.seibel.lod.core.util.ColorUtil;
|
||||
import com.seibel.lod.core.util.DataPointUtil;
|
||||
|
||||
Reference in New Issue
Block a user