diff --git a/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java b/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java index 036256cf..0d30fab0 100644 --- a/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java +++ b/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java @@ -28,7 +28,7 @@ import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RunnableVal4; import com.boydti.fawe.object.changeset.AnvilHistory; -import com.boydti.fawe.object.clipboard.ClipboardRemapper; +import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; import com.boydti.fawe.object.mask.FaweBlockMatcher; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.SetQueue; diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/filters/RemapFilter.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/filters/RemapFilter.java index d742633e..0739edf1 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/filters/RemapFilter.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/filters/RemapFilter.java @@ -5,7 +5,7 @@ import com.boydti.fawe.jnbt.anvil.MCAChunk; import com.boydti.fawe.jnbt.anvil.MCAFile; import com.boydti.fawe.jnbt.anvil.MCAFilterCounter; import com.boydti.fawe.jnbt.anvil.MutableMCABackedBaseBlock; -import com.boydti.fawe.object.clipboard.ClipboardRemapper; +import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; import com.boydti.fawe.object.collection.BlockVectorSet; import com.boydti.fawe.object.number.MutableLong; import com.boydti.fawe.util.ReflectionUtils; @@ -84,9 +84,10 @@ public class RemapFilter extends MCAFilterCounter { case PC: { int newLight = 0; switch (id) { - case 90: + case 90: { pLocs.add(x, y, z); - if (pLocs.contains(x, y - 1, z) || pLocs.contains(x - 1, y, z) || pLocs.contains(x, y, z - 1)) break; + if (pLocs.contains(x, y - 1, z) || pLocs.contains(x - 1, y, z) || pLocs.contains(x, y, z - 1)) + break; Map tag = new HashMap<>(); tag.put("Span", new ByteTag((byte) 1)); tag.put("TpX", new IntTag(x)); @@ -98,8 +99,10 @@ public class RemapFilter extends MCAFilterCounter { tag.put("Za", new ByteTag((byte) ((data == 2) ? 1 : 0))); portals.add(new CompoundTag(tag)); break; + } case 29: - case 33: + case 33: { + int data = block.getData(); Map map = new HashMap<>(); map.put("Progress", 1f); map.put("State", (byte) 2); @@ -114,6 +117,7 @@ public class RemapFilter extends MCAFilterCounter { map.put("z", z); block.setNbtData(FaweCache.asTag(map)); break; + } case 44: case 182: case 158: diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/ItemWikiScraper.java b/core/src/main/java/com/boydti/fawe/object/clipboard/ItemWikiScraper.java deleted file mode 100644 index 254278e2..00000000 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/ItemWikiScraper.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.boydti.fawe.object.clipboard; - - -import com.boydti.fawe.util.MainUtil; -import com.google.common.io.Resources; -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.HashMap; -import java.util.Map; - -public class ItemWikiScraper { - private static String PE = "https://minecraft.gamepedia.com/index.php?title=Bedrock_Edition_data_values&action=edit§ion=1"; - private static String PC = "https://minecraft.gamepedia.com/index.php?title=Java_Edition_data_values/Item_IDs&action=edit"; - - private Map> cache = new HashMap<>(); - - public Map expand(Map map) { - HashMap newMap = new HashMap<>(map); - for (Map.Entry entry : map.entrySet()) { - newMap.put(entry.getKey().replace("_", ""), entry.getValue()); - } - return newMap; - } - - public synchronized Map scapeOrCache(ClipboardRemapper.RemapPlatform platform) throws IOException { - Map map; - try { - Map cached = cache.get(platform); - if (cached != null) return cached; - - File file = new File("lib" + File.separator + "item-mappings-" + platform.name().toLowerCase() + ".json"); - Gson gson = new Gson(); - if (file.exists()) { - try { - String str = Resources.toString(file.toURL(), Charset.defaultCharset()); - return gson.fromJson(str, new TypeToken>() { - }.getType()); - } catch (Throwable ignore) { - ignore.printStackTrace(); - } - } - map = scrape(platform); - java.io.File parent = file.getParentFile(); - parent.mkdirs(); - file.createNewFile(); - Files.write(file.toPath(), gson.toJson(map).getBytes(), StandardOpenOption.CREATE); - } catch (IOException e) { - map = new HashMap<>(); - } - cache.put(platform, map); - return map; - } - - private Map scrape(ClipboardRemapper.RemapPlatform platform) throws IOException { - String url = (platform == ClipboardRemapper.RemapPlatform.PC) ? PC : PE; - String text = MainUtil.getText(url); - - String header = platform == ClipboardRemapper.RemapPlatform.PE ? "=== Item IDs ===" : "{{"; - String footer = "{{-}}"; - String prefix = "{{id table|"; - - HashMap map = new HashMap<>(); - - int headerIndex = text.indexOf(header); - if (headerIndex == -1) return map; - int endIndex = text.indexOf(footer, headerIndex); - String part = text.substring(headerIndex, endIndex == -1 ? text.length() : endIndex); - - int id = 255; - for (String line : part.split("\n")) { - String lower = line.toLowerCase(); - if (lower.startsWith(prefix)) { - line = line.substring(prefix.length(), line.indexOf("}}")); - String[] split = line.split("\\|"); - String nameId = null; - for (String entry : split) { - String[] pair = entry.split("="); - switch (pair[0].toLowerCase()) { - case "dv": - id = Integer.parseInt(pair[1]); - break; - case "nameid": - nameId = pair[1]; - break; - } - } - if (nameId == null) nameId = split[0].toLowerCase().replace(' ', '_'); - map.put(nameId, id); - } - id++; - } - return map; - } -} diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/ClipboardRemapper.java b/core/src/main/java/com/boydti/fawe/object/clipboard/remap/ClipboardRemapper.java similarity index 96% rename from core/src/main/java/com/boydti/fawe/object/clipboard/ClipboardRemapper.java rename to core/src/main/java/com/boydti/fawe/object/clipboard/remap/ClipboardRemapper.java index dba7a3dd..76199373 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/ClipboardRemapper.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/remap/ClipboardRemapper.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.object.clipboard; +package com.boydti.fawe.object.clipboard.remap; import com.boydti.fawe.FaweCache; import com.google.common.io.Resources; @@ -40,12 +40,12 @@ public class ClipboardRemapper { this.from = null; } - private ItemWikiScraper scraper; + private WikiScraper scraper; - private synchronized ItemWikiScraper loadItemMapping() throws IOException { - ItemWikiScraper tmp = scraper; + public synchronized WikiScraper loadItemMapping() throws IOException { + WikiScraper tmp = scraper; if (tmp == null) { - scraper = tmp = new ItemWikiScraper(); + scraper = tmp = new WikiScraper(); } return tmp; } @@ -60,9 +60,9 @@ public class ClipboardRemapper { } else { try { name = name.replace("minecraft:", ""); - ItemWikiScraper scraper = loadItemMapping(); - Map mapFrom = scraper.scapeOrCache(from); - Map mapTo = scraper.scapeOrCache(from.opposite()); + WikiScraper scraper = loadItemMapping(); + Map mapFrom = scraper.scapeOrCache(WikiScraper.Wiki.valueOf("ITEM_MAPPINGS_" + from.name())); + Map mapTo = scraper.scapeOrCache(WikiScraper.Wiki.valueOf("ITEM_MAPPINGS_" + from.opposite().name())); scraper.expand(mapTo); switch (name) { case "spruce_boat": return new BaseItem(333, (short) 1); @@ -100,7 +100,19 @@ public class ClipboardRemapper { throw new UnsupportedOperationException("TODO"); } - public String remapEntityId(String id) { + public int remapEntityId(String id) { + try { + Map mappings = loadItemMapping().scapeOrCache(WikiScraper.Wiki.ENTITY_MAPPINGS); + id = id.replace("minecraft:", ""); + Integer legacyId = mappings.get(id); + if (legacyId != null) return legacyId; + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } + + public String remapBlockEntityId(String id) { if (from == null) return id; switch (from) { case PE: { diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/RemappedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/remap/RemappedClipboard.java similarity index 91% rename from core/src/main/java/com/boydti/fawe/object/clipboard/RemappedClipboard.java rename to core/src/main/java/com/boydti/fawe/object/clipboard/remap/RemappedClipboard.java index 04ec1a03..68d5113c 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/RemappedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/remap/RemappedClipboard.java @@ -1,6 +1,8 @@ -package com.boydti.fawe.object.clipboard; +package com.boydti.fawe.object.clipboard.remap; import com.boydti.fawe.jnbt.NBTStreamer; +import com.boydti.fawe.object.clipboard.AbstractDelegateFaweClipboard; +import com.boydti.fawe.object.clipboard.FaweClipboard; import com.sk89q.worldedit.blocks.BaseBlock; public class RemappedClipboard extends AbstractDelegateFaweClipboard { diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/remap/WikiScraper.java b/core/src/main/java/com/boydti/fawe/object/clipboard/remap/WikiScraper.java new file mode 100644 index 00000000..25cc2829 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/remap/WikiScraper.java @@ -0,0 +1,133 @@ +package com.boydti.fawe.object.clipboard.remap; + + +import com.boydti.fawe.util.MainUtil; +import com.google.common.io.Resources; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.HashMap; +import java.util.Map; + +public class WikiScraper { + public enum Wiki { + ITEM_MAPPINGS_PE("https://minecraft.gamepedia.com/index.php?title=Bedrock_Edition_data_values&action=edit§ion=1"), + ITEM_MAPPINGS_PC("https://minecraft.gamepedia.com/index.php?title=Java_Edition_data_values/Item_IDs&action=edit"), + ENTITY_MAPPINGS("https://minecraft.gamepedia.com/index.php?title=Bedrock_Edition_data_values&action=edit§ion=4"), + ; + public final String url; + Wiki(String url) {this.url = url;} + } + + private Map> cache = new HashMap<>(); + + public Map expand(Map map) { + HashMap newMap = new HashMap<>(map); + for (Map.Entry entry : map.entrySet()) { + newMap.put(entry.getKey().replace("_", ""), entry.getValue()); + } + return newMap; + } + + protected String getName() { + return "item-mappings"; + } + + public synchronized Map scapeOrCache(Wiki wiki) throws IOException { + Map map; + try { + Map cached = cache.get(wiki); + if (cached != null) return cached; + + File file = new File("lib" + File.separator + wiki.name().toLowerCase().replace('_', '-') + ".json"); + Gson gson = new Gson(); + if (file.exists()) { + try { + String str = Resources.toString(file.toURL(), Charset.defaultCharset()); + return gson.fromJson(str, new TypeToken>() { + }.getType()); + } catch (Throwable ignore) { + ignore.printStackTrace(); + } + } + map = scrape(wiki); + java.io.File parent = file.getParentFile(); + parent.mkdirs(); + file.createNewFile(); + Files.write(file.toPath(), gson.toJson(map).getBytes(), StandardOpenOption.CREATE); + } catch (IOException e) { + map = new HashMap<>(); + } + cache.put(wiki, map); + return map; + } + + protected Map scrape(Wiki wiki) throws IOException { + String url = wiki.url; + String text = MainUtil.getText(url); + HashMap map = new HashMap<>(); + + if (wiki == Wiki.ENTITY_MAPPINGS) { + String header = "{|"; + String footer = "|}"; + + + int headerIndex = text.indexOf(header); + if (headerIndex == -1) return map; + int endIndex = text.indexOf(footer, headerIndex); + String part = text.substring(headerIndex, endIndex == -1 ? text.length() : endIndex); + +// System.out.println(part); + + for (String line : part.split("\n")) { + if (line.startsWith("| {{")) { + String[] split = line.split("\\|\\|"); + if (split.length == 5) { + int id = Integer.parseInt(split[1].trim()); + String name = split[3].trim(); + map.put(name, id); + } + } + } + return map; + } else { + String header = wiki == Wiki.ITEM_MAPPINGS_PE ? "=== Item IDs ===" : "{{"; + String footer = "{{-}}"; + String prefix = "{{id table|"; + + int headerIndex = text.indexOf(header); + if (headerIndex == -1) return map; + int endIndex = text.indexOf(footer, headerIndex); + String part = text.substring(headerIndex, endIndex == -1 ? text.length() : endIndex); + + int id = 255; + for (String line : part.split("\n")) { + String lower = line.toLowerCase(); + if (lower.startsWith(prefix)) { + line = line.substring(prefix.length(), line.indexOf("}}")); + String[] split = line.split("\\|"); + String nameId = null; + for (String entry : split) { + String[] pair = entry.split("="); + switch (pair[0].toLowerCase()) { + case "dv": + id = Integer.parseInt(pair[1]); + break; + case "nameid": + nameId = pair[1]; + break; + } + } + if (nameId == null) nameId = split[0].toLowerCase().replace(' ', '_'); + map.put(nameId, id); + } + id++; + } + return map; + } + } +} diff --git a/core/src/main/java/com/sk89q/jnbt/ListTag.java b/core/src/main/java/com/sk89q/jnbt/ListTag.java index 6e516cce..7d81afe9 100644 --- a/core/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/core/src/main/java/com/sk89q/jnbt/ListTag.java @@ -11,10 +11,10 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * The {@code TAG_List} tag. */ -public final class ListTag extends Tag { +public final class ListTag extends Tag { - private final Class type; - private final List value; + private final Class type; + private final List value; /** * Creates the tag with an empty name. @@ -22,11 +22,11 @@ public final class ListTag extends Tag { * @param type the type of tag * @param value the value of the tag */ - public ListTag(Class type, List value) { + public ListTag(Class type, List value) { super(); checkNotNull(value); this.type = type; - this.value = Collections.unmodifiableList(value); + this.value = value; } @Override @@ -43,12 +43,12 @@ public final class ListTag extends Tag { * * @return The type of item in this list. */ - public Class getType() { + public Class getType() { return type; } @Override - public List getValue() { + public List getValue() { return value; } diff --git a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 9fb8bef7..3f4ce47d 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -23,7 +23,7 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Settings; -import com.boydti.fawe.object.clipboard.ClipboardRemapper; +import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.boydti.fawe.object.schematic.StructureFormat; import com.boydti.fawe.util.MainUtil; diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/NBTConverter.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/NBTConverter.java index 1eaf0af0..36ffc3ea 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/NBTConverter.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/NBTConverter.java @@ -128,7 +128,7 @@ public final class NBTConverter { private static cn.nukkit.nbt.tag.ListTag toNative(ListTag tag) { cn.nukkit.nbt.tag.ListTag list = new cn.nukkit.nbt.tag.ListTag(); - for (Tag child : tag.getValue()) { + for (Tag child : (List) tag.getValue()) { if (child instanceof EndTag) { continue; } diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConvertCommands.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConvertCommands.java index f132e3c3..510e2117 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConvertCommands.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConvertCommands.java @@ -9,7 +9,7 @@ import com.boydti.fawe.jnbt.anvil.filters.DelegateMCAFilter; import com.boydti.fawe.jnbt.anvil.filters.RemapFilter; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.object.clipboard.ClipboardRemapper; +import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; import com.boydti.fawe.object.number.MutableLong; import com.boydti.fawe.util.SetQueue; import com.sk89q.minecraft.util.commands.Command; diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConverterFrame.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConverterFrame.java index 53acb081..f0bf2e7e 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConverterFrame.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/ConverterFrame.java @@ -11,8 +11,7 @@ import com.boydti.fawe.installer.MinimizeButton; import com.boydti.fawe.installer.MovablePanel; import com.boydti.fawe.installer.TextAreaOutputStream; import com.boydti.fawe.installer.URLButton; -import com.boydti.fawe.object.clipboard.ClipboardRemapper; -import com.boydti.fawe.object.clipboard.ItemWikiScraper; +import com.boydti.fawe.object.clipboard.remap.WikiScraper; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.wrappers.FakePlayer; import java.awt.BorderLayout; @@ -359,7 +358,7 @@ public class ConverterFrame extends JFrame { if (dependenciesLoaded.get()) return; try { ExecutorService pool = Executors.newCachedThreadPool(); - ItemWikiScraper scraper = new ItemWikiScraper(); + WikiScraper scraper = new WikiScraper(); File lib = new File("lib"); File leveldb = new File(lib, "leveldb_v1.jar"); @@ -376,7 +375,7 @@ public class ConverterFrame extends JFrame { pool.submit((Runnable) () -> { try { - scraper.scapeOrCache(ClipboardRemapper.RemapPlatform.PE); + scraper.scapeOrCache(WikiScraper.Wiki.ITEM_MAPPINGS_PE); } catch (IOException e) { e.printStackTrace(); } @@ -384,7 +383,15 @@ public class ConverterFrame extends JFrame { pool.submit((Runnable) () -> { try { - scraper.scapeOrCache(ClipboardRemapper.RemapPlatform.PC); + scraper.scapeOrCache(WikiScraper.Wiki.ITEM_MAPPINGS_PC); + } catch (IOException e) { + e.printStackTrace(); + } + }); + + pool.submit((Runnable) () -> { + try { + scraper.scapeOrCache(WikiScraper.Wiki.ENTITY_MAPPINGS); } catch (IOException e) { e.printStackTrace(); } diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/MCAFile2LevelDB.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/MCAFile2LevelDB.java index 3356d8fe..360374fe 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/MCAFile2LevelDB.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/MCAFile2LevelDB.java @@ -9,7 +9,7 @@ import com.boydti.fawe.jnbt.anvil.MCAQueue; import com.boydti.fawe.jnbt.anvil.filters.DelegateMCAFilter; import com.boydti.fawe.jnbt.anvil.filters.RemapFilter; import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.object.clipboard.ClipboardRemapper; +import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; import com.boydti.fawe.object.io.LittleEndianOutputStream; import com.boydti.fawe.object.number.MutableLong; import com.boydti.fawe.util.MainUtil; @@ -432,7 +432,7 @@ public class MCAFile2LevelDB extends MapConverter { List tiles = new ArrayList<>(); for (Map.Entry entry : chunk.getTiles().entrySet()) { CompoundTag tag = entry.getValue(); - if (transform(chunk, tag) && time != 0l) { + if (transform(chunk, tag, false) && time != 0l) { // Needs tick if (tickList == null) tickList = new ArrayList<>(); @@ -464,7 +464,7 @@ public class MCAFile2LevelDB extends MapConverter { if (!chunk.entities.isEmpty()) { List entities = new ArrayList<>(); for (CompoundTag tag : chunk.getEntities()) { - transform(chunk, tag); + transform(chunk, tag, true); entities.add(tag); } update(getKey(chunk, Tag.Entity, dim), write(entities)); @@ -590,13 +590,14 @@ public class MCAFile2LevelDB extends MapConverter { Map map = ReflectionUtils.getMap(item.getValue()); map.put("id", new ShortTag((short) remapped.getType())); map.put("Damage", new ShortTag((short) remapped.getData())); + if (!map.containsKey("Count")) map.put("Count", new ByteTag((byte) 0)); CompoundTag tag = (CompoundTag) item.getValue().get("tag"); if (tag != null) { Map tagMap = ReflectionUtils.getMap(tag.getValue()); - List enchants = (List) tag.getList("ench"); + ListTag enchants = (ListTag) tagMap.get("ench"); if (enchants != null) { - for (CompoundTag ench : enchants) { + for (CompoundTag ench : enchants.getValue()) { Map value = ReflectionUtils.getMap(ench.getValue()); String id = ench.getString("id"); String lvl = ench.getString("lvl"); @@ -612,19 +613,48 @@ public class MCAFile2LevelDB extends MapConverter { return item; } - private boolean transform(MCAChunk chunk, CompoundTag tag) { + private boolean transform(MCAChunk chunk, CompoundTag tag, boolean entity) { try { String id = tag.getString("id"); if (id != null) { Map map = ReflectionUtils.getMap(tag.getValue()); - id = remapper.remapEntityId(id); - map.put("id", new StringTag(id)); - if (map.containsKey("Pos")) { - map.put("id", new IntTag(11)); + if (entity) { + int legacyId = remapper.remapEntityId(id); + if (legacyId != -1) map.put("id", new IntTag(legacyId)); + } else { + id = remapper.remapBlockEntityId(id); + map.put("id", new StringTag(id)); + } + { // Hand items + com.sk89q.jnbt.ListTag items = (ListTag) map.remove("HandItems"); + if (items != null) { + CompoundTag hand = transformItem((CompoundTag) items.getValue().get(0)); + CompoundTag offHand = transformItem((CompoundTag) items.getValue().get(1)); + map.put("Mainhand", hand); + map.put("Offhand", offHand); + } + } + { // Convert armor + com.sk89q.jnbt.ListTag items = (ListTag) map.remove("ArmorItems"); + if (items != null) { + ((List) items.getValue()).forEach(this::transformItem); + Collections.reverse(items.getValue()); + map.put("Armor", items); + } } { // Convert items com.sk89q.jnbt.ListTag items = tag.getListTag("Items"); - ((List) (List) items.getValue()).forEach(this::transformItem); + if (items != null) { + ((List) items.getValue()).forEach(this::transformItem); + } + } + { // Convert color + for (String key : new String[] {"color", "Color"}) { + com.sk89q.jnbt.Tag value = map.get(key); + if (value instanceof IntTag) { + map.put(key, new ByteTag((byte) (int) ((IntTag) value).getValue())); + } + } } { // Convert item String item = tag.getString("Item");