Update #42 - Fixed several WebRTC bugs and other issues

This commit is contained in:
lax1dude
2024-11-16 21:47:35 -08:00
parent 4d66ca140a
commit 64ac208565
95 changed files with 1084 additions and 501 deletions

View File

@ -119,7 +119,7 @@ public class PlatformApplication {
});
}
@JSBody(params = { "cb" }, script = "if(!navigator.clipboard) { cb(null); } else if (!navigator.clipboard.readText) cb(null); else navigator.clipboard.readText().then(function(s) { cb(s || null); }, function() { cb(null); });")
@JSBody(params = { "cb" }, script = "if(!navigator.clipboard) { cb(null); } else if (!navigator.clipboard.readText) cb(null); else navigator.clipboard.readText().then(function(s) { cb((typeof s === \"string\") ? s : null); }, function(err) { cb(null); });")
private static native void getClipboard1(StupidFunctionResolveString cb);
@JSBody(params = { "str" }, script = "if(navigator.clipboard) { navigator.clipboard.writeText(str); return true; } else { return false; }")
@ -212,7 +212,7 @@ public class PlatformApplication {
}
@JSBody(params = { "ctx", "buffer", "w", "h" }, script = "var imgData = ctx.createImageData(w, h); var ww = w * 4; for(var i = 0; i < h; ++i) { imgData.data.set(new Uint8ClampedArray(buffer, (h - i - 1) * ww, ww), i * ww); } ctx.putImageData(imgData, 0, 0);")
private static native JSObject putImageData(CanvasRenderingContext2D ctx, ArrayBuffer buffer, int w, int h);
private static native void putImageData(CanvasRenderingContext2D ctx, ArrayBuffer buffer, int w, int h);
@JSBody(params = { "cvs", "name", "parentElement" }, script =
"var vigg = function(el, url){" +
@ -474,7 +474,7 @@ public class PlatformApplication {
}
@JSFunctor
private static interface DownloadBytesBlobURLRevoke extends JSObject {
static interface DownloadBytesBlobURLRevoke extends JSObject {
void call();
}
@ -507,6 +507,10 @@ public class PlatformApplication {
downloadBytesImpl(str, blobHandle.toExternalForm(), blobHandle::release, PlatformRuntime.parent);
}
static void downloadURLWithNameTeaVM(String str, String url, DownloadBytesBlobURLRevoke revoker) {
downloadBytesImpl(str, url, revoker, PlatformRuntime.parent);
}
public static void showDebugConsole() {
DebugConsoleWindow.showDebugConsole();
}

View File

@ -87,16 +87,19 @@ public class PlatformAudio {
protected final PannerNode panner;
protected final GainNode gain;
protected float pitch;
protected boolean repeat;
protected boolean isPaused = false;
protected boolean isEnded = false;
protected boolean isDisposed = false;
public BrowserAudioHandle(BrowserAudioResource resource, AudioBufferSourceNode source, PannerNode panner,
GainNode gain, float pitch) {
GainNode gain, float pitch, boolean repeat) {
this.resource = resource;
this.source = source;
this.panner = panner;
this.gain = gain;
this.pitch = pitch;
this.repeat = repeat;
source.setOnEnded(this);
}
@ -115,6 +118,14 @@ public class PlatformAudio {
}
}
@Override
public void repeat(boolean en) {
repeat = en;
if(!isEnded) {
source.setLoop(en);
}
}
@Override
public void restart() {
if(isEnded) {
@ -124,11 +135,21 @@ public class PlatformAudio {
resource.cacheHit = PlatformRuntime.steadyTimeMillis();
src.setBuffer(resource.buffer);
src.getPlaybackRate().setValue(pitch);
src.setLoop(repeat);
source.disconnect();
src.connect(panner == null ? gain : panner);
if(isDisposed) {
isDisposed = false;
activeSounds.add(this);
gain.connect(audioctx.getDestination());
if(gameRecGain != null) {
gain.connect(gameRecGain);
}
}
source = src;
source.start();
}else {
isPaused = false;
source.getPlaybackRate().setValue(pitch);
source.start(0.0);
}
@ -179,6 +200,12 @@ public class PlatformAudio {
isEnded = true;
}
private void dispose() {
if(!isDisposed) {
isDisposed = true;
gain.disconnect();
}
}
}
static void initialize() {
@ -304,10 +331,9 @@ public class PlatformAudio {
gameRecGain = audioctx.createGain();
gameRecGain.getGain().setValue(gameVol);
for(BrowserAudioHandle handle : activeSounds) {
if(handle.panner != null) {
handle.panner.connect(gameRecGain);
}else {
try {
handle.gain.connect(gameRecGain);
}catch(Throwable t) {
}
}
PlatformVoiceClient.addRecordingDest(gameRecGain);
@ -342,11 +368,7 @@ public class PlatformAudio {
}
for(BrowserAudioHandle handle : activeSounds) {
try {
if(handle.panner != null) {
handle.panner.disconnect(gameRecGain);
}else {
handle.gain.disconnect(gameRecGain);
}
handle.gain.disconnect(gameRecGain);
}catch(Throwable t) {
}
}
@ -451,8 +473,10 @@ public class PlatformAudio {
activeFreeTimer = millis;
Iterator<BrowserAudioHandle> itr = activeSounds.iterator();
while(itr.hasNext()) {
if(itr.next().shouldFree()) {
BrowserAudioHandle h = itr.next();
if(h.shouldFree()) {
itr.remove();
h.dispose();
}
}
}
@ -460,6 +484,10 @@ public class PlatformAudio {
public static void flushAudioCache() {
soundCache.clear();
Iterator<BrowserAudioHandle> itr = activeSounds.iterator();
while(itr.hasNext()) {
itr.next().dispose();
}
activeSounds.clear();
}
@ -468,13 +496,14 @@ public class PlatformAudio {
}
public static IAudioHandle beginPlayback(IAudioResource track, float x, float y, float z,
float volume, float pitch) {
float volume, float pitch, boolean repeat) {
BrowserAudioResource internalTrack = (BrowserAudioResource) track;
internalTrack.cacheHit = PlatformRuntime.steadyTimeMillis();
AudioBufferSourceNode src = audioctx.createBufferSource();
src.setBuffer(internalTrack.buffer);
src.getPlaybackRate().setValue(pitch);
src.setLoop(repeat);
PannerNode panner = audioctx.createPanner();
panner.setPosition(x, y, z);
@ -503,18 +532,19 @@ public class PlatformAudio {
src.start();
BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, panner, gain, pitch);
BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, panner, gain, pitch, repeat);
activeSounds.add(ret);
return ret;
}
public static IAudioHandle beginPlaybackStatic(IAudioResource track, float volume, float pitch) {
public static IAudioHandle beginPlaybackStatic(IAudioResource track, float volume, float pitch, boolean repeat) {
BrowserAudioResource internalTrack = (BrowserAudioResource) track;
internalTrack.cacheHit = PlatformRuntime.steadyTimeMillis();
AudioBufferSourceNode src = audioctx.createBufferSource();
src.setBuffer(internalTrack.buffer);
src.getPlaybackRate().setValue(pitch);
src.setLoop(repeat);
GainNode gain = audioctx.createGain();
float v2 = volume;
@ -529,7 +559,7 @@ public class PlatformAudio {
src.start();
BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, null, gain, pitch);
BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, null, gain, pitch, repeat);
activeSounds.add(ret);
return ret;
}

View File

@ -330,7 +330,7 @@ public class PlatformInput {
if(tryGrabCursorHook()) return;
int b = evt.getButton();
b = b == 1 ? 2 : (b == 2 ? 1 : b);
buttonStates[b] = true;
if(b >= 0 && b < buttonStates.length) buttonStates[b] = true;
int eventX = (int)(getOffsetX(evt, touchOffsetXTeaVM) * windowDPI);
int eventY = windowHeight - (int)(getOffsetY(evt, touchOffsetYTeaVM) * windowDPI) - 1;
synchronized(mouseEvents) {
@ -348,7 +348,7 @@ public class PlatformInput {
evt.stopPropagation();
int b = evt.getButton();
b = b == 1 ? 2 : (b == 2 ? 1 : b);
buttonStates[b] = false;
if(b >= 0 && b < buttonStates.length) buttonStates[b] = false;
int eventX = (int)(getOffsetX(evt, touchOffsetXTeaVM) * windowDPI);
int eventY = windowHeight - (int)(getOffsetY(evt, touchOffsetYTeaVM) * windowDPI) - 1;
synchronized(mouseEvents) {
@ -366,8 +366,10 @@ public class PlatformInput {
evt.stopPropagation();
mouseX = (int)(getOffsetX(evt, touchOffsetXTeaVM) * windowDPI);
mouseY = windowHeight - (int)(getOffsetY(evt, touchOffsetYTeaVM) * windowDPI) - 1;
mouseDX += evt.getMovementX();
mouseDY += -evt.getMovementY();
if(pointerLockFlag) {
mouseDX += evt.getMovementX();
mouseDY += -evt.getMovementY();
}
if(hasShownPressAnyKey) {
int eventX = (int)(getOffsetX(evt, touchOffsetXTeaVM) * windowDPI);
int eventY = windowHeight - (int)(getOffsetY(evt, touchOffsetYTeaVM) * windowDPI) - 1;
@ -765,7 +767,7 @@ public class PlatformInput {
win.addEventListener("gamepaddisconnected", gamepaddisconnected = new EventListener<GamepadEvent>() {
@Override
public void handleEvent(GamepadEvent evt) {
if(evt.getGamepad() == selectedGamepad) {
if(selectedGamepad != null && evt.getGamepad().getIndex() == selectedGamepad.getIndex()) {
selectedGamepad = null;
}
enumerateGamepads();
@ -1287,7 +1289,7 @@ public class PlatformInput {
public static int mouseGetDWheel() {
int ret = (int)mouseDWheel;
mouseDWheel = 0.0D;
mouseDWheel -= ret;
return ret;
}

View File

@ -599,7 +599,11 @@ public class PlatformRuntime {
}
public static void downloadRemoteURIByteArray(String assetPackageURI, final Consumer<byte[]> cb) {
downloadRemoteURI(assetPackageURI, arr -> cb.accept(TeaVMUtils.wrapByteArrayBuffer(arr)));
downloadRemoteURIByteArray(assetPackageURI, false, cb);
}
public static void downloadRemoteURIByteArray(String assetPackageURI, boolean useCache, final Consumer<byte[]> cb) {
downloadRemoteURI(assetPackageURI, useCache, arr -> cb.accept(TeaVMUtils.wrapByteArrayBuffer(arr)));
}
public static void downloadRemoteURI(String assetPackageURI, final Consumer<ArrayBuffer> cb) {

View File

@ -3,7 +3,6 @@ package net.lax1dude.eaglercraft.v1_8.internal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.teavm.interop.Async;
@ -16,7 +15,6 @@ import org.teavm.jso.browser.Window;
import org.teavm.jso.canvas.CanvasRenderingContext2D;
import org.teavm.jso.dom.events.Event;
import org.teavm.jso.dom.events.EventListener;
import org.teavm.jso.dom.html.HTMLAnchorElement;
import org.teavm.jso.dom.html.HTMLCanvasElement;
import org.teavm.jso.webaudio.MediaStream;
@ -193,19 +191,11 @@ public class PlatformScreenRecord {
final String fileName = EaglercraftVersion.mainMenuStringB + " - " + EaglerProfile.getName() + " - " + fmt.format(new Date()) + "." + params.codec.fileExt;
if("video/webm".equals(params.codec.container)) {
FixWebMDurationJS.getRecUrl(evt, (int) (PlatformRuntime.steadyTimeMillis() - startTime), url -> {
HTMLAnchorElement a = (HTMLAnchorElement) win.getDocument().createElement("a");
a.setDownload(fileName);
a.setHref(url);
a.click();
TeaVMUtils.freeDataURL(url);
PlatformApplication.downloadURLWithNameTeaVM(fileName, url, () -> TeaVMUtils.freeDataURL(url));
}, logger::info);
}else {
String url = TeaVMUtils.getDataURL(evt.getData());
HTMLAnchorElement a = (HTMLAnchorElement) win.getDocument().createElement("a");
a.setDownload(fileName);
a.setHref(url);
a.click();
TeaVMUtils.freeDataURL(url);
PlatformApplication.downloadURLWithNameTeaVM(fileName, url, () -> TeaVMUtils.freeDataURL(url));
}
}
});

View File

@ -4,7 +4,6 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
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.voice.EnumVoiceChannelPeerState;
import net.lax1dude.eaglercraft.v1_8.voice.EnumVoiceChannelReadyState;
import net.lax1dude.eaglercraft.v1_8.voice.EnumVoiceChannelType;
import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController;
@ -179,32 +178,17 @@ public class PlatformVoiceClient {
VoiceClientController.sendPacketDesc(peerId, JSON.stringify(desc));
}, err -> {
logger.error("Failed to set local description for \"{}\"! {}", peerId, err);
if (peerStateInitial == EnumVoiceChannelPeerState.LOADING) {
peerStateInitial = EnumVoiceChannelPeerState.FAILED;
}
signalDisconnect(VoicePeer.this, false);
});
}, err -> {
logger.error("Failed to set create offer for \"{}\"! {}", peerId, err);
if (peerStateInitial == EnumVoiceChannelPeerState.LOADING) {
peerStateInitial = EnumVoiceChannelPeerState.FAILED;
}
signalDisconnect(VoicePeer.this, false);
});
}
TeaVMUtils.addEventListener(peerConnection, "connectionstatechange", (EventListener<Event>) evt -> {
String cs = PlatformWebRTC.getConnectionState(peerConnection);
if ("disconnected".equals(cs)) {
signalDisconnect(VoicePeer.this, false);
} else if ("connected".equals(cs)) {
if (peerState != EnumVoiceChannelPeerState.SUCCESS) {
peerState = EnumVoiceChannelPeerState.SUCCESS;
}
} else if ("failed".equals(cs)) {
if (peerState == EnumVoiceChannelPeerState.LOADING) {
peerState = EnumVoiceChannelPeerState.FAILED;
}
if ("disconnected".equals(cs) || "failed".equals(cs)) {
signalDisconnect(VoicePeer.this, false);
}
});
@ -226,26 +210,21 @@ public class PlatformVoiceClient {
PlatformWebRTC.createAnswer(peerConnection, desc -> {
PlatformWebRTC.setLocalDescription(peerConnection, desc, () -> {
VoiceClientController.sendPacketDesc(peerId, JSON.stringify(desc));
if (peerStateDesc != EnumVoiceChannelPeerState.SUCCESS) peerStateDesc = EnumVoiceChannelPeerState.SUCCESS;
}, err -> {
logger.error("Failed to set local description for \"{}\"! {}", peerId, err.getMessage());
if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(VoicePeer.this, false);
});
}, err -> {
logger.error("Failed to create answer for \"{}\"! {}", peerId, err.getMessage());
if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(VoicePeer.this, false);
});
}
}, err -> {
logger.error("Failed to set remote description for \"{}\"! {}", peerId, err.getMessage());
if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(VoicePeer.this, false);
});
} catch (Throwable err) {
logger.error("Failed to parse remote description for \"{}\"! {}", peerId, err.getMessage());
if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(VoicePeer.this, false);
}
}
@ -253,10 +232,8 @@ public class PlatformVoiceClient {
public void addICECandidate(String candidate) {
try {
addIceCandidate(peerConnection, candidate);
if (peerStateIce != EnumVoiceChannelPeerState.SUCCESS) peerStateIce = EnumVoiceChannelPeerState.SUCCESS;
} catch (Throwable err) {
logger.error("Failed to parse ice candidate for \"{}\"! {}", peerId, err.getMessage());
if (peerStateIce == EnumVoiceChannelPeerState.LOADING) peerStateIce = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(VoicePeer.this, false);
}
}
@ -269,11 +246,6 @@ public class PlatformVoiceClient {
public static GainNode localMediaStreamGain;
public static MediaStream localRawMediaStream;
public static EnumVoiceChannelReadyState readyState = EnumVoiceChannelReadyState.NONE;
public static EnumVoiceChannelPeerState peerState = EnumVoiceChannelPeerState.LOADING;
public static EnumVoiceChannelPeerState peerStateConnect = EnumVoiceChannelPeerState.LOADING;
public static EnumVoiceChannelPeerState peerStateInitial = EnumVoiceChannelPeerState.LOADING;
public static EnumVoiceChannelPeerState peerStateDesc = EnumVoiceChannelPeerState.LOADING;
public static EnumVoiceChannelPeerState peerStateIce = EnumVoiceChannelPeerState.LOADING;
public static AudioContext microphoneVolumeAudioContext = null;
public static void setICEServers(String[] urls) {
@ -348,43 +320,16 @@ public class PlatformVoiceClient {
}
}
public static void resetPeerStates() {
peerState = peerStateConnect = peerStateInitial = peerStateDesc = peerStateIce = EnumVoiceChannelPeerState.LOADING;
}
public static EnumVoiceChannelPeerState getPeerState() {
return peerState;
}
public static EnumVoiceChannelPeerState getPeerStateConnect() {
return peerStateConnect;
}
public static EnumVoiceChannelPeerState getPeerStateInitial() {
return peerStateInitial;
}
public static EnumVoiceChannelPeerState getPeerStateDesc() {
return peerStateDesc;
}
public static EnumVoiceChannelPeerState getPeerStateIce() {
return peerStateIce;
}
public static EnumVoiceChannelReadyState getReadyState() {
return readyState;
}
public static void signalConnect(EaglercraftUUID peerId, boolean offer) {
if (!hasInit) initializeDevices();
try {
JSObject peerConnection = PlatformWebRTC.createRTCPeerConnection(JSONWriter.valueToString(iceServers));
VoicePeer peerInstance = new VoicePeer(peerId, peerConnection, offer);
peerList.put(peerId, peerInstance);
if (peerStateConnect != EnumVoiceChannelPeerState.SUCCESS) peerStateConnect = EnumVoiceChannelPeerState.SUCCESS;
} catch (Throwable e) {
if (peerStateConnect == EnumVoiceChannelPeerState.LOADING) peerStateConnect = EnumVoiceChannelPeerState.FAILED;
}
}

View File

@ -4,23 +4,15 @@ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
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.internal.ClientPlatformSingleplayer;
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANPeerEvent;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryImpl;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryRateLimitDummy;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerRateLimitTracker;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketImpl;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketRateLimitDummy;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQuery;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryImpl;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryRateLimitDummy;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSObject;
import org.teavm.jso.browser.TimerHandler;
import org.teavm.jso.browser.Window;
import org.teavm.jso.core.JSError;
import org.teavm.jso.dom.events.Event;
@ -326,8 +318,6 @@ public class PlatformWebRTC {
@JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);")
static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer);
private static final Map<String, JSObject> fuckTeaVM = new HashMap<>();
public static void runScheduledTasks() {
}
@ -403,12 +393,20 @@ public class PlatformWebRTC {
TeaVMUtils.addEventListener(peerConnection, "icecandidate", (EventListener<Event>) evt -> {
if (hasCandidate(evt)) {
if (iceCandidates.isEmpty()) {
Window.setTimeout(() -> {
final int[] candidateState = new int[2];
final TimerHandler[] runnable = new TimerHandler[1];
Window.setTimeout(runnable[0] = () -> {
if (peerConnection != null && !"disconnected".equals(getConnectionState(peerConnection))) {
int trial = ++candidateState[1];
if(candidateState[0] != iceCandidates.size() && trial < 3) {
candidateState[0] = iceCandidates.size();
Window.setTimeout(runnable[0], 2000);
return;
}
clientICECandidate = JSONWriter.valueToString(iceCandidates);
iceCandidates.clear();
}
}, 3000);
}, 2000);
}
Map<String, String> m = new HashMap<>();
m.put("sdpMLineIndex", "" + getSdpMLineIndex(evt));
@ -506,6 +504,8 @@ public class PlatformWebRTC {
public LANServer client;
public String peerId;
public JSObject peerConnection;
public JSObject dataChannel;
public String ipcChannel;
public LANPeer(LANServer client, String peerId, JSObject peerConnection) {
this.client = client;
@ -517,15 +517,23 @@ public class PlatformWebRTC {
TeaVMUtils.addEventListener(peerConnection, "icecandidate", (EventListener<Event>) evt -> {
if (hasCandidate(evt)) {
if (iceCandidates.isEmpty()) {
Window.setTimeout(() -> {
final int[] candidateState = new int[2];
final TimerHandler[] runnable = new TimerHandler[1];
Window.setTimeout(runnable[0] = () -> {
if (peerConnection != null && !"disconnected".equals(getConnectionState(peerConnection))) {
int trial = ++candidateState[1];
if(candidateState[0] != iceCandidates.size() && trial < 3) {
candidateState[0] = iceCandidates.size();
Window.setTimeout(runnable[0], 2000);
return;
}
LANPeerEvent.LANPeerICECandidateEvent e = new LANPeerEvent.LANPeerICECandidateEvent(peerId, JSONWriter.valueToString(iceCandidates));
synchronized(serverLANEventBuffer) {
serverLANEventBuffer.put(peerId, e);
}
iceCandidates.clear();
}
}, 3000);
}, 2000);
}
Map<String, String> m = new HashMap<>();
m.put("sdpMLineIndex", "" + getSdpMLineIndex(evt));
@ -542,16 +550,23 @@ public class PlatformWebRTC {
}
if (getChannel(evt) == null) return;
JSObject dataChannel = getChannel(evt);
synchronized(fuckTeaVM) {
fuckTeaVM.put(peerId, dataChannel);
if(this.dataChannel != null) {
closeIt(dataChannel);
return;
}
this.dataChannel = dataChannel;
synchronized(serverLANEventBuffer) {
serverLANEventBuffer.put(peerId, new LANPeerEvent.LANPeerDataChannelEvent(peerId));
}
TeaVMUtils.addEventListener(dataChannel, "message", (EventListener<Event>) evt2 -> {
LANPeerEvent.LANPeerPacketEvent e = new LANPeerEvent.LANPeerPacketEvent(peerId, TeaVMUtils.wrapByteArrayBuffer(getData(evt2)));
synchronized(serverLANEventBuffer) {
serverLANEventBuffer.put(peerId, e);
ArrayBuffer data = getData(evt2);
if(ipcChannel != null) {
ClientPlatformSingleplayer.sendPacketTeaVM(ipcChannel, data);
}else {
LANPeerEvent.LANPeerPacketEvent e = new LANPeerEvent.LANPeerPacketEvent(peerId, TeaVMUtils.wrapByteArrayBuffer(data));
synchronized(serverLANEventBuffer) {
serverLANEventBuffer.put(peerId, e);
}
}
});
};
@ -572,11 +587,8 @@ public class PlatformWebRTC {
}
public void disconnect() {
synchronized(fuckTeaVM) {
if (fuckTeaVM.get(peerId) != null) {
closeIt(fuckTeaVM.get(peerId));
fuckTeaVM.remove(peerId);
}
if(dataChannel != null) {
closeIt(dataChannel);
}
closeIt(peerConnection);
}
@ -627,11 +639,26 @@ public class PlatformWebRTC {
client.signalRemoteDisconnect(peerId);
}
}
public void mapIPC(String ipcChannel) {
if(this.ipcChannel == null) {
if(ipcChannel != null) {
this.ipcChannel = ipcChannel;
this.client.ipcMapList.put(ipcChannel, this);
}
}else {
if(ipcChannel == null) {
this.client.ipcMapList.remove(this.ipcChannel);
this.ipcChannel = null;
}
}
}
}
public static class LANServer {
public Set<Map<String, String>> iceServers = new HashSet<>();
public Map<String, LANPeer> peerList = new HashMap<>();
public Map<String, LANPeer> ipcMapList = new HashMap<>();
public byte peerState = PEERSTATE_LOADING;
public byte peerStateConnect = PEERSTATE_LOADING;
public byte peerStateInitial = PEERSTATE_LOADING;
@ -659,21 +686,23 @@ public class PlatformWebRTC {
public void sendPacketToRemoteClient(String peerId, ArrayBuffer buffer) {
LANPeer thePeer = this.peerList.get(peerId);
if (thePeer != null) {
boolean b = false;
synchronized(fuckTeaVM) {
if (fuckTeaVM.get(thePeer.peerId) != null && "open".equals(getReadyState(fuckTeaVM.get(thePeer.peerId)))) {
try {
sendIt(fuckTeaVM.get(thePeer.peerId), buffer);
} catch (Throwable e) {
b = true;
}
} else {
b = true;
}
}
if(b) {
signalRemoteDisconnect(peerId);
sendPacketToRemoteClient(thePeer, buffer);
}
}
public void sendPacketToRemoteClient(LANPeer thePeer, ArrayBuffer buffer) {
boolean b = false;
if (thePeer.dataChannel != null && "open".equals(getReadyState(thePeer.dataChannel))) {
try {
sendIt(thePeer.dataChannel, buffer);
} catch (Throwable e) {
b = true;
}
} else {
b = true;
}
if(b) {
signalRemoteDisconnect(thePeer.peerId);
}
}
@ -719,26 +748,29 @@ public class PlatformWebRTC {
}
}
peerList.clear();
synchronized(fuckTeaVM) {
fuckTeaVM.clear();
}
return;
}
LANPeer thePeer = peerList.get(peerId);
LANPeer thePeer = peerList.remove(peerId);
if(thePeer != null) {
peerList.remove(peerId);
if(thePeer.ipcChannel != null) {
ipcMapList.remove(thePeer.ipcChannel);
}
try {
thePeer.disconnect();
} catch (Throwable ignored) {}
synchronized(fuckTeaVM) {
fuckTeaVM.remove(peerId);
}
synchronized(serverLANEventBuffer) {
serverLANEventBuffer.put(thePeer.peerId, new LANPeerEvent.LANPeerDisconnectEvent(peerId));
}
}
}
public void serverPeerMapIPC(String peer, String ipcChannel) {
LANPeer peerr = peerList.get(peer);
if(peerr != null) {
peerr.mapIPC(ipcChannel);
}
}
public int countPeers() {
return peerList.size();
}
@ -759,30 +791,6 @@ public class PlatformWebRTC {
void call(JSError err);
}
public static RelayQuery openRelayQuery(String addr) {
RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
return new RelayQueryRateLimitDummy(limit);
}
return new RelayQueryImpl(addr);
}
public static RelayWorldsQuery openRelayWorldsQuery(String addr) {
RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
return new RelayWorldsQueryRateLimitDummy(limit);
}
return new RelayWorldsQueryImpl(addr);
}
public static RelayServerSocket openRelayConnection(String addr, int timeout) {
RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
return new RelayServerSocketRateLimitDummy(limit);
}
return new RelayServerSocketImpl(addr, timeout);
}
private static LANClient rtcLANClient = null;
public static void startRTCLANClient() {
@ -806,7 +814,6 @@ public class PlatformWebRTC {
rtcLANClient.signalRemoteDisconnect(false);
}
// todo: ArrayBuffer version
public static void clientLANSendPacket(byte[] pkt) {
rtcLANClient.sendPacketToServer(TeaVMUtils.unwrapArrayBuffer(pkt));
}
@ -949,6 +956,24 @@ public class PlatformWebRTC {
rtcLANServer.signalRemoteDescription(peer, description);
}
public static void serverLANPeerMapIPC(String peer, String ipcChannel) {
rtcLANServer.serverPeerMapIPC(peer, ipcChannel);
}
public static boolean serverLANPeerPassIPC(String channelName, ArrayBuffer data) {
if(rtcLANServer != null) {
LANPeer peer = rtcLANServer.ipcMapList.get(channelName);
if(peer != null) {
rtcLANServer.sendPacketToRemoteClient(peer, data);
return true;
}else {
return false;
}
}else {
return false;
}
}
public static void serverLANDisconnectPeer(String peer) {
rtcLANServer.signalRemoteDisconnect(peer);
}

View File

@ -169,7 +169,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
int l = src.remaining();
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
for(int i = 0; i < l; ++i) {
dataView.setInt8(position + l, src.get());
dataView.setInt8(position + i, src.get());
}
position += l;
}

View File

@ -153,7 +153,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
int l = src.remaining();
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
for(int i = 0; i < l; ++i) {
typedArray.set(position + l, src.get());
typedArray.set(position + i, src.get());
}
position += l;
}

View File

@ -153,7 +153,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
int l = src.remaining();
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
for(int i = 0; i < l; ++i) {
typedArray.set(position + l, src.get());
typedArray.set(position + i, src.get());
}
position += l;
}

View File

@ -153,7 +153,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
int l = src.remaining();
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
for(int i = 0; i < l; ++i) {
typedArray.set(position + l, src.get());
typedArray.set(position + i, src.get());
}
position += l;
}

View File

@ -130,7 +130,7 @@ public class TeaVMUtils {
@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBuffer.class)
public static native short[] wrapShortArrayBuffer(ArrayBuffer buf);
@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapArrayBuffer.class)
@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBufferView.class)
public static native short[] wrapShortArrayBuffer(ArrayBufferView buf);
@Async
@ -140,12 +140,8 @@ public class TeaVMUtils {
Window.setTimeout(() -> cb.complete(null), millis);
}
public static final Comparator<Touch> touchSortingComparator = (t1, t2) -> {
return t1.getIdentifier() - t2.getIdentifier();
};
public static final Comparator<OffsetTouch> touchSortingComparator2 = (t1, t2) -> {
return t1.touch.getIdentifier() - t2.touch.getIdentifier();
return t1.eventUID - t2.eventUID;
};
public static List<OffsetTouch> toSortedTouchList(TouchList touchList, SortedTouchEvent.ITouchUIDMapper mapper,