world list and export/import buttons added to singleplayer

This commit is contained in:
LAX1DUDE 2022-03-05 04:00:08 -08:00
parent f6ab8847c6
commit a1a25e12d3
36 changed files with 55427 additions and 42917 deletions

View File

@ -1,3 +1,5 @@
To quickly recompile the assets.epk file in /javascript, open 'run.bat' if you are on windows or open 'run_unix.sh' if you are on mac or linux
Use this tool like this:
java -jar CompilePackage.jar <source directory> <output file>

3
epkcompiler/run.bat Normal file
View File

@ -0,0 +1,3 @@
@echo off
java -jar CompilePackage.jar "../lwjgl-rundir/resources" "../javascript/assets.epk"
pause

2
epkcompiler/run_unix.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar CompilePackage.jar "../lwjgl-rundir/resources" "../javascript/assets.epk"

Binary file not shown.

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

@ -11,6 +11,7 @@ gui.up=Up
gui.down=Down
gui.yes=Yes
gui.no=No
gui.killTask=Kill Task
menu.singleplayer=Singleplayer
menu.multiplayer=Multiplayer
@ -72,6 +73,9 @@ selectWorld.enterSeed=Seed for the World Generator
selectWorld.seedInfo=Leave blank for a random seed
selectWorld.cheats=Cheats
selectWorld.customizeType=Customize
selectWorld.duplicateTitle=Duplicate World
selectWorld.duplicateButton=Duplicate
selectWorld.importName=Set World Name
selectWorld.backup.title=World Backup Menu:
selectWorld.backup.recreate=Re-Create World
@ -137,6 +141,17 @@ selectWorld.hardcoreMode=Hardcore:
selectWorld.hardcoreMode.info=World is deleted upon death
selectWorld.bonusItems=Bonus Chest:
selectWorld.progress.deleting=Deleting World
selectWorld.progress.renaming=Renaming World
selectWorld.progress.copying=Copying World
selectWorld.progress.exporting.1=Exporting as EPK
selectWorld.progress.exporting.2=Exporting as Vanilla
selectWorld.progress.importing.0=Importing as EPK
selectWorld.progress.importing.1=Importing as Vanilla
selectWorld.progress.cancelWarning=Do you really want to 'Kill Task'? Your world may fail to save
selectWorld.progress.confirmCancel=Yes, Kill Task
selectWorld.progress.continue=Continue
generator.default=Default
generator.flat=Superflat
generator.largeBiomes=Large Biomes

View File

