Some conversion fixes

This commit is contained in:
Jesse Boyd 2017-10-06 16:51:04 +11:00
parent 4150413885
commit 201809aedd
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
13 changed files with 686 additions and 17814 deletions

17729
blocks.json

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,11 @@ import javafx.embed.swing.JFXPanel;
import javafx.stage.DirectoryChooser;
public abstract class BrowseButton extends InteractiveButton {
public BrowseButton() {
private final String id;
public BrowseButton(String id) {
super("Browse");
this.id = id;
}
public abstract void onSelect(File folder);
@ -32,7 +35,8 @@ public abstract class BrowseButton extends InteractiveButton {
File file = folderChooser.showDialog(null);
if (file != null && file.exists()) {
File parent = file.getParentFile();
Preferences.userRoot().node(Fawe.class.getName()).put("LAST_USED_FOLDER", file.getPath());
if (parent == null) parent = file;
Preferences.userRoot().node(Fawe.class.getName()).put("LAST_USED_FOLDER" + id, parent.getPath());
onSelect(file);
}
});

View File

@ -100,7 +100,7 @@ public class InstallerFrame extends JFrame {
text.setBackground(DARKER_GRAY);
text.setOpaque(true);
text.setBorder(new EmptyBorder(4, 4, 4, 4));
browse = new BrowseButton() {
browse = new BrowseButton("") {
@Override
public void onSelect(File folder) {
text.setText(folder.getPath());

View File

@ -6,6 +6,7 @@ import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.number.MutableLong;
import com.boydti.fawe.util.ArrayUtil;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
@ -530,7 +531,8 @@ public class MCAChunk extends FaweChunk<Void> {
streamer.readFully();
}
public void filterBlocks(MutableMCABackedBaseBlock mutableBlock, MCAFilter filter) {
public long filterBlocks(MutableMCABackedBaseBlock mutableBlock, MCAFilter filter) {
MutableLong result = new MutableLong();
mutableBlock.setChunk(this);
int bx = getX() << 4;
int bz = getZ() << 4;
@ -551,12 +553,13 @@ public class MCAChunk extends FaweChunk<Void> {
int xIndex = zIndex + x0;
mutableBlock.setX(x);
mutableBlock.setIndex(xIndex);
filter.applyBlock(x, y, z, mutableBlock, null);
filter.applyBlock(x, y, z, mutableBlock, result);
}
}
}
}
}
return result.get();
}
public int[] getHeightMapArray() {

View File

@ -187,7 +187,6 @@ public class MCAQueueMap implements IFaweQueueMap {
lastZ = Integer.MIN_VALUE;
lastFileX = Integer.MIN_VALUE;
lastFileZ = Integer.MIN_VALUE;
System.out.println("Files " + mcaFileMap);
if (!mcaFileMap.isEmpty()) {
Iterator<Map.Entry<Long, MCAFile>> iter = mcaFileMap.entrySet().iterator();
boolean result;

View File

@ -1,32 +1,231 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.FaweCache;
import com.google.common.io.Resources;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.intellectualcrafters.plot.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.boydti.fawe.FaweCache.getBlock;
public class ClipboardRemapper {
private final RemapPlatform from;
public enum RemapPlatform {
PE,
PC
;
public RemapPlatform opposite() {
return this == PE ? PC : PE;
}
}
public ClipboardRemapper() {
this.from = null;
}
public ClipboardRemapper(RemapPlatform fromPlatform, RemapPlatform toPlatform) {
if (fromPlatform == toPlatform) {
return;
private ItemWikiScraper scraper;
private synchronized ItemWikiScraper loadItemMapping() throws IOException {
ItemWikiScraper tmp = scraper;
if (tmp == null) {
scraper = tmp = new ItemWikiScraper();
}
return tmp;
}
public BaseBlock remapItem(String name, int damage) {
if (name.isEmpty()) return EditSession.nullBlock;
if (from == RemapPlatform.PC) {
BundledBlockData.BlockEntry state = BundledBlockData.getInstance().findById(name);
if (state != null) {
return remap(new BaseBlock(state.legacyId, damage));
} else {
try {
name = name.replace("minecraft:", "");
ItemWikiScraper scraper = loadItemMapping();
Map<String, Integer> mapFrom = scraper.scapeOrCache(from);
Map<String, Integer> mapTo = scraper.scapeOrCache(from.opposite());
scraper.expand(mapTo);
switch (name) {
case "spruce_boat": return new BaseBlock(333, 1);
case "birch_boat": return new BaseBlock(333, 2);
case "jungle_boat": return new BaseBlock(333, 3);
case "acacia_boat": return new BaseBlock(333, 4);
case "dark_oak_boat": return new BaseBlock(333, 5);
case "water_bucket": return new BaseBlock(325, 8);
case "lava_bucket": return new BaseBlock(325, 10);
case "milk_bucket": return new BaseBlock(325, 1);
case "tipped_arrow":
case "spectral_arrow":
name = "arrow"; // Unsupported
break;
case "totem_of_undying":
name = "totem";
break;
case "furnace_minecart":
name = "minecart"; // Unsupported
break;
}
Integer itemId = mapTo.get(name);
if (itemId == null) itemId = mapTo.get(name.replace("_", ""));
if (itemId == null) itemId = mapFrom.get(name);
if (itemId != null) return new BaseBlock(itemId, damage);
} catch (IOException ignore) {
ignore.printStackTrace();
}
}
}
return EditSession.nullBlock;
}
public Map.Entry<String, Integer> remapItem(int id, int data) {
throw new UnsupportedOperationException("TODO");
}
public String remapEntityId(String id) {
if (from == null) return id;
switch (from) {
case PE: {
switch (id) {
case "EnchantTable": return "minecraft:enchanting_table";
case "Music": return "minecraft:noteblock";
case "Chest": return "minecraft:trapped_chest";
case "ChalkboardBlock": return "minecraft:chalk_board_block";
case "FallingSand": return "minecraft:falling_block";
case "FireworksRocketEntity": return "minecraft:fireworks_rocket";
case "LavaSlime": return "minecraft:magma_cube";
case "MinecartChest": return "minecraft:chest_minecart";
case "MinecartCommandBlock": return "minecraft:commandblock_minecart";
case "MinecartFurnace": return "minecraft:furnace_minecart";
case "MinecartHopper": return "minecraft:hopper_minecart";
case "MinecartRideable": return "minecraft:minecart";
case "MinecartSpawner": return "minecraft:spawner_minecart";
case "MinecartTNT": return "minecraft:tnt_minecart";
case "MushroomCow": return "minecraft:mooshroom";
case "Ocelot": return "minecraft:ocelot";
case "PigZombie": return "minecraft:zombie_pigman";
case "PrimedTnt": return "minecraft:tnt";
case "SnowMan": return "minecraft:snowman";
case "ThrownEgg": return "minecraft:egg";
case "ThrownEnderpearl": return "minecraft:ender_pearl";
case "ThrownExpBottle": return "minecraft:xp_bottle";
case "ThrownPotion": return "minecraft:potion";
case "WitherBoss": return "minecraft:wither";
case "XPOrb": return "minecraft:xp_orb";
}
StringBuilder result = new StringBuilder("minecraft:");
for (int i = 0; i < result.length(); i++) {
char c = id.charAt(i);
if (Character.isUpperCase(c)) {
c = Character.toLowerCase(c);
if (i != 0) result.append('_');
}
result.append(c);
}
id = result.toString();
return id;
}
case PC: {
switch (id) {
case "minecraft:enchanting_table": return "EnchantTable";
case "minecraft:noteblock": return "Music";
case "minecraft:trapped_chest": return "Chest";
case "minecraft:chalk_board_block": return "ChalkboardBlock";
case "minecraft:falling_block": return "FallingSand";
case "minecraft:fireworks_rocket": return "FireworksRocketEntity";
case "minecraft:magma_cube": return "LavaSlime";
case "minecraft:chest_minecart": return "MinecartChest";
case "minecraft:commandblock_minecart": return "MinecartCommandBlock";
case "minecraft:furnace_minecart": return "MinecartFurnace";
case "minecraft:hopper_minecart": return "MinecartHopper";
case "minecraft:minecart": return "MinecartRideable";
case "minecraft:spawner_minecart": return "MinecartSpawner";
case "minecraft:tnt_minecart": return "MinecartTNT";
case "minecraft:mooshroom": return "MushroomCow";
case "minecraft:ocelot": return "Ocelot";
case "minecraft:zombie_pigman": return "PigZombie";
case "minecraft:tnt": return "PrimedTnt";
case "minecraft:snowman": return "SnowMan";
case "minecraft:egg": return "ThrownEgg";
case "minecraft:ender_pearl": return "ThrownEnderpearl";
case "minecraft:xp_bottle": return "ThrownExpBottle";
case "minecraft:potion": return "ThrownPotion";
case "minecraft:wither": return "WitherBoss";
case "minecraft:xp_orb": return "XPOrb";
}
id = id.replace("minecraft:", "");
StringBuilder result = new StringBuilder();
boolean toUpper = false;
for (int i = 0; i < id.length(); i++) {
char c = id.charAt(i);
if (i == 0) toUpper = true;
if (c == '_') {
toUpper = true;
} else {
result.append(toUpper ? Character.toUpperCase(c) : c);
toUpper = false;
}
}
id = result.toString();
return id;
}
}
return id;
}
private Map<String, List<Integer>> parse(File file) throws IOException {
JsonParser parser = new JsonParser();
JsonObject toParse = (JsonObject) parser.parse(Resources.toString(file.toURL(), Charset.defaultCharset()));
Map<String, List<Integer>> map = new HashMap<>();
outer:
for (Map.Entry<String, JsonElement> entry : toParse.entrySet()) {
String key = entry.getKey();
JsonObject value = entry.getValue().getAsJsonObject();
if (MathMan.isInteger(key)) {
int id = Integer.parseInt(key);
for (Map.Entry<String, JsonElement> dataEntry : value.entrySet()) {
String dataKey = dataEntry.getKey();
if (MathMan.isInteger(dataKey)) {
int data = Integer.parseInt(dataEntry.getKey());
int combined = (id << 4) + data;
String name = dataEntry.getValue().getAsJsonObject().get("intermediateID").getAsString();
map.putIfAbsent(name, new ArrayList<>());
map.get(name).add(combined);
}
}
} else {
String name = entry.getKey();
int id = value.get("id").getAsInt();
int data = value.get("data").getAsInt();
int combined = FaweCache.getCombined(id, data);
map.putIfAbsent(name, new ArrayList<>());
map.get(name).add(combined);
}
}
return map;
}
private HashMap<BaseBlock, BaseBlock> getPEtoPCMappings() {
HashMap<BaseBlock, BaseBlock> mapPEtoPC = new HashMap<>();
mapPEtoPC.put(new BaseBlock(281, -1), new BaseBlock(25, -1));
mapPEtoPC.put(new BaseBlock(95,-1), new BaseBlock(166,-1));
mapPEtoPC.put(new BaseBlock(125,-1), new BaseBlock(158,-1));
mapPEtoPC.put(new BaseBlock(126,-1), new BaseBlock(157,-1));
@ -34,9 +233,19 @@ public class ClipboardRemapper {
mapPEtoPC.put(new BaseBlock(158,-1), new BaseBlock(126,-1));
mapPEtoPC.put(new BaseBlock(188,-1), new BaseBlock(210,-1));
mapPEtoPC.put(new BaseBlock(189,-1), new BaseBlock(211,-1));
mapPEtoPC.put(new BaseBlock(155,4), new BaseBlock(155,10));
mapPEtoPC.put(new BaseBlock(155,3), new BaseBlock(155,6));
mapPEtoPC.put(new BaseBlock(198,-1), new BaseBlock(208,-1));
mapPEtoPC.put(new BaseBlock(207,-1), new BaseBlock(212,-1));
mapPEtoPC.put(new BaseBlock(208,-1), new BaseBlock(198,-1));
{ // beetroot
mapPEtoPC.put(new BaseBlock(244, 2), new BaseBlock(207, 1));
mapPEtoPC.put(new BaseBlock(244, 4), new BaseBlock(207, 2));
mapPEtoPC.put(new BaseBlock(244, 7), new BaseBlock(207, 3));
for (int data = 3; data < 16; data++) mapPEtoPC.putIfAbsent(new BaseBlock(244, data), new BaseBlock(207, data));
}
for (int data = 0; data < 16; data++) {
mapPEtoPC.put(new BaseBlock(218, data), new BaseBlock(219 + data, -1));
}
@ -67,16 +276,20 @@ public class ClipboardRemapper {
}
for (int id : new int[] {29, 33}) {
addBoth(getBlock(id, 3), getBlock(id, 4));
addBoth(getBlock(id, 10), getBlock(id, 11));
mapPEtoPC.put(new BaseBlock(id,3), new BaseBlock(id,2));
mapPEtoPC.put(new BaseBlock(id,2), new BaseBlock(id,3));
mapPEtoPC.put(new BaseBlock(id,5), new BaseBlock(id,4));
mapPEtoPC.put(new BaseBlock(id,13), new BaseBlock(id,12));
mapPEtoPC.put(new BaseBlock(id,4), new BaseBlock(id,5));
mapPEtoPC.put(new BaseBlock(id,12), new BaseBlock(id,13));
}
mapPEtoPC.put(new BaseBlock(250,-1), new BaseBlock(36,-1));
mapPEtoPC.put(new BaseBlock(236,-1), new BaseBlock(251,-1));
mapPEtoPC.put(new BaseBlock(237,-1), new BaseBlock(252,-1));
mapPEtoPC.put(new BaseBlock(240,-1), new BaseBlock(199,-1));
mapPEtoPC.put(new BaseBlock(241,-1), new BaseBlock(95,-1));
mapPEtoPC.put(new BaseBlock(243,0), new BaseBlock(3, 2));
mapPEtoPC.put(new BaseBlock(244,-1), new BaseBlock(207,-1));
mapPEtoPC.put(new BaseBlock(251,-1), new BaseBlock(218,-1));
@ -98,14 +311,18 @@ public class ClipboardRemapper {
mapPEtoPC.put(new BaseBlock(85,3), new BaseBlock(190,-1));
mapPEtoPC.put(new BaseBlock(85,4), new BaseBlock(192,-1));
mapPEtoPC.put(new BaseBlock(85, 5), new BaseBlock(191,-1));
mapPEtoPC.put(new BaseBlock(202,-1), new BaseBlock(201,2));
mapPEtoPC.put(new BaseBlock(182,1), new BaseBlock(205,-1));
mapPEtoPC.put(new BaseBlock(202,-1), new BaseBlock(203,2));
for (int id : new int[] {208}) { // end rod
mapPEtoPC.put(new BaseBlock(id,4), new BaseBlock(id,5));
mapPEtoPC.put(new BaseBlock(id,2), new BaseBlock(id,3));
mapPEtoPC.put(new BaseBlock(id,5), new BaseBlock(id,4));
mapPEtoPC.put(new BaseBlock(id,3), new BaseBlock(id,2));
mapPEtoPC.put(new BaseBlock(201,2), new BaseBlock(202,0));
mapPEtoPC.put(new BaseBlock(201,10), new BaseBlock(202,8));
mapPEtoPC.put(new BaseBlock(201,6), new BaseBlock(202,4));
mapPEtoPC.put(new BaseBlock(181,1), new BaseBlock(204,-1));
{
for (int data = 0; data < 16; data++) mapPEtoPC.put(new BaseBlock(208, data), new BaseBlock(198, data));
mapPEtoPC.put(new BaseBlock(208,4), new BaseBlock(198,5));
mapPEtoPC.put(new BaseBlock(208,2), new BaseBlock(198,3));
mapPEtoPC.put(new BaseBlock(208,5), new BaseBlock(198,4));
mapPEtoPC.put(new BaseBlock(208,3), new BaseBlock(198,2));
}
for (int id : new int[] {77, 143}) { // button
@ -113,6 +330,11 @@ public class ClipboardRemapper {
mapPEtoPC.put(new BaseBlock(id,1), new BaseBlock(id,5));
mapPEtoPC.put(new BaseBlock(id,2), new BaseBlock(id,4));
mapPEtoPC.put(new BaseBlock(id,5), new BaseBlock(id,1));
mapPEtoPC.put(new BaseBlock(id,13), new BaseBlock(id,9));
mapPEtoPC.put(new BaseBlock(id,12), new BaseBlock(id,10));
mapPEtoPC.put(new BaseBlock(id,10), new BaseBlock(id,12));
mapPEtoPC.put(new BaseBlock(id,9), new BaseBlock(id,13));
}
// leaves
@ -123,13 +345,41 @@ public class ClipboardRemapper {
for (int data = 0; data < 4; data++) mapPEtoPC.put(new BaseBlock(id, data), new BaseBlock(id, 3 - data));
for (int data = 4; data < 12; data++) mapPEtoPC.put(new BaseBlock(id, data), new BaseBlock(id, 15 - data));
for (int data = 12; data < 15; data++) mapPEtoPC.put(new BaseBlock(id, data), new BaseBlock(id, 27 - data));
mapPEtoPC.put(new BaseBlock(id, 2), new BaseBlock(id, 0));
mapPEtoPC.put(new BaseBlock(id, 3), new BaseBlock(id, 1));
mapPEtoPC.put(new BaseBlock(id, 7), new BaseBlock(id, 9));
mapPEtoPC.put(new BaseBlock(id, 6), new BaseBlock(id, 8));
}
return mapPEtoPC;
}
public ClipboardRemapper(RemapPlatform fromPlatform, RemapPlatform toPlatform) {
if (fromPlatform == toPlatform) {
this.from = null;
return;
}
HashMap<BaseBlock, BaseBlock> mapPEtoPC = getPEtoPCMappings();
// TODO any custom ids
switch (fromPlatform) {
case PE:
for (int data = 0; data < 8; data++) add(new BaseBlock(182, 1), new BaseBlock(205, data));
for (int data = 8; data < 16; data++) add(new BaseBlock(182, 9), new BaseBlock(205, data));
for (int data = 0; data < 8; data++) add(new BaseBlock(182, 0), new BaseBlock(182, data));
for (int data = 8; data < 16; data++) add(new BaseBlock(182, 8), new BaseBlock(182, data));
break;
case PC:
add(new BaseBlock(202, -1), new BaseBlock(201, -1));
add(new BaseBlock(204, -1), new BaseBlock(201, -1));
for (int data = 0; data < 8; data++) add(new BaseBlock(205, data), new BaseBlock(182, 1));
for (int data = 8; data < 16; data++) add(new BaseBlock(205, data), new BaseBlock(182, 9));
for (int data = 0; data < 8; data++) add(new BaseBlock(182, data), new BaseBlock(182, 0));
for (int data = 8; data < 16; data++) add(new BaseBlock(182, data), new BaseBlock(182, 8));
break;
}
@ -142,6 +392,8 @@ public class ClipboardRemapper {
add(to, from);
}
}
this.from = fromPlatform;
}
public void addBoth(BaseBlock from, BaseBlock to) {
@ -191,7 +443,6 @@ public class ClipboardRemapper {
return id;
}
public void add(BaseBlock from, BaseBlock to) {
if (from.getData() != to.getData()) {
if (from.getData() == -1) {
@ -237,4 +488,7 @@ public class ClipboardRemapper {
return block;
}
public void remap(CompoundTag tag) {
}
}

View File

@ -0,0 +1,102 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.Fawe;
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&section=1";
private static String PC = "https://minecraft.gamepedia.com/index.php?title=Java_Edition_data_values/Item_IDs&action=edit";
private Map<ClipboardRemapper.RemapPlatform, Map<String, Integer>> cache = new HashMap<>();
public Map<String, Integer> expand(Map<String, Integer> map) {
HashMap<String, Integer> newMap = new HashMap<>(map);
for (Map.Entry<String, Integer> entry : map.entrySet()) {
newMap.put(entry.getKey().replace("_", ""), entry.getValue());
}
return newMap;
}
public synchronized Map<String, Integer> scapeOrCache(ClipboardRemapper.RemapPlatform platform) throws IOException {
Map<String, Integer> map;
try {
Map<String, Integer> cached = cache.get(platform);
if (cached != null) return cached;
File file = new File("lib" + File.separator + "items-" + 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<Map<String, Integer>>() {
}.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<String, Integer> scrape(ClipboardRemapper.RemapPlatform platform) throws IOException {
Fawe.debug("Downloading item mappings for " + platform + ". Please wait...");
String url = (platform == ClipboardRemapper.RemapPlatform.PC) ? PC : PE;
String text = MainUtil.getText(url);
String header = "{{";
String footer = "{{-}}";
String prefix = "{{id table|";
HashMap<String, Integer> 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++;
}
Fawe.debug("Download complete.");
return map;
}
}

View File

@ -47,13 +47,16 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
@ -61,6 +64,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.DataFormatException;
@ -508,7 +512,28 @@ public class MainUtil {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}
}
public static String getText(String url) throws IOException {
try (Scanner scanner = new Scanner(new URL(url).openStream(), "UTF-8")) {
return scanner.useDelimiter("\\A").next();
}
}
public static void download(URL url, File out) throws IOException {
File parent = out.getParentFile();
if (!out.exists()) {
if (parent != null) parent.mkdirs();
File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp", parent);
tempFile.deleteOnExit();
try (InputStream is = url.openStream()) {
ReadableByteChannel rbc = Channels.newChannel(is);
FileOutputStream fos = new FileOutputStream(tempFile);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
Files.copy(tempFile.toPath(), out.toPath(), StandardCopyOption.REPLACE_EXISTING);
tempFile.delete();
}
}

View File

@ -73,6 +73,16 @@ public final class NBTInputStream implements Closeable {
return readNamedTag(0);
}
/**
* Reads an NBT map from the stream.
*
* @return The map that was read.
* @throws IOException if an I/O error occurs.
*/
public NamedData readNamedData() throws IOException {
return readNamedData(0);
}
/**
* Reads an NBT from the stream.
*
@ -85,6 +95,11 @@ public final class NBTInputStream implements Closeable {
return new NamedTag(readNamedTagName(type), readTagPayload(type, depth));
}
private NamedData readNamedData(int depth) throws IOException {
int type = is.readByte();
return new NamedData(readNamedTagName(type), readDataPayload(type, depth));
}
public Tag readTag() throws IOException {
int type = is.readByte();
return readTagPayload(type, 0);
@ -363,6 +378,79 @@ public final class NBTInputStream implements Closeable {
}
}
public Object readDataPayload(int type, int depth) throws IOException {
switch (type) {
case NBTConstants.TYPE_END:
if (depth == 0) {
throw new IOException(
"TAG_End found without a TAG_Compound/TAG_List tag preceding it.");
} else {
return null;
}
case NBTConstants.TYPE_BYTE:
return is.readByte();
case NBTConstants.TYPE_SHORT:
return is.readShort();
case NBTConstants.TYPE_INT:
return is.readInt();
case NBTConstants.TYPE_LONG:
return is.readLong();
case NBTConstants.TYPE_FLOAT:
return is.readFloat();
case NBTConstants.TYPE_DOUBLE:
return is.readDouble();
case NBTConstants.TYPE_BYTE_ARRAY:
int length = is.readInt();
byte[] bytes = new byte[length];
is.readFully(bytes);
return bytes;
case NBTConstants.TYPE_STRING:
length = is.readShort();
bytes = new byte[length];
is.readFully(bytes);
return new String(bytes, NBTConstants.CHARSET);
case NBTConstants.TYPE_LIST:
int childType = is.readByte();
if (childType == NBTConstants.TYPE_LIST) {
childType = NBTConstants.TYPE_COMPOUND;
}
length = is.readInt();
ArrayList<Object> list = new ArrayList<>();
for (int i = 0; i < length; ++i) {
Object obj = readDataPayload(childType, depth + 1);
if (obj == null) {
throw new IOException("TAG_End not permitted in a list.");
}
list.add(obj);
}
return list;
case NBTConstants.TYPE_COMPOUND:
Map<String, Object> map = new HashMap<>();
while (true) {
int newType = is.readByte();
String name = readNamedTagName(newType);
Object data = readDataPayload(newType, depth + 1);
if (data == null) {
break;
} else {
map.put(name, data);
}
}
return map;
case NBTConstants.TYPE_INT_ARRAY:
length = is.readInt();
int[] data = new int[length];
for (int i = 0; i < length; i++) {
data[i] = is.readInt();
}
return data;
default:
throw new IOException("Invalid tag type: " + type + ".");
}
}
/**
* Reads the payload of a tag given the type.
*

View File

@ -0,0 +1,41 @@
package com.sk89q.jnbt;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Some data with a name
*/
public class NamedData {
private final String name;
private final Object data;
/**
* Create a new named tag.
*
* @param name the name
* @param data the data
*/
public NamedData(String name, Object data) {
checkNotNull(name);
this.name = name;
this.data = data;
}
/**
* Get the name of the tag.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Get the tag.
*
* @return the tag
*/
public Object getValue() {
return data;
}
}

View File

@ -24,14 +24,9 @@ import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
@ -115,13 +110,17 @@ public class ConverterFrame extends JFrame {
final JPanel mainContent = new InvisiblePanel(new BorderLayout());
{
File world = MainUtil.getWorkingDirectory("minecraft");
long lastMod = Long.MIN_VALUE;
if (world != null && world.exists()) {
File saves = new File(world, "saves");
if (saves.exists()) {
for (File file : saves.listFiles()) {
if (file.isDirectory()) {
world = file;
break;
long modified = file.lastModified();
if (modified > lastMod) {
world = file;
lastMod = modified;
}
}
}
}
@ -130,7 +129,7 @@ public class ConverterFrame extends JFrame {
final InteractiveButton browseLoadText = new InteractiveButton(world.getPath(), DARKER_GRAY) {
@Override
public void actionPerformed(ActionEvent e) {
browseLoad.browse(new File(getText()));
browseLoad.browse(new File(getText()).getParentFile());
}
};
final InteractiveButton browseSaveText = new InteractiveButton(getDefaultOutput().getPath(), DARKER_GRAY) {
@ -145,14 +144,14 @@ public class ConverterFrame extends JFrame {
button.setOpaque(true);
button.setBorder(new EmptyBorder(4, 4, 4, 4));
}
browseLoad = new BrowseButton() {
browseLoad = new BrowseButton("_FROM") {
@Override
public void onSelect(File folder) {
browseLoadText.setText(folder.getPath());
movable.repaint();
}
};
browseSave = new BrowseButton() {
browseSave = new BrowseButton("_TO") {
@Override
public void onSelect(File folder) {
browseSaveText.setText(folder.getPath());
@ -325,21 +324,20 @@ public class ConverterFrame extends JFrame {
FakePlayer console = FakePlayer.getConsole();
try {
debug("Loading leveldb.jar");
File leveldb = new File("leveldb.jar");
if (!leveldb.exists()) {
File tempFile = File.createTempFile("leveldb.jar", ".tmp");
tempFile.deleteOnExit();
String download = "https://github.com/boy0001/FastAsyncWorldedit/raw/master/nukkit/lib/leveldb.jar";
debug("Downloading: " + download);
URL url = new URL(download);
try (InputStream is = url.openStream()) {
ReadableByteChannel rbc = Channels.newChannel(is);
FileOutputStream fos = new FileOutputStream(tempFile);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
Files.copy(tempFile.toPath(), leveldb.toPath(), StandardCopyOption.REPLACE_EXISTING);
tempFile.delete();
}
File lib = new File("lib");
File leveldb = new File(lib, "leveldb.jar");
// File blocksPE = new File(lib, "blocks-pe.json");
// File blocksPC = new File(lib, "blocks-pc.json");
URL levelDbUrl = new URL("https://git.io/vdZ9e");
// URL urlPE = new URL("https://git.io/vdZSj");
// URL urlPC = new URL("https://git.io/vdZSx");
MainUtil.download(levelDbUrl, leveldb);
// MainUtil.download(urlPE, blocksPC);
// MainUtil.download(urlPC, blocksPE);
MainUtil.loadURLClasspath(leveldb.toURL());
File newWorldFile = new File(output, dirMc.getName());

View File

@ -19,7 +19,7 @@ import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.File;
import java.io.FileInputStream;
@ -27,10 +27,12 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
@ -47,7 +49,7 @@ public class LevelDBToMCAFile extends MapConverter {
public LevelDBToMCAFile(File from, File to) {
super(from, to);
try {
BundledBlockData.getInstance().loadFromResource();
// BundledBlockData.getInstance().loadFromResource();
this.pool = new ForkJoinPool();
this.remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PE, ClipboardRemapper.RemapPlatform.PC);
int bufferSize = (int) Math.min(Integer.MAX_VALUE, Math.max((long) (MemUtil.getFreeBytes() * 0.8), 134217728));
@ -98,7 +100,6 @@ public class LevelDBToMCAFile extends MapConverter {
File levelDat = new File(folderFrom, "level.dat");
copyLevelDat(levelDat);
// Chunks
MCAQueue queue = new MCAQueue(worldName, new File(worldOut, "region"), true);
RemapFilter filter = new RemapFilter(this.remapper);
@ -117,7 +118,7 @@ public class LevelDBToMCAFile extends MapConverter {
MCAChunk chunk = (MCAChunk) queue.getFaweChunk(cx, cz);
switch (tag) {
case Data2D:
case Data2D: {
// height
ByteBuffer buffer = ByteBuffer.wrap(value);
int[] heightArray = chunk.getHeightMapArray();
@ -130,7 +131,8 @@ public class LevelDBToMCAFile extends MapConverter {
System.arraycopy(value, biomeOffset, chunk.biomes, 0, chunk.biomes.length);
}
break;
case SubChunkPrefix:
}
case SubChunkPrefix: {
int layer = key[9];
byte[] ids = getOrCreate(chunk.ids, layer, 4096);
byte[] data = getOrCreate(chunk.data, layer, 2048);
@ -144,15 +146,25 @@ public class LevelDBToMCAFile extends MapConverter {
chunk.filterBlocks(new MutableMCABackedBaseBlock(), filter);
break;
case BlockEntity:
}
case BlockEntity: {
List<NamedTag> tags = read(value);
for (NamedTag nt : tags) {
com.sk89q.jnbt.Tag tile = nt.getTag();
}
break;
}
case Entity:
List<NamedTag> tags = read(value);
for (NamedTag nt : tags) {
com.sk89q.jnbt.Tag ent = nt.getTag();
// chunk.setEntity((CompoundTag) ent);
}
break;
// Ignore
case LegacyTerrain:
case BiomeState:
case Data2DLegacy:
System.out.println("Legacy terrain not supported, please update.");
Fawe.debug("Legacy terrain not supported, please update. " + tag);
case BiomeState:
case FinalizedState:
case PendingTicks:
case BlockExtraData:
@ -167,10 +179,24 @@ public class LevelDBToMCAFile extends MapConverter {
e.printStackTrace();
} finally {
close();
app.prompt("Compaction complete!");
app.prompt("Conversion complete!");
}
}
private List<NamedTag> read(byte[] data) {
ArrayList<NamedTag> list = new ArrayList<>();
ByteArrayInputStream baos = new ByteArrayInputStream(data);
try (NBTInputStream in = new NBTInputStream((DataInput) new LittleEndianDataInputStream(baos))) {
while (baos.available() > 0) {
NamedTag nt = in.readNamedTag();
list.add(nt);
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
private void copySection(byte[] dest, byte[] src, int srcPos) {
if (src.length <= srcPos) return;
switch (dest.length) {
@ -240,8 +266,14 @@ public class LevelDBToMCAFile extends MapConverter {
}
public void copyLevelDat(File in) throws IOException {
copyLevelDat(this.folderTo, in);
}
public static void copyLevelDat(File folderTo, File in) throws IOException {
File levelDat = new File(folderTo, "level.dat");
if (!levelDat.exists()) {
folderTo.mkdirs();
levelDat.createNewFile();
}
try (LittleEndianDataInputStream ledis = new LittleEndianDataInputStream(new FileInputStream(in))) {
@ -274,7 +306,9 @@ public class LevelDBToMCAFile extends MapConverter {
if (value instanceof ByteTag) {
value = new StringTag((Byte) value.getValue() == 1 ? "true" : "false");
}
ruleTagValue.put(rule.getValue(), value);
if (value != null) {
ruleTagValue.put(rule.getValue(), value);
}
}
HashSet<String> allowed = new HashSet<>(Arrays.asList(
@ -284,7 +318,6 @@ public class LevelDBToMCAFile extends MapConverter {
while (iterator.hasNext()) {
Map.Entry<String, com.sk89q.jnbt.Tag> entry = iterator.next();
if (!allowed.contains(entry.getKey())) {
System.out.println("TODO (Unsupported): " + entry.getKey() + " | " + entry.getValue());
iterator.remove();
}
}

View File

@ -17,7 +17,9 @@ import com.boydti.fawe.util.ReflectionUtils;
import com.boydti.fawe.util.StringMan;
import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.FloatTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.LongTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
@ -25,6 +27,7 @@ import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
@ -55,7 +58,7 @@ public class MCAFile2LevelDB extends MapConverter {
private final ByteStore keyStore9 = new ByteStore(9);
private final ByteStore keyStore10 = new ByteStore(10);
private final ByteStore bufData2D = new ByteStore(512 + 256);
private final ByteStore bufSubChunkPrefix = new ByteStore(1 + 4096 + 2058 + 2048 + 2048);
private final ByteStore bufSubChunkPrefix = new ByteStore(1 + 4096 + 2048 + 2048 + 2048);
private final byte[] VERSION = new byte[] { 4 };
private final byte[] COMPLETE_STATE = new byte[] { 2, 0, 0, 0 };
@ -274,7 +277,7 @@ public class MCAFile2LevelDB extends MapConverter {
List<com.sk89q.jnbt.Tag> tiles = new ArrayList<>();
for (Map.Entry<Short, CompoundTag> entry : chunk.getTiles().entrySet()) {
CompoundTag tag = entry.getValue();
tiles.add(transform(tag));
tiles.add(transform(chunk, tag));
}
update(getKey(chunk, Tag.BlockEntity), write(tiles));
}
@ -282,7 +285,7 @@ public class MCAFile2LevelDB extends MapConverter {
if (!chunk.entities.isEmpty()) {
List<com.sk89q.jnbt.Tag> entities = new ArrayList<>();
for (com.sk89q.jnbt.CompoundTag tag : chunk.getEntities()) {
entities.add(transform(tag));
entities.add(transform(chunk, tag));
}
update(getKey(chunk, Tag.Entity), write(entities));
}
@ -399,42 +402,71 @@ public class MCAFile2LevelDB extends MapConverter {
return baos.toByteArray();
}
private String convertId(String input) {
input = input.replace("minecraft:", "");
StringBuilder result = new StringBuilder();
boolean toUpper = false;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (i == 0) toUpper = true;
if (c == '_') {
toUpper = true;
} else {
result.append(toUpper ? Character.toUpperCase(c) : c);
toUpper = false;
private CompoundTag transformItem(CompoundTag item) {
String itemId = item.getString("id");
short damage = item.getShort("Damage");
BaseBlock remapped = remapper.remapItem(itemId, damage);
Map<String, com.sk89q.jnbt.Tag> map = ReflectionUtils.getMap(item.getValue());
map.put("id", new ShortTag((short) remapped.getId()));
map.put("Damage", new ShortTag((short) remapped.getData()));
CompoundTag tag = (CompoundTag) item.getValue().get("tag");
if (tag != null) {
List<CompoundTag> enchants = (List) tag.getList("ench");
if (enchants != null) {
for (CompoundTag ench : enchants) {
Map<String, com.sk89q.jnbt.Tag> value = ReflectionUtils.getMap(ench.getValue());
String id = ench.getString("id");
String lvl = ench.getString("lvl");
if (id != null) value.put("id", new ShortTag(Short.parseShort(id)));
if (id != null) value.put("lvl", new ShortTag(Short.parseShort(id)));
}
}
}
return result.toString();
return item;
}
private CompoundTag transform(CompoundTag tag) {
private CompoundTag transform(MCAChunk chunk, CompoundTag tag) {
try {
String id = tag.getString("id");
if (id != null) {
Map<String, com.sk89q.jnbt.Tag> map = ReflectionUtils.getMap(tag.getValue());
id = convertId(id);
id = remapper.remapEntityId(id);
map.put("id", new StringTag(id));
{ // Convert items
com.sk89q.jnbt.ListTag items = tag.getListTag("Items");
for (CompoundTag item : (List<CompoundTag>) (List) items.getValue()) {
String itemId = item.getString("id");
BaseBlock state = BundledBlockData.getInstance().findByState(itemId);
if (state != null) {
int legacy = state.getId();
ReflectionUtils.getMap(item.getValue()).put("id", new ShortTag((short) legacy));
((List<CompoundTag>) (List) items.getValue()).forEach(this::transformItem);
}
{ // Convert item
String item = tag.getString("Item");
if (item != null) {
short damage = tag.getShort("Data");
BaseBlock remapped = remapper.remapItem(item, damage);
map.put("Item", new ShortTag((short) remapped.getId()));
map.put("mData", new IntTag(remapped.getData()));
}
}
{ // Health
com.sk89q.jnbt.Tag health = map.get("Health");
if (health != null && health instanceof FloatTag) {
map.put("Health", new ShortTag((short) tag.getFloat("Health")));
}
}
{ // Orientation / Position
for (String key : new String[] {"Orientation", "Position"}) {
ListTag list = (ListTag) map.get(key);
if (list != null) {
List<com.sk89q.jnbt.Tag> value = list.getValue();
ArrayList<FloatTag> newList = new ArrayList<>();
for (com.sk89q.jnbt.Tag coord : value) {
newList.add(new FloatTag(((Number) coord.getValue()).floatValue()));
}
map.put(key, new ListTag(FloatTag.class, newList));
}
}
}
switch (id) {
case "EndGateway":
case "MobSpawner": {
map.clear();
break;
@ -446,8 +478,30 @@ public class MCAFile2LevelDB extends MapConverter {
if (text != null && text.startsWith("{")) {
map.put(key, new StringTag(BBC.jsonToString(text)));
}
}
break;
}
case "CommandBlock": {
int x = tag.getInt("x");
int y = tag.getInt("y");
int z = tag.getInt("z");
map.put("Version", new IntTag(3));
BaseBlock block = chunk.getBlock(x & 15, y, z & 15);
int LPCommandMode = 0;
switch (block.getId()) {
case BlockID.CHAIN_COMMAND_BLOCK:
LPCommandMode = 2;
break;
case BlockID.REPEATING_COMMAND_BLOCK:
LPCommandMode = 1;
break;
}
map.putIfAbsent("isMovable", new ByteTag((byte) 1));
map.put("LPCommandMode", new IntTag(LPCommandMode));
map.put("LPCondionalMode", new ByteTag((byte) (block.getData() > 7 ? 1 : 0)));
map.put("LPRedstoneMode", new ByteTag(tag.getByte("auto")));
break;
}
}
}