Update #22 - Singleplayer and shared worlds, shader fixes

This commit is contained in:
lax1dude
2023-12-12 01:22:54 -08:00
parent e3d6256493
commit 3f00d402fa
2350 changed files with 45241 additions and 7798 deletions

View File

@ -0,0 +1,35 @@
package net.lax1dude.eaglercraft.v1_8.update;
/**
* 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 CertificateInvalidException extends RuntimeException {
public CertificateInvalidException() {
}
public CertificateInvalidException(String message, Throwable cause) {
super(message, cause);
}
public CertificateInvalidException(String message) {
super(message);
}
public CertificateInvalidException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,235 @@
package net.lax1dude.eaglercraft.v1_8.update;
import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.EnumChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ResourceLocation;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
/**
* 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 GuiUpdateCheckerOverlay extends Gui {
private static final ResourceLocation eaglerIcons = new ResourceLocation("eagler:gui/eagler_gui.png");
private Minecraft mc;
private int width;
private int height;
private boolean isIngame;
private GuiScreen backScreen;
private GuiButton checkForUpdatesButton;
private GuiButton startDownloadButton;
private GuiButton viewAllUpdatesButton;
private GuiButton dismissUpdatesButton;
public GuiUpdateCheckerOverlay(boolean isIngame, GuiScreen screen) {
this.isIngame = isIngame;
this.backScreen = screen;
}
public void setResolution(Minecraft mc, int w, int h) {
this.mc = mc;
this.width = w;
this.height = h;
checkForUpdatesButton = new GuiButton(0, w - 150, 0, 150, 20, I18n.format("update.button") + " " + I18n.format(mc.gameSettings.enableUpdateSvc ? "gui.yes" : "gui.no"));
startDownloadButton = new GuiButton(1, w - 115, 0, 115, 20, I18n.format("update.startDownload"));
viewAllUpdatesButton = new GuiButton(2, w - 115, 0, 115, 20, I18n.format("update.viewAll", 0));
dismissUpdatesButton = new GuiButton(3, w - 115, 0, 115, 20, I18n.format("update.dismiss"));
}
public void drawScreen(int mx, int my, float partialTicks) {
UpdateProgressStruct progressState = UpdateService.getUpdatingStatus();
if(progressState.isBusy) {
drawScreenBusy(mx, my, partialTicks, progressState);
return;
}
checkForUpdatesButton.visible = isIngame;
startDownloadButton.visible = false;
viewAllUpdatesButton.visible = false;
dismissUpdatesButton.visible = false;
int i = UpdateService.getAvailableUpdates().size();
boolean shownSP = i > 0 || !mc.isSingleplayer() || LANServerController.isHostingLAN();
checkForUpdatesButton.visible &= shownSP;
if(mc.gameSettings.enableUpdateSvc) {
String str;
UpdateCertificate cert = UpdateService.getLatestUpdateFound();
if(cert != null) {
startDownloadButton.visible = true;
viewAllUpdatesButton.visible = true;
dismissUpdatesButton.visible = true;
viewAllUpdatesButton.displayString = I18n.format("update.viewAll", i);
str = I18n.format("update.found");
mc.fontRendererObj.drawStringWithShadow(str, width - mc.fontRendererObj.getStringWidth(str) - 3, 22, 0xFFFFAA);
int embedY = 35;
int embedWidth = 115;
int embedWidth2 = (int)(embedWidth / 0.75f);
List<String> lst = cert.bundleVersionComment.length() == 0 ? null : mc.fontRendererObj.listFormattedStringToWidth(cert.bundleVersionComment, embedWidth2 - 14);
int embedHeight = 44;
if(lst != null) {
embedHeight += 3 + lst.size() * 6;
}
GlStateManager.pushMatrix();
GlStateManager.translate(width - embedWidth - 1, embedY, 0.0f);
GlStateManager.scale(0.75f, 0.75f, 0.75f);
int embedHeight2 = (int)(embedHeight / 0.75f);
drawGradientRect(1, 1, embedWidth2 - 1, embedHeight2 - 1, 0xFFFFFFAA, 0xFFFFFFAA);
drawGradientRect(0, 1, embedWidth2, 2, 0xFF000000, 0xFF000000);
drawGradientRect(0, embedHeight2 - 1, embedWidth2, embedHeight2, 0xFF000000, 0xFF000000);
drawGradientRect(0, 1, 1, embedHeight2 - 1, 0xFF000000, 0xFF000000);
drawGradientRect(embedWidth2 - 1, 1, embedWidth2, embedHeight2 - 1, 0xFF000000, 0xFF000000);
mc.getTextureManager().bindTexture(eaglerIcons);
GlStateManager.pushMatrix();
GlStateManager.scale(0.3f, 0.3f, 0.3f);
drawGradientRect(23, 23, 127, 127, 0xFF000000, 0xFF000000);
EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // rip
drawTexturedModalRect(25, 25, 156, 0, 100, 100);
EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GlStateManager.popMatrix();
mc.fontRendererObj.drawString(EnumChatFormatting.UNDERLINE + cert.bundleDisplayName, 45, 11, 0x000000);
mc.fontRendererObj.drawString(I18n.format("update.update") + " " + EnumChatFormatting.DARK_RED + cert.bundleDisplayVersion, 45, 25, 0x000000);
if(lst != null) {
for(int j = 0, l = lst.size(); j < l; ++j) {
mc.fontRendererObj.drawString(lst.get(j), 5, 42 + j * 8, 0x000000);
}
}
mc.fontRendererObj.drawString(I18n.format("update.author") + " " + cert.bundleAuthorName, 5, 44 + (lst == null ? 0 : (3 + lst.size() * 8)), 0x777777);
startDownloadButton.yPosition = embedHeight + embedY + 5;
viewAllUpdatesButton.yPosition = startDownloadButton.yPosition + 22;
dismissUpdatesButton.yPosition = viewAllUpdatesButton.yPosition + 22;
GlStateManager.popMatrix();
}else if(isIngame) {
if(shownSP) {
str = I18n.format("update.noneNew");
mc.fontRendererObj.drawString(str, width - mc.fontRendererObj.getStringWidth(str) - 3, 22, 0xDDDDDD);
if(i > 0) {
viewAllUpdatesButton.yPosition = 40;
viewAllUpdatesButton.visible = true;
viewAllUpdatesButton.displayString = I18n.format("update.viewAll", i);
}
}
}
}
checkForUpdatesButton.drawButton(mc, mx, my);
startDownloadButton.drawButton(mc, mx, my);
viewAllUpdatesButton.drawButton(mc, mx, my);
dismissUpdatesButton.drawButton(mc, mx, my);
}
public void drawScreenBusy(int mx, int my, float partialTicks, UpdateProgressStruct progressState) {
checkForUpdatesButton.visible = false;
startDownloadButton.visible = false;
viewAllUpdatesButton.visible = false;
dismissUpdatesButton.visible = false;
GlStateManager.pushMatrix();
GlStateManager.translate(width, isIngame ? 0.0f : 10.0f, 0.0f);
String str = I18n.format("update.downloading");
mc.fontRendererObj.drawStringWithShadow(str, -mc.fontRendererObj.getStringWidth(str) - 2, 2, 0xFFFFAA);
GlStateManager.translate(0.0f, 14.0f, 0.0f);
GlStateManager.scale(0.75f, 0.75f, 0.75f);
if(!StringUtils.isAllBlank(progressState.statusString1)) {
str = progressState.statusString1;
mc.fontRendererObj.drawStringWithShadow(str, -mc.fontRendererObj.getStringWidth(str) - 3, 0, 0xFFFFFF);
}
int cc = isIngame ? 0xBBBBBB : 0xFFFFFF;
if(!StringUtils.isAllBlank(progressState.statusString2)) {
str = progressState.statusString2;
mc.fontRendererObj.drawStringWithShadow(str, -mc.fontRendererObj.getStringWidth(str) - 3, 11, cc);
}
int progX1 = -135;
int progY1 = 22;
int progX2 = -3;
int progY2 = 32;
float prog = progressState.progressBar;
if(prog >= 0.0f) {
int bk = 0xFFBBBBBB;
int fg = 0xFFDD0000;
drawGradientRect(progX1 + 1, progY1 + 1, progX1 + (int)((progX2 - progX1 - 1) * prog), progY2 - 1, fg, fg);
drawGradientRect(progX1 + (int)((progX2 - progX1 - 1) * prog), progY1 + 1, progX2 - 1, progY2 - 1, bk, bk);
drawGradientRect(progX1, progY1, progX2, progY1 + 1, 0xFF000000, 0xFF000000);
drawGradientRect(progX1, progY2 - 1, progX2, progY2, 0xFF000000, 0xFF000000);
drawGradientRect(progX1, progY1 + 1, progX1 + 1, progY2 - 1, 0xFF000000, 0xFF000000);
drawGradientRect(progX2 - 1, progY1 + 1, progX2, progY2 - 1, 0xFF000000, 0xFF000000);
}
if(!StringUtils.isAllBlank(progressState.statusString3)) {
GlStateManager.translate(0.0f, progY2 + 2, 0.0f);
GlStateManager.scale(0.66f, 0.66f, 0.66f);
str = progressState.statusString3;
List<String> wrappedURL = mc.fontRendererObj.listFormattedStringToWidth(str, (int)((progX2 - progX1) * 1.5f));
for(int i = 0, l = wrappedURL.size(); i < l; ++i) {
str = wrappedURL.get(i);
mc.fontRendererObj.drawStringWithShadow(str, -mc.fontRendererObj.getStringWidth(str) - 5, i * 11, cc);
}
}
GlStateManager.popMatrix();
}
public void mouseClicked(int mx, int my, int btn) {
if (btn == 0) {
if(checkForUpdatesButton.mousePressed(mc, mx, my)) {
mc.gameSettings.enableUpdateSvc = !mc.gameSettings.enableUpdateSvc;
mc.gameSettings.saveOptions();
checkForUpdatesButton.displayString = I18n.format("update.button") + " " + I18n.format(mc.gameSettings.enableUpdateSvc ? "gui.yes" : "gui.no");
}
if(startDownloadButton.mousePressed(mc, mx, my)) {
if(!UpdateService.getUpdatingStatus().isBusy) {
UpdateCertificate cert = UpdateService.getLatestUpdateFound();
if(cert != null) {
UpdateService.startClientUpdateFrom(cert);
}
}
}
if(viewAllUpdatesButton.mousePressed(mc, mx, my)) {
mc.displayGuiScreen(new GuiUpdateVersionList(backScreen));
}
if(dismissUpdatesButton.mousePressed(mc, mx, my)) {
UpdateCertificate cert = UpdateService.getLatestUpdateFound();
if(cert != null) {
UpdateService.dismiss(cert);
}
}
}
}
}

View File

@ -0,0 +1,93 @@
package net.lax1dude.eaglercraft.v1_8.update;
import java.io.IOException;
import java.util.List;
import net.minecraft.client.Minecraft;
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 GuiUpdateVersionList extends GuiScreen {
final GuiScreen back;
GuiUpdateVersionSlot slots;
int selected;
GuiButton downloadButton;
int mx = 0;
int my = 0;
String tooltip = null;
public GuiUpdateVersionList(GuiScreen back) {
this.back = back;
}
public void initGui() {
selected = -1;
buttonList.clear();
buttonList.add(new GuiButton(0, this.width / 2 + 54, this.height - 28, 100, 20, I18n.format("gui.done")));
buttonList.add(downloadButton = new GuiButton(1, this.width / 2 - 50, this.height - 28, 100, 20, I18n.format("updateList.download")));
buttonList.add(new GuiButton(2, this.width / 2 - 154, this.height - 28, 100, 20, I18n.format("updateList.refresh")));
slots = new GuiUpdateVersionSlot(this);
updateButtons();
}
void updateButtons() {
downloadButton.enabled = selected != -1;
}
static Minecraft getMinecraft(GuiUpdateVersionList screen) {
return screen.mc;
}
public void actionPerformed(GuiButton btn) {
switch(btn.id) {
case 1:
if(selected != -1) {
UpdateService.startClientUpdateFrom(slots.certList.get(selected));
}
case 0:
default:
mc.displayGuiScreen(back);
break;
case 2:
this.initGui();
break;
}
}
public void drawScreen(int par1, int par2, float par3) {
mx = par1;
my = par2;
slots.drawScreen(par1, par2, par3);
this.drawCenteredString(fontRendererObj, I18n.format("updateList.title"), this.width / 2, 16, 16777215);
this.drawCenteredString(fontRendererObj, I18n.format("updateList.note.0"), this.width / 2, this.height - 55, 0x888888);
this.drawCenteredString(fontRendererObj, I18n.format("updateList.note.1"), this.width / 2, this.height - 45, 0x888888);
super.drawScreen(par1, par2, par3);
if(tooltip != null) {
drawHoveringText(mc.fontRendererObj.listFormattedStringToWidth(tooltip, 180), par1, par2);
tooltip = null;
}
}
@Override
public void handleMouseInput() throws IOException {
super.handleMouseInput();
slots.handleMouseInput();
}
}

View File

@ -0,0 +1,150 @@
package net.lax1dude.eaglercraft.v1_8.update;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.EnumChatFormatting;
import net.minecraft.client.gui.GuiSlot;
import net.minecraft.util.ResourceLocation;
/**
* 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 GuiUpdateVersionSlot extends GuiSlot {
private static final ResourceLocation eaglerGuiTex = new ResourceLocation("eagler:gui/eagler_gui.png");
final List<UpdateCertificate> certList = new ArrayList();
final GuiUpdateVersionList screen;
public GuiUpdateVersionSlot(GuiUpdateVersionList screen) {
super(GuiUpdateVersionList.getMinecraft(screen), screen.width, screen.height, 32, screen.height - 64, 37);
this.screen = screen;
this.refresh();
}
public void refresh() {
certList.clear();
Collection<UpdateCertificate> certs = UpdateService.getAvailableUpdates();
synchronized(certs) {
certList.addAll(certs);
}
certList.sort((c1, c2) -> {
if(c1.bundleVersionInteger > c2.bundleVersionInteger) {
return -1;
}else if(c1.bundleVersionInteger == c2.bundleVersionInteger) {
if(c1.sigTimestamp > c2.sigTimestamp) {
return -1;
}else if(c1.sigTimestamp == c2.sigTimestamp) {
return 0;
}
}
return 1;
});
}
@Override
protected int getSize() {
return certList.size();
}
@Override
protected void elementClicked(int var1, boolean var2, int var3, int var4) {
screen.selected = var1;
screen.updateButtons();
}
@Override
protected boolean isSelected(int var1) {
return var1 == screen.selected;
}
@Override
protected void drawBackground() {
screen.drawBackground(0);
}
public static final SimpleDateFormat dateFmt = EagRuntime.fixDateFormat(new SimpleDateFormat("M/dd/yyyy"));
private static final char[] hexChars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
@Override
protected void drawSlot(int id, int xx, int yy, int width, int height, int ii) {
if(id < certList.size()) {
this.mc.getTextureManager().bindTexture(eaglerGuiTex);
GlStateManager.pushMatrix();
GlStateManager.translate(xx, yy, 0.0f);
GlStateManager.pushMatrix();
int iconSize = 33;
GlStateManager.scale(iconSize * 0.01f, iconSize * 0.01f, iconSize * 0.01f);
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // rip
screen.drawTexturedModalRect(0, 0, 156, 0, 100, 100);
EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GlStateManager.popMatrix();
GlStateManager.translate(iconSize + 1, 0.0f, 0.0f);
GlStateManager.scale(0.75f, 0.75f, 0.75f);
UpdateCertificate cert = certList.get(id);
screen.drawString(mc.fontRendererObj,
EnumChatFormatting.WHITE + cert.bundleDisplayName + EnumChatFormatting.GRAY + " - "
+ (cert.bundleVersionInteger > EaglercraftVersion.updateBundlePackageVersionInt
? EnumChatFormatting.GREEN
: (cert.bundleVersionInteger < EaglercraftVersion.updateBundlePackageVersionInt
? EnumChatFormatting.RED
: EnumChatFormatting.YELLOW))
+ cert.bundleDisplayVersion + EnumChatFormatting.DARK_GRAY + " "
+ cert.bundleVersionInteger + " " + EnumChatFormatting.GRAY
+ dateFmt.format(new Date(cert.sigTimestamp)) + EnumChatFormatting.WHITE + " " + (cert.bundleDataLength / 1024) + " kB",
2, 2, 0xFFFFFF);
List<String> strs = (List<String>)mc.fontRendererObj.listFormattedStringToWidth(cert.bundleVersionComment, (int)((getListWidth() - iconSize - 6) * 1.25f));
if(strs.size() > 0) {
screen.drawString(mc.fontRendererObj, strs.get(0), 2, 13, 0x888888);
}
if(strs.size() > 1) {
screen.drawString(mc.fontRendererObj, strs.get(1), 2, 24, 0x888888);
}
if(strs.size() > 2 && screen.mx > xx + iconSize && screen.my > yy + 8 && screen.mx < xx + getListWidth() - 5 && screen.my < yy + 25) {
screen.tooltip = cert.bundleVersionComment;
}
char[] hexStr1 = new char[] { hexChars[(cert.bundleDataHash[0] >> 4) & 0xF],
hexChars[cert.bundleDataHash[1] & 0xF], hexChars[(cert.bundleDataHash[1] >> 4) & 0xF],
hexChars[cert.bundleDataHash[1] & 0xF], hexChars[(cert.bundleDataHash[2] >> 4) & 0xF],
hexChars[cert.bundleDataHash[2] & 0xF] };
char[] hexStr2 = new char[] { hexChars[(cert.bundleDataHash[29] >> 4) & 0xF],
hexChars[cert.bundleDataHash[29] & 0xF], hexChars[(cert.bundleDataHash[30] >> 4) & 0xF],
hexChars[cert.bundleDataHash[30] & 0xF], hexChars[(cert.bundleDataHash[31] >> 4) & 0xF],
hexChars[cert.bundleDataHash[31] & 0xF] };
screen.drawString(mc.fontRendererObj,
"Author: " + EnumChatFormatting.GRAY + cert.bundleAuthorName + EnumChatFormatting.WHITE + " Hash: "
+ EnumChatFormatting.GRAY + "0x" + (new String(hexStr1)) + "......" + (new String(hexStr2)),
2, 35, 0xFFFFFF);
GlStateManager.popMatrix();
}
}
@Override
public int getListWidth() {
return 250;
}
}

View File

@ -0,0 +1,140 @@
package net.lax1dude.eaglercraft.v1_8.update;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
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.internal.PlatformApplication;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket00Handshake;
import net.minecraft.client.Minecraft;
/**
* 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 RelayUpdateChecker {
private static class RelayEntry {
private final String uri;
private boolean queued;
private boolean handshake;
private RelayServerSocket currentSocket;
private RelayEntry(String uri) {
this.uri = uri;
}
}
private static final List<RelayEntry> relaysList = new ArrayList();
private static long lastUpdateCheck = -1l;
private static boolean hasInit = false;
private static final long updateCheckRate = 3l * 60l * 60l * 1000l;
private static final String magic = "~!REQUEST_UPDATE_CERT";
public static void runTick() {
if(!EagRuntime.getConfiguration().isCheckRelaysForUpdates()) {
return;
}
if(!hasInit) {
hasInit = true;
for(net.lax1dude.eaglercraft.v1_8.sp.relay.RelayEntry etr : EagRuntime.getConfiguration().getRelays()) {
relaysList.add(new RelayEntry(etr.address));
}
byte[] b = PlatformApplication.getLocalStorage("lastRelayUpdate");
if(b != null) {
try {
lastUpdateCheck = (new DataInputStream(new ByteArrayInputStream(b))).readLong();
} catch (IOException e) {
}
}
}
long millis = System.currentTimeMillis();
Minecraft mc = Minecraft.getMinecraft();
if((mc.theWorld == null || mc.isSingleplayer()) && millis - lastUpdateCheck > updateCheckRate) {
lastUpdateCheck = millis;
try {
ByteArrayOutputStream bao = new ByteArrayOutputStream(8);
(new DataOutputStream(bao)).writeLong(lastUpdateCheck);
PlatformApplication.setLocalStorage("lastRelayUpdate", bao.toByteArray());
} catch (IOException e) {
}
for (int i = 0, l = relaysList.size(); i < l; ++i) {
relaysList.get(i).queued = true;
}
}
for(int i = 0, l = relaysList.size(); i < l; ++i) {
RelayEntry etr = relaysList.get(i);
if(etr.currentSocket != null) {
updateRelay(etr);
if(etr.currentSocket != null) {
return;
}
}
}
for(int i = 0, l = relaysList.size(); i < l; ++i) {
RelayEntry etr = relaysList.get(i);
if(etr.queued) {
etr.queued = false;
connect(etr);
if(etr.currentSocket != null) {
return;
}
}
}
}
private static void connect(RelayEntry socket) {
try {
socket.handshake = false;
socket.currentSocket = PlatformWebRTC.openRelayConnection(socket.uri, 10000);
if(socket.currentSocket.isClosed()) {
socket.currentSocket = null;
}
}catch(Throwable t) {
}
}
private static void updateRelay(RelayEntry socket) {
try {
if(socket.currentSocket.isClosed()) {
socket.currentSocket = null;
}else if(socket.currentSocket.isOpen()) {
if(!socket.handshake) {
socket.handshake = true;
socket.currentSocket.writePacket(new IPacket00Handshake(0x02, RelayManager.preferredRelayVersion, magic));
}else {
// close immediately
if(socket.currentSocket.nextPacket() != null) {
socket.currentSocket.close();
socket.currentSocket = null;
}
}
}
}catch(Throwable t) {
}
}
}

View File

@ -0,0 +1,226 @@
package net.lax1dude.eaglercraft.v1_8.update;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Objects;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder.ListMultimapBuilder;
import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
import net.lax1dude.eaglercraft.v1_8.crypto.SHA256Digest;
/**
* 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 UpdateCertificate {
public static class DLSource {
public final String type;
public final String addr;
private DLSource(String type, String addr) {
this.type = type;
this.addr = addr;
}
@Override
public int hashCode() {
return Objects.hash(addr, type);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DLSource other = (DLSource) obj;
return Objects.equals(addr, other.addr) && Objects.equals(type, other.type);
}
}
public final byte[] rawCertData;
public final int sigVersion;
public final long sigTimestamp;
public final int bundleDataLength;
public final byte[] bundleDataHash;
public final String bundlePackageName;
public final String bundleDisplayName;
public final String bundleAuthorName;
public final int bundleVersionInteger;
public final String bundleDisplayVersion;
public final String bundleVersionComment;
public final DLSource[] bundleDataSources;
public static UpdateCertificate parseAndVerifyCertificate(byte[] certData) throws IOException, CertificateInvalidException {
InputStream is = new ByteArrayInputStream(certData);
if(is.read() != 'E' || is.read() != 'A' || is.read() != 'G' || is.read() != 'S' || is.read() != 'I' || is.read() != 'G') {
throw new IOException("Data is not a certificate!");
}
int vers = is.read() << 8;
vers |= is.read();
if(vers != 1) {
throw new IOException("Invalid certificate version: " + vers);
}
byte[] rsa2048sum = new byte[256];
is.read(rsa2048sum);
byte[] rsa2048sumDec = (new BigInteger(rsa2048sum)).modPow(new BigInteger("65537"), EaglercraftVersion.updateSignatureModulus).toByteArray();
if(rsa2048sumDec.length > 256) {
throw new IOException("Invalid decrypted hash length: " + rsa2048sum.length);
}
if(rsa2048sumDec.length < 256) {
byte[] tmp = rsa2048sumDec;
rsa2048sumDec = new byte[256];
System.arraycopy(tmp, 0, rsa2048sumDec, 256 - tmp.length, tmp.length);
}
int payloadLen = is.read() << 8;
payloadLen |= is.read();
byte[] signaturePayload = new byte[payloadLen];
is.read(signaturePayload);
SHA256Digest sha256 = new SHA256Digest();
sha256.update(new byte[] { (byte) 170, (byte) 191, (byte) 203, (byte) 188, (byte) 47, (byte) 37, (byte) 17,
(byte) 187, (byte) 169, (byte) 225, (byte) 247, (byte) 193, (byte) 100, (byte) 101, (byte) 233,
(byte) 106, (byte) 80, (byte) 204, (byte) 192, (byte) 140, (byte) 19, (byte) 18, (byte) 165, (byte) 252,
(byte) 138, (byte) 187, (byte) 229, (byte) 148, (byte) 118, (byte) 208, (byte) 179, (byte) 233 }, 0, 32);
sha256.update(signaturePayload, 0, signaturePayload.length);
byte[] hash2048 = new byte[256];
sha256.doFinal(hash2048, 0);
sha256.reset();
sha256.update(new byte[] { (byte) 95, (byte) 222, (byte) 208, (byte) 153, (byte) 171, (byte) 133, (byte) 7,
(byte) 88, (byte) 111, (byte) 87, (byte) 37, (byte) 104, (byte) 98, (byte) 115, (byte) 185, (byte) 153,
(byte) 206, (byte) 188, (byte) 143, (byte) 18, (byte) 247, (byte) 28, (byte) 130, (byte) 87, (byte) 56,
(byte) 223, (byte) 45, (byte) 192, (byte) 108, (byte) 166, (byte) 254, (byte) 19 }, 0, 32);
sha256.update(signaturePayload, 0, signaturePayload.length);
sha256.doFinal(hash2048, 32);
sha256.reset();
sha256.update(new byte[] { (byte) 101, (byte) 245, (byte) 91, (byte) 125, (byte) 50, (byte) 79, (byte) 71,
(byte) 52, (byte) 244, (byte) 249, (byte) 84, (byte) 5, (byte) 139, (byte) 21, (byte) 13, (byte) 200,
(byte) 75, (byte) 0, (byte) 103, (byte) 1, (byte) 14, (byte) 159, (byte) 199, (byte) 194, (byte) 56,
(byte) 161, (byte) 63, (byte) 248, (byte) 90, (byte) 134, (byte) 96, (byte) 160 }, 0, 32);
sha256.update(signaturePayload, 0, signaturePayload.length);
sha256.doFinal(hash2048, 64);
sha256.reset();
sha256.update(new byte[] { (byte) 84, (byte) 208, (byte) 74, (byte) 114, (byte) 251, (byte) 86, (byte) 195,
(byte) 222, (byte) 90, (byte) 18, (byte) 194, (byte) 226, (byte) 20, (byte) 56, (byte) 191, (byte) 235,
(byte) 187, (byte) 93, (byte) 18, (byte) 122, (byte) 161, (byte) 40, (byte) 160, (byte) 88, (byte) 151,
(byte) 88, (byte) 215, (byte) 216, (byte) 253, (byte) 235, (byte) 7, (byte) 60 }, 0, 32);
sha256.update(signaturePayload, 0, signaturePayload.length);
sha256.doFinal(hash2048, 96);
hash2048[0] = (byte)((signaturePayload.length >> 8) & 0xFF);
hash2048[1] = (byte)(signaturePayload.length & 0xFF);
if(!Arrays.equals(hash2048, rsa2048sumDec)) {
throw new CertificateInvalidException("SHA256 checksum of signature payload is invalid!");
}
return new UpdateCertificate(certData, EaglerZLIB.newGZIPInputStream(new ByteArrayInputStream(signaturePayload)), vers);
}
private UpdateCertificate(byte[] certData, InputStream is, int sigVers) throws IOException {
this.rawCertData = certData;
this.sigVersion = sigVers;
DataInputStream dis = new DataInputStream(is);
this.sigTimestamp = dis.readLong();
this.bundleDataLength = dis.readInt();
this.bundleDataHash = new byte[32];
dis.read(bundleDataHash);
this.bundlePackageName = dis.readUTF();
this.bundleDisplayName = dis.readUTF();
this.bundleAuthorName = dis.readUTF();
this.bundleVersionInteger = dis.readInt();
this.bundleDisplayVersion = dis.readUTF();
this.bundleVersionComment = dis.readUTF();
dis.skip(dis.read());
int sourceCount = dis.readInt();
this.bundleDataSources = new DLSource[sourceCount];
for(int i = 0; i < sourceCount; ++i) {
dis.skip(4);
bundleDataSources[i] = new DLSource(dis.readUTF(), dis.readUTF());
}
}
public boolean isBundleDataValid(byte[] bundleData) {
if(bundleData.length != bundleDataLength) {
return false;
}
SHA256Digest sha256 = new SHA256Digest();
sha256.update(bundleData, 0, bundleData.length);
byte[] out = new byte[32];
sha256.doFinal(out, 0);
return Arrays.equals(out, bundleDataHash);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(bundleDataHash);
result = prime * result + Arrays.hashCode(bundleDataSources);
result = prime * result
+ Objects.hash(bundleAuthorName, bundleDataLength, bundleDisplayName, bundleDisplayVersion,
bundlePackageName, bundleVersionComment, bundleVersionInteger, sigTimestamp, sigVersion);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof UpdateCertificate))
return false;
UpdateCertificate other = (UpdateCertificate) obj;
return Objects.equals(bundleAuthorName, other.bundleAuthorName)
&& Arrays.equals(bundleDataHash, other.bundleDataHash) && bundleDataLength == other.bundleDataLength
&& Arrays.equals(bundleDataSources, other.bundleDataSources)
&& Objects.equals(bundleDisplayName, other.bundleDisplayName)
&& Objects.equals(bundleDisplayVersion, other.bundleDisplayVersion)
&& Objects.equals(bundlePackageName, other.bundlePackageName)
&& Objects.equals(bundleVersionComment, other.bundleVersionComment)
&& bundleVersionInteger == other.bundleVersionInteger && sigTimestamp == other.sigTimestamp
&& sigVersion == other.sigVersion;
}
public ListMultimap<String,String> getSourceMultimap() {
ListMultimap<String,String> ret = ListMultimapBuilder.hashKeys().arrayListValues().build();
for(int i = 0; i < bundleDataSources.length; ++i) {
ret.put(bundleDataSources[i].type, bundleDataSources[i].addr);
}
return ret;
}
}

View File

@ -0,0 +1,33 @@
package net.lax1dude.eaglercraft.v1_8.update;
/**
* 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 UpdateProgressStruct {
public boolean isBusy = false;
public String statusString1 = null;
public String statusString2 = null;
public String statusString3 = null;
public float progressBar = -1.0f;
public void clear() {
isBusy = false;
statusString1 = null;
statusString2 = null;
statusString3 = null;
progressBar = -1.0f;
}
}

View File

@ -0,0 +1,183 @@
package net.lax1dude.eaglercraft.v1_8.update;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformUpdateSvc;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
/**
* 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 UpdateService {
private static final Logger logger = LogManager.getLogger("UpdateService");
private static UpdateCertificate myUpdateCert = null;
private static boolean isBundleDataValid = false;
private static UpdateCertificate latestUpdateFound = null;
private static final Set<UpdateCertificate> availableUpdates = new HashSet();
private static final Set<UpdateCertificate> dismissedUpdates = new HashSet();
public static boolean supported() {
return EaglercraftVersion.enableUpdateService && EagRuntime.getConfiguration().allowUpdateSvc() && PlatformUpdateSvc.supported();
}
public static void initialize() {
if(!supported()) {
logger.info("Update service is not supported on this client");
return;
}
PlatformUpdateSvc.initialize();
if(PlatformUpdateSvc.getClientSignatureData() != null) {
logger.info("Testing client update certificate...");
try {
myUpdateCert = UpdateCertificate.parseAndVerifyCertificate(PlatformUpdateSvc.getClientSignatureData());
if(!EaglercraftVersion.updateBundlePackageName.equalsIgnoreCase(myUpdateCert.bundlePackageName)) {
throw new CertificateInvalidException("Certificate package name does not match current client package name!");
}
if(EaglercraftVersion.updateBundlePackageVersionInt != myUpdateCert.bundleVersionInteger) {
throw new CertificateInvalidException("Certificate client version does not match current client version!");
}
}catch(Throwable t) {
myUpdateCert = null;
logger.error("Client update certificate is invalid!");
logger.error(t);
}
if(myUpdateCert != null && PlatformUpdateSvc.getClientBundleData() != null) {
isBundleDataValid = myUpdateCert.isBundleDataValid(PlatformUpdateSvc.getClientBundleData());
if(!isBundleDataValid) {
logger.error("Client checksum does not match certificate! \"Download Offline\" button will download a fresh client");
}
}
}
byte[] latestUpdate = PlatformApplication.getLocalStorage(EaglercraftVersion.updateLatestLocalStorageKey);
if(latestUpdate != null) {
addCertificateToSet(latestUpdate, false);
}
}
public static byte[] getClientSignatureData() {
if(myUpdateCert != null) {
return PlatformUpdateSvc.getClientSignatureData();
}
return null;
}
public static byte[] getClientBundleData() {
if(isBundleDataValid) {
return PlatformUpdateSvc.getClientBundleData();
}
return null;
}
public static UpdateCertificate getClientCertificate() {
return myUpdateCert;
}
public static void addCertificateToSet(byte[] certificateData) {
addCertificateToSet(certificateData, true);
}
private static void addCertificateToSet(byte[] certificateData, boolean saveLatest) {
if (EagRuntime.getConfiguration().allowUpdateDL()) {
synchronized(availableUpdates) {
try {
UpdateCertificate cert = UpdateCertificate.parseAndVerifyCertificate(certificateData);
if (EaglercraftVersion.updateBundlePackageName.equalsIgnoreCase(cert.bundlePackageName)) {
if (myUpdateCert == null || !Arrays.equals(cert.bundleDataHash, myUpdateCert.bundleDataHash)) {
if(availableUpdates.add(cert)) {
logger.info("Found new update: {} - {}", cert.bundleDisplayName, cert.bundleDisplayVersion);
if (cert.bundleVersionInteger > EaglercraftVersion.updateBundlePackageVersionInt
&& (latestUpdateFound == null
|| cert.bundleVersionInteger > latestUpdateFound.bundleVersionInteger
|| (cert.bundleVersionInteger == latestUpdateFound.bundleVersionInteger
&& cert.sigTimestamp > latestUpdateFound.sigTimestamp))
&& !dismissedUpdates.contains(cert)) {
latestUpdateFound = cert;
if (saveLatest) {
PlatformApplication.setLocalStorage(EaglercraftVersion.updateLatestLocalStorageKey,
certificateData);
}
}
}else if(EagRuntime.getConfiguration().isLogInvalidCerts()) {
logger.info("Ignoring already indexed update: {} - {}", cert.bundleDisplayName, cert.bundleDisplayVersion);
}
}
} else {
if (EagRuntime.getConfiguration().isLogInvalidCerts()) {
logger.warn("Ignoring 3rd party update certificate: {} - {} ({})", cert.bundleDisplayName,
cert.bundleDisplayVersion, cert.bundlePackageName);
logger.warn("Note: the certificate still had a valid signature (leaked private key?!)");
}
}
} catch (Throwable t) {
if (EagRuntime.getConfiguration().isLogInvalidCerts()) {
logger.error("Invalid update certificate recieved! The certificate may be from a different client");
logger.error(t);
}
}
}
}
}
public static void startClientUpdateFrom(UpdateCertificate clientUpdate) {
PlatformUpdateSvc.startClientUpdateFrom(clientUpdate);
}
public static UpdateProgressStruct getUpdatingStatus() {
return PlatformUpdateSvc.getUpdatingStatus();
}
public static UpdateCertificate getLatestUpdateFound() {
return latestUpdateFound;
}
public static Collection<UpdateCertificate> getAvailableUpdates() {
return availableUpdates;
}
public static void dismiss(UpdateCertificate cert) {
if(latestUpdateFound == cert) {
latestUpdateFound = null;
}
dismissedUpdates.add(cert);
}
public static void quine() {
if(myUpdateCert != null) {
byte[] data = getClientBundleData();
if(data != null) {
logger.info("Generating signed offline download...");
PlatformUpdateSvc.quine(myUpdateCert, data);
}else {
logger.error("Client checksum does not match certificate! Downloading a fresh client...");
PlatformUpdateSvc.startClientUpdateFrom(myUpdateCert);
}
}
}
public static boolean shouldDisableDownloadButton() {
return EagRuntime.getConfiguration().getDownloadOfflineButtonLink() == null && (myUpdateCert == null
|| (getClientBundleData() == null && PlatformUpdateSvc.getUpdatingStatus().isBusy));
}
}