Update #24 - 1000s of optimizations, shared worlds on desktop

This commit is contained in:
lax1dude
2024-03-02 20:51:44 -08:00
parent a50c93cb75
commit 8ab65942c5
624 changed files with 8091 additions and 3620 deletions

View File

@ -1,17 +1,16 @@
package net.lax1dude.eaglercraft.v1_8.profile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ResourceLocation;
@ -148,8 +147,10 @@ public class EaglerProfile {
}
public static void read() {
byte[] profileStorage = EagRuntime.getStorage("p");
read(EagRuntime.getStorage("p"));
}
public static void read(byte[] profileStorage) {
if (profileStorage == null) {
return;
}
@ -207,7 +208,7 @@ public class EaglerProfile {
}
public static void write() {
public static byte[] write() {
NBTTagCompound profile = new NBTTagCompound();
profile.setInteger("presetSkin", presetSkinId);
profile.setInteger("customSkin", customSkinId);
@ -222,13 +223,20 @@ public class EaglerProfile {
skinsList.appendTag(skin);
}
profile.setTag("skins", skinsList);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
EaglerOutputStream bao = new EaglerOutputStream();
try {
CompressedStreamTools.writeCompressed(profile, bao);
} catch (IOException e) {
return;
return null;
}
return bao.toByteArray();
}
public static void save() {
byte[] b = write();
if(b != null) {
EagRuntime.setStorage("p", b);
}
EagRuntime.setStorage("p", bao.toByteArray());
}
static {

View File

@ -3,13 +3,16 @@ package net.lax1dude.eaglercraft.v1_8.profile;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.Keyboard;
import net.lax1dude.eaglercraft.v1_8.Mouse;
import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
@ -162,6 +165,23 @@ public class GuiScreenEditProfile extends GuiScreen {
drawRect(skinX + skinWidth - 4, skinY + scrollerPos + 1, skinX + skinWidth - 1, skinY + scrollerPos + scrollerSize, 0xff888888);
}
if(!EagRuntime.getConfiguration().isDemo()) {
GlStateManager.pushMatrix();
GlStateManager.scale(0.75f, 0.75f, 0.75f);
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
String text = I18n.format("editProfile.importExport");
int w = mc.fontRendererObj.getStringWidth(text);
boolean hover = mx > 1 && my > 1 && mx < (w * 3 / 4) + 7 && my < 12;
if(hover) {
Mouse.showCursor(EnumCursorType.HAND);
}
drawString(mc.fontRendererObj, EnumChatFormatting.UNDERLINE + text, 5, 5, hover ? 0xFFEEEE22 : 0xFFCCCCCC);
GlStateManager.popMatrix();
}
int xx = width / 2 - 80;
int yy = height / 6 + 130;
int numberOfCustomSkins = EaglerProfile.customSkins.size();
@ -370,6 +390,15 @@ public class GuiScreenEditProfile extends GuiScreen {
super.mouseClicked(mx, my, button);
usernameField.mouseClicked(mx, my, button);
if (button == 0) {
if(!EagRuntime.getConfiguration().isDemo()) {
int w = mc.fontRendererObj.getStringWidth(I18n.format("editProfile.importExport"));
if(mx > 1 && my > 1 && mx < (w * 3 / 4) + 7 && my < 12) {
mc.displayGuiScreen(new GuiScreenImportExportProfile(this));
mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
return;
}
}
if(newSkinWaitSteveOrAlex) {
int skinX = width / 2 - 90;
int skinY = height / 4;
@ -459,7 +488,7 @@ public class GuiScreenEditProfile extends GuiScreen {
name = name.substring(0, 16);
}
EaglerProfile.setName(name);
EaglerProfile.write();
EaglerProfile.save();
}
}

View File

@ -0,0 +1,90 @@
package net.lax1dude.eaglercraft.v1_8.profile;
import java.io.IOException;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class GuiScreenExportProfile extends GuiScreen {
private GuiScreen back;
private GuiButton exportProfile;
private boolean doExportProfile = true;
private GuiButton exportSettings;
private boolean doExportSettings = true;
private GuiButton exportServers;
private boolean doExportServers = true;
private GuiButton exportResourcePacks;
private boolean doExportResourcePacks = false;
public GuiScreenExportProfile(GuiScreen back) {
this.back = back;
}
public void initGui() {
this.buttonList.add(exportProfile = new GuiButton(2, this.width / 2 - 100, this.height / 4, I18n.format("settingsBackup.export.option.profile") + " " + I18n.format(doExportProfile ? "gui.yes" : "gui.no")));
this.buttonList.add(exportSettings = new GuiButton(3, this.width / 2 - 100, this.height / 4 + 25, I18n.format("settingsBackup.export.option.settings") + " " + I18n.format(doExportSettings ? "gui.yes" : "gui.no")));
this.buttonList.add(exportServers = new GuiButton(4, this.width / 2 - 100, this.height / 4 + 50, I18n.format("settingsBackup.export.option.servers") + " " + I18n.format(doExportServers ? "gui.yes" : "gui.no")));
this.buttonList.add(exportResourcePacks = new GuiButton(5, this.width / 2 - 100, this.height / 4 + 75, I18n.format("settingsBackup.export.option.resourcePacks") + " " + I18n.format(doExportResourcePacks ? "gui.yes" : "gui.no")));
exportResourcePacks.enabled = EaglerFolderResourcePack.isSupported();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 115, I18n.format("settingsBackup.export.option.export")));
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 140, I18n.format("gui.cancel")));
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
if(!doExportProfile && !doExportSettings && !doExportServers && !doExportResourcePacks) {
mc.displayGuiScreen(back);
}else {
mc.loadingScreen.eaglerShow(I18n.format("settingsBackup.exporting.1"), I18n.format("settingsBackup.exporting.2"));
try {
ProfileExporter.exportProfileAndSettings(doExportProfile, doExportSettings, doExportServers, doExportResourcePacks);
mc.displayGuiScreen(back);
} catch (IOException e) {
EagRuntime.debugPrintStackTrace(e);
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("settingsBackup.exporting.failed.1", "settingsBackup.exporting.failed.2", back));
}
}
}else if(par1GuiButton.id == 1) {
mc.displayGuiScreen(back);
}else if(par1GuiButton.id == 2) {
doExportProfile = !doExportProfile;
exportProfile.displayString = I18n.format("settingsBackup.export.option.profile") + " " + I18n.format(doExportProfile ? "gui.yes" : "gui.no");
}else if(par1GuiButton.id == 3) {
doExportSettings = !doExportSettings;
exportSettings.displayString = I18n.format("settingsBackup.export.option.settings") + " " + I18n.format(doExportSettings ? "gui.yes" : "gui.no");
}else if(par1GuiButton.id == 4) {
doExportServers = !doExportServers;
exportServers.displayString = I18n.format("settingsBackup.export.option.servers") + " " + I18n.format(doExportServers ? "gui.yes" : "gui.no");
}else if(par1GuiButton.id == 5) {
doExportResourcePacks = !doExportResourcePacks;
exportResourcePacks.displayString = I18n.format("settingsBackup.export.option.resourcePacks") + " " + I18n.format(doExportResourcePacks ? "gui.yes" : "gui.no");
}
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("settingsBackup.export.title"), this.width / 2, this.height / 4 - 25, 16777215);
super.drawScreen(par1, par2, par3);
}
}

