mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 02:48:14 -05:00
Update #52 - Fixed various issues with the client
This commit is contained in:
@ -24,6 +24,7 @@ import java.util.Date;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.browser.Storage;
|
||||
@ -43,6 +44,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.MemoryStack;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.ClientMain;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.TeaVMUtils;
|
||||
|
||||
public class PlatformApplication {
|
||||
@ -174,7 +176,23 @@ public class PlatformApplication {
|
||||
}
|
||||
}
|
||||
|
||||
public static final void displayFileChooser(String mime, String ext) {
|
||||
public static void setResetSettingsCallbackWASM() {
|
||||
setResetSettingsCallbackWASM0().call(ClientMain::resetSettings);
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface JSWASMResetSettingsCallback extends JSObject {
|
||||
void callback();
|
||||
}
|
||||
|
||||
private static interface JSWASMResetSettingsCallbackInterface extends JSObject {
|
||||
void call(JSWASMResetSettingsCallback callback);
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "setResetSettingsCallback")
|
||||
private static native JSWASMResetSettingsCallbackInterface setResetSettingsCallbackWASM0();
|
||||
|
||||
public static void displayFileChooser(String mime, String ext) {
|
||||
displayFileChooser0(BetterJSStringConverter.stringToJS(mime), BetterJSStringConverter.stringToJS(ext));
|
||||
}
|
||||
|
||||
|
@ -94,11 +94,26 @@ public class PlatformAudio {
|
||||
logger.error("OGG file support detected as false! Using embedded JOrbis OGG decoder");
|
||||
}
|
||||
}
|
||||
|
||||
if(((WASMGCClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isKeepAliveHackTeaVM()) {
|
||||
byte[] silenceFile = PlatformAssets.getResourceBytes("/assets/eagler/silence_loop.wav");
|
||||
if (silenceFile != null) {
|
||||
MemoryStack.push();
|
||||
try {
|
||||
initKeepAliveHack(WASMGCDirectArrayConverter.byteArrayToStackU8Array(silenceFile));
|
||||
}finally {
|
||||
MemoryStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformAudio", name = "getContext")
|
||||
private static native AudioContext getContext();
|
||||
|
||||
@Import(module = "platformAudio", name = "initKeepAliveHack")
|
||||
private static native void initKeepAliveHack(Uint8Array array);
|
||||
|
||||
protected static class BrowserAudioResource implements IAudioResource {
|
||||
|
||||
protected AudioBuffer buffer;
|
||||
@ -356,11 +371,8 @@ public class PlatformAudio {
|
||||
return audioctx != null;
|
||||
}
|
||||
|
||||
@JSBody(params = { "node" }, script = "node.distanceModel = \"linear\";")
|
||||
static native void setDistanceModelLinearFast(PannerNode node) ;
|
||||
|
||||
@JSBody(params = { "node" }, script = "node.panningModel = \"HRTF\";")
|
||||
static native void setPanningModelHRTFFast(PannerNode node) ;
|
||||
@Import(module = "platformAudio", name = "setupPanner")
|
||||
static native void setupPanner(PannerNode node, float maxDist, float x, float y, float z);
|
||||
|
||||
public static IAudioHandle beginPlayback(IAudioResource track, float x, float y, float z,
|
||||
float volume, float pitch, boolean repeat) {
|
||||
@ -373,17 +385,10 @@ public class PlatformAudio {
|
||||
src.setLoop(repeat);
|
||||
|
||||
PannerNode panner = audioctx.createPanner();
|
||||
panner.setPosition(x, y, z);
|
||||
|
||||
float v1 = volume * 16.0f;
|
||||
if(v1 < 16.0f) v1 = 16.0f;
|
||||
panner.setMaxDistance(v1);
|
||||
panner.setRolloffFactor(1.0f);
|
||||
setDistanceModelLinearFast(panner);
|
||||
setPanningModelHRTFFast(panner);
|
||||
panner.setConeInnerAngle(360.0f);
|
||||
panner.setConeOuterAngle(0.0f);
|
||||
panner.setConeOuterGain(0.0f);
|
||||
panner.setOrientation(0.0f, 1.0f, 0.0f);
|
||||
setupPanner(panner, v1, x, y, z);
|
||||
|
||||
GainNode gain = audioctx.createGain();
|
||||
float v2 = volume;
|
||||
@ -396,7 +401,7 @@ public class PlatformAudio {
|
||||
if(gameRecGain != null) {
|
||||
gain.connect(gameRecGain);
|
||||
}
|
||||
|
||||
|
||||
src.start();
|
||||
|
||||
BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, panner, gain, pitch, repeat);
|
||||
|
@ -113,6 +113,7 @@ public class PlatformInput {
|
||||
|
||||
static boolean vsync = true;
|
||||
static boolean vsyncSupport = false;
|
||||
static boolean finish = true;
|
||||
|
||||
private static Map<String, LegacyKeycodeTranslator.LegacyKeycode> keyCodeTranslatorMap = null;
|
||||
|
||||
@ -125,6 +126,7 @@ public class PlatformInput {
|
||||
fullscreenSupported = supportsFullscreen0();
|
||||
vsyncSupport = isVSyncSupported0();
|
||||
WASMGCClientConfigAdapter conf = (WASMGCClientConfigAdapter)PlatformRuntime.getClientConfigAdapter();
|
||||
finish = conf.isFinishOnSwapTeaVM();
|
||||
useVisualViewport = conf.isUseVisualViewportTeaVM() && isVisualViewport0();
|
||||
lastWasResizedWindowWidth = -2;
|
||||
lastWasResizedWindowHeight = -2;
|
||||
@ -656,7 +658,7 @@ public class PlatformInput {
|
||||
PlatformScreenRecord.captureFrameHook();
|
||||
}
|
||||
|
||||
updatePlatformAndSleep(fpsLimit, vsync && vsyncSupport);// && vsync
|
||||
updatePlatformAndSleep(fpsLimit, vsync && vsyncSupport, finish);
|
||||
PlatformRuntime.pollJSEventsAfterSleep();
|
||||
}
|
||||
|
||||
@ -664,7 +666,7 @@ public class PlatformInput {
|
||||
private static native void updateCanvasSize(int width, int height);
|
||||
|
||||
@Import(module = "platformInput", name = "updatePlatformAndSleep")
|
||||
private static native void updatePlatformAndSleep(int fpsLimit, boolean vsync);
|
||||
private static native void updatePlatformAndSleep(int fpsLimit, boolean vsync, boolean finish);
|
||||
|
||||
public static boolean isVSyncSupported() {
|
||||
return vsyncSupport;
|
||||
|
@ -79,6 +79,7 @@ public class PlatformRuntime {
|
||||
canvas = getCanvasElement();
|
||||
printMemoryStackAddrWASMGC();
|
||||
PlatformApplication.setMCServerWindowGlobal(null);
|
||||
PlatformApplication.setResetSettingsCallbackWASM();
|
||||
PlatformOpenGL.initContext();
|
||||
PlatformInput.initContext(win, parent, canvas);
|
||||
|
||||
|
@ -215,16 +215,8 @@ public class PlatformVoiceClient {
|
||||
audioNode.disconnect(gain);
|
||||
}
|
||||
panner = PlatformAudio.audioctx.createPanner();
|
||||
panner.setRolloffFactor(1f);
|
||||
PlatformAudio.setDistanceModelLinearFast(panner);
|
||||
PlatformAudio.setPanningModelHRTFFast(panner);
|
||||
panner.setConeInnerAngle(360f);
|
||||
panner.setConeOuterAngle(0f);
|
||||
panner.setConeOuterGain(0f);
|
||||
panner.setOrientation(0f, 1f, 0f);
|
||||
panner.setPosition(0, 0, 0);
|
||||
float vol = VoiceClientController.getVoiceListenVolume();
|
||||
panner.setMaxDistance(vol * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
|
||||
PlatformAudio.setupPanner(panner, vol * 2 * VoiceClientController.getVoiceProximity() + 0.1f, 0, 0, 0);
|
||||
gain = PlatformAudio.audioctx.createGain();
|
||||
gain.getGain().setValue(vol);
|
||||
audioNode.connect(gain);
|
||||
|
@ -30,22 +30,26 @@ public class BetterJSStringConverter {
|
||||
|
||||
@Unmanaged
|
||||
public static JSString stringToJS(String input) {
|
||||
if (input == null) return null;
|
||||
return (JSString) JS.wrap(input);
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
@SuppressWarnings("unchecked")
|
||||
public static JSArray<JSString> stringArrayToJS(String[] input) {
|
||||
if (input == null) return null;
|
||||
return (JSArray<JSString>) JS.wrap(input);
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static String stringFromJS(JSString input) {
|
||||
if (input == null) return null;
|
||||
return JS.unwrapString(input);
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static String[] stringArrayFromJS(JSArray<JSString> input) {
|
||||
if (input == null) return null;
|
||||
return JS.unwrapStringArray(input);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import org.teavm.jso.browser.Window;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.ContextLostError;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsRoot;
|
||||
import net.minecraft.client.main.Main;
|
||||
@ -98,6 +99,25 @@ public class ClientMain {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined here to match the JS runtime
|
||||
*/
|
||||
public static void resetSettings() {
|
||||
boolean y = false;
|
||||
if (Window.confirm("Do you want to reset client settings?")) {
|
||||
PlatformApplication.setLocalStorage("g", null);
|
||||
PlatformApplication.setLocalStorage("p", null);
|
||||
y = true;
|
||||
}
|
||||
if (Window.confirm("Do you want to reset servers and relays?")) {
|
||||
PlatformApplication.setLocalStorage("r", null);
|
||||
PlatformApplication.setLocalStorage("s", null);
|
||||
y = true;
|
||||
}
|
||||
if (y) {
|
||||
Window.alert("Settings reset.");
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "getEaglercraftXOpts")
|
||||
private static native JSObject getEaglerXOpts();
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
@ -24,16 +25,17 @@ import com.jcraft.jzlib.CRC32;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.IOUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerBufferInputStream;
|
||||
|
||||
public class EPKLoader {
|
||||
|
||||
public static final void loadEPK(ByteBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
public static void loadEPK(ByteBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
loadEPK(epkFile, "", loadedFiles);
|
||||
}
|
||||
|
||||
public static final void loadEPK(ByteBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
public static void loadEPK(ByteBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
int byteLength = epkFile.remaining();
|
||||
int l = byteLength - 16;
|
||||
if(l < 1) {
|
||||
@ -43,7 +45,7 @@ public class EPKLoader {
|
||||
EaglerBufferInputStream is = new EaglerBufferInputStream(epkFile);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
is.read(header);
|
||||
IOUtils.readFully(is, header);
|
||||
String type = readASCII(header);
|
||||
|
||||
if(!"EAGPKG$$".equals(type)) {
|
||||
@ -65,13 +67,13 @@ public class EPKLoader {
|
||||
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||
}
|
||||
|
||||
is.skip(is.read()); // skip filename
|
||||
is.skip(loadShort(is)); // skip comment
|
||||
is.skip(8); // skip millis date
|
||||
IOUtils.skipFully(is, loadByte(is)); // skip filename
|
||||
IOUtils.skipFully(is, loadShort(is)); // skip comment
|
||||
IOUtils.skipFully(is, 8); // skip millis date
|
||||
|
||||
int numFiles = loadInt(is);
|
||||
|
||||
char compressionType = (char)is.read();
|
||||
char compressionType = (char)loadByte(is);
|
||||
|
||||
InputStream zis;
|
||||
switch(compressionType) {
|
||||
@ -112,11 +114,11 @@ public class EPKLoader {
|
||||
if(i == 0) {
|
||||
if(blockType == blockHead) {
|
||||
byte[] readType = new byte[len];
|
||||
zis.read(readType);
|
||||
IOUtils.readFully(zis, readType);
|
||||
if(!"file-type".equals(name) || !"epk/resources".equals(readASCII(readType))) {
|
||||
throw new IOException("EPK is not of file-type 'epk/resources'!");
|
||||
}
|
||||
if(zis.read() != '>') {
|
||||
if(loadByte(zis) != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
continue;
|
||||
@ -133,7 +135,7 @@ public class EPKLoader {
|
||||
int expectedCRC = loadInt(zis);
|
||||
|
||||
byte[] load = new byte[len - 5];
|
||||
zis.read(load);
|
||||
IOUtils.readFully(zis, load);
|
||||
|
||||
if(len > 5) {
|
||||
crc32.reset();
|
||||
@ -143,16 +145,16 @@ public class EPKLoader {
|
||||
}
|
||||
}
|
||||
|
||||
if(zis.read() != ':') {
|
||||
if(loadByte(zis) != ':') {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
loadedFiles.put(path + name, load);
|
||||
}else {
|
||||
zis.skip(len);
|
||||
IOUtils.skipFully(zis, len);
|
||||
}
|
||||
|
||||
if(zis.read() != '>') {
|
||||
if(loadByte(zis) != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
}
|
||||
@ -163,28 +165,36 @@ public class EPKLoader {
|
||||
|
||||
zis.close();
|
||||
}
|
||||
|
||||
private static final int loadShort(InputStream is) throws IOException {
|
||||
return (is.read() << 8) | is.read();
|
||||
|
||||
private static int loadByte(InputStream is) throws IOException {
|
||||
int i = is.read();
|
||||
if (i < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private static final int loadInt(InputStream is) throws IOException {
|
||||
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||
|
||||
private static int loadShort(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
private static final String readASCII(byte[] bytesIn) throws IOException {
|
||||
|
||||
private static int loadInt(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 24) | (loadByte(is) << 16) | (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
private static String readASCII(byte[] bytesIn) throws IOException {
|
||||
char[] charIn = new char[bytesIn.length];
|
||||
for(int i = 0; i < bytesIn.length; ++i) {
|
||||
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
private static final String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = bytesIn.read();
|
||||
|
||||
private static String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = loadByte(bytesIn);
|
||||
char[] charIn = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||
charIn[i] = (char)loadByte(bytesIn);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
@ -82,6 +82,8 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
private boolean ramdiskMode = false;
|
||||
private boolean singleThreadMode = false;
|
||||
private boolean enforceVSync = true;
|
||||
private boolean keepAliveHack = true;
|
||||
private boolean finishOnSwap = true;
|
||||
|
||||
public void loadNative(JSObject jsObject) {
|
||||
JSEaglercraftXOptsRoot eaglercraftXOpts = (JSEaglercraftXOptsRoot)jsObject;
|
||||
@ -124,6 +126,8 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
ramdiskMode = eaglercraftXOpts.getRamdiskMode(false);
|
||||
singleThreadMode = eaglercraftXOpts.getSingleThreadMode(false);
|
||||
enforceVSync = eaglercraftXOpts.getEnforceVSync(true);
|
||||
keepAliveHack = eaglercraftXOpts.getKeepAliveHack(true);
|
||||
finishOnSwap = eaglercraftXOpts.getFinishOnSwap(true);
|
||||
JSEaglercraftXOptsHooks hooksObj = eaglercraftXOpts.getHooks();
|
||||
if(hooksObj != null) {
|
||||
hooks.loadHooks(hooksObj);
|
||||
@ -400,6 +404,14 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
return enforceVSync;
|
||||
}
|
||||
|
||||
public boolean isKeepAliveHackTeaVM() {
|
||||
return keepAliveHack;
|
||||
}
|
||||
|
||||
public boolean isFinishOnSwapTeaVM() {
|
||||
return finishOnSwap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
@ -446,6 +458,8 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
jsonObject.put("ramdiskMode", ramdiskMode);
|
||||
jsonObject.put("singleThreadMode", singleThreadMode);
|
||||
jsonObject.put("enforceVSync", enforceVSync);
|
||||
jsonObject.put("keepAliveHack", keepAliveHack);
|
||||
jsonObject.put("finishOnSwap", finishOnSwap);
|
||||
JSONArray serversArr = new JSONArray();
|
||||
for(int i = 0, l = defaultServers.size(); i < l; ++i) {
|
||||
DefaultServer srv = defaultServers.get(i);
|
||||
|
@ -114,10 +114,14 @@ public class WASMGCClientConfigAdapterHooks implements IClientConfigAdapterHooks
|
||||
}
|
||||
|
||||
public void loadHooks(JSEaglercraftXOptsHooks hooks) {
|
||||
saveHook = (LocalStorageSaveHook)hooks.getLocalStorageSavedHook();
|
||||
loadHook = (LocalStorageLoadHook)hooks.getLocalStorageLoadedHook();
|
||||
crashHook = (CrashReportHook)hooks.getCrashReportHook();
|
||||
screenChangedHook = (ScreenChangeHook)hooks.getScreenChangedHook();
|
||||
JSObject obj = hooks.getLocalStorageSavedHook();
|
||||
saveHook = obj != null ? (LocalStorageSaveHook) obj : null;
|
||||
obj = hooks.getLocalStorageLoadedHook();
|
||||
loadHook = obj != null ? (LocalStorageLoadHook) obj : null;
|
||||
obj = hooks.getCrashReportHook();
|
||||
crashHook = obj != null ? (CrashReportHook) obj : null;
|
||||
obj = hooks.getScreenChangedHook();
|
||||
screenChangedHook = obj != null ? (ScreenChangeHook) obj : null;
|
||||
}
|
||||
|
||||
}
|
@ -172,4 +172,10 @@ public interface JSEaglercraftXOptsRoot extends JSObject {
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableEPKVersionCheck === \"boolean\") ? this.enableEPKVersionCheck : def;")
|
||||
boolean getEnableEPKVersionCheck(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.keepAliveHack === \"boolean\") ? this.keepAliveHack : def;")
|
||||
boolean getKeepAliveHack(boolean keepAliveHack);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.finishOnSwap === \"boolean\") ? this.finishOnSwap : def;")
|
||||
boolean getFinishOnSwap(boolean finishOnSwap);
|
||||
|
||||
}
|
@ -100,6 +100,12 @@ var isCrashed = false;
|
||||
const crashReportStrings = [];
|
||||
/** @type {function()|null} */
|
||||
var removeEventHandlers = null;
|
||||
/** @type {function()|null} */
|
||||
var keepAliveCallback = null;
|
||||
/** @type {function()|null} */
|
||||
var showDebugConsole = null;
|
||||
/** @type {function()|null} */
|
||||
var resetSettings = null;
|
||||
|
||||
const runtimeOpts = {
|
||||
localStorageNamespace: "_eaglercraftX",
|
||||
@ -530,6 +536,44 @@ function deobfuscateStack(stack) {
|
||||
return stackFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
function createToolButtons() {
|
||||
const buttonResetSettings = /** @type {HTMLButtonElement} */ (document.createElement("button"));
|
||||
buttonResetSettings.setAttribute("style", "margin-left:10px;");
|
||||
buttonResetSettings.innerText = "Reset Settings";
|
||||
buttonResetSettings.addEventListener("click", function(/** Event */ evt) {
|
||||
if (resetSettings) {
|
||||
resetSettings();
|
||||
} else {
|
||||
window.alert("Local storage has not been initialized yet");
|
||||
}
|
||||
});
|
||||
const buttonOpenConsole = /** @type {HTMLButtonElement} */ (document.createElement("button"));
|
||||
buttonOpenConsole.setAttribute("style", "margin-left:10px;");
|
||||
buttonOpenConsole.innerText = "Open Debug Console";
|
||||
buttonOpenConsole.addEventListener("click", function(/** Event */ evt) {
|
||||
if (showDebugConsole) {
|
||||
showDebugConsole();
|
||||
} else {
|
||||
window.alert("Debug console has not been initialized yet");
|
||||
}
|
||||
});
|
||||
const div1 = /** @type {HTMLElement} */ (document.createElement("div"));
|
||||
div1.setAttribute("style", "position:absolute;bottom:5px;right:0px;");
|
||||
div1.appendChild(buttonResetSettings);
|
||||
div1.appendChild(buttonOpenConsole);
|
||||
const div2 = /** @type {HTMLElement} */ (document.createElement("div"));
|
||||
div2.setAttribute("style", "position:relative;");
|
||||
div2.appendChild(div1);
|
||||
const div3 = /** @type {HTMLElement} */ (document.createElement("div"));
|
||||
div3.classList.add("_eaglercraftX_crash_tools_element");
|
||||
div3.setAttribute("style", "z-index:101;position:absolute;top:135px;left:10%;right:10%;height:0px;");
|
||||
div3.appendChild(div2);
|
||||
return div3;
|
||||
}
|
||||
|
||||
function displayUncaughtCrashReport(error) {
|
||||
const stack = error ? deobfuscateStack(error.stack) : null;
|
||||
const crashContent = "Native Browser Exception\n" +
|
||||
@ -657,6 +701,7 @@ function displayCrashReport(crashReport, enablePrint) {
|
||||
div.classList.add("_eaglercraftX_crash_element");
|
||||
parentEl.appendChild(img);
|
||||
parentEl.appendChild(div);
|
||||
parentEl.appendChild(createToolButtons());
|
||||
div.appendChild(document.createTextNode(strFinal));
|
||||
|
||||
if(removeEventHandlers) removeEventHandlers();
|
||||
@ -709,6 +754,7 @@ function showIncompatibleScreen(msg) {
|
||||
div.classList.add("_eaglercraftX_incompatible_element");
|
||||
parentEl.appendChild(img);
|
||||
parentEl.appendChild(div);
|
||||
parentEl.appendChild(createToolButtons());
|
||||
div.innerHTML = "<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg>+ This device is incompatible with Eaglercraft :(</h2>"
|
||||
+ "<div style=\"margin-left:40px;\">"
|
||||
+ "<p style=\"font-size:1.2em;\"><b style=\"font-size:1.1em;\">Issue:</b> <span style=\"color:#BB0000;\" id=\"_eaglercraftX_crashReason\"></span><br /></p>"
|
||||
@ -785,14 +831,17 @@ function showContextLostScreen(msg) {
|
||||
div.classList.add("_eaglercraftX_context_lost_element");
|
||||
parentEl.appendChild(img);
|
||||
parentEl.appendChild(div);
|
||||
parentEl.appendChild(createToolButtons());
|
||||
div.innerHTML = "<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg> + WebGL context lost!</h2>"
|
||||
+ "<div style=\"margin-left:40px;\">"
|
||||
+ "<p style=\"font-size:1.2em;\">Your browser has forcibly released all of the resources "
|
||||
+ "allocated by the game's 3D rendering context. EaglercraftX cannot continue, please refresh "
|
||||
+ "the page to restart the game.</p>"
|
||||
+ "the page to restart the game, sorry for the inconvenience.</p>"
|
||||
+ "<p style=\"font-size:1.2em;\">This is not a bug, it is usually caused by the browser "
|
||||
+ "deciding it no longer has sufficient resources to continue rendering this page. If it "
|
||||
+ "happens again, try closing your other browser tabs and windows.</p>"
|
||||
+ "<p style=\"font-size:1.2em;\">If you're playing with vsync disabled, try enabling vsync "
|
||||
+ "to allow the browser to control the GPU usage more precisely.</p>"
|
||||
+ "<p style=\"overflow-wrap:break-word;white-space:pre-wrap;font:0.75em monospace;margin-top:1.5em;\" id=\"_eaglercraftX_contextLostTrace\"></p>"
|
||||
+ "</div>";
|
||||
|
||||
|
@ -328,7 +328,7 @@ function initializePlatfApplication(applicationImports) {
|
||||
/** @type {HTMLElement} */
|
||||
var loggerMessageContainer = null;
|
||||
/** @type {string} */
|
||||
const loggerLocalStorageKey = runtimeOpts.localStorageNamespace + "showDebugConsole";
|
||||
const loggerLocalStorageKey = runtimeOpts.localStorageNamespace + ".showDebugConsole";
|
||||
/** @type {string} */
|
||||
const loggerWinUnloadEvent = runtimeOpts.fixDebugConsoleUnloadListener ? "beforeunload" : "unload";
|
||||
|
||||
@ -365,7 +365,7 @@ function initializePlatfApplication(applicationImports) {
|
||||
showDebugConsole0();
|
||||
}
|
||||
|
||||
function showDebugConsole() {
|
||||
showDebugConsole = function() {
|
||||
debugConsoleLocalStorageSet(true);
|
||||
showDebugConsole0();
|
||||
}
|
||||
@ -480,6 +480,17 @@ function initializePlatfApplication(applicationImports) {
|
||||
return faviconURL;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Object}
|
||||
*/
|
||||
applicationImports["setResetSettingsCallback"] = function() {
|
||||
return {
|
||||
"call": function(/** function() */ cb) {
|
||||
resetSettings = cb;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -499,4 +510,5 @@ function initializeNoPlatfApplication(applicationImports) {
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "addLogMessage");
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "isShowingDebugConsole");
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "getFaviconURL");
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "setResetSettingsCallback");
|
||||
}
|
||||
|
@ -25,6 +25,47 @@ function setCurrentAudioContext(audioContext, audioImports) {
|
||||
return audioContext;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} fileData
|
||||
*/
|
||||
audioImports["initKeepAliveHack"] = function(fileData) {
|
||||
const copiedData = new Uint8Array(fileData.length);
|
||||
copiedData.set(fileData, 0);
|
||||
const copiedDataURI = URL.createObjectURL(new Blob([copiedData], {type: "audio/wav"}));
|
||||
const audioElement = /** @type {HTMLAudioElement} */ (document.createElement("audio"));
|
||||
audioElement.classList.add("_eaglercraftX_keepalive_hack");
|
||||
audioElement.setAttribute("style", "display:none;");
|
||||
audioElement.autoplay = true;
|
||||
audioElement.loop = true;
|
||||
const sourceElement = /** @type {HTMLSourceElement} */ (document.createElement("source"));
|
||||
sourceElement.type = "audio/wav";
|
||||
sourceElement.src = copiedDataURI;
|
||||
audioElement.appendChild(sourceElement);
|
||||
audioElement.addEventListener("seeked", function() {
|
||||
// NOP, wakes up the browser's event loop
|
||||
});
|
||||
parentElement.appendChild(audioElement);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {PannerNode} node
|
||||
* @param {number} maxDist
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} z
|
||||
*/
|
||||
audioImports["setupPanner"] = function(node, maxDist, x, y, z) {
|
||||
node.maxDistance = maxDist;
|
||||
node.rolloffFactor = 1.0;
|
||||
node.panningModel = "HRTF";
|
||||
node.distanceModel = "linear";
|
||||
node.coneInnerAngle = 360.0;
|
||||
node.coneOuterAngle = 0.0;
|
||||
node.coneOuterGain = 0.0;
|
||||
node.setOrientation(0.0, 1.0, 0.0);
|
||||
node.setPosition(x, y, z);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {AudioBufferSourceNode} sourceNode
|
||||
* @param {Object} isEnded
|
||||
@ -72,6 +113,8 @@ function setNoAudioContext(audioImports) {
|
||||
audioImports["getContext"] = function() {
|
||||
return null;
|
||||
};
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "setupPanner");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "initKeepAliveHack");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "registerIsEndedHandler");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "releaseIsEndedHandler");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "decodeAudioBrowser");
|
||||
|
@ -617,15 +617,19 @@ async function initPlatformInput(inputImports) {
|
||||
/**
|
||||
* @param {number} fpsLimit
|
||||
* @param {number} vsync
|
||||
* @param {number} finish
|
||||
* @return {Promise}
|
||||
*/
|
||||
function updatePlatformAndSleepImpl(fpsLimit, vsync) {
|
||||
function updatePlatformAndSleepImpl(fpsLimit, vsync, finish) {
|
||||
reportWindowSize();
|
||||
if((typeof document.visibilityState !== "string") || (document.visibilityState === "visible")) {
|
||||
if(vsyncSupport && vsync) {
|
||||
manualSyncTimer = 0;
|
||||
return asyncRequestAnimationFrame();
|
||||
}else {
|
||||
if(finish) {
|
||||
webglContext.finish();
|
||||
}
|
||||
if(fpsLimit <= 0) {
|
||||
manualSyncTimer = 0;
|
||||
return swapDelayImpl();
|
||||
|
Reference in New Issue
Block a user