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

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

View File

@ -1,5 +1,6 @@
package net.lax1dude.eaglercraft.v1_8.sp.internal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@ -9,15 +10,19 @@ import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSObject;
import org.teavm.jso.dom.events.ErrorEvent;
import org.teavm.jso.dom.events.EventListener;
import org.teavm.jso.dom.html.HTMLScriptElement;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.workers.Worker;
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.teavm.SingleThreadWorker;
/**
* Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
@ -38,28 +43,34 @@ public class ClientPlatformSingleplayer {
private static final Logger logger = LogManager.getLogger("ClientPlatformSingleplayer");
private static final LinkedList<IPCPacketData> messageQueue = new LinkedList();
private static final LinkedList<IPCPacketData> messageQueue = new LinkedList<>();
@JSBody(params = {}, script = "return (typeof window.eaglercraftXClientScriptElement !== \"undefined\") ? window.eaglercraftXClientScriptElement : null;")
@JSBody(params = {}, script = "return (typeof eaglercraftXClientScriptElement !== \"undefined\") ? eaglercraftXClientScriptElement : null;")
private static native JSObject loadIntegratedServerSourceOverride();
@JSBody(params = {}, script = "return (typeof window.eaglercraftXClientScriptURL === \"string\") ? window.eaglercraftXClientScriptURL : null;")
@JSBody(params = {}, script = "return (typeof eaglercraftXClientScriptURL === \"string\") ? eaglercraftXClientScriptURL : null;")
private static native String loadIntegratedServerSourceOverrideURL();
@JSBody(params = {}, script = "try{throw new Error();}catch(ex){return ex.stack;}return null;")
@JSBody(params = {}, script = "try{throw new Error();}catch(ex){return ex.stack||null;}return null;")
private static native String loadIntegratedServerSourceStack();
@JSBody(params = { "csc" }, script = "if(typeof csc.src === \"string\" && csc.src.length > 0) return csc.src; else return null;")
private static native String loadIntegratedServerSourceURL(JSObject scriptTag);
@JSBody(params = { "csc", "tail" }, script = "const cscText = csc.text;"
@JSBody(params = { "csc", "tail" }, script = "var cscText = csc.text;"
+ "if(typeof cscText === \"string\" && cscText.length > 0) return new Blob([cscText, tail], { type: \"text/javascript;charset=utf8\" });"
+ "else return null;")
private static native JSObject loadIntegratedServerSourceInline(JSObject scriptTag, String tail);
@JSBody(params = { "csc" }, script = "var cscText = csc.text;"
+ "if(typeof cscText === \"string\" && cscText.length > 0) return cscText;"
+ "else return null;")
private static native String loadIntegratedServerSourceInlineStr(JSObject scriptTag);
private static String integratedServerSource = null;
private static String integratedServerSourceOriginalURL = null;
private static boolean serverSourceLoaded = false;
private static boolean isSingleThreadMode = false;
private static Worker workerObj = null;
@ -68,7 +79,7 @@ public class ClientPlatformSingleplayer {
public void onMessage(String channel, ArrayBuffer buf);
}
@JSBody(params = { "w", "wb" }, script = "w.onmessage = function(o) { wb(o.data.ch, o.data.dat); };")
@JSBody(params = { "w", "wb" }, script = "w.addEventListener(\"message\", function(o) { wb(o.data.ch, o.data.dat); });")
private static native void registerPacketHandler(Worker w, WorkerBinaryPacketHandler wb);
@JSBody(params = { "w", "ch", "dat" }, script = "w.postMessage({ ch: ch, dat : dat });")
@ -108,13 +119,13 @@ public class ClientPlatformSingleplayer {
private static JSObject loadIntegratedServerSource() {
String str = loadIntegratedServerSourceOverrideURL();
if(str != null) {
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str);
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
if(buf != null) {
integratedServerSourceOriginalURL = str;
logger.info("Using integrated server at: {}", str);
logger.info("Using integrated server at: {}", truncateURL(str));
return createBlobObj(buf, workerBootstrapCode);
}else {
logger.error("Failed to load integrated server: {}", str);
logger.error("Failed to load integrated server: {}", truncateURL(str));
}
}
JSObject el = loadIntegratedServerSourceOverride();
@ -128,25 +139,34 @@ public class ClientPlatformSingleplayer {
return el;
}
}else {
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(url);
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(url, true);
if(buf != null) {
integratedServerSourceOriginalURL = url;
logger.info("Using integrated server from script tag src: {}", url);
logger.info("Using integrated server from script tag src: {}", truncateURL(url));
return createBlobObj(buf, workerBootstrapCode);
}else {
logger.error("Failed to load integrated server from script tag src: {}", url);
logger.error("Failed to load integrated server from script tag src: {}", truncateURL(url));
}
}
}
str = TeaVMUtils.tryResolveClassesSource();
if(str != null) {
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str);
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
if(buf != null) {
integratedServerSourceOriginalURL = str;
logger.info("Using integrated server from script src: {}", str);
logger.info("Using integrated server from script src: {}", truncateURL(str));
return createBlobObj(buf, workerBootstrapCode);
}else {
logger.error("Failed to load integrated server from script src: {}", str);
logger.error("Failed to load integrated server from script src: {}", truncateURL(str));
}
}
HTMLScriptElement sc = TeaVMUtils.tryResolveClassesSourceInline();
if(sc != null) {
el = loadIntegratedServerSourceInline(sc, workerBootstrapCode);
if(el != null) {
integratedServerSourceOriginalURL = "inline script tag (client guess)";
logger.info("Loading integrated server from (likely) inline script tag");
return el;
}
}
logger.info("Could not resolve the location of client's classes.js!");
@ -155,12 +175,57 @@ public class ClientPlatformSingleplayer {
return null;
}
private static String truncateURL(String url) {
if(url == null) return null;
if(url.length() > 256) {
url = url.substring(0, 254) + "...";
}
return url;
}
private static String createIntegratedServerWorkerURL() {
JSObject blobObj = loadIntegratedServerSource();
if(blobObj == null) {
return null;
}
return createWorkerScriptURL(blobObj);
return TeaVMBlobURLManager.registerNewURLBlob(blobObj).toExternalForm();
}
public static byte[] getIntegratedServerSourceTeaVM() {
String str = loadIntegratedServerSourceOverrideURL();
if(str != null) {
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
if(buf != null) {
return TeaVMUtils.wrapByteArrayBuffer(buf);
}
}
JSObject el = loadIntegratedServerSourceOverride();
if(el != null) {
String url = loadIntegratedServerSourceURL(el);
if(url == null) {
str = loadIntegratedServerSourceInlineStr(el);
if(str != null) {
return str.getBytes(StandardCharsets.UTF_8);
}
}else {
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(url, true);
if(buf != null) {
return TeaVMUtils.wrapByteArrayBuffer(buf);
}
}
}
str = TeaVMUtils.tryResolveClassesSource();
if(str != null) {
ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
if(buf != null) {
return TeaVMUtils.wrapByteArrayBuffer(buf);
}
}
HTMLScriptElement sc = TeaVMUtils.tryResolveClassesSourceInline();
if(sc != null) {
return sc.getText().getBytes(StandardCharsets.UTF_8);
}
return null;
}
public static String getLoadedWorkerURLTeaVM() {
@ -171,36 +236,58 @@ public class ClientPlatformSingleplayer {
return (serverSourceLoaded && workerObj != null) ? integratedServerSourceOriginalURL : null;
}
public static void startIntegratedServer() {
if(!serverSourceLoaded) {
integratedServerSource = createIntegratedServerWorkerURL();
serverSourceLoaded = true;
}
if(integratedServerSource == null) {
throw new RuntimeException("Could not resolve the location of client's classes.js! Make sure client's classes.js is linked/embedded in a dedicated <script> tag. Define \"window.eaglercraftXClientScriptElement\" or \"window.eaglercraftXClientScriptURL\" to force");
}
workerObj = Worker.create(integratedServerSource);
workerObj.onError(new EventListener<ErrorEvent>() {
@Override
public void handleEvent(ErrorEvent evt) {
logger.error("Worker Error: {}", evt.getError());
PlatformRuntime.printNativeExceptionToConsoleTeaVM(evt);
public static void startIntegratedServer(boolean singleThreadMode) {
singleThreadMode |= ((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isSingleThreadModeTeaVM();
if(singleThreadMode) {
if(!isSingleThreadMode) {
SingleThreadWorker.singleThreadStartup((pkt) -> {
synchronized(messageQueue) {
messageQueue.add(pkt);
}
});
isSingleThreadMode = true;
}
});
registerPacketHandler(workerObj, new WorkerBinaryPacketHandlerImpl());
sendWorkerStartPacket(workerObj, PlatformRuntime.getClientConfigAdapter().getIntegratedServerOpts().toString());
}else {
if(!serverSourceLoaded) {
integratedServerSource = createIntegratedServerWorkerURL();
serverSourceLoaded = true;
}
if(integratedServerSource == null) {
logger.error("Could not resolve the location of client's classes.js! Make sure client's classes.js is linked/embedded in a dedicated <script> tag. Define \"window.eaglercraftXClientScriptElement\" or \"window.eaglercraftXClientScriptURL\" to force");
logger.error("Falling back to single thread mode...");
startIntegratedServer(true);
return;
}
workerObj = Worker.create(integratedServerSource);
workerObj.addEventListener("error", new EventListener<ErrorEvent>() {
@Override
public void handleEvent(ErrorEvent evt) {
logger.error("Worker Error: {}", evt.getError());
PlatformRuntime.printNativeExceptionToConsoleTeaVM(evt);
}
});
registerPacketHandler(workerObj, new WorkerBinaryPacketHandlerImpl());
sendWorkerStartPacket(workerObj, PlatformRuntime.getClientConfigAdapter().getIntegratedServerOpts().toString());
}
}
public static void sendPacket(IPCPacketData packet) {
sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
if(isSingleThreadMode) {
SingleThreadWorker.sendPacketToWorker(packet);
}else {
sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
}
}
public static void sendPacketTeaVM(String channel, ArrayBuffer packet) {
if(workerObj != null) {
sendWorkerPacket(workerObj, channel, packet);
if(isSingleThreadMode) {
SingleThreadWorker.sendPacketToWorker(new IPCPacketData(channel, TeaVMUtils.wrapByteArrayBuffer(packet)));
}else {
if(workerObj != null) {
sendWorkerPacket(workerObj, channel, packet);
}
}
}
@ -217,7 +304,7 @@ public class ClientPlatformSingleplayer {
}
public static boolean canKillWorker() {
return true;
return !isSingleThreadMode;
}
public static void killWorker() {
@ -228,7 +315,17 @@ public class ClientPlatformSingleplayer {
}
public static boolean isRunningSingleThreadMode() {
return false;
return isSingleThreadMode;
}
public static boolean isSingleThreadModeSupported() {
return true;
}
public static void updateSingleThreadMode() {
if(isSingleThreadMode) {
SingleThreadWorker.singleThreadUpdate();
}
}
public static void showCrashReportOverlay(String report, int x, int y, int w, int h) {

View File

@ -3,17 +3,36 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.internal;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import org.teavm.interop.Async;
import org.teavm.interop.AsyncCallback;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSFunctor;
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.jso.typedarrays.ArrayBuffer;
import com.google.common.collect.Collections2;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.Filesystem;
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.ES6ShimStatus;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EnumES6ShimStatus;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EnumES6Shims;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.MessageChannel;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
@ -36,7 +55,17 @@ public class ServerPlatformSingleplayer {
private static final Logger logger = LogManager.getLogger("ServerPlatformSingleplayer");
private static final LinkedList<IPCPacketData> messageQueue = new LinkedList();
private static final LinkedList<IPCPacketData> messageQueue = new LinkedList<>();
private static boolean immediateContinueSupport = 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("");
private static boolean singleThreadMode = false;
private static Consumer<IPCPacketData> singleThreadCB = null;
private static IEaglerFilesystem filesystem = null;
@JSFunctor
private static interface WorkerBinaryPacketHandler extends JSObject {
@ -63,7 +92,7 @@ public class ServerPlatformSingleplayer {
}
@JSBody(params = { "wb" }, script = "onmessage = function(o) { wb(o.data.ch, o.data.dat); };")
@JSBody(params = { "wb" }, script = "__eaglerXOnMessage = function(o) { wb(o.data.ch, o.data.dat); };")
private static native void registerPacketHandler(WorkerBinaryPacketHandler wb);
public static void register() {
@ -71,14 +100,66 @@ public class ServerPlatformSingleplayer {
}
public static void initializeContext() {
PlatformFilesystem.initialize(getClientConfigAdapter().getWorldsDB());
singleThreadMode = false;
singleThreadCB = null;
ES6ShimStatus shimStatus = ES6ShimStatus.getRuntimeStatus();
if(shimStatus != null) {
EnumES6ShimStatus stat = shimStatus.getStatus();
switch(stat) {
case STATUS_ERROR:
case STATUS_DISABLED_ERRORS:
logger.error("ES6 Shim Status: {}", stat.statusDesc);
break;
case STATUS_ENABLED_ERRORS:
logger.error("ES6 Shim Status: {}", stat.statusDesc);
dumpShims(shimStatus.getShims());
break;
case STATUS_DISABLED:
case STATUS_NOT_PRESENT:
logger.info("ES6 Shim Status: {}", stat.statusDesc);
break;
case STATUS_ENABLED:
logger.info("ES6 Shim Status: {}", stat.statusDesc);
dumpShims(shimStatus.getShims());
break;
default:
break;
}
}
TeaVMBlobURLManager.initialize();
checkImmediateContinueSupport();
filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
VFile2.setPrimaryFilesystem(filesystem);
}
public static IEaglerFilesystem getWorldsDatabase() {
return filesystem;
}
public static void initializeContextSingleThread(Consumer<IPCPacketData> packetSendCallback) {
singleThreadMode = true;
singleThreadCB = packetSendCallback;
filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
}
private static void dumpShims(Set<EnumES6Shims> shims) {
if(!shims.isEmpty()) {
logger.info("(Enabled {} shims: {})", shims.size(), String.join(", ", Collections2.transform(shims, (shim) -> shim.shimDesc)));
}
}
@JSBody(params = { "ch", "dat" }, script = "postMessage({ ch: ch, dat : dat });")
public static native void sendPacketTeaVM(String channel, ArrayBuffer arr);
public static void sendPacket(IPCPacketData packet) {
sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
if(singleThreadMode) {
singleThreadCB.accept(packet);
}else {
sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
}
}
public static List<IPCPacketData> recieveAllPacket() {
@ -86,7 +167,7 @@ public class ServerPlatformSingleplayer {
if(messageQueue.size() == 0) {
return null;
}else {
List<IPCPacketData> ret = new ArrayList(messageQueue);
List<IPCPacketData> ret = new ArrayList<>(messageQueue);
messageQueue.clear();
return ret;
}
@ -96,4 +177,118 @@ public class ServerPlatformSingleplayer {
public static IClientConfigAdapter getClientConfigAdapter() {
return TeaVMClientConfigAdapter.instance;
}
private static void checkImmediateContinueSupport() {
try {
immediateContinueSupport = false;
if(!MessageChannel.supported()) {
logger.error("Fast immediate continue will be disabled for server context due to MessageChannel being unsupported");
return;
}
immediateContinueChannel = MessageChannel.create();
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;
logger.error("Fast immediate continue will be disabled for server context due to actually continuing immediately");
return;
}
EagUtils.sleep(10l);
currentContinueHack = null;
if(!checkMe[0]) {
if(immediateContinueChannel != null) {
safeShutdownChannel(immediateContinueChannel);
}
immediateContinueChannel = null;
logger.error("Fast immediate continue will be disabled for server context due to startup check failing");
}else {
immediateContinueSupport = true;
}
}catch(Throwable t) {
logger.error("Fast immediate continue will be disabled for server context due to exceptions");
immediateContinueSupport = false;
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) {
}
}
public static void immediateContinue() {
if(singleThreadMode) {
PlatformRuntime.immediateContinue();
}else {
if(immediateContinueSupport) {
immediateContinueTeaVM();
}else {
EagUtils.sleep(0l);
}
}
}
@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) {
logger.error("Caught error posting immediate continue, using setTimeout instead");
Window.setTimeout(() -> cb.complete(null), 0);
}
}
}
public static boolean isSingleThreadMode() {
return singleThreadMode;
}
public static void recievePacketSingleThreadTeaVM(IPCPacketData pkt) {
synchronized(messageQueue) {
messageQueue.add(pkt);
}
}
}

View File

@ -0,0 +1,44 @@
package net.lax1dude.eaglercraft.v1_8.sp.server.internal.teavm;
import java.util.function.Consumer;
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class SingleThreadWorker {
private static final Logger logger = LogManager.getLogger("SingleThreadWorker");
public static void singleThreadStartup(Consumer<IPCPacketData> packetSendCallback) {
logger.info("Starting single-thread mode worker...");
ServerPlatformSingleplayer.initializeContextSingleThread(packetSendCallback);
EaglerIntegratedServerWorker.singleThreadMain();
}
public static void sendPacketToWorker(IPCPacketData pkt) {
ServerPlatformSingleplayer.recievePacketSingleThreadTeaVM(pkt);
}
public static void singleThreadUpdate() {
EaglerIntegratedServerWorker.singleThreadUpdate();
}
}

View File

@ -77,7 +77,7 @@ public class WorkerMain {
public void onMessage(String msg);
}
@JSBody(params = { "wb" }, script = "onmessage = function(o) { wb(o.data.msg); };")
@JSBody(params = { "wb" }, script = "__eaglerXOnMessage = function(o) { wb(o.data.msg); }; addEventListener(\"message\", function(evt) { __eaglerXOnMessage(evt); });")
private static native void setOnMessage(WorkerArgumentsPacketHandler cb);
@Async