mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 10:58:15 -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);
|
||||
|
||||
}
|
Reference in New Issue
Block a user