mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-27 18:38:14 -05:00
Update #37 - Touch support without userscript, many other feats
This commit is contained in:
@ -0,0 +1,104 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.webview;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
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 GuiScreenPhishingWaring extends GuiScreen {
|
||||
|
||||
public static boolean hasShownMessage = false;
|
||||
|
||||
private static final ResourceLocation beaconGuiTexture = new ResourceLocation("textures/gui/container/beacon.png");
|
||||
|
||||
private GuiScreen cont;
|
||||
private boolean mouseOverCheck;
|
||||
private boolean hasCheckedBox;
|
||||
|
||||
public GuiScreenPhishingWaring(GuiScreen cont) {
|
||||
this.cont = cont;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 134, I18n.format("webviewPhishingWaring.continue")));
|
||||
}
|
||||
|
||||
public void drawScreen(int mx, int my, float pt) {
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(fontRendererObj, EnumChatFormatting.BOLD + I18n.format("webviewPhishingWaring.title"), this.width / 2, 70, 0xFF4444);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text0"), this.width / 2, 90, 16777215);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text1"), this.width / 2, 102, 16777215);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text2"), this.width / 2, 114, 16777215);
|
||||
|
||||
String dontShowAgain = I18n.format("webviewPhishingWaring.dontShowAgain");
|
||||
int w = fontRendererObj.getStringWidth(dontShowAgain) + 20;
|
||||
int ww = (this.width - w) / 2;
|
||||
this.drawString(fontRendererObj, dontShowAgain, ww + 20, 137, 0xCCCCCC);
|
||||
|
||||
mouseOverCheck = ww < mx && ww + 17 > mx && 133 < my && 150 > my;
|
||||
|
||||
if(mouseOverCheck) {
|
||||
GlStateManager.color(0.7f, 0.7f, 1.0f, 1.0f);
|
||||
}else {
|
||||
GlStateManager.color(0.6f, 0.6f, 0.6f, 1.0f);
|
||||
}
|
||||
|
||||
mc.getTextureManager().bindTexture(beaconGuiTexture);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.scale(0.75f, 0.75f, 0.75f);
|
||||
drawTexturedModalRect(ww * 4 / 3, 133 * 4 / 3, 22, 219, 22, 22);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
if(hasCheckedBox) {
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.color(1.1f, 1.1f, 1.1f, 1.0f);
|
||||
GlStateManager.translate(0.5f, 0.5f, 0.0f);
|
||||
drawTexturedModalRect(ww, 133, 90, 222, 16, 16);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
super.drawScreen(mx, my, pt);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
if(hasCheckedBox && !mc.gameSettings.hasHiddenPhishWarning) {
|
||||
mc.gameSettings.hasHiddenPhishWarning = true;
|
||||
mc.gameSettings.saveOptions();
|
||||
}
|
||||
hasShownMessage = true;
|
||||
mc.displayGuiScreen(cont);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mx, int my, int btn) {
|
||||
if(btn == 0 && mouseOverCheck) {
|
||||
hasCheckedBox = !hasCheckedBox;
|
||||
mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
|
||||
return;
|
||||
}
|
||||
super.mouseClicked(mx, my, btn);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,203 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.webview;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
|
||||
import net.lax1dude.eaglercraft.v1_8.IOUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketRequestServerInfoV4EAG;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
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 GuiScreenRecieveServerInfo extends GuiScreen {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("GuiScreenRecieveServerInfo");
|
||||
|
||||
protected final GuiScreen parent;
|
||||
protected final byte[] expectHash;
|
||||
protected int timer;
|
||||
protected int timer2;
|
||||
protected String statusString = "recieveServerInfo.checkingCache";
|
||||
|
||||
public GuiScreenRecieveServerInfo(GuiScreen parent, byte[] expectHash) {
|
||||
this.parent = parent;
|
||||
this.expectHash = expectHash;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 106, I18n.format("gui.cancel")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("recieveServerInfo.title"), this.width / 2, 70, 11184810);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format(statusString), this.width / 2, 90, 16777215);
|
||||
if(Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash) && ServerInfoCache.chunkFinalSize > 0) {
|
||||
int progress = ServerInfoCache.chunkCurrentSize * 100 / ServerInfoCache.chunkFinalSize;
|
||||
if(progress < 0) progress = 0;
|
||||
if(progress > 100) progress = 100;
|
||||
if(ServerInfoCache.hasLastChunk) {
|
||||
progress = 100;
|
||||
}
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
WorldRenderer worldrenderer = tessellator.getWorldRenderer();
|
||||
byte b0 = 100;
|
||||
byte b1 = 2;
|
||||
int i1 = width / 2 - b0 / 2;
|
||||
int j1 = 103;
|
||||
GlStateManager.disableTexture2D();
|
||||
worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR);
|
||||
worldrenderer.pos((double) i1, (double) j1, 0.0D).color(128, 128, 128, 255).endVertex();
|
||||
worldrenderer.pos((double) i1, (double) (j1 + b1), 0.0D).color(128, 128, 128, 255).endVertex();
|
||||
worldrenderer.pos((double) (i1 + b0), (double) (j1 + b1), 0.0D).color(128, 128, 128, 255)
|
||||
.endVertex();
|
||||
worldrenderer.pos((double) (i1 + b0), (double) j1, 0.0D).color(128, 128, 128, 255).endVertex();
|
||||
worldrenderer.pos((double) i1, (double) j1, 0.0D).color(128, 255, 128, 255).endVertex();
|
||||
worldrenderer.pos((double) i1, (double) (j1 + b1), 0.0D).color(128, 255, 128, 255).endVertex();
|
||||
worldrenderer.pos((double) (i1 + progress), (double) (j1 + b1), 0.0D).color(128, 255, 128, 255)
|
||||
.endVertex();
|
||||
worldrenderer.pos((double) (i1 + progress), (double) j1, 0.0D).color(128, 255, 128, 255)
|
||||
.endVertex();
|
||||
tessellator.draw();
|
||||
GlStateManager.enableTexture2D();
|
||||
}
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
public void actionPerformed(GuiButton button) {
|
||||
if(button.id == 0) {
|
||||
mc.displayGuiScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(mc.thePlayer == null) {
|
||||
mc.displayGuiScreen(parent);
|
||||
return;
|
||||
}
|
||||
++timer;
|
||||
if(timer == 1) {
|
||||
byte[] data = ServerInfoCache.loadFromCache(expectHash);
|
||||
if(data != null) {
|
||||
mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, data, WebViewOptions.getEmbedOriginUUID(expectHash)));
|
||||
}else {
|
||||
byte[] b = mc.thePlayer.sendQueue.cachedServerInfoData;
|
||||
if(b != null) {
|
||||
if(b.length == 0) {
|
||||
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
|
||||
}else {
|
||||
ServerInfoCache.storeInCache(expectHash, b);
|
||||
mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, b, WebViewOptions.getEmbedOriginUUID(expectHash)));
|
||||
}
|
||||
}else {
|
||||
statusString = "recieveServerInfo.contactingServer";
|
||||
if(!mc.thePlayer.sendQueue.hasRequestedServerInfo) {
|
||||
if(!ServerInfoCache.hasLastChunk || !Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash)) {
|
||||
ServerInfoCache.clearDownload();
|
||||
mc.thePlayer.sendQueue.sendEaglerMessage(new CPacketRequestServerInfoV4EAG(expectHash));
|
||||
mc.thePlayer.sendQueue.hasRequestedServerInfo = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if(timer > 1) {
|
||||
if(Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash)) {
|
||||
if(ServerInfoCache.hasLastChunk) {
|
||||
statusString = "recieveServerInfo.decompressing";
|
||||
++timer2;
|
||||
if(timer2 == 2) {
|
||||
byte[] finalData = new byte[ServerInfoCache.chunkCurrentSize];
|
||||
int i = 0;
|
||||
for(byte[] b : ServerInfoCache.chunkRecieveBuffer) {
|
||||
System.arraycopy(b, 0, finalData, i, b.length);
|
||||
i += b.length;
|
||||
}
|
||||
if(i != ServerInfoCache.chunkCurrentSize) {
|
||||
logger.error("An unknown error occured!");
|
||||
mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
|
||||
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
|
||||
return;
|
||||
}
|
||||
ServerInfoCache.clearDownload();
|
||||
try {
|
||||
EaglerInputStream bis = new EaglerInputStream(finalData);
|
||||
int finalSize = (new DataInputStream(bis)).readInt();
|
||||
if(finalSize < 0) {
|
||||
logger.error("The response data was corrupt, decompressed size is negative!");
|
||||
mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
|
||||
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
|
||||
return;
|
||||
}
|
||||
if(finalSize > ServerInfoCache.CACHE_MAX_SIZE * 2) {
|
||||
logger.error("Failed to decompress/verify server info response! Size is massive, {} " + finalSize + " bytes reported!");
|
||||
logger.error("Aborting decompression. Rejoin the server to try again.");
|
||||
mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
|
||||
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
|
||||
return;
|
||||
}
|
||||
byte[] decompressed = new byte[finalSize];
|
||||
try(InputStream is = EaglerZLIB.newGZIPInputStream(bis)) {
|
||||
IOUtils.readFully(is, decompressed);
|
||||
}
|
||||
SHA1Digest digest = new SHA1Digest();
|
||||
digest.update(decompressed, 0, decompressed.length);
|
||||
byte[] csum = new byte[20];
|
||||
digest.doFinal(csum, 0);
|
||||
if(Arrays.equals(csum, expectHash)) {
|
||||
ServerInfoCache.storeInCache(csum, decompressed);
|
||||
mc.thePlayer.sendQueue.cachedServerInfoData = decompressed;
|
||||
mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, decompressed, WebViewOptions.getEmbedOriginUUID(expectHash)));
|
||||
}else {
|
||||
logger.error("The data recieved from the server did not have the correct SHA1 checksum! Rejoin the server to try again.");
|
||||
mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
|
||||
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
|
||||
}
|
||||
}catch(IOException ex) {
|
||||
logger.error("Failed to decompress/verify server info response! Rejoin the server to try again.");
|
||||
logger.error(ex);
|
||||
mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
|
||||
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
|
||||
}
|
||||
}
|
||||
}else {
|
||||
statusString = "recieveServerInfo.recievingData";
|
||||
}
|
||||
}else {
|
||||
statusString = "recieveServerInfo.contactingServer";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isPartOfPauseMenu() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.webview;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumWebViewContentMode;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
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 GuiScreenServerInfo extends GuiScreen {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("GuiScreenServerInfo");
|
||||
|
||||
private final GuiScreen parent;
|
||||
private final WebViewOptions opts;
|
||||
private boolean isShowing = false;
|
||||
|
||||
public GuiScreenServerInfo(GuiScreen parent, WebViewOptions opts) {
|
||||
this.parent = parent;
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
public static GuiScreen createForCurrentState(GuiScreen parent, String url) {
|
||||
URI urlObj;
|
||||
try {
|
||||
urlObj = new URI(url);
|
||||
}catch(URISyntaxException ex) {
|
||||
logger.error("Refusing to iframe an invalid URL: {}", url);
|
||||
logger.error(ex);
|
||||
return new GuiScreenGenericErrorMessage("webviewInvalidURL.title", "webviewInvalidURL.desc", parent);
|
||||
}
|
||||
return createForCurrentState(parent, urlObj);
|
||||
}
|
||||
|
||||
public static GuiScreen createForCurrentState(GuiScreen parent, URI url) {
|
||||
boolean support = WebViewOverlayController.supported();
|
||||
boolean fallbackSupport = WebViewOverlayController.fallbackSupported();
|
||||
if(!support && !fallbackSupport) {
|
||||
return new GuiScreenGenericErrorMessage("webviewNotSupported.title", "webviewNotSupported.desc", parent);
|
||||
}
|
||||
WebViewOptions opts = new WebViewOptions();
|
||||
opts.contentMode = EnumWebViewContentMode.URL_BASED;
|
||||
opts.url = url;
|
||||
setupState(opts);
|
||||
opts.permissionsOriginUUID = WebViewOptions.getURLOriginUUID(url);
|
||||
return support ? new GuiScreenServerInfo(parent, opts) : new GuiScreenServerInfoDesktop(parent, opts);
|
||||
}
|
||||
|
||||
public static GuiScreen createForCurrentState(GuiScreen parent, byte[] blob, EaglercraftUUID permissionsOriginUUID) {
|
||||
boolean support = WebViewOverlayController.supported();
|
||||
boolean fallbackSupport = WebViewOverlayController.fallbackSupported();
|
||||
if(!support && !fallbackSupport) {
|
||||
return new GuiScreenGenericErrorMessage("webviewNotSupported.title", "webviewNotSupported.desc", parent);
|
||||
}
|
||||
WebViewOptions opts = new WebViewOptions();
|
||||
opts.contentMode = EnumWebViewContentMode.BLOB_BASED;
|
||||
opts.blob = blob;
|
||||
setupState(opts);
|
||||
opts.permissionsOriginUUID = permissionsOriginUUID;
|
||||
return support ? new GuiScreenServerInfo(parent, opts) : new GuiScreenServerInfoDesktop(parent, opts);
|
||||
}
|
||||
|
||||
public static void setupState(WebViewOptions opts) {
|
||||
opts.scriptEnabled = (PauseMenuCustomizeState.serverInfoEmbedPerms & PauseMenuCustomizeState.SERVER_INFO_EMBED_PERMS_JAVASCRIPT) != 0;
|
||||
opts.strictCSPEnable = (PauseMenuCustomizeState.serverInfoEmbedPerms & PauseMenuCustomizeState.SERVER_INFO_EMBED_PERMS_STRICT_CSP) != 0;
|
||||
opts.serverMessageAPIEnabled = (PauseMenuCustomizeState.serverInfoEmbedPerms & PauseMenuCustomizeState.SERVER_INFO_EMBED_PERMS_MESSAGE_API) != 0;
|
||||
opts.fallbackTitle = PauseMenuCustomizeState.serverInfoEmbedTitle;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
ScaledResolution res = mc.scaledResolution;
|
||||
if(!isShowing) {
|
||||
isShowing = true;
|
||||
WebViewOverlayController.beginShowingSmart(opts, res, 30, 30, width - 60, height - 60);
|
||||
}else {
|
||||
WebViewOverlayController.resizeSmart(res, 30, 30, width - 60, height - 60);
|
||||
}
|
||||
buttonList.clear();
|
||||
buttonList.add(new GuiButton(0, (width - 200) / 2, height - 25, I18n.format("gui.done")));
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
if(isShowing) {
|
||||
isShowing = false;
|
||||
WebViewOverlayController.endShowing();
|
||||
}
|
||||
}
|
||||
|
||||
public void actionPerformed(GuiButton btn) {
|
||||
if(btn.id == 0) {
|
||||
mc.displayGuiScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawScreen(int mx, int my, float pt) {
|
||||
drawDefaultBackground();
|
||||
drawCenteredString(fontRendererObj, PauseMenuCustomizeState.serverInfoEmbedTitle == null ? "Server Info"
|
||||
: PauseMenuCustomizeState.serverInfoEmbedTitle, width / 2, 13, 0xFFFFFF);
|
||||
super.drawScreen(mx, my, pt);
|
||||
}
|
||||
|
||||
protected boolean isPartOfPauseMenu() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.webview;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
|
||||
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 GuiScreenServerInfoDesktop extends GuiScreen {
|
||||
|
||||
private final GuiScreen parent;
|
||||
private final WebViewOptions opts;
|
||||
|
||||
private int timer = 0;
|
||||
private boolean hasStarted = false;
|
||||
|
||||
private GuiButton btnOpen;
|
||||
|
||||
public GuiScreenServerInfoDesktop(GuiScreen parent, WebViewOptions opts) {
|
||||
this.parent = parent;
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
buttonList.clear();
|
||||
buttonList.add(btnOpen = new GuiButton(0, (width - 200) / 2, height / 6 + 110, I18n.format("fallbackWebViewScreen.openButton")));
|
||||
btnOpen.enabled = false;
|
||||
buttonList.add(new GuiButton(1, (width - 200) / 2, height / 6 + 140, I18n.format("fallbackWebViewScreen.exitButton")));
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
++timer;
|
||||
if(timer == 2) {
|
||||
WebViewOverlayController.endFallbackServer();
|
||||
WebViewOverlayController.launchFallback(opts);
|
||||
}else if(timer > 2) {
|
||||
if(WebViewOverlayController.fallbackRunning()) {
|
||||
btnOpen.enabled = WebViewOverlayController.getFallbackURL() != null;
|
||||
hasStarted = true;
|
||||
}else {
|
||||
btnOpen.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void actionPerformed(GuiButton button) {
|
||||
if(button.id == 0) {
|
||||
String link = WebViewOverlayController.getFallbackURL();
|
||||
if(link != null) {
|
||||
EagRuntime.openLink(link);
|
||||
}
|
||||
}else if(button.id == 1) {
|
||||
mc.displayGuiScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
WebViewOverlayController.endFallbackServer();
|
||||
}
|
||||
|
||||
public void drawScreen(int mx, int my, float pt) {
|
||||
drawDefaultBackground();
|
||||
drawCenteredString(fontRendererObj, PauseMenuCustomizeState.serverInfoEmbedTitle, this.width / 2, 70, 16777215);
|
||||
drawCenteredString(fontRendererObj, I18n.format("fallbackWebViewScreen.text0"), this.width / 2, 90, 11184810);
|
||||
String link = WebViewOverlayController.fallbackRunning() ? WebViewOverlayController.getFallbackURL()
|
||||
: I18n.format(hasStarted ? "fallbackWebViewScreen.exited" : "fallbackWebViewScreen.startingUp");
|
||||
drawCenteredString(fontRendererObj, link != null ? link : I18n.format("fallbackWebViewScreen.pleaseWait"),
|
||||
width / 2, 110, 16777215);
|
||||
super.drawScreen(mx, my, pt);
|
||||
}
|
||||
|
||||
protected boolean isPartOfPauseMenu() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.webview;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
|
||||
/**
|
||||
* 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 PermissionsCache {
|
||||
|
||||
public static class Permission {
|
||||
|
||||
public final int perm;
|
||||
public final boolean choice;
|
||||
|
||||
private Permission(int perm, boolean choice) {
|
||||
this.perm = perm;
|
||||
this.choice = choice;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final Map<EaglercraftUUID,Permission> javaScriptAllowed = new HashMap<>();
|
||||
|
||||
public static Permission getJavaScriptAllowed(EaglercraftUUID uuid, int flags) {
|
||||
synchronized(javaScriptAllowed) {
|
||||
if(uuid == null) {
|
||||
return null;
|
||||
}
|
||||
Permission p = javaScriptAllowed.get(uuid);
|
||||
if(p == null) {
|
||||
return null;
|
||||
}
|
||||
return (p.perm | flags) != p.perm ? null : p;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setJavaScriptAllowed(EaglercraftUUID uuid, int flags, boolean allowed) {
|
||||
synchronized(javaScriptAllowed) {
|
||||
if(uuid != null) javaScriptAllowed.put(uuid, new Permission(flags, allowed));
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearJavaScriptAllowed(EaglercraftUUID uuid) {
|
||||
synchronized(javaScriptAllowed) {
|
||||
if(uuid != null) javaScriptAllowed.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.webview;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.HashKey;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketServerInfoDataChunkV4EAG;
|
||||
|
||||
/**
|
||||
* 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 ServerInfoCache {
|
||||
|
||||
public static final int CACHE_MAX_SIZE = 0x200000; // 2 MB
|
||||
|
||||
private static final Map<HashKey,CacheEntry> cache = new HashMap<>();
|
||||
private static int cacheSize = 0;
|
||||
|
||||
private static class CacheEntry {
|
||||
|
||||
private final byte[] data;
|
||||
private final HashKey hash;
|
||||
private long lastHit;
|
||||
|
||||
private CacheEntry(byte[] data, HashKey hash) {
|
||||
this.data = data;
|
||||
this.hash = hash;
|
||||
this.lastHit = EagRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static final List<byte[]> chunkRecieveBuffer = new LinkedList<>();
|
||||
protected static byte[] chunkRecieveHash = null;
|
||||
protected static int chunkCurrentSize = 0;
|
||||
protected static int chunkFinalSize = 0;
|
||||
protected static boolean hasLastChunk = false;
|
||||
|
||||
public static void handleChunk(SPacketServerInfoDataChunkV4EAG chunk) {
|
||||
//System.out.println("p: " + chunk.seqId + " " + chunk.finalSize + " " + Base64.encodeBase64String(chunk.finalHash) + " " + chunk.lastChunk);
|
||||
if (chunkRecieveHash == null || hasLastChunk || !Arrays.equals(chunk.finalHash, chunkRecieveHash)
|
||||
|| chunk.seqId != chunkRecieveBuffer.size()) {
|
||||
chunkRecieveBuffer.clear();
|
||||
hasLastChunk = false;
|
||||
chunkRecieveHash = null;
|
||||
chunkCurrentSize = 0;
|
||||
chunkFinalSize = 0;
|
||||
if(chunk.seqId != 0) {
|
||||
return;
|
||||
}
|
||||
chunkRecieveHash = chunk.finalHash;
|
||||
}
|
||||
chunkRecieveBuffer.add(chunk.data);
|
||||
chunkCurrentSize += chunk.data.length;
|
||||
chunkFinalSize = chunk.finalSize;
|
||||
hasLastChunk = chunk.lastChunk;
|
||||
}
|
||||
|
||||
public static void clearDownload() {
|
||||
chunkRecieveBuffer.clear();
|
||||
hasLastChunk = false;
|
||||
chunkRecieveHash = null;
|
||||
chunkCurrentSize = 0;
|
||||
chunkFinalSize = 0;
|
||||
}
|
||||
|
||||
public static byte[] loadFromCache(byte[] hash) {
|
||||
if(hash == null || hash.length != 20) {
|
||||
return null;
|
||||
}
|
||||
CacheEntry etr = cache.get(new HashKey(hash));
|
||||
if(etr != null) {
|
||||
etr.lastHit = EagRuntime.steadyTimeMillis();
|
||||
return etr.data;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void storeInCache(byte[] hash, byte[] data) {
|
||||
if(hash == null || hash.length != 20 || data == null) {
|
||||
return;
|
||||
}
|
||||
HashKey hashObj = new HashKey(hash);
|
||||
if(cache.containsKey(hashObj)) {
|
||||
return;
|
||||
}
|
||||
shrink(data.length);
|
||||
cache.put(hashObj, new CacheEntry(data, hashObj));
|
||||
cacheSize += data.length;
|
||||
}
|
||||
|
||||
private static void shrink(int toAdd) {
|
||||
if(toAdd > CACHE_MAX_SIZE) {
|
||||
cache.clear();
|
||||
cacheSize = 0;
|
||||
return;
|
||||
}
|
||||
while(!cache.isEmpty() && cacheSize + toAdd > CACHE_MAX_SIZE) {
|
||||
CacheEntry oldest = null;
|
||||
for(CacheEntry e : cache.values()) {
|
||||
if(oldest == null || e.lastHit < oldest.lastHit) {
|
||||
oldest = e;
|
||||
}
|
||||
}
|
||||
if(cache.remove(oldest.hash) != null) {
|
||||
cacheSize -= oldest.data.length;
|
||||
}else {
|
||||
break; //wtf?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.webview;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebView;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
|
||||
/**
|
||||
* 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 WebViewOverlayController {
|
||||
|
||||
public static boolean supported() {
|
||||
return PlatformWebView.supported();
|
||||
}
|
||||
|
||||
public static boolean isShowing() {
|
||||
return PlatformWebView.isShowing();
|
||||
}
|
||||
|
||||
public static void beginShowing(WebViewOptions options, int x, int y, int w, int h) {
|
||||
PlatformWebView.beginShowing(options, x, y, w, h);
|
||||
}
|
||||
|
||||
public static void resize(int x, int y, int w, int h) {
|
||||
PlatformWebView.resize(x, y, w, h);
|
||||
}
|
||||
|
||||
public static void beginShowingSmart(WebViewOptions options, ScaledResolution res, int x, int y, int w, int h) {
|
||||
int fac = res.getScaleFactor();
|
||||
PlatformWebView.beginShowing(options, x * fac, y * fac, w * fac, h * fac);
|
||||
}
|
||||
|
||||
public static void resizeSmart(ScaledResolution res, int x, int y, int w, int h) {
|
||||
int fac = res.getScaleFactor();
|
||||
PlatformWebView.resize(x * fac, y * fac, w * fac, h * fac);
|
||||
}
|
||||
|
||||
public static void endShowing() {
|
||||
PlatformWebView.endShowing();
|
||||
}
|
||||
|
||||
public static boolean fallbackSupported() {
|
||||
return PlatformWebView.fallbackSupported();
|
||||
}
|
||||
|
||||
public static void launchFallback(WebViewOptions options) {
|
||||
PlatformWebView.launchFallback(options);
|
||||
}
|
||||
|
||||
public static boolean fallbackRunning() {
|
||||
return PlatformWebView.fallbackRunning();
|
||||
}
|
||||
|
||||
public static String getFallbackURL() {
|
||||
return PlatformWebView.getFallbackURL();
|
||||
}
|
||||
|
||||
public static void endFallbackServer() {
|
||||
PlatformWebView.endFallbackServer();
|
||||
}
|
||||
|
||||
public static void handleMessagePacket(SPacketWebViewMessageV4EAG packet) {
|
||||
PlatformWebView.handleMessageFromServer(packet);
|
||||
}
|
||||
|
||||
public static interface IPacketSendCallback {
|
||||
boolean sendPacket(GameMessagePacket packet);
|
||||
}
|
||||
|
||||
public static void setPacketSendCallback(IPacketSendCallback callback) {
|
||||
PlatformWebView.setPacketSendCallback(callback);
|
||||
}
|
||||
|
||||
public static void runTick() {
|
||||
PlatformWebView.runTick();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user