View File

@ -0,0 +1,78 @@
package net.lax1dude.eaglercraft.v1_8.profile;
import java.io.IOException;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class GuiScreenImportExportProfile extends GuiScreen {
private GuiScreen back;
private boolean waitingForFile = false;
public GuiScreenImportExportProfile(GuiScreen back) {
this.back = back;
}
public void initGui() {
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 40, I18n.format("settingsBackup.importExport.import")));
this.buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 4 + 65, I18n.format("settingsBackup.importExport.export")));
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 130, I18n.format("gui.cancel")));
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
mc.displayGuiScreen(back);
}else if(par1GuiButton.id == 1) {
waitingForFile = true;
EagRuntime.displayFileChooser(null, "epk");
}else if(par1GuiButton.id == 2) {
mc.displayGuiScreen(new GuiScreenExportProfile(back));
}
}
public void updateScreen() {
if(waitingForFile && EagRuntime.fileChooserHasResult()) {
waitingForFile = false;
FileChooserResult result = EagRuntime.getFileChooserResult();
if(result != null) {
mc.loadingScreen.eaglerShow(I18n.format("settingsBackup.importing.1"), "settingsBackup.importing.2");
try {
ProfileImporter importer = new ProfileImporter(result.fileData);
importer.readHeader();
mc.displayGuiScreen(new GuiScreenImportProfile(importer, back));
}catch(IOException ex) {
EagRuntime.debugPrintStackTrace(ex);
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("settingsBackup.importing.failed.1", "settingsBackup.importing.failed.2", back));
}
}
}
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("settingsBackup.importExport.title"), this.width / 2, this.height / 4, 16777215);
super.drawScreen(par1, par2, par3);
}
}

