chunks use an int array. Chunk files will take up less memory now
parent
e70f21c81c
commit
159f2133f3
|
@ -169,7 +169,7 @@ public class Chunk implements BlockAccess, WorldGenConstants, DataStorage
|
|||
}
|
||||
}
|
||||
//
|
||||
DataSection blockData = data.get("block");
|
||||
IntArrayDataSection blockData = data.getIntArray("block");
|
||||
int index = 0;
|
||||
//
|
||||
for (int z = 0; z < CHUNK_SIZE; ++z) // z, y, x order for data saving and loading so we can use incremental pos hashes
|
||||
|
@ -207,7 +207,7 @@ public class Chunk implements BlockAccess, WorldGenConstants, DataStorage
|
|||
{
|
||||
Object2IntMap<Block> palette = new Object2IntArrayMap<>(); // block to int id
|
||||
DataSection paletteData = new DataSection();
|
||||
DataSection blockData = new DataSection();
|
||||
IntArrayDataSection blockData = new IntArrayDataSection();
|
||||
int index = 0;
|
||||
nextId = 0;
|
||||
ToIntFunction<Block> nextIdProvider = b -> nextId++;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.github.halotroop.litecraft.world;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Random;
|
||||
import java.util.function.LongConsumer;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
interface BaseDataSection<E> extends Iterable<E> {
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
<T> void writeForParser(T data);
|
||||
}
|
|
@ -1,58 +1,97 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import tk.valoeghese.sod.exception.SODParseException;
|
||||
|
||||
public class BinaryData implements Iterable<Map.Entry<String, DataSection>>
|
||||
{
|
||||
public static BinaryData read(File file) throws SODParseException
|
||||
{
|
||||
try (DataInputStream dis = new DataInputStream(new FileInputStream(file)))
|
||||
{
|
||||
long magic = dis.readLong();
|
||||
if (magic != 0xA77D1E)
|
||||
{ throw new SODParseException("Not a valid SOD file!"); }
|
||||
return Parser.parse(dis);
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class BinaryData implements Iterable<Map.Entry<String, BaseDataSection>> {
|
||||
public BinaryData() {
|
||||
this.sections = new HashMap<>();
|
||||
}
|
||||
|
||||
private final Map<String, BaseDataSection> sections;
|
||||
|
||||
public DataSection get(String name) {
|
||||
return (DataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public ByteArrayDataSection getByteArray(String name) {
|
||||
return (ByteArrayDataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public ShortArrayDataSection getShortArray(String name) {
|
||||
return (ShortArrayDataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public IntArrayDataSection getIntArray(String name) {
|
||||
return (IntArrayDataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public LongArrayDataSection getLongArray(String name) {
|
||||
return (LongArrayDataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public FloatArrayDataSection getFloatArray(String name) {
|
||||
return (FloatArrayDataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public DoubleArrayDataSection getDoubleArray(String name) {
|
||||
return (DoubleArrayDataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public StringArrayDataSection getStringArray(String name) {
|
||||
return (StringArrayDataSection) this.sections.get(name);
|
||||
}
|
||||
|
||||
public DataSection getOrCreate(String name) {
|
||||
return (DataSection) this.sections.computeIfAbsent(name, k -> new DataSection());
|
||||
}
|
||||
|
||||
public void put(String name, BaseDataSection section) {
|
||||
this.sections.put(name, section);
|
||||
}
|
||||
|
||||
public boolean containsSection(String name) {
|
||||
return this.sections.containsKey(name);
|
||||
}
|
||||
|
||||
public boolean write(File file) {
|
||||
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
|
||||
Parser.write(this, dos);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, BaseDataSection>> iterator() {
|
||||
return this.sections.entrySet().iterator();
|
||||
}
|
||||
|
||||
public static BinaryData read(File file) throws SODParseException {
|
||||
try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
|
||||
long magic = dis.readLong();
|
||||
|
||||
if (magic != 0xA77D1E) {
|
||||
throw new SODParseException("Not a valid SOD file!");
|
||||
}
|
||||
|
||||
return Parser.parse(dis);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
//throw new SODParseException("Error in parsing file " + file.toString());
|
||||
return new BinaryData();
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, DataSection> sections;
|
||||
|
||||
public BinaryData()
|
||||
{ this.sections = new HashMap<>(); }
|
||||
|
||||
public DataSection get(String name)
|
||||
{ return this.sections.get(name); }
|
||||
|
||||
public DataSection getOrCreate(String name)
|
||||
{ return this.sections.computeIfAbsent(name, k -> new DataSection()); }
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, DataSection>> iterator()
|
||||
{ return this.sections.entrySet().iterator(); }
|
||||
|
||||
public void put(String name, DataSection section)
|
||||
{ this.sections.put(name, section); }
|
||||
|
||||
public boolean write(File file)
|
||||
{
|
||||
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file)))
|
||||
{
|
||||
Parser.write(this, dos);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||
import it.unimi.dsi.fastutil.bytes.ByteList;
|
||||
|
||||
public class ByteArrayDataSection implements BaseDataSection<Byte> {
|
||||
public ByteArrayDataSection() {
|
||||
this.array = new ByteArrayList();
|
||||
}
|
||||
|
||||
private final ByteList array;
|
||||
|
||||
public void writeByte(byte value) {
|
||||
this.array.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public <T> void writeForParser(T data) throws UnsupportedOperationException {
|
||||
if (data instanceof Byte) {
|
||||
this.writeByte((byte) data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
|
||||
}
|
||||
}
|
||||
|
||||
public byte readByte(int index) {
|
||||
return this.array.getByte(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Byte> iterator() {
|
||||
return this.array.iterator();
|
||||
}
|
||||
}
|
|
@ -1,86 +1,120 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/** Represents a section of SOD data.
|
||||
*
|
||||
* @author Valoeghese */
|
||||
public class DataSection implements Iterable<Object>
|
||||
{
|
||||
private final List<Object> data;
|
||||
/**
|
||||
* Represents a section of SOD data.
|
||||
* @author Valoeghese
|
||||
*/
|
||||
public class DataSection implements BaseDataSection<Object> {
|
||||
public DataSection() {
|
||||
this.data = new ArrayList<>();
|
||||
}
|
||||
|
||||
public DataSection()
|
||||
{ this.data = new ArrayList<>(); }
|
||||
private final List<Object> data;
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Object> iterator()
|
||||
{ return this.data.iterator(); }
|
||||
public <T> void writeForParser(T data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public boolean readBoolean(int index)
|
||||
{ return ((byte) this.data.get(index)) != 0; }
|
||||
public void writeByte(byte data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public byte readByte(int index)
|
||||
{ return (byte) this.data.get(index); }
|
||||
public void writeShort(short data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public double readDouble(int index)
|
||||
{ return (double) this.data.get(index); }
|
||||
public void writeInt(int data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public <T extends Enum<?>> T readEnum(int index, T[] values)
|
||||
{
|
||||
public void writeLong(long data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public void writeFloat(float data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public void writeDouble(double data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public void writeString(String data) {
|
||||
this.data.add(data);
|
||||
}
|
||||
|
||||
public void writeBoolean(boolean data) {
|
||||
this.data.add(data ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
|
||||
public <T extends Enum<?>> void writeEnum(T enumValue) {
|
||||
this.data.add(enumValue.ordinal());
|
||||
}
|
||||
|
||||
public <T extends Enum<?>> void writeEnumAsString(T enumValue) {
|
||||
this.data.add(enumValue.toString());
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.data.size();
|
||||
}
|
||||
|
||||
public byte readByte(int index) {
|
||||
return (byte) this.data.get(index);
|
||||
}
|
||||
|
||||
public short readShort(int index) {
|
||||
return (short) this.data.get(index);
|
||||
}
|
||||
|
||||
public int readInt(int index) {
|
||||
return (int) this.data.get(index);
|
||||
}
|
||||
|
||||
public long readLong(int index) {
|
||||
return (long) this.data.get(index);
|
||||
}
|
||||
|
||||
public float readFloat(int index) {
|
||||
return (float) this.data.get(index);
|
||||
}
|
||||
|
||||
public double readDouble(int index) {
|
||||
return (double) this.data.get(index);
|
||||
}
|
||||
|
||||
public String readString(int index) {
|
||||
return (String) this.data.get(index);
|
||||
}
|
||||
|
||||
public boolean readBoolean(int index) {
|
||||
return ((byte) this.data.get(index)) != 0;
|
||||
}
|
||||
|
||||
public <T extends Enum<T>> T readEnumString(int index, Class<T> type) {
|
||||
return Enum.valueOf(type, (String) this.data.get(index));
|
||||
}
|
||||
|
||||
public <T extends Enum<?>> T readEnum(int index, T[] values) {
|
||||
Integer i = (Integer) this.data.get(index);
|
||||
if (i == null)
|
||||
{ return null; }
|
||||
|
||||
if (i == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return values[i];
|
||||
}
|
||||
|
||||
public <T extends Enum<T>> T readEnumString(int index, Class<T> type)
|
||||
{ return Enum.valueOf(type, (String) this.data.get(index)); }
|
||||
|
||||
public float readFloat(int index)
|
||||
{ return (float) this.data.get(index); }
|
||||
|
||||
public int readInt(int index)
|
||||
{ return (int) this.data.get(index); }
|
||||
|
||||
public long readLong(int index)
|
||||
{ return (long) this.data.get(index); }
|
||||
|
||||
public short readShort(int index)
|
||||
{ return (short) this.data.get(index); }
|
||||
|
||||
public String readString(int index)
|
||||
{ return (String) this.data.get(index); }
|
||||
|
||||
public int size()
|
||||
{ return this.data.size(); }
|
||||
|
||||
public void writeBoolean(boolean data)
|
||||
{ this.data.add(data ? (byte) 1 : (byte) 0); }
|
||||
|
||||
public void writeByte(byte data)
|
||||
{ this.data.add(data); }
|
||||
|
||||
public void writeDouble(double data)
|
||||
{ this.data.add(data); }
|
||||
|
||||
public <T extends Enum<?>> void writeEnum(T enumValue)
|
||||
{ this.data.add(enumValue.ordinal()); }
|
||||
|
||||
public <T extends Enum<?>> void writeEnumAsString(T enumValue)
|
||||
{ this.data.add(enumValue.toString()); }
|
||||
|
||||
public void writeFloat(float data)
|
||||
{ this.data.add(data); }
|
||||
|
||||
public void writeInt(int data)
|
||||
{ this.data.add(data); }
|
||||
|
||||
public void writeLong(long data)
|
||||
{ this.data.add(data); }
|
||||
|
||||
public void writeShort(short data)
|
||||
{ this.data.add(data); }
|
||||
|
||||
public void writeString(String data)
|
||||
{ this.data.add(data); }
|
||||
@Override
|
||||
public Iterator<Object> iterator() {
|
||||
return this.data.iterator();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
||||
import it.unimi.dsi.fastutil.doubles.DoubleList;
|
||||
|
||||
public class DoubleArrayDataSection implements BaseDataSection<Double> {
|
||||
public DoubleArrayDataSection() {
|
||||
this.array = new DoubleArrayList();
|
||||
}
|
||||
|
||||
private final DoubleList array;
|
||||
|
||||
public void writeDouble(double value) {
|
||||
this.array.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public <T> void writeForParser(T data) throws UnsupportedOperationException {
|
||||
if (data instanceof Double) {
|
||||
this.writeDouble((double) data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
|
||||
}
|
||||
}
|
||||
|
||||
public double readDouble(int index) {
|
||||
return this.array.getDouble(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Double> iterator() {
|
||||
return this.array.iterator();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import it.unimi.dsi.fastutil.floats.FloatArrayList;
|
||||
import it.unimi.dsi.fastutil.floats.FloatList;
|
||||
|
||||
public class FloatArrayDataSection implements BaseDataSection<Float> {
|
||||
public FloatArrayDataSection() {
|
||||
this.array = new FloatArrayList();
|
||||
}
|
||||
|
||||
private final FloatList array;
|
||||
|
||||
public void writeFloat(float value) {
|
||||
this.array.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public <T> void writeForParser(T data) throws UnsupportedOperationException {
|
||||
if (data instanceof Float) {
|
||||
this.writeFloat((float) data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
|
||||
}
|
||||
}
|
||||
|
||||
public float readFloat(int index) {
|
||||
return this.array.getFloat(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Float> iterator() {
|
||||
return this.array.iterator();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
||||
public class IntArrayDataSection implements BaseDataSection<Integer> {
|
||||
public IntArrayDataSection() {
|
||||
this.array = new IntArrayList();
|
||||
}
|
||||
|
||||
private final IntList array;
|
||||
|
||||
public void writeInt(int value) {
|
||||
this.array.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public <T> void writeForParser(T data) throws UnsupportedOperationException {
|
||||
if (data instanceof Integer) {
|
||||
this.writeInt((int) data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
|
||||
}
|
||||
}
|
||||
|
||||
public int readInt(int index) {
|
||||
return this.array.getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return this.array.iterator();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.LongList;
|
||||
|
||||
public class LongArrayDataSection implements BaseDataSection<Long> {
|
||||
public LongArrayDataSection() {
|
||||
this.array = new LongArrayList();
|
||||
}
|
||||
|
||||
private final LongList array;
|
||||
|
||||
public void writeLong(long value) {
|
||||
this.array.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public <T> void writeForParser(T data) throws UnsupportedOperationException {
|
||||
if (data instanceof Long) {
|
||||
this.writeLong((long) data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
|
||||
}
|
||||
}
|
||||
|
||||
public long readLong(int index) {
|
||||
return this.array.getLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Long> iterator() {
|
||||
return this.array.iterator();
|
||||
}
|
||||
}
|
|
@ -1,12 +1,329 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import tk.valoeghese.sod.exception.SODParseException;
|
||||
|
||||
enum DataType
|
||||
{
|
||||
final class Parser {
|
||||
@SuppressWarnings({"deprecation", "rawtypes", "unchecked"})
|
||||
static BinaryData parse(DataInputStream input) throws IOException, SODParseException {
|
||||
BinaryData data = new BinaryData();
|
||||
|
||||
DataType dataType;
|
||||
DataType sectionType;
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
|
||||
BaseDataSection currentSection;
|
||||
int arraySizeCountdown = 0;
|
||||
|
||||
try {
|
||||
currentSection = dataType.createSection();
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new SODParseException("Data must be segregated into sections!");
|
||||
}
|
||||
|
||||
data.put(input.readUTF(), currentSection);
|
||||
|
||||
while (input.available() > 0) {
|
||||
switch (sectionType) {
|
||||
case BYTE_ARRAY_SECTION:
|
||||
while (arraySizeCountdown --> 0) {
|
||||
currentSection.writeForParser(input.readByte());
|
||||
}
|
||||
// create new section if available
|
||||
if (input.available() > 0) {
|
||||
try {
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
currentSection = dataType.createSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
// set countdown
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SHORT_ARRAY_SECTION:
|
||||
while (arraySizeCountdown --> 0) {
|
||||
currentSection.writeForParser(input.readShort());
|
||||
}
|
||||
// create new section if available
|
||||
if (input.available() > 0) {
|
||||
try {
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
currentSection = dataType.createSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
// set countdown
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INT_ARRAY_SECTION:
|
||||
while (arraySizeCountdown --> 0) {
|
||||
currentSection.writeForParser(input.readInt());
|
||||
}
|
||||
// create new section if available
|
||||
if (input.available() > 0) {
|
||||
try {
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
currentSection = dataType.createSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
// set countdown
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LONG_ARRAY_SECTION:
|
||||
while (arraySizeCountdown --> 0) {
|
||||
currentSection.writeForParser(input.readLong());
|
||||
}
|
||||
// create new section if available
|
||||
if (input.available() > 0) {
|
||||
try {
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
currentSection = dataType.createSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
// set countdown
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FLOAT_ARRAY_SECTION:
|
||||
while (arraySizeCountdown --> 0) {
|
||||
currentSection.writeForParser(input.readFloat());
|
||||
}
|
||||
// create new section if available
|
||||
if (input.available() > 0) {
|
||||
try {
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
currentSection = dataType.createSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
// set countdown
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DOUBLE_ARRAY_SECTION:
|
||||
while (arraySizeCountdown --> 0) {
|
||||
currentSection.writeForParser(input.readDouble());
|
||||
}
|
||||
// create new section if available
|
||||
if (input.available() > 0) {
|
||||
try {
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
currentSection = dataType.createSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
// set countdown
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STRING_ARRAY_SECTION:
|
||||
while (arraySizeCountdown --> 0) {
|
||||
currentSection.writeForParser(input.readUTF());
|
||||
}
|
||||
// create new section if available
|
||||
if (input.available() > 0) {
|
||||
try {
|
||||
dataType = DataType.of(input.readByte());
|
||||
sectionType = dataType;
|
||||
currentSection = dataType.createSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
// set countdown
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SECTION:
|
||||
default:
|
||||
dataType = DataType.of(input.readByte());
|
||||
|
||||
switch (dataType) {
|
||||
case BYTE:
|
||||
currentSection.writeForParser(input.readByte());
|
||||
break;
|
||||
case DOUBLE:
|
||||
currentSection.writeForParser(input.readDouble());
|
||||
break;
|
||||
case FLOAT:
|
||||
currentSection.writeForParser(input.readFloat());
|
||||
break;
|
||||
case INT:
|
||||
currentSection.writeForParser(input.readInt());
|
||||
break;
|
||||
case LONG:
|
||||
currentSection.writeForParser(input.readLong());
|
||||
break;
|
||||
case SHORT:
|
||||
currentSection.writeForParser(input.readShort());
|
||||
break;
|
||||
case STRING:
|
||||
currentSection.writeForParser(input.readUTF());
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
currentSection = dataType.createSection();
|
||||
sectionType = dataType;
|
||||
data.put(input.readUTF(), currentSection);
|
||||
if (dataType != DataType.SECTION) {
|
||||
arraySizeCountdown = input.readInt();
|
||||
}
|
||||
} catch (SODParseException e) {
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static void write(BinaryData data, DataOutputStream dos) throws IOException {
|
||||
dos.writeLong(0xA77D1E);
|
||||
|
||||
Iterator<Map.Entry<String, BaseDataSection>> sectionStream = data.iterator();
|
||||
|
||||
while (sectionStream.hasNext()) {
|
||||
Map.Entry<String, BaseDataSection> entry = sectionStream.next();
|
||||
BaseDataSection section = entry.getValue();
|
||||
|
||||
if (section instanceof DataSection) {
|
||||
dos.writeByte(DataType.SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
|
||||
Iterator<Object> dataStream = ((DataSection) section).iterator();
|
||||
|
||||
while (dataStream.hasNext()) {
|
||||
Object o = dataStream.next();
|
||||
|
||||
if (o instanceof Byte) {
|
||||
dos.writeByte(DataType.BYTE.id);
|
||||
dos.writeByte((byte) o);
|
||||
} else if (o instanceof Short) {
|
||||
dos.writeByte(DataType.SHORT.id);
|
||||
dos.writeShort((short) o);
|
||||
} else if (o instanceof Integer) {
|
||||
dos.writeByte(DataType.INT.id);
|
||||
dos.writeInt((int) o);
|
||||
} else if (o instanceof Long) {
|
||||
dos.writeByte(DataType.LONG.id);
|
||||
dos.writeLong((long) o);
|
||||
} else if (o instanceof Float) {
|
||||
dos.writeByte(DataType.FLOAT.id);
|
||||
dos.writeFloat((float) o);
|
||||
} else if (o instanceof Double) {
|
||||
dos.writeByte(DataType.DOUBLE.id);
|
||||
dos.writeDouble((double) o);
|
||||
} else if (o instanceof String) {
|
||||
dos.writeByte(DataType.STRING.id);
|
||||
dos.writeUTF((String) o);
|
||||
}
|
||||
}
|
||||
} else if (section instanceof ByteArrayDataSection) { // byte array
|
||||
dos.writeByte(DataType.BYTE_ARRAY_SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
dos.writeInt(((ByteArrayDataSection) section).size());
|
||||
|
||||
for (byte b : (ByteArrayDataSection) section) {
|
||||
dos.writeByte(b);
|
||||
}
|
||||
} else if (section instanceof ShortArrayDataSection) { // short array
|
||||
dos.writeByte(DataType.SHORT_ARRAY_SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
dos.writeInt(((ShortArrayDataSection) section).size());
|
||||
|
||||
for (short s : (ShortArrayDataSection) section) {
|
||||
dos.writeShort(s);
|
||||
}
|
||||
} else if (section instanceof IntArrayDataSection) { // int array
|
||||
dos.writeByte(DataType.INT_ARRAY_SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
dos.writeInt(((IntArrayDataSection) section).size());
|
||||
|
||||
for (int i : (IntArrayDataSection) section) {
|
||||
dos.writeInt(i);
|
||||
}
|
||||
} else if (section instanceof LongArrayDataSection) { // long array
|
||||
dos.writeByte(DataType.LONG_ARRAY_SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
dos.writeInt(((LongArrayDataSection) section).size());
|
||||
|
||||
for (long l : (LongArrayDataSection) section) {
|
||||
dos.writeLong(l);
|
||||
}
|
||||
} else if (section instanceof FloatArrayDataSection) { // float array
|
||||
dos.writeByte(DataType.FLOAT_ARRAY_SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
dos.writeInt(((FloatArrayDataSection) section).size());
|
||||
|
||||
for (float f: (FloatArrayDataSection) section) {
|
||||
dos.writeFloat(f);
|
||||
}
|
||||
} else if (section instanceof DoubleArrayDataSection) { // double array
|
||||
dos.writeByte(DataType.DOUBLE_ARRAY_SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
dos.writeInt(((DoubleArrayDataSection) section).size());
|
||||
|
||||
for (double d : (DoubleArrayDataSection) section) {
|
||||
dos.writeDouble(d);
|
||||
}
|
||||
} else if (section instanceof StringArrayDataSection) { // string array
|
||||
dos.writeByte(DataType.STRING_ARRAY_SECTION.id);
|
||||
dos.writeUTF(entry.getKey());
|
||||
dos.writeInt(((StringArrayDataSection) section).size());
|
||||
|
||||
for (String s : (StringArrayDataSection) section) {
|
||||
dos.writeUTF(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum DataType {
|
||||
SECTION(0),
|
||||
BYTE(1),
|
||||
SHORT(2),
|
||||
|
@ -14,12 +331,23 @@ enum DataType
|
|||
LONG(4),
|
||||
FLOAT(5),
|
||||
DOUBLE(6),
|
||||
STRING(7);
|
||||
STRING(7),
|
||||
BYTE_ARRAY_SECTION(8),
|
||||
SHORT_ARRAY_SECTION(9),
|
||||
INT_ARRAY_SECTION(10),
|
||||
LONG_ARRAY_SECTION(11),
|
||||
FLOAT_ARRAY_SECTION(12),
|
||||
DOUBLE_ARRAY_SECTION(13),
|
||||
STRING_ARRAY_SECTION(14);
|
||||
|
||||
public static DataType of(byte id) throws SODParseException
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
private DataType(int id) {
|
||||
this.id = (byte) id;
|
||||
}
|
||||
|
||||
public final byte id;
|
||||
|
||||
public static DataType of(byte id) throws SODParseException {
|
||||
switch (id) {
|
||||
case 0:
|
||||
return SECTION;
|
||||
case 1:
|
||||
|
@ -36,114 +364,46 @@ enum DataType
|
|||
return DOUBLE;
|
||||
case 7:
|
||||
return STRING;
|
||||
case 8:
|
||||
return BYTE_ARRAY_SECTION;
|
||||
case 9:
|
||||
return SHORT_ARRAY_SECTION;
|
||||
case 10:
|
||||
return INT_ARRAY_SECTION;
|
||||
case 11:
|
||||
return LONG_ARRAY_SECTION;
|
||||
case 12:
|
||||
return FLOAT_ARRAY_SECTION;
|
||||
case 13:
|
||||
return DOUBLE_ARRAY_SECTION;
|
||||
case 14:
|
||||
return STRING_ARRAY_SECTION;
|
||||
default:
|
||||
throw new SODParseException("Unknown data type " + String.valueOf(id));
|
||||
}
|
||||
}
|
||||
|
||||
public final byte id;
|
||||
|
||||
private DataType(int id)
|
||||
{ this.id = (byte) id; }
|
||||
}
|
||||
|
||||
final class Parser
|
||||
{
|
||||
static BinaryData parse(DataInputStream input) throws IOException, SODParseException
|
||||
{
|
||||
BinaryData data = new BinaryData();
|
||||
DataType dataType;
|
||||
dataType = DataType.of(input.readByte());
|
||||
if (dataType != DataType.SECTION)
|
||||
{ throw new SODParseException("Data must be segregated into sections!"); }
|
||||
DataSection currentSection = new DataSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
while (input.available() > 0)
|
||||
{
|
||||
dataType = DataType.of(input.readByte());
|
||||
switch (dataType)
|
||||
{
|
||||
case BYTE:
|
||||
currentSection.writeByte(input.readByte());
|
||||
break;
|
||||
case DOUBLE:
|
||||
currentSection.writeDouble(input.readDouble());
|
||||
break;
|
||||
case FLOAT:
|
||||
currentSection.writeFloat(input.readFloat());
|
||||
break;
|
||||
case INT:
|
||||
currentSection.writeInt(input.readInt());
|
||||
break;
|
||||
case LONG:
|
||||
currentSection.writeLong(input.readLong());
|
||||
break;
|
||||
case SECTION:
|
||||
currentSection = new DataSection();
|
||||
data.put(input.readUTF(), currentSection);
|
||||
break;
|
||||
case SHORT:
|
||||
currentSection.writeShort(input.readShort());
|
||||
break;
|
||||
case STRING:
|
||||
currentSection.writeString(input.readUTF());
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void write(BinaryData data, DataOutputStream dos) throws IOException
|
||||
{
|
||||
dos.writeLong(0xA77D1E);
|
||||
Iterator<Map.Entry<String, DataSection>> sectionStream = data.iterator();
|
||||
while (sectionStream.hasNext())
|
||||
{
|
||||
Map.Entry<String, DataSection> section = sectionStream.next();
|
||||
dos.writeByte(DataType.SECTION.id);
|
||||
dos.writeUTF(section.getKey());
|
||||
Iterator<Object> dataStream = section.getValue().iterator();
|
||||
while (dataStream.hasNext())
|
||||
{
|
||||
Object o = dataStream.next();
|
||||
if (o instanceof Byte)
|
||||
{
|
||||
dos.writeByte(DataType.BYTE.id);
|
||||
dos.writeByte((byte) o);
|
||||
}
|
||||
else if (o instanceof Short)
|
||||
{
|
||||
dos.writeByte(DataType.SHORT.id);
|
||||
dos.writeShort((short) o);
|
||||
}
|
||||
else if (o instanceof Integer)
|
||||
{
|
||||
dos.writeByte(DataType.INT.id);
|
||||
dos.writeInt((int) o);
|
||||
}
|
||||
else if (o instanceof Long)
|
||||
{
|
||||
dos.writeByte(DataType.LONG.id);
|
||||
dos.writeLong((long) o);
|
||||
}
|
||||
else if (o instanceof Float)
|
||||
{
|
||||
dos.writeByte(DataType.FLOAT.id);
|
||||
dos.writeFloat((float) o);
|
||||
}
|
||||
else if (o instanceof Double)
|
||||
{
|
||||
dos.writeByte(DataType.DOUBLE.id);
|
||||
dos.writeDouble((double) o);
|
||||
}
|
||||
else if (o instanceof String)
|
||||
{
|
||||
dos.writeByte(DataType.STRING.id);
|
||||
dos.writeUTF((String) o);
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
BaseDataSection createSection() {
|
||||
switch (this) {
|
||||
case SECTION:
|
||||
return new DataSection();
|
||||
case BYTE_ARRAY_SECTION:
|
||||
return new ByteArrayDataSection();
|
||||
case DOUBLE_ARRAY_SECTION:
|
||||
return new DoubleArrayDataSection();
|
||||
case FLOAT_ARRAY_SECTION:
|
||||
return new FloatArrayDataSection();
|
||||
case INT_ARRAY_SECTION:
|
||||
return new IntArrayDataSection();
|
||||
case LONG_ARRAY_SECTION:
|
||||
return new LongArrayDataSection();
|
||||
case SHORT_ARRAY_SECTION:
|
||||
return new ShortArrayDataSection();
|
||||
case STRING_ARRAY_SECTION:
|
||||
return new StringArrayDataSection();
|
||||
default:
|
||||
throw new SODParseException("Tried to create section from non-section data type!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||
import it.unimi.dsi.fastutil.shorts.ShortList;
|
||||
|
||||
public class ShortArrayDataSection implements BaseDataSection<Short> {
|
||||
public ShortArrayDataSection() {
|
||||
this.array = new ShortArrayList();
|
||||
}
|
||||
|
||||
private final ShortList array;
|
||||
|
||||
public void writeShort(short value) {
|
||||
this.array.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public <T> void writeForParser(T data) throws UnsupportedOperationException {
|
||||
if (data instanceof Short) {
|
||||
this.writeShort((short) data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
|
||||
}
|
||||
}
|
||||
|
||||
public short readShort(int index) {
|
||||
return this.array.getShort(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Short> iterator() {
|
||||
return this.array.iterator();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class StringArrayDataSection implements BaseDataSection<String> {
|
||||
public StringArrayDataSection() {
|
||||
this.array = new ArrayList<String>();
|
||||
}
|
||||
|
||||
private final List<String> array;
|
||||
|
||||
public void writeString(String value) {
|
||||
this.array.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
|
||||
*/
|
||||
@Override
|
||||
public <T> void writeForParser(T data) throws UnsupportedOperationException {
|
||||
if (data instanceof String) {
|
||||
this.writeString((String) data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
|
||||
}
|
||||
}
|
||||
|
||||
public String readString(int index) {
|
||||
return this.array.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return this.array.iterator();
|
||||
}
|
||||
}
|
|
@ -1,45 +1,77 @@
|
|||
package tk.valoeghese.sod;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestMain
|
||||
{
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
//writeTest()
|
||||
class TestMain {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
writeTest();
|
||||
readTest();
|
||||
}
|
||||
|
||||
static void readTest() throws IOException
|
||||
{
|
||||
static void readTest() throws IOException {
|
||||
File f = new File("../test.sod");
|
||||
if (!f.createNewFile())
|
||||
{
|
||||
|
||||
if (!f.createNewFile()) {
|
||||
BinaryData bd = BinaryData.read(f);
|
||||
|
||||
StringArrayDataSection ds0 = bd.getStringArray("StringArray");
|
||||
|
||||
for (String s : ds0) {
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
DataSection ds1 = bd.get("DS1");
|
||||
for (Object i : ds1)
|
||||
{ System.out.println(i); }
|
||||
|
||||
for (Object i : ds1) {
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
DataSection ds2 = bd.get("yeet");
|
||||
for (Object i : ds2)
|
||||
{ System.out.println(i); }
|
||||
|
||||
for (Object i : ds2) {
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
ByteArrayDataSection ds3 = bd.getByteArray("ByteArray");
|
||||
|
||||
for (byte i : ds3) {
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void writeTest() throws IOException
|
||||
{
|
||||
static void writeTest() throws IOException {
|
||||
File f = new File("../test.sod");
|
||||
f.createNewFile();
|
||||
BinaryData bd = new BinaryData();
|
||||
|
||||
StringArrayDataSection ds0 = new StringArrayDataSection();
|
||||
ds0.writeString("Once upon a time");
|
||||
ds0.writeString("There was a programmer who went by the username of \"Valoeghese\"");
|
||||
ds0.writeString("One day he updated his data format SOD to have array sections");
|
||||
bd.put("StringArray", ds0);
|
||||
|
||||
DataSection ds1 = bd.getOrCreate("DS1");
|
||||
ds1.writeBoolean(false);
|
||||
ds1.writeDouble(0.666D);
|
||||
ds1.writeLong(69696969);
|
||||
ds1.writeString("yaY33T");
|
||||
|
||||
DataSection ds2 = bd.getOrCreate("yeet");
|
||||
ds2.writeByte((byte) 4);
|
||||
ds2.writeFloat(1.3F);
|
||||
ds2.writeString("e");
|
||||
ds2.writeString("ff");
|
||||
|
||||
ByteArrayDataSection ds3 = new ByteArrayDataSection();
|
||||
ds3.writeByte((byte)0);
|
||||
ds3.writeByte((byte)9);
|
||||
ds3.writeByte((byte)-10);
|
||||
bd.put("ByteArray", ds3);
|
||||
|
||||
bd.write(f);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package tk.valoeghese.sod.exception;
|
||||
|
||||
public class SODParseException extends RuntimeException
|
||||
{
|
||||
public class SODParseException extends RuntimeException {
|
||||
private static final long serialVersionUID = -3337517517501006140L;
|
||||
|
||||
public SODParseException(String message)
|
||||
{ super(message); }
|
||||
public SODParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue