This commit is contained in:
zedoCN 2023-04-28 17:49:52 +08:00
parent c72e17b4ac
commit f91165ca6d
19 changed files with 0 additions and 2590 deletions

View File

@ -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>

View File

@ -1 +0,0 @@

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}
}

View File

@ -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);
}
}

View File

@ -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]);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
});
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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;
};
}
}