mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-12-29 12:37:53 +01:00
Progress, lower memory usage
This commit is contained in:
parent
911f613f2f
commit
b2395f7aa9
@ -1,7 +1,6 @@
|
||||
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;
|
||||
@ -58,7 +57,6 @@ public class ItemWikiScraper {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -96,7 +94,6 @@ public class ItemWikiScraper {
|
||||
}
|
||||
id++;
|
||||
}
|
||||
Fawe.debug("Download complete.");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
409
core/src/main/java/com/sk89q/jnbt/CompoundTag.java
Normal file
409
core/src/main/java/com/sk89q/jnbt/CompoundTag.java
Normal file
@ -0,0 +1,409 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Compound} tag.
|
||||
*/
|
||||
public final class CompoundTag extends Tag {
|
||||
|
||||
private final Map<String, Tag> value;
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public CompoundTag(Map<String, Tag> value) {
|
||||
super();
|
||||
this.value = Collections.unmodifiableMap(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getRaw() {
|
||||
HashMap<String, Object> raw = new HashMap<>();
|
||||
for (Map.Entry<String, Tag> entry : value.entrySet()) {
|
||||
raw.put(entry.getKey(), entry.getValue().getRaw());
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this compound tag contains the given key.
|
||||
*
|
||||
* @param key the given key
|
||||
* @return true if the tag contains the given key
|
||||
*/
|
||||
public boolean containsKey(String key) {
|
||||
return value.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new compound tag with the given values.
|
||||
*
|
||||
* @param value the value
|
||||
* @return the new compound tag
|
||||
*/
|
||||
public CompoundTag setValue(Map<String, Tag> value) {
|
||||
return new CompoundTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a compound tag builder.
|
||||
*
|
||||
* @return the builder
|
||||
*/
|
||||
public CompoundTagBuilder createBuilder() {
|
||||
return new CompoundTagBuilder(new HashMap<String, Tag>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a byte array named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a byte array tag,
|
||||
* then an empty byte array will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a byte array
|
||||
*/
|
||||
public byte[] getByteArray(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ByteArrayTag) {
|
||||
return ((ByteArrayTag) tag).getValue();
|
||||
} else {
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a byte named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a byte tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a byte
|
||||
*/
|
||||
public byte getByte(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
} else {
|
||||
return (byte) 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a double named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a double tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a double
|
||||
*/
|
||||
public double getDouble(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a double named with the given key, even if it's another
|
||||
* type of number.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a number,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a double
|
||||
*/
|
||||
public double asDouble(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue();
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a float named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a float tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a float
|
||||
*/
|
||||
public float getFloat(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code int[]} named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not an int array tag,
|
||||
* then an empty array will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return an int array
|
||||
*/
|
||||
public int[] getIntArray(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof IntArrayTag) {
|
||||
return ((IntArrayTag) tag).getValue();
|
||||
} else {
|
||||
return new int[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an int named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not an int tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return an int
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an int named with the given key, even if it's another
|
||||
* type of number.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a number,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return an int
|
||||
*/
|
||||
public int asInt(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue().intValue();
|
||||
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue().intValue();
|
||||
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue().intValue();
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of tags named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a list tag,
|
||||
* then an empty list will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a list of tags
|
||||
*/
|
||||
public List<Tag> getList(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ListTag) {
|
||||
return ((ListTag) tag).getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code TagList} named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a list tag,
|
||||
* then an empty tag list will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a tag list instance
|
||||
*/
|
||||
public ListTag getListTag(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ListTag) {
|
||||
return (ListTag) tag;
|
||||
} else {
|
||||
return new ListTag(StringTag.class, Collections.<Tag>emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of tags named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a list tag,
|
||||
* then an empty list will be returned. If the given key references
|
||||
* a list but the list of of a different type, then an empty
|
||||
* list will also be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param listType the class of the contained type
|
||||
* @return a list of tags
|
||||
* @param <T> the type of list
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ListTag) {
|
||||
ListTag listTag = (ListTag) tag;
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a long tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a long
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue();
|
||||
} else {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long named with the given key, even if it's another
|
||||
* type of number.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a number,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a long
|
||||
*/
|
||||
public long asLong(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue().longValue();
|
||||
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue().longValue();
|
||||
|
||||
} else {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a short named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a short tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a short
|
||||
*/
|
||||
public short getShort(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string named with the given key.
|
||||
*
|
||||
* <p>If the key does not exist or its value is not a string tag,
|
||||
* then {@code ""} will be returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a string
|
||||
*/
|
||||
public String getString(String key) {
|
||||
Tag tag = value.get(key);
|
||||
if (tag instanceof StringTag) {
|
||||
return ((StringTag) tag).getValue();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder bldr = new StringBuilder();
|
||||
bldr.append("TAG_Compound").append(": ").append(value.size()).append(" entries\r\n{\r\n");
|
||||
for (Map.Entry<String, Tag> entry : value.entrySet()) {
|
||||
bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n");
|
||||
}
|
||||
bldr.append("}");
|
||||
return bldr.toString();
|
||||
}
|
||||
|
||||
}
|
422
core/src/main/java/com/sk89q/jnbt/ListTag.java
Normal file
422
core/src/main/java/com/sk89q/jnbt/ListTag.java
Normal file
@ -0,0 +1,422 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* The {@code TAG_List} tag.
|
||||
*/
|
||||
public final class ListTag extends Tag {
|
||||
|
||||
private final Class<? extends Tag> type;
|
||||
private final List<Tag> value;
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param type the type of tag
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public ListTag(Class<? extends Tag> type, List<? extends Tag> value) {
|
||||
super();
|
||||
checkNotNull(value);
|
||||
this.type = type;
|
||||
this.value = Collections.unmodifiableList(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getRaw() {
|
||||
ArrayList<Object> raw = new ArrayList<>();
|
||||
for (Tag t : value) {
|
||||
raw.add(t.getRaw());
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of item in this list.
|
||||
*
|
||||
* @return The type of item in this list.
|
||||
*/
|
||||
public Class<? extends Tag> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new list tag with this tag's name and type.
|
||||
*
|
||||
* @param list the new list
|
||||
* @return a new list tag
|
||||
*/
|
||||
public ListTag setValue(List<Tag> list) {
|
||||
return new ListTag(getType(), list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tag if it exists at the given index.
|
||||
*
|
||||
* @param index the index
|
||||
* @return the tag or null
|
||||
*/
|
||||
@Nullable
|
||||
public Tag getIfExists(int index) {
|
||||
try {
|
||||
return value.get(index);
|
||||
} catch (NoSuchElementException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a byte array named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a byte array tag,
|
||||
* then an empty byte array will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a byte array
|
||||
*/
|
||||
public byte[] getByteArray(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ByteArrayTag) {
|
||||
return ((ByteArrayTag) tag).getValue();
|
||||
} else {
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a byte named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a byte tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a byte
|
||||
*/
|
||||
public byte getByte(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
} else {
|
||||
return (byte) 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a double named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a double tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a double
|
||||
*/
|
||||
public double getDouble(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a double named with the given index, even if it's another
|
||||
* type of number.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a number,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a double
|
||||
*/
|
||||
public double asDouble(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue();
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a float named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a float tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a float
|
||||
*/
|
||||
public float getFloat(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code int[]} named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not an int array tag,
|
||||
* then an empty array will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return an int array
|
||||
*/
|
||||
public int[] getIntArray(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof IntArrayTag) {
|
||||
return ((IntArrayTag) tag).getValue();
|
||||
} else {
|
||||
return new int[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an int named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not an int tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return an int
|
||||
*/
|
||||
public int getInt(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an int named with the given index, even if it's another
|
||||
* type of number.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a number,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return an int
|
||||
*/
|
||||
public int asInt(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue().intValue();
|
||||
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue().intValue();
|
||||
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue().intValue();
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of tags named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a list tag,
|
||||
* then an empty list will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a list of tags
|
||||
*/
|
||||
public List<Tag> getList(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ListTag) {
|
||||
return ((ListTag) tag).getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code TagList} named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a list tag,
|
||||
* then an empty tag list will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a tag list instance
|
||||
*/
|
||||
public ListTag getListTag(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ListTag) {
|
||||
return (ListTag) tag;
|
||||
} else {
|
||||
return new ListTag(StringTag.class, Collections.<Tag>emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of tags named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a list tag,
|
||||
* then an empty list will be returned. If the given index references
|
||||
* a list but the list of of a different type, then an empty
|
||||
* list will also be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @param listType the class of the contained type
|
||||
* @return a list of tags
|
||||
* @param <T> the NBT type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(int index, Class<T> listType) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ListTag) {
|
||||
ListTag listTag = (ListTag) tag;
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a long tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a long
|
||||
*/
|
||||
public long getLong(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue();
|
||||
} else {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long named with the given index, even if it's another
|
||||
* type of number.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a number,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a long
|
||||
*/
|
||||
public long asLong(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ByteTag) {
|
||||
return ((ByteTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof IntTag) {
|
||||
return ((IntTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof LongTag) {
|
||||
return ((LongTag) tag).getValue();
|
||||
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return ((FloatTag) tag).getValue().longValue();
|
||||
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return ((DoubleTag) tag).getValue().longValue();
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a short named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a short tag,
|
||||
* then {@code 0} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a short
|
||||
*/
|
||||
public short getShort(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof ShortTag) {
|
||||
return ((ShortTag) tag).getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string named with the given index.
|
||||
*
|
||||
* <p>If the index does not exist or its value is not a string tag,
|
||||
* then {@code ""} will be returned.</p>
|
||||
*
|
||||
* @param index the index
|
||||
* @return a string
|
||||
*/
|
||||
public String getString(int index) {
|
||||
Tag tag = getIfExists(index);
|
||||
if (tag instanceof StringTag) {
|
||||
return ((StringTag) tag).getValue();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder bldr = new StringBuilder();
|
||||
bldr.append("TAG_List").append(": ").append(value.size()).append(" entries of type ").append(NBTUtils.getTypeName(type)).append("\r\n{\r\n");
|
||||
for (Tag t : value) {
|
||||
bldr.append(" ").append(t.toString().replaceAll("\r\n", "\r\n ")).append("\r\n");
|
||||
}
|
||||
bldr.append("}");
|
||||
return bldr.toString();
|
||||
}
|
||||
|
||||
}
|
38
core/src/main/java/com/sk89q/jnbt/Tag.java
Normal file
38
core/src/main/java/com/sk89q/jnbt/Tag.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
/**
|
||||
* Represents a NBT tag.
|
||||
*/
|
||||
public abstract class Tag {
|
||||
|
||||
/**
|
||||
* Gets the value of this tag.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public abstract Object getValue();
|
||||
|
||||
public Object getRaw() {
|
||||
return getValue();
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
@ -11,6 +11,8 @@ 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.util.MainUtil;
|
||||
import com.boydti.fawe.wrappers.FakePlayer;
|
||||
import java.awt.BorderLayout;
|
||||
@ -30,6 +32,10 @@ import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
@ -37,13 +43,17 @@ import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
public class ConverterFrame extends JFrame {
|
||||
private final InvisiblePanel loggerPanel;
|
||||
private final JProgressBar progressBar;
|
||||
private Color LIGHT_GRAY = new Color(0x66, 0x66, 0x66);
|
||||
private Color GRAY = new Color(0x44, 0x44, 0x46);
|
||||
private Color DARK_GRAY = new Color(0x33, 0x33, 0x36);
|
||||
@ -56,6 +66,8 @@ public class ConverterFrame extends JFrame {
|
||||
private BrowseButton browseSave;
|
||||
|
||||
public ConverterFrame() throws Exception {
|
||||
async(() -> downloadDependencies());
|
||||
|
||||
final MovablePanel movable = new MovablePanel(this);
|
||||
movable.setBorder(BorderFactory.createLineBorder(new Color(0x28, 0x28, 0x29)));
|
||||
|
||||
@ -69,23 +81,27 @@ public class ConverterFrame extends JFrame {
|
||||
int y = (int) ((dimension.getHeight() - this.getHeight()) / 2);
|
||||
this.setLocation(x, y);
|
||||
this.setVisible(true);
|
||||
this.setOpacity(0);
|
||||
|
||||
if (this.transparency(0)) {
|
||||
fadeIn();
|
||||
}
|
||||
|
||||
movable.setBackground(DARK_GRAY);
|
||||
movable.setLayout(new BorderLayout());
|
||||
|
||||
fadeIn();
|
||||
|
||||
JPanel topBar = new InvisiblePanel(new BorderLayout());
|
||||
{
|
||||
JPanel topBarLeft = new InvisiblePanel();
|
||||
JPanel topBarCenter = new InvisiblePanel();
|
||||
JPanel topBarRight = new InvisiblePanel();
|
||||
|
||||
JLabel title = new JLabel("(FAWE) Anvil and LevelDB converter");
|
||||
JLabel title = new JLabel();
|
||||
title.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
title.setAlignmentX(Component.RIGHT_ALIGNMENT);
|
||||
title.setForeground(Color.LIGHT_GRAY);
|
||||
title.setText("(FAWE) Anvil and LevelDB converter");
|
||||
title.setFont(new Font("Lucida Sans Unicode", Font.PLAIN, 15));
|
||||
setTitle(null);
|
||||
|
||||
MinimizeButton minimize = new MinimizeButton(this);
|
||||
CloseButton exit = new CloseButton();
|
||||
@ -195,8 +211,7 @@ public class ConverterFrame extends JFrame {
|
||||
installContent.add(install);
|
||||
installContent.setBorder(new EmptyBorder(10, 0, 10, 0));
|
||||
this.loggerPanel = new InvisiblePanel(new BorderLayout());
|
||||
this.loggerPanel.setBackground(Color.GREEN);
|
||||
loggerPanel.setPreferredSize(new Dimension(416, 442));
|
||||
loggerPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, 380));
|
||||
loggerTextArea = new JTextArea();
|
||||
loggerTextArea.setBackground(Color.GRAY);
|
||||
loggerTextArea.setForeground(Color.DARK_GRAY);
|
||||
@ -208,10 +223,22 @@ public class ConverterFrame extends JFrame {
|
||||
loggerPanel.add(scroll);
|
||||
loggerPanel.setVisible(false);
|
||||
|
||||
this.progressBar = new JProgressBar();
|
||||
progressBar.setVisible(false);
|
||||
progressBar.setStringPainted(true);
|
||||
progressBar.setBackground(DARK_GRAY);
|
||||
progressBar.setForeground(OFF_WHITE);
|
||||
|
||||
mainContent.setBorder(new EmptyBorder(6, 32, 6, 32));
|
||||
mainContent.add(browseContent, BorderLayout.NORTH);
|
||||
mainContent.add(installContent, BorderLayout.CENTER);
|
||||
mainContent.add(loggerPanel, BorderLayout.SOUTH);
|
||||
|
||||
final JPanel console = new InvisiblePanel(new BorderLayout());
|
||||
console.setBorder(new EmptyBorder(6, 0, 6, 0));
|
||||
console.add(progressBar, BorderLayout.SOUTH);
|
||||
console.add(loggerPanel, BorderLayout.NORTH);
|
||||
|
||||
mainContent.add(console, BorderLayout.SOUTH);
|
||||
}
|
||||
JPanel bottomBar = new InvisiblePanel();
|
||||
{
|
||||
@ -270,6 +297,47 @@ public class ConverterFrame extends JFrame {
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
public void prompt(String message) {
|
||||
JOptionPane.showMessageDialog(null, message);
|
||||
Fawe.debug(message);
|
||||
}
|
||||
|
||||
public void debug(String m) {
|
||||
System.out.println(m);
|
||||
}
|
||||
|
||||
public void setProgress(String text, int percent) {
|
||||
Border border = BorderFactory.createTitledBorder(new EmptyBorder(0, 0, 0, 0), "Time remaining: " + text, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, new Font("Lucida Sans Unicode",Font.PLAIN,12), OFF_WHITE);
|
||||
progressBar.setVisible(true);
|
||||
progressBar.setBorder(border);
|
||||
progressBar.setValue(percent);
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void fadeIn() {
|
||||
async(() -> {
|
||||
for (float i = 0; i <= 1.015; i += 0.016) {
|
||||
if (!transparency(Math.min(1, i))) return;
|
||||
try {
|
||||
Thread.sleep(16);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (UnsupportedOperationException ignore) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean transparency(float val) {
|
||||
try {
|
||||
super.setOpacity(val);
|
||||
return true;
|
||||
} catch (UnsupportedOperationException ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private File getDefaultOutput() {
|
||||
if (MainUtil.getPlatform() == MainUtil.OS.WINDOWS) {
|
||||
String applicationData = System.getenv("APPDATA");
|
||||
@ -281,16 +349,61 @@ public class ConverterFrame extends JFrame {
|
||||
return new File(".");
|
||||
}
|
||||
|
||||
public void prompt(String message) {
|
||||
JOptionPane.showMessageDialog(null, message);
|
||||
Fawe.debug(message);
|
||||
private void async(Runnable r) {
|
||||
new Thread(r).start();
|
||||
}
|
||||
|
||||
public void debug(String m) {
|
||||
System.out.println(m);
|
||||
private AtomicBoolean dependenciesLoaded = new AtomicBoolean(false);
|
||||
private void downloadDependencies() {
|
||||
synchronized (dependenciesLoaded) {
|
||||
if (dependenciesLoaded.get()) return;
|
||||
try {
|
||||
ExecutorService pool = Executors.newCachedThreadPool();
|
||||
ItemWikiScraper scraper = new ItemWikiScraper();
|
||||
|
||||
File lib = new File("lib");
|
||||
File leveldb = new File(lib, "leveldb_v1.jar");
|
||||
URL levelDbUrl = new URL("https://git.io/vdZ9e");
|
||||
|
||||
pool.submit((Runnable) () -> {
|
||||
try {
|
||||
MainUtil.download(levelDbUrl, leveldb);
|
||||
MainUtil.loadURLClasspath(leveldb.toURL());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
pool.submit((Runnable) () -> {
|
||||
try {
|
||||
scraper.scapeOrCache(ClipboardRemapper.RemapPlatform.PE);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
pool.submit((Runnable) () -> {
|
||||
try {
|
||||
scraper.scapeOrCache(ClipboardRemapper.RemapPlatform.PC);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
pool.shutdown();
|
||||
try {
|
||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
dependenciesLoaded.set(true);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void install(String input, String output) throws Exception {
|
||||
private void install(String input, String output) throws Exception {
|
||||
if (!loggerPanel.isVisible()) {
|
||||
loggerPanel.setVisible(true);
|
||||
this.repaint();
|
||||
@ -324,30 +437,10 @@ public class ConverterFrame extends JFrame {
|
||||
public void run() {
|
||||
FakePlayer console = FakePlayer.getConsole();
|
||||
try {
|
||||
debug("Loading leveldb.jar");
|
||||
|
||||
File lib = new File("lib");
|
||||
|
||||
File leveldb = new File(lib, "leveldb.jar");
|
||||
URL levelDbUrl = new URL("https://git.io/vdZ9e");
|
||||
|
||||
|
||||
// File blocksPE = new File(lib, "blocks-pe.json");
|
||||
// File blocksPC = new File(lib, "blocks-pc.json");
|
||||
|
||||
// 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());
|
||||
|
||||
debug("Downloading levedb.jar and mappings (~4MB), please wait...");
|
||||
downloadDependencies();
|
||||
debug("Starting converter...");
|
||||
|
||||
File newWorldFile = new File(output, dirMc.getName());
|
||||
MapConverter converter = MapConverter.get(dirMc, newWorldFile);
|
||||
converter.accept(ConverterFrame.this);
|
||||
} catch (Throwable e) {
|
||||
@ -355,28 +448,13 @@ public class ConverterFrame extends JFrame {
|
||||
prompt("[ERROR] Conversion failed, you will have to do it manually (Nukkit server + anvil2leveldb command)");
|
||||
return;
|
||||
}
|
||||
System.gc();
|
||||
System.gc();
|
||||
}
|
||||
});
|
||||
installThread.start();
|
||||
}
|
||||
|
||||
public void fadeIn() {
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (float i = 0; i <= 1.015; i += 0.016) {
|
||||
ConverterFrame.this.setOpacity(Math.min(1, i));
|
||||
try {
|
||||
Thread.sleep(16);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ConverterFrame window = new ConverterFrame();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.clipboard.ClipboardRemapper;
|
||||
import com.boydti.fawe.object.io.LittleEndianOutputStream;
|
||||
import com.boydti.fawe.object.number.MutableLong;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
@ -52,6 +53,7 @@ import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import org.iq80.leveldb.CompressionType;
|
||||
import org.iq80.leveldb.DB;
|
||||
import org.iq80.leveldb.Options;
|
||||
import org.iq80.leveldb.WriteBatch;
|
||||
@ -61,16 +63,22 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
private final byte[] VERSION = new byte[] { 4 };
|
||||
private final byte[] COMPLETE_STATE = new byte[] { 2, 0, 0, 0 };
|
||||
|
||||
private DB db;
|
||||
private final DB db;
|
||||
private final ClipboardRemapper remapper;
|
||||
private final ForkJoinPool pool;
|
||||
private boolean closed;
|
||||
private LongAdder submitted = new LongAdder();
|
||||
private LongAdder submittedChunks = new LongAdder();
|
||||
private LongAdder submittedFiles = new LongAdder();
|
||||
|
||||
private LongAdder totalOperations = new LongAdder();
|
||||
private long estimatedOperations;
|
||||
|
||||
private long time;
|
||||
|
||||
private boolean remap;
|
||||
|
||||
private final long startTime;
|
||||
private ConverterFrame app;
|
||||
|
||||
private ConcurrentLinkedQueue<CompoundTag> portals = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private ConcurrentHashMap<Thread, WriteBatch> batches = new ConcurrentHashMap<Thread, WriteBatch>() {
|
||||
@ -79,7 +87,7 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
public WriteBatch get(Object key) {
|
||||
WriteBatch value = super.get(key);
|
||||
if (value == null) {
|
||||
synchronized (batches) {
|
||||
synchronized (MCAFile2LevelDB.this) {
|
||||
synchronized (Thread.currentThread()) {
|
||||
value = db.createWriteBatch();
|
||||
put((Thread) key, value);
|
||||
@ -92,6 +100,7 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
|
||||
public MCAFile2LevelDB(File folderFrom, File folderTo) {
|
||||
super(folderFrom, folderTo);
|
||||
this.startTime = System.currentTimeMillis();
|
||||
try {
|
||||
if (!folderTo.exists()) {
|
||||
folderTo.mkdirs();
|
||||
@ -104,15 +113,61 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
this.pool = new ForkJoinPool();
|
||||
this.remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PC, ClipboardRemapper.RemapPlatform.PE);
|
||||
BundledBlockData.getInstance().loadFromResource();
|
||||
flush(true);
|
||||
|
||||
int bufferSize = (int) Math.min(Integer.MAX_VALUE, Math.max((long) (MemUtil.getFreeBytes() * 0.8), 134217728));
|
||||
this.db = Iq80DBFactory.factory.open(new File(folderTo, "db"),
|
||||
new Options()
|
||||
.createIfMissing(true)
|
||||
.verifyChecksums(false)
|
||||
.compressionType(CompressionType.ZLIB)
|
||||
.blockSize(262144) // 256K
|
||||
.cacheSize(8388608) // 8MB
|
||||
.writeBufferSize(134217728) // >=512MB
|
||||
);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void flush(boolean openDB) throws IOException {
|
||||
private double lastPercent;
|
||||
private double lastTimeRatio;
|
||||
|
||||
private void progress(int increment) {
|
||||
if (app == null) return;
|
||||
totalOperations.add(increment);
|
||||
|
||||
long completedOps = totalOperations.longValue();
|
||||
double percent = Math.max(0, Math.min(100, (Math.pow(completedOps, 1.5) * 100 / Math.pow(estimatedOperations, 1.5))));
|
||||
double lastPercent = (this.lastPercent == 0 ? percent : this.lastPercent);
|
||||
percent = (percent + lastPercent * 19) / 20;
|
||||
if (increment != 0) this.lastPercent = percent;
|
||||
|
||||
double remaining = estimatedOperations - completedOps;
|
||||
long timeSpent = System.currentTimeMillis() - startTime;
|
||||
|
||||
double totalTime = Math.pow(estimatedOperations, 1.5) * 1000;
|
||||
double estimatedTimeSpent = Math.pow(completedOps, 1.5) * 1000;
|
||||
|
||||
double timeRemaining;
|
||||
if (completedOps > 32) {
|
||||
double timeRatio = (timeSpent * totalTime / estimatedTimeSpent);
|
||||
double lastTimeRatio = this.lastTimeRatio == 0 ? timeRatio : this.lastTimeRatio;
|
||||
timeRatio = (timeRatio + lastTimeRatio * 19) / 20;
|
||||
if (increment != 0) this.lastTimeRatio = timeRatio;
|
||||
timeRemaining = timeRatio - timeSpent;
|
||||
} else {
|
||||
timeRemaining = ((long) totalTime >> 5) - timeSpent;
|
||||
}
|
||||
String msg = MainUtil.secToTime((long) (timeRemaining / 1000));
|
||||
app.setProgress(msg, (int) percent);
|
||||
}
|
||||
|
||||
public synchronized void flush() throws IOException {
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
synchronized (batches) {
|
||||
progress(1);
|
||||
synchronized (MCAFile2LevelDB.this) {
|
||||
int count = pool.getParallelism();
|
||||
Iterator<Map.Entry<Thread, WriteBatch>> iter = batches.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<Thread, WriteBatch> entry = iter.next();
|
||||
@ -121,29 +176,20 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
db.write(batch);
|
||||
batch.close();
|
||||
iter.remove();
|
||||
progress(2);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
if (openDB) {
|
||||
Fawe.debug("Flushing changes, please wait");
|
||||
if (db != null) db.close();
|
||||
System.gc();
|
||||
System.gc();
|
||||
int bufferSize = (int) Math.min(Integer.MAX_VALUE, Math.max((long) (MemUtil.getFreeBytes() * 0.8), 134217728));
|
||||
this.db = Iq80DBFactory.factory.open(new File(folderTo, "db"),
|
||||
new Options()
|
||||
.createIfMissing(true)
|
||||
.verifyChecksums(false)
|
||||
.blockSize(262144) // 256K
|
||||
.cacheSize(8388608) // 8MB
|
||||
.writeBufferSize(536870912) // >=512MB
|
||||
);
|
||||
}
|
||||
System.gc();
|
||||
System.gc();
|
||||
progress(count * 2);
|
||||
}
|
||||
}
|
||||
|
||||
public DelegateMCAFilter<MutableLong> toFilter(final int dimension) {
|
||||
RemapFilter filter = new RemapFilter(ClipboardRemapper.RemapPlatform.PC, ClipboardRemapper.RemapPlatform.PE);
|
||||
filter.setDimension(dimension);
|
||||
|
||||
DelegateMCAFilter<MutableLong> delegate = new DelegateMCAFilter<MutableLong>(filter) {
|
||||
@Override
|
||||
public void finishFile(MCAFile file, MutableLong cache) {
|
||||
@ -158,6 +204,16 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
}
|
||||
});
|
||||
file.clear();
|
||||
|
||||
progress(1);
|
||||
submittedFiles.increment();
|
||||
if ((submittedFiles.longValue() & 7) == 0) {
|
||||
try {
|
||||
flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return delegate;
|
||||
@ -166,6 +222,7 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
|
||||
@Override
|
||||
public void accept(ConverterFrame app) {
|
||||
this.app = app;
|
||||
File levelDat = new File(folderFrom, "level.dat");
|
||||
if (levelDat.exists()) {
|
||||
try {
|
||||
@ -177,12 +234,34 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
|
||||
List<CompoundTag> portals = new ArrayList<>();
|
||||
String[] dimDirs = {"region", "DIM-1/region", "DIM1/region"};
|
||||
File[] regionFolders = new File[dimDirs.length];
|
||||
int totalFiles = 0;
|
||||
for (int dim = 0; dim < 3; dim++) {
|
||||
File source = new File(folderFrom, dimDirs[dim]);
|
||||
if (source.exists()) {
|
||||
regionFolders[dim] = source;
|
||||
totalFiles += source.listFiles().length;
|
||||
}
|
||||
}
|
||||
this.estimatedOperations = totalFiles + (totalFiles >> 3) + (totalFiles >> 3) * pool.getParallelism() * 2;
|
||||
|
||||
Thread progressThread = new Thread(() -> {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
progress(0);
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
progressThread.start();
|
||||
|
||||
for (int dim = 0; dim < regionFolders.length; dim++) {
|
||||
File source = regionFolders[dim];
|
||||
if (source != null) {
|
||||
DelegateMCAFilter filter = toFilter(dim);
|
||||
MCAQueue queue = new MCAQueue(null, source, true);
|
||||
|
||||
MCAFilter result = queue.filterWorld(filter);
|
||||
portals.addAll(((RemapFilter) filter.getFilter()).getPortals());
|
||||
}
|
||||
@ -201,11 +280,13 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
|
||||
|
||||
try {
|
||||
flush(false);
|
||||
flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
progressThread.interrupt();
|
||||
close();
|
||||
app.setProgress("Done", 0);
|
||||
app.prompt(
|
||||
"Conversion complete!\n" +
|
||||
" - The world save is still being compacted, but you can close the program anytime\n" +
|
||||
@ -223,7 +304,7 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
public synchronized void close() {
|
||||
try {
|
||||
if (closed == (closed = true)) return;
|
||||
Fawe.debug("Collecting threads");
|
||||
@ -238,7 +319,7 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
}
|
||||
}
|
||||
|
||||
public void compact() {
|
||||
public synchronized void compact() {
|
||||
// Since the library doesn't support it, only way to flush the cache is to loop over everything
|
||||
try (DB newDb = Iq80DBFactory.factory.open(new File(folderTo, "db"), new Options()
|
||||
.verifyChecksums(false)
|
||||
@ -315,8 +396,9 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
}
|
||||
|
||||
public void write(MCAChunk chunk, boolean remap, int dim) throws IOException {
|
||||
submitted.add(1);
|
||||
if ((submitted.longValue() & 1023) == 0) {
|
||||
submittedChunks.add(1);
|
||||
long numChunks = submittedChunks.longValue();
|
||||
if ((numChunks & 1023) == 0) {
|
||||
long queued = pool.getQueuedTaskCount() + pool.getQueuedSubmissionCount();
|
||||
if (queued > 127) {
|
||||
System.gc();
|
||||
@ -329,110 +411,106 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((submitted.longValue() & 8191) == 0) {
|
||||
boolean reopen = (submitted.longValue() & 65535) == 0;
|
||||
flush(reopen);
|
||||
}
|
||||
synchronized (MCAFile2LevelDB.this) {
|
||||
try {
|
||||
update(getKey(chunk, Tag.Version, dim), VERSION);
|
||||
update(getKey(chunk, Tag.FinalizedState, dim), COMPLETE_STATE);
|
||||
|
||||
ByteBuffer data2d = ByteBuffer.wrap(new byte[512 + 256]);
|
||||
int[] heightMap = chunk.getHeightMapArray();
|
||||
for (int i = 0; i < heightMap.length; i++) {
|
||||
data2d.putShort((short) heightMap[i]);
|
||||
}
|
||||
if (chunk.biomes != null) {
|
||||
System.arraycopy(chunk.biomes, 0, data2d.array(), 512, 256);
|
||||
}
|
||||
update(getKey(chunk, Tag.Data2D, dim), data2d.array());
|
||||
|
||||
if (!chunk.tiles.isEmpty()) {
|
||||
List<CompoundTag> tickList = null;
|
||||
List<com.sk89q.jnbt.Tag> tiles = new ArrayList<>();
|
||||
for (Map.Entry<Short, CompoundTag> entry : chunk.getTiles().entrySet()) {
|
||||
CompoundTag tag = entry.getValue();
|
||||
if (transform(chunk, tag) && time != 0l) {
|
||||
// Needs tick
|
||||
if (tickList == null) tickList = new ArrayList<>();
|
||||
|
||||
int x = tag.getInt("x");
|
||||
int y = tag.getInt("y");
|
||||
int z = tag.getInt("z");
|
||||
BaseBlock block = chunk.getBlock(x & 15, y, z & 15);
|
||||
|
||||
Map<String, com.sk89q.jnbt.Tag> tickable = new HashMap<>();
|
||||
tickable.put("tileID", new ByteTag((byte) block.getId()));
|
||||
tickable.put("x", new IntTag(x));
|
||||
tickable.put("y", new IntTag(y));
|
||||
tickable.put("z", new IntTag(z));
|
||||
tickable.put("time", new LongTag(1));
|
||||
tickList.add(new CompoundTag(tickable));
|
||||
}
|
||||
|
||||
tiles.add(tag);
|
||||
}
|
||||
update(getKey(chunk, Tag.BlockEntity, dim), write(tiles));
|
||||
|
||||
if (tickList != null) {
|
||||
HashMap<String, com.sk89q.jnbt.Tag> root = new HashMap<String, com.sk89q.jnbt.Tag>();
|
||||
root.put("tickList", new ListTag(CompoundTag.class, tickList));
|
||||
update(getKey(chunk, Tag.PendingTicks, dim), write(Arrays.asList(new CompoundTag(root))));
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunk.entities.isEmpty()) {
|
||||
List<com.sk89q.jnbt.Tag> entities = new ArrayList<>();
|
||||
for (CompoundTag tag : chunk.getEntities()) {
|
||||
transform(chunk, tag);
|
||||
entities.add(tag);
|
||||
}
|
||||
update(getKey(chunk, Tag.Entity, dim), write(entities));
|
||||
}
|
||||
|
||||
int maxLayer = chunk.ids.length - 1;
|
||||
while (maxLayer >= 0 && chunk.ids[maxLayer] == null) maxLayer--;
|
||||
if (maxLayer >= 0) {
|
||||
for (int layer = 0; layer <= maxLayer; layer++) {
|
||||
// Set layer
|
||||
byte[] key = getSectionKey(chunk, layer, dim);
|
||||
byte[] value = new byte[1 + 4096 + 2048 + 2048 + 2048];
|
||||
byte[] ids = chunk.ids[layer];
|
||||
if (ids == null) {
|
||||
Arrays.fill(value, (byte) 0);
|
||||
} else {
|
||||
byte[] data = chunk.data[layer];
|
||||
byte[] skyLight = chunk.skyLight[layer];
|
||||
byte[] blockLight = chunk.blockLight[layer];
|
||||
|
||||
if (remap) {
|
||||
copySection(ids, value, 1);
|
||||
copySection(data, value, 1 + 4096);
|
||||
copySection(skyLight, value, 1 + 4096 + 2048);
|
||||
copySection(blockLight, value, 1 + 4096 + 2048 + 2048);
|
||||
} else {
|
||||
System.arraycopy(ids, 0, value, 1, ids.length);
|
||||
System.arraycopy(data, 0, value, 1 + 4096, data.length);
|
||||
System.arraycopy(skyLight, 0, value, 1 + 4096 + 2048, skyLight.length);
|
||||
System.arraycopy(blockLight, 0, value, 1 + 4096 + 2048 + 2048, blockLight.length);
|
||||
}
|
||||
}
|
||||
update(key, value);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
pool.submit((Runnable) () -> {
|
||||
synchronized (Thread.currentThread()) {
|
||||
try {
|
||||
update(getKey(chunk, Tag.Version, dim), VERSION);
|
||||
update(getKey(chunk, Tag.FinalizedState, dim), COMPLETE_STATE);
|
||||
|
||||
ByteBuffer data2d = ByteBuffer.wrap(new byte[512 + 256]);
|
||||
int[] heightMap = chunk.getHeightMapArray();
|
||||
for (int i = 0; i < heightMap.length; i++) {
|
||||
data2d.putShort((short) heightMap[i]);
|
||||
}
|
||||
if (chunk.biomes != null) {
|
||||
System.arraycopy(chunk.biomes, 0, data2d.array(), 512, 256);
|
||||
}
|
||||
update(getKey(chunk, Tag.Data2D, dim), data2d.array());
|
||||
|
||||
if (!chunk.tiles.isEmpty()) {
|
||||
List<CompoundTag> tickList = null;
|
||||
List<com.sk89q.jnbt.Tag> tiles = new ArrayList<>();
|
||||
for (Map.Entry<Short, CompoundTag> entry : chunk.getTiles().entrySet()) {
|
||||
CompoundTag tag = entry.getValue();
|
||||
if (transform(chunk, tag) && time != 0l) {
|
||||
// Needs tick
|
||||
if (tickList == null) tickList = new ArrayList<>();
|
||||
|
||||
int x = tag.getInt("x");
|
||||
int y = tag.getInt("y");
|
||||
int z = tag.getInt("z");
|
||||
BaseBlock block = chunk.getBlock(x & 15, y, z & 15);
|
||||
|
||||
Map<String, com.sk89q.jnbt.Tag> tickable = new HashMap<>();
|
||||
tickable.put("tileID", new ByteTag((byte) block.getId()));
|
||||
tickable.put("x", new IntTag(x));
|
||||
tickable.put("y", new IntTag(y));
|
||||
tickable.put("z", new IntTag(z));
|
||||
tickable.put("time", new LongTag(1));
|
||||
tickList.add(new CompoundTag(tickable));
|
||||
}
|
||||
|
||||
tiles.add(tag);
|
||||
}
|
||||
update(getKey(chunk, Tag.BlockEntity, dim), write(tiles));
|
||||
|
||||
if (tickList != null) {
|
||||
HashMap<String, com.sk89q.jnbt.Tag> root = new HashMap<String, com.sk89q.jnbt.Tag>();
|
||||
root.put("tickList", new ListTag(CompoundTag.class, tickList));
|
||||
update(getKey(chunk, Tag.PendingTicks, dim), write(Arrays.asList(new CompoundTag(root))));
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunk.entities.isEmpty()) {
|
||||
List<com.sk89q.jnbt.Tag> entities = new ArrayList<>();
|
||||
for (CompoundTag tag : chunk.getEntities()) {
|
||||
transform(chunk, tag);
|
||||
entities.add(tag);
|
||||
}
|
||||
update(getKey(chunk, Tag.Entity, dim), write(entities));
|
||||
}
|
||||
|
||||
int maxLayer = chunk.ids.length - 1;
|
||||
while (maxLayer >= 0 && chunk.ids[maxLayer] == null) maxLayer--;
|
||||
if (maxLayer >= 0) {
|
||||
for (int layer = maxLayer; layer >= 0; layer--) {
|
||||
// Set layer
|
||||
byte[] key = getSectionKey(chunk, layer, dim);
|
||||
byte[] value = new byte[1 + 4096 + 2048 + 2048 + 2048];
|
||||
byte[] ids = chunk.ids[layer];
|
||||
if (ids == null) {
|
||||
Arrays.fill(value, (byte) 0);
|
||||
} else {
|
||||
byte[] data = chunk.data[layer];
|
||||
byte[] skyLight = chunk.skyLight[layer];
|
||||
byte[] blockLight = chunk.blockLight[layer];
|
||||
|
||||
if (remap) {
|
||||
copySection(ids, value, 1);
|
||||
copySection(data, value, 1 + 4096);
|
||||
copySection(skyLight, value, 1 + 4096 + 2048);
|
||||
copySection(blockLight, value, 1 + 4096 + 2048 + 2048);
|
||||
} else {
|
||||
System.arraycopy(ids, 0, value, 1, ids.length);
|
||||
System.arraycopy(data, 0, value, 1 + 4096, data.length);
|
||||
System.arraycopy(skyLight, 0, value, 1 + 4096 + 2048, skyLight.length);
|
||||
System.arraycopy(blockLight, 0, value, 1 + 4096 + 2048 + 2048, blockLight.length);
|
||||
}
|
||||
}
|
||||
update(key, value);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void update(byte[] key, byte[] value) {
|
||||
WriteBatch batch = batches.get(Thread.currentThread());
|
||||
batch.put(key, value);
|
||||
synchronized (Thread.currentThread()) {
|
||||
WriteBatch batch = batches.get(Thread.currentThread());
|
||||
batch.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void copySection(byte[] src, byte[] dest, int destPos) {
|
||||
@ -541,6 +619,9 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
Map<String, com.sk89q.jnbt.Tag> 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));
|
||||
}
|
||||
{ // Convert items
|
||||
com.sk89q.jnbt.ListTag items = tag.getListTag("Items");
|
||||
((List<CompoundTag>) (List) items.getValue()).forEach(this::transformItem);
|
||||
@ -555,13 +636,21 @@ public class MCAFile2LevelDB extends MapConverter {
|
||||
}
|
||||
}
|
||||
{ // Health
|
||||
com.sk89q.jnbt.Tag health = map.get("Health");
|
||||
if (health != null && health instanceof FloatTag) {
|
||||
map.put("Health", new ShortTag((short) tag.getFloat("Health")));
|
||||
com.sk89q.jnbt.Tag tVal = map.get("Health");
|
||||
if (tVal != null) {
|
||||
short newVal = ((Number) tVal.getValue()).shortValue();
|
||||
map.put("Health", new ShortTag((short) (newVal * 2)));
|
||||
}
|
||||
}
|
||||
for (String key : new String[] {"Age", "Health"}) {
|
||||
com.sk89q.jnbt.Tag tVal = map.get(key);
|
||||
if (tVal != null) {
|
||||
short newVal = ((Number) tVal.getValue()).shortValue();
|
||||
map.put(key, new ShortTag(newVal));
|
||||
}
|
||||
}
|
||||
{ // Orientation / Position
|
||||
for (String key : new String[] {"Orientation", "Position"}) {
|
||||
for (String key : new String[] {"Orientation", "Position", "Rotation", "Pos", "Motion"}) {
|
||||
ListTag list = (ListTag) map.get(key);
|
||||
if (list != null) {
|
||||
List<com.sk89q.jnbt.Tag> value = list.getValue();
|
||||
|
Loading…
Reference in New Issue
Block a user