mirror of
https://github.com/zedoCN/NBTUtils.git
synced 2025-05-14 11:09:56 +08:00
del
This commit is contained in:
parent
c72e17b4ac
commit
f91165ca6d
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="java" level="project" />
|
||||
<orderEntry type="library" name="obj-0.3.0" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -1 +0,0 @@
|
||||
|
@ -1,240 +0,0 @@
|
||||
package main.Utils;
|
||||
|
||||
import com.sun.jdi.ByteValue;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class BytesUtils {
|
||||
|
||||
public static String bytes2fStr(byte[] data) {
|
||||
String result = "";
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
result += Integer.toHexString((data[i] & 0xFF) | 0x100).toUpperCase().substring(1, 3) + " ";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static short bytes2short(byte[] res) {
|
||||
short ret = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (i < res.length)
|
||||
ret |= (short) (res[i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int bytes2int(byte[] res) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i < res.length)
|
||||
ret |= (res[i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static long bytes2long(byte[] res) {
|
||||
long ret = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i < res.length)
|
||||
ret |= (long) (res[i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static float bytes2float(byte[] res) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ret |= (res[i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return Float.intBitsToFloat(ret);
|
||||
}
|
||||
|
||||
public static double bytes2double(byte[] res) {
|
||||
long ret = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ret |= (long) (res[i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return Double.longBitsToDouble(ret);
|
||||
}
|
||||
|
||||
public static byte byte2byteA(byte res) {
|
||||
BitSet ret = new BitSet(8);
|
||||
BitSet resb = BitSet.valueOf(new byte[]{res});
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ret.set(i, resb.get(7 - i));
|
||||
}
|
||||
if (ret.length() == 0)
|
||||
return -128;
|
||||
return ret.toByteArray()[0];
|
||||
}
|
||||
|
||||
public static byte[] bytes2bytesA(byte[] res) {
|
||||
byte[] ret = new byte[res.length];
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
ret[i] = byte2byteA(res[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static short bytes2shortA(byte[] res) {
|
||||
short ret = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ret |= (short) (res[1 - i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] bytesCut(byte[] res, int pos,int destPos, int destLen) {
|
||||
byte[] ret = new byte[destLen];
|
||||
System.arraycopy(res, pos, ret, destPos, destLen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] bytesSplicing(byte[] a, byte[] b) {
|
||||
byte[] ret = new byte[a.length + b.length];
|
||||
System.arraycopy(a, 0, ret, 0, a.length);
|
||||
System.arraycopy(b, 0, ret, a.length, b.length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int bytes2intA(byte[] res) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (3 - i < res.length)
|
||||
ret |= (res[3 - i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static long bytes2longA(byte[] res) {
|
||||
long ret = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (7 - i < res.length)
|
||||
ret |= (long) (res[7 - i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static float bytes2floatA(byte[] res) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ret |= (res[3 - i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return Float.intBitsToFloat(ret);
|
||||
}
|
||||
|
||||
public static double bytes2doubleA(byte[] res) {
|
||||
long ret = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ret |= (long) (res[7 - i] & 0xFF) << (i * 8);
|
||||
}
|
||||
return Double.longBitsToDouble(ret);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] longs2bytesA(long[] res) {
|
||||
byte[] ret = new byte[res.length * 8];
|
||||
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
|
||||
for (int j = 0; j < 8; j++) {//字节
|
||||
ret[j + i * 8] = long2bytes(res[i])[7 - j];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public static byte[] short2bytes(short res) {
|
||||
byte[] ret = new byte[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int offset = 16 - (i + 1) * 8;
|
||||
ret[i] = (byte) ((res >> offset) & 0xff);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] int2bytes(int res) {
|
||||
byte[] ret = new byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int offset = 32 - (i + 1) * 8;
|
||||
ret[i] = (byte) ((res >> offset) & 0xff);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] long2bytes(long res) {
|
||||
byte[] ret = new byte[8];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int offset = 64 - (i + 1) * 8;
|
||||
ret[i] = (byte) ((res >> offset) & 0xff);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] float2bytes(float res) {
|
||||
return int2bytes(Float.floatToIntBits(res));
|
||||
}
|
||||
|
||||
public static byte[] short2bytesA(short res) {
|
||||
byte[] buffer = new byte[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int offset = 16 - (1 - i + 1) * 8;
|
||||
buffer[i] = (byte) ((res >> offset) & 0xff);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] int2bytesA(int res) {
|
||||
byte[] buffer = new byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int offset = 32 - (3 - i + 1) * 8;
|
||||
buffer[i] = (byte) ((res >> offset) & 0xff);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] long2bytesA(long res) {
|
||||
byte[] buffer = new byte[8];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int offset = 64 - (7 - i + 1) * 8;
|
||||
buffer[i] = (byte) ((res >> offset) & 0xff);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] double2bytes(double res) {
|
||||
return long2bytes(Double.doubleToLongBits(res));
|
||||
}
|
||||
|
||||
public static byte[] float2bytesA(float res) {
|
||||
return int2bytesA(Float.floatToIntBits(res));
|
||||
}
|
||||
|
||||
public static byte[] double2bytesA(double res) {
|
||||
return long2bytesA(Double.doubleToLongBits(res));
|
||||
}
|
||||
|
||||
|
||||
public static BitSet bytes2bits(byte[] res) {
|
||||
BitSet ret = new BitSet(res.length * 8);
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
ret.set(i * 8 + j, ((res[i] >> j) & 0x01) == 1);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static BitSet bytes2bitsA(byte[] res) {
|
||||
BitSet ret = new BitSet(res.length * 8);
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
ret.set(res.length * 8 - i * 8 - j - 1, ((res[i] >> j) & 0x01) == 1);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package main.Utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public abstract class CompressUtils {
|
||||
//Zlib压缩
|
||||
public static byte[] zlibCompress(byte[] data) throws IOException {
|
||||
byte[] output = new byte[0];
|
||||
|
||||
Deflater compresser = new Deflater();
|
||||
|
||||
compresser.reset();
|
||||
compresser.setInput(data);
|
||||
compresser.finish();
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
|
||||
byte[] buf = new byte[1024];
|
||||
while (!compresser.finished()) {
|
||||
int i = compresser.deflate(buf);
|
||||
bos.write(buf, 0, i);
|
||||
}
|
||||
output = bos.toByteArray();
|
||||
bos.close();
|
||||
compresser.end();
|
||||
return output;
|
||||
}
|
||||
|
||||
//Zlib解压
|
||||
public static byte[] zlibDecompress(byte[] data) throws IOException, DataFormatException {
|
||||
|
||||
|
||||
Inflater decompresser = new Inflater();
|
||||
decompresser.reset();
|
||||
decompresser.setInput(data);
|
||||
|
||||
ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
while (!decompresser.finished()) {
|
||||
int i = decompresser.inflate(buf);
|
||||
o.write(buf, 0, i);
|
||||
}
|
||||
byte[] output = o.toByteArray();
|
||||
o.close();
|
||||
decompresser.end();
|
||||
return output;
|
||||
}
|
||||
|
||||
//Gzip压缩
|
||||
public static byte[] gzipCompress(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzipOutputStream =new GZIPOutputStream(byteArrayOutputStream);
|
||||
gzipOutputStream.write(data);
|
||||
gzipOutputStream.close();
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
//Gzip解压
|
||||
public static byte[] gzipDecompress(byte[] data) throws IOException {
|
||||
GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(data));
|
||||
byte[] output = gzipInputStream.readAllBytes();
|
||||
gzipInputStream.close();
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package main.exception;
|
||||
|
||||
public class NBTException extends RuntimeException {
|
||||
public NBTException(String message) {
|
||||
super(message);
|
||||
System.out.println(message);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
// fast valid
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,531 +0,0 @@
|
||||
package main.io;
|
||||
|
||||
import main.Utils.BytesUtils;
|
||||
import main.Utils.CompressUtils;
|
||||
import main.exception.NBTException;
|
||||
import main.mc.MCA;
|
||||
import main.mc.MCPosInt;
|
||||
import main.nbt.CompoundTag;
|
||||
import main.nbt.ListTag;
|
||||
import main.nbt.TagType;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
public class MCUtil {
|
||||
/**
|
||||
* 解析NBT
|
||||
*
|
||||
* @param nbt NBT数据
|
||||
* @return 复合标签
|
||||
* @throws IOException
|
||||
*/
|
||||
public static CompoundTag parseNBT(byte[] nbt) throws IOException {
|
||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(nbt);
|
||||
CompoundTag compoundTag = parseCompoundTag(byteArrayInputStream);
|
||||
byteArrayInputStream.close();
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算方块列表大小所占存储的位大小
|
||||
*
|
||||
* @param blockListSize 方块列表大小
|
||||
* @return 存储的位大小
|
||||
*/
|
||||
public static int getMapBitSize(int blockListSize) {
|
||||
blockListSize--;
|
||||
int count = 0;
|
||||
while (blockListSize != 0) {
|
||||
count++;
|
||||
blockListSize >>= 1;
|
||||
}
|
||||
return (count < 4 ? 4 : count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析复合标签
|
||||
*
|
||||
* @param in 输入流
|
||||
* @return 复合标签
|
||||
* @throws IOException
|
||||
*/
|
||||
private static CompoundTag parseCompoundTag(InputStream in) throws IOException {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
|
||||
|
||||
while (true) {
|
||||
//读取标签类型
|
||||
short tagType = BytesUtils.bytes2short(in.readNBytes(1));
|
||||
//判断是否结束
|
||||
if (tagType == TagType.TAG_End) {
|
||||
return nbt;
|
||||
}
|
||||
|
||||
//读取标签名
|
||||
String tagName = new String(in.readNBytes(BytesUtils.bytes2shortA(in.readNBytes(2))));
|
||||
|
||||
if (tagType == TagType.TAG_Byte) {
|
||||
nbt.setTag(tagName, in.readNBytes(1)[0]);
|
||||
} else if (tagType == TagType.TAG_Short) {
|
||||
nbt.setTag(tagName, BytesUtils.bytes2shortA(in.readNBytes(2)));
|
||||
} else if (tagType == TagType.TAG_Int) {
|
||||
nbt.setTag(tagName, BytesUtils.bytes2intA(in.readNBytes(4)));
|
||||
} else if (tagType == TagType.TAG_Long) {
|
||||
nbt.setTag(tagName, BytesUtils.bytes2longA(in.readNBytes(8)));
|
||||
} else if (tagType == TagType.TAG_Float) {
|
||||
nbt.setTag(tagName, BytesUtils.bytes2floatA(in.readNBytes(4)));
|
||||
} else if (tagType == TagType.TAG_Double) {
|
||||
nbt.setTag(tagName, BytesUtils.bytes2doubleA(in.readNBytes(8)));
|
||||
} else if (tagType == TagType.TAG_Byte_Array) {
|
||||
nbt.setTag(tagName, in.readNBytes(BytesUtils.bytes2intA(in.readNBytes(4))));
|
||||
} else if (tagType == TagType.TAG_String) {
|
||||
nbt.setTag(tagName, new String(in.readNBytes(BytesUtils.bytes2shortA(in.readNBytes(2)))));
|
||||
} else if (tagType == TagType.TAG_List) {
|
||||
nbt.setListTag(tagName, parseListTag(in));
|
||||
} else if (tagType == TagType.TAG_Compound) {
|
||||
nbt.setCompoundTag(tagName, parseCompoundTag(in));
|
||||
} else if (tagType == TagType.TAG_Int_Array) {
|
||||
int arraySize = BytesUtils.bytes2intA(in.readNBytes(4));//读取数组个数
|
||||
int[] intdata = new int[arraySize];
|
||||
for (int j = 0; j < arraySize; j++) {
|
||||
intdata[j] = BytesUtils.bytes2intA(in.readNBytes(4));
|
||||
}
|
||||
nbt.setTag(tagName, intdata);
|
||||
} else if (tagType == TagType.TAG_Long_Array) {
|
||||
int arraySize = BytesUtils.bytes2intA(in.readNBytes(4));//读取数组个数
|
||||
long[] intdata = new long[arraySize];
|
||||
for (int j = 0; j < arraySize; j++) {
|
||||
intdata[j] = BytesUtils.bytes2longA(in.readNBytes(8));
|
||||
}
|
||||
nbt.setTag(tagName, intdata);
|
||||
} else if (tagType == TagType.TAG_End) {
|
||||
return nbt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析列表标签
|
||||
*
|
||||
* @param in 输入流
|
||||
* @return 列表标签
|
||||
* @throws IOException
|
||||
*/
|
||||
private static ListTag parseListTag(InputStream in) throws IOException {
|
||||
|
||||
//读取列表类型
|
||||
short ListTagType = BytesUtils.bytes2short(in.readNBytes(1));
|
||||
//创建新列表
|
||||
ListTag nbtList = new ListTag(ListTagType);
|
||||
//获取列表成员数
|
||||
int listSize = BytesUtils.bytes2intA(in.readNBytes(4));
|
||||
//遍历所有成员
|
||||
for (int i = 0; i < listSize; i++) {
|
||||
if (ListTagType == TagType.TAG_Byte) {
|
||||
nbtList.addTag(in.readNBytes(1)[0]);
|
||||
} else if (ListTagType == TagType.TAG_Short) {
|
||||
nbtList.addTag(BytesUtils.bytes2shortA(in.readNBytes(2)));
|
||||
} else if (ListTagType == TagType.TAG_Int) {
|
||||
nbtList.addTag(BytesUtils.bytes2intA(in.readNBytes(4)));
|
||||
} else if (ListTagType == TagType.TAG_Long) {
|
||||
nbtList.addTag(BytesUtils.bytes2longA(in.readNBytes(8)));
|
||||
} else if (ListTagType == TagType.TAG_Float) {
|
||||
nbtList.addTag(BytesUtils.bytes2floatA(in.readNBytes(4)));
|
||||
} else if (ListTagType == TagType.TAG_Double) {
|
||||
nbtList.addTag(BytesUtils.bytes2doubleA(in.readNBytes(8)));
|
||||
} else if (ListTagType == TagType.TAG_Byte_Array) {
|
||||
nbtList.addTag(in.readNBytes(BytesUtils.bytes2intA(in.readNBytes(4))));
|
||||
} else if (ListTagType == TagType.TAG_String) {
|
||||
nbtList.addTag(new String(in.readNBytes(BytesUtils.bytes2shortA(in.readNBytes(2)))));
|
||||
} else if (ListTagType == TagType.TAG_List) {
|
||||
nbtList.addTag(parseListTag(in));
|
||||
} else if (ListTagType == TagType.TAG_Compound) {
|
||||
nbtList.addTag(parseCompoundTag(in));
|
||||
} else if (ListTagType == TagType.TAG_Int_Array) {
|
||||
int arraySize = BytesUtils.bytes2intA(in.readNBytes(4));//读取数组个数
|
||||
int[] intdata = new int[arraySize];
|
||||
for (int j = 0; j < arraySize; j++) {
|
||||
intdata[j] = BytesUtils.bytes2intA(in.readNBytes(4));
|
||||
}
|
||||
nbtList.addTag(intdata);
|
||||
} else if (ListTagType == TagType.TAG_Long_Array) {
|
||||
int arraySize = BytesUtils.bytes2intA(in.readNBytes(4));//读取数组个数
|
||||
long[] longdata = new long[arraySize];
|
||||
for (int j = 0; j < arraySize; j++) {
|
||||
longdata[j] = BytesUtils.bytes2longA(in.readNBytes(8));
|
||||
}
|
||||
nbtList.addTag(longdata);
|
||||
} else {
|
||||
throw new NBTException("ListTag处理异常");
|
||||
}
|
||||
}
|
||||
|
||||
return nbtList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写标签
|
||||
*
|
||||
* @param nbt 标签
|
||||
* @param out 输出流
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void writeNBT(CompoundTag nbt, OutputStream out) throws IOException {
|
||||
writeCompoundTag(nbt, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写复合标签
|
||||
*
|
||||
* @param nbt 复合标签
|
||||
* @param out 输出流
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void writeCompoundTag(CompoundTag nbt, OutputStream out) throws IOException {
|
||||
|
||||
|
||||
Iterator<Map.Entry<String, Object>> integer = nbt.entrySet().iterator();
|
||||
while (integer.hasNext()) {
|
||||
Map.Entry<String, Object> tag = integer.next();
|
||||
short tagType = TagType.Object2TagType(tag.getValue());
|
||||
//判断标签类型
|
||||
if (tagType == -1) {
|
||||
throw new NBTException("错误的标签类型");
|
||||
}
|
||||
|
||||
out.write(tagType);//写标签类型
|
||||
out.write(BytesUtils.short2bytes((short) tag.getKey().getBytes().length));//标签名长度
|
||||
out.write(tag.getKey().getBytes());
|
||||
|
||||
|
||||
writeTag(tagType, tag.getValue(), out);
|
||||
|
||||
}
|
||||
|
||||
//out.write(TagType.TAG_End);//复合标签尾
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出标签
|
||||
*
|
||||
* @param tagType 标签类型
|
||||
* @param object 标签对象
|
||||
* @param out 输出流
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void writeTag(short tagType, Object object, OutputStream out) throws IOException {
|
||||
if (tagType == TagType.TAG_Byte) {
|
||||
out.write((byte) object);
|
||||
} else if (tagType == TagType.TAG_Short) {
|
||||
out.write(BytesUtils.short2bytes((short) object));
|
||||
} else if (tagType == TagType.TAG_Int) {
|
||||
out.write(BytesUtils.int2bytes((int) object));
|
||||
} else if (tagType == TagType.TAG_Long) {
|
||||
out.write(BytesUtils.long2bytes((long) object));
|
||||
} else if (tagType == TagType.TAG_Float) {
|
||||
out.write(BytesUtils.float2bytes((float) object));
|
||||
} else if (tagType == TagType.TAG_Double) {
|
||||
out.write(BytesUtils.double2bytes((double) object));
|
||||
} else if (tagType == TagType.TAG_Byte_Array) {
|
||||
out.write(BytesUtils.int2bytes(((byte[]) object).length));
|
||||
out.write((byte[]) object);
|
||||
} else if (tagType == TagType.TAG_String) {
|
||||
out.write(BytesUtils.short2bytes((short) ((String) object).getBytes().length));
|
||||
out.write(((String) object).getBytes());
|
||||
} else if (tagType == TagType.TAG_List) {
|
||||
writeListTag((ListTag) object, out);
|
||||
} else if (tagType == TagType.TAG_Compound) {
|
||||
writeCompoundTag((CompoundTag) object, out);
|
||||
out.write(0);
|
||||
} else if (tagType == TagType.TAG_Int_Array) {
|
||||
out.write(BytesUtils.int2bytes(((int[]) object).length));
|
||||
for (int ints : (int[]) object) {
|
||||
out.write(BytesUtils.int2bytes(ints));
|
||||
}
|
||||
} else if (tagType == TagType.TAG_Long_Array) {
|
||||
out.write(BytesUtils.int2bytes(((long[]) object).length));
|
||||
for (long longs : (long[]) object) {
|
||||
out.write(BytesUtils.long2bytes(longs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出列表标签
|
||||
*
|
||||
* @param nbt 列表标签
|
||||
* @param out 输出流
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void writeListTag(ListTag nbt, OutputStream out) throws IOException {
|
||||
short ListTagType = nbt.type;
|
||||
|
||||
/*out.write(TagType.TAG_List);//写标签类型
|
||||
out.write(BytesUtils.short2bytes((short) nbt.Name.getBytes().length));//标签名长度
|
||||
out.write(nbt.Name.getBytes());*/
|
||||
|
||||
|
||||
out.write(ListTagType);//写列表类型
|
||||
out.write(BytesUtils.int2bytes(nbt.size()));//写列表大小
|
||||
for (int i = 0; i < nbt.size(); i++) {
|
||||
Object object = nbt.get(i);
|
||||
writeTag(ListTagType, object, out);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取Dat文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 读取的复合标签
|
||||
* @throws IOException
|
||||
*/
|
||||
public static CompoundTag readDATFile(File filePath) throws IOException {
|
||||
|
||||
FileInputStream fileInputStream = new FileInputStream(filePath);
|
||||
CompoundTag tag = parseNBT(CompressUtils.gzipDecompress(fileInputStream.readAllBytes()));
|
||||
fileInputStream.close();
|
||||
return tag;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出Dat文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param compoundTag 复合标签
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void writeDATFile(File filePath, CompoundTag compoundTag) throws IOException {
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(filePath, false);
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
writeNBT(compoundTag, byteArrayOutputStream);
|
||||
fileOutputStream.write(CompressUtils.gzipCompress(byteArrayOutputStream.toByteArray()));
|
||||
byteArrayOutputStream.close();
|
||||
fileOutputStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取MCA文件 mca坐标
|
||||
*
|
||||
* @param path mca文件夹路径
|
||||
* @param mcaPos mca文件位置
|
||||
* @return mca对象
|
||||
* @throws IOException
|
||||
*/
|
||||
public static MCA readMCAFile(File path, MCPosInt mcaPos) throws IOException {
|
||||
MCA mca = new MCA();
|
||||
mca.Pos = mcaPos.clone();
|
||||
File mcaFile = new File(path.getPath() + "\\r." + mcaPos.x + "." + mcaPos.z + ".mca");
|
||||
if (!mcaFile.isFile()) {
|
||||
mcaFile.createNewFile();
|
||||
}
|
||||
|
||||
RandomAccessFile randomAccessFile = new RandomAccessFile(mcaFile, "r");
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
//顺序读取区块索引表
|
||||
randomAccessFile.seek(i * 4);
|
||||
//读取区块偏移
|
||||
int chunkPosOffset = BytesUtils.bytes2intA(BytesUtils.bytesSplicing(new byte[1], RandomAccessFileReadBytes(randomAccessFile, 3)));
|
||||
if (chunkPosOffset == 0) {
|
||||
//区块还未生成
|
||||
continue;
|
||||
}
|
||||
|
||||
//区块数据段大小
|
||||
byte chunkSectionSize = randomAccessFile.readByte();
|
||||
|
||||
|
||||
//跳转区块数据区
|
||||
randomAccessFile.seek(chunkPosOffset * 4096);
|
||||
|
||||
int chunkSize = randomAccessFile.readInt();
|
||||
byte compressType = randomAccessFile.readByte();
|
||||
byte[] chunkData = new byte[chunkSize];
|
||||
randomAccessFile.read(chunkData);
|
||||
if (compressType == 1) {//GZip压缩
|
||||
mca.chunksNBT[i] = MCUtil.parseNBT(CompressUtils.gzipDecompress(chunkData));
|
||||
} else if (compressType == 2) {//ZLib压缩
|
||||
try {
|
||||
mca.chunksNBT[i] = (MCUtil.parseNBT(CompressUtils.zlibDecompress(chunkData)));
|
||||
} catch (DataFormatException e) {
|
||||
throw new NBTException("ZLIB解压失败");
|
||||
}
|
||||
} else if (compressType == 3) {//未压缩
|
||||
mca.chunksNBT[i] = (MCUtil.parseNBT(chunkData));
|
||||
} else {
|
||||
System.out.println("未知压缩类型:" + String.valueOf(compressType));
|
||||
//throw new NBTException("未知压缩类型:" + String.valueOf(compressType));
|
||||
}
|
||||
}
|
||||
randomAccessFile.close();
|
||||
|
||||
return mca;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出MCA文件 全部修改
|
||||
*
|
||||
* @param mca mca对象
|
||||
* @param path mca文件夹路径
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void writeMCAFile(MCA mca, File path) throws IOException {
|
||||
|
||||
RandomAccessFile randomAccessFile = new RandomAccessFile(
|
||||
new File(path.getPath() + "\\r." + mca.Pos.x + "." + mca.Pos.z + ".mca"), "rw");
|
||||
|
||||
|
||||
randomAccessFile.setLength(0);//清除所有
|
||||
|
||||
|
||||
long time = System.currentTimeMillis();//生成新时间戳
|
||||
|
||||
//数据区写区块
|
||||
int chunksCount = 2;
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
if (mca.chunksNBT[i] != null) {
|
||||
//写区块数据
|
||||
randomAccessFile.seek(chunksCount * 4096);
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
MCUtil.writeNBT(mca.chunksNBT[i], byteArrayOutputStream);
|
||||
byte[] NBTData = CompressUtils.zlibCompress(byteArrayOutputStream.toByteArray());
|
||||
byteArrayOutputStream.close();
|
||||
randomAccessFile.writeInt(NBTData.length);
|
||||
randomAccessFile.write(2);
|
||||
randomAccessFile.write(NBTData);
|
||||
|
||||
|
||||
//写区块时间戳
|
||||
randomAccessFile.seek(i * 4 + 4096);
|
||||
randomAccessFile.writeInt((int) time);
|
||||
|
||||
//写区块位置
|
||||
randomAccessFile.seek(i * 4);
|
||||
randomAccessFile.write(BytesUtils.bytesCut(BytesUtils.int2bytes(chunksCount), 1, 0, 3));
|
||||
randomAccessFile.write((int) Math.ceil(NBTData.length / 4096.0));
|
||||
|
||||
chunksCount += (int) Math.ceil(NBTData.length / 4096.0);
|
||||
|
||||
//mca.chunkLocation.put(chunksCount, (byte) Math.ceil(NBTData.length / 4096.0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
randomAccessFile.seek(8191 + chunksCount * 4096);
|
||||
randomAccessFile.write(0);
|
||||
randomAccessFile.close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出MCA文件 局部修改
|
||||
*
|
||||
* @param mca mca对象
|
||||
* @param path mca文件夹路径
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void writeMCAFile2(MCA mca, File path) throws IOException {
|
||||
RandomAccessFile randomAccessFile = new RandomAccessFile(
|
||||
new File(path.getPath() + "\\r." + mca.Pos.x + "." + mca.Pos.z + ".mca"), "rw");
|
||||
if (randomAccessFile.length() == 0)
|
||||
randomAccessFile.setLength(8192);
|
||||
|
||||
long time = System.currentTimeMillis();//生成新时间戳
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
if (mca.chunksFlag[i]) {//如果被标记 重写新数据
|
||||
//读取区块信息表
|
||||
randomAccessFile.seek(i * 4);
|
||||
int chunkPosOffset;
|
||||
chunkPosOffset = BytesUtils.bytes2intA(BytesUtils.bytesSplicing(new byte[1], RandomAccessFileReadBytes(randomAccessFile, 3)));
|
||||
//区块数据段大小
|
||||
byte chunkSectionSize = randomAccessFile.readByte();
|
||||
|
||||
/*if (chunkPosOffset == 0) {//未找到区块
|
||||
//MCUtil.writeMCAFile(mca,path);
|
||||
//throw new NBTException("保存时 未找到区块");
|
||||
chunkSectionSize = -1;
|
||||
}*/
|
||||
|
||||
//生成新区块数据
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
MCUtil.writeNBT(mca.chunksNBT[i], byteArrayOutputStream);
|
||||
byte[] newChunkData = CompressUtils.zlibCompress(byteArrayOutputStream.toByteArray());
|
||||
byteArrayOutputStream.close();
|
||||
|
||||
//计算新区块数据所占段数
|
||||
byte newChunkSectionSize = (byte) Math.ceil(newChunkData.length / 4096.0);
|
||||
|
||||
//判断大小
|
||||
if (chunkSectionSize < newChunkSectionSize) {
|
||||
//System.out.println("遇到增容");
|
||||
//比原先大 查找最大偏移
|
||||
int maxChunkOffset = 0;
|
||||
byte maxChunkSectionSize = 0;
|
||||
int maxChunkIndex = 0;
|
||||
for (int j = 0; j < 1024; j++) {//找到最后面位置
|
||||
//读取区块信息表
|
||||
randomAccessFile.seek(j * 4);
|
||||
int maxChunkPosOffset = BytesUtils.bytes2intA(BytesUtils.bytesSplicing(new byte[1], RandomAccessFileReadBytes(randomAccessFile, 3)));
|
||||
if (maxChunkPosOffset == 0) {
|
||||
continue;
|
||||
}
|
||||
if (maxChunkOffset < maxChunkPosOffset) {
|
||||
maxChunkOffset = maxChunkPosOffset;
|
||||
maxChunkIndex = j;
|
||||
//区块数据段大小
|
||||
maxChunkSectionSize = randomAccessFile.readByte();
|
||||
}
|
||||
|
||||
}
|
||||
chunkPosOffset = maxChunkOffset + maxChunkSectionSize;//设置最后面的偏移
|
||||
}
|
||||
|
||||
if (chunkPosOffset == 0) {
|
||||
chunkPosOffset = 2;
|
||||
}
|
||||
|
||||
//写区块数据
|
||||
randomAccessFile.seek(chunkPosOffset * 4096);
|
||||
|
||||
randomAccessFile.writeInt(newChunkData.length);
|
||||
randomAccessFile.write(2);
|
||||
randomAccessFile.write(newChunkData);
|
||||
|
||||
|
||||
//写区块时间戳
|
||||
randomAccessFile.seek(i * 4 + 4096);
|
||||
randomAccessFile.writeInt((int) time);
|
||||
|
||||
//写区块信息
|
||||
randomAccessFile.seek(i * 4);
|
||||
randomAccessFile.write(BytesUtils.bytesCut(BytesUtils.int2bytes(chunkPosOffset), 1, 0, 3));
|
||||
randomAccessFile.write(newChunkSectionSize);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RandomAccessFile 读取N个字节
|
||||
*
|
||||
* @param randomAccessFile RandomAccessFile对象
|
||||
* @param lenth 欲读取的字节长度
|
||||
* @return 读取的字节数组
|
||||
* @throws IOException
|
||||
*/
|
||||
private static byte[] RandomAccessFileReadBytes(RandomAccessFile randomAccessFile, int lenth) throws IOException {
|
||||
byte[] data = new byte[lenth];
|
||||
randomAccessFile.read(data);
|
||||
return data;
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.exception.NBTException;
|
||||
import main.nbt.CompoundTag;
|
||||
import main.nbt.ListTag;
|
||||
import main.nbt.TagType;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class MCA {
|
||||
public MCPosInt Pos;//当前MCA所在位置
|
||||
public long[] chunkTimeStamp = new long[1024];//时间戳
|
||||
public CompoundTag[] chunksNBT = new CompoundTag[1024];//区块数据
|
||||
public boolean[] chunksFlag = new boolean[1024];//被读取或修改过的标记
|
||||
|
||||
/**
|
||||
* 获取相对区块
|
||||
*
|
||||
* @param chunkIndex 区块索引
|
||||
* @return 区块对象
|
||||
*/
|
||||
public MCChunk getChunk(int chunkIndex) {
|
||||
if (chunksNBT[chunkIndex] == null)
|
||||
throw new NBTException("区块为空:" + chunkIndex);
|
||||
chunksFlag[chunkIndex] = true;
|
||||
return new MCChunk(chunksNBT[chunkIndex]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制区块标签对象
|
||||
*
|
||||
* @param chunkIndex 区块索引
|
||||
* @return 新的区块标签对象
|
||||
*/
|
||||
public CompoundTag cloneChunkCompoundTag(int chunkIndex) {
|
||||
if (chunksNBT[chunkIndex] == null)
|
||||
throw new NBTException("区块为空:" + chunkIndex);
|
||||
chunksFlag[chunkIndex] = true;
|
||||
return chunksNBT[chunkIndex].clone();
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.nbt.CompoundTag;
|
||||
|
||||
public class MCBlock {
|
||||
public CompoundTag blockState;//方块状态
|
||||
public CompoundTag blockEntitie;//方块实体
|
||||
|
||||
|
||||
public static final String FACING_UP = "up";
|
||||
public static final String FACING_DOWN = "down";
|
||||
public static final String FACING_NORTH = "north";
|
||||
public static final String FACING_SOUTH = "south";
|
||||
public static final String FACING_EAST = "east";
|
||||
public static final String FACING_WEST = "west";
|
||||
|
||||
/**
|
||||
* 通过标签创建方块
|
||||
*
|
||||
* @param blockState
|
||||
* @param blockEntitie
|
||||
*/
|
||||
public MCBlock(CompoundTag blockState, CompoundTag blockEntitie) {
|
||||
this.blockState = blockState;
|
||||
this.blockEntitie = blockEntitie;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过方块名创建方块
|
||||
*
|
||||
* @param blockName 方块名 如 "minecraft:air"
|
||||
*/
|
||||
public MCBlock(String blockName) {
|
||||
blockState = new CompoundTag();
|
||||
blockState.setTag("Name", blockName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方块名
|
||||
*
|
||||
* @return 方块名
|
||||
*/
|
||||
public String getBlockName() {
|
||||
return (String) blockState.getTag("Name");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置方块朝向
|
||||
*
|
||||
* @param blockFacing 方块朝向 请使用"FACING_xx"
|
||||
*/
|
||||
public void setBlockFacing(String blockFacing) {
|
||||
blockState.setCompoundTag("Properties").setTag("facing", blockFacing);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制一个新对象
|
||||
*
|
||||
* @return 新方块
|
||||
*/
|
||||
public MCBlock clone() {
|
||||
if (blockEntitie == null)
|
||||
return new MCBlock(blockState.clone(), null);
|
||||
return new MCBlock(blockState.clone(), blockEntitie.clone());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MCBlockColors {
|
||||
private ArrayList<BlockColor> blocks = new ArrayList<>();
|
||||
|
||||
public MCBlockColors(File blockImgPath) throws IOException {
|
||||
ArrayList<File> FileList = new ArrayList<>();
|
||||
File[] files = blockImgPath.listFiles();
|
||||
for (File f : files) {
|
||||
if (f.isFile()) {
|
||||
FileList.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
for (File file : FileList) {
|
||||
BufferedImage img = ImageIO.read(file);
|
||||
BufferedImage pix = new BufferedImage(1, 1, img.getType());
|
||||
pix.createGraphics().drawImage(img, 0, 0, 1, 1, null);
|
||||
blocks.add(new BlockColor(file.getName().substring(0, file.getName().length() - 4), new Color(pix.getRGB(0, 0))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class BlockColor {
|
||||
public String name;
|
||||
public Color color;
|
||||
|
||||
public BlockColor(String name, Color color) {
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public int compare(Color color2) {
|
||||
return Math.abs(color2.getRed() - color.getRed()) + Math.abs(color2.getGreen() - color.getGreen()) + Math.abs(color2.getBlue() - color.getBlue());
|
||||
}
|
||||
}
|
||||
|
||||
public BlockColor colorFindBlock(Color color) {
|
||||
if (color.getAlpha() == 0)
|
||||
return new BlockColor("air", new Color(0, 0, 0, 0));
|
||||
int minIndex = 0;
|
||||
int min = 255 * 255 * 255;
|
||||
for (int i = 0; i < blocks.size(); i++) {
|
||||
int c = blocks.get(i).compare(color);
|
||||
if (min > c) {
|
||||
min = c;
|
||||
minIndex = i;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return blocks.get(minIndex);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.exception.NBTException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MCBlocksCollective {
|
||||
public MCPosInt lwh;//集合的宽高
|
||||
public ArrayList<MCBlock> bloks;//方块集合
|
||||
|
||||
public MCBlocksCollective(MCPosInt lwh) {
|
||||
this.lwh = lwh;
|
||||
bloks = new ArrayList<MCBlock>(lwh.x * lwh.y * lwh.z);
|
||||
for (int i = 0; i < lwh.x * lwh.y * lwh.z; i++) {
|
||||
bloks.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方块
|
||||
*
|
||||
* @param pos 要设置的坐标
|
||||
* @param block 方块
|
||||
*/
|
||||
public void setBlock(MCPosInt pos, MCBlock block) {
|
||||
checkPos(pos);
|
||||
bloks.set(pos.x + pos.z * lwh.x + pos.y * lwh.x * lwh.z, block);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方块
|
||||
*
|
||||
* @param pos 要获取的坐标
|
||||
* @return 方块
|
||||
*/
|
||||
public MCBlock getBlock(MCPosInt pos) {
|
||||
checkPos(pos);
|
||||
return bloks.get(pos.x + pos.z * lwh.x + pos.y * lwh.x * lwh.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查坐标是否超集合
|
||||
*
|
||||
* @param pos 欲检查坐标
|
||||
*/
|
||||
private void checkPos(MCPosInt pos) {
|
||||
if ((pos.x < 0 || pos.x >= lwh.x) || (pos.y < 0 || pos.y >= lwh.y) || (pos.z < 0 || pos.z >= lwh.z))
|
||||
throw new NBTException("超出范围:" + pos.toStr());
|
||||
}
|
||||
|
||||
public MCBlocksCollective clone() {
|
||||
MCBlocksCollective mcBlocksCollective = new MCBlocksCollective(lwh.clone());
|
||||
mcBlocksCollective.bloks = (ArrayList<MCBlock>) bloks.clone();
|
||||
return mcBlocksCollective;
|
||||
}
|
||||
|
||||
/**
|
||||
* 空间翻转
|
||||
*
|
||||
* @param xFlip x翻转
|
||||
* @param yFlip y翻转
|
||||
* @param zFlip z翻转
|
||||
* @return 自身
|
||||
*/
|
||||
public MCBlocksCollective flip(boolean xFlip, boolean yFlip, boolean zFlip) {
|
||||
MCBlocksCollective BlocksCollective = clone();
|
||||
MCPosInt.iteratePos(lwh, p -> {
|
||||
MCPosInt blockPos = p.clone();
|
||||
if (xFlip)
|
||||
blockPos.x = lwh.x - p.x - 1;
|
||||
if (yFlip)
|
||||
blockPos.y = lwh.y - p.y - 1;
|
||||
if (zFlip)
|
||||
blockPos.z = lwh.z - p.z - 1;
|
||||
setBlock(p, BlocksCollective.getBlock(blockPos));
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 空间旋转
|
||||
*
|
||||
* @param rotation 旋转的方向 0绕x轴 1绕y轴 2绕z轴
|
||||
* @param times 旋转的次数 整数顺时针 负数逆时针
|
||||
* @return 自身
|
||||
*/
|
||||
public MCBlocksCollective rotation(int rotation, int times) {
|
||||
while (times != 0) {
|
||||
MCBlocksCollective BlocksCollective = clone();
|
||||
|
||||
{
|
||||
int temp;
|
||||
if (rotation == 0) {
|
||||
temp = lwh.z;
|
||||
lwh.z = lwh.y;
|
||||
lwh.y = temp;
|
||||
} else if (rotation == 1) {
|
||||
temp = lwh.z;
|
||||
lwh.z = lwh.x;
|
||||
lwh.x = temp;
|
||||
} else if (rotation == 2) {
|
||||
temp = lwh.y;
|
||||
lwh.y = lwh.x;
|
||||
lwh.x = temp;
|
||||
}
|
||||
}
|
||||
|
||||
MCPosInt.iteratePos(lwh, p -> {
|
||||
MCPosInt blockPos = p.clone();
|
||||
int temp;
|
||||
if (rotation == 0) {
|
||||
temp = blockPos.z;
|
||||
blockPos.z = blockPos.y;
|
||||
blockPos.y = temp;
|
||||
} else if (rotation == 1) {
|
||||
temp = blockPos.z;
|
||||
blockPos.z = blockPos.x;
|
||||
blockPos.x = temp;
|
||||
} else if (rotation == 2) {
|
||||
temp = blockPos.y;
|
||||
blockPos.y = blockPos.x;
|
||||
blockPos.x = temp;
|
||||
}
|
||||
|
||||
|
||||
setBlock(p, BlocksCollective.getBlock(blockPos));
|
||||
});
|
||||
|
||||
if (rotation == 0) {
|
||||
flip(false, times > 0, times < 0);
|
||||
} else if (rotation == 1) {
|
||||
flip(times < 0, false, times > 0);
|
||||
} else if (rotation == 2) {
|
||||
flip(times > 0, times < 0, false);
|
||||
}
|
||||
|
||||
|
||||
if (times > 0)
|
||||
times--;
|
||||
else if (times < 0)
|
||||
times++;
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCBlocksCollective replace(replace r, MCBlock replaceBlock) {
|
||||
MCPosInt.iteratePos(lwh, p -> {
|
||||
if (r.isReplace(getBlock(p)))
|
||||
setBlock(p, replaceBlock);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public interface replace {
|
||||
boolean isReplace(MCBlock block);
|
||||
}
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.Utils.BytesUtils;
|
||||
import main.exception.NBTException;
|
||||
import main.io.MCUtil;
|
||||
import main.nbt.CompoundTag;
|
||||
import main.nbt.ListTag;
|
||||
import main.nbt.TagType;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class MCChunk {
|
||||
public CompoundTag chunk;//区块对象
|
||||
|
||||
/**
|
||||
* 通过区块标签创建区块对象
|
||||
*
|
||||
* @param chunk
|
||||
*/
|
||||
public MCChunk(CompoundTag chunk) {
|
||||
if (chunk == null)
|
||||
throw new NBTException("区块为空");
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制区块对象
|
||||
*
|
||||
* @return 新的区块对象
|
||||
*/
|
||||
public MCChunk cloneChunk() {
|
||||
return new MCChunk(chunk.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区块坐标 Y可以忽略
|
||||
*
|
||||
* @return 区块坐标
|
||||
*/
|
||||
public MCPosInt getChunkPos() {
|
||||
return new MCPosInt((int) chunk.getTag("xPos"), (int) chunk.getTag("yPos"), (int) chunk.getTag("zPos"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在区块里寻找子区块
|
||||
*
|
||||
* @param Y 区块Y索引
|
||||
* @return 子区块标签对象
|
||||
*/
|
||||
public CompoundTag getSubChunk(int Y) {
|
||||
ListTag subChunks = chunk.getCompoundTag("").getListTag("sections");
|
||||
for (int i = 0; i < subChunks.size(); i++) {
|
||||
CompoundTag subChunk = subChunks.getCompoundTag(i);
|
||||
if ((byte) subChunk.getTag("Y") == (byte) Y) {
|
||||
return subChunk;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取方块实体对象
|
||||
*
|
||||
* @param pos 世界绝对坐标
|
||||
* @return 方块实体标签
|
||||
*/
|
||||
public CompoundTag getBlockEntitie(MCPosInt pos) {
|
||||
ListTag chunkBlockEntities = chunk.getCompoundTag("").getListTag("block_entities");
|
||||
if (chunkBlockEntities == null)
|
||||
return null;
|
||||
for (int i = 0; i < chunkBlockEntities.size(); i++) {
|
||||
CompoundTag blockEntitie = chunkBlockEntities.getCompoundTag(i);
|
||||
if ((int) blockEntitie.getTag("x") == pos.x)
|
||||
if ((int) blockEntitie.getTag("y") == pos.y)
|
||||
if ((int) blockEntitie.getTag("z") == pos.z)
|
||||
return blockEntitie;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方块实体对象
|
||||
*
|
||||
* @param pos 世界绝对坐标
|
||||
* @param blockEntitie 方块实体标签
|
||||
*/
|
||||
public void setBlockEntitie(MCPosInt pos, CompoundTag blockEntitie) {
|
||||
|
||||
ListTag chunkBlockEntities = chunk.getCompoundTag("").getListTag("block_entities");
|
||||
if (chunkBlockEntities.type == TagType.TAG_End) {
|
||||
chunkBlockEntities = new ListTag(TagType.TAG_Compound);
|
||||
chunk.getCompoundTag("").setListTag("block_entities", chunkBlockEntities);
|
||||
}
|
||||
|
||||
CompoundTag tag = blockEntitie.clone();
|
||||
|
||||
tag.setTag("x", pos.x);
|
||||
tag.setTag("y", pos.y);
|
||||
tag.setTag("z", pos.z);
|
||||
for (int i = 0; i < chunkBlockEntities.size(); i++) {
|
||||
if (chunkBlockEntities.getCompoundTag(i).getTag("x") != null)
|
||||
if ((int) chunkBlockEntities.getCompoundTag(i).getTag("x") == pos.x)
|
||||
if ((int) chunkBlockEntities.getCompoundTag(i).getTag("y") == pos.y)
|
||||
if ((int) chunkBlockEntities.getCompoundTag(i).getTag("z") == pos.z) {
|
||||
chunkBlockEntities.set(i, tag);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
chunkBlockEntities.addTag(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个方块状态
|
||||
*
|
||||
* @param blockIndex 方块索引
|
||||
* @param subChunkY 子区块Y索引
|
||||
* @return 方块状态标签
|
||||
*/
|
||||
public CompoundTag getBlockState(int blockIndex, int subChunkY) {
|
||||
CompoundTag sunChunkBlocks = getSubChunk(subChunkY).getCompoundTag("block_states");
|
||||
|
||||
//读取区块方块索引
|
||||
ListTag blocks = sunChunkBlocks.getListTag("palette");
|
||||
|
||||
|
||||
int mapBit = MCUtil.getMapBitSize(blocks.size());
|
||||
int longIndex = blockIndex / (64 / mapBit);
|
||||
int longBlockIndex = blockIndex % (64 / mapBit);
|
||||
//System.out.println(sunChunkBlocks);
|
||||
|
||||
if (sunChunkBlocks.getTag("data") == null)
|
||||
return blocks.getCompoundTag(0);
|
||||
BitSet blockData = BitSet.valueOf(new long[]{((long[]) sunChunkBlocks.getTag("data"))[longIndex]});
|
||||
|
||||
//System.out.println(BytesUtils.bytes2int(blockData.get(longBlockIndex * mapBit, (longBlockIndex + 1) * mapBit).toByteArray()));
|
||||
|
||||
return blocks.getCompoundTag(BytesUtils.bytes2int(blockData.get(longBlockIndex * mapBit, (longBlockIndex + 1) * mapBit).toByteArray()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方块状态
|
||||
*
|
||||
* @param blockIndex 方块索引
|
||||
* @param subChunkY 子区块Y索引
|
||||
* @param blockState 方块状态标签
|
||||
*/
|
||||
public void setBlockState(int blockIndex, int subChunkY, CompoundTag blockState) {
|
||||
CompoundTag subChunk = getSubChunk(subChunkY);
|
||||
if (subChunk == null) {
|
||||
throw new NBTException("Y越界:" + subChunkY);
|
||||
}
|
||||
CompoundTag sunChunkBlocks = subChunk.getCompoundTag("block_states");
|
||||
//读取区块方块索引
|
||||
ListTag blocks = sunChunkBlocks.getListTag("palette");
|
||||
int mapBitBefore = MCUtil.getMapBitSize(blocks.size());
|
||||
|
||||
//防止为空
|
||||
if (sunChunkBlocks.getTag("data") == null)
|
||||
sunChunkBlocks.setTag("data", new long[1]);
|
||||
|
||||
|
||||
int foundBlockIndex = -1;
|
||||
//查找方块列表是否存在要添加的方块
|
||||
for (int i = 0; i < blocks.size(); i++) {
|
||||
if (blocks.getCompoundTag(i).equals(blockState)) {
|
||||
foundBlockIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//未找到 添加方块列表
|
||||
if (foundBlockIndex == -1) {
|
||||
blocks.addTag(blockState);
|
||||
foundBlockIndex = blocks.size() - 1;
|
||||
}
|
||||
|
||||
int mapBitNow = MCUtil.getMapBitSize(blocks.size());
|
||||
MCSubChunk mcSubChunkBefore = new MCSubChunk((long[]) sunChunkBlocks.getTag("data"), (int) Math.ceil(4096.0 / (double) (64 / mapBitBefore)), mapBitBefore);
|
||||
if (mapBitNow != mapBitBefore) {//存储位数不一样
|
||||
MCSubChunk mcSubChunkNow = new MCSubChunk((int) Math.ceil(4096.0 / (double) (64 / mapBitNow)), mapBitNow);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (blockIndex == i) {//找到欲替换方块
|
||||
mcSubChunkNow.set(i, foundBlockIndex);
|
||||
} else {//转移数据
|
||||
mcSubChunkNow.set(i, mcSubChunkBefore.get(i));
|
||||
}
|
||||
|
||||
}
|
||||
sunChunkBlocks.setTag("data", mcSubChunkNow.getLongArray());
|
||||
} else {
|
||||
mcSubChunkBefore.set(blockIndex, foundBlockIndex);
|
||||
sunChunkBlocks.setTag("data", mcSubChunkBefore.getLongArray());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.exception.NBTException;
|
||||
import main.io.MCUtil;
|
||||
import main.nbt.CompoundTag;
|
||||
import text.lib.MyImageFilter;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class MCMap {
|
||||
private CompoundTag map;
|
||||
private File mapFile;
|
||||
|
||||
/**
|
||||
* 创建地图对象
|
||||
*
|
||||
* @param mapFile 地图文件
|
||||
* @throws IOException
|
||||
*/
|
||||
public MCMap(File mapFile) throws IOException {
|
||||
this.mapFile = mapFile;
|
||||
map = MCUtil.readDATFile(mapFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存地图文件
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void saveFile() throws IOException {
|
||||
MCUtil.writeDATFile(mapFile, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置地图被制图台锁定
|
||||
*
|
||||
* @param locked 是否锁定
|
||||
*/
|
||||
public void setLocked(boolean locked) {
|
||||
map.getCompoundTag("").getCompoundTag("data").setTag("locked", (byte) (locked ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 地图在游戏世界里的位置中心
|
||||
*
|
||||
* @param xz 位置中心坐标
|
||||
*/
|
||||
public void setXZCenter(MCPosInt xz) {
|
||||
map.getCompoundTag("").getCompoundTag("data").setTag("xCenter", xz.x);
|
||||
map.getCompoundTag("").getCompoundTag("data").setTag("zCenter", xz.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置位置箭头是否被显示
|
||||
*
|
||||
* @param trackingPosition 是否被显示
|
||||
*/
|
||||
public void setTrackingPosition(boolean trackingPosition) {
|
||||
map.getCompoundTag("").getCompoundTag("data").setTag("trackingPosition", (byte) (trackingPosition ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置玩家位置指示器是否显示
|
||||
*
|
||||
* @param unlimitedTracking 是否被显示
|
||||
*/
|
||||
public void setUnlimitedTracking(boolean unlimitedTracking) {
|
||||
map.getCompoundTag("").getCompoundTag("data").setTag("unlimitedTracking", (byte) (unlimitedTracking ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置地图缩放等级
|
||||
*
|
||||
* @param scale 缩放等级(最大为4)
|
||||
*/
|
||||
public void setScale(int scale) {
|
||||
if (scale < 0)
|
||||
scale = 0;
|
||||
if (scale > 4)
|
||||
scale = 4;
|
||||
map.getCompoundTag("").getCompoundTag("data").setTag("scale", (byte) scale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取某像素颜色
|
||||
*
|
||||
* @param x 水平像素位置
|
||||
* @param y 垂直像素位置
|
||||
* @return 返回获取的颜色
|
||||
*/
|
||||
public Color getColor(int x, int y) {
|
||||
return MCMapColors.byte2color(((byte[]) (map.getCompoundTag("").getCompoundTag("data").getTag("colors")))[x + y * 128]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置某像素颜色
|
||||
*
|
||||
* @param x 水平像素位置
|
||||
* @param y 垂直像素位置
|
||||
* @param color 要设置的颜色
|
||||
*/
|
||||
public void setColor(int x, int y, Color color) {
|
||||
((byte[]) (map.getCompoundTag("").getCompoundTag("data").getTag("colors")))[x + y * 128] = MCMapColors.color2byte(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图片 (128x128)
|
||||
*
|
||||
* @param inputStream 图片输入流
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setImg(InputStream inputStream) throws IOException {
|
||||
BufferedImage bufferedImage = ImageIO.read(inputStream);
|
||||
for (int y = 0; y < 128; y++) {
|
||||
for (int x = 0; x < 128; x++) {
|
||||
setColor(x, y, new Color(bufferedImage.getRGB(x, y)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出png图片 (128x128)
|
||||
*
|
||||
* @param outputStream
|
||||
* @throws IOException
|
||||
*/
|
||||
public void save2img(OutputStream outputStream) throws IOException {
|
||||
BufferedImage bufferedImage = new BufferedImage(128, 128, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
for (int y = 0; y < 128; y++) {
|
||||
for (int x = 0; x < 128; x++) {
|
||||
bufferedImage.setRGB(x, y, getColor(x, y).getRGB());
|
||||
}
|
||||
}
|
||||
ImageIO.write(bufferedImage, "png", outputStream);
|
||||
}
|
||||
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.Utils.BytesUtils;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/*
|
||||
* 资料:
|
||||
* https://minecraft.fandom.com/zh/wiki/%E5%9C%B0%E5%9B%BE%E7%89%A9%E5%93%81%E6%A0%BC%E5%BC%8F
|
||||
* */
|
||||
public class MCMapColors {
|
||||
//MC地图颜色索引
|
||||
public static final Color[] mapColors = {
|
||||
new Color(0, 0, 0, 0),
|
||||
new Color(127, 178, 56),
|
||||
new Color(247, 233, 163),
|
||||
new Color(199, 199, 199),
|
||||
new Color(255, 0, 0),
|
||||
new Color(160, 160, 255),
|
||||
new Color(167, 167, 167),
|
||||
new Color(0, 124, 0),
|
||||
new Color(255, 255, 255),
|
||||
new Color(164, 168, 184),
|
||||
new Color(151, 109, 77),
|
||||
new Color(112, 112, 112),
|
||||
new Color(64, 64, 255),
|
||||
new Color(143, 119, 72),
|
||||
new Color(255, 252, 245),
|
||||
new Color(216, 127, 51),
|
||||
new Color(178, 76, 216),
|
||||
new Color(102, 153, 216),
|
||||
new Color(229, 229, 51),
|
||||
new Color(127, 204, 25),
|
||||
new Color(242, 127, 165),
|
||||
new Color(76, 76, 76),
|
||||
new Color(153, 153, 153),
|
||||
new Color(76, 127, 153),
|
||||
new Color(127, 63, 178),
|
||||
new Color(51, 76, 178),
|
||||
new Color(102, 76, 51),
|
||||
new Color(102, 127, 51),
|
||||
new Color(153, 51, 51),
|
||||
new Color(25, 25, 25),
|
||||
new Color(250, 238, 77),
|
||||
new Color(92, 219, 213),
|
||||
new Color(74, 128, 255),
|
||||
new Color(0, 217, 58),
|
||||
new Color(129, 86, 49),
|
||||
new Color(112, 2, 0),
|
||||
new Color(209, 177, 161),
|
||||
new Color(159, 82, 36),
|
||||
new Color(149, 87, 108),
|
||||
new Color(112, 108, 138),
|
||||
new Color(186, 133, 36),
|
||||
new Color(103, 117, 53),
|
||||
new Color(160, 77, 78),
|
||||
new Color(57, 41, 35),
|
||||
new Color(135, 107, 98),
|
||||
new Color(87, 92, 92),
|
||||
new Color(122, 73, 88),
|
||||
new Color(76, 62, 92),
|
||||
new Color(76, 50, 35),
|
||||
new Color(76, 82, 42),
|
||||
new Color(142, 60, 46),
|
||||
new Color(37, 22, 16),
|
||||
new Color(189, 48, 49),
|
||||
new Color(148, 63, 97),
|
||||
new Color(92, 25, 29),
|
||||
new Color(22, 126, 134),
|
||||
new Color(58, 142, 140),
|
||||
new Color(86, 44, 62),
|
||||
new Color(20, 180, 133),
|
||||
new Color(86, 86, 86),
|
||||
new Color(186, 150, 126)
|
||||
};
|
||||
|
||||
//相关联的地图色 乘数
|
||||
public static final float[] relatedColor = {
|
||||
0.71f,
|
||||
0.86f,
|
||||
1f,
|
||||
0.53f
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算颜色差
|
||||
*
|
||||
* @param color 比对颜色1
|
||||
* @param color2 比对颜色2
|
||||
* @return 颜色差
|
||||
*/
|
||||
public static int compareColor(Color color, Color color2) {
|
||||
return Math.abs(color2.getRed() - color.getRed()) + Math.abs(color2.getGreen() - color.getGreen()) + Math.abs(color2.getBlue() - color.getBlue());
|
||||
}
|
||||
|
||||
/* HSB计算色差 (效果不咋滴 废弃)
|
||||
public static int compareColor(Color color, Color color2) {
|
||||
float[] HSB = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
|
||||
float[] HSB2 = Color.RGBtoHSB(color2.getRed(), color2.getGreen(), color2.getBlue(), null);
|
||||
|
||||
HSB[0] = (Math.abs(HSB[0] - HSB2[0])) * 1000f;
|
||||
HSB[1] = (Math.abs(HSB[1] - HSB2[1])) * 100f;
|
||||
HSB[2] = (Math.abs(HSB[2] - HSB2[2])) * 100f;
|
||||
|
||||
return (int) (HSB[0] + HSB[1] + HSB[2]);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* 颜色乘
|
||||
*
|
||||
* @param color 欲被乘的颜色
|
||||
* @param n 被乘的小数
|
||||
* @return 乘后的颜色
|
||||
*/
|
||||
public static Color multiplyColor(Color color, float n) {
|
||||
return new Color((int) (color.getRed() * n), (int) (color.getGreen() * n), (int) (color.getBlue() * n));
|
||||
}
|
||||
|
||||
/**
|
||||
* 颜色到字节
|
||||
*
|
||||
* @param color 颜色
|
||||
* @return 颜色字节
|
||||
*/
|
||||
public static byte color2byte(Color color) {
|
||||
byte iMin = 0;
|
||||
byte jMin = 0;
|
||||
int colorDeviation = 16581375;
|
||||
for (byte i = 0; i < 61; i++) {//所有色
|
||||
for (byte j = 0; j < 4; j++) {//关联色
|
||||
int Deviation = compareColor(color, multiplyColor(mapColors[i], relatedColor[j]));
|
||||
if (Deviation < colorDeviation) {
|
||||
colorDeviation = Deviation;
|
||||
iMin = i;
|
||||
jMin = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (byte) ((iMin * 4 + jMin));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节到颜色
|
||||
*
|
||||
* @param color 颜色字节
|
||||
* @return 返回颜色
|
||||
*/
|
||||
public static Color byte2color(byte color) {
|
||||
return multiplyColor(mapColors[(color & 0xFF) / 4], relatedColor[(color & 0xFF) % 4]);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,222 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
public class MCPosInt {
|
||||
public int x, y, z;
|
||||
|
||||
public MCPosInt() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过xyz创建坐标对象
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public MCPosInt(int x, int y, int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过xz创建坐标对象
|
||||
*
|
||||
* @param x
|
||||
* @param z
|
||||
*/
|
||||
public MCPosInt(int x, int z) {
|
||||
this.x = x;
|
||||
this.y = 0;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* 坐标到字符串
|
||||
*
|
||||
* @return 格式化后的坐标文本
|
||||
*/
|
||||
public String toStr() {
|
||||
return "x:" + x + " y:" + y + " z:" + z;
|
||||
}
|
||||
|
||||
/**
|
||||
* 世界坐标取区块位置
|
||||
*
|
||||
* @param xyz 世界绝对坐标
|
||||
* @return 区块绝对坐标
|
||||
*/
|
||||
public static MCPosInt pos2chunk(MCPosInt xyz) {
|
||||
return new MCPosInt(xyz.x >> 4, xyz.y >> 4, xyz.z >> 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 世界坐标取方块索引
|
||||
*
|
||||
* @param xyz 世界绝对坐标
|
||||
* @return 方块索引值
|
||||
*/
|
||||
public static int pos2blockIndex(MCPosInt xyz) {
|
||||
return (xyz.x & 0xF) + (xyz.y & 0xF) * 256 + (xyz.z & 0xF) * 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* 世界坐标Y到子区块Y索引
|
||||
*
|
||||
* @param y 世界绝对y坐标
|
||||
* @return 子区块Y索引
|
||||
*/
|
||||
public static int pos2subChunkY(int y) {
|
||||
return y >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* 区块坐标取区块索引
|
||||
*
|
||||
* @param xz 区块绝对坐标
|
||||
* @return 区块索引
|
||||
*/
|
||||
public static int chunk2chunkIndex(MCPosInt xz) {
|
||||
return (xz.x & 0x1F) + (xz.z & 0x1F) * 32;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 世界坐标取区块索引
|
||||
*
|
||||
* @param xz 世界绝对坐标
|
||||
* @return 区块索引
|
||||
*/
|
||||
public static int pos2chunkIndex(MCPosInt xz) {
|
||||
MCPosInt rel = pos2chunk(xz);
|
||||
return chunk2chunkIndex(rel);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将世界坐标转成mca位置
|
||||
*
|
||||
* @param xz 世界绝对坐标
|
||||
* @return mca文件位置
|
||||
*/
|
||||
public static MCPosInt pos2regionPos(MCPosInt xz) {
|
||||
return new MCPosInt(xz.x >> 9, xz.z >> 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将区块位置转成mca位置
|
||||
*
|
||||
* @param xz 区块位置
|
||||
* @return mca文件位置
|
||||
*/
|
||||
public static MCPosInt chunk2regionPos(MCPosInt xz) {
|
||||
return new MCPosInt(xz.x >> 5, xz.z >> 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制个全新的坐标对象
|
||||
*
|
||||
* @return 新的坐标对象
|
||||
*/
|
||||
public MCPosInt clone() {
|
||||
return new MCPosInt(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* 两坐标取原点坐标 和 区域大小
|
||||
*
|
||||
* @param p1 坐标1
|
||||
* @param p2 坐标2
|
||||
* @param Origin 原点坐标
|
||||
* @param LWH 长宽高
|
||||
*/
|
||||
public static void getOrigin(MCPosInt p1, MCPosInt p2, MCPosInt Origin, MCPosInt LWH) {
|
||||
LWH.x = Math.abs(p1.x - p2.x);
|
||||
LWH.y = Math.abs(p1.y - p2.y);
|
||||
LWH.z = Math.abs(p1.z - p2.z);
|
||||
Origin.x = Math.min(p1.x, p2.x);
|
||||
Origin.y = Math.min(p1.y, p2.y);
|
||||
Origin.z = Math.min(p1.z, p2.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将两坐标相加
|
||||
*
|
||||
* @param p1 坐标1
|
||||
* @param p2 坐标2
|
||||
* @return 相加后的坐标
|
||||
*/
|
||||
public static MCPosInt additive(MCPosInt p1, MCPosInt p2) {
|
||||
return new MCPosInt(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 和坐标比较
|
||||
*
|
||||
* @param xyz 要比较的坐标
|
||||
* @return 是否一样
|
||||
*/
|
||||
public boolean isEquals(MCPosInt xyz) {
|
||||
return (xyz.x == x && xyz.y == y && xyz.z == z);
|
||||
}
|
||||
|
||||
public static void iteratePos(MCPosInt lwh, callBack cb) {
|
||||
for (int y = 0; y < lwh.y; y++) {
|
||||
for (int z = 0; z < lwh.z; z++) {
|
||||
for (int x = 0; x < lwh.x; x++) {
|
||||
cb.iterate(new MCPosInt(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static float getDistance(MCPosInt p1, MCPosInt p2) {
|
||||
return (float) Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2) + Math.pow(p2.z - p1.z, 2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 枚举两坐标直线所有坐标
|
||||
*
|
||||
* @param p1 坐标1
|
||||
* @param p2 坐标2
|
||||
* @param s 细分
|
||||
* @param p 所有坐标
|
||||
*/
|
||||
public static void enumLinePos(MCPosInt p1, MCPosInt p2, float s, callBack p) {
|
||||
enumLinePos(p1, p2, s, (p_, d) -> {
|
||||
p.iterate(p_);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static void enumLinePos(MCPosInt p1, MCPosInt p2, float s, callBack2 p) {
|
||||
float k = (MCPosInt.getDistance(p1, p2)) * s;
|
||||
for (float i = 0; i < k; i++) {
|
||||
MCPosInt pos = new MCPosInt(
|
||||
Math.round((p1.x - (p1.x - p2.x) / k * i)),
|
||||
Math.round((p1.y - (p1.y - p2.y) / k * i)),
|
||||
Math.round((p1.z - (p1.z - p2.z) / k * i)));
|
||||
p.iterate(pos, 1f / k * i);
|
||||
}
|
||||
if (k == 0) {
|
||||
p.iterate(p1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface callBack {
|
||||
void iterate(MCPosInt p);
|
||||
}
|
||||
|
||||
public interface callBack2 {
|
||||
void iterate(MCPosInt p, float d);
|
||||
}
|
||||
|
||||
}
|
@ -1,309 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.exception.NBTException;
|
||||
import main.io.MCUtil;
|
||||
import main.nbt.CompoundTag;
|
||||
import main.nbt.ListTag;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
public class MCRegion {
|
||||
public static final short SAVEMODE_RewriteAll = 0;//0全部重写 稳定 需要退出存档
|
||||
public static final short SAVEMODE_RewritePart = 1;//1局部重写 速度快 只需区块不被加载就能写
|
||||
private int saveMode = SAVEMODE_RewritePart;//保存模式 默认为局部重写
|
||||
private File mcaFileDirectory;//MCA文件目录的路径
|
||||
private MCA[] mca;//当前打开的MCA
|
||||
private int mcaCache = 3;//用于缓存mca文件 加快反复横跳速度
|
||||
private int mcaCacheNumber = 0;//已存在的缓存数量
|
||||
private MCChunk generateChunk = null;//自动生成区块 适合超平坦使用
|
||||
|
||||
/**
|
||||
* @param mcaFileDirectory mca文件夹路径
|
||||
* @throws IOException
|
||||
*/
|
||||
public MCRegion(File mcaFileDirectory) throws IOException {
|
||||
if (!mcaFileDirectory.isDirectory()) {
|
||||
throw new NBTException("需要一个文件夹路径");
|
||||
}
|
||||
this.mcaFileDirectory = mcaFileDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mcaFileDirectory mca文件夹路径
|
||||
* @param mcaCache 缓存数量 默认为3
|
||||
* @throws IOException
|
||||
*/
|
||||
public MCRegion(File mcaFileDirectory, int mcaCache) throws IOException {
|
||||
if (!mcaFileDirectory.isDirectory()) {
|
||||
throw new NBTException("需要一个文件夹路径");
|
||||
}
|
||||
this.mcaFileDirectory = mcaFileDirectory;
|
||||
this.mcaCache = mcaCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置保存模式
|
||||
*
|
||||
* @param saveMode 保存模式 默认为局部重写 请使用"SAVEMODE_xx"
|
||||
*/
|
||||
public void setSaveMode(int saveMode) {
|
||||
this.saveMode = saveMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置生成区块 遇到空区块时会自动创建区块 为空时开摆
|
||||
*
|
||||
* @param generateChunk 要自动生成的区块
|
||||
*/
|
||||
public void setGenerateChunk(MCChunk generateChunk) {
|
||||
this.generateChunk = generateChunk;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存所有MCA文件
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void saveMCA() throws IOException {
|
||||
for (int i = 0; i < mcaCacheNumber; i++) {
|
||||
saveMCA(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存MCA文件
|
||||
*
|
||||
* @param index 缓存索引
|
||||
* @throws IOException
|
||||
*/
|
||||
private void saveMCA(int index) throws IOException {
|
||||
System.out.println("保存mca:" + mca[index].Pos.toStr());
|
||||
if (saveMode == SAVEMODE_RewriteAll) {
|
||||
MCUtil.writeMCAFile(mca[index], mcaFileDirectory);
|
||||
} else if (saveMode == SAVEMODE_RewritePart) {
|
||||
MCUtil.writeMCAFile2(mca[index], mcaFileDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 区块坐标查mca缓存 如果没有则读取mca
|
||||
*
|
||||
* @param xz 区块绝对坐标
|
||||
* @return 缓存索引
|
||||
* @throws IOException
|
||||
*/
|
||||
private int checkMCA(MCPosInt xz) throws IOException {
|
||||
MCPosInt mcaPos = MCPosInt.chunk2regionPos(xz);//转换坐标
|
||||
int chunkIndex = MCPosInt.chunk2chunkIndex(xz);
|
||||
if (mca == null) {//初始化
|
||||
mca = new MCA[mcaCache];
|
||||
mca[0] = MCUtil.readMCAFile(mcaFileDirectory, mcaPos);
|
||||
mcaCacheNumber = 1;
|
||||
System.out.println("载入mca:" + mcaPos.toStr());
|
||||
mca[0].chunkTimeStamp[chunkIndex] = System.currentTimeMillis();//修改时间戳
|
||||
mca[0].chunksFlag[chunkIndex] = true;
|
||||
if (generateChunk != null)//自动生成区块
|
||||
if (mca[0].chunksNBT[chunkIndex] == null) {
|
||||
mca[0].chunksNBT[chunkIndex] = generateChunk.cloneChunk().chunk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//查找
|
||||
for (int i = 0; i < mcaCacheNumber; i++) {
|
||||
if (mca[i].Pos.isEquals(mcaPos)) {
|
||||
mca[i].chunkTimeStamp[chunkIndex] = System.currentTimeMillis();//修改时间戳
|
||||
mca[i].chunksFlag[chunkIndex] = true;
|
||||
if (generateChunk != null)//自动生成区块
|
||||
if (mca[i].chunksNBT[chunkIndex] == null)
|
||||
mca[i].chunksNBT[chunkIndex] = generateChunk.cloneChunk().chunk;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
//保存末尾
|
||||
if (mcaCacheNumber < mcaCache) {
|
||||
mcaCacheNumber++;
|
||||
} else {
|
||||
saveMCA(mcaCache - 1);
|
||||
}
|
||||
|
||||
//移动
|
||||
System.arraycopy(mca, 0, mca, 1, mcaCache - 1);
|
||||
|
||||
//载入
|
||||
mca[0] = MCUtil.readMCAFile(mcaFileDirectory, mcaPos);
|
||||
System.out.println("载入mca:" + mcaPos.toStr());
|
||||
|
||||
mca[0].chunkTimeStamp[chunkIndex] = System.currentTimeMillis();//修改时间戳
|
||||
mca[0].chunksFlag[chunkIndex] = true;
|
||||
if (generateChunk != null)//自动生成区块
|
||||
if (mca[0].chunksNBT[chunkIndex] == null)
|
||||
mca[0].chunksNBT[chunkIndex] = generateChunk.cloneChunk().chunk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取方块状态
|
||||
*
|
||||
* @param xyz 方块绝对坐标
|
||||
* @return 新的Tag对象
|
||||
* @throws IOException
|
||||
*/
|
||||
public CompoundTag getBlockState(MCPosInt xyz) throws IOException {
|
||||
int index = checkMCA(MCPosInt.pos2chunk(xyz));
|
||||
MCChunk chunk = mca[index].getChunk(MCPosInt.pos2chunkIndex(xyz));
|
||||
return chunk.getBlockState(MCPosInt.pos2blockIndex(xyz), MCPosInt.pos2subChunkY(xyz.y)).clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方块状态
|
||||
*
|
||||
* @param xyz 方块绝对坐标
|
||||
* @param blockState 方块状态
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setBlockState(MCPosInt xyz, CompoundTag blockState) throws IOException {
|
||||
int index = checkMCA(MCPosInt.pos2chunk(xyz));
|
||||
MCChunk chunk = mca[index].getChunk(MCPosInt.pos2chunkIndex(xyz));
|
||||
chunk.setBlockState(MCPosInt.pos2blockIndex(xyz), MCPosInt.pos2subChunkY(xyz.y), blockState);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方块实体
|
||||
*
|
||||
* @param xyz 方块绝对坐标
|
||||
* @return 方块实体标签
|
||||
* @throws IOException
|
||||
*/
|
||||
public CompoundTag getBlockEntitie(MCPosInt xyz) throws IOException {
|
||||
int index = checkMCA(MCPosInt.pos2chunk(xyz));
|
||||
MCChunk chunk = mca[index].getChunk(MCPosInt.pos2chunkIndex(xyz));
|
||||
return chunk.getBlockEntitie(xyz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方块实体 直接覆盖
|
||||
*
|
||||
* @param xyz 方块绝对坐标
|
||||
* @param blockEntitie 方块实体标签
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setBlockEntitie(MCPosInt xyz, CompoundTag blockEntitie) throws IOException {
|
||||
int index = checkMCA(MCPosInt.pos2chunk(xyz));
|
||||
MCChunk chunk = mca[index].getChunk(MCPosInt.pos2chunkIndex(xyz));
|
||||
chunk.setBlockEntitie((xyz), blockEntitie);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个区块
|
||||
*
|
||||
* @param xz 区块绝对坐标
|
||||
* @return 区块对象
|
||||
* @throws IOException
|
||||
*/
|
||||
public MCChunk getChunk(MCPosInt xz) throws IOException {
|
||||
int index = checkMCA(xz);
|
||||
return mca[index].getChunk(MCPosInt.chunk2chunkIndex(xz)).cloneChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置区块
|
||||
*
|
||||
* @param xz 区块绝对坐标
|
||||
* @param chunk 要设置的区块对象
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setChunk(MCPosInt xz, MCChunk chunk) throws IOException {
|
||||
int index = checkMCA(xz);
|
||||
chunk.chunk.getCompoundTag("").setTag("xPos", xz.x).setTag("zPos", xz.z);
|
||||
ListTag blockEntities = chunk.chunk.getCompoundTag("").getListTag("block_entities");
|
||||
if (blockEntities != null) {
|
||||
for (int i = 0; i < blockEntities.size(); i++) {
|
||||
CompoundTag tag = blockEntities.getCompoundTag(i);
|
||||
MCPosInt blockPos = new MCPosInt((int) tag.getTag("x"), (int) tag.getTag("z"));
|
||||
blockPos.x = blockPos.x % 16 + xz.x * 16;
|
||||
blockPos.z = blockPos.z % 16 + xz.z * 16;
|
||||
tag.setTag("x", blockPos.x);
|
||||
tag.setTag("z", blockPos.z);
|
||||
}
|
||||
}
|
||||
mca[index].chunksNBT[MCPosInt.chunk2chunkIndex(xz)] = chunk.chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方块
|
||||
*
|
||||
* @param xyz 要获取的坐标
|
||||
* @return 获取到的方块
|
||||
* @throws IOException
|
||||
*/
|
||||
public MCBlock getBlock(MCPosInt xyz) throws IOException {
|
||||
return new MCBlock(getBlockState(xyz), getBlockEntitie(xyz));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方块
|
||||
*
|
||||
* @param xyz 要设置的坐标
|
||||
* @param block 要设置的方块
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setBlock(MCPosInt xyz, MCBlock block) throws IOException {
|
||||
setBlockState(xyz, block.blockState);
|
||||
if (block.blockEntitie != null)
|
||||
setBlockEntitie(xyz, block.blockEntitie);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方块集
|
||||
*
|
||||
* @param Pos1 坐标1
|
||||
* @param Pos2 坐标2
|
||||
* @return 方块集
|
||||
* @throws IOException
|
||||
*/
|
||||
public MCBlocksCollective getBlocksCollective(MCPosInt Pos1, MCPosInt Pos2) throws IOException {
|
||||
MCPosInt origin = new MCPosInt();
|
||||
MCPosInt lwh = new MCPosInt();
|
||||
MCPosInt.getOrigin(Pos1, Pos2, origin, lwh);
|
||||
lwh = MCPosInt.additive(lwh, new MCPosInt(1, 1, 1));
|
||||
MCBlocksCollective mcBlocksCollective = new MCBlocksCollective(lwh);
|
||||
|
||||
MCPosInt.iteratePos(lwh, p -> {
|
||||
MCPosInt blockPos = MCPosInt.additive(origin, p);
|
||||
MCBlock mcBlock = null;
|
||||
try {
|
||||
mcBlock = getBlock(blockPos);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mcBlocksCollective.setBlock(p, mcBlock);
|
||||
});
|
||||
|
||||
|
||||
return mcBlocksCollective;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方块集
|
||||
*
|
||||
* @param pos 原点坐标
|
||||
* @param mcBlocksCollective 方块集
|
||||
*/
|
||||
public void setBlocksCollective(MCPosInt pos, MCBlocksCollective mcBlocksCollective) {
|
||||
MCPosInt.iteratePos(mcBlocksCollective.lwh, p -> {
|
||||
MCBlock block = mcBlocksCollective.getBlock(p);
|
||||
if (block != null)
|
||||
try {
|
||||
setBlock(MCPosInt.additive(pos, p), block.clone());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package main.mc;
|
||||
|
||||
import main.exception.NBTException;
|
||||
|
||||
public class MCSubChunk {
|
||||
private long[] longArray;//地图数据
|
||||
private int mapBit;//存储的位大小
|
||||
private long max;
|
||||
|
||||
public MCSubChunk(long[] longArray, int longLength, int mapBit) {
|
||||
this.longArray = new long[longLength];
|
||||
System.arraycopy(longArray, 0, this.longArray, 0, longArray.length);
|
||||
this.mapBit = mapBit;
|
||||
max = (int) Math.pow(2, mapBit) - 1;
|
||||
}
|
||||
|
||||
public MCSubChunk(long[] longArray, int mapBit) {
|
||||
this.longArray = longArray;
|
||||
this.mapBit = mapBit;
|
||||
max = (int) Math.pow(2, mapBit) - 1;
|
||||
}
|
||||
|
||||
public MCSubChunk(int longLength, int mapBit) {
|
||||
this.longArray = new long[longLength];
|
||||
this.mapBit = mapBit;
|
||||
max = (int) Math.pow(2, mapBit) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Long数组
|
||||
*
|
||||
* @return 地图数据
|
||||
*/
|
||||
public long[] getLongArray() {
|
||||
return longArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地图存储的位大小
|
||||
* @return 存储的位大小
|
||||
*/
|
||||
public int getMapBit() {
|
||||
return mapBit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置值
|
||||
* @param index 索引
|
||||
* @param vel 值
|
||||
*/
|
||||
public void set(int index, long vel) {
|
||||
if (vel < 0 || vel > max)
|
||||
throw new NBTException("设置的值不在范围:" + vel);
|
||||
int longIndex = index / (64 / mapBit);
|
||||
if (longIndex >= longArray.length)
|
||||
throw new NBTException("索引超出范围:" + index);
|
||||
int bitIndex = index % (64 / mapBit) * mapBit;
|
||||
longArray[longIndex] = longArray[longIndex] & ~(max << bitIndex);
|
||||
longArray[longIndex] = (vel << bitIndex) | longArray[longIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取值
|
||||
* @param index 索引
|
||||
* @return 值
|
||||
*/
|
||||
public long get(int index) {
|
||||
int longIndex = index / (64 / mapBit);
|
||||
if (longIndex >= longArray.length)
|
||||
throw new NBTException("索引超出范围:" + index);
|
||||
int bitIndex = index % (64 / mapBit) * mapBit;
|
||||
long b = (longArray[longIndex] & (max << bitIndex)) >> bitIndex;
|
||||
if (b < 0)
|
||||
return 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
package main.nbt;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static main.nbt.TagType.*;
|
||||
|
||||
public class CompoundTag extends LinkedHashMap<String, Object> {
|
||||
|
||||
|
||||
public CompoundTag() {
|
||||
}
|
||||
|
||||
@Override//克隆新的复合标签对象
|
||||
public CompoundTag clone() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
Iterator<Map.Entry<String, Object>> integer = super.entrySet().iterator();
|
||||
while (integer.hasNext()) {
|
||||
Map.Entry<String, Object> entry = integer.next();
|
||||
tag.put(entry.getKey(), TagType.cloneTag(entry.getValue()));
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
public ListTag getListTag(String name) {
|
||||
return (ListTag) (Object) super.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取复合标签
|
||||
*
|
||||
* @param name 标签名
|
||||
* @return 复合标签 没有返回null
|
||||
*/
|
||||
public CompoundTag getCompoundTag(String name) {
|
||||
return (CompoundTag) super.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签
|
||||
*
|
||||
* @param name 标签名
|
||||
* @return 标签 没有返回null
|
||||
*/
|
||||
public Object getTag(String name) {
|
||||
return super.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签的类型
|
||||
*
|
||||
* @param name 标签名
|
||||
* @return 标签类型 没有返回-1
|
||||
*/
|
||||
public short getTagType(String name) {
|
||||
return TagType.Object2TagType(super.get(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置列表标签
|
||||
*
|
||||
* @param name 标签名
|
||||
* @param listTag 要设置的列表标签
|
||||
* @return 自身
|
||||
*/
|
||||
public CompoundTag setListTag(String name, ListTag listTag) {
|
||||
super.put(name, listTag);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置复合标签
|
||||
*
|
||||
* @param name 标签名
|
||||
* @param compoundTag 要设置的复合标签
|
||||
* @return 自身
|
||||
*/
|
||||
public CompoundTag setCompoundTag(String name, CompoundTag compoundTag) {
|
||||
super.put(name, compoundTag);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置新的复合标签
|
||||
*
|
||||
* @param name 标签名
|
||||
* @return 新的复合标签
|
||||
*/
|
||||
public CompoundTag setCompoundTag(String name) {
|
||||
CompoundTag newCompoundTag = new CompoundTag();
|
||||
super.put(name, newCompoundTag);
|
||||
return newCompoundTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置标签
|
||||
*
|
||||
* @param name 标签名
|
||||
* @param data 标签对象
|
||||
* @return 自身
|
||||
*/
|
||||
public CompoundTag setTag(String name, Object data) {
|
||||
super.put(name, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
package main.nbt;
|
||||
|
||||
import main.exception.NBTException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ListTag extends ArrayList<Object> {
|
||||
|
||||
public short type;
|
||||
|
||||
public ListTag(short type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
@Override//克隆新的列表标签对象
|
||||
public ListTag clone() {
|
||||
ListTag tag = new ListTag(type);
|
||||
for (int i = 0; i < super.size(); i++) {
|
||||
tag.addTag(TagType.cloneTag(super.get(i)));
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表标签
|
||||
*
|
||||
* @param index 索引
|
||||
* @return 列表标签
|
||||
*/
|
||||
public ListTag getListTag(int index) {
|
||||
return (ListTag) super.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取复合标签
|
||||
*
|
||||
* @param index 索引
|
||||
* @return 复合标签
|
||||
*/
|
||||
public CompoundTag getCompoundTag(int index) {
|
||||
return (CompoundTag) super.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签对象
|
||||
*
|
||||
* @param index 索引
|
||||
* @return 标签对象
|
||||
*/
|
||||
public Object getTag(int index) {
|
||||
return super.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加一个标签
|
||||
*
|
||||
* @param o 欲增加的标签对象
|
||||
* @return 自身
|
||||
* @throws NBTException
|
||||
*/
|
||||
public ListTag addTag(Object o) throws NBTException {
|
||||
if (type == TagType.Object2TagType(o)) {
|
||||
super.add(o);
|
||||
return this;
|
||||
} else {
|
||||
throw new NBTException("List类型错误 不能为:" + o.getClass().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
package main.nbt;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class TagType {
|
||||
public static final short TAG_End = 0;
|
||||
public static final short TAG_Byte = 1;
|
||||
public static final short TAG_Short = 2;
|
||||
public static final short TAG_Int = 3;
|
||||
public static final short TAG_Long = 4;
|
||||
public static final short TAG_Float = 5;
|
||||
public static final short TAG_Double = 6;
|
||||
public static final short TAG_Byte_Array = 7;
|
||||
public static final short TAG_String = 8;
|
||||
public static final short TAG_List = 9;
|
||||
public static final short TAG_Compound = 10;
|
||||
public static final short TAG_Int_Array = 11;
|
||||
public static final short TAG_Long_Array = 12;
|
||||
|
||||
/**
|
||||
* 对象到标签类型
|
||||
*
|
||||
* @param o 对象
|
||||
* @return 标签类型 没有返回-1
|
||||
*/
|
||||
public static short Object2TagType(Object o) {
|
||||
if (o == null)
|
||||
return -1;
|
||||
Class oc = o.getClass();
|
||||
if (oc.equals(Byte.class)) {
|
||||
return TAG_Byte;
|
||||
} else if (oc.equals(Short.class)) {
|
||||
return TAG_Short;
|
||||
} else if (oc.equals(Integer.class)) {
|
||||
return TAG_Int;
|
||||
} else if (oc.equals(Long.class)) {
|
||||
return TAG_Long;
|
||||
} else if (oc.equals(Float.class)) {
|
||||
return TAG_Float;
|
||||
} else if (oc.equals(Double.class)) {
|
||||
return TAG_Double;
|
||||
} else if (oc.equals(byte[].class)) {
|
||||
return TAG_Byte_Array;
|
||||
} else if (oc.equals(String.class)) {
|
||||
return TAG_String;
|
||||
} else if (oc.equals(ListTag.class)) {
|
||||
return TAG_List;
|
||||
} else if (oc.equals(CompoundTag.class)) {
|
||||
return TAG_Compound;
|
||||
} else if (oc.equals(int[].class)) {
|
||||
return TAG_Int_Array;
|
||||
} else if (oc.equals(long[].class)) {
|
||||
return TAG_Long_Array;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标签类型取标签类型名
|
||||
*
|
||||
* @param type 标签类型
|
||||
* @return 标签类型名
|
||||
*/
|
||||
public static String TagType2Str(short type) {
|
||||
return switch (type) {
|
||||
case TAG_End -> "TAG_End";
|
||||
case TAG_Byte -> "TAG_Byte";
|
||||
case TAG_Short -> "TAG_Short";
|
||||
case TAG_Int -> "TAG_Int";
|
||||
case TAG_Long -> "TAG_LONG";
|
||||
case TAG_Float -> "TAG_Float";
|
||||
case TAG_Double -> "TAG_Double";
|
||||
case TAG_Byte_Array -> "TAG_Byte_Array";
|
||||
case TAG_String -> "TAG_String";
|
||||
case TAG_List -> "TAG_List";
|
||||
case TAG_Compound -> "TAG_Compound";
|
||||
case TAG_Int_Array -> "TAG_Int_Array";
|
||||
case TAG_Long_Array -> "TAG_Long_Array";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制标签
|
||||
*
|
||||
* @param object 欲复制的标签对象
|
||||
* @return 新的标签对象
|
||||
*/
|
||||
public static Object cloneTag(Object object) {
|
||||
return switch (TagType.Object2TagType(object)) {
|
||||
case TAG_Byte_Array -> ((byte[]) object).clone();
|
||||
case TAG_List -> ((ListTag) object).clone();
|
||||
case TAG_Compound -> ((CompoundTag) object).clone();
|
||||
case TAG_Int_Array -> ((int[]) object).clone();
|
||||
case TAG_Long_Array -> ((long[]) object).clone();
|
||||
default -> object;
|
||||
};
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user