Partial export-to-vanilla

This commit is contained in:
ayunami2000 2022-08-01 23:54:25 -04:00
parent 09783034b2
commit a013bf69b1
8 changed files with 31921 additions and 31537 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,19 +1,19 @@
package net.lax1dude.eaglercraft.sp; package net.lax1dude.eaglercraft.sp;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.zip.GZIPInputStream; import java.util.Map;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import net.minecraft.src.NBTBase; import net.minecraft.src.ChunkCoordIntPair;
import org.teavm.jso.JSBody; import org.teavm.jso.JSBody;
import org.teavm.jso.JSFunctor; import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
@ -287,6 +287,89 @@ public class IntegratedServer {
throwExceptionToClient("Failed to export world '" + pkt.worldName + "' as EPK", t); throwExceptionToClient("Failed to export world '" + pkt.worldName + "' as EPK", t);
sendTaskFailed(); sendTaskFailed();
} }
}else if(pkt.request == IPCPacket05RequestData.REQUEST_LEVEL_MCA) {
try {
final int[] bytesWritten = new int[1];
final int[] lastUpdate = new int[1];
String pfx = "worlds/" + pkt.worldName + "/";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream c = new ZipOutputStream(baos);
c.setComment("contains backup of world '" + pkt.worldName + "'");
Map<ChunkCoordIntPair, byte[]> regions = new HashMap<>();
Map<ChunkCoordIntPair, byte[]> regions1 = new HashMap<>();
Map<ChunkCoordIntPair, byte[]> regionsn1 = new HashMap<>();
SYS.VFS.iterateFiles(pfx, false, (i) -> {
String currPath = i.path.substring(pfx.length());
System.out.println(currPath); // 12yee
try {
byte[] b = i.getAllBytes();
if (currPath.startsWith("region/")) {
regions.put(VFSChunkLoader.getChunkCoords(currPath.substring(7, -4)), b);
} else if (currPath.startsWith("DIM1/region/")) {
regions1.put(VFSChunkLoader.getChunkCoords(currPath.substring(12, -4)), b);
} else if (currPath.startsWith("DIM-1/region/")) {
regionsn1.put(VFSChunkLoader.getChunkCoords(currPath.substring(13, -4)), b);
} else {
ZipEntry zipEntry = new ZipEntry(currPath);
c.putNextEntry(zipEntry);
c.write(b); // 12yee
c.closeEntry();
bytesWritten[0] += b.length;
if (bytesWritten[0] - lastUpdate[0] > 10000) {
lastUpdate[0] = bytesWritten[0];
updateStatusString("selectWorld.progress.exporting." + pkt.request, bytesWritten[0]);
}
}
} catch (Throwable t) {
throwExceptionToClient("Failed to export file '" + currPath + "'", t);
sendTaskFailed();
}
});
Map<String, byte[]> regionsOut = MCAConverter.convertToMCA(regions);
for (String path : regionsOut.keySet()) {
byte[] b = regionsOut.get(path);
ZipEntry zipEntry = new ZipEntry("region/" + path + ".dat");
c.putNextEntry(zipEntry);
c.write(b); // 12yee
c.closeEntry();
bytesWritten[0] += b.length;
if (bytesWritten[0] - lastUpdate[0] > 10000) {
lastUpdate[0] = bytesWritten[0];
updateStatusString("selectWorld.progress.exporting." + pkt.request, bytesWritten[0]);
}
}
Map<String, byte[]> regions1Out = MCAConverter.convertToMCA(regions1);
for (String path : regions1Out.keySet()) {
byte[] b = regions1Out.get(path);
ZipEntry zipEntry = new ZipEntry("DIM1/region/" + path + ".dat");
c.putNextEntry(zipEntry);
c.write(b); // 12yee
c.closeEntry();
bytesWritten[0] += b.length;
if (bytesWritten[0] - lastUpdate[0] > 10000) {
lastUpdate[0] = bytesWritten[0];
updateStatusString("selectWorld.progress.exporting." + pkt.request, bytesWritten[0]);
}
}
Map<String, byte[]> regionsn1Out = MCAConverter.convertToMCA(regionsn1);
for (String path : regionsn1Out.keySet()) {
byte[] b = regionsn1Out.get(path);
ZipEntry zipEntry = new ZipEntry("DIM-1/region/" + path + ".dat");
c.putNextEntry(zipEntry);
c.write(b); // 12yee
c.closeEntry();
bytesWritten[0] += b.length;
if (bytesWritten[0] - lastUpdate[0] > 10000) {
lastUpdate[0] = bytesWritten[0];
updateStatusString("selectWorld.progress.exporting." + pkt.request, bytesWritten[0]);
}
}
c.close();
sendIPCPacket(new IPCPacket09RequestResponse(baos.toByteArray()));
} catch (Throwable t) {
throwExceptionToClient("Failed to export world '" + pkt.worldName + "' as MCA", t);
sendTaskFailed();
}
}else { }else {
System.err.println("Unknown IPCPacket05RequestData type '" + pkt.request + "'"); System.err.println("Unknown IPCPacket05RequestData type '" + pkt.request + "'");
sendTaskFailed(); sendTaskFailed();
@ -361,9 +444,9 @@ public class IntegratedServer {
List<char[]> fileNames = new ArrayList<>(); List<char[]> fileNames = new ArrayList<>();
while((folderNameFile = folderNames.getNextEntry()) != null) { while((folderNameFile = folderNames.getNextEntry()) != null) {
if (folderNameFile.getName().contains("__MACOSX/")) continue; if (folderNameFile.getName().contains("__MACOSX/")) continue;
if (folderNameFile.getName().toLowerCase().endsWith(".txt")) continue;
if (folderNameFile.getName().toLowerCase().endsWith(".lnk")) continue;
if (folderNameFile.isDirectory()) continue; if (folderNameFile.isDirectory()) continue;
String lowerName = folderNameFile.getName().toLowerCase();
if (!(lowerName.endsWith(".dat") || lowerName.endsWith(".dat_old") || lowerName.endsWith(".dat_mcr") || lowerName.endsWith(".mca") || lowerName.endsWith(".mcr"))) continue;
fileNames.add(folderNameFile.getName().toCharArray()); fileNames.add(folderNameFile.getName().toCharArray());
} }
final int[] i = new int[] { 0 }; final int[] i = new int[] { 0 };
@ -376,9 +459,9 @@ public class IntegratedServer {
byte[] bb = new byte[16000]; byte[] bb = new byte[16000];
while ((f = dc.getNextEntry()) != null) { while ((f = dc.getNextEntry()) != null) {
if (f.getName().contains("__MACOSX/")) continue; if (f.getName().contains("__MACOSX/")) continue;
if (f.getName().toLowerCase().endsWith(".txt")) continue;
if (f.getName().toLowerCase().endsWith(".lnk")) continue;
if (f.isDirectory()) continue; if (f.isDirectory()) continue;
String lowerName = f.getName().toLowerCase();
if (!(lowerName.endsWith(".dat") || lowerName.endsWith(".dat_old") || lowerName.endsWith(".dat_mcr") || lowerName.endsWith(".mca") || lowerName.endsWith(".mcr"))) continue;
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len; int len;
while ((len = dc.read(bb)) != -1) { while ((len = dc.read(bb)) != -1) {
@ -394,7 +477,7 @@ public class IntegratedServer {
b = CompressedStreamTools.compress(worldDatNBT); b = CompressedStreamTools.compress(worldDatNBT);
} }
if (fileName.endsWith(".mcr") || fileName.endsWith(".mca")) { if (fileName.endsWith(".mcr") || fileName.endsWith(".mca")) {
MCAConverter.convertMCA(dir, b, fileName); MCAConverter.convertFromMCA(dir, b, fileName);
} else { } else {
VFile ff = new VFile(dir, fileName); VFile ff = new VFile(dir, fileName);
ff.setAllBytes(b); ff.setAllBytes(b);

View File

@ -1,12 +1,20 @@
package net.lax1dude.eaglercraft.sp; package net.lax1dude.eaglercraft.sp;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import com.jcraft.jzlib.GZIPOutputStream; import com.jcraft.jzlib.GZIPOutputStream;
import net.minecraft.src.ChunkCoordIntPair;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
public class MCAConverter { public class MCAConverter {
public static void convertMCA(VFile dir, byte[] file, String fileName) { public static void convertFromMCA(VFile dir, byte[] file, String fileName) {
VFile levelDir = new VFile(dir, "level" + (fileName.startsWith("region/") ? "0" : fileName.substring(3, fileName.indexOf('/')))); VFile levelDir = new VFile(dir, "level" + (fileName.startsWith("region/") ? "0" : fileName.substring(3, fileName.indexOf('/'))));
String[] xz = fileName.substring(fileName.lastIndexOf('r') + 2, fileName.length() - 4).split("\\."); String[] xz = fileName.substring(fileName.lastIndexOf('r') + 2, fileName.length() - 4).split("\\.");
@ -58,4 +66,81 @@ public class MCAConverter {
e.printStackTrace(); e.printStackTrace();
} }
} }
public static Map<String, byte[]> convertToMCA(Map<ChunkCoordIntPair, byte[]> regions) {
Map<String, byte[]> regionsOut = new HashMap<>();
try {
int timestamp = (int) System.currentTimeMillis();
int maxX = Integer.MIN_VALUE;
int maxZ = Integer.MIN_VALUE;
int minX = Integer.MAX_VALUE;
int minZ = Integer.MAX_VALUE;
for (ChunkCoordIntPair coords : regions.keySet()) {
if (maxX < coords.chunkXPos) maxX = coords.chunkXPos;
if (maxZ < coords.chunkZPos) maxZ = coords.chunkZPos;
if (minX > coords.chunkXPos) minX = coords.chunkXPos;
if (minZ > coords.chunkZPos) minZ = coords.chunkZPos;
}
for (int x = minX - (minX % 32); x <= maxX + (maxX % 32); x += 32) {
for (int z = minZ - (minZ % 32); z <= maxZ + (maxZ % 32); z += 32) {
ByteArrayOutputStream offsets = new ByteArrayOutputStream();
DataOutputStream offsetsDos = new DataOutputStream(offsets);
ByteArrayOutputStream timestamps = new ByteArrayOutputStream();
DataOutputStream timestampsDos = new DataOutputStream(timestamps);
ByteArrayOutputStream chunks = new ByteArrayOutputStream();
DataOutputStream chunksDos = new DataOutputStream(chunks);
for (int cx = 0; cx < 32; ++cx) {
for (int cz = 0; cz < 32; ++cz) {
int tx = x + cx;
int tz = z + cz;
byte[] region = regions.get(new ChunkCoordIntPair(tx, tz));
if (region == null) {
offsetsDos.writeInt(0);
timestampsDos.writeInt(0);
} else {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(baos);
dos.write(region);
dos.close();
byte[] zlibbed = baos.toByteArray();
int offset = chunksDos.size();
offsetsDos.write((offset >> 16) & 0xff);
offsetsDos.write((offset >> 8) & 0xff);
offsetsDos.write(offset & 0xff);
offsetsDos.write(5 + zlibbed.length);
timestampsDos.writeInt(timestamp);
chunksDos.writeInt(region.length);
chunksDos.write(2);
chunksDos.write(zlibbed);
}
}
}
offsetsDos.close();
timestampsDos.close();
chunksDos.close();
byte[] offsetsOut = offsets.toByteArray();
byte[] timestampsOut = timestamps.toByteArray();
byte[] chunksOut = chunks.toByteArray();
byte[] regionFile = new byte[offsetsOut.length + timestampsOut.length + chunksOut.length];
System.arraycopy(offsetsOut, 0, regionFile, 0, offsetsOut.length);
System.arraycopy(timestampsOut, 0, regionFile, offsetsOut.length, timestampsOut.length);
System.arraycopy(chunksOut, 0, regionFile, offsetsOut.length + timestampsOut.length, chunksOut.length);
regionsOut.put("r." + (x / 32) + "." + (z / 32), regionFile);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return regionsOut;
}
} }

View File

@ -5,6 +5,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import net.minecraft.src.Chunk; import net.minecraft.src.Chunk;
import net.minecraft.src.ChunkCoordIntPair;
import net.minecraft.src.CompressedStreamTools; import net.minecraft.src.CompressedStreamTools;
import net.minecraft.src.Entity; import net.minecraft.src.Entity;
import net.minecraft.src.EntityList; import net.minecraft.src.EntityList;
@ -37,6 +38,21 @@ public class VFSChunkLoader implements IChunkLoader {
return new String(path); return new String(path);
} }
public static ChunkCoordIntPair getChunkCoords(String filename) {
String strX = filename.substring(0, 6);
String strZ = filename.substring(6);
int retX = 0;
int retZ = 0;
for(int i = 0; i < 6; ++i) {
retX |= hex.indexOf(strX.charAt(i)) << (i << 2);
retZ |= hex.indexOf(strZ.charAt(i)) << (i << 2);
}
return new ChunkCoordIntPair(retX - 1900000, retZ - 1900000);
}
public VFSChunkLoader(VFile chunkDirectory) { public VFSChunkLoader(VFile chunkDirectory) {
this.chunkDirectory = chunkDirectory; this.chunkDirectory = chunkDirectory;
} }

View File

@ -79,7 +79,15 @@ public class GuiScreenBackupWorld extends GuiScreen {
return false; return false;
})); }));
}else if(par1GuiButton.id == 4) { }else if(par1GuiButton.id == 4) {
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "export vanilla 1.5.2 world")); IntegratedServer.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_MCA);
this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(selectWorld, "selectWorld.progress.exporting.1", () -> {
byte[] b = IntegratedServer.getExportResponse();
if(b != null) {
EaglerAdapter.downloadBytes(worldName + ".zip", b);
return true;
}
return false;
}));
} }
} }
} }