partial vsync implementation, immediate continue hack
This commit is contained in:
parent
511e95a067
commit
d862a08a4a
|
@ -59,15 +59,10 @@ public class EAGMinecraftServer extends MinecraftServer {
|
||||||
this.tick();
|
this.tick();
|
||||||
lastTick = SysUtil.steadyTimeMillis();
|
lastTick = SysUtil.steadyTimeMillis();
|
||||||
} else {
|
} else {
|
||||||
boolean mustYield = false;
|
if (delta >= 50l) {
|
||||||
while (delta >= 50L) {
|
|
||||||
if(mustYield) {
|
|
||||||
SysUtil.sleep(1); // allow some async
|
|
||||||
}
|
|
||||||
delta -= 50L;
|
delta -= 50L;
|
||||||
lastTick = SysUtil.steadyTimeMillis();
|
lastTick += 50l;
|
||||||
this.tick();
|
this.tick();
|
||||||
mustYield = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -749,6 +749,8 @@ public class IntegratedServer {
|
||||||
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket01StopServer.ID));
|
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket01StopServer.ID));
|
||||||
currentProcess = null;
|
currentProcess = null;
|
||||||
}
|
}
|
||||||
|
}else {
|
||||||
|
SysUtil.sleep(50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,7 +769,7 @@ public class IntegratedServer {
|
||||||
|
|
||||||
mainLoop();
|
mainLoop();
|
||||||
|
|
||||||
SysUtil.sleep(1); // allow some async to occur
|
SysUtil.immediateContinue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// yee
|
// yee
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package net.lax1dude.eaglercraft.sp;
|
||||||
|
|
||||||
|
import org.teavm.jso.JSBody;
|
||||||
|
import org.teavm.jso.JSClass;
|
||||||
|
import org.teavm.jso.JSObject;
|
||||||
|
import org.teavm.jso.JSProperty;
|
||||||
|
import org.teavm.jso.workers.MessagePort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@JSClass
|
||||||
|
public class MessageChannel implements JSObject {
|
||||||
|
|
||||||
|
@JSBody(params = { }, script = "return (typeof MessageChannel !== \"undefined\");")
|
||||||
|
public static native boolean supported();
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
public native MessagePort getPort1();
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
public native MessagePort getPort2();
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,10 @@ import org.teavm.interop.Async;
|
||||||
import org.teavm.interop.AsyncCallback;
|
import org.teavm.interop.AsyncCallback;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
import org.teavm.jso.JSObject;
|
import org.teavm.jso.JSObject;
|
||||||
|
import org.teavm.jso.browser.Window;
|
||||||
|
import org.teavm.jso.core.JSString;
|
||||||
|
import org.teavm.jso.dom.events.EventListener;
|
||||||
|
import org.teavm.jso.dom.events.MessageEvent;
|
||||||
import org.teavm.platform.Platform;
|
import org.teavm.platform.Platform;
|
||||||
import org.teavm.platform.PlatformRunnable;
|
import org.teavm.platform.PlatformRunnable;
|
||||||
|
|
||||||
|
@ -45,4 +49,110 @@ public class SysUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean hasCheckedImmediateContinue = false;
|
||||||
|
private static MessageChannel immediateContinueChannel = null;
|
||||||
|
private static Runnable currentContinueHack = null;
|
||||||
|
private static final Object immediateContLock = new Object();
|
||||||
|
private static final JSString emptyJSString = JSString.valueOf("");
|
||||||
|
|
||||||
|
public static void immediateContinue() {
|
||||||
|
if(!hasCheckedImmediateContinue) {
|
||||||
|
hasCheckedImmediateContinue = true;
|
||||||
|
checkImmediateContinueSupport();
|
||||||
|
}
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
immediateContinueTeaVM();
|
||||||
|
}else {
|
||||||
|
sleep(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
private static native void immediateContinueTeaVM();
|
||||||
|
|
||||||
|
private static void immediateContinueTeaVM(final AsyncCallback<Void> cb) {
|
||||||
|
synchronized(immediateContLock) {
|
||||||
|
if(currentContinueHack != null) {
|
||||||
|
cb.error(new IllegalStateException("Worker thread is already waiting for an immediate continue callback!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentContinueHack = () -> {
|
||||||
|
cb.complete(null);
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
immediateContinueChannel.getPort2().postMessage(emptyJSString);
|
||||||
|
}catch(Throwable t) {
|
||||||
|
System.err.println("Caught error posting immediate continue, using setTimeout instead");
|
||||||
|
Window.setTimeout(() -> cb.complete(null), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkImmediateContinueSupport() {
|
||||||
|
try {
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
if(!MessageChannel.supported()) {
|
||||||
|
System.err.println("Fast immediate continue will be disabled for server context due to MessageChannel being unsupported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
immediateContinueChannel = new MessageChannel();
|
||||||
|
immediateContinueChannel.getPort1().addEventListener("message", new EventListener<MessageEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(MessageEvent evt) {
|
||||||
|
Runnable toRun;
|
||||||
|
synchronized(immediateContLock) {
|
||||||
|
toRun = currentContinueHack;
|
||||||
|
currentContinueHack = null;
|
||||||
|
}
|
||||||
|
if(toRun != null) {
|
||||||
|
toRun.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
immediateContinueChannel.getPort1().start();
|
||||||
|
immediateContinueChannel.getPort2().start();
|
||||||
|
final boolean[] checkMe = new boolean[1];
|
||||||
|
checkMe[0] = false;
|
||||||
|
currentContinueHack = () -> {
|
||||||
|
checkMe[0] = true;
|
||||||
|
};
|
||||||
|
immediateContinueChannel.getPort2().postMessage(emptyJSString);
|
||||||
|
if(checkMe[0]) {
|
||||||
|
currentContinueHack = null;
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
safeShutdownChannel(immediateContinueChannel);
|
||||||
|
}
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
System.err.println("Fast immediate continue will be disabled for server context due to actually continuing immediately");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sleep(10);
|
||||||
|
currentContinueHack = null;
|
||||||
|
if(!checkMe[0]) {
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
safeShutdownChannel(immediateContinueChannel);
|
||||||
|
}
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
System.err.println("Fast immediate continue will be disabled for server context due to startup check failing");
|
||||||
|
}
|
||||||
|
}catch(Throwable t) {
|
||||||
|
System.err.println("Fast immediate continue will be disabled for server context due to exceptions");
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
safeShutdownChannel(immediateContinueChannel);
|
||||||
|
}
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void safeShutdownChannel(MessageChannel chan) {
|
||||||
|
try {
|
||||||
|
chan.getPort1().close();
|
||||||
|
}catch(Throwable tt) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
chan.getPort2().close();
|
||||||
|
}catch(Throwable tt) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,8 +81,6 @@ import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch;
|
||||||
import net.lax1dude.eaglercraft.RelayWorldsQuery;
|
import net.lax1dude.eaglercraft.RelayWorldsQuery;
|
||||||
import net.lax1dude.eaglercraft.ServerQuery;
|
import net.lax1dude.eaglercraft.ServerQuery;
|
||||||
import net.lax1dude.eaglercraft.Voice;
|
import net.lax1dude.eaglercraft.Voice;
|
||||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ProgramGL;
|
|
||||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit;
|
|
||||||
import net.lax1dude.eaglercraft.adapter.lwjgl.GameWindowListener;
|
import net.lax1dude.eaglercraft.adapter.lwjgl.GameWindowListener;
|
||||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket;
|
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket;
|
||||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld;
|
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld;
|
||||||
|
@ -971,11 +969,15 @@ public class EaglerAdapterImpl2 {
|
||||||
public static final boolean shouldShutdown() {
|
public static final boolean shouldShutdown() {
|
||||||
return Display.isCloseRequested();
|
return Display.isCloseRequested();
|
||||||
}
|
}
|
||||||
public static final void updateDisplay() {
|
public static final void updateDisplay(int fpsLimit, boolean vsync) {
|
||||||
|
if(vsync) {
|
||||||
|
Display.setVSyncEnabled(true);
|
||||||
|
Display.update();
|
||||||
|
}else {
|
||||||
|
Display.setVSyncEnabled(false);
|
||||||
|
Display.sync(fpsLimit);
|
||||||
Display.update();
|
Display.update();
|
||||||
}
|
}
|
||||||
public static final void setVSyncEnabled(boolean p1) {
|
|
||||||
Display.setVSyncEnabled(p1);
|
|
||||||
}
|
}
|
||||||
public static final void enableRepeatEvents(boolean b) {
|
public static final void enableRepeatEvents(boolean b) {
|
||||||
Keyboard.enableRepeatEvents(b);
|
Keyboard.enableRepeatEvents(b);
|
||||||
|
@ -1005,17 +1007,14 @@ public class EaglerAdapterImpl2 {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static final void syncDisplay(int performanceToFps) {
|
|
||||||
Display.sync(performanceToFps);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Set<String> rateLimitedAddresses = new HashSet();
|
private static final Set<String> rateLimitedAddresses = new HashSet<>();
|
||||||
private static final Set<String> blockedAddresses = new HashSet();
|
private static final Set<String> blockedAddresses = new HashSet<>();
|
||||||
|
|
||||||
private static WebSocketClient clientSocket = null;
|
private static WebSocketClient clientSocket = null;
|
||||||
private static final Object socketSync = new Object();
|
private static final Object socketSync = new Object();
|
||||||
|
|
||||||
private static LinkedList<byte[]> readPackets = new LinkedList();
|
private static LinkedList<byte[]> readPackets = new LinkedList<>();
|
||||||
|
|
||||||
private static class EaglerSocketClient extends WebSocketClient {
|
private static class EaglerSocketClient extends WebSocketClient {
|
||||||
|
|
||||||
|
@ -1465,7 +1464,7 @@ public class EaglerAdapterImpl2 {
|
||||||
public static final float getVoiceSpeakVolume() {
|
public static final float getVoiceSpeakVolume() {
|
||||||
return volumeSpeak;
|
return volumeSpeak;
|
||||||
}
|
}
|
||||||
private static final Set<String> emptySet = new HashSet();
|
private static final Set<String> emptySet = new HashSet<>();
|
||||||
public static final Set<String> getVoiceListening() {
|
public static final Set<String> getVoiceListening() {
|
||||||
return emptySet;
|
return emptySet;
|
||||||
}
|
}
|
||||||
|
@ -1478,7 +1477,7 @@ public class EaglerAdapterImpl2 {
|
||||||
public static final Set<String> getVoiceMuted() {
|
public static final Set<String> getVoiceMuted() {
|
||||||
return emptySet;
|
return emptySet;
|
||||||
}
|
}
|
||||||
private static final List<String> emptyList = new ArrayList();
|
private static final List<String> emptyList = new ArrayList<>();
|
||||||
public static final List<String> getVoiceRecent() {
|
public static final List<String> getVoiceRecent() {
|
||||||
return emptyList;
|
return emptyList;
|
||||||
}
|
}
|
||||||
|
@ -1546,8 +1545,8 @@ public class EaglerAdapterImpl2 {
|
||||||
|
|
||||||
private static class ServerQueryImpl extends WebSocketClient implements ServerQuery {
|
private static class ServerQueryImpl extends WebSocketClient implements ServerQuery {
|
||||||
|
|
||||||
private final LinkedList<QueryResponse> queryResponses = new LinkedList();
|
private final LinkedList<QueryResponse> queryResponses = new LinkedList<>();
|
||||||
private final LinkedList<byte[]> queryResponsesBytes = new LinkedList();
|
private final LinkedList<byte[]> queryResponsesBytes = new LinkedList<>();
|
||||||
private final String type;
|
private final String type;
|
||||||
private boolean open;
|
private boolean open;
|
||||||
private boolean alive;
|
private boolean alive;
|
||||||
|
|
|
@ -99,7 +99,8 @@ public class EarlyLoadScreen {
|
||||||
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
||||||
_wglDisableVertexAttribArray(0);
|
_wglDisableVertexAttribArray(0);
|
||||||
_wglFlush();
|
_wglFlush();
|
||||||
updateDisplay();
|
updateDisplay(0, false);
|
||||||
|
sleep(20);
|
||||||
|
|
||||||
_wglUseProgram(null);
|
_wglUseProgram(null);
|
||||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, null);
|
_wglBindBuffer(_wGL_ARRAY_BUFFER, null);
|
||||||
|
@ -156,7 +157,8 @@ public class EarlyLoadScreen {
|
||||||
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
||||||
_wglDisableVertexAttribArray(0);
|
_wglDisableVertexAttribArray(0);
|
||||||
_wglFlush();
|
_wglFlush();
|
||||||
updateDisplay();
|
updateDisplay(0, false);
|
||||||
|
sleep(20);
|
||||||
|
|
||||||
_wglUseProgram(null);
|
_wglUseProgram(null);
|
||||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, null);
|
_wglBindBuffer(_wGL_ARRAY_BUFFER, null);
|
||||||
|
|
|
@ -1613,4 +1613,33 @@ public class EaglerAdapterGL30 extends EaglerAdapterImpl2 {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean sync(int limitFramerate, long[] timerPtr) {
|
||||||
|
boolean limitFPS = limitFramerate > 0 && limitFramerate < 1000;
|
||||||
|
boolean blocked = false;
|
||||||
|
|
||||||
|
if(limitFPS) {
|
||||||
|
if(timerPtr[0] == 0l) {
|
||||||
|
timerPtr[0] = steadyTimeMillis();
|
||||||
|
}else {
|
||||||
|
long millis = steadyTimeMillis();
|
||||||
|
long frameMillis = (1000l / limitFramerate);
|
||||||
|
long frameTime = millis - timerPtr[0];
|
||||||
|
if(frameTime > 2000l || frameTime < 0l) {
|
||||||
|
frameTime = frameMillis;
|
||||||
|
timerPtr[0] = millis;
|
||||||
|
}else {
|
||||||
|
timerPtr[0] += frameMillis;
|
||||||
|
}
|
||||||
|
if(frameTime >= 0l && frameTime < frameMillis) {
|
||||||
|
sleep((int)(frameMillis - frameTime));
|
||||||
|
blocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
timerPtr[0] = 0l;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocked;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,6 +243,7 @@ public class Minecraft implements Runnable {
|
||||||
|
|
||||||
public boolean lanState = false;
|
public boolean lanState = false;
|
||||||
public boolean yeeState = false;
|
public boolean yeeState = false;
|
||||||
|
public boolean checkGLErrors = false;
|
||||||
|
|
||||||
public Minecraft() {
|
public Minecraft() {
|
||||||
this.tempDisplayHeight = 480;
|
this.tempDisplayHeight = 480;
|
||||||
|
@ -404,7 +405,7 @@ public class Minecraft implements Runnable {
|
||||||
EaglerAdapter.glPopMatrix();
|
EaglerAdapter.glPopMatrix();
|
||||||
|
|
||||||
EaglerAdapter.glFlush();
|
EaglerAdapter.glFlush();
|
||||||
EaglerAdapter.updateDisplay();
|
updateDisplay();
|
||||||
|
|
||||||
long t = t1 + 17 + 17*i - EaglerAdapter.steadyTimeMillis();
|
long t = t1 + 17 + 17*i - EaglerAdapter.steadyTimeMillis();
|
||||||
if(t > 0) {
|
if(t > 0) {
|
||||||
|
@ -437,7 +438,7 @@ public class Minecraft implements Runnable {
|
||||||
EaglerAdapter.glPopMatrix();
|
EaglerAdapter.glPopMatrix();
|
||||||
|
|
||||||
EaglerAdapter.glFlush();
|
EaglerAdapter.glFlush();
|
||||||
EaglerAdapter.updateDisplay();
|
updateDisplay();
|
||||||
|
|
||||||
long t = t1 + 17 + 17*i - EaglerAdapter.steadyTimeMillis();
|
long t = t1 + 17 + 17*i - EaglerAdapter.steadyTimeMillis();
|
||||||
if(t > 0) {
|
if(t > 0) {
|
||||||
|
@ -468,7 +469,7 @@ public class Minecraft implements Runnable {
|
||||||
EaglerAdapter.glPopMatrix();
|
EaglerAdapter.glPopMatrix();
|
||||||
|
|
||||||
EaglerAdapter.glFlush();
|
EaglerAdapter.glFlush();
|
||||||
EaglerAdapter.updateDisplay();
|
updateDisplay();
|
||||||
|
|
||||||
long t = t1 + 17 + 17*i - EaglerAdapter.steadyTimeMillis();
|
long t = t1 + 17 + 17*i - EaglerAdapter.steadyTimeMillis();
|
||||||
if(t > 0) {
|
if(t > 0) {
|
||||||
|
@ -478,7 +479,7 @@ public class Minecraft implements Runnable {
|
||||||
|
|
||||||
EaglerAdapter.glClear(EaglerAdapter.GL_COLOR_BUFFER_BIT | EaglerAdapter.GL_DEPTH_BUFFER_BIT);
|
EaglerAdapter.glClear(EaglerAdapter.GL_COLOR_BUFFER_BIT | EaglerAdapter.GL_DEPTH_BUFFER_BIT);
|
||||||
EaglerAdapter.glFlush();
|
EaglerAdapter.glFlush();
|
||||||
EaglerAdapter.updateDisplay();
|
updateDisplay();
|
||||||
|
|
||||||
EaglerAdapter.sleep(100);
|
EaglerAdapter.sleep(100);
|
||||||
|
|
||||||
|
@ -521,7 +522,7 @@ public class Minecraft implements Runnable {
|
||||||
EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST);
|
EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST);
|
||||||
EaglerAdapter.glAlphaFunc(EaglerAdapter.GL_GREATER, 0.1F);
|
EaglerAdapter.glAlphaFunc(EaglerAdapter.GL_GREATER, 0.1F);
|
||||||
EaglerAdapter.glFlush();
|
EaglerAdapter.glFlush();
|
||||||
EaglerAdapter.updateDisplay();
|
updateDisplay();
|
||||||
EaglerAdapter.optimize();
|
EaglerAdapter.optimize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,6 +604,7 @@ public class Minecraft implements Runnable {
|
||||||
* string.
|
* string.
|
||||||
*/
|
*/
|
||||||
public void checkGLError(String par1Str) {
|
public void checkGLError(String par1Str) {
|
||||||
|
if(!checkGLErrors) return;
|
||||||
int var2;
|
int var2;
|
||||||
|
|
||||||
|
|
||||||
|
@ -712,7 +714,7 @@ public class Minecraft implements Runnable {
|
||||||
EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D);
|
EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D);
|
||||||
|
|
||||||
if (!EaglerAdapter.isKeyDown(65)) {
|
if (!EaglerAdapter.isKeyDown(65)) {
|
||||||
EaglerAdapter.updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.thePlayer != null && this.thePlayer.isEntityInsideOpaqueBlock()) {
|
if (this.thePlayer != null && this.thePlayer.isEntityInsideOpaqueBlock()) {
|
||||||
|
@ -781,11 +783,6 @@ public class Minecraft implements Runnable {
|
||||||
chunkGeometryUpdates = 0;
|
chunkGeometryUpdates = 0;
|
||||||
secondTimer = EaglerAdapter.steadyTimeMillis();
|
secondTimer = EaglerAdapter.steadyTimeMillis();
|
||||||
}
|
}
|
||||||
this.mcProfiler.startSection("syncDisplay");
|
|
||||||
|
|
||||||
if (this.func_90020_K() > 0) {
|
|
||||||
EaglerAdapter.syncDisplay(EntityRenderer.performanceToFps(this.func_90020_K()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isGonnaTakeDatScreenShot) {
|
if(isGonnaTakeDatScreenShot) {
|
||||||
isGonnaTakeDatScreenShot = false;
|
isGonnaTakeDatScreenShot = false;
|
||||||
|
@ -1104,6 +1101,11 @@ public class Minecraft implements Runnable {
|
||||||
this.voiceOverlay.setResolution(var4, var5);
|
this.voiceOverlay.setResolution(var4, var5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateDisplay() {
|
||||||
|
int i = this.func_90020_K();
|
||||||
|
EaglerAdapter.updateDisplay(i > 0 ? EntityRenderer.performanceToFps(i) : 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean wasPaused = false;
|
private boolean wasPaused = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -101,13 +101,13 @@ public class GuiConnecting extends GuiScreen {
|
||||||
private void showDisconnectScreen(String e) {
|
private void showDisconnectScreen(String e) {
|
||||||
RateLimit l = EaglerAdapter.getRateLimitStatus();
|
RateLimit l = EaglerAdapter.getRateLimitStatus();
|
||||||
if(l == RateLimit.NOW_LOCKED) {
|
if(l == RateLimit.NOW_LOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipNowLocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipNowLocked", "disconnect.endOfStream"));
|
||||||
}else if(l == RateLimit.LOCKED) {
|
}else if(l == RateLimit.LOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipLocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipLocked", "disconnect.endOfStream"));
|
||||||
}else if(l == RateLimit.BLOCKED) {
|
}else if(l == RateLimit.BLOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipBlocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipBlocked", "disconnect.endOfStream"));
|
||||||
}else if(l == RateLimit.FAILED_POSSIBLY_LOCKED) {
|
}else if(l == RateLimit.FAILED_POSSIBLY_LOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipFailedPossiblyLocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "disconnect.ipFailedPossiblyLocked", "disconnect.endOfStream"));
|
||||||
}else {
|
}else {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "connect.failed", "disconnect.genericReason", "could not connect to "+uri, e));
|
this.mc.displayGuiScreen(new GuiDisconnected(this.field_98098_c, "connect.failed", "disconnect.genericReason", "could not connect to "+uri, e));
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ public class LoadingScreenRenderer implements IProgressUpdate {
|
||||||
|
|
||||||
this.mc.fontRenderer.drawStringWithShadow(this.currentlyDisplayedText, (var5 - this.mc.fontRenderer.getStringWidth(this.currentlyDisplayedText)) / 2, var6 / 2 - 4 - 16, 16777215);
|
this.mc.fontRenderer.drawStringWithShadow(this.currentlyDisplayedText, (var5 - this.mc.fontRenderer.getStringWidth(this.currentlyDisplayedText)) / 2, var6 / 2 - 4 - 16, 16777215);
|
||||||
this.mc.fontRenderer.drawStringWithShadow(this.field_73727_a, (var5 - this.mc.fontRenderer.getStringWidth(this.field_73727_a)) / 2, var6 / 2 - 4 + 8, 16777215);
|
this.mc.fontRenderer.drawStringWithShadow(this.field_73727_a, (var5 - this.mc.fontRenderer.getStringWidth(this.field_73727_a)) / 2, var6 / 2 - 4 + 8, 16777215);
|
||||||
EaglerAdapter.updateDisplay();
|
this.mc.updateDisplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,20 +119,20 @@ public class NetClientHandler extends NetHandler {
|
||||||
RateLimit r = EaglerAdapter.getRateLimitStatus();
|
RateLimit r = EaglerAdapter.getRateLimitStatus();
|
||||||
if(r != null) {
|
if(r != null) {
|
||||||
if(r == RateLimit.NOW_LOCKED) {
|
if(r == RateLimit.NOW_LOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipNowLocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipNowLocked", "disconnect.endOfStream"));
|
||||||
}else if(r == RateLimit.LOCKED) {
|
}else if(r == RateLimit.LOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipLocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipLocked", "disconnect.endOfStream"));
|
||||||
}else if(r == RateLimit.BLOCKED) {
|
}else if(r == RateLimit.BLOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipBlocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipBlocked", "disconnect.endOfStream"));
|
||||||
}else if(r == RateLimit.FAILED_POSSIBLY_LOCKED) {
|
}else if(r == RateLimit.FAILED_POSSIBLY_LOCKED) {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipFailedPossiblyLocked", "disconnect.endOfStream", null));
|
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.ipFailedPossiblyLocked", "disconnect.endOfStream"));
|
||||||
}else {
|
}else {
|
||||||
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "RateLimit." + r.name(), null));
|
this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "RateLimit." + r.name()));
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
if(!(this.mc.currentScreen instanceof GuiDisconnected) && !(this.mc.currentScreen instanceof GuiScreenSingleplayerException) &&
|
if(!(this.mc.currentScreen instanceof GuiDisconnected) && !(this.mc.currentScreen instanceof GuiScreenSingleplayerException) &&
|
||||||
!(this.mc.currentScreen instanceof GuiScreenSingleplayerLoading)) {
|
!(this.mc.currentScreen instanceof GuiScreenSingleplayerLoading)) {
|
||||||
this.mc.stopServerAndDisplayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "disconnect.endOfStream", null));
|
this.mc.stopServerAndDisplayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "disconnect.endOfStream"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.disconnected = true;
|
this.disconnected = true;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.teavm.interop.AsyncCallback;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
import org.teavm.jso.JSFunctor;
|
import org.teavm.jso.JSFunctor;
|
||||||
import org.teavm.jso.JSObject;
|
import org.teavm.jso.JSObject;
|
||||||
|
import org.teavm.jso.JSProperty;
|
||||||
import org.teavm.jso.ajax.ReadyStateChangeHandler;
|
import org.teavm.jso.ajax.ReadyStateChangeHandler;
|
||||||
import org.teavm.jso.ajax.XMLHttpRequest;
|
import org.teavm.jso.ajax.XMLHttpRequest;
|
||||||
import org.teavm.jso.browser.Storage;
|
import org.teavm.jso.browser.Storage;
|
||||||
|
@ -39,6 +40,7 @@ import org.teavm.jso.browser.TimerHandler;
|
||||||
import org.teavm.jso.browser.Window;
|
import org.teavm.jso.browser.Window;
|
||||||
import org.teavm.jso.canvas.CanvasRenderingContext2D;
|
import org.teavm.jso.canvas.CanvasRenderingContext2D;
|
||||||
import org.teavm.jso.canvas.ImageData;
|
import org.teavm.jso.canvas.ImageData;
|
||||||
|
import org.teavm.jso.core.JSString;
|
||||||
import org.teavm.jso.dom.css.CSSStyleDeclaration;
|
import org.teavm.jso.dom.css.CSSStyleDeclaration;
|
||||||
import org.teavm.jso.dom.events.ErrorEvent;
|
import org.teavm.jso.dom.events.ErrorEvent;
|
||||||
import org.teavm.jso.dom.events.Event;
|
import org.teavm.jso.dom.events.Event;
|
||||||
|
@ -108,10 +110,12 @@ import net.lax1dude.eaglercraft.Voice;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftLANClient;
|
import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftLANClient;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftLANServer;
|
import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftLANServer;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftVoiceClient;
|
import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftVoiceClient;
|
||||||
|
import net.lax1dude.eaglercraft.adapter.teavm.MessageChannel;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.SelfDefence;
|
import net.lax1dude.eaglercraft.adapter.teavm.SelfDefence;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext;
|
import net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.WebGLQuery;
|
import net.lax1dude.eaglercraft.adapter.teavm.WebGLQuery;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.WebGLVertexArray;
|
import net.lax1dude.eaglercraft.adapter.teavm.WebGLVertexArray;
|
||||||
|
import net.lax1dude.eaglercraft.glemu.EaglerAdapterGL30;
|
||||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket;
|
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket;
|
||||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket00Handshake;
|
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket00Handshake;
|
||||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds;
|
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds;
|
||||||
|
@ -243,6 +247,13 @@ public class EaglerAdapterImpl2 {
|
||||||
private static String[] identifier = new String[0];
|
private static String[] identifier = new String[0];
|
||||||
private static String integratedServerScript = "worker_bootstrap.js";
|
private static String integratedServerScript = "worker_bootstrap.js";
|
||||||
private static boolean anisotropicFilteringSupported = false;
|
private static boolean anisotropicFilteringSupported = false;
|
||||||
|
private static boolean vsyncSupport = false;
|
||||||
|
private static int vsyncTimeout = -1;
|
||||||
|
private static boolean useDelayOnSwap = false;
|
||||||
|
private static MessageChannel immediateContinueChannel = null;
|
||||||
|
private static Runnable currentMsgChannelContinueHack = null;
|
||||||
|
|
||||||
|
private static final EagsFileChooser fileChooser = initFileChooser();
|
||||||
|
|
||||||
public static final String[] getIdentifier() {
|
public static final String[] getIdentifier() {
|
||||||
return identifier;
|
return identifier;
|
||||||
|
@ -395,6 +406,18 @@ public class EaglerAdapterImpl2 {
|
||||||
});
|
});
|
||||||
onBeforeCloseRegister();
|
onBeforeCloseRegister();
|
||||||
|
|
||||||
|
checkImmediateContinueSupport();
|
||||||
|
|
||||||
|
vsyncTimeout = -1;
|
||||||
|
vsyncSupport = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
asyncRequestAnimationFrame();
|
||||||
|
vsyncSupport = true;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
System.err.println("VSync is not supported on this browser!");
|
||||||
|
}
|
||||||
|
|
||||||
initFileChooser();
|
initFileChooser();
|
||||||
|
|
||||||
EarlyLoadScreen.paintScreen();
|
EarlyLoadScreen.paintScreen();
|
||||||
|
@ -456,33 +479,54 @@ public class EaglerAdapterImpl2 {
|
||||||
@JSBody(params = { }, script = "return window.startVoiceClient();")
|
@JSBody(params = { }, script = "return window.startVoiceClient();")
|
||||||
private static native EaglercraftVoiceClient startVoiceClient();
|
private static native EaglercraftVoiceClient startVoiceClient();
|
||||||
|
|
||||||
|
private static interface EagsFileChooser extends JSObject {
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
HTMLElement getInputElement();
|
||||||
|
|
||||||
|
void openFileChooser(String ext, String mime);
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
ArrayBuffer getGetFileChooserResult();
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
void setGetFileChooserResult(ArrayBuffer val);
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
String getGetFileChooserResultName();
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
void setGetFileChooserResultName(String str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@JSBody(params = { }, script =
|
@JSBody(params = { }, script =
|
||||||
"window.eagsFileChooser = {\r\n" +
|
"var ret = {\r\n" +
|
||||||
"inputElement: null,\r\n" +
|
"inputElement: null,\r\n" +
|
||||||
"openFileChooser: function(ext, mime){\r\n" +
|
"openFileChooser: function(ext, mime){\r\n" +
|
||||||
"var el = window.eagsFileChooser.inputElement = document.createElement(\"input\");\r\n" +
|
"var el = ret.inputElement = document.createElement(\"input\");\r\n" +
|
||||||
"el.type = \"file\";\r\n" +
|
"el.type = \"file\";\r\n" +
|
||||||
"el.multiple = false;\r\n" +
|
"el.multiple = false;\r\n" +
|
||||||
"el.addEventListener(\"change\", function(evt){\r\n" +
|
"el.addEventListener(\"change\", function(evt){\r\n" +
|
||||||
"var f = window.eagsFileChooser.inputElement.files;\r\n" +
|
"var f = ret.inputElement.files;\r\n" +
|
||||||
"if(f.length == 0){\r\n" +
|
"if(f.length == 0){\r\n" +
|
||||||
"window.eagsFileChooser.getFileChooserResult = null;\r\n" +
|
"ret.getFileChooserResult = null;\r\n" +
|
||||||
"}else{\r\n" +
|
"}else{\r\n" +
|
||||||
"(async function(){\r\n" +
|
"f[0].arrayBuffer().then(function(res) {\r\n" +
|
||||||
"window.eagsFileChooser.getFileChooserResult = await f[0].arrayBuffer();\r\n" +
|
"ret.getFileChooserResult = res;\r\n" +
|
||||||
"window.eagsFileChooser.getFileChooserResultName = f[0].name;\r\n" +
|
"ret.getFileChooserResultName = f[0].name;\r\n" +
|
||||||
"})();\r\n" +
|
"});\r\n" +
|
||||||
"}\r\n" +
|
"}\r\n" +
|
||||||
"});\r\n" +
|
"});\r\n" +
|
||||||
"window.eagsFileChooser.getFileChooserResult = null;\r\n" +
|
"ret.getFileChooserResult = null;\r\n" +
|
||||||
"window.eagsFileChooser.getFileChooserResultName = null;\r\n" +
|
"ret.getFileChooserResultName = null;\r\n" +
|
||||||
"el.accept = \".\" + ext;\r\n" +
|
"el.accept = \".\" + ext;\r\n" +
|
||||||
"el.click();\r\n" +
|
"el.click();\r\n" +
|
||||||
"},\r\n" +
|
"},\r\n" +
|
||||||
"getFileChooserResult: null,\r\n" +
|
"getFileChooserResult: null,\r\n" +
|
||||||
"getFileChooserResultName: null\r\n" +
|
"getFileChooserResultName: null\r\n" +
|
||||||
"};")
|
"}; return ret;")
|
||||||
private static native void initFileChooser();
|
private static native EagsFileChooser initFileChooser();
|
||||||
|
|
||||||
public static final void destroyContext() {
|
public static final void destroyContext() {
|
||||||
|
|
||||||
|
@ -1695,7 +1739,13 @@ public class EaglerAdapterImpl2 {
|
||||||
public static final boolean shouldShutdown() {
|
public static final boolean shouldShutdown() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public static final void updateDisplay() {
|
public static final boolean isVSyncSupported() {
|
||||||
|
return vsyncSupport;
|
||||||
|
}
|
||||||
|
@JSBody(params = { "doc" }, script = "return (typeof doc.visibilityState !== \"string\") || (doc.visibilityState === \"visible\");")
|
||||||
|
private static native boolean getVisibilityState(JSObject doc);
|
||||||
|
private static final long[] syncTimer = new long[1];
|
||||||
|
public static final void updateDisplay(int fpsLimit, boolean vsync) {
|
||||||
double r = win.getDevicePixelRatio();
|
double r = win.getDevicePixelRatio();
|
||||||
int w = parent.getClientWidth();
|
int w = parent.getClientWidth();
|
||||||
int h = parent.getClientHeight();
|
int h = parent.getClientHeight();
|
||||||
|
@ -1713,7 +1763,172 @@ public class EaglerAdapterImpl2 {
|
||||||
webgl.blitFramebuffer(0, 0, backBufferWidth, backBufferHeight, 0, 0, w2, h2, COLOR_BUFFER_BIT, NEAREST);
|
webgl.blitFramebuffer(0, 0, backBufferWidth, backBufferHeight, 0, 0, w2, h2, COLOR_BUFFER_BIT, NEAREST);
|
||||||
webgl.bindFramebuffer(FRAMEBUFFER, backBuffer.obj);
|
webgl.bindFramebuffer(FRAMEBUFFER, backBuffer.obj);
|
||||||
resizeBackBuffer(w2, h2);
|
resizeBackBuffer(w2, h2);
|
||||||
sleep(1);
|
|
||||||
|
if(getVisibilityState(win.getDocument())) {
|
||||||
|
if(vsyncSupport && vsync) {
|
||||||
|
syncTimer[0] = 0l;
|
||||||
|
asyncRequestAnimationFrame();
|
||||||
|
}else {
|
||||||
|
if(fpsLimit <= 0) {
|
||||||
|
syncTimer[0] = 0l;
|
||||||
|
swapDelayTeaVM();
|
||||||
|
}else {
|
||||||
|
if(!EaglerAdapterGL30.sync(fpsLimit, syncTimer)) {
|
||||||
|
swapDelayTeaVM();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
syncTimer[0] = 0l;
|
||||||
|
sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Async
|
||||||
|
private static native void asyncRequestAnimationFrame();
|
||||||
|
private static void asyncRequestAnimationFrame(AsyncCallback<Void> cb) {
|
||||||
|
if(vsyncTimeout != -1) {
|
||||||
|
cb.error(new IllegalStateException("Already waiting for vsync!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final boolean[] hasTimedOut = new boolean[] { false };
|
||||||
|
final int[] timeout = new int[] { -1 };
|
||||||
|
Window.requestAnimationFrame((d) -> {
|
||||||
|
if(!hasTimedOut[0]) {
|
||||||
|
hasTimedOut[0] = true;
|
||||||
|
if(vsyncTimeout != -1) {
|
||||||
|
if(vsyncTimeout == timeout[0]) {
|
||||||
|
try {
|
||||||
|
Window.clearTimeout(vsyncTimeout);
|
||||||
|
}catch(Throwable t) {
|
||||||
|
}
|
||||||
|
vsyncTimeout = -1;
|
||||||
|
}
|
||||||
|
cb.complete(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
vsyncTimeout = timeout[0] = Window.setTimeout(() -> {
|
||||||
|
if(!hasTimedOut[0]) {
|
||||||
|
hasTimedOut[0] = true;
|
||||||
|
if(vsyncTimeout != -1) {
|
||||||
|
vsyncTimeout = -1;
|
||||||
|
cb.complete(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
private static final void swapDelayTeaVM() {
|
||||||
|
if(!useDelayOnSwap && immediateContinueChannel != null) {
|
||||||
|
immediateContinueTeaVM0();
|
||||||
|
}else {
|
||||||
|
sleep(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static final void immediateContinue() {
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
immediateContinueTeaVM0();
|
||||||
|
}else {
|
||||||
|
sleep(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static final JSString emptyJSString = JSString.valueOf("");
|
||||||
|
@Async
|
||||||
|
private static native void immediateContinueTeaVM0();
|
||||||
|
private static void immediateContinueTeaVM0(final AsyncCallback<Void> cb) {
|
||||||
|
if(currentMsgChannelContinueHack != null) {
|
||||||
|
cb.error(new IllegalStateException("Main thread is already waiting for an immediate continue callback!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentMsgChannelContinueHack = () -> {
|
||||||
|
cb.complete(null);
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
immediateContinueChannel.getPort2().postMessage(emptyJSString);
|
||||||
|
}catch(Throwable t) {
|
||||||
|
currentMsgChannelContinueHack = null;
|
||||||
|
System.err.println("Caught error posting immediate continue, using setTimeout instead");
|
||||||
|
Window.setTimeout(() -> cb.complete(null), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static final int IMMEDIATE_CONT_SUPPORTED = 0;
|
||||||
|
private static final int IMMEDIATE_CONT_FAILED_NOT_ASYNC = 1;
|
||||||
|
private static final int IMMEDIATE_CONT_FAILED_NOT_CONT = 2;
|
||||||
|
private static final int IMMEDIATE_CONT_FAILED_EXCEPTIONS = 3;
|
||||||
|
private static void checkImmediateContinueSupport() {
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
int stat = checkImmediateContinueSupport0();
|
||||||
|
if(stat == IMMEDIATE_CONT_SUPPORTED) {
|
||||||
|
return;
|
||||||
|
}else if(stat == IMMEDIATE_CONT_FAILED_NOT_ASYNC) {
|
||||||
|
System.err.println("MessageChannel fast immediate continue hack is incompatible with this browser due to actually continuing immediately!");
|
||||||
|
}else if(stat == IMMEDIATE_CONT_FAILED_NOT_CONT) {
|
||||||
|
System.err.println("MessageChannel fast immediate continue hack is incompatible with this browser due to startup check failing!");
|
||||||
|
}else if(stat == IMMEDIATE_CONT_FAILED_EXCEPTIONS) {
|
||||||
|
System.err.println("MessageChannel fast immediate continue hack is incompatible with this browser due to exceptions!");
|
||||||
|
}
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
}
|
||||||
|
private static int checkImmediateContinueSupport0() {
|
||||||
|
try {
|
||||||
|
if(!MessageChannel.supported()) {
|
||||||
|
return IMMEDIATE_CONT_SUPPORTED;
|
||||||
|
}
|
||||||
|
immediateContinueChannel = new MessageChannel();
|
||||||
|
immediateContinueChannel.getPort1().addEventListener("message", new EventListener<MessageEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(MessageEvent evt) {
|
||||||
|
Runnable toRun = currentMsgChannelContinueHack;
|
||||||
|
currentMsgChannelContinueHack = null;
|
||||||
|
if(toRun != null) {
|
||||||
|
toRun.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
immediateContinueChannel.getPort1().start();
|
||||||
|
immediateContinueChannel.getPort2().start();
|
||||||
|
final boolean[] checkMe = new boolean[1];
|
||||||
|
checkMe[0] = false;
|
||||||
|
currentMsgChannelContinueHack = () -> {
|
||||||
|
checkMe[0] = true;
|
||||||
|
};
|
||||||
|
immediateContinueChannel.getPort2().postMessage(emptyJSString);
|
||||||
|
if(checkMe[0]) {
|
||||||
|
currentMsgChannelContinueHack = null;
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
safeShutdownChannel(immediateContinueChannel);
|
||||||
|
}
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
return IMMEDIATE_CONT_FAILED_NOT_ASYNC;
|
||||||
|
}
|
||||||
|
sleep(10);
|
||||||
|
currentMsgChannelContinueHack = null;
|
||||||
|
if(!checkMe[0]) {
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
safeShutdownChannel(immediateContinueChannel);
|
||||||
|
}
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
return IMMEDIATE_CONT_FAILED_NOT_CONT;
|
||||||
|
}else {
|
||||||
|
return IMMEDIATE_CONT_SUPPORTED;
|
||||||
|
}
|
||||||
|
}catch(Throwable t) {
|
||||||
|
currentMsgChannelContinueHack = null;
|
||||||
|
if(immediateContinueChannel != null) {
|
||||||
|
safeShutdownChannel(immediateContinueChannel);
|
||||||
|
}
|
||||||
|
immediateContinueChannel = null;
|
||||||
|
return IMMEDIATE_CONT_FAILED_EXCEPTIONS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void safeShutdownChannel(MessageChannel chan) {
|
||||||
|
try {
|
||||||
|
chan.getPort1().close();
|
||||||
|
}catch(Throwable tt) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
chan.getPort2().close();
|
||||||
|
}catch(Throwable tt) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public static final void setupBackBuffer() {
|
public static final void setupBackBuffer() {
|
||||||
backBuffer = _wglCreateFramebuffer();
|
backBuffer = _wglCreateFramebuffer();
|
||||||
|
@ -1739,9 +1954,6 @@ public class EaglerAdapterImpl2 {
|
||||||
}
|
}
|
||||||
public static final float getContentScaling() {
|
public static final float getContentScaling() {
|
||||||
return (float)win.getDevicePixelRatio();
|
return (float)win.getDevicePixelRatio();
|
||||||
}
|
|
||||||
public static final void setVSyncEnabled(boolean p1) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public static final void enableRepeatEvents(boolean b) {
|
public static final void enableRepeatEvents(boolean b) {
|
||||||
enableRepeatEvents = b;
|
enableRepeatEvents = b;
|
||||||
|
@ -1776,9 +1988,6 @@ public class EaglerAdapterImpl2 {
|
||||||
}
|
}
|
||||||
public static final void setDisplaySize(int x, int y) {
|
public static final void setDisplaySize(int x, int y) {
|
||||||
|
|
||||||
}
|
|
||||||
public static final void syncDisplay(int performanceToFps) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final DateFormat dateFormatSS = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
|
private static final DateFormat dateFormatSS = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
|
||||||
|
@ -2001,11 +2210,13 @@ public class EaglerAdapterImpl2 {
|
||||||
@JSBody(params = { }, script = "window.onbeforeunload = function(){javaMethods.get('net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.onWindowUnload()V').invoke();return false;};")
|
@JSBody(params = { }, script = "window.onbeforeunload = function(){javaMethods.get('net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.onWindowUnload()V').invoke();return false;};")
|
||||||
private static native void onBeforeCloseRegister();
|
private static native void onBeforeCloseRegister();
|
||||||
|
|
||||||
@JSBody(params = { "ext", "mime" }, script = "window.eagsFileChooser.openFileChooser(ext, mime);")
|
public static final void openFileChooser(String ext, String mime) {
|
||||||
public static native void openFileChooser(String ext, String mime);
|
fileChooser.openFileChooser(ext, mime);
|
||||||
|
}
|
||||||
|
|
||||||
@JSBody(params = { }, script = "return window.eagsFileChooser.getFileChooserResult != null;")
|
public static final boolean getFileChooserResultAvailable() {
|
||||||
public static final native boolean getFileChooserResultAvailable();
|
return fileChooser.getGetFileChooserResult() != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static final byte[] getFileChooserResult() {
|
public static final byte[] getFileChooserResult() {
|
||||||
ArrayBuffer b = getFileChooserResult0();
|
ArrayBuffer b = getFileChooserResult0();
|
||||||
|
@ -2022,11 +2233,15 @@ public class EaglerAdapterImpl2 {
|
||||||
getFileChooserResult0();
|
getFileChooserResult0();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JSBody(params = { }, script = "var ret = window.eagsFileChooser.getFileChooserResult; window.eagsFileChooser.getFileChooserResult = null; return ret;")
|
private static final ArrayBuffer getFileChooserResult0() {
|
||||||
private static native ArrayBuffer getFileChooserResult0();
|
ArrayBuffer ret = fileChooser.getGetFileChooserResult();
|
||||||
|
fileChooser.setGetFileChooserResultName(null);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
@JSBody(params = { }, script = "var ret = window.eagsFileChooser.getFileChooserResultName; window.eagsFileChooser.getFileChooserResultName = null; return ret;")
|
public static final String getFileChooserResultName() {
|
||||||
public static native String getFileChooserResultName();
|
return fileChooser.getGetFileChooserResultName();
|
||||||
|
}
|
||||||
|
|
||||||
public static final void setListenerPos(float x, float y, float z, float vx, float vy, float vz, float pitch, float yaw) {
|
public static final void setListenerPos(float x, float y, float z, float vx, float vy, float vz, float pitch, float yaw) {
|
||||||
float var2 = MathHelper.cos(-yaw * 0.017453292F);
|
float var2 = MathHelper.cos(-yaw * 0.017453292F);
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package net.lax1dude.eaglercraft.adapter.teavm;
|
||||||
|
|
||||||
|
import org.teavm.jso.JSBody;
|
||||||
|
import org.teavm.jso.JSClass;
|
||||||
|
import org.teavm.jso.JSObject;
|
||||||
|
import org.teavm.jso.JSProperty;
|
||||||
|
import org.teavm.jso.workers.MessagePort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@JSClass
|
||||||
|
public class MessageChannel implements JSObject {
|
||||||
|
|
||||||
|
@JSBody(params = { }, script = "return (typeof MessageChannel !== \"undefined\");")
|
||||||
|
public static native boolean supported();
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
public native MessagePort getPort1();
|
||||||
|
|
||||||
|
@JSProperty
|
||||||
|
public native MessagePort getPort2();
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user