@ -10,6 +10,10 @@ public class IPCPacket07ImportWorld implements IPCPacketBase {
public String worldName;
public byte[] worldData;
public byte worldFormat;
public static final byte WORLD_FORMAT_EAG = 0x00;
public static final byte WORLD_FORMAT_MCA = 0x01;
public IPCPacket07ImportWorld() {
}
@ -17,12 +21,14 @@ public class IPCPacket07ImportWorld implements IPCPacketBase {
public IPCPacket07ImportWorld(String worldName, byte[] worldData, byte worldFormat) {
this.worldName = worldName;
this.worldData = worldData;
this.worldFormat = worldFormat;
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldName = bin.readUTF();
worldData = new byte[bin.readInt()];
worldFormat = bin.readByte();
bin.readFully(worldData);
}
@ -30,6 +36,7 @@ public class IPCPacket07ImportWorld implements IPCPacketBase {
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
bin.writeInt(worldData.length);
bin.writeByte(worldFormat);
bin.write(worldData);
}

View File

@ -9,6 +9,7 @@ public class IPCPacketFFProcessKeepAlive implements IPCPacketBase {
public static final int ID = 0xFF;
public static final int KEEPALIVE = 0;
public static final int FAILURE = 0xFE;
public int ack;

View File

@ -0,0 +1,58 @@
package net.lax1dude.eaglercraft.sp;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.nio.charset.Charset;
import com.jcraft.jzlib.Deflater;
import com.jcraft.jzlib.DeflaterOutputStream;
public class EPKCompiler {
private final ByteArrayOutputStream osb = new ByteArrayOutputStream();
private DataOutputStream os;
private Deflater d;
private final SHA1Digest dig = new SHA1Digest();
public EPKCompiler(String name) {
try {
d = new Deflater(9);
os = new DataOutputStream(osb);
os.write("EAGPKG!!".getBytes(Charset.forName("UTF-8")));
os.writeUTF("\n\n # eaglercraft package file - " + name + "\n # eagler eagler eagler eagler eagler eagler eagler\n\n");
d = new Deflater(9);
os = new DataOutputStream(new DeflaterOutputStream(osb, d));
}catch(Throwable t) {
throw new RuntimeException("this happened somehow", t);
}
}
public void append(String name, byte[] dat) {
try {
os.writeUTF("<file>");
os.writeUTF(name);
byte[] v = dat;
dig.update(v, 0, v.length);
byte[] final_ = new byte[20];
dig.doFinal(final_, 0);
os.write(final_);
os.writeInt(v.length);
os.write(v);
os.writeUTF("</file>");
}catch(Throwable t) {
throw new RuntimeException("this happened somehow", t);
}
}
public byte[] complete() {
try {
os.writeUTF(" end");
os.flush();
os.close();
return osb.toByteArray();
}catch(Throwable t) {
throw new RuntimeException("this happened somehow", t);
}
}
}

View File

@ -0,0 +1,61 @@
package net.lax1dude.eaglercraft.sp;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import com.jcraft.jzlib.InflaterInputStream;
public class EPKDecompiler {
public static class FileEntry {
public final String name;
public final byte[] data;
protected FileEntry(String name, byte[] data) {
this.name = name;
this.data = data;
}
}
private final ByteArrayInputStream in2;
private DataInputStream in;
private SHA1Digest dg = new SHA1Digest();
private boolean isFinished = false;
public EPKDecompiler(byte[] data) throws IOException {
in2 = new ByteArrayInputStream(data);
in = new DataInputStream(in2);
byte[] header = new byte[8];
in.read(header);
if(!"EAGPKG!!".equals(new String(header, Charset.forName("UTF-8")))) throw new IOException("invalid epk file");
in.readUTF();
in = new DataInputStream(new InflaterInputStream(in2));
}
public FileEntry readFile() throws IOException {
if(isFinished) {
return null;
}
String s = in.readUTF();
if(s.equals(" end")) {
isFinished = true;
return null;
}else if(!s.equals("<file>")) {
throw new IOException("invalid epk file");
}
String path = in.readUTF();
byte[] digest = new byte[20];
byte[] digest2 = new byte[20];
in.read(digest);
int len = in.readInt();
byte[] file = new byte[len];
in.read(file);
dg.update(file, 0, len); dg.doFinal(digest2, 0);
if(!Arrays.equals(digest, digest2)) throw new IOException("invalid file hash for "+path);
if(!"</file>".equals(in.readUTF())) throw new IOException("invalid epk file");
return new FileEntry(path, file);
}
}

View File

@ -88,6 +88,10 @@ public class IntegratedServer {
}
}
public static void updateStatusString(String stat, float prog) {
sendIPCPacket(new IPCPacket0DProgressUpdate(stat, prog));
}
private static boolean isServerStopped() {
return currentProcess == null || !currentProcess.isServerRunning();
}
@ -104,6 +108,10 @@ public class IntegratedServer {
sendIPCPacket(new IPCPacket15ThrowException(str, arr));
}
public static void sendTaskFailed() {
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacketFFProcessKeepAlive.FAILURE));
}
private static void processAsyncMessageQueue() {
ArrayList<PKT> cur;
synchronized(messageQueue) {
@ -207,8 +215,20 @@ public class IntegratedServer {
case IPCPacket03DeleteWorld.ID: {
tryStopServer();
IPCPacket03DeleteWorld pkt = (IPCPacket03DeleteWorld)packet;
if(SYS.VFS.deleteFiles("worlds/" + pkt.worldName) <= 0) {
if(SYS.VFS.deleteFiles("worlds/" + pkt.worldName + "/") <= 0) {
throwExceptionToClient("Failed to delete world!", new RuntimeException("VFS did not delete directory 'worlds/" + pkt.worldName + "' correctly"));
sendTaskFailed();
break;
}
String[] worldsTxt = SYS.VFS.getFile("worlds.txt").getAllLines();
if(worldsTxt != null) {
LinkedList<String> newWorlds = new LinkedList();
for(String str : worldsTxt) {
if(!str.equalsIgnoreCase(pkt.worldName)) {
newWorlds.add(str);
}
}
SYS.VFS.getFile("worlds.txt").setAllChars(String.join("\n", newWorlds));
}
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket03DeleteWorld.ID));
}
@ -216,23 +236,63 @@ public class IntegratedServer {
case IPCPacket04RenameWorld.ID: {
tryStopServer();
IPCPacket04RenameWorld pkt = (IPCPacket04RenameWorld)packet;
if(SYS.VFS.renameFiles("worlds/" + pkt.worldOldName, "worlds/" + pkt.worldNewName, pkt.copy) <= 0) {
if(SYS.VFS.renameFiles("worlds/" + pkt.worldOldName + "/", "worlds/" + pkt.worldNewName + "/", pkt.copy) <= 0) {
throwExceptionToClient("Failed to copy/rename server!", new RuntimeException("VFS did not copy/rename directory 'worlds/" + pkt.worldOldName + "' correctly"));
sendTaskFailed();
break;
}else {
String[] worldsTxt = SYS.VFS.getFile("worlds.txt").getAllLines();
LinkedList<String> newWorlds = new LinkedList();
if(worldsTxt != null) {
for(String str : worldsTxt) {
if(pkt.copy || !str.equalsIgnoreCase(pkt.worldOldName)) {
newWorlds.add(str);
}
}
}
newWorlds.add(pkt.worldNewName);
SYS.VFS.getFile("worlds.txt").setAllChars(String.join("\n", newWorlds));
VFile worldDat = new VFile("worlds", pkt.worldNewName, "level.dat");
if(worldDat.canRead()) {
NBTTagCompound worldDatNBT = CompressedStreamTools.decompress(worldDat.getAllBytes());
worldDatNBT.setString("LevelName", pkt.displayName);
worldDatNBT.getCompoundTag("Data").setString("LevelName", pkt.displayName);
worldDat.setAllBytes(CompressedStreamTools.compress(worldDatNBT));
}else {
throwExceptionToClient("Failed to copy/rename world!", new RuntimeException("Failed to change level.dat world '" + pkt.worldNewName + "' display name to '" + pkt.displayName + "' because level.dat was missing"));
sendTaskFailed();
break;
}
}
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket04RenameWorld.ID));
}
break;
case IPCPacket05RequestData.ID:
case IPCPacket05RequestData.ID: {
IPCPacket05RequestData pkt = (IPCPacket05RequestData)packet;
if(pkt.request == IPCPacket05RequestData.REQUEST_LEVEL_EAG) {
try {
final int[] bytesWritten = new int[1];
final int[] lastUpdate = new int[1];
String pfx = "worlds/" + pkt.worldName + "/";
EPKCompiler c = new EPKCompiler("contains backup of world '" + pkt.worldName + "'");
SYS.VFS.iterateFiles(pfx, false, (i) -> {
byte[] b = i.getAllBytes();
c.append(i.path.substring(pfx.length()), b);
bytesWritten[0] += b.length;
if(bytesWritten[0] - lastUpdate[0] > 10000) {
lastUpdate[0] = bytesWritten[0];
updateStatusString("selectWorld.progress.exporting." + pkt.request, bytesWritten[0]);
}
});
sendIPCPacket(new IPCPacket09RequestResponse(c.complete()));
}catch(Throwable t) {
throwExceptionToClient("Failed to export world '" + pkt.worldName + "' as EPK", t);
sendTaskFailed();
}
}else {
System.err.println("Unknown IPCPacket05RequestData type '" + pkt.request + "'");
sendTaskFailed();
}
}
break;
case IPCPacket06RenameWorldNBT.ID: {
IPCPacket06RenameWorldNBT pkt = (IPCPacket06RenameWorldNBT)packet;
@ -240,18 +300,63 @@ public class IntegratedServer {
VFile worldDat = new VFile("worlds", pkt.worldName, "level.dat");
if(worldDat.canRead()) {
NBTTagCompound worldDatNBT = CompressedStreamTools.decompress(worldDat.getAllBytes());
worldDatNBT.setString("LevelName", pkt.displayName);
worldDatNBT.getCompoundTag("Data").setString("LevelName", pkt.displayName);
worldDat.setAllBytes(CompressedStreamTools.compress(worldDatNBT));
}else {
throwExceptionToClient("Failed to rename world!", new RuntimeException("Failed to change level.dat world '" + pkt.worldName + "' display name to '" + pkt.displayName + "' because level.dat was missing"));
}
}else {
System.err.println("Client tried to rename a world '" + pkt.worldName + "' to have name '" + pkt.displayName + "' while the server is running");
sendTaskFailed();
}
}
break;
case IPCPacket07ImportWorld.ID:
case IPCPacket07ImportWorld.ID: {
IPCPacket07ImportWorld pkt = (IPCPacket07ImportWorld)packet;
if(pkt.worldFormat == IPCPacket07ImportWorld.WORLD_FORMAT_EAG) {
try {
String folder = VFSSaveHandler.worldNameToFolderName(pkt.worldName);
VFile dir = new VFile("worlds", folder);
EPKDecompiler dc = new EPKDecompiler(pkt.worldData);
EPKDecompiler.FileEntry f = null;
int lastProgUpdate = 0;
int prog = 0;
while((f = dc.readFile()) != null) {
byte[] b = f.data;
if(f.name.equals("level.dat")) {
NBTTagCompound worldDatNBT = CompressedStreamTools.decompress(b);
worldDatNBT.getCompoundTag("Data").setString("LevelName", pkt.worldName);
worldDatNBT.getCompoundTag("Data").setLong("LastPlayed", System.currentTimeMillis());
b = CompressedStreamTools.compress(worldDatNBT);
}
VFile ff = new VFile(dir, f.name);
ff.setAllBytes(b);
prog += b.length;
if(prog - lastProgUpdate > 10000) {
lastProgUpdate = prog;
updateStatusString("selectWorld.progress.importing." + pkt.worldFormat, prog);
}
}
String[] worldsTxt = SYS.VFS.getFile("worlds.txt").getAllLines();
if(worldsTxt == null || worldsTxt.length <= 0) {
worldsTxt = new String[] { folder };
}else {
String[] tmp = worldsTxt;
worldsTxt = new String[worldsTxt.length + 1];
System.arraycopy(tmp, 0, worldsTxt, 0, tmp.length);
worldsTxt[worldsTxt.length - 1] = folder;
}
SYS.VFS.getFile("worlds.txt").setAllChars(String.join("\n", worldsTxt));
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket07ImportWorld.ID));
}catch(Throwable t) {
throwExceptionToClient("Failed to import world '" + pkt.worldName + "' as EPK", t);
sendTaskFailed();
}
}else {
System.err.println("Client tried to import a world '" + pkt.worldName + "' while the server is running");
sendTaskFailed();
}
}
break;
case IPCPacket09RequestResponse.ID:
@ -262,6 +367,7 @@ public class IntegratedServer {
currentProcess.setDifficultyForAllWorlds(pkt.difficulty);
}else {
System.err.println("Client tried to set difficulty '" + pkt.difficulty + "' while server was stopped");
sendTaskFailed();
}
}
break;
@ -279,6 +385,7 @@ public class IntegratedServer {
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket0BPause.ID));
}else {
System.err.println("Client tried to " + (pkt.pause ? "pause" : "unpause") + " while server was stopped");
sendTaskFailed();
}
}
break;
@ -314,29 +421,25 @@ public class IntegratedServer {
LinkedList<NBTTagCompound> sendListNBT = new LinkedList();
boolean rewrite = false;
for(String w : worlds) {
VFile lvl = new VFile("worlds", w, "level.dat");
if(!lvl.canRead()) {
rewrite = true;
System.err.println("World level.dat for '" + w + "' was not found, attempting to delete 'worlds/" + w + "/*'");
if(SYS.VFS.deleteFiles("worlds/" + w) <= 0) {
System.err.println("No files were deleted in 'worlds/" + w + "/*', this may be corruption but '" + w + "' will still be removed from worlds.txt");
}
}else {
byte[] dat = (new VFile("worlds", w, "level.dat")).getAllBytes();
if(dat != null) {
NBTTagCompound worldDatNBT;
try {
worldDatNBT = CompressedStreamTools.decompress(lvl.getAllBytes());
worldDatNBT = CompressedStreamTools.decompress(dat);
worldDatNBT.setString("folderName", w);
sendListNBT.add(worldDatNBT);
updatedList.add(w);
continue;
}catch(IOException e) {
rewrite = true;
System.err.println("World level.dat for '" + w + "' was corrupt, attempting to delete 'worlds/" + w + "/*'");
if(SYS.VFS.deleteFiles("worlds/" + w) <= 0) {
System.err.println("No files were deleted in 'worlds/" + w + "/*', this may be corruption but '" + w + "' will still be removed from worlds.txt");
}
// shit fuck
}
}
rewrite = true;
System.err.println("World level.dat for '" + w + "' was not found, attempting to delete 'worlds/" + w + "/*'");
if(SYS.VFS.deleteFiles("worlds/" + w) <= 0) {
System.err.println("No files were deleted in 'worlds/" + w + "/*', this may be corruption but '" + w + "' will still be removed from worlds.txt");
}
}
if(rewrite) {
SYS.VFS.getFile("worlds.txt").setAllChars(String.join("\n", updatedList));
@ -344,6 +447,7 @@ public class IntegratedServer {
sendIPCPacket(new IPCPacket16NBTList(IPCPacket16NBTList.WORLD_LIST, sendListNBT));
}else {
System.err.println("Client tried to list worlds while server was running");
sendTaskFailed();
}
}
break;
@ -377,11 +481,14 @@ public class IntegratedServer {
break;
default:
System.err.println("IPC packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' was not handled");
sendTaskFailed();
break;
}
}catch(Throwable t) {
System.err.println("IPC packet 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' was not processed correctly");
t.printStackTrace();
String str = "IPC packet 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' was not processed correctly";
System.err.println(str);
throwExceptionToClient(str, t);
sendTaskFailed();
}
continue;

View File

@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.sp;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import net.minecraft.src.CompressedStreamTools;
import net.minecraft.src.EntityPlayer;
@ -155,4 +156,18 @@ public class VFSSaveHandler implements ISaveHandler, IPlayerFileData {
return null;
}
public static String worldNameToFolderName(String par1Str) {
par1Str = par1Str.replaceAll("[\\./\"]", "_");
boolean shit = true;
while(shit) {
shit = (new VFile("worlds", par1Str, "level.dat")).exists();
if(shit) {
par1Str = par1Str + "_";
}
}
return par1Str;
}
}

