Update #37 - Touch support without userscript, many other feats

This commit is contained in:
lax1dude
2024-09-21 20:17:42 -07:00
parent 173727c8c4
commit ec1ab8ece3
683 changed files with 62074 additions and 8996 deletions

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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?
}
}
}
}

View File

@ -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();
}
}