2021-05-17 12:34:45 +02:00
|
|
|
package net.minestom.server.tag;
|
|
|
|
|
2022-03-20 01:47:57 +01:00
|
|
|
import net.minestom.server.item.ItemStack;
|
2022-03-23 08:49:40 +01:00
|
|
|
import net.minestom.server.utils.collection.IndexMap;
|
2021-05-17 17:46:56 +02:00
|
|
|
import org.jetbrains.annotations.ApiStatus;
|
2021-05-28 16:19:58 +02:00
|
|
|
import org.jetbrains.annotations.Contract;
|
2021-05-17 12:34:45 +02:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2021-05-17 12:44:22 +02:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2022-03-20 01:47:57 +01:00
|
|
|
import org.jglrxavpok.hephaistos.nbt.*;
|
2021-12-13 16:41:30 +01:00
|
|
|
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
2021-05-17 12:34:45 +02:00
|
|
|
|
2022-03-24 05:42:01 +01:00
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.List;
|
2021-05-17 12:34:45 +02:00
|
|
|
import java.util.function.Function;
|
2021-05-17 12:44:22 +02:00
|
|
|
import java.util.function.Supplier;
|
2021-05-17 12:34:45 +02:00
|
|
|
|
2021-05-17 15:14:16 +02:00
|
|
|
/**
|
|
|
|
* Represents a key to retrieve or change a value.
|
|
|
|
* <p>
|
|
|
|
* All tags are serializable.
|
|
|
|
*
|
|
|
|
* @param <T> the tag type
|
|
|
|
*/
|
2021-05-17 17:46:56 +02:00
|
|
|
@ApiStatus.NonExtendable
|
|
|
|
public class Tag<T> {
|
2022-03-23 08:49:40 +01:00
|
|
|
private static final IndexMap<String> INDEX_MAP = new IndexMap<>();
|
2021-06-22 02:51:04 +02:00
|
|
|
|
2022-03-24 05:42:01 +01:00
|
|
|
record PathEntry(String name, int index) {
|
|
|
|
}
|
|
|
|
|
2021-05-17 12:34:45 +02:00
|
|
|
private final String key;
|
2022-03-23 06:51:36 +01:00
|
|
|
final Function<NBT, T> readFunction;
|
|
|
|
final Function<T, NBT> writeFunction;
|
2021-05-28 16:19:58 +02:00
|
|
|
private final Supplier<T> defaultValue;
|
2021-05-17 12:44:22 +02:00
|
|
|
|
2022-03-20 01:47:57 +01:00
|
|
|
final int index;
|
|
|
|
|
2022-03-24 05:42:01 +01:00
|
|
|
final List<PathEntry> path;
|
|
|
|
|
2022-03-20 01:47:57 +01:00
|
|
|
protected Tag(@NotNull String key,
|
|
|
|
@NotNull Function<NBT, T> readFunction,
|
|
|
|
@NotNull Function<T, NBT> writeFunction,
|
2022-03-24 05:42:01 +01:00
|
|
|
@Nullable Supplier<T> defaultValue,
|
|
|
|
@Nullable List<PathEntry> path) {
|
|
|
|
this.index = INDEX_MAP.get(key);
|
2021-05-17 12:34:45 +02:00
|
|
|
this.key = key;
|
|
|
|
this.readFunction = readFunction;
|
2022-03-20 01:47:57 +01:00
|
|
|
this.writeFunction = writeFunction;
|
2021-05-28 16:19:58 +02:00
|
|
|
this.defaultValue = defaultValue;
|
2022-03-24 05:42:01 +01:00
|
|
|
this.path = path;
|
2021-05-28 16:19:58 +02:00
|
|
|
}
|
|
|
|
|
2022-03-20 01:47:57 +01:00
|
|
|
static <T, N extends NBT> Tag<T> tag(@NotNull String key,
|
|
|
|
@NotNull Function<N, T> readFunction,
|
|
|
|
@NotNull Function<T, N> writeFunction) {
|
2022-03-24 05:42:01 +01:00
|
|
|
return new Tag<>(key, (Function<NBT, T>) readFunction, (Function<T, NBT>) writeFunction, null, null);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
2021-06-26 05:08:33 +02:00
|
|
|
/**
|
|
|
|
* Returns the key used to navigate inside the holder nbt.
|
|
|
|
*
|
|
|
|
* @return the tag key
|
|
|
|
*/
|
2022-03-20 01:47:57 +01:00
|
|
|
public @NotNull String getKey() {
|
2021-05-17 12:34:45 +02:00
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2021-05-28 16:19:58 +02:00
|
|
|
@Contract(value = "_ -> new", pure = true)
|
2021-05-17 12:44:22 +02:00
|
|
|
public Tag<T> defaultValue(@NotNull Supplier<T> defaultValue) {
|
2022-03-24 05:42:01 +01:00
|
|
|
return new Tag<>(key, readFunction, writeFunction, defaultValue, path);
|
2021-05-17 12:44:22 +02:00
|
|
|
}
|
|
|
|
|
2021-05-28 16:19:58 +02:00
|
|
|
@Contract(value = "_ -> new", pure = true)
|
2021-05-17 12:44:22 +02:00
|
|
|
public Tag<T> defaultValue(@NotNull T defaultValue) {
|
2021-05-28 16:21:54 +02:00
|
|
|
return defaultValue(() -> defaultValue);
|
2021-05-28 16:19:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Contract(value = "_, _ -> new", pure = true)
|
|
|
|
public <R> Tag<R> map(@NotNull Function<T, R> readMap,
|
|
|
|
@NotNull Function<R, T> writeMap) {
|
2021-06-22 02:51:04 +02:00
|
|
|
return new Tag<>(key,
|
2021-05-28 16:19:58 +02:00
|
|
|
// Read
|
2022-03-20 01:47:57 +01:00
|
|
|
readFunction.andThen(t -> {
|
|
|
|
if (t == null) return null;
|
|
|
|
return readMap.apply(t);
|
|
|
|
}),
|
2021-05-28 16:19:58 +02:00
|
|
|
// Write
|
2022-03-20 01:47:57 +01:00
|
|
|
writeMap.andThen(writeFunction),
|
2021-05-28 16:19:58 +02:00
|
|
|
// Default value
|
2022-03-24 05:42:01 +01:00
|
|
|
() -> readMap.apply(createDefault()),
|
|
|
|
path);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ApiStatus.Experimental
|
|
|
|
@Contract(value = "_ -> new", pure = true)
|
|
|
|
public Tag<T> path(@NotNull String @Nullable ... path) {
|
|
|
|
final List<PathEntry> entries = path != null ? Arrays.stream(path).map(s -> new PathEntry(s, INDEX_MAP.get(s))).toList() : null;
|
|
|
|
return new Tag<>(key, readFunction, writeFunction, defaultValue, entries);
|
2021-05-17 12:44:22 +02:00
|
|
|
}
|
|
|
|
|
2022-03-20 01:47:57 +01:00
|
|
|
public @Nullable T read(@NotNull NBTCompoundLike nbt) {
|
|
|
|
final String key = this.key;
|
2022-03-23 06:51:36 +01:00
|
|
|
final NBT readable = key.isEmpty() ? nbt.toCompound() : nbt.get(key);
|
|
|
|
final T result;
|
|
|
|
try {
|
|
|
|
if (readable == null || (result = readFunction.apply(readable)) == null)
|
|
|
|
return createDefault();
|
|
|
|
return result;
|
|
|
|
} catch (ClassCastException e) {
|
|
|
|
return createDefault();
|
2021-05-17 13:04:00 +02:00
|
|
|
}
|
2022-03-20 01:47:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
T createDefault() {
|
|
|
|
final var supplier = defaultValue;
|
|
|
|
return supplier != null ? supplier.get() : null;
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
2021-12-13 16:41:30 +01:00
|
|
|
public void write(@NotNull MutableNBTCompound nbtCompound, @Nullable T value) {
|
2022-03-20 01:47:57 +01:00
|
|
|
final String key = this.key;
|
|
|
|
if (value != null) {
|
|
|
|
final NBT nbt = writeFunction.apply(value);
|
|
|
|
if (key.isEmpty()) nbtCompound.copyFrom((NBTCompoundLike) nbt);
|
|
|
|
else nbtCompound.set(key, nbt);
|
2021-05-17 13:04:00 +02:00
|
|
|
} else {
|
2022-03-20 01:47:57 +01:00
|
|
|
if (key.isEmpty()) nbtCompound.clear();
|
|
|
|
else nbtCompound.remove(key);
|
2021-05-17 13:04:00 +02:00
|
|
|
}
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
2021-12-13 16:41:30 +01:00
|
|
|
public void writeUnsafe(@NotNull MutableNBTCompound nbtCompound, @Nullable Object value) {
|
2021-12-16 01:22:42 +01:00
|
|
|
//noinspection unchecked
|
2021-06-22 02:51:04 +02:00
|
|
|
write(nbtCompound, (T) value);
|
|
|
|
}
|
|
|
|
|
2021-05-17 12:34:45 +02:00
|
|
|
public static @NotNull Tag<Byte> Byte(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, NBTByte::getValue, NBT::Byte);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static @NotNull Tag<Short> Short(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, NBTShort::getValue, NBT::Short);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static @NotNull Tag<Integer> Integer(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, NBTInt::getValue, NBT::Int);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static @NotNull Tag<Long> Long(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, NBTLong::getValue, NBT::Long);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static @NotNull Tag<Float> Float(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, NBTFloat::getValue, NBT::Float);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static @NotNull Tag<Double> Double(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, NBTDouble::getValue, NBT::Double);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static @NotNull Tag<String> String(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, NBTString::getValue, NBT::String);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
2021-06-22 02:51:04 +02:00
|
|
|
public static <T extends NBT> @NotNull Tag<T> NBT(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return Tag.<T, T>tag(key, nbt -> nbt, t -> t);
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|
|
|
|
|
2021-06-22 02:51:04 +02:00
|
|
|
/**
|
|
|
|
* Create a wrapper around a compound.
|
|
|
|
*
|
|
|
|
* @param key the tag key
|
|
|
|
* @param serializer the tag serializer
|
|
|
|
* @param <T> the tag type
|
|
|
|
* @return the created tag
|
|
|
|
*/
|
|
|
|
public static <T> @NotNull Tag<T> Structure(@NotNull String key, @NotNull TagSerializer<T> serializer) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key,
|
|
|
|
(NBTCompound compound) -> serializer.read(TagHandler.fromCompound(compound)),
|
2022-03-20 01:47:57 +01:00
|
|
|
(value) -> {
|
|
|
|
TagHandler handler = TagHandler.newHandler();
|
|
|
|
serializer.write(handler, value);
|
|
|
|
return handler.asCompound();
|
2021-05-28 16:19:58 +02:00
|
|
|
});
|
2021-05-17 14:02:14 +02:00
|
|
|
}
|
2021-06-22 02:51:04 +02:00
|
|
|
|
|
|
|
public static <T> @NotNull Tag<T> View(@NotNull TagSerializer<T> serializer) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag("",
|
|
|
|
(NBTCompound compound) -> serializer.read(TagHandler.fromCompound(compound)),
|
2022-03-20 01:47:57 +01:00
|
|
|
(value) -> {
|
|
|
|
TagHandler handler = TagHandler.newHandler();
|
|
|
|
serializer.write(handler, value);
|
|
|
|
return handler.asCompound();
|
|
|
|
});
|
2021-12-16 20:11:17 +01:00
|
|
|
}
|
|
|
|
|
2022-03-20 01:47:57 +01:00
|
|
|
public static @NotNull Tag<ItemStack> ItemStack(@NotNull String key) {
|
2022-03-23 07:04:05 +01:00
|
|
|
return tag(key, ItemStack::fromItemNBT, ItemStack::toItemNBT);
|
2021-06-22 03:05:22 +02:00
|
|
|
}
|
2021-05-17 12:34:45 +02:00
|
|
|
}
|