[PlutoUSS2/PlutoLib] Added PlutoUSS2
This commit is contained in:
parent
2ec489ee65
commit
9711c7d05b
|
@ -30,6 +30,7 @@ version numbers.*
|
|||
* **PlutoShader** - Stable
|
||||
* **PlutoSpriteSheet** - Stable, some features are unfinished
|
||||
* **PlutoStatic** - Stable, collision API nowhere near completion
|
||||
* **PlutoUSS2** - Stable
|
||||
|
||||
### Unstable submodules
|
||||
* **PlutoAudio** - Somewhat usable, unfinished
|
||||
|
@ -64,7 +65,7 @@ See `NEXT_RELEASE_DRAFT.md` for details.
|
|||
[ *Items not required immediately, planned to be implemented eventually.* ]
|
||||
* Allow multiple running instances of Pluto
|
||||
* Alternatively, if this deems too difficult to implement,
|
||||
prohibit the creation of more than instance per VM to avoid issues
|
||||
prohibit the creation of more than one instance per JVM to avoid issues
|
||||
* A networking API
|
||||
* Expand upon the Color API
|
||||
* Color mixing and blending
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
## 20.2.0.0-alpha.3
|
||||
* `[PlutoUSS2]` **Added USS2 as a new module**
|
||||
* `[PlutoLib]` `PlutoLib` now depends on `PlutoUSS2`
|
||||
* `[PlutoLib]` *Removed* `Severity`, use `SmartSeverity` instead
|
||||
* `[PlutoLib]` *Removed* `TextIn`, `TextOut`, `ResourceImage` and `ResourceInputStream`
|
||||
* `[PlutoLib]` *Removed* `StaticPlutoEventManager` as the implementation was too obscure
|
||||
|
@ -18,7 +20,7 @@
|
|||
* `[PlutoLib]` Created the Version API
|
||||
* Added the `IVersion` interface
|
||||
* Added support for version objects
|
||||
* As a result, all fields except the version string are no longer compile-time constants
|
||||
* As a result, all fields in `Pluto` except the version string are no longer compile-time constants
|
||||
* `[PlutoCore]` Made `PlutoApplication`'s constructor private
|
||||
* `[PlutoLib]` `MiniTimeParseException` no longer contains a hardcoded String message
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ task generateConfigs(type: Copy) {
|
|||
compileJava.dependsOn generateConfigs
|
||||
|
||||
dependencies {
|
||||
api project(":plutouss2")
|
||||
|
||||
api platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
|
||||
|
||||
api "com.google.code.findbugs:jsr305:3.0.2"
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
apply plugin: 'java-library'
|
||||
|
||||
description = "UniversalSerializationSystem 2 (formerly UserStorageSystem) is a simple library for " +
|
||||
"in-memory serialization of basic data types to ByteBuffers with versioned schema support."
|
||||
|
||||
dependencies {
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package cz.tefek.pluto.uss2.properties;
|
||||
|
||||
public enum EnumUSS2PropertyType
|
||||
{
|
||||
BYTE,
|
||||
INT,
|
||||
LONG,
|
||||
STRING,
|
||||
DOUBLE
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package cz.tefek.pluto.uss2.properties;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public final class USS2PropertyObject
|
||||
{
|
||||
final USS2PropertySchema schema;
|
||||
|
||||
final int currentVersion;
|
||||
final int latestVersion;
|
||||
boolean dirty;
|
||||
|
||||
final ByteBuffer data;
|
||||
|
||||
private USS2PropertyObject(ByteBuffer buf, USS2PropertySchema schema)
|
||||
{
|
||||
this.schema = schema;
|
||||
|
||||
if (buf.limit() != schema.getCapacity())
|
||||
throw new IllegalArgumentException("The input ByteBuffer's limit and the USS2PropertySchema size must be the same value!");
|
||||
|
||||
this.currentVersion = 0xff & buf.get(0);
|
||||
this.latestVersion = schema.getVersion();
|
||||
|
||||
if (this.currentVersion > this.latestVersion)
|
||||
throw new RuntimeException(String.format("The file's version (%d) is newer than what USS2 can read (%d)!", this.currentVersion, this.latestVersion));
|
||||
|
||||
this.data = buf;
|
||||
}
|
||||
|
||||
private static USS2PropertyObject upgrade(USS2PropertyObject po)
|
||||
{
|
||||
var poNew = create(po.schema);
|
||||
var props = po.schema.getProperties();
|
||||
props.forEach(property -> {
|
||||
if (property instanceof USS2PropertySchema.USS2Int)
|
||||
{
|
||||
var ussInt = (USS2PropertySchema.USS2Int) property;
|
||||
ussInt.write(poNew, ussInt.read(po));
|
||||
}
|
||||
else if (property instanceof USS2PropertySchema.USS2Long)
|
||||
{
|
||||
var ussLong = (USS2PropertySchema.USS2Long) property;
|
||||
ussLong.write(poNew, ussLong.read(po));
|
||||
}
|
||||
else if (property instanceof USS2PropertySchema.USS2Double)
|
||||
{
|
||||
var ussDouble = (USS2PropertySchema.USS2Double) property;
|
||||
ussDouble.write(poNew, ussDouble.read(po));
|
||||
}
|
||||
else if (property instanceof USS2PropertySchema.USS2Byte)
|
||||
{
|
||||
var ussByte = (USS2PropertySchema.USS2Byte) property;
|
||||
ussByte.write(poNew, ussByte.read(po));
|
||||
}
|
||||
else if (property instanceof USS2PropertySchema.USS2String)
|
||||
{
|
||||
var ussString = (USS2PropertySchema.USS2String) property;
|
||||
ussString.write(poNew, ussString.read(po));
|
||||
}
|
||||
});
|
||||
|
||||
return poNew;
|
||||
}
|
||||
|
||||
public static USS2PropertyObject create(USS2PropertySchema schema)
|
||||
{
|
||||
var buf = ByteBuffer.wrap(new byte[schema.getCapacity()]);
|
||||
buf.put(0, (byte) schema.getVersion());
|
||||
|
||||
var po = new USS2PropertyObject(buf, schema);
|
||||
po.dirty = true;
|
||||
|
||||
return po;
|
||||
}
|
||||
|
||||
public static USS2PropertyObject from(ByteBuffer buf, USS2PropertySchema schema)
|
||||
{
|
||||
var po = new USS2PropertyObject(buf, schema);
|
||||
|
||||
if (po.latestVersion != po.currentVersion)
|
||||
return upgrade(po);
|
||||
|
||||
return po;
|
||||
}
|
||||
|
||||
public ByteBuffer getData()
|
||||
{
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public byte[] getDataByteArray()
|
||||
{
|
||||
if (!this.data.hasArray())
|
||||
throw new RuntimeException("Data does not have a backing array!");
|
||||
|
||||
return this.data.array();
|
||||
}
|
||||
|
||||
public boolean isDirty()
|
||||
{
|
||||
return this.dirty;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,273 @@
|
|||
package cz.tefek.pluto.uss2.properties;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class USS2PropertySchema
|
||||
{
|
||||
public static final int DOES_NOT_EXIST_IN_VERSION = -1;
|
||||
public static final int MAX_VERSION = 0xff;
|
||||
|
||||
private final List<USS2Property> properties;
|
||||
|
||||
private final int capacity;
|
||||
|
||||
private int version;
|
||||
private final int[] offsets;
|
||||
|
||||
protected USS2PropertySchema(int capacity)
|
||||
{
|
||||
if (capacity < 16)
|
||||
throw new IllegalArgumentException("Please use a starting capacity of at least 16 bytes.");
|
||||
|
||||
this.properties = new ArrayList<>();
|
||||
this.offsets = new int[MAX_VERSION + 1];
|
||||
|
||||
// Version byte
|
||||
Arrays.fill(this.offsets, Byte.BYTES);
|
||||
|
||||
this.capacity = capacity;
|
||||
this.version = 0;
|
||||
}
|
||||
|
||||
public final String getInfo()
|
||||
{
|
||||
float used = this.offsets[MAX_VERSION] / (float) this.capacity;
|
||||
final int bars = 30;
|
||||
int usedBars = Math.round(used * bars);
|
||||
|
||||
return String.format("[%s%s] %.2f%% of schema used (%d/%d bytes).", "|".repeat(usedBars), " ".repeat(bars - usedBars), used * 100, this.offsets[MAX_VERSION], this.capacity);
|
||||
}
|
||||
|
||||
private void declareProperty(USS2Property property)
|
||||
{
|
||||
Arrays.fill(property.offsets, 0, property.version, DOES_NOT_EXIST_IN_VERSION);
|
||||
System.arraycopy(this.offsets, property.version, property.offsets, property.version, property.offsets.length - property.version);
|
||||
|
||||
// No need to check all versions, because the highest version is the largest by default (properties cannot be removed)
|
||||
if (this.offsets[MAX_VERSION] + property.objectSize > this.capacity)
|
||||
throw new IllegalStateException(
|
||||
String.format("Error: Declaring another property (of size %d) " +
|
||||
"would put the schema's total size to %d, which is over the capacity of %d.",
|
||||
property.objectSize,
|
||||
this.offsets[MAX_VERSION] + property.objectSize,
|
||||
this.capacity));
|
||||
|
||||
this.properties.add(property);
|
||||
|
||||
if (property.version > this.version)
|
||||
this.version = property.version;
|
||||
|
||||
for (int i = property.version; i <= MAX_VERSION; i++)
|
||||
this.offsets[i] += property.objectSize;
|
||||
}
|
||||
|
||||
public final List<USS2Property> getProperties()
|
||||
{
|
||||
return Collections.unmodifiableList(this.properties);
|
||||
}
|
||||
|
||||
public final int getVersion()
|
||||
{
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public final int getCapacity()
|
||||
{
|
||||
return this.capacity;
|
||||
}
|
||||
|
||||
protected final USS2Int declareInt(byte version)
|
||||
{
|
||||
var ussInt = new USS2Int(0xff & version);
|
||||
this.declareProperty(ussInt);
|
||||
return ussInt;
|
||||
}
|
||||
|
||||
protected final USS2Long declareLong(byte version)
|
||||
{
|
||||
var ussLong = new USS2Long(0xff & version);
|
||||
this.declareProperty(ussLong);
|
||||
return ussLong;
|
||||
}
|
||||
|
||||
protected final USS2Double declareDouble(byte version)
|
||||
{
|
||||
var ussDouble = new USS2Double(0xff & version);
|
||||
this.declareProperty(ussDouble);
|
||||
return ussDouble;
|
||||
}
|
||||
|
||||
protected final USS2Byte declareByte(byte version)
|
||||
{
|
||||
var ussByte = new USS2Byte(0xff & version);
|
||||
this.declareProperty(ussByte);
|
||||
return ussByte;
|
||||
}
|
||||
|
||||
protected final USS2String declareString(byte version, byte length)
|
||||
{
|
||||
var ussByte = new USS2String(0xff & version, 0xff & length);
|
||||
this.declareProperty(ussByte);
|
||||
return ussByte;
|
||||
}
|
||||
|
||||
public static abstract class USS2Property
|
||||
{
|
||||
private final int version;
|
||||
private final int objectSize;
|
||||
protected final int[] offsets;
|
||||
|
||||
protected USS2Property(int version, int objectSize)
|
||||
{
|
||||
this.version = version;
|
||||
this.objectSize = objectSize;
|
||||
this.offsets = new int[MAX_VERSION];
|
||||
}
|
||||
|
||||
final int getObjectSize()
|
||||
{
|
||||
return this.objectSize;
|
||||
}
|
||||
|
||||
int getVersion()
|
||||
{
|
||||
return this.version;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class USS2Int extends USS2Property
|
||||
{
|
||||
private USS2Int(int version)
|
||||
{
|
||||
super(version, Integer.BYTES);
|
||||
}
|
||||
|
||||
public final void write(USS2PropertyObject po, int value)
|
||||
{
|
||||
po.dirty = true;
|
||||
po.data.putInt(this.offsets[po.currentVersion], value);
|
||||
}
|
||||
|
||||
public final int read(USS2PropertyObject po)
|
||||
{
|
||||
if (this.offsets[po.currentVersion] == DOES_NOT_EXIST_IN_VERSION)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return po.data.getInt(this.offsets[po.currentVersion]);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class USS2Long extends USS2Property
|
||||
{
|
||||
private USS2Long(int version)
|
||||
{
|
||||
super(version, Long.BYTES);
|
||||
}
|
||||
|
||||
public final void write(USS2PropertyObject po, long value)
|
||||
{
|
||||
po.dirty = true;
|
||||
po.data.putLong(this.offsets[po.currentVersion], value);
|
||||
}
|
||||
|
||||
public final long read(USS2PropertyObject po)
|
||||
{
|
||||
if (this.offsets[po.currentVersion] == DOES_NOT_EXIST_IN_VERSION)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return po.data.getLong(this.offsets[po.currentVersion]);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class USS2Double extends USS2Property
|
||||
{
|
||||
private USS2Double(int version)
|
||||
{
|
||||
super(version, Double.BYTES);
|
||||
}
|
||||
|
||||
public final void write(USS2PropertyObject po, double value)
|
||||
{
|
||||
po.dirty = true;
|
||||
po.data.putDouble(this.offsets[po.currentVersion], value);
|
||||
}
|
||||
|
||||
public final double read(USS2PropertyObject po)
|
||||
{
|
||||
if (this.offsets[po.currentVersion] == DOES_NOT_EXIST_IN_VERSION)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return po.data.getDouble(this.offsets[po.currentVersion]);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class USS2Byte extends USS2Property
|
||||
{
|
||||
public USS2Byte(int version)
|
||||
{
|
||||
super(version, Byte.BYTES);
|
||||
}
|
||||
|
||||
public final void write(USS2PropertyObject po, byte value)
|
||||
{
|
||||
po.dirty = true;
|
||||
po.data.put(this.offsets[po.currentVersion], value);
|
||||
}
|
||||
|
||||
public final byte read(USS2PropertyObject po)
|
||||
{
|
||||
if (this.offsets[po.currentVersion] == DOES_NOT_EXIST_IN_VERSION)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return po.data.get(this.offsets[po.currentVersion]);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class USS2String extends USS2Property
|
||||
{
|
||||
private USS2String(int version, int length)
|
||||
{
|
||||
super(version, Byte.BYTES + length);
|
||||
}
|
||||
|
||||
public final void write(USS2PropertyObject po, String value)
|
||||
{
|
||||
po.dirty = true;
|
||||
var offset = this.offsets[po.currentVersion];
|
||||
var data = value.getBytes(StandardCharsets.UTF_8);
|
||||
po.data.position(offset);
|
||||
po.data.put((byte) data.length);
|
||||
po.data.put(data);
|
||||
po.data.rewind();
|
||||
}
|
||||
|
||||
public final String read(USS2PropertyObject po)
|
||||
{
|
||||
if (this.offsets[po.currentVersion] == DOES_NOT_EXIST_IN_VERSION)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var offset = this.offsets[po.currentVersion];
|
||||
po.data.position(offset);
|
||||
var length = po.data.get();
|
||||
var bytes = new byte[0xff & length];
|
||||
po.data.get(bytes);
|
||||
po.data.rewind();
|
||||
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
include 'plutolib',
|
||||
include 'plutouss2',
|
||||
'plutolib',
|
||||
'plutostatic',
|
||||
'plutotexturing',
|
||||
'plutomesher',
|
||||
|
|
Loading…
Reference in New Issue