View File

@ -0,0 +1,111 @@
package net.lax1dude.eaglercraft.v1_8.profile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.resources.ResourcePackRepository;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class GuiScreenImportProfile extends GuiScreen {
private GuiScreen back;
private ProfileImporter importer;
private GuiButton importProfile;
private boolean doImportProfile;
private GuiButton importSettings;
private boolean doImportSettings;
private GuiButton importServers;
private boolean doImportServers;
private GuiButton importResourcePacks;
private boolean doImportResourcePacks;
public GuiScreenImportProfile(ProfileImporter importer, GuiScreen back) {
this.back = back;
this.importer = importer;
this.doImportProfile = importer.hasProfile();
this.doImportSettings = importer.hasSettings();
this.doImportServers = importer.hasSettings();
this.doImportResourcePacks = importer.hasResourcePacks();
}
public void initGui() {
this.buttonList.add(importProfile = new GuiButton(2, this.width / 2 - 100, this.height / 4, I18n.format("settingsBackup.import.option.profile") + " " + I18n.format(doImportProfile ? "gui.yes" : "gui.no")));
importProfile.enabled = importer.hasProfile();
this.buttonList.add(importSettings = new GuiButton(3, this.width / 2 - 100, this.height / 4 + 25, I18n.format("settingsBackup.import.option.settings") + " " + I18n.format(doImportSettings ? "gui.yes" : "gui.no")));
importSettings.enabled = importer.hasProfile();
this.buttonList.add(importServers = new GuiButton(4, this.width / 2 - 100, this.height / 4 + 50, I18n.format("settingsBackup.import.option.servers") + " " + I18n.format(doImportServers ? "gui.yes" : "gui.no")));
importServers.enabled = importer.hasServers();
this.buttonList.add(importResourcePacks = new GuiButton(5, this.width / 2 - 100, this.height / 4 + 75, I18n.format("settingsBackup.import.option.resourcePacks") + " " + I18n.format(doImportResourcePacks ? "gui.yes" : "gui.no")));
importResourcePacks.enabled = importer.hasResourcePacks() && EaglerFolderResourcePack.isSupported();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 115, I18n.format("settingsBackup.import.option.import")));
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 140, I18n.format("gui.cancel")));
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
if(!doImportProfile && !doImportSettings && !doImportServers && !doImportResourcePacks) {
mc.displayGuiScreen(back);
}else {
mc.loadingScreen.eaglerShow(I18n.format("settingsBackup.importing.1"), I18n.format("settingsBackup.importing.2"));
try {
List<String> list1 = new ArrayList(mc.gameSettings.resourcePacks);
List<String> list2 = new ArrayList(mc.gameSettings.field_183018_l);
importer.importProfileAndSettings(doImportProfile, doImportSettings, doImportServers, doImportResourcePacks);
boolean resourcePacksChanged = !mc.gameSettings.resourcePacks.equals(list1) || !mc.gameSettings.field_183018_l.equals(list2);
if(resourcePacksChanged || (doImportResourcePacks && (list1.size() > 0 || list2.size() > 0))) {
mc.loadingScreen.eaglerShow(I18n.format("resourcePack.load.refreshing"),
I18n.format("resourcePack.load.pleaseWait"));
mc.getResourcePackRepository().reconstruct(mc.gameSettings);
mc.refreshResources();
}
mc.displayGuiScreen(back);
} catch (IOException e) {
EagRuntime.debugPrintStackTrace(e);
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("settingsBackup.importing.failed.1", "settingsBackup.importing.failed.2", back));
}
}
}else if(par1GuiButton.id == 1) {
mc.displayGuiScreen(back);
}else if(par1GuiButton.id == 2) {
doImportProfile = !doImportProfile;
importProfile.displayString = I18n.format("settingsBackup.import.option.profile") + " " + I18n.format(doImportProfile ? "gui.yes" : "gui.no");
}else if(par1GuiButton.id == 3) {
doImportSettings = !doImportSettings;
importSettings.displayString = I18n.format("settingsBackup.import.option.settings") + " " + I18n.format(doImportSettings ? "gui.yes" : "gui.no");
}else if(par1GuiButton.id == 4) {
doImportServers = !doImportServers;
importServers.displayString = I18n.format("settingsBackup.import.option.servers") + " " + I18n.format(doImportServers ? "gui.yes" : "gui.no");
}else if(par1GuiButton.id == 5) {
doImportResourcePacks = !doImportResourcePacks;
importResourcePacks.displayString = I18n.format("settingsBackup.import.option.resourcePacks") + " " + I18n.format(doImportResourcePacks ? "gui.yes" : "gui.no");
}
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("settingsBackup.import.title"), this.width / 2, this.height / 4 - 25, 16777215);
super.drawScreen(par1, par2, par3);
}
}

