Update #39 - Fix various issues with the client

This commit is contained in:
lax1dude
2024-09-26 21:47:56 -07:00
parent c0eddc3dfd
commit 82a70b7649
24 changed files with 314 additions and 45 deletions

View File

@ -597,7 +597,7 @@ public class PlatformInput {
public void handleEvent(WheelEvent evt) {
evt.preventDefault();
evt.stopPropagation();
double delta = evt.getDeltaY();
double delta = -evt.getDeltaY();
mouseDWheel += delta;
if(hasShownPressAnyKey) {
int eventX = (int)(getOffsetX(evt, touchOffsetXTeaVM) * windowDPI);
@ -1246,7 +1246,11 @@ public class PlatformInput {
}
public static int mouseGetEventDWheel() {
return (currentEvent.type == EVENT_MOUSE_WHEEL) ? (currentEvent.wheel == 0.0f ? 0 : (currentEvent.wheel > 0.0f ? -1 : 1)) : 0;
return (currentEvent.type == EVENT_MOUSE_WHEEL) ? fixWheel(currentEvent.wheel) : 0;
}
private static int fixWheel(float val) {
return (val > 0.0f ? 1 : (val < 0.0f ? -1 : 0));
}
public static int mouseGetX() {

View File

@ -5,6 +5,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -13,6 +14,7 @@ import java.util.function.Consumer;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
import net.lax1dude.eaglercraft.v1_8.Filesystem;
import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuEntryPoint;
import org.teavm.interop.Async;
@ -48,7 +50,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EPKLoader;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.ES6ShimStatus;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EarlyLoadScreen;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EnumES6ShimStatus;
@ -58,8 +59,8 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.ImmediateContinue;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.MessageChannel;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain.EPKFileEntry;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.DebugConsoleWindow;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EPKDownloadHelper;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMDataURLManager;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMEnterBootMenuException;
@ -426,29 +427,14 @@ public class PlatformRuntime {
EarlyLoadScreen.paintScreen(glesVer, PlatformOpenGL.checkVAOCapable(), allowBootMenu);
EPKFileEntry[] epkFiles = ClientMain.configEPKFiles;
for(int i = 0; i < epkFiles.length; ++i) {
String url = epkFiles[i].url;
String logURL = url.startsWith("data:") ? "<data: " + url.length() + " chars>" : url;
logger.info("Downloading: {}", logURL);
ArrayBuffer epkFileData = downloadRemoteURI(url);
if(epkFileData == null) {
throw new RuntimeInitializationFailureException("Could not download EPK file \"" + url + "\"");
}
logger.info("Decompressing: {}", logURL);
try {
EPKLoader.loadEPK(epkFileData, epkFiles[i].path, PlatformAssets.assets);
}catch(Throwable t) {
throw new RuntimeInitializationFailureException("Could not extract EPK file \"" + url + "\"", t);
}
if(PlatformAssets.assets == null || !PlatformAssets.assets.isEmpty()) {
PlatformAssets.assets = new HashMap<>();
}
EPKDownloadHelper.downloadEPKFilesOfVersion(ClientMain.configEPKFiles,
teavmCfg.isEnableEPKVersionCheckTeaVM() ? EaglercraftVersion.EPKVersionIdentifier : null,
PlatformAssets.assets);
logger.info("Loaded {} resources from EPKs", PlatformAssets.assets.size());
if(allowBootMenu && BootMenuEntryPoint.checkShouldLaunchFlag(win)) {
@ -606,6 +592,10 @@ public class PlatformRuntime {
}
public static boolean hasFetchSupportTeaVM() {
return hasFetchSupport;
}
public static void downloadRemoteURIByteArray(String assetPackageURI, final Consumer<byte[]> cb) {
downloadRemoteURI(assetPackageURI, arr -> cb.accept(TeaVMUtils.wrapByteArrayBuffer(arr)));
}

View File

@ -0,0 +1,160 @@
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import org.teavm.jso.browser.Window;
import org.teavm.jso.typedarrays.ArrayBuffer;
import net.lax1dude.eaglercraft.v1_8.Base64;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.RuntimeInitializationFailureException;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain.EPKFileEntry;
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 EPKDownloadHelper {
private static final Logger logger = LogManager.getLogger("BrowserRuntime");
public static void downloadEPKFilesOfVersion(EPKFileEntry[] epkFiles, String expectedVersionIdentifier,
Map<String, byte[]> loadedFiles) {
byte[] bTrue = Base64.decodeBase64("true");
boolean oldEPKInvalidFlag = Arrays.equals(bTrue, PlatformApplication.getLocalStorage("epkInvalidFlag", false));
boolean epkInvalidFlag = oldEPKInvalidFlag;
attempt_loop: for(int a = 0; a < 3; ++a) {
if(a == 1 && !PlatformRuntime.hasFetchSupportTeaVM()) continue;
loadedFiles.clear();
boolean canBeInvalid = expectedVersionIdentifier != null;
for(int i = 0; i < epkFiles.length; ++i) {
boolean noCache = false;
String url = null;
switch(a) {
case 0:
url = epkFiles[i].url;
noCache = false;
break;
case 1:
logger.warn("Failed to download one or more correct/valid files, attempting to bypass the browser's cache...");
url = epkFiles[i].url;
noCache = true;
break;
case 2:
logger.warn("Failed to download one or more correct/valid files, attempting to bypass the server's cache...");
url = injectCacheInvalidationHack(epkFiles[i].url, expectedVersionIdentifier);
noCache = true;
break;
}
boolean b = url.startsWith("data:");
boolean c = !b && !url.startsWith("blob:");
String toCheck = url.indexOf("://") != -1 ? url : PlatformRuntime.win.getLocation().getFullURL();
boolean canBeCorrupt = c && (a < 1 || toCheck.startsWith("http:") || toCheck.startsWith("https:"));
canBeInvalid &= c;
String logURL = b ? "<data: " + url.length() + " chars>" : url;
logger.info("Downloading: {}", logURL);
ArrayBuffer epkFileData = PlatformRuntime.downloadRemoteURI(url, !noCache);
if(epkFileData == null) {
if(a < 2 && canBeCorrupt) {
logger.error("Could not download EPK file \"{}\"", logURL);
continue attempt_loop;
}else {
throw new RuntimeInitializationFailureException("Could not download EPK file \"" + logURL + "\"");
}
}
logger.info("Decompressing: {}", logURL);
try {
EPKLoader.loadEPK(epkFileData, epkFiles[i].path, loadedFiles);
}catch(Throwable t) {
if(a < 2 && canBeCorrupt) {
logger.error("Could not extract EPK file \"{}\"", logURL);
continue attempt_loop;
}else {
throw new RuntimeInitializationFailureException("Could not extract EPK file \"" + logURL + "\"", t);
}
}
}
if(canBeInvalid) {
byte[] dat = loadedFiles.get("EPKVersionIdentifier.txt");
if(dat != null) {
String epkStr = (new String(dat, StandardCharsets.UTF_8)).trim();
if(expectedVersionIdentifier.equals(epkStr)) {
epkInvalidFlag = false;
break;
}
logger.error("EPK version identifier \"{}\" does not match the expected identifier \"{}\"", epkStr, expectedVersionIdentifier);
}else {
logger.error("Version identifier file is missing from the EPK, expecting \"{}\"", expectedVersionIdentifier);
}
if(epkInvalidFlag) {
break;
}else {
if(a < 2) {
continue;
}else {
logger.error("Nothing we can do about this, ignoring the invalid EPK version and setting invalid flag to true");
epkInvalidFlag = true;
}
}
}else {
epkInvalidFlag = false;
break;
}
}
if(epkInvalidFlag != oldEPKInvalidFlag) {
PlatformApplication.setLocalStorage("epkInvalidFlag", epkInvalidFlag ? bTrue : null, false);
}
}
private static String injectCacheInvalidationHack(String url, String cacheFixStr) {
if(cacheFixStr != null) {
cacheFixStr = Window.encodeURIComponent(cacheFixStr);
}else {
cacheFixStr = "t" + System.currentTimeMillis();
}
String toCheck = url.indexOf("://") != -1 ? url : PlatformRuntime.win.getLocation().getFullURL();
if(toCheck.startsWith("http:") || toCheck.startsWith("https:")) {
int i = url.indexOf('?');
if(i == url.length() - 1) {
return url + "eaglerCacheFix=" + cacheFixStr;
}else if(i != -1) {
String s = url.substring(i + 1);
if(!s.startsWith("&") && !s.startsWith("#")) {
s = "&" + s;
}
return url.substring(0, i + 1) + "eaglerCacheFix=" + cacheFixStr + s;
}else {
i = url.indexOf('#');
if(i != -1) {
return url.substring(0, i) + "?eaglerCacheFix=" + cacheFixStr + url.substring(i);
}else {
return url + "?eaglerCacheFix=" + cacheFixStr;
}
}
}else {
return url;
}
}
}

View File

@ -87,6 +87,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
private boolean eaglerNoDelay = false;
private boolean ramdiskMode = false;
private boolean singleThreadMode = false;
private boolean enableEPKVersionCheck = true;
public void loadNative(JSObject jsObject) {
integratedServerOpts = new JSONObject();
@ -134,6 +135,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
eaglerNoDelay = eaglercraftXOpts.getEaglerNoDelay(false);
ramdiskMode = eaglercraftXOpts.getRamdiskMode(false);
singleThreadMode = eaglercraftXOpts.getSingleThreadMode(false);
enableEPKVersionCheck = eaglercraftXOpts.getEnableEPKVersionCheck(true);
JSEaglercraftXOptsHooks hooksObj = eaglercraftXOpts.getHooks();
if(hooksObj != null) {
hooks.loadHooks(hooksObj);
@ -263,6 +265,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
eaglerNoDelay = eaglercraftOpts.optBoolean("eaglerNoDelay", false);
ramdiskMode = eaglercraftOpts.optBoolean("ramdiskMode", false);
singleThreadMode = eaglercraftOpts.optBoolean("singleThreadMode", false);
enableEPKVersionCheck = eaglercraftOpts.optBoolean("enableEPKVersionCheck", true);
defaultServers.clear();
JSONArray serversArray = eaglercraftOpts.optJSONArray("servers");
if(serversArray != null) {
@ -505,6 +508,10 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
return singleThreadMode;
}
public boolean isEnableEPKVersionCheckTeaVM() {
return enableEPKVersionCheck;
}
@Override
public boolean isShowBootMenuOnLaunch() {
return showBootMenuOnLaunch;
@ -585,6 +592,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
jsonObject.put("eaglerNoDelay", eaglerNoDelay);
jsonObject.put("ramdiskMode", ramdiskMode);
jsonObject.put("singleThreadMode", singleThreadMode);
jsonObject.put("enableEPKVersionCheck", enableEPKVersionCheck);
JSONArray serversArr = new JSONArray();
for(int i = 0, l = defaultServers.size(); i < l; ++i) {
DefaultServer srv = defaultServers.get(i);

View File

@ -30,7 +30,7 @@ public class TeaVMFetchJS {
@JSBody(params = { }, script = "return (typeof fetch === \"function\");")
public static native boolean checkFetchSupport();
@JSBody(params = { "uri", "forceCache", "callback" }, script = "fetch(uri, { cache: forceCache, mode: \"no-cors\" })"
@JSBody(params = { "uri", "forceCache", "callback" }, script = "fetch(uri, { cache: forceCache, mode: \"cors\" })"
+ ".then(function(res) { return res.arrayBuffer(); }).then(function(arr) { callback(arr); })"
+ ".catch(function(err) { console.error(err); callback(null); });")
public static native void doFetchDownload(String uri, String forceCache, FetchHandler callback);

View File

@ -171,4 +171,7 @@ public abstract class JSEaglercraftXOptsRoot implements JSObject {
@JSBody(params = { "def" }, script = "return (typeof this.singleThreadMode === \"boolean\") ? this.singleThreadMode : def;")
public native boolean getSingleThreadMode(boolean deobfStackTraces);
@JSBody(params = { "def" }, script = "return (typeof this.enableEPKVersionCheck === \"boolean\") ? this.enableEPKVersionCheck : def;")
public native boolean getEnableEPKVersionCheck(boolean deobfStackTraces);
}