package org.bukkit.craftbukkit.persistence; import com.google.common.base.Preconditions; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.util.CraftNBTTagConfigSerializer; import org.bukkit.persistence.PersistentDataAdapterContext; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; public class CraftPersistentDataContainer implements PersistentDataContainer { private final Map customDataTags = new HashMap<>(); private final CraftPersistentDataTypeRegistry registry; private final CraftPersistentDataAdapterContext adapterContext; public CraftPersistentDataContainer(Map customTags, CraftPersistentDataTypeRegistry registry) { this(registry); this.customDataTags.putAll(customTags); } public CraftPersistentDataContainer(CraftPersistentDataTypeRegistry registry) { this.registry = registry; this.adapterContext = new CraftPersistentDataAdapterContext(this.registry); } @Override public void set(NamespacedKey key, PersistentDataType type, Z value) { Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null"); Preconditions.checkArgument(type != null, "The provided type cannot be null"); Preconditions.checkArgument(value != null, "The provided value cannot be null"); this.customDataTags.put(key.toString(), registry.wrap(type.getPrimitiveType(), type.toPrimitive(value, adapterContext))); } @Override public boolean has(NamespacedKey key, PersistentDataType type) { Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null"); Preconditions.checkArgument(type != null, "The provided type cannot be null"); NBTBase value = this.customDataTags.get(key.toString()); if (value == null) { return false; } return registry.isInstanceOf(type.getPrimitiveType(), value); } @Override public boolean has(NamespacedKey key) { return this.customDataTags.get(key.toString()) != null; } @Override public Z get(NamespacedKey key, PersistentDataType type) { Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null"); Preconditions.checkArgument(type != null, "The provided type cannot be null"); NBTBase value = this.customDataTags.get(key.toString()); if (value == null) { return null; } return type.fromPrimitive(registry.extract(type.getPrimitiveType(), value), adapterContext); } @Override public Z getOrDefault(NamespacedKey key, PersistentDataType type, Z defaultValue) { Z z = get(key, type); return z != null ? z : defaultValue; } @Override public Set getKeys() { Set keys = new HashSet<>(); this.customDataTags.keySet().forEach(key -> { String[] keyData = key.split(":", 2); if (keyData.length == 2) { keys.add(new NamespacedKey(keyData[0], keyData[1])); } }); return keys; } @Override public void remove(NamespacedKey key) { Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null"); this.customDataTags.remove(key.toString()); } @Override public boolean isEmpty() { return this.customDataTags.isEmpty(); } @Override public void copyTo(PersistentDataContainer other, boolean replace) { Preconditions.checkArgument(other != null, "The target container cannot be null"); CraftPersistentDataContainer target = (CraftPersistentDataContainer) other; if (replace) { target.customDataTags.putAll(customDataTags); } else { customDataTags.forEach(target.customDataTags::putIfAbsent); } } @Override public PersistentDataAdapterContext getAdapterContext() { return this.adapterContext; } @Override public boolean equals(Object obj) { if (!(obj instanceof CraftPersistentDataContainer)) { return false; } Map myRawMap = getRaw(); Map theirRawMap = ((CraftPersistentDataContainer) obj).getRaw(); return Objects.equals(myRawMap, theirRawMap); } public NBTTagCompound toTagCompound() { NBTTagCompound tag = new NBTTagCompound(); for (Entry entry : this.customDataTags.entrySet()) { tag.put(entry.getKey(), entry.getValue()); } return tag; } public void put(String key, NBTBase base) { this.customDataTags.put(key, base); } public void putAll(Map map) { this.customDataTags.putAll(map); } public void putAll(NBTTagCompound compound) { for (String key : compound.getAllKeys()) { this.customDataTags.put(key, compound.get(key)); } } public Map getRaw() { return this.customDataTags; } public CraftPersistentDataTypeRegistry getDataTagTypeRegistry() { return registry; } @Override public int hashCode() { int hashCode = 3; hashCode += this.customDataTags.hashCode(); // We will simply add the maps hashcode return hashCode; } public String serialize() { return CraftNBTTagConfigSerializer.serialize(toTagCompound()); } }