Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ dependencies {
implementation 'com.github.seancfoley:ipaddress:5.3.3'

// Tests - JUnit 5
testImplementation("org.junit.jupiter:junit-jupiter-params:5.7.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2020-2021 DumbDogDiner <dumbdogdiner.com>. All rights reserved.
* Licensed under the MIT license, see LICENSE for more information...
*/
package com.dumbdogdiner.stickyapi.common.nbt;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import org.jetbrains.annotations.NotNull;


/**
* A convenience class for converting booleans from {@link JsonPrimitive}s, and for easily creating
*/
public class NbtBooleanTag extends NbtPrimitiveTag<Boolean> {
Comment thread
jcxldn marked this conversation as resolved.
private final boolean bool;

public NbtBooleanTag(boolean bool) {
this.bool = bool;
}

/**
* Converts a {@link JsonPrimitive} of a boolean to a new {@link NbtBooleanTag}
* It is recommended to make sure the primitive is a boolean first
*
* @param primitive The incoming {@link JsonPrimitive} to be converted, must be a boolean type!
* @return A new tag with tbe boolean value of the primitive
* @throws ClassCastException if the primitive is not a boolean
* @see JsonPrimitive#isBoolean()
*/
public static @NotNull NbtBooleanTag fromPrimitive(@NotNull JsonPrimitive primitive) throws ClassCastException {
return new NbtBooleanTag(primitive.getAsBoolean());
}

// As much as I hate the object form... we have to because generics
@Override
public @NotNull Boolean asPrimitive() {
return bool;
}

@Override
public @NotNull JsonElement toJson() {
return new JsonPrimitive(bool);
}

@Override
public @NotNull String toNbtString() {
return bool ? NbtNumberTag.TRUE.toNbtString() : NbtNumberTag.FALSE.toNbtString();
}

@Override
public boolean equals(Object other) {
if (other instanceof NbtBooleanTag) {
return ((NbtBooleanTag) other).asPrimitive() == bool;
} else if (other instanceof NbtNumberTag) {
return (!((NbtNumberTag) other).asPrimitive().equals(0)) == bool;
} else {
return false;
}
}

@Override
public int hashCode() {
return Boolean.hashCode(bool);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright (c) 2020-2021 DumbDogDiner <dumbdogdiner.com>. All rights reserved.
* Licensed under the MIT license, see LICENSE for more information...
*/
package com.dumbdogdiner.stickyapi.common.nbt;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;

/**
* A wrapper tag that allows working with Compound NBT tags as maps!
*/
public class NbtCompoundTag extends HashMap<String, NbtTag> implements NbtTag {

/**
* Creates a new {@link NbtCompoundTag} from an existing {@link Map}
* {@inheritDoc}
*/
public NbtCompoundTag(Map<String, NbtTag> map) {
super(map);
}

/**
* Create a new, blank {@link NbtCompoundTag}
*
* {@inheritDoc}
*/
public NbtCompoundTag() {
super();
}

/**
* Create a new {@link NbtCompoundTag} with an existing key and tag (useful for 1-element compound tags!)
* @param key The key to set
* @param tag The tag to assign
*/
public NbtCompoundTag(String key, NbtTag tag){
super();
put(key, tag);
}

/**
* Constructs a new {@link NbtCompoundTag} from a given {@link JsonObject}
*/
public static NbtCompoundTag fromJsonObject(JsonObject object){
NbtCompoundTag tag = new NbtCompoundTag();
for(String elementName : object.keySet()){
tag.put(elementName, NbtJsonAdapter.fromJson(object.get(elementName)));
}
return tag;
}

@Override
public @NotNull JsonElement toJson() {
JsonObject object = new JsonObject();
forEach((name, nbtTag) -> {
if(nbtTag instanceof NbtPrimitiveTag){
Object primitive = ((NbtPrimitiveTag<?>) nbtTag).asPrimitive();
if(primitive instanceof NbtNumberTag){
object.addProperty(name, ((NbtNumberTag) primitive).asPrimitive());
} else if(primitive instanceof NbtBooleanTag){
object.addProperty(name, ((NbtBooleanTag) primitive).asPrimitive());
} else if(primitive instanceof NbtStringTag){
object.addProperty(name, ((NbtStringTag) primitive).asPrimitive());
}
} else {
object.add(name, nbtTag.toJson());
}
});
return object;
}

@Override
public @NotNull String toNbtString() {
StringJoiner stringNbt = new StringJoiner(",", "{", "}");
forEach((name, nbtTag) -> {
StringJoiner element = new StringJoiner(":");
element.add(name);
element.add(nbtTag.toNbtString());
stringNbt.add(element.toString());
});
return stringNbt.toString();
}

/**
* Convenience method to add a number directly to the compound tag with a given key
* @return The original number
*/
public @NotNull Number put(@NotNull String key, @NotNull Number n) {
put(key, new NbtNumberTag(n));
return n;
}

/**
* Convenience method to add a boolean directly to the compound tag with a given key
* @return The original boolean
*/
public boolean put(@NotNull String key, boolean b) {
put(key, new NbtBooleanTag(b));
return b;
}

/**
* Convenience method to add a String directly to the compound tag with a given key
* @return The original String
*/
public String put(@NotNull String key, @NotNull String s){
put(key, new NbtStringTag(s));
return s;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2020-2021 DumbDogDiner <dumbdogdiner.com>. All rights reserved.
* Licensed under the MIT license, see LICENSE for more information...
*/
package com.dumbdogdiner.stickyapi.common.nbt;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;

import java.text.MessageFormat;

/**
* Utility class for easy creation of the appropriate {@link NbtTag} from an existing {@link JsonElement}
*/
@UtilityClass
public final class NbtJsonAdapter {
Comment thread
jcxldn marked this conversation as resolved.
/**
* Creates the appropriate tag from a given {@link JsonElement}, but never creates a {@link NbtJsonTag}
* @param element The incoming {@link JsonElement} to convert
* @return the new {@link NbtTag}
*/
public static NbtTag fromJson(@NotNull JsonElement element) {
if(element.isJsonArray()){
return NbtListTag.fromJsonArray(element.getAsJsonArray());
} else if(element.isJsonObject()){
return NbtCompoundTag.fromJsonObject(element.getAsJsonObject());
} else if (element.isJsonPrimitive()) {
// TODO: Rewrite to look cleaner?
// https://github.com/DumbDogDiner/StickyAPI/pull/92/files#r575639999
JsonPrimitive primitive = element.getAsJsonPrimitive();
if(primitive.isBoolean()){
return NbtBooleanTag.fromPrimitive(primitive);
} else if(primitive.isNumber()){
return NbtNumberTag.fromPrimitive(primitive);
} else if(primitive.isString()){
return NbtStringTag.fromPrimitive(primitive);
} else {
throw new UnsupportedOperationException("Illegal type of NBT primitive");
}
} else if(element.isJsonNull()) {
return null;
} else {
throw new UnsupportedOperationException(MessageFormat.format("This type of JSONElement is unsupported ({0})", element.getClass().getName()));
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2020-2021 DumbDogDiner <dumbdogdiner.com>. All rights reserved.
* Licensed under the MIT license, see LICENSE for more information...
*/
package com.dumbdogdiner.stickyapi.common.nbt;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import org.jetbrains.annotations.NotNull;

/**
* A special type of {@link NbtTag} that converts an arbitrary {@link JsonElement} into an appropriately escaped string as NBT
*/
public class NbtJsonTag implements NbtTag{
Comment thread
jcxldn marked this conversation as resolved.
private final @NotNull JsonElement element;
private static final Gson G = new GsonBuilder()
// Make sure things aren't weirdly escaped, may need to turn this back on
.disableHtmlEscaping()
.create();

public NbtJsonTag(@NotNull JsonElement element) {
this.element = element;
}

/**
* {@inheritDoc}
*/
@Override
public @NotNull JsonElement toJson() {
return element;
}

/**
* {@inheritDoc}
*/
@Override
public @NotNull String toNbtString() {
return '\'' + G.toJson(element)
// Because minecraft json is a hack on a hack.....
// And sometimes the NBT is just json that gets quoted

.replaceAll("(?<!\\\\)[']", "\\\\'") // Escape single quotes
// FIXME: do we need to escape double quotes too?? In theory we don't as long as we are using a single quote style!
.replace("\n", "\\n") // Replace new lines with escaped versions
.replaceAll("\\+n", "\\\\n") // Fix formatting of any escaped new lines already in there
+'\'';
}

@Override
public boolean equals(Object other) {
return ((other instanceof NbtJsonTag || other instanceof NbtStringTag)
&& toNbtString().equals(((NbtTag) other).toNbtString()));
}

@Override
public int hashCode() {
return element.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2020-2021 DumbDogDiner <dumbdogdiner.com>. All rights reserved.
* Licensed under the MIT license, see LICENSE for more information...
*/
package com.dumbdogdiner.stickyapi.common.nbt;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringJoiner;

/**
* A wrapper class that allows the construction of or conversion (from JSON) of NBT List Tags
*/

public class NbtListTag extends ArrayList<NbtTag> implements NbtTag {
Comment thread
jcxldn marked this conversation as resolved.
/**
* Generates a new, empty {@link NbtListTag}
* {@inheritDoc}
*/
public NbtListTag() {
super();
}

/**
* Generate a new {@link NbtListTag} with elements from an existing array or individual objects
*/
public NbtListTag(NbtTag ... tags){
super(Arrays.asList(tags));
}

/**
* Converts a JSON array into an NBT List tag of the native types
* @param arr The Json Array to convert
* @return the new {@link NbtListTag}
*/
public static NbtListTag fromJsonArray(JsonArray arr){
NbtListTag listTag = new NbtListTag();
for(JsonElement jse : arr){
listTag.add(NbtJsonAdapter.fromJson(jse));
}
return listTag;
}

/**
* Creates an NBT tag that is a list of stringified JSON elements from source array
* @param arr Source JSON array to convert
* @return The newly converted NBT list tag
*/
public static NbtListTag fromJsonArrayQuoted(JsonArray arr){
NbtListTag listTag = new NbtListTag();
for(JsonElement jse : arr){
listTag.add(new NbtJsonTag(jse));
}
return listTag;
}

@Override
public @NotNull JsonElement toJson() {
JsonArray array = new JsonArray();
for(NbtTag tag : this){
array.add(tag.toJson());
}
return array;
}

@Override
public @NotNull String toNbtString() {
StringJoiner joiner = new StringJoiner(",", "[", "]");
forEach(nbtTag -> joiner.add(nbtTag.toNbtString()));
return joiner.toString();
}

/**
* Creates a {@link NbtStringTag} of escaped NBT as a string
*/
public NbtStringTag toNbtStringTag() {
return new NbtStringTag(toNbtString(), true);
}
}
Loading