CraftBukkit/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
2019-03-17 11:48:53 +11:00

268 lines
9.6 KiB
Java

package org.bukkit.craftbukkit.util;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.server.AdvancementDataWorld;
import net.minecraft.server.Block;
import net.minecraft.server.ChatDeserializer;
import net.minecraft.server.IBlockData;
import net.minecraft.server.IRegistry;
import net.minecraft.server.Item;
import net.minecraft.server.MinecraftKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.MojangsonParser;
import net.minecraft.server.NBTTagCompound;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.UnsafeValues;
import org.bukkit.advancement.Advancement;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.MaterialData;
import org.bukkit.plugin.InvalidPluginException;
import org.bukkit.plugin.PluginDescriptionFile;
@SuppressWarnings("deprecation")
public final class CraftMagicNumbers implements UnsafeValues {
public static final UnsafeValues INSTANCE = new CraftMagicNumbers();
private CraftMagicNumbers() {}
public static IBlockData getBlock(MaterialData material) {
return getBlock(material.getItemType(), material.getData());
}
public static IBlockData getBlock(Material material, byte data) {
return CraftLegacy.fromLegacyData(CraftLegacy.toLegacy(material), getBlock(material), data);
}
public static MaterialData getMaterial(IBlockData data) {
return CraftLegacy.toLegacy(getMaterial(data.getBlock())).getNewData(toLegacyData(data));
}
public static Item getItem(Material material, short data) {
if (material.isLegacy()) {
return CraftLegacy.fromLegacyData(CraftLegacy.toLegacy(material), getItem(material), data);
}
return getItem(material);
}
public static MaterialData getMaterialData(Item item) {
return CraftLegacy.toLegacyData(getMaterial(item));
}
// ========================================================================
private static final Map<Block, Material> BLOCK_MATERIAL = new HashMap<>();
private static final Map<Item, Material> ITEM_MATERIAL = new HashMap<>();
private static final Map<Material, Item> MATERIAL_ITEM = new HashMap<>();
private static final Map<Material, Block> MATERIAL_BLOCK = new HashMap<>();
static {
for (Block block : (Iterable<Block>) IRegistry.BLOCK) { // Eclipse fail
BLOCK_MATERIAL.put(block, Material.getMaterial(IRegistry.BLOCK.getKey(block).getKey().toUpperCase(Locale.ROOT)));
}
for (Item item : (Iterable<Item>) IRegistry.ITEM) { // Eclipse fail
ITEM_MATERIAL.put(item, Material.getMaterial(IRegistry.ITEM.getKey(item).getKey().toUpperCase(Locale.ROOT)));
}
for (Material material : Material.values()) {
MinecraftKey key = key(material);
// TODO: only register if block/item?
MATERIAL_ITEM.put(material, IRegistry.ITEM.get(key));
MATERIAL_BLOCK.put(material, IRegistry.BLOCK.get(key));
}
}
public static Material getMaterial(Block block) {
return BLOCK_MATERIAL.get(block);
}
public static Material getMaterial(Item item) {
return ITEM_MATERIAL.getOrDefault(item, Material.AIR);
}
public static Item getItem(Material material) {
return MATERIAL_ITEM.get(material);
}
public static Block getBlock(Material material) {
return MATERIAL_BLOCK.get(material);
}
public static MinecraftKey key(Material mat) {
if (mat.isLegacy()) {
mat = CraftLegacy.fromLegacy(mat);
}
return CraftNamespacedKey.toMinecraft(mat.getKey());
}
// ========================================================================
public static byte toLegacyData(IBlockData data) {
return CraftLegacy.toLegacyData(data);
}
@Override
public Material toLegacy(Material material) {
return CraftLegacy.toLegacy(material);
}
@Override
public Material fromLegacy(Material material) {
return CraftLegacy.fromLegacy(material);
}
@Override
public Material fromLegacy(MaterialData material) {
return CraftLegacy.fromLegacy(material);
}
@Override
public Material fromLegacy(MaterialData material, boolean itemPriority) {
return CraftLegacy.fromLegacy(material, itemPriority);
}
@Override
public BlockData fromLegacy(Material material, byte data) {
return CraftBlockData.fromData(getBlock(material, data));
}
/**
* This string should be changed if the NMS mappings do.
*
* It has no meaning and should only be used as an equality check. Plugins
* which are sensitive to the NMS mappings may read it and refuse to load if
* it cannot be found or is different to the expected value.
*
* Remember: NMS is not supported API and may break at any time for any
* reason irrespective of this. There is often supported API to do the same
* thing as many common NMS usages. If not, you are encouraged to open a
* feature and/or pull request for consideration, or use a well abstracted
* third-party API such as ProtocolLib.
*
* @return string
*/
public String getMappingsVersion() {
return "7dd4b3ec31629620c41553e5c142e454";
}
@Override
public int getDataVersion() {
return 1631;
}
@Override
public ItemStack modifyItemStack(ItemStack stack, String arguments) {
net.minecraft.server.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
try {
nmsStack.setTag((NBTTagCompound) MojangsonParser.parse(arguments));
} catch (CommandSyntaxException ex) {
Logger.getLogger(CraftMagicNumbers.class.getName()).log(Level.SEVERE, null, ex);
}
stack.setItemMeta(CraftItemStack.getItemMeta(nmsStack));
return stack;
}
@Override
public Advancement loadAdvancement(NamespacedKey key, String advancement) {
if (Bukkit.getAdvancement(key) != null) {
throw new IllegalArgumentException("Advancement " + key + " already exists.");
}
net.minecraft.server.Advancement.SerializedAdvancement nms = (net.minecraft.server.Advancement.SerializedAdvancement) ChatDeserializer.a(AdvancementDataWorld.DESERIALIZER, advancement, net.minecraft.server.Advancement.SerializedAdvancement.class);
if (nms != null) {
AdvancementDataWorld.REGISTRY.a(Maps.newHashMap(Collections.singletonMap(CraftNamespacedKey.toMinecraft(key), nms)));
Advancement bukkit = Bukkit.getAdvancement(key);
if (bukkit != null) {
File file = new File(MinecraftServer.getServer().bukkitDataPackFolder, "data" + File.separator + key.getNamespace() + File.separator + "advancements" + File.separator + key.getKey() + ".json");
file.getParentFile().mkdirs();
try {
Files.write(advancement, file, Charsets.UTF_8);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Error saving advancement " + key, ex);
}
MinecraftServer.getServer().getPlayerList().reload();
return bukkit;
}
}
return null;
}
@Override
public boolean removeAdvancement(NamespacedKey key) {
File file = new File(MinecraftServer.getServer().bukkitDataPackFolder, "data" + File.separator + key.getNamespace() + File.separator + "advancements" + File.separator + key.getKey() + ".json");
return file.delete();
}
@Override
public void checkSupported(PluginDescriptionFile pdf) throws InvalidPluginException {
if (pdf.getAPIVersion() != null) {
if (!pdf.getAPIVersion().equals("1.13")) {
throw new InvalidPluginException("Unsupported API version " + pdf.getAPIVersion());
}
}
}
public static boolean isLegacy(PluginDescriptionFile pdf) {
return pdf.getAPIVersion() == null;
}
@Override
public byte[] processClass(PluginDescriptionFile pdf, String path, byte[] clazz) {
try {
clazz = Commodore.convert(clazz, !isLegacy(pdf));
} catch (Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, "Fatal error trying to convert " + pdf.getFullName() + ":" + path, ex);
}
return clazz;
}
/**
* This helper class represents the different NBT Tags.
* <p>
* These should match NBTBase#getTypeId
*/
public static class NBT {
public static final int TAG_END = 0;
public static final int TAG_BYTE = 1;
public static final int TAG_SHORT = 2;
public static final int TAG_INT = 3;
public static final int TAG_LONG = 4;
public static final int TAG_FLOAT = 5;
public static final int TAG_DOUBLE = 6;
public static final int TAG_BYTE_ARRAY = 7;
public static final int TAG_STRING = 8;
public static final int TAG_LIST = 9;
public static final int TAG_COMPOUND = 10;
public static final int TAG_INT_ARRAY = 11;
public static final int TAG_ANY_NUMBER = 99;
}
}