View File

@ -0,0 +1,195 @@
package net.lax1dude.eaglercraft.v1_8.profile;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.zip.CRC32;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ServerList;
import static net.lax1dude.eaglercraft.v1_8.sp.server.export.EPKCompiler.*;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ProfileExporter {
private static final Logger logger = LogManager.getLogger("ProfileExporter");
public static void exportProfileAndSettings(boolean doExportProfile, boolean doExportSettings,
boolean doExportServers, boolean doExportResourcePacks) throws IOException {
doExportResourcePacks &= EaglerFolderResourcePack.isSupported();
EaglerOutputStream osb = new EaglerOutputStream();
osb.write(new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)36,(byte)36}); // EAGPKG$$
osb.write(new byte[]{(byte)6,(byte)118,(byte)101,(byte)114,(byte)50,(byte)46,(byte)48}); // 6 + ver2.0
Date d = new Date();
byte[] filename = "profile.epk".getBytes(StandardCharsets.UTF_8);
osb.write(filename.length);
osb.write(filename);
byte[] comment = ("\n\n # Eaglercraft profile backup - \"" + EaglerProfile.getName() + "\""
+ "\n # Contains: " + (doExportProfile ? "profile " : "") + (doExportSettings ? "settings " : "")
+ (doExportServers ? "servers " : "") + (doExportResourcePacks ? "resourcePacks" : "") + "\n\n")
.getBytes(StandardCharsets.UTF_8);
osb.write((comment.length >> 8) & 255);
osb.write(comment.length & 255);
osb.write(comment);
writeLong(d.getTime(), osb);
int lengthIntegerOffset = osb.size();
osb.write(new byte[]{(byte)255,(byte)255,(byte)255,(byte)255}); // this will be replaced with the file count
osb.write('G');
OutputStream os = EaglerZLIB.newGZIPOutputStream(osb);
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
os.write(new byte[]{(byte)9,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)116,(byte)121,
(byte)112,(byte)101}); // 9 + file-type
os.write(new byte[]{(byte)0,(byte)0,(byte)0,(byte)14,(byte)101,(byte)112,(byte)107,(byte)47,(byte)112,(byte)114,(byte)111,
(byte)102,(byte)105,(byte)108,(byte)101,(byte)49,(byte)56,(byte)56}); // 14 + epk/profile188
os.write('>');
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
os.write(new byte[]{(byte)12,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)101,(byte)120,
(byte)112,(byte)111,(byte)114,(byte)116,(byte)115,(byte)0,(byte)0,(byte)0,(byte)1}); // 12 + file-exports + 1
os.write((doExportProfile ? 1 : 0) | (doExportSettings ? 2 : 0) | (doExportServers ? 4 : 0) | (doExportResourcePacks ? 8 : 0));
os.write('>');
int fileCount = 2;
if(doExportProfile) {
byte[] profileData = EaglerProfile.write();
if(profileData == null) {
throw new IOException("Could not write profile data!");
}
exportFileToEPK("_eaglercraftX.p", profileData, os);
++fileCount;
}
if(doExportSettings) {
logger.info("Exporting game settings...");
byte[] gameSettings = Minecraft.getMinecraft().gameSettings.writeOptions();
if(gameSettings == null) {
throw new IOException("Could not write game settings!");
}
exportFileToEPK("_eaglercraftX.g", gameSettings, os);
++fileCount;
logger.info("Exporting relay settings...");
byte[] relays = RelayManager.relayManager.write();
if(relays == null) {
throw new IOException("Could not write relay settings!");
}
exportFileToEPK("_eaglercraftX.r", relays, os);
++fileCount;
}
if(doExportServers) {
logger.info("Exporting server list...");
byte[] servers = ServerList.getServerList().writeServerList();
if(servers == null) {
throw new IOException("Could not write server list!");
}
exportFileToEPK("_eaglercraftX.s", servers, os);
++fileCount;
}
logger.info("Exporting certificates...");
UpdateCertificate cert = UpdateService.getClientCertificate();
if(cert != null) {
exportFileToEPK("certs/main.cert", cert.rawCertData, os);
++fileCount;
}
Collection<UpdateCertificate> updatesExport = UpdateService.getAvailableUpdates();
int cc = 0;
for(UpdateCertificate cert2 : updatesExport) {
exportFileToEPK("certs/c" + (cc++) + ".cert", cert2.rawCertData, os);
++fileCount;
}
if(doExportResourcePacks) {
logger.info("Exporting resource packs...");
byte[] packManifest = (new VFile2(EaglerFolderResourcePack.RESOURCE_PACKS + "/manifest.json")).getAllBytes();
if(packManifest != null) {
exportFileToEPK(EaglerFolderResourcePack.RESOURCE_PACKS + "/manifest.json", packManifest, os);
++fileCount;
VFile2 baseDir = new VFile2(EaglerFolderResourcePack.RESOURCE_PACKS);
List<VFile2> files = baseDir.listFiles(true);
logger.info("({} files to export)", files.size());
for(int i = 0, l = files.size(); i < l; ++i) {
VFile2 f = files.get(i);
if(f.getPath().equals(EaglerFolderResourcePack.RESOURCE_PACKS + "/manifest.json")) {
continue;
}
exportFileToEPK(f.getPath(), f.getAllBytes(), os);
++fileCount;
if(i > 0 && i % 100 == 0) {
logger.info("Exported {} files", i);
}
}
}
}
os.write(new byte[]{(byte)69,(byte)78,(byte)68,(byte)36}); // END$
os.close();
osb.write(new byte[]{(byte)58,(byte)58,(byte)58,(byte)89,(byte)69,(byte)69,(byte)58,(byte)62}); // :::YEE:>
byte[] ret = osb.toByteArray();
ret[lengthIntegerOffset] = (byte)((fileCount >> 24) & 0xFF);
ret[lengthIntegerOffset + 1] = (byte)((fileCount >> 16) & 0xFF);
ret[lengthIntegerOffset + 2] = (byte)((fileCount >> 8) & 0xFF);
ret[lengthIntegerOffset + 3] = (byte)(fileCount & 0xFF);
logger.info("Export complete!");
EagRuntime.downloadFileWithName(EaglerProfile.getName() + "-backup.epk", ret);
}
private static void exportFileToEPK(String name, byte[] contents, OutputStream os) throws IOException {
CRC32 checkSum = new CRC32();
checkSum.update(contents);
long sum = checkSum.getValue();
os.write(new byte[]{(byte)70,(byte)73,(byte)76,(byte)69}); // FILE
byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
os.write(nameBytes.length);
os.write(nameBytes);
writeInt(contents.length + 5, os);
writeInt((int)sum, os);
os.write(contents);
os.write(':');
os.write('>');
}
}

