449 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			449 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.nbt;
 | |
| 
 | |
| import com.mojang.datafixers.util.Pair;
 | |
| import com.mojang.serialization.DataResult;
 | |
| import com.mojang.serialization.DynamicOps;
 | |
| import com.mojang.serialization.MapLike;
 | |
| import com.mojang.serialization.RecordBuilder;
 | |
| import com.mojang.serialization.RecordBuilder.AbstractStringBuilder;
 | |
| import it.unimi.dsi.fastutil.bytes.ByteArrayList;
 | |
| import it.unimi.dsi.fastutil.ints.IntArrayList;
 | |
| import it.unimi.dsi.fastutil.longs.LongArrayList;
 | |
| import java.nio.ByteBuffer;
 | |
| import java.util.ArrayList;
 | |
| import java.util.Arrays;
 | |
| import java.util.List;
 | |
| import java.util.Map;
 | |
| import java.util.Optional;
 | |
| import java.util.Map.Entry;
 | |
| import java.util.function.BiConsumer;
 | |
| import java.util.function.Consumer;
 | |
| import java.util.stream.IntStream;
 | |
| import java.util.stream.LongStream;
 | |
| import java.util.stream.Stream;
 | |
| import net.minecraft.Util;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| public class NbtOps implements DynamicOps<Tag> {
 | |
| 	public static final NbtOps INSTANCE = new NbtOps();
 | |
| 
 | |
| 	private NbtOps() {
 | |
| 	}
 | |
| 
 | |
| 	public Tag empty() {
 | |
| 		return EndTag.INSTANCE;
 | |
| 	}
 | |
| 
 | |
| 	public <U> U convertTo(DynamicOps<U> ops, Tag tag) {
 | |
| 		return (U)(switch (tag) {
 | |
| 			case EndTag endTag -> (Object)ops.empty();
 | |
| 			case ByteTag(byte var34) -> (Object)ops.createByte(var34);
 | |
| 			case ShortTag(short var35) -> (Object)ops.createShort(var35);
 | |
| 			case IntTag(int var36) -> (Object)ops.createInt(var36);
 | |
| 			case LongTag(long var37) -> (Object)ops.createLong(var37);
 | |
| 			case FloatTag(float var38) -> (Object)ops.createFloat(var38);
 | |
| 			case DoubleTag(double var39) -> (Object)ops.createDouble(var39);
 | |
| 			case ByteArrayTag byteArrayTag -> (Object)ops.createByteList(ByteBuffer.wrap(byteArrayTag.getAsByteArray()));
 | |
| 			case StringTag(String var40) -> (Object)ops.createString(var40);
 | |
| 			case ListTag listTag -> (Object)this.convertList(ops, listTag);
 | |
| 			case CompoundTag compoundTag -> (Object)this.convertMap(ops, compoundTag);
 | |
| 			case IntArrayTag intArrayTag -> (Object)ops.createIntList(Arrays.stream(intArrayTag.getAsIntArray()));
 | |
| 			case LongArrayTag longArrayTag -> (Object)ops.createLongList(Arrays.stream(longArrayTag.getAsLongArray()));
 | |
| 			default -> throw new MatchException(null, null);
 | |
| 		});
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Number> getNumberValue(Tag tag) {
 | |
| 		return (DataResult<Number>)tag.asNumber().map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Not a number"));
 | |
| 	}
 | |
| 
 | |
| 	public Tag createNumeric(Number data) {
 | |
| 		return DoubleTag.valueOf(data.doubleValue());
 | |
| 	}
 | |
| 
 | |
| 	public Tag createByte(byte data) {
 | |
| 		return ByteTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createShort(short data) {
 | |
| 		return ShortTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createInt(int data) {
 | |
| 		return IntTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createLong(long data) {
 | |
| 		return LongTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createFloat(float data) {
 | |
| 		return FloatTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createDouble(double data) {
 | |
| 		return DoubleTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createBoolean(boolean data) {
 | |
| 		return ByteTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<String> getStringValue(Tag tag) {
 | |
| 		return tag instanceof StringTag(String var4) ? DataResult.success(var4) : DataResult.error(() -> "Not a string");
 | |
| 	}
 | |
| 
 | |
| 	public Tag createString(String data) {
 | |
| 		return StringTag.valueOf(data);
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Tag> mergeToList(Tag list, Tag tag) {
 | |
| 		return (DataResult<Tag>)createCollector(list)
 | |
| 			.map(listCollector -> DataResult.success(listCollector.accept(tag).result()))
 | |
| 			.orElseGet(() -> DataResult.error(() -> "mergeToList called with not a list: " + list, list));
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Tag> mergeToList(Tag list, List<Tag> tags) {
 | |
| 		return (DataResult<Tag>)createCollector(list)
 | |
| 			.map(listCollector -> DataResult.success(listCollector.acceptAll(tags).result()))
 | |
| 			.orElseGet(() -> DataResult.error(() -> "mergeToList called with not a list: " + list, list));
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Tag> mergeToMap(Tag map, Tag key, Tag value) {
 | |
| 		if (!(map instanceof CompoundTag) && !(map instanceof EndTag)) {
 | |
| 			return DataResult.error(() -> "mergeToMap called with not a map: " + map, map);
 | |
| 		} else if (key instanceof StringTag(String var10)) {
 | |
| 			String compoundTag = var10;
 | |
| 			CompoundTag compoundTag2 = map instanceof CompoundTag compoundTagx ? compoundTagx.shallowCopy() : new CompoundTag();
 | |
| 			compoundTag2.put(compoundTag, value);
 | |
| 			return DataResult.success(compoundTag2);
 | |
| 		} else {
 | |
| 			return DataResult.error(() -> "key is not a string: " + key, map);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Tag> mergeToMap(Tag map, MapLike<Tag> otherMap) {
 | |
| 		if (!(map instanceof CompoundTag) && !(map instanceof EndTag)) {
 | |
| 			return DataResult.error(() -> "mergeToMap called with not a map: " + map, map);
 | |
| 		} else {
 | |
| 			CompoundTag compoundTag2 = map instanceof CompoundTag compoundTag ? compoundTag.shallowCopy() : new CompoundTag();
 | |
| 			List<Tag> list = new ArrayList();
 | |
| 			otherMap.entries().forEach(pair -> {
 | |
| 				Tag tag = (Tag)pair.getFirst();
 | |
| 				if (tag instanceof StringTag(String string)) {
 | |
| 					compoundTag2.put(string, (Tag)pair.getSecond());
 | |
| 				} else {
 | |
| 					list.add(tag);
 | |
| 				}
 | |
| 			});
 | |
| 			return !list.isEmpty() ? DataResult.error(() -> "some keys are not strings: " + list, compoundTag2) : DataResult.success(compoundTag2);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Tag> mergeToMap(Tag tag, Map<Tag, Tag> map) {
 | |
| 		if (!(tag instanceof CompoundTag) && !(tag instanceof EndTag)) {
 | |
| 			return DataResult.error(() -> "mergeToMap called with not a map: " + tag, tag);
 | |
| 		} else {
 | |
| 			CompoundTag compoundTag2 = tag instanceof CompoundTag compoundTag ? compoundTag.shallowCopy() : new CompoundTag();
 | |
| 			List<Tag> list = new ArrayList();
 | |
| 
 | |
| 			for (Entry<Tag, Tag> entry : map.entrySet()) {
 | |
| 				Tag tag2 = (Tag)entry.getKey();
 | |
| 				if (tag2 instanceof StringTag(String var10)) {
 | |
| 					compoundTag2.put(var10, (Tag)entry.getValue());
 | |
| 				} else {
 | |
| 					list.add(tag2);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return !list.isEmpty() ? DataResult.error(() -> "some keys are not strings: " + list, compoundTag2) : DataResult.success(compoundTag2);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Stream<Pair<Tag, Tag>>> getMapValues(Tag map) {
 | |
| 		return map instanceof CompoundTag compoundTag
 | |
| 			? DataResult.success(compoundTag.entrySet().stream().map(entry -> Pair.of(this.createString((String)entry.getKey()), (Tag)entry.getValue())))
 | |
| 			: DataResult.error(() -> "Not a map: " + map);
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Consumer<BiConsumer<Tag, Tag>>> getMapEntries(Tag map) {
 | |
| 		return map instanceof CompoundTag compoundTag ? DataResult.success(biConsumer -> {
 | |
| 			for (Entry<String, Tag> entry : compoundTag.entrySet()) {
 | |
| 				biConsumer.accept(this.createString((String)entry.getKey()), (Tag)entry.getValue());
 | |
| 			}
 | |
| 		}) : DataResult.error(() -> "Not a map: " + map);
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<MapLike<Tag>> getMap(Tag map) {
 | |
| 		return map instanceof CompoundTag compoundTag ? DataResult.success(new MapLike<Tag>() {
 | |
| 			@Nullable
 | |
| 			public Tag get(Tag tag) {
 | |
| 				if (tag instanceof StringTag(String var4)) {
 | |
| 					return compoundTag.get(var4);
 | |
| 				} else {
 | |
| 					throw new UnsupportedOperationException("Cannot get map entry with non-string key: " + tag);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			@Nullable
 | |
| 			public Tag get(String string) {
 | |
| 				return compoundTag.get(string);
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public Stream<Pair<Tag, Tag>> entries() {
 | |
| 				return compoundTag.entrySet().stream().map(entry -> Pair.of(NbtOps.this.createString((String)entry.getKey()), (Tag)entry.getValue()));
 | |
| 			}
 | |
| 
 | |
| 			public String toString() {
 | |
| 				return "MapLike[" + compoundTag + "]";
 | |
| 			}
 | |
| 		}) : DataResult.error(() -> "Not a map: " + map);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createMap(Stream<Pair<Tag, Tag>> data) {
 | |
| 		CompoundTag compoundTag = new CompoundTag();
 | |
| 		data.forEach(pair -> {
 | |
| 			Tag tag = (Tag)pair.getFirst();
 | |
| 			Tag tag2 = (Tag)pair.getSecond();
 | |
| 			if (tag instanceof StringTag(String string)) {
 | |
| 				compoundTag.put(string, tag2);
 | |
| 			} else {
 | |
| 				throw new UnsupportedOperationException("Cannot create map with non-string key: " + tag);
 | |
| 			}
 | |
| 		});
 | |
| 		return compoundTag;
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Stream<Tag>> getStream(Tag tag) {
 | |
| 		return tag instanceof CollectionTag collectionTag ? DataResult.success(collectionTag.stream()) : DataResult.error(() -> "Not a list");
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<Consumer<Consumer<Tag>>> getList(Tag tag) {
 | |
| 		return tag instanceof CollectionTag collectionTag ? DataResult.success(collectionTag::forEach) : DataResult.error(() -> "Not a list: " + tag);
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<ByteBuffer> getByteBuffer(Tag tag) {
 | |
| 		return tag instanceof ByteArrayTag byteArrayTag ? DataResult.success(ByteBuffer.wrap(byteArrayTag.getAsByteArray())) : DynamicOps.super.getByteBuffer(tag);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createByteList(ByteBuffer data) {
 | |
| 		ByteBuffer byteBuffer = data.duplicate().clear();
 | |
| 		byte[] bs = new byte[data.capacity()];
 | |
| 		byteBuffer.get(0, bs, 0, bs.length);
 | |
| 		return new ByteArrayTag(bs);
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<IntStream> getIntStream(Tag tag) {
 | |
| 		return tag instanceof IntArrayTag intArrayTag ? DataResult.success(Arrays.stream(intArrayTag.getAsIntArray())) : DynamicOps.super.getIntStream(tag);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createIntList(IntStream data) {
 | |
| 		return new IntArrayTag(data.toArray());
 | |
| 	}
 | |
| 
 | |
| 	public DataResult<LongStream> getLongStream(Tag tag) {
 | |
| 		return tag instanceof LongArrayTag longArrayTag ? DataResult.success(Arrays.stream(longArrayTag.getAsLongArray())) : DynamicOps.super.getLongStream(tag);
 | |
| 	}
 | |
| 
 | |
| 	public Tag createLongList(LongStream data) {
 | |
| 		return new LongArrayTag(data.toArray());
 | |
| 	}
 | |
| 
 | |
| 	public Tag createList(Stream<Tag> data) {
 | |
| 		return new ListTag((List<Tag>)data.collect(Util.toMutableList()));
 | |
| 	}
 | |
| 
 | |
| 	public Tag remove(Tag map, String removeKey) {
 | |
| 		if (map instanceof CompoundTag compoundTag) {
 | |
| 			CompoundTag compoundTag2 = compoundTag.shallowCopy();
 | |
| 			compoundTag2.remove(removeKey);
 | |
| 			return compoundTag2;
 | |
| 		} else {
 | |
| 			return map;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public String toString() {
 | |
| 		return "NBT";
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public RecordBuilder<Tag> mapBuilder() {
 | |
| 		return new NbtOps.NbtRecordBuilder();
 | |
| 	}
 | |
| 
 | |
| 	private static Optional<NbtOps.ListCollector> createCollector(Tag tag) {
 | |
| 		if (tag instanceof EndTag) {
 | |
| 			return Optional.of(new NbtOps.GenericListCollector());
 | |
| 		} else if (tag instanceof CollectionTag collectionTag) {
 | |
| 			if (collectionTag.isEmpty()) {
 | |
| 				return Optional.of(new NbtOps.GenericListCollector());
 | |
| 			} else {
 | |
| 				return switch (collectionTag) {
 | |
| 					case ListTag listTag -> Optional.of(new NbtOps.GenericListCollector(listTag));
 | |
| 					case ByteArrayTag byteArrayTag -> Optional.of(new NbtOps.ByteListCollector(byteArrayTag.getAsByteArray()));
 | |
| 					case IntArrayTag intArrayTag -> Optional.of(new NbtOps.IntListCollector(intArrayTag.getAsIntArray()));
 | |
| 					case LongArrayTag longArrayTag -> Optional.of(new NbtOps.LongListCollector(longArrayTag.getAsLongArray()));
 | |
| 					default -> throw new MatchException(null, null);
 | |
| 				};
 | |
| 			}
 | |
| 		} else {
 | |
| 			return Optional.empty();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	static class ByteListCollector implements NbtOps.ListCollector {
 | |
| 		private final ByteArrayList values = new ByteArrayList();
 | |
| 
 | |
| 		public ByteListCollector(byte[] values) {
 | |
| 			this.values.addElements(0, values);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public NbtOps.ListCollector accept(Tag tag) {
 | |
| 			if (tag instanceof ByteTag byteTag) {
 | |
| 				this.values.add(byteTag.byteValue());
 | |
| 				return this;
 | |
| 			} else {
 | |
| 				return new NbtOps.GenericListCollector(this.values).accept(tag);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public Tag result() {
 | |
| 			return new ByteArrayTag(this.values.toByteArray());
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	static class GenericListCollector implements NbtOps.ListCollector {
 | |
| 		private final ListTag result = new ListTag();
 | |
| 
 | |
| 		GenericListCollector() {
 | |
| 		}
 | |
| 
 | |
| 		GenericListCollector(ListTag list) {
 | |
| 			this.result.addAll(list);
 | |
| 		}
 | |
| 
 | |
| 		public GenericListCollector(IntArrayList list) {
 | |
| 			list.forEach(i -> this.result.add(IntTag.valueOf(i)));
 | |
| 		}
 | |
| 
 | |
| 		public GenericListCollector(ByteArrayList list) {
 | |
| 			list.forEach(b -> this.result.add(ByteTag.valueOf(b)));
 | |
| 		}
 | |
| 
 | |
| 		public GenericListCollector(LongArrayList list) {
 | |
| 			list.forEach(l -> this.result.add(LongTag.valueOf(l)));
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public NbtOps.ListCollector accept(Tag tag) {
 | |
| 			this.result.add(tag);
 | |
| 			return this;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public Tag result() {
 | |
| 			return this.result;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	static class IntListCollector implements NbtOps.ListCollector {
 | |
| 		private final IntArrayList values = new IntArrayList();
 | |
| 
 | |
| 		public IntListCollector(int[] values) {
 | |
| 			this.values.addElements(0, values);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public NbtOps.ListCollector accept(Tag tag) {
 | |
| 			if (tag instanceof IntTag intTag) {
 | |
| 				this.values.add(intTag.intValue());
 | |
| 				return this;
 | |
| 			} else {
 | |
| 				return new NbtOps.GenericListCollector(this.values).accept(tag);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public Tag result() {
 | |
| 			return new IntArrayTag(this.values.toIntArray());
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	interface ListCollector {
 | |
| 		NbtOps.ListCollector accept(Tag tag);
 | |
| 
 | |
| 		default NbtOps.ListCollector acceptAll(Iterable<Tag> tags) {
 | |
| 			NbtOps.ListCollector listCollector = this;
 | |
| 
 | |
| 			for (Tag tag : tags) {
 | |
| 				listCollector = listCollector.accept(tag);
 | |
| 			}
 | |
| 
 | |
| 			return listCollector;
 | |
| 		}
 | |
| 
 | |
| 		default NbtOps.ListCollector acceptAll(Stream<Tag> tags) {
 | |
| 			return this.acceptAll(tags::iterator);
 | |
| 		}
 | |
| 
 | |
| 		Tag result();
 | |
| 	}
 | |
| 
 | |
| 	static class LongListCollector implements NbtOps.ListCollector {
 | |
| 		private final LongArrayList values = new LongArrayList();
 | |
| 
 | |
| 		public LongListCollector(long[] values) {
 | |
| 			this.values.addElements(0, values);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public NbtOps.ListCollector accept(Tag tag) {
 | |
| 			if (tag instanceof LongTag longTag) {
 | |
| 				this.values.add(longTag.longValue());
 | |
| 				return this;
 | |
| 			} else {
 | |
| 				return new NbtOps.GenericListCollector(this.values).accept(tag);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public Tag result() {
 | |
| 			return new LongArrayTag(this.values.toLongArray());
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	class NbtRecordBuilder extends AbstractStringBuilder<Tag, CompoundTag> {
 | |
| 		protected NbtRecordBuilder() {
 | |
| 			super(NbtOps.this);
 | |
| 		}
 | |
| 
 | |
| 		protected CompoundTag initBuilder() {
 | |
| 			return new CompoundTag();
 | |
| 		}
 | |
| 
 | |
| 		protected CompoundTag append(String key, Tag value, CompoundTag tag) {
 | |
| 			tag.put(key, value);
 | |
| 			return tag;
 | |
| 		}
 | |
| 
 | |
| 		protected DataResult<Tag> build(CompoundTag compoundTag, Tag tag) {
 | |
| 			if (tag == null || tag == EndTag.INSTANCE) {
 | |
| 				return DataResult.success(compoundTag);
 | |
| 			} else if (!(tag instanceof CompoundTag compoundTag2)) {
 | |
| 				return DataResult.error(() -> "mergeToMap called with not a map: " + tag, tag);
 | |
| 			} else {
 | |
| 				CompoundTag compoundTag3 = compoundTag2.shallowCopy();
 | |
| 
 | |
| 				for (Entry<String, Tag> entry : compoundTag.entrySet()) {
 | |
| 					compoundTag3.put((String)entry.getKey(), (Tag)entry.getValue());
 | |
| 				}
 | |
| 
 | |
| 				return DataResult.success(compoundTag3);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |