Skip to content

Commit

Permalink
update version, util classes and readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Querz committed Apr 25, 2020
1 parent a17ae03 commit 6887824
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 70 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2016 Querz
Copyright (c) 2016 - 2020 Querz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
38 changes: 7 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# NBT
[![Build Status](https://travis-ci.org/Querz/NBT.svg?branch=master)](https://travis-ci.org/Querz/NBT) [![Coverage Status](https://img.shields.io/coveralls/github/Querz/NBT/master.svg)](https://coveralls.io/github/Querz/NBT?branch=master) [![Release](https://jitpack.io/v/Querz/NBT.svg)](https://jitpack.io/#Querz/NBT)
#### A java implementation of the [NBT protocol](http://minecraft.gamepedia.com/NBT_format), including a way to implement custom tags.
#### A java implementation of the [NBT protocol](http://minecraft.gamepedia.com/NBT_format) for Minecraft Java Edition.
---
### Specification
According to the [specification](https://minecraft.gamepedia.com/NBT_format), there are currently 13 different types of tags:
Expand Down Expand Up @@ -56,33 +56,31 @@ Some methods do not provide a parameter to specify the maximum depth, but instea
### Utility
There are several utility methods to make your life easier if you use this library.
#### NBTUtil
`NBTUtil.writeTag()` lets you write a Tag into a gzip compressed or uncompressed file in one line (not counting exception handling). Files are gzip compressed by default.
`NBTUtil.write()` lets you write a Tag into a gzip compressed or uncompressed file in one line (not counting exception handling). Files are gzip compressed by default.

Example usage:
```java
NBTUtil.writeTag(tag, "filename.dat");
NBTUtil.write(namedTag, "filename.dat");
```
`NBTUtil.readTag()` reads any file containing NBT data. No worry about compression, it will automatically uncompress gzip compressed files.
`NBTUtil.read()` reads any file containing NBT data. No worry about compression, it will automatically uncompress gzip compressed files.

Example usage:
```java
Tag<?> tag = NBTUtil.readTag("filename.dat");
NamedTag namedTag = NBTUtil.read("filename.dat");
```
#### Playing Minecraft?
Each tag can be converted into a JSON-like NBT String used in Minecraft commands.
Each tag can be converted into an NBT String (SNBT) used in Minecraft commands.

Example usage:
```java
CompoundTag c = new CompoundTag();
c.putByte("blah", (byte) 5);
c.putString("foo", "bär");
System.out.println(c.toTagString()); // {blah:5b,foo:"bär"}

ListTag<StringTag> s = new ListTag<>(StringTag.class);
s.addString("test");
s.add(new StringTag("text"));
c.add("list", s);
System.out.println(c.toTagString()); // {blah:5b,foo:"bär",list:[test,text]}
System.out.println(SNBTUtil.toSNBT(c)); // {blah:5b,foo:"bär",list:[test,text]}

```
There is also a tool to read, change and write MCA files.
Expand Down Expand Up @@ -117,25 +115,3 @@ mcaFile.cleanupPalettesAndBlockStates();
chunk.cleanupPalettesAndBlockStates();
section.cleanupPaletteAndBlockStates();
```

---
### Custom tags
Interested in more advanced features, and the default NBT protocol just isn't enough? Simply create your own tags!
There are 4 example classes in `net.querz.nbt.custom` that show how to implement custom tags:
| Class | ID | Description |
| ------------- | :-: | ----------- |
| [ObjectTag](src/main/java/net/querz/nbt/custom/ObjectTag.java) | 90 | A wrapper tag that serializes and deserializes any object using the default java serialization. |
| [ShortArrayTag](src/main/java/net/querz/nbt/custom/ShortArrayTag.java) | 100 | In addition to the already existing `ByteArrayTag`, `IntArrayTag` and `LongArrayTag`. |
| [CharTag](src/main/java/net/querz/nbt/custom/CharTag.java) | 110 | `Character` (char) tag. |
| [StructTag](src/main/java/net/querz/nbt/custom/StructTag.java) | 120 | Similar to the `ListTag`, but with the ability to store multiple types. |
To be able to use a custom tag with deserialization, a `Supplier` and the custom tag class must be registered at runtime alongside its id with `TagFactory.registerCustomTag()`. The `Supplier` can be anything that returns a new instance of this custom tag. Here is an example using the custom tags no-args constructor:
```java
TagFactory.registerCustomTag(90, ObjectTag::new, ObjectTag.class);
```
#### Nesting
As mentioned before, serialization and deserialization methods are provided with a parameter indicating the maximum processing depth of the structure. This is not guaranteed when using custom tags, it is the responsibility of the creator of that custom tag to call `Tag#decrementMaxDepth(int)` to correctly update the nesting depth.
It is also highly encouraged to document the custom tag behaviour when it does so to make users aware of the possible exceptions thrown by `Tag#decrementMaxDepth(int)`.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ apply plugin: 'jacoco'

group = 'net.querz.nbt'
archivesBaseName = 'nbt'
version = '4.0'
version = '5.0'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
compileJava.options.encoding = 'UTF-8'
Expand Down
32 changes: 16 additions & 16 deletions src/main/java/net/querz/mca/MCAUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public final class MCAUtil {
private MCAUtil() {}

/**
* @see MCAUtil#readMCAFile(File)
* @see MCAUtil#read(File)
* @param file The file to read the data from.
* @return An in-memory representation of the MCA file with decompressed chunk data.
* @throws IOException if something during deserialization goes wrong.
* */
public static MCAFile readMCAFile(String file) throws IOException {
return readMCAFile(new File(file));
public static MCAFile read(String file) throws IOException {
return read(new File(file));
}

/**
Expand All @@ -32,7 +32,7 @@ public static MCAFile readMCAFile(String file) throws IOException {
* @return An in-memory representation of the MCA file with decompressed chunk data.
* @throws IOException if something during deserialization goes wrong.
* */
public static MCAFile readMCAFile(File file) throws IOException {
public static MCAFile read(File file) throws IOException {
MCAFile mcaFile = newMCAFile(file);
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
mcaFile.deserialize(raf);
Expand All @@ -41,39 +41,39 @@ public static MCAFile readMCAFile(File file) throws IOException {
}

/**
* Calls {@link MCAUtil#writeMCAFile(MCAFile, File, boolean)} without changing the timestamps.
* @see MCAUtil#writeMCAFile(MCAFile, File, boolean)
* Calls {@link MCAUtil#write(MCAFile, File, boolean)} without changing the timestamps.
* @see MCAUtil#write(MCAFile, File, boolean)
* @param file The file to write to.
* @param mcaFile The data of the MCA file to write.
* @return The amount of chunks written to the file.
* @throws IOException If something goes wrong during serialization.
* */
public static int writeMCAFile(MCAFile mcaFile, String file) throws IOException {
return writeMCAFile(mcaFile, new File(file), false);
public static int write(MCAFile mcaFile, String file) throws IOException {
return write(mcaFile, new File(file), false);
}

/**
* Calls {@link MCAUtil#writeMCAFile(MCAFile, File, boolean)} without changing the timestamps.
* @see MCAUtil#writeMCAFile(MCAFile, File, boolean)
* Calls {@link MCAUtil#write(MCAFile, File, boolean)} without changing the timestamps.
* @see MCAUtil#write(MCAFile, File, boolean)
* @param file The file to write to.
* @param mcaFile The data of the MCA file to write.
* @return The amount of chunks written to the file.
* @throws IOException If something goes wrong during serialization.
* */
public static int writeMCAFile(MCAFile mcaFile, File file) throws IOException {
return writeMCAFile(mcaFile, file, false);
public static int write(MCAFile mcaFile, File file) throws IOException {
return write(mcaFile, file, false);
}

/**
* @see MCAUtil#writeMCAFile(MCAFile, File, boolean)
* @see MCAUtil#write(MCAFile, File, boolean)
* @param file The file to write to.
* @param mcaFile The data of the MCA file to write.
* @param changeLastUpdate Whether to adjust the timestamps of when the file was saved.
* @return The amount of chunks written to the file.
* @throws IOException If something goes wrong during serialization.
* */
public static int writeMCAFile(MCAFile mcaFile, String file, boolean changeLastUpdate) throws IOException {
return writeMCAFile(mcaFile, new File(file), changeLastUpdate);
public static int write(MCAFile mcaFile, String file, boolean changeLastUpdate) throws IOException {
return write(mcaFile, new File(file), changeLastUpdate);
}

/**
Expand All @@ -87,7 +87,7 @@ public static int writeMCAFile(MCAFile mcaFile, String file, boolean changeLastU
* @return The amount of chunks written to the file.
* @throws IOException If something goes wrong during serialization.
* */
public static int writeMCAFile(MCAFile mcaFile, File file, boolean changeLastUpdate) throws IOException {
public static int write(MCAFile mcaFile, File file, boolean changeLastUpdate) throws IOException {
File to = file;
if (file.exists()) {
to = File.createTempFile(to.getName(), null);
Expand Down
28 changes: 14 additions & 14 deletions src/test/java/net/querz/mca/MCAFileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ public void testGetChunkIndex() {
}

public void testChangeData() {
MCAFile mcaFile = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile mcaFile = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertNotNull(mcaFile);
mcaFile.setChunk(0, null);
File tmpFile = getNewTmpFile("r.2.2.mca");
Integer x = assertThrowsNoException(() -> MCAUtil.writeMCAFile(mcaFile, tmpFile, true));
Integer x = assertThrowsNoException(() -> MCAUtil.write(mcaFile, tmpFile, true));
assertNotNull(x);
assertEquals(2, x.intValue());
MCAFile again = assertThrowsNoException(() -> MCAUtil.readMCAFile(tmpFile));
MCAFile again = assertThrowsNoException(() -> MCAUtil.read(tmpFile));
assertNotNull(again);
for (int i = 0; i < 1024; i++) {
if (i != 512 && i != 1023) {
Expand All @@ -47,11 +47,11 @@ public void testChangeData() {
}

public void testChangeLastUpdate() {
MCAFile from = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile from = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertNotNull(from);
File tmpFile = getNewTmpFile("r.2.2.mca");
assertThrowsNoException(() -> MCAUtil.writeMCAFile(from, tmpFile, true));
MCAFile to = assertThrowsNoException(() -> MCAUtil.readMCAFile(tmpFile));
assertThrowsNoException(() -> MCAUtil.write(from, tmpFile, true));
MCAFile to = assertThrowsNoException(() -> MCAUtil.read(tmpFile));
assertNotNull(to);
assertFalse(from.getChunk(0).getLastMCAUpdate() == to.getChunk(0).getLastMCAUpdate());
assertFalse(from.getChunk(512).getLastMCAUpdate() == to.getChunk(512).getLastMCAUpdate());
Expand All @@ -61,7 +61,7 @@ public void testChangeLastUpdate() {
}

public void testGetters() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertNotNull(f);

assertThrowsRuntimeException(() -> f.getChunk(-1), IndexOutOfBoundsException.class);
Expand Down Expand Up @@ -180,7 +180,7 @@ public void testSetters() {
}

public void testGetBiomeAt() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertEquals(21, f.getBiomeAt(1024, 1024));
assertEquals(-1, f.getBiomeAt(1040, 1024));
f.setChunk(0, 1, Chunk.newChunk());
Expand All @@ -189,7 +189,7 @@ public void testGetBiomeAt() {
}

public void testSetBiomeAt() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")), true);
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")), true);
f.setBiomeAt(1024, 1024, 20);
assertEquals(20, f.getChunk(64, 64).updateHandle(64, 64).getCompoundTag("Level").getIntArray("Biomes")[0]);
f.setBiomeAt(1039, 1039, 47);
Expand All @@ -203,7 +203,7 @@ public void testSetBiomeAt() {
}

public void testCleanupPaletteAndBlockStates() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertThrowsNoRuntimeException(f::cleanupPalettesAndBlockStates);
Chunk c = f.getChunk(0, 0);
Section s = c.getSection(0);
Expand Down Expand Up @@ -233,7 +233,7 @@ public void testCleanupPaletteAndBlockStates() {
}

public void testSetBlockDataAt() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
Section section = f.getChunk(0, 0).getSection(0);
assertEquals(10, section.getPalette().size());
assertEquals(0b0001000100010001000100010001000100010001000100010001000100010001L, section.getBlockStates()[0]);
Expand Down Expand Up @@ -299,7 +299,7 @@ public void testSetBlockDataAt() {
}

public void testGetBlockDataAt() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertEquals(block("minecraft:bedrock"), f.getBlockStateAt(0, 0, 0));
assertNull(f.getBlockStateAt(16, 0, 0));
assertEquals(block("minecraft:dirt"), f.getBlockStateAt(0, 62, 0));
Expand All @@ -308,12 +308,12 @@ public void testGetBlockDataAt() {
}

public void testGetChunkStatus() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertEquals("mobs_spawned", f.getChunk(0, 0).getStatus());
}

public void testSetChunkStatus() {
MCAFile f = assertThrowsNoException(() -> MCAUtil.readMCAFile(copyResourceToTmp("r.2.2.mca")));
MCAFile f = assertThrowsNoException(() -> MCAUtil.read(copyResourceToTmp("r.2.2.mca")));
assertThrowsNoRuntimeException(() -> f.getChunk(0, 0).setStatus("base"));
assertEquals("base", f.getChunk(0, 0).updateHandle(64, 64).getCompoundTag("Level").getString("Status"));
assertNull(f.getChunk(1, 0));
Expand Down
14 changes: 7 additions & 7 deletions src/test/java/net/querz/mca/MCAUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ public void testCreateNameFromLocation() {
}

public void testMakeMyCoverageGreatAgain() {
assertThrowsException(() -> MCAUtil.readMCAFile((String) null), NullPointerException.class);
assertThrowsException(() -> MCAUtil.writeMCAFile(null, (String) null), NullPointerException.class);
assertThrowsException(() -> MCAUtil.writeMCAFile(null, (File) null), NullPointerException.class);
assertThrowsException(() -> MCAUtil.writeMCAFile(null, (String) null, false), NullPointerException.class);
assertThrowsException(() -> MCAUtil.readMCAFile("r.a.b.mca"), IllegalArgumentException.class);
assertThrowsException(() -> MCAUtil.read((String) null), NullPointerException.class);
assertThrowsException(() -> MCAUtil.write(null, (String) null), NullPointerException.class);
assertThrowsException(() -> MCAUtil.write(null, (File) null), NullPointerException.class);
assertThrowsException(() -> MCAUtil.write(null, (String) null, false), NullPointerException.class);
assertThrowsException(() -> MCAUtil.read("r.a.b.mca"), IllegalArgumentException.class);
assertThrowsNoException(() -> new MCAFile(0, 0).serialize(null)); // empty MCAFile will not even attempt to write to file

// test overwriting file
MCAFile m = new MCAFile(0, 0);
m.setChunk(0, Chunk.newChunk());
assertThrowsNoException(() -> MCAUtil.writeMCAFile(m, getTmpFile("r.0.0.mca"), false), true);
assertThrowsNoException(() -> MCAUtil.writeMCAFile(m, getTmpFile("r.0.0.mca"), false), true);
assertThrowsNoException(() -> MCAUtil.write(m, getTmpFile("r.0.0.mca"), false), true);
assertThrowsNoException(() -> MCAUtil.write(m, getTmpFile("r.0.0.mca"), false), true);
}
}

0 comments on commit 6887824

Please sign in to comment.