View File

@ -0,0 +1,151 @@
package net.lax1dude.eaglercraft.v1_8.profile;
import java.io.IOException;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.sp.server.export.EPKDecompiler;
import net.lax1dude.eaglercraft.v1_8.sp.server.export.EPKDecompiler.FileEntry;
import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ServerList;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ProfileImporter {
private static final Logger logger = LogManager.getLogger("ProfileImporter");
private byte[] data;
private EPKDecompiler epkDecompiler;
private boolean headerHasProfile;
private boolean headerHasSettings;
private boolean headerHasServers;
private boolean headerHasResourcePacks;
public ProfileImporter(byte[] data) {
this.data = data;
}
public void readHeader() throws IOException {
logger.info("Reading EPK file header...");
epkDecompiler = new EPKDecompiler(data);
FileEntry etr = epkDecompiler.readFile();
if (etr == null || !etr.type.equals("HEAD") || !etr.name.equals("file-type")
|| !EPKDecompiler.readASCII(etr.data).equals("epk/profile188")) {
throw new IOException("EPK file is not a profile backup!");
}
etr = epkDecompiler.readFile();
if (etr == null || !etr.type.equals("HEAD") || !etr.name.equals("file-exports") || etr.data.length != 1) {
throw new IOException("EPK file is not a profile backup!");
}
headerHasProfile = (etr.data[0] & 1) != 0;
headerHasSettings = (etr.data[0] & 2) != 0;
headerHasServers = (etr.data[0] & 4) != 0;
headerHasResourcePacks = (etr.data[0] & 8) != 0;
}
public boolean hasProfile() {
return headerHasProfile;
}
public boolean hasSettings() {
return headerHasSettings;
}
public boolean hasServers() {
return headerHasServers;
}
public boolean hasResourcePacks() {
return headerHasResourcePacks;
}
/**
* Note: this function is sensitive to the order file appear in the EPK
*/
public void importProfileAndSettings(boolean doImportProfile, boolean doImportSettings,
boolean doImportServers, boolean doImportResourcePacks) throws IOException {
doImportProfile &= headerHasProfile;
doImportSettings &= headerHasSettings;
doImportServers &= headerHasServers;
doImportResourcePacks &= headerHasResourcePacks && EaglerFolderResourcePack.isSupported();
FileEntry etr;
vigg: while((etr = epkDecompiler.readFile()) != null) {
if(etr.type.equals("FILE")) {
switch(etr.name) {
case "_eaglercraftX.p":
if(doImportProfile) {
logger.info("Importing profile...");
EaglerProfile.read(etr.data);
EagRuntime.setStorage("p", etr.data);
}
break;
case "_eaglercraftX.g":
if(doImportSettings) {
logger.info("Importing settings...");
Minecraft.getMinecraft().gameSettings.loadOptions(etr.data);
EagRuntime.setStorage("g", etr.data);
}
break;
case "_eaglercraftX.r":
if(doImportSettings) {
logger.info("Importing relays...");
RelayManager.relayManager.load(etr.data);
EagRuntime.setStorage("r", etr.data);
}
break;
case "_eaglercraftX.s":
if(doImportServers) {
logger.info("Importing servers...");
ServerList.getServerList().loadServerList(etr.data);
EagRuntime.setStorage("s", etr.data);
}
break;
default:
if(etr.name.startsWith("certs/")) {
UpdateService.addCertificateToSet(etr.data);
}else if(etr.name.startsWith(EaglerFolderResourcePack.RESOURCE_PACKS + "/")) {
if(doImportResourcePacks) {
logger.info("Deleting old resource packs...");
(new VFile2(EaglerFolderResourcePack.RESOURCE_PACKS)).listFiles(true).forEach(VFile2::delete);
logger.info("Importing resource packs...");
int counter = 0;
do {
if(etr.name.startsWith(EaglerFolderResourcePack.RESOURCE_PACKS + "/")) {
(new VFile2(etr.name)).setAllBytes(etr.data);
if(++counter % 100 == 0) {
logger.info("Imported {} files", counter);
}
}
}while((etr = epkDecompiler.readFile()) != null);
}
break vigg;
}
break;
}
}
}
logger.info("Import complete!");
}
}