View File

@ -280,15 +280,17 @@ public class VirtualFilesystem {
if(!AsyncHandlers.writeWholeFile(virtualFilesystem.indexeddb, newName, arr).bool) {
return false;
}
if(!AsyncHandlers.deleteFile(virtualFilesystem.indexeddb, filePath).bool) {
if(!copy && !AsyncHandlers.deleteFile(virtualFilesystem.indexeddb, filePath).bool) {
return false;
}
}else {
exists = false;
}
virtualFilesystem.fileMap.remove(filePath);
filePath = newName;
virtualFilesystem.fileMap.put(newName, this);
if(!copy) {
virtualFilesystem.fileMap.remove(filePath);
filePath = newName;
virtualFilesystem.fileMap.put(newName, this);
}
return true;
}
return false;
@ -557,7 +559,7 @@ public class VirtualFilesystem {
@Override
public void handleEvent() {
IDBCursor c = r.getResult();
if(c == null || c.getKey() == null) {
if(c == null || c.getKey() == null || c.getValue() == null) {
cb.complete(res[0]);
return;
}
@ -569,6 +571,7 @@ public class VirtualFilesystem {
itr.next(VIteratorFile.create(ci, vfs, c));
}catch(VFSIterator.BreakLoop ex) {
cb.complete(res[0]);
return;
}
}
}
@ -594,7 +597,7 @@ public class VirtualFilesystem {
@Override
public void handleEvent() {
IDBCursor c = r.getResult();
if(c == null || c.getKey() == null) {
if(c == null || c.getKey() == null || c.getValue() == null) {
cb.complete(res[0]);
return;
}

View File

@ -148,8 +148,15 @@ public abstract class MinecraftServer implements ICommandSender, Runnable {
/**
* Typically "menu.convertingLevel", "menu.loadingLevel" or others.
*/
protected synchronized void setUserMessage(String par1Str) {
protected void setUserMessage(String par1Str) {
IntegratedServer.sendIPCPacket(new IPCPacket0DProgressUpdate(par1Str, 0.0f));
this.logInfo(par1Str);
this.userMessage = par1Str;
}
protected void setUserMessage(String par1Str, float prog) {
IntegratedServer.sendIPCPacket(new IPCPacket0DProgressUpdate(par1Str, prog));
this.logInfo(par1Str + ": " + (prog > 1.0f ? "" + (int)prog : "" + (int)(prog * 100.0f) + "%"));
this.userMessage = par1Str;
}
@ -195,26 +202,27 @@ public abstract class MinecraftServer implements ICommandSender, Runnable {
}
this.setDifficultyForAllWorlds(this.getDifficulty());
this.setGameType(var8.getGameType());
this.initialWorldChunkLoad();
}
protected void initialWorldChunkLoad() {
int var5 = 0;
this.setUserMessage("menu.generatingTerrain");
//this.setUserMessage("menu.generatingTerrain");
byte var6 = 0;
this.getLogAgent().func_98233_a("Preparing start region for level " + var6);
this.setUserMessage("Preparing start region for level " + var6);
WorldServer var7 = this.worldServers[var6];
ChunkCoordinates var8 = var7.getSpawnPoint();
long var9 = System.currentTimeMillis();
int prepareRadius = 48;
int prepareRadius = 64;
for (int var11 = -prepareRadius; var11 <= prepareRadius && this.isServerRunning(); var11 += 16) {
for (int var12 = -prepareRadius; var12 <= prepareRadius && this.isServerRunning(); var12 += 16) {
long var13 = System.currentTimeMillis();
if (var13 - var9 > 1000L) {
this.outputPercentRemaining("Preparing spawn area", var5 * 100 / 625);
setUserMessage("Preparing spawn area", Math.min(var5 / 64.0f, 0.99f));
var9 = var13;
}
@ -247,7 +255,7 @@ public abstract class MinecraftServer implements ICommandSender, Runnable {
protected void outputPercentRemaining(String par1Str, int par2) {
this.currentTask = par1Str;
this.percentDone = par2;
this.getLogAgent().func_98233_a(par1Str + ": " + par2 + "%");
setUserMessage(par1Str, (par2 / 100.0f));
}
/**
@ -270,10 +278,7 @@ public abstract class MinecraftServer implements ICommandSender, Runnable {
WorldServer var5 = var2[var4];
if (var5 != null) {
if (!par1) {
this.getLogAgent().func_98233_a("Saving chunks for level \'"
+ var5.getWorldInfo().getWorldName() + "\'/" + var5.provider.getDimensionName());
}
setUserMessage("Saving chunks for level \'" + var5.getWorldInfo().getWorldName() + "\'/" + var5.provider.getDimensionName());
try {
var5.saveAllChunks(true, (IProgressUpdate) null);
@ -290,7 +295,7 @@ public abstract class MinecraftServer implements ICommandSender, Runnable {
*/
public void stopServer() {
if (!this.worldIsBeingDeleted) {
this.getLogAgent().func_98233_a("Stopping server");
setUserMessage("Stopping server");
if (this.getNetworkThread() != null) {
this.getNetworkThread().stopListening();
@ -302,7 +307,7 @@ public abstract class MinecraftServer implements ICommandSender, Runnable {
this.serverConfigManager.removeAllPlayers();
}
this.getLogAgent().func_98233_a("Saving worlds");
setUserMessage("Saving worlds");
this.saveAllWorlds(false);
for (int var1 = 0; var1 < this.worldServers.length; ++var1) {

View File

@ -8,7 +8,7 @@ public class ItemMap extends ItemMapBase {
public MapData getMapData(ItemStack par1ItemStack, World par2World) {
String var3 = "map_" + par1ItemStack.getItemDamage();
MapData var4 = (MapData) par2World.loadItemData(MapData.class, var3);
MapData var4 = (MapData) par2World.loadItemData((s) -> new MapData(s), var3);
if (var4 == null && !par2World.isRemote) {
par1ItemStack.setItemDamage(par2World.getUniqueDataId("map"));

View File

@ -8,6 +8,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.lax1dude.eaglercraft.sp.VFile;
@ -36,7 +37,7 @@ public class MapStorage {
* instantiating the given Class, or returns null if none such file exists.
* args: Class to instantiate, String dataid
*/
public WorldSavedData loadData(Class par1Class, String par2Str) {
public WorldSavedData loadData(Function<String, WorldSavedData> par1Class, String par2Str) {
WorldSavedData var3 = (WorldSavedData) this.loadedDataMap.get(par2Str);
if (var3 != null) {
@ -48,8 +49,7 @@ public class MapStorage {
if (var4 != null && var4.exists()) {
try {
var3 = (WorldSavedData) par1Class.getConstructor(new Class[] { String.class })
.newInstance(new Object[] { par2Str });
var3 = (WorldSavedData) par1Class.apply(par2Str);
} catch (Exception var7) {
throw new RuntimeException("Failed to instantiate " + par1Class.toString(), var7);
}

View File

@ -7,6 +7,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import net.lax1dude.eaglercraft.sp.EaglercraftRandom;
@ -177,15 +178,15 @@ public abstract class World implements IBlockAccess {
this.worldInfo.setServerInitialized(true);
}
//VillageCollection var7 = (VillageCollection) this.mapStorage.loadData(VillageCollection.class, "villages");
VillageCollection var7 = (VillageCollection) this.mapStorage.loadData((s) -> new VillageCollection(s), "villages");
//if (var7 == null) {
if (var7 == null) {
this.villageCollectionObj = new VillageCollection(this);
this.mapStorage.setData("villages", this.villageCollectionObj);
//} else {
// this.villageCollectionObj = var7;
// this.villageCollectionObj.func_82566_a(this);
//}
} else {
this.villageCollectionObj = var7;
this.villageCollectionObj.func_82566_a(this);
}
this.calculateInitialSkylight();
this.calculateInitialWeather();
@ -3056,7 +3057,7 @@ public abstract class World implements IBlockAccess {
* using the MapStorage, instantiating the given Class, or returns null if none
* such file exists. args: Class to instantiate, String dataid
*/
public WorldSavedData loadItemData(Class par1Class, String par2Str) {
public WorldSavedData loadItemData(Function<String, WorldSavedData> par1Class, String par2Str) {
return this.mapStorage.loadData(par1Class, par2Str);
}

View File

@ -78,7 +78,7 @@ public class WorldServer extends World {
this.field_85177_Q = new Teleporter(this);
this.worldScoreboard = new ServerScoreboard(par1MinecraftServer);
ScoreboardSaveData var8 = (ScoreboardSaveData) this.mapStorage.loadData(ScoreboardSaveData.class, "scoreboard");
ScoreboardSaveData var8 = (ScoreboardSaveData) this.mapStorage.loadData((s) -> new ScoreboardSaveData(s), "scoreboard");
if (var8 == null) {
var8 = new ScoreboardSaveData();

View File

@ -1010,6 +1010,9 @@ public class EaglerAdapterImpl2 {
});
}
public static final boolean getFileChooserResultAvailable() {
return fileChooserFile != null;
}
public static final byte[] getFileChooserResult() {
byte[] b = fileChooserFile;
fileChooserFile = null;
@ -1208,4 +1211,8 @@ public class EaglerAdapterImpl2 {
throw new UnsupportedOperationException("Integrated server is not available in LWJGL eagleradapter");
}
public static final void downloadBytes(String str, byte[] dat) {
JOptionPane.showMessageDialog(null, "downloadBytes was called for file '" + str + "' with " + dat.length + " bytes");
}
}

View File

@ -4,7 +4,7 @@ public class ConfigConstants {
public static boolean profanity = false;
public static final String version = "22w04b";
public static final String version = "singleplayer snapshot";
public static final String mainMenuString = "eaglercraft " + version;
public static final String forkMe = "https://github.com/LAX1DUDE/eaglercraft";

View File

@ -0,0 +1,122 @@
package net.lax1dude.eaglercraft;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiCreateWorld;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.GuiTextField;
import net.minecraft.src.StringTranslate;
public class GuiNameWorldImport extends GuiScreen {
private GuiScreen parentGuiScreen;
private GuiTextField theGuiTextField;
private int importFormat;
private String name;
private String oldName;
private boolean timeToImport = false;
private boolean definetlyTimeToImport = false;
private boolean isImporting = false;
public GuiNameWorldImport(GuiScreen menu, String name, int format) {
this.parentGuiScreen = menu;
this.importFormat = format;
this.oldName = name;
if(name.length() > 4 && name.endsWith(".epk")) {
name = name.substring(0, name.length() - 4);
}
this.name = name;
}
/**
* Called from the main game loop to update the screen.
*/
public void updateScreen() {
if(!timeToImport) {
this.theGuiTextField.updateCursorCounter();
}
if(definetlyTimeToImport && !isImporting) {
isImporting = true;
IntegratedServer.importWorld(GuiCreateWorld.makeUsableName(this.theGuiTextField.getText().trim()), EaglerAdapter.getFileChooserResult(), importFormat);
mc.displayGuiScreen(new GuiScreenSingleplayerLoading(parentGuiScreen, "selectWorld.progress.importing." + importFormat, () -> IntegratedServer.isReady()));
}
}
/**
* Adds the buttons (and other controls) to the screen in question.
*/
public void initGui() {
if(!timeToImport) {
StringTranslate var1 = StringTranslate.getInstance();
EaglerAdapter.enableRepeatEvents(true);
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, var1.translateKey("selectWorld.progress.continue")));
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, var1.translateKey("gui.cancel")));
this.theGuiTextField = new GuiTextField(this.fontRenderer, this.width / 2 - 100, this.height / 4 + 3, 200, 20);
this.theGuiTextField.setFocused(true);
this.theGuiTextField.setText(name);
}
}
/**
* Called when the screen is unloaded. Used to disable keyboard repeat events
*/
public void onGuiClosed() {
EaglerAdapter.enableRepeatEvents(false);
}
/**
* Fired when a control is clicked. This is the equivalent of
* ActionListener.actionPerformed(ActionEvent e).
*/
protected void actionPerformed(GuiButton par1GuiButton) {
if (par1GuiButton.enabled) {
if (par1GuiButton.id == 1) {
this.mc.displayGuiScreen(this.parentGuiScreen);
} else if (par1GuiButton.id == 0) {
this.buttonList.clear();
timeToImport = true;
}
}
}
/**
* Fired when a key is typed. This is the equivalent of
* KeyListener.keyTyped(KeyEvent e).
*/
protected void keyTyped(char par1, int par2) {
this.theGuiTextField.textboxKeyTyped(par1, par2);
((GuiButton) this.buttonList.get(0)).enabled = this.theGuiTextField.getText().trim().length() > 0;
if (par1 == 13) {
this.actionPerformed((GuiButton) this.buttonList.get(0));
}
}
/**
* Called when the mouse is clicked.
*/
protected void mouseClicked(int par1, int par2, int par3) {
super.mouseClicked(par1, par2, par3);
if(!timeToImport) {
this.theGuiTextField.mouseClicked(par1, par2, par3);
}
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
if(!timeToImport) {
StringTranslate var4 = StringTranslate.getInstance();
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.importName"), this.width / 2, this.height / 4 - 60 + 20, 16777215);
this.drawString(this.fontRenderer, var4.translateKey("selectWorld.enterName"), this.width / 2 - 100, this.height / 4 - 60 + 50, 10526880);
this.theGuiTextField.drawTextBox();
}else {
definetlyTimeToImport = true;
long dots = (System.currentTimeMillis() / 500l) % 4l;
String str = "Reading: '" + oldName + "'";
this.drawString(fontRenderer, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(str)) / 2, this.height / 3 + 10, 0xFFFFFF);
}
super.drawScreen(par1, par2, par3);
}
}

View File

@ -1,8 +1,13 @@
package net.lax1dude.eaglercraft;
import net.lax1dude.eaglercraft.sp.ipc.IPCPacket05RequestData;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiCreateWorld;
import net.minecraft.src.GuiRenameWorld;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.NBTTagCompound;
import net.minecraft.src.StringTranslate;
import net.minecraft.src.WorldInfo;
public class GuiScreenBackupWorld extends GuiScreen {
@ -13,13 +18,15 @@ public class GuiScreenBackupWorld extends GuiScreen {
private GuiButton worldExport = null;
private GuiButton worldConvert = null;
private long worldSeed;
private NBTTagCompound levelDat;
private String worldName;
public GuiScreenBackupWorld(GuiScreen selectWorld, String worldName, long worldSeed) {
public GuiScreenBackupWorld(GuiScreen selectWorld, String worldName, NBTTagCompound levelDat) {
this.selectWorld = selectWorld;
this.worldName = worldName;
this.worldSeed = worldSeed;
this.levelDat = levelDat;
this.worldSeed = levelDat.getCompoundTag("Data").getLong("RandomSeed");
}
public void initGui() {
@ -56,11 +63,21 @@ public class GuiScreenBackupWorld extends GuiScreen {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(selectWorld);
}else if(par1GuiButton.id == 1) {
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "recreate world"));
GuiCreateWorld cw = new GuiCreateWorld(selectWorld);
cw.func_82286_a(new WorldInfo(this.levelDat.getCompoundTag("Data")));
this.mc.displayGuiScreen(cw);
}else if(par1GuiButton.id == 2) {
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "duplicate world"));
this.mc.displayGuiScreen(new GuiRenameWorld(this.selectWorld, this.worldName, true));
}else if(par1GuiButton.id == 3) {
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "export world"));
IntegratedServer.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_EAG);
this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(selectWorld, "selectWorld.progress.exporting.1", () -> {
byte[] b = IntegratedServer.getExportResponse();
if(b != null) {
EaglerAdapter.downloadBytes(worldName + ".epk", b);
return true;
}
return false;
}));
}else if(par1GuiButton.id == 4) {
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "export vanilla 1.5.2 world"));
}

View File

@ -11,6 +11,8 @@ public class GuiScreenCreateWorldSelection extends GuiScreen {
private GuiButton worldCreate = null;
private GuiButton worldImport = null;
private GuiButton worldVanilla = null;
private boolean isImportingEPK = false;
private boolean isImportingMCA = false;
public GuiScreenCreateWorldSelection(GuiScreen mainmenu) {
this.mainmenu = mainmenu;
@ -24,6 +26,13 @@ public class GuiScreenCreateWorldSelection extends GuiScreen {
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 130, var1.translateKey("gui.cancel")));
}
public void updateScreen() {
if(EaglerAdapter.getFileChooserResultAvailable() && (isImportingEPK || isImportingMCA)) {
this.mc.displayGuiScreen(new GuiNameWorldImport(mainmenu, EaglerAdapter.getFileChooserResultName(), isImportingEPK ? 0 : (isImportingMCA ? 1 : -1)));
isImportingEPK = isImportingMCA = false;
}
}
public void drawScreen(int par1, int par2, float par3) {
StringTranslate var4 = StringTranslate.getInstance();
this.drawDefaultBackground();
@ -48,7 +57,8 @@ public class GuiScreenCreateWorldSelection extends GuiScreen {
}else if(par1GuiButton.id == 1) {
this.mc.displayGuiScreen(new GuiCreateWorld(mainmenu));
}else if(par1GuiButton.id == 2) {
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "load world backup"));
isImportingEPK = true;
EaglerAdapter.openFileChooser("epk", null);
}else if(par1GuiButton.id == 3) {
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "import vanilla world"));
}

View File

@ -0,0 +1,72 @@
package net.lax1dude.eaglercraft;
import net.lax1dude.eaglercraft.sp.ipc.IPCPacket15ThrowException;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.StringTranslate;
public class GuiScreenSingleplayerException extends GuiScreen {
private GuiScreen mainmenu;
private IPCPacket15ThrowException exception;
private GuiButton returnToMenu;
private String action;
public GuiScreenSingleplayerException(GuiScreen mainmenu, String action, IPCPacket15ThrowException exception) {
this.mainmenu = mainmenu;
this.action = action;
this.exception = exception;
}
public void initGui() {
this.buttonList.add(returnToMenu = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, StringTranslate.getInstance().translateKey("selectWorld.progress.continue")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
int width_ = this.fontRenderer.getStringWidth(exception.errorMessage);
int numTrace = exception.stackTrace.size();
if(numTrace > 7) {
numTrace = 7;
}
int height_ = numTrace * 10 + 90 + (numTrace >= 7 ? 10 : 0);
for(String s : exception.stackTrace) {
int w = this.fontRenderer.getStringWidth(" " + s);
if(width_ < w) {
width_ = w;
}
}
int top = (this.height - height_) / 2;
if(top < 5) top = 5;
int left = (this.width - width_) / 2;
if(left < 5) left = 5;
this.drawCenteredString(fontRenderer, "An error occured while '" + StringTranslate.getInstance().translateKey(action) + "'", this.width / 2, top, 0xFFAAAA);
this.drawCenteredString(fontRenderer, "eaglercraft singleplayer is incomplete, please DO NOT report", this.width / 2, top + 22, 0xFFFFFF);
this.drawCenteredString(fontRenderer, "this until you obtain a stable release or you will be mocked", this.width / 2, top + 32, 0xFFFFFF);
this.drawString(fontRenderer, exception.errorMessage, left, top + 54, 0xFFAAAA);
for(int i = 0; i < numTrace; ++i) {
this.drawString(fontRenderer, " " + exception.stackTrace.get(i), left, top + 64 + i * 10, 0xFFAAAA);
}
if(numTrace >= 7) {
this.drawCenteredString(fontRenderer, "... " + (exception.size() - numTrace) + " remaining ...", this.width / 2, top + 64 + numTrace * 10, 0xFFAAAA);
}
returnToMenu.yPosition = top + 80 + numTrace * 10 + (numTrace >= 7 ? 10 : 0);
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(mainmenu);
}
}
}

View File

@ -1,44 +1,72 @@
package net.lax1dude.eaglercraft;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import net.lax1dude.eaglercraft.sp.ipc.IPCPacket15ThrowException;
import net.minecraft.client.Minecraft;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiMainMenu;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.StringTranslate;
public class GuiScreenSingleplayerLoading extends GuiScreen {
private GuiScreen menu;
public final GuiScreen menu;
private GuiButton killTask;
private String message;
public final String message;
private BooleanSupplier checkTaskComplete;
private Runnable taskKill;
private String lastStatus;
private String currentStatus;
private BiConsumer<GuiScreen, IPCPacket15ThrowException[]> onException;
private int areYouSure;
private long startStartTime;
private static final Runnable defaultTerminateAction = new Runnable() {
@Override
public void run() {
IntegratedServer.killWorker();
Minecraft.getMinecraft().displayGuiScreen(new GuiMainMenu());
private static final Runnable defaultTerminateAction = () -> {
IntegratedServer.killWorker();
Minecraft.getMinecraft().displayGuiScreen(new GuiMainMenu());
};
public static GuiScreen createException(GuiScreen ok, String msg, IPCPacket15ThrowException[] exceptions) {
for(int i = exceptions.length - 1; i >= 0; --i) {
ok = new GuiScreenSingleplayerException(ok, msg, exceptions[i]);
}
return ok;
}
private static final BiConsumer<GuiScreen, IPCPacket15ThrowException[]> defaultExceptionAction = (t, u) -> {
GuiScreenSingleplayerLoading tt = (GuiScreenSingleplayerLoading) t;
Minecraft.getMinecraft().displayGuiScreen(createException(tt.menu, tt.message, u));
};
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete) {
this(menu, message, checkTaskComplete, defaultTerminateAction);
this(menu, message, checkTaskComplete, defaultExceptionAction, defaultTerminateAction);
}
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, BiConsumer<GuiScreen, IPCPacket15ThrowException[]> exceptionAction) {
this(menu, message, checkTaskComplete, exceptionAction, defaultTerminateAction);
}
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, Runnable onTerminate) {
this(menu, message, checkTaskComplete, defaultExceptionAction, onTerminate);
}
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, BiConsumer<GuiScreen, IPCPacket15ThrowException[]> onException, Runnable onTerminate) {
this.menu = menu;
this.message = message;
this.checkTaskComplete = checkTaskComplete;
this.onException = onException;
this.taskKill = onTerminate;
this.lastStatus = IntegratedServer.worldStatusString();
this.currentStatus = message;
}
public void initGui() {
if(startStartTime == 0) this.startStartTime = System.currentTimeMillis();
this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, "Kill Task"));
areYouSure = 0;
this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, StringTranslate.getInstance().translateKey("gui.killTask")));
killTask.enabled = false;
}
@ -53,12 +81,24 @@ public class GuiScreenSingleplayerLoading extends GuiScreen {
long millis = System.currentTimeMillis();
long dots = (millis / 500l) % 4l;
this.drawString(fontRenderer, message + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(message)) / 2, top + 10, 0xFFFFFF);
String str = StringTranslate.getInstance().translateKey(currentStatus);
long elapsed = (millis - startStartTime) / 1000l;
if(elapsed > 3) {
this.drawCenteredString(fontRenderer, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF);
long dots = (millis / 500l) % 4l;
this.drawString(fontRenderer, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(str)) / 2, top + 10, 0xFFFFFF);
if(areYouSure > 0) {
this.drawCenteredString(fontRenderer, StringTranslate.getInstance().translateKey("selectWorld.progress.cancelWarning"), this.width / 2, top + 25, 0xFF8888);
}else {
float prog = IntegratedServer.worldStatusProgress();
if(this.currentStatus.equals(this.lastStatus) && prog > 0.01f) {
this.drawCenteredString(fontRenderer, (prog > 1.0f ? ("(" + (prog > 1000000.0f ? "" + (int)(prog / 1000000.0f) + "MB" :
(prog > 1000.0f ? "" + (int)(prog / 1000.0f) + "kB" : "" + (int)prog + "B")) + ")") : "" + (int)(prog * 100.0f) + "%"), this.width / 2, top + 25, 0xFFFFFF);
}else {
long elapsed = (millis - startStartTime) / 1000l;
if(elapsed > 3) {
this.drawCenteredString(fontRenderer, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF);
}
}
}
super.drawScreen(par1, par2, par3);
@ -69,14 +109,31 @@ public class GuiScreenSingleplayerLoading extends GuiScreen {
if(millis - startStartTime > 6000l) {
killTask.enabled = true;
}
if(IntegratedServer.didLastCallFail()) {
onException.accept(this, IntegratedServer.worldStatusErrors());
return;
}
if(checkTaskComplete.getAsBoolean()) {
this.mc.displayGuiScreen(menu);
}
String str = IntegratedServer.worldStatusString();
if(!lastStatus.equals(str)) {
lastStatus = str;
currentStatus = str;
}
killTask.displayString = StringTranslate.getInstance().translateKey(areYouSure > 0 ? "selectWorld.progress.confirmCancel" : "gui.killTask");
if(areYouSure > 0) {
--areYouSure;
}
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
taskKill.run();
if(areYouSure <= 0) {
areYouSure = 80;
}else if(areYouSure <= 40) {
taskKill.run();
}
}
}

View File

@ -34,6 +34,7 @@ public class IntegratedServer {
}
public static void begin(String[] locale, String[] stats) {
logException = true;
if(!isWorkerAlive()) {
openConnections.clear();
exceptions.clear();
@ -129,7 +130,7 @@ public class IntegratedServer {
public static NBTTagCompound getWorld(String folderName) {
for(NBTTagCompound nbt : worlds) {
if(folderName.equals(nbt.getString(folderName))) {
if(folderName.equals(nbt.getString("folderName"))) {
return nbt;
}
}
@ -177,12 +178,52 @@ public class IntegratedServer {
return exceptions.size() > 0 ? exceptions.remove(0) : null;
}
public static IPCPacket15ThrowException[] worldStatusErrors() {
if(exceptions.size() <= 0) {
return null;
}
IPCPacket15ThrowException[] t = new IPCPacket15ThrowException[exceptions.size()];
for(int i = 0; i < t.length; ++i) {
t[i] = exceptions.get(i);
}
exceptions.clear();
return t;
}
private static boolean logException = false;
public static void enableExceptionLog(boolean f) {
logException = f;
}
private static boolean callFailed = false;
public static boolean didLastCallFail() {
boolean c = callFailed;
callFailed = false;
return c;
}
public static void importWorld(String name, byte[] data, int format) {
ensureReady();
statusState = IntegratedState.WORLD_IMPORTING;
sendIPCPacket(new IPCPacket07ImportWorld(name, data, (byte)format));
}
public static void exportWorld(String name, int format) {
ensureReady();
statusState = IntegratedState.WORLD_EXPORTING;
sendIPCPacket(new IPCPacket05RequestData(name, (byte)format));
}
private static byte[] exportResponse = null;
public static byte[] getExportResponse() {
byte[] dat = exportResponse;
exportResponse = null;
return dat;
}
public static void processICP() {
if(!EaglerAdapter.isIntegratedServerAlive()) {
@ -223,6 +264,11 @@ public class IntegratedServer {
case IPCPacket0BPause.ID:
statusState = isPaused ? IntegratedState.WORLD_PAUSED : IntegratedState.WORLD_LOADED;
break;
case IPCPacketFFProcessKeepAlive.FAILURE:
System.err.println("Server signaled 'FAILURE' response in state '" + IntegratedState.getStateName(statusState) + "'");
statusState = IntegratedState.WORLD_NONE;
callFailed = true;
break;
case IPCPacket01StopServer.ID:
case IPCPacket03DeleteWorld.ID:
case IPCPacket04RenameWorld.ID:
@ -239,9 +285,12 @@ public class IntegratedServer {
}
case IPCPacket09RequestResponse.ID: {
IPCPacket09RequestResponse pkt = (IPCPacket09RequestResponse)packet;
// import/export/read
if(statusState == IntegratedState.WORLD_EXPORTING) {
statusState = IntegratedState.WORLD_NONE;
exportResponse = pkt.response;
}else {
System.err.println("IPCPacket09RequestResponse was recieved but statusState was '" + IntegratedState.getStateName(statusState) + "' instead of 'WORLD_EXPORTING'");
}
break;
}
case IPCPacket0DProgressUpdate.ID: {
@ -249,7 +298,7 @@ public class IntegratedServer {
worldStatusString = pkt.updateMessage;
worldStatusProgress = pkt.updateProgress;
if(logException) {
System.out.println("IntegratedServer: task '" + pkt.updateMessage + "' is " + ((int)(pkt.updateProgress * 100.0f)) + "% complete");
System.out.println("IntegratedServer: task \"" + pkt.updateMessage + "\"" + (pkt.updateProgress > 0.0f ? " is " + ((int)(pkt.updateProgress * 100.0f)) + "% complete" : ""));
}
break;
}

View File

@ -494,7 +494,7 @@ public class Minecraft implements Runnable {
public void stopServerAndDisplayGuiScreen(GuiScreen par1GuiScreen) {
if(IntegratedServer.isWorldRunning()) {
IntegratedServer.unloadWorld();
displayGuiScreen(new GuiScreenSingleplayerLoading(par1GuiScreen, "saving world", () -> !IntegratedServer.isWorldRunning()));
displayGuiScreen(new GuiScreenSingleplayerLoading(par1GuiScreen, "saving world", () -> IntegratedServer.isReady()));
}else {
displayGuiScreen(par1GuiScreen);
}
@ -1191,7 +1191,7 @@ public class Minecraft implements Runnable {
}
if (this.currentScreen == null) {
if (!this.inGameHasFocus && EaglerAdapter.mouseGetEventButtonState()) {
if ((!this.inGameHasFocus || !EaglerAdapter.isPointerLocked()) && EaglerAdapter.mouseGetEventButtonState()) {
this.setIngameFocus();
}
} else if (this.currentScreen != null) {
@ -1792,7 +1792,7 @@ public class Minecraft implements Runnable {
* the integrated one.
*/
public boolean isSingleplayer() {
return isIntegratedServerRunning();
return isIntegratedServerRunning() && (this.theWorld == null || this.theWorld.playerEntities.size() <= 1);
}
/**

View File

@ -136,20 +136,22 @@ public class GuiCreateWorld extends GuiScreen {
* available.
*/
private void makeUseableName() {
this.folderName = this.textboxWorldName.getText().trim();
this.folderName = makeUsableName(this.textboxWorldName.getText().trim());
}
public static String makeUsableName(String s) {
char[] var1 = ChatAllowedCharacters.allowedCharactersArray;
int var2 = var1.length;
for (int var3 = 0; var3 < var2; ++var3) {
char var4 = var1[var3];
this.folderName = this.folderName.replace(var4, '_');
s = s.replace(var4, '_');
}
if (MathHelper.stringNullOrLengthZero(this.folderName)) {
this.folderName = "World";
if (MathHelper.stringNullOrLengthZero(s)) {
s = "World";
}
this.folderName = func_73913_a(this.folderName);
return func_73913_a(s);
}
private void updateButtonText() {

View File

@ -1,15 +1,25 @@
package net.minecraft.src;
import net.lax1dude.eaglercraft.EaglerAdapter;
import net.lax1dude.eaglercraft.GuiScreenSingleplayerLoading;
import net.lax1dude.eaglercraft.IntegratedServer;
public class GuiRenameWorld extends GuiScreen {
private GuiScreen parentGuiScreen;
private GuiTextField theGuiTextField;
private final String worldName;
private final boolean duplicate;
public GuiRenameWorld(GuiScreen par1GuiScreen, String par2Str) {
this.parentGuiScreen = par1GuiScreen;
this.worldName = par2Str;
this.duplicate = false;
}
public GuiRenameWorld(GuiScreen par1GuiScreen, String par2Str, boolean d) {
this.parentGuiScreen = par1GuiScreen;
this.worldName = par2Str;
this.duplicate = d;
}
/**
@ -27,12 +37,15 @@ public class GuiRenameWorld extends GuiScreen {
EaglerAdapter.enableRepeatEvents(true);
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12,
var1.translateKey("selectWorld.renameButton")));
var1.translateKey(duplicate ? "selectWorld.duplicateButton" : "selectWorld.renameButton")));
this.buttonList.add(
new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, var1.translateKey("gui.cancel")));
//ISaveFormat var2 = this.mc.getSaveLoader();
//WorldInfo var3 = var2.getWorldInfo(this.worldName);
String var4 = worldName; //var3.getWorldName(); //TODO: add rename logic
if(duplicate) {
var4 = "Copy of " + var4;
}
this.theGuiTextField = new GuiTextField(this.fontRenderer, this.width / 2 - 100, this.height / 4 + 3, 200, 20);
this.theGuiTextField.setFocused(true);
this.theGuiTextField.setText(var4);
@ -56,7 +69,13 @@ public class GuiRenameWorld extends GuiScreen {
} else if (par1GuiButton.id == 0) {
//ISaveFormat var2 = this.mc.getSaveLoader();
//var2.renameWorld(this.worldName, this.theGuiTextField.getText().trim());
this.mc.displayGuiScreen(this.parentGuiScreen);
String str = theGuiTextField.getText().trim();
if(duplicate) {
IntegratedServer.copyMoveWorld(worldName, GuiCreateWorld.makeUsableName(str), str, true);
}else {
IntegratedServer.setWorldName(worldName, str);
}
this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(this.parentGuiScreen, "selectWorld.progress." + (duplicate ? "copying" : "renaming"), () -> IntegratedServer.isReady()));
}
}
}
@ -88,7 +107,7 @@ public class GuiRenameWorld extends GuiScreen {
public void drawScreen(int par1, int par2, float par3) {
StringTranslate var4 = StringTranslate.getInstance();
this.drawDefaultBackground();
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.renameTitle"), this.width / 2, this.height / 4 - 60 + 20, 16777215);
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld." + (duplicate ? "duplicateTitle" : "renameTitle")), this.width / 2, this.height / 4 - 60 + 20, 16777215);
this.drawString(this.fontRenderer, var4.translateKey("selectWorld.enterName"), this.width / 2 - 100, this.height / 4 - 60 + 50, 10526880);
this.theGuiTextField.drawTextBox();
super.drawScreen(par1, par2, par3);

View File

@ -2,11 +2,13 @@ package net.minecraft.src;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import net.lax1dude.eaglercraft.GuiScreenBackupWorld;
import net.lax1dude.eaglercraft.GuiScreenCreateWorldSelection;
import net.lax1dude.eaglercraft.GuiScreenSingleplayerLoading;
import net.lax1dude.eaglercraft.GuiScreenSingleplayerNotImplemented;
import net.lax1dude.eaglercraft.IntegratedServer;
@ -94,12 +96,15 @@ public class GuiSelectWorld extends GuiScreen {
* loads the saves
*/
private void loadSaves() {
this.saveList.clear();
List<NBTTagCompound> levels = IntegratedServer.getWorldList();
for(NBTTagCompound n : levels) {
WorldInfo w = new WorldInfo(n.getCompoundTag("Data"));
this.saveList.add(new SaveFormatComparator(n.getString("folderName"), w.getWorldName(), w.getLastTimePlayed(),
w.getSizeOnDisk(), w.getGameType(), false, w.isHardcoreModeEnabled(), w.areCommandsAllowed(), n));
}
Collections.sort(this.saveList);
this.selectedWorld = -1;
}
/**
@ -147,7 +152,6 @@ public class GuiSelectWorld extends GuiScreen {
protected void actionPerformed(GuiButton par1GuiButton) {
if (par1GuiButton.enabled) {
if (par1GuiButton.id == 2) {
/*
String var2 = this.getSaveName(this.selectedWorld);
if (var2 != null) {
@ -155,8 +159,7 @@ public class GuiSelectWorld extends GuiScreen {
GuiYesNo var3 = getDeleteWorldScreen(this, var2, this.selectedWorld);
this.mc.displayGuiScreen(var3);
}
*/
this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "delete world"));
//this.mc.displayGuiScreen(new GuiScreenSingleplayerNotImplemented(this, "delete world"));
} else if (par1GuiButton.id == 1) {
this.selectWorld(this.selectedWorld);
} else if (par1GuiButton.id == 3) {
@ -169,7 +172,8 @@ public class GuiSelectWorld extends GuiScreen {
//GuiCreateWorld var5 = new GuiCreateWorld(this);
//var5.func_82286_a(new WorldInfo(this.saveList.get(this.selectedWorld).levelDat));
//this.mc.displayGuiScreen(var5);
this.mc.displayGuiScreen(new GuiScreenBackupWorld(this, this.getSaveFileName(this.selectedWorld), 11111111l));
this.mc.displayGuiScreen(new GuiScreenBackupWorld(this, this.getSaveFileName(this.selectedWorld),
((SaveFormatComparator)getSize(this).get(selectedWorld)).levelDat));
} else {
this.worldSlotContainer.actionPerformed(par1GuiButton);
}
@ -204,13 +208,18 @@ public class GuiSelectWorld extends GuiScreen {
public void confirmClicked(boolean par1, int par2) {
if (this.deleting) {
this.deleting = false;
/*
/*
if (par1) {
waitingForWorlds = true;
IntegratedServer.requestWorldList();
}
*/
this.mc.displayGuiScreen(this);
*/
if (par1) {
IntegratedServer.deleteWorld(this.getSaveFileName(par2));
this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(this, "selectWorld.progress.deleting", () -> IntegratedServer.isReady()));
}else {
this.mc.displayGuiScreen(this);
}
}
}

View File

@ -291,6 +291,7 @@ public class EaglerAdapterImpl2 {
"var f = window.eagsFileChooser.inputElement.files;\r\n" +
"if(f.length == 0){\r\n" +
"window.eagsFileChooser.getFileChooserResult = null;\r\n" +
"window.eagsFileChooser.getFileChooserResultName = \"<none>\";\r\n" +
"}else{\r\n" +
"(async function(){\r\n" +
"window.eagsFileChooser.getFileChooserResult = await f[0].arrayBuffer();\r\n" +
@ -300,7 +301,7 @@ public class EaglerAdapterImpl2 {
"});\r\n" +
"window.eagsFileChooser.getFileChooserResult = null;\r\n" +
"window.eagsFileChooser.getFileChooserResultName = null;\r\n" +
"el.accept = mime;\r\n" +
"el.accept = (mime === null ? \".\"+ext : mime);\r\n" +
"el.click();\r\n" +
"},\r\n" +
"getFileChooserResult: null,\r\n" +
@ -1097,6 +1098,9 @@ public class EaglerAdapterImpl2 {
@JSBody(params = { "ext", "mime" }, script = "window.eagsFileChooser.openFileChooser(ext, mime);")
public static native void openFileChooser(String ext, String mime);
@JSBody(params = { }, script = "return window.eagsFileChooser.getFileChooserResult != null;")
public static final native boolean getFileChooserResultAvailable();
public static final byte[] getFileChooserResult() {
ArrayBuffer b = getFileChooserResult0();
if(b == null) return null;
@ -1692,4 +1696,18 @@ public class EaglerAdapterImpl2 {
}
}
}
@JSBody(params = { "name", "buf" }, script =
"var hr = window.URL.createObjectURL(new Blob([buf], {type: \"octet/stream\"}));" +
"var a = document.createElement(\"a\");" +
"a.href = hr; a.download = name; a.click();" +
"window.URL.revokeObjectURL(hr);")
private static final native void downloadBytesImpl(String str, ArrayBuffer buf);
public static final void downloadBytes(String str, byte[] dat) {
ArrayBuffer d = ArrayBuffer.create(dat.length);
Uint8Array.create(d).set(dat);
downloadBytesImpl(str, d);
}
}

View File

@ -0,0 +1,2 @@
#!/bin/sh
java -Xmx512M -Xms512M -jar craftbukkit-1.5.2-R1.0.jar

View File

@ -0,0 +1,2 @@
#!/bin/sh
java -Xmx32M -Xms32M -jar bungee-dist.jar