Update #28 - Added capes, voice chat, FNAW skins, and fixes

This commit is contained in:
lax1dude
2024-04-20 16:20:06 -07:00
parent 42c57894f9
commit ba88b52022
171 changed files with 7476 additions and 868 deletions

View File

@ -46,8 +46,8 @@ public class PlatformAudio {
static final Logger logger = LogManager.getLogger("BrowserAudio");
private static AudioContext audioctx = null;
private static MediaStreamAudioDestinationNode recDest = null;
static AudioContext audioctx = null;
static MediaStreamAudioDestinationNode recDest = null;
private static final Map<String, BrowserAudioResource> soundCache = new HashMap();
private static long cacheFreeTimer = 0l;

View File

@ -21,10 +21,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
public class PlatformBufferFunctions {
public static void put(ByteBuffer newBuffer, ByteBuffer flip) {
int len = flip.remaining();
for(int i = 0; i < len; ++i) {
newBuffer.put(flip.get());
}
newBuffer.put(flip);
}
public static void put(IntBuffer intBuffer, int index, int[] data) {

View File

@ -18,7 +18,7 @@ import org.teavm.jso.indexeddb.IDBRequest;
import org.teavm.jso.indexeddb.IDBTransaction;
import org.teavm.jso.indexeddb.IDBVersionChangeEvent;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.DataView;
import org.teavm.jso.typedarrays.Int8Array;
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
@ -85,11 +85,11 @@ public class PlatformFilesystem {
if(ar == null) {
return null;
}
return EaglerArrayBufferAllocator.wrapByteBufferTeaVM(DataView.create(ar));
return EaglerArrayBufferAllocator.wrapByteBufferTeaVM(Int8Array.create(ar));
}
public static void eaglerWrite(String pathName, ByteBuffer data) {
if(!AsyncHandlers.writeWholeFile(database, pathName, EaglerArrayBufferAllocator.getDataViewStupid(data).getBuffer()).bool) {
if(!AsyncHandlers.writeWholeFile(database, pathName, EaglerArrayBufferAllocator.getDataView8Unsigned(data).getBuffer()).bool) {
throw new RuntimeException("Failed to write " + data.remaining() + " byte file to indexeddb table: " + pathName);
}
}

View File

@ -4,6 +4,9 @@ import java.util.LinkedList;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
import org.teavm.interop.Async;
import org.teavm.interop.AsyncCallback;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject;
import org.teavm.jso.browser.TimerHandler;
@ -100,6 +103,8 @@ public class PlatformInput {
public static boolean keyboardLockSupported = false;
public static boolean lockKeys = false;
private static boolean vsync = true;
@JSBody(params = { }, script = "window.onbeforeunload = () => {return false;};")
private static native void onBeforeCloseRegister();
@ -291,6 +296,10 @@ public class PlatformInput {
return false;
}
public static void setVSync(boolean enable) {
vsync = enable;
}
public static void update() {
double r = win.getDevicePixelRatio();
int w = PlatformRuntime.parent.getClientWidth();
@ -304,9 +313,41 @@ public class PlatformInput {
canvas.setHeight(h2);
}
flipBuffer();
EagUtils.sleep(1l);
if (PlatformRuntime.recording) {
long t = System.currentTimeMillis();
if(t - PlatformRuntime.lastFrame > (1000 / 30)) {
PlatformRuntime.recFrame();
PlatformRuntime.lastFrame = t;
}
}
if(vsync) {
asyncRequestAnimationFrame();
}else {
EagUtils.sleep(0l);
}
}
@Async
private static native void asyncRequestAnimationFrame();
private static void asyncRequestAnimationFrame(AsyncCallback<Void> cb) {
final boolean[] hasCompleted = new boolean[1];
final int[] timeout = new int[] { -1 };
Window.requestAnimationFrame((d) -> {
if(!hasCompleted[0]) {
hasCompleted[0] = true;
Window.clearTimeout(timeout[0]);
cb.complete(null);
}
});
timeout[0] = Window.setTimeout(() -> {
if(!hasCompleted[0]) {
hasCompleted[0] = true;
cb.complete(null);
}
}, 50);
}
static void initFramebuffer(WebGL2RenderingContext ctx, WebGLFramebuffer fbo, int sw, int sh) {
context = ctx;
mainFramebuffer = fbo;
@ -590,7 +631,7 @@ public class PlatformInput {
@JSBody(params = { }, script = "window.navigator.keyboard.unlock();")
private static native void unlockKeys();
@JSBody(params = { }, script = "return 'keyboard' in window.navigator && 'lock' in window.navigator.keyboard;")
@JSBody(params = { }, script = "return !!(window.navigator.keyboard && window.navigator.keyboard.lock);")
private static native boolean checkKeyboardLockSupported();
@JSBody(params = { }, script = "document.exitFullscreen();")

View File

@ -36,12 +36,14 @@ public class PlatformOpenGL {
static boolean hasDebugRenderInfoExt = false;
static boolean hasFramebufferHDR16FSupport = false;
static boolean hasFramebufferHDR32FSupport = false;
static boolean hasLinearHDR32FSupport = false;
static void setCurrentContext(WebGL2RenderingContext context) {
ctx = context;
hasDebugRenderInfoExt = ctx.getExtension("WEBGL_debug_renderer_info") != null;
hasFramebufferHDR16FSupport = ctx.getExtension("EXT_color_buffer_half_float") != null;
hasFramebufferHDR32FSupport = ctx.getExtension("EXT_color_buffer_float") != null;
hasLinearHDR32FSupport = ctx.getExtension("OES_texture_float_linear") != null;
_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
@ -191,15 +193,15 @@ public class PlatformOpenGL {
}
public static final void _wglBufferData(int target, ByteBuffer data, int usage) {
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView(data), usage);
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView8(data), usage);
}
public static final void _wglBufferData(int target, IntBuffer data, int usage) {
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView(data), usage);
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView32(data), usage);
}
public static final void _wglBufferData(int target, FloatBuffer data, int usage) {
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView(data), usage);
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView32F(data), usage);
}
public static final void _wglBufferData(int target, int size, int usage) {
@ -207,15 +209,15 @@ public class PlatformOpenGL {
}
public static final void _wglBufferSubData(int target, int offset, ByteBuffer data) {
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView(data));
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView8(data));
}
public static final void _wglBufferSubData(int target, int offset, IntBuffer data) {
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView(data));
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView32(data));
}
public static final void _wglBufferSubData(int target, int offset, FloatBuffer data) {
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView(data));
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView32F(data));
}
public static final void _wglBindVertexArray(IBufferArrayGL obj) {
@ -258,55 +260,61 @@ public class PlatformOpenGL {
public static final void _wglTexImage3D(int target, int level, int internalFormat, int width, int height, int depth,
int border, int format, int type, ByteBuffer data) {
ctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView8Unsigned(data));
}
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width,
int height, int border, int format, int type, ByteBuffer data) {
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView8Unsigned(data));
}
public static final void _wglTexImage2Du16(int target, int level, int internalFormat, int width,
int height, int border, int format, int type, ByteBuffer data) {
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid16(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView16Unsigned(data));
}
public static final void _wglTexImage2Df32(int target, int level, int internalFormat, int width,
int height, int border, int format, int type, ByteBuffer data) {
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataView32F(data));
}
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width,
int height, int border, int format, int type, IntBuffer data) {
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView8Unsigned(data));
}
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width,
int height, int border, int format, int type, FloatBuffer data) {
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView8Unsigned(data));
}
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
int width, int height, int format, int type, ByteBuffer data) {
ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView8Unsigned(data));
}
public static final void _wglTexSubImage2Du16(int target, int level, int xoffset, int yoffset,
int width, int height, int format, int type, ByteBuffer data) {
ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid16(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView16Unsigned(data));
}
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
int width, int height, int format, int type, IntBuffer data) {
ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView8Unsigned(data));
}
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
int width, int height, int format, int type, FloatBuffer data) {
ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
data == null ? null : EaglerArrayBufferAllocator.getDataView8Unsigned(data));
}
public static final void _wglCopyTexSubImage2D(int target, int level, int xoffset, int yoffset,
@ -455,32 +463,32 @@ public class PlatformOpenGL {
public static final void _wglUniformMatrix2fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
if(obj != null) ctx.uniformMatrix2fv(((OpenGLObjects.UniformGL)obj).ptr, transpose,
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
mat == null ? null : EaglerArrayBufferAllocator.getDataView32F(mat));
}
public static final void _wglUniformMatrix3fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
if(obj != null) ctx.uniformMatrix3fv(((OpenGLObjects.UniformGL)obj).ptr, transpose,
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
mat == null ? null : EaglerArrayBufferAllocator.getDataView32F(mat));
}
public static final void _wglUniformMatrix3x2fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
if(obj != null) ctx.uniformMatrix3x2fv(((OpenGLObjects.UniformGL)obj).ptr, transpose,
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
mat == null ? null : EaglerArrayBufferAllocator.getDataView32F(mat));
}
public static final void _wglUniformMatrix4fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
if(obj != null) ctx.uniformMatrix4fv(((OpenGLObjects.UniformGL)obj).ptr, transpose,
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
mat == null ? null : EaglerArrayBufferAllocator.getDataView32F(mat));
}
public static final void _wglUniformMatrix4x2fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
if(obj != null) ctx.uniformMatrix4x2fv(((OpenGLObjects.UniformGL)obj).ptr, transpose,
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
mat == null ? null : EaglerArrayBufferAllocator.getDataView32F(mat));
}
public static final void _wglUniformMatrix4x3fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
if(obj != null) ctx.uniformMatrix4x3fv(((OpenGLObjects.UniformGL)obj).ptr, transpose,
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
mat == null ? null : EaglerArrayBufferAllocator.getDataView32F(mat));
}
public static final void _wglBindFramebuffer(int target, IFramebufferGL framebuffer) {
@ -570,7 +578,11 @@ public class PlatformOpenGL {
return false;
}
}
public static final boolean checkLinearHDR32FSupport() {
return hasLinearHDR32FSupport;
}
private static final void checkErr(String name) {
int i = ctx.getError();
if(i != 0) {

View File

@ -28,7 +28,6 @@ import org.teavm.jso.dom.html.HTMLCanvasElement;
import org.teavm.jso.dom.html.HTMLDocument;
import org.teavm.jso.dom.html.HTMLElement;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.DataView;
import org.teavm.jso.typedarrays.Uint8Array;
import org.teavm.jso.webaudio.MediaStream;
import org.teavm.jso.webgl.WebGLFramebuffer;
@ -275,27 +274,27 @@ public class PlatformRuntime {
}
public static ByteBuffer castPrimitiveByteArray(byte[] array) {
return EaglerArrayBufferAllocator.wrapByteBufferTeaVM(DataView.create(TeaVMUtils.unwrapArrayBuffer(array)));
return EaglerArrayBufferAllocator.wrapByteBufferTeaVM(TeaVMUtils.unwrapByteArray(array));
}
public static IntBuffer castPrimitiveIntArray(int[] array) {
return EaglerArrayBufferAllocator.wrapIntBufferTeaVM(DataView.create(TeaVMUtils.unwrapArrayBuffer(array)));
return EaglerArrayBufferAllocator.wrapIntBufferTeaVM(TeaVMUtils.unwrapIntArray(array));
}
public static FloatBuffer castPrimitiveFloatArray(float[] array) {
return EaglerArrayBufferAllocator.wrapFloatBufferTeaVM(DataView.create(TeaVMUtils.unwrapArrayBuffer(array)));
return EaglerArrayBufferAllocator.wrapFloatBufferTeaVM(TeaVMUtils.unwrapFloatArray(array));
}
public static byte[] castNativeByteBuffer(ByteBuffer buffer) {
return TeaVMUtils.wrapUnsignedByteArray(EaglerArrayBufferAllocator.getDataViewStupid(buffer));
return TeaVMUtils.wrapUnsignedByteArray(EaglerArrayBufferAllocator.getDataView8Unsigned(buffer));
}
public static int[] castNativeIntBuffer(IntBuffer buffer) {
return TeaVMUtils.wrapIntArray(EaglerArrayBufferAllocator.getDataViewStupid32(buffer));
return TeaVMUtils.wrapIntArray(EaglerArrayBufferAllocator.getDataView32(buffer));
}
public static float[] castNativeFloatBuffer(FloatBuffer buffer) {
return TeaVMUtils.wrapFloatArray(EaglerArrayBufferAllocator.getFloatArrayStupid(buffer));
return TeaVMUtils.wrapFloatArray(EaglerArrayBufferAllocator.getDataView32F(buffer));
}
public static void freeByteBuffer(ByteBuffer byteBuffer) {
@ -500,12 +499,13 @@ public class PlatformRuntime {
return TeaVMClientConfigAdapter.instance;
}
private static boolean canRec = false;
private static boolean recording = false;
private static JSObject mediaRec = null;
private static HTMLCanvasElement recCanvas = null;
private static CanvasRenderingContext2D recCtx = null;
private static MediaStream recStream = null;
static boolean canRec = false;
static boolean recording = false;
static long lastFrame = 0l;
static JSObject mediaRec = null;
static HTMLCanvasElement recCanvas = null;
static CanvasRenderingContext2D recCtx = null;
static MediaStream recStream = null;
public static boolean isRec() {
return recording && canRec;
@ -534,7 +534,7 @@ public class PlatformRuntime {
return recording ? "recording.stop" : "recording.start";
}
private static void recFrame() {
static void recFrame() {
if (mediaRec != null) {
int w = PlatformRuntime.canvas.getWidth();
int h = PlatformRuntime.canvas.getHeight();
@ -546,21 +546,6 @@ public class PlatformRuntime {
}
}
private static void onRecFrame() {
if (recording) {
recFrame();
long t = System.currentTimeMillis();
Window.requestAnimationFrame(timestamp -> {
long d = (1000 / 30) - (System.currentTimeMillis() - t);
if (d <= 0) {
onRecFrame();
} else {
Window.setTimeout(PlatformRuntime::onRecFrame, d);
}
});
}
}
@JSFunctor
private static interface MediaHandler extends JSObject {
void onMedia(MediaStream stream);
@ -630,7 +615,6 @@ public class PlatformRuntime {
}, logger::info);
}
});
onRecFrame();
} else {
stopRec(mediaRec);
mediaRec = null;

View File

@ -0,0 +1,439 @@
package net.lax1dude.eaglercraft.v1_8.internal;
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;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject;
import org.teavm.jso.dom.events.Event;
import org.teavm.jso.dom.events.EventListener;
import org.teavm.jso.dom.html.HTMLAudioElement;
import org.teavm.jso.dom.html.HTMLDocument;
import org.teavm.jso.json.JSON;
import org.teavm.jso.typedarrays.Uint8Array;
import org.teavm.jso.webaudio.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Copyright (c) 2022-2024 ayunami2000. 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 PlatformVoiceClient {
private static final Logger logger = LogManager.getLogger("PlatformVoiceClient");
private static final HashMap<EaglercraftUUID, AnalyserNode> voiceAnalysers = new HashMap<>();
private static final HashMap<EaglercraftUUID, GainNode> voiceGains = new HashMap<>();
private static final HashMap<EaglercraftUUID, PannerNode> voicePanners = new HashMap<>();
@JSBody(params = {}, script = "return typeof window.RTCPeerConnection !== \"undefined\" && typeof navigator.mediaDevices !== \"undefined\" && typeof navigator.mediaDevices.getUserMedia !== \"undefined\";")
public static native boolean isSupported();
@JSBody(params = { "item" }, script = "return item.streams[0];")
static native MediaStream getFirstStream(JSObject item);
@JSBody(params = { "aud", "stream" }, script = "return aud.srcObject = stream;")
static native void setSrcObject(HTMLAudioElement aud, MediaStream stream);
@JSBody(params = { "aud" }, script = "return aud.remove();")
static native void removeAud(HTMLAudioElement aud);
@JSBody(params = { "pc", "stream" }, script = "return stream.getTracks().forEach((track) => { pc.addTrack(track, stream); });")
static native void addStream(JSObject pc, MediaStream stream);
@JSBody(params = { "rawStream", "muted" }, script = "return rawStream.getAudioTracks()[0].enabled = !muted;")
static native void mute(MediaStream rawStream, boolean muted);
@JSBody(params = { "peerConnection", "str" }, script = "return peerConnection.addIceCandidate(new RTCIceCandidate(JSON.parse(str)));")
static native void addIceCandidate(JSObject peerConnection, String str);
public static void disconnect(JSObject peerConnection) {
PlatformWebRTC.closeIt(peerConnection);
}
public static void setVoiceProximity(int prox) {
for (PannerNode panner : voicePanners.values()) {
panner.setMaxDistance(VoiceClientController.getVoiceListenVolume() * 2 * prox + 0.1f);
}
}
public static void updateVoicePosition(EaglercraftUUID uuid, double x, double y, double z) {
if (voicePanners.containsKey(uuid)) voicePanners.get(uuid).setPosition((float) x, (float) y, (float) z);
}
public static class VoicePeer {
public final EaglercraftUUID peerId;
public final JSObject peerConnection;
public MediaStream rawStream;
public VoicePeer(EaglercraftUUID peerId, JSObject peerConnection, boolean offer) {
this.peerId = peerId;
this.peerConnection = peerConnection;
TeaVMUtils.addEventListener(peerConnection, "icecandidate", (EventListener<Event>) evt -> {
if (PlatformWebRTC.hasCandidate(evt)) {
Map<String, String> m = new HashMap<>();
m.put("sdpMLineIndex", "" + PlatformWebRTC.getSdpMLineIndex(evt));
m.put("candidate", PlatformWebRTC.getCandidate(evt));
handleIceCandidate(peerId, JSONWriter.valueToString(m));
}
});
TeaVMUtils.addEventListener(peerConnection, "track", (EventListener<Event>) evt -> {
rawStream = getFirstStream(evt);
HTMLAudioElement aud = (HTMLAudioElement) HTMLDocument.current().createElement("audio");
aud.setAutoplay(true);
aud.setMuted(true);
TeaVMUtils.addEventListener(aud, "ended", (EventListener<Event>) evt2 -> {
removeAud(aud);
});
setSrcObject(aud, rawStream);
handlePeerTrack(peerId, rawStream);
});
addStream(peerConnection, localMediaStream.getStream());
if (offer) {
PlatformWebRTC.createOffer(peerConnection, desc -> {
PlatformWebRTC.setLocalDescription(peerConnection, desc, () -> {
handleDescription(peerId, JSON.stringify(desc));
}, err -> {
logger.error("Failed to set local description for \"{}\"! {}", peerId, err);
if (peerStateInitial == EnumVoiceChannelPeerState.LOADING) {
peerStateInitial = EnumVoiceChannelPeerState.FAILED;
}
signalDisconnect(peerId, false);
});
}, err -> {
logger.error("Failed to set create offer for \"{}\"! {}", peerId, err);
if (peerStateInitial == EnumVoiceChannelPeerState.LOADING) {
peerStateInitial = EnumVoiceChannelPeerState.FAILED;
}
signalDisconnect(peerId, false);
});
}
TeaVMUtils.addEventListener(peerConnection, "connectionstatechange", (EventListener<Event>) evt -> {
String cs = PlatformWebRTC.getConnectionState(peerConnection);
if ("disconnected".equals(cs)) {
signalDisconnect(peerId, 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;
}
signalDisconnect(peerId, false);
}
});
}
public void disconnect() {
PlatformVoiceClient.disconnect(peerConnection);
}
public void mute(boolean muted) {
PlatformVoiceClient.mute(rawStream, muted);
}
public void setRemoteDescription(String descJSON) {
try {
JSONObject remoteDesc = new JSONObject(descJSON);
PlatformWebRTC.setRemoteDescription2(peerConnection, descJSON, () -> {
if (remoteDesc.has("type") && "offer".equals(remoteDesc.getString("type"))) {
PlatformWebRTC.createAnswer(peerConnection, desc -> {
PlatformWebRTC.setLocalDescription(peerConnection, desc, () -> {
handleDescription(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(peerId, false);
});
}, err -> {
logger.error("Failed to create answer for \"{}\"! {}", peerId, err.getMessage());
if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(peerId, false);
});
}
}, err -> {
logger.error("Failed to set remote description for \"{}\"! {}", peerId, err.getMessage());
if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(peerId, false);
});
} catch (Throwable err) {
logger.error("Failed to parse remote description for \"{}\"! {}", peerId, err.getMessage());
if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
signalDisconnect(peerId, false);
}
}
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(peerId, false);
}
}
}
public static Set<Map<String, String>> iceServers = new HashSet<>();
public static boolean hasInit = false;
public static Map<EaglercraftUUID, VoicePeer> peerList = new HashMap<>();
public static MediaStreamAudioDestinationNode localMediaStream;
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) {
iceServers.clear();
if (urls == null) return;
for (String url : urls) {
String[] etr = url.split(";");
if (etr.length == 1) {
Map<String, String> m = new HashMap<>();
m.put("urls", etr[0]);
iceServers.add(m);
} else if (etr.length == 3) {
Map<String, String> m = new HashMap<>();
m.put("urls", etr[0]);
m.put("username", etr[1]);
m.put("credential", etr[2]);
iceServers.add(m);
}
}
}
public static void activateVoice(boolean talk) {
if (hasInit) {
PlatformVoiceClient.mute(localRawMediaStream, !talk);
}
}
public static void initializeDevices() {
if (!hasInit) {
localRawMediaStream = PlatformRuntime.getMic();
if (localRawMediaStream == null) {
readyState = EnumVoiceChannelReadyState.ABORTED;
return;
}
microphoneVolumeAudioContext = AudioContext.create();
mute(localRawMediaStream, true);
localMediaStream = microphoneVolumeAudioContext.createMediaStreamDestination();
localMediaStreamGain = microphoneVolumeAudioContext.createGain();
microphoneVolumeAudioContext.createMediaStreamSource(localRawMediaStream).connect(localMediaStreamGain);
localMediaStreamGain.connect(localMediaStream);
localMediaStreamGain.getGain().setValue(1.0F);
readyState = EnumVoiceChannelReadyState.DEVICE_INITIALIZED;
hasInit = true;
} else {
readyState = EnumVoiceChannelReadyState.DEVICE_INITIALIZED;
}
}
public static void tickVoiceClient() {
for (EaglercraftUUID uuid : voiceAnalysers.keySet()) {
AnalyserNode analyser = voiceAnalysers.get(uuid);
Uint8Array array = Uint8Array.create(analyser.getFrequencyBinCount());
analyser.getByteFrequencyData(array);
int len = array.getLength();
for (int i = 0; i < len; i++) {
if (array.get(i) >= 0.1f) {
VoiceClientController.getVoiceSpeaking().add(uuid);
break;
}
}
}
}
public static void setMicVolume(float val) {
if (hasInit) {
if(val > 0.5F) val = 0.5F + (val - 0.5F) * 2.0F;
if(val > 1.5F) val = 1.5F;
if(val < 0.0F) val = 0.0F;
localMediaStreamGain.getGain().setValue(val * 2.0F);
}
}
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;
}
}
public static void signalDescription(EaglercraftUUID peerId, String descJSON) {
VoicePeer peer = peerList.get(peerId);
if (peer != null) {
peer.setRemoteDescription(descJSON);
}
}
public static void signalDisconnect(EaglercraftUUID peerId, boolean quiet) {
VoicePeer peer = peerList.get(peerId);
if (peer != null) {
peerList.remove(peerId, peer);
try {
peer.disconnect();
} catch (Throwable ignored) {}
handlePeerDisconnect(peerId, quiet);
}
}
public static void mutePeer(EaglercraftUUID peerId, boolean muted) {
VoicePeer peer = peerList.get(peerId);
if (peer != null) {
peer.mute(muted);
}
}
public static void signalICECandidate(EaglercraftUUID peerId, String candidate) {
VoicePeer peer = peerList.get(peerId);
if (peer != null) {
peer.addICECandidate(candidate);
}
}
public static void handleIceCandidate(EaglercraftUUID peerId, String candidate) {
VoiceClientController.sendPacketICE(peerId, candidate);
}
public static void handleDescription(EaglercraftUUID peerId, String desc) {
VoiceClientController.sendPacketDesc(peerId, desc);
}
public static void handlePeerTrack(EaglercraftUUID peerId, MediaStream audioStream) {
if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.NONE) return;
MediaStreamAudioSourceNode audioNode = PlatformAudio.audioctx.createMediaStreamSource(audioStream);
AnalyserNode analyser = PlatformAudio.audioctx.createAnalyser();
analyser.setSmoothingTimeConstant(0f);
analyser.setFftSize(32);
audioNode.connect(analyser);
voiceAnalysers.put(peerId, analyser);
if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.GLOBAL) {
GainNode gain = PlatformAudio.audioctx.createGain();
gain.getGain().setValue(VoiceClientController.getVoiceListenVolume());
analyser.connect(gain);
gain.connect(PlatformAudio.audioctx.getDestination());
gain.connect(PlatformAudio.recDest);
voiceGains.put(peerId, gain);
VoiceClientController.getVoiceListening().add(peerId);
} else if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.PROXIMITY) {
PannerNode panner = PlatformAudio.audioctx.createPanner();
panner.setRolloffFactor(1f);
panner.setDistanceModel("linear");
panner.setPanningModel("HRTF");
panner.setConeInnerAngle(360f);
panner.setConeOuterAngle(0f);
panner.setConeOuterGain(0f);
panner.setOrientation(0f, 1f, 0f);
panner.setPosition(0, 0, 0);
float vol = VoiceClientController.getVoiceListenVolume();
panner.setMaxDistance(vol * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
GainNode gain = PlatformAudio.audioctx.createGain();
gain.getGain().setValue(vol);
analyser.connect(gain);
gain.connect(panner);
panner.connect(PlatformAudio.audioctx.getDestination());
panner.connect(PlatformAudio.recDest);
voiceGains.put(peerId, gain);
VoiceClientController.getVoiceListening().add(peerId);
voicePanners.put(peerId, panner);
}
if (VoiceClientController.getVoiceMuted().contains(peerId)) mutePeer(peerId, true);
}
public static void handlePeerDisconnect(EaglercraftUUID peerId, boolean quiet) {
if (voiceAnalysers.containsKey(peerId)) {
voiceAnalysers.get(peerId).disconnect();
voiceAnalysers.remove(peerId);
}
if (voiceGains.containsKey(peerId)) {
voiceGains.get(peerId).disconnect();
voiceGains.remove(peerId);
VoiceClientController.getVoiceListening().remove(peerId);
}
if (voicePanners.containsKey(peerId)) {
voicePanners.get(peerId).disconnect();
voicePanners.remove(peerId);
}
if (!quiet) {
VoiceClientController.sendPacketDisconnect(peerId);
}
}
public static void setVoiceListenVolume(float f) {
for (EaglercraftUUID uuid : voiceGains.keySet()) {
GainNode gain = voiceGains.get(uuid);
float val = f;
if(val > 0.5f) val = 0.5f + (val - 0.5f) * 3.0f;
if(val > 2.0f) val = 2.0f;
if(val < 0.0f) val = 0.0f;
gain.getGain().setValue(val * 2.0f);
if (voicePanners.containsKey(uuid)) voicePanners.get(uuid).setMaxDistance(f * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
}
}
}

View File

@ -1,9 +1,9 @@
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.DataView;
import org.teavm.jso.typedarrays.Float32Array;
import org.teavm.jso.typedarrays.Int32Array;
import org.teavm.jso.typedarrays.Int8Array;
import org.teavm.jso.typedarrays.Uint16Array;
import org.teavm.jso.typedarrays.Uint8Array;
@ -31,27 +31,31 @@ public class EaglerArrayBufferAllocator {
}
public static ByteBuffer allocateByteBuffer(int size) {
return new EaglerArrayByteBuffer(DataView.create(ArrayBuffer.create(size)));
return new EaglerArrayByteBuffer(Int8Array.create(size));
}
public static ByteBuffer wrapByteBufferTeaVM(DataView dv) {
return new EaglerArrayByteBuffer(dv);
}
public static IntBuffer allocateIntBuffer(int size) {
return new EaglerArrayIntBuffer(DataView.create(ArrayBuffer.create(size << 2)));
public static ByteBuffer wrapByteBufferTeaVM(Int8Array typedArray) {
return new EaglerArrayByteBuffer(typedArray);
}
public static IntBuffer wrapIntBufferTeaVM(DataView dv) {
return new EaglerArrayIntBuffer(dv);
public static IntBuffer allocateIntBuffer(int size) {
return new EaglerArrayIntBuffer(Int32Array.create(size));
}
public static IntBuffer wrapIntBufferTeaVM(Int32Array typedArray) {
return new EaglerArrayIntBuffer(typedArray);
}
public static FloatBuffer allocateFloatBuffer(int size) {
return new EaglerArrayFloatBuffer(DataView.create(ArrayBuffer.create(size << 2)));
return new EaglerArrayFloatBuffer(Float32Array.create(size));
}
public static FloatBuffer wrapFloatBufferTeaVM(DataView dv) {
return new EaglerArrayFloatBuffer(dv);
public static FloatBuffer wrapFloatBufferTeaVM(Float32Array typedArray) {
return new EaglerArrayFloatBuffer(typedArray);
}
public static DataView getDataView(ByteBuffer buffer) {
@ -63,121 +67,115 @@ public class EaglerArrayBufferAllocator {
if(p == 0 && l == b.capacity) {
return d;
}else {
int i = d.getByteOffset();
return DataView.create(d.getBuffer(), i + p, l - p);
return DataView.create(d.getBuffer(), d.getByteOffset() + p, l - p);
}
}else {
throw notEagler(buffer);
}
}
public static Uint8Array getDataViewStupid(ByteBuffer buffer) {
public static Int8Array getDataView8(ByteBuffer buffer) {
if(buffer instanceof EaglerArrayByteBuffer) {
EaglerArrayByteBuffer b = (EaglerArrayByteBuffer)buffer;
DataView d = b.dataView;
int p = b.position;
int l = b.limit;
int i = d.getByteOffset();
return Uint8Array.create(d.getBuffer(), i + p, l - p);
}else {
throw notEagler(buffer);
}
}
public static Uint16Array getDataViewStupid16(ByteBuffer buffer) {
if(buffer instanceof EaglerArrayByteBuffer) {
EaglerArrayByteBuffer b = (EaglerArrayByteBuffer)buffer;
DataView d = b.dataView;
int p = b.position;
int l = b.limit;
int i = d.getByteOffset();
return Uint16Array.create(d.getBuffer(), i + p, (l - p) >> 1);
}else {
throw notEagler(buffer);
}
}
public static DataView getDataView(IntBuffer buffer) {
if(buffer instanceof EaglerArrayIntBuffer) {
EaglerArrayIntBuffer b = (EaglerArrayIntBuffer)buffer;
DataView d = b.dataView;
Int8Array d = b.typedArray;
int p = b.position;
int l = b.limit;
if(p == 0 && l == b.capacity) {
return d;
}else {
int i = d.getByteOffset();
return DataView.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
return Int8Array.create(d.getBuffer(), d.getByteOffset() + p, l - p);
}
}else {
throw notEagler(buffer);
}
}
public static Uint8Array getDataViewStupid(IntBuffer buffer) {
if(buffer instanceof EaglerArrayIntBuffer) {
EaglerArrayIntBuffer b = (EaglerArrayIntBuffer)buffer;
DataView d = b.dataView;
public static Uint8Array getDataView8Unsigned(ByteBuffer buffer) {
if(buffer instanceof EaglerArrayByteBuffer) {
EaglerArrayByteBuffer b = (EaglerArrayByteBuffer)buffer;
Int8Array d = b.typedArray;
int p = b.position;
int l = b.limit;
int i = d.getByteOffset();
return Uint8Array.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
return Uint8Array.create(d.getBuffer(), i + p, b.limit - p);
}else {
throw notEagler(buffer);
}
}
public static Int32Array getDataViewStupid32(IntBuffer buffer) {
if(buffer instanceof EaglerArrayIntBuffer) {
EaglerArrayIntBuffer b = (EaglerArrayIntBuffer)buffer;
DataView d = b.dataView;
public static Uint16Array getDataView16Unsigned(ByteBuffer buffer) {
if(buffer instanceof EaglerArrayByteBuffer) {
EaglerArrayByteBuffer b = (EaglerArrayByteBuffer)buffer;
Int8Array d = b.typedArray;
int p = b.position;
int l = b.limit;
int i = d.getByteOffset();
return Int32Array.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
return Uint16Array.create(d.getBuffer(), d.getByteOffset() + p, (b.limit - p) >> 1);
}else {
throw notEagler(buffer);
}
}
public static DataView getDataView(FloatBuffer buffer) {
if(buffer instanceof EaglerArrayFloatBuffer) {
EaglerArrayFloatBuffer b = (EaglerArrayFloatBuffer)buffer;
DataView d = b.dataView;
public static Float32Array getDataView32F(ByteBuffer buffer) {
if(buffer instanceof EaglerArrayByteBuffer) {
EaglerArrayByteBuffer b = (EaglerArrayByteBuffer)buffer;
Int8Array d = b.typedArray;
int p = b.position;
return Float32Array.create(d.getBuffer(), d.getByteOffset() + p, (b.limit - p) >> 2);
}else {
throw notEagler(buffer);
}
}
public static Int32Array getDataView32(IntBuffer buffer) {
if(buffer instanceof EaglerArrayIntBuffer) {
EaglerArrayIntBuffer b = (EaglerArrayIntBuffer)buffer;
Int32Array d = b.typedArray;
int p = b.position;
int l = b.limit;
if(p == 0 && l == b.capacity) {
return d;
}else {
int i = d.getByteOffset();
return DataView.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
return Int32Array.create(d.getBuffer(), d.getByteOffset() + (p << 2), l - p);
}
}else {
throw notEagler(buffer);
}
}
public static Uint8Array getDataViewStupid(FloatBuffer buffer) {
if(buffer instanceof EaglerArrayFloatBuffer) {
EaglerArrayFloatBuffer b = (EaglerArrayFloatBuffer)buffer;
DataView d = b.dataView;
public static Uint8Array getDataView8Unsigned(IntBuffer buffer) {
if(buffer instanceof EaglerArrayIntBuffer) {
EaglerArrayIntBuffer b = (EaglerArrayIntBuffer)buffer;
Int32Array d = b.typedArray;
int p = b.position;
int l = b.limit;
int i = d.getByteOffset();
return Uint8Array.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
return Uint8Array.create(d.getBuffer(), d.getByteOffset() + (p << 2), (l - p) << 2);
}else {
throw notEagler(buffer);
}
}
public static Float32Array getFloatArrayStupid(FloatBuffer buffer) {
public static Float32Array getDataView32F(FloatBuffer buffer) {
if(buffer instanceof EaglerArrayFloatBuffer) {
EaglerArrayFloatBuffer b = (EaglerArrayFloatBuffer)buffer;
DataView d = b.dataView;
Float32Array d = b.typedArray;
int p = b.position;
int l = b.limit;
int i = d.getByteOffset();
return Float32Array.create(d.getBuffer(), i + p, l - p);
if(p == 0 && l == b.capacity) {
return d;
}else {
return Float32Array.create(d.getBuffer(), d.getByteOffset() + (p << 2), l - p);
}
}else {
throw notEagler(buffer);
}
}
public static Uint8Array getDataView8Unsigned(FloatBuffer buffer) {
if(buffer instanceof EaglerArrayFloatBuffer) {
EaglerArrayFloatBuffer b = (EaglerArrayFloatBuffer)buffer;
Float32Array d = b.typedArray;
int p = b.position;
int l = b.limit;
return Uint8Array.create(d.getBuffer(), d.getByteOffset() + (p << 2), (l - p) << 2);
}else {
throw notEagler(buffer);
}

View File

@ -1,8 +1,12 @@
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.DataView;
import org.teavm.jso.typedarrays.Uint8Array;
import org.teavm.jso.typedarrays.Float32Array;
import org.teavm.jso.typedarrays.Int16Array;
import org.teavm.jso.typedarrays.Int32Array;
import org.teavm.jso.typedarrays.Int8Array;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
/**
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
@ -22,16 +26,18 @@ import org.teavm.jso.typedarrays.Uint8Array;
public class EaglerArrayByteBuffer implements ByteBuffer {
final DataView dataView;
final Int8Array typedArray;
final int capacity;
int position;
int limit;
int mark;
static final DataView ZERO_LENGTH_BUFFER = DataView.create(ArrayBuffer.create(0));
static final Int8Array ZERO_LENGTH_BUFFER = Int8Array.create(0);
EaglerArrayByteBuffer(DataView dataView) {
this.dataView = dataView;
this.typedArray = Int8Array.create(dataView.getBuffer(), dataView.getByteOffset(), dataView.getByteLength());
this.capacity = dataView.getByteLength();
this.position = 0;
this.limit = this.capacity;
@ -40,11 +46,30 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
EaglerArrayByteBuffer(DataView dataView, int position, int limit, int mark) {
this.dataView = dataView;
this.typedArray = Int8Array.create(dataView.getBuffer(), dataView.getByteOffset(), dataView.getByteLength());
this.capacity = dataView.getByteLength();
this.position = position;
this.limit = limit;
this.mark = mark;
}
EaglerArrayByteBuffer(Int8Array typedArray) {
this.typedArray = typedArray;
this.dataView = DataView.create(typedArray.getBuffer(), typedArray.getByteOffset(), typedArray.getByteLength());
this.capacity = typedArray.getByteLength();
this.position = 0;
this.limit = this.capacity;
this.mark = -1;
}
EaglerArrayByteBuffer(Int8Array typedArray, int position, int limit, int mark) {
this.typedArray = typedArray;
this.dataView = DataView.create(typedArray.getBuffer(), typedArray.getByteOffset(), typedArray.getByteLength());
this.capacity = typedArray.getByteLength();
this.position = position;
this.limit = limit;
this.mark = mark;
}
@Override
public int capacity() {
@ -93,8 +118,12 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public ByteBuffer slice() {
int o = dataView.getByteOffset();
return new EaglerArrayByteBuffer(DataView.create(dataView.getBuffer(), o + position, limit - position));
if(position == limit) {
return new EaglerArrayByteBuffer(ZERO_LENGTH_BUFFER);
}else {
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
return new EaglerArrayByteBuffer(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, limit - position));
}
}
@Override
@ -110,35 +139,33 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public byte get() {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
return dataView.getInt8(position++);
return typedArray.get(position++);
}
@Override
public ByteBuffer put(byte b) {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
dataView.setInt8(position++, b);
typedArray.set(position++, b);
return this;
}
@Override
public byte get(int index) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
return dataView.getInt8(index);
return typedArray.get(index);
}
@Override
public ByteBuffer put(int index, byte b) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
dataView.setInt8(index, b);
typedArray.set(index, b);
return this;
}
@Override
public ByteBuffer get(byte[] dst, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dst[offset + i] = dataView.getInt8(position + i);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, length), offset);
position += length;
return this;
}
@ -146,9 +173,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public ByteBuffer get(byte[] dst) {
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
for(int i = 0; i < dst.length; ++i) {
dst[position + i] = dataView.getInt8(position + i);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, dst.length));
position += dst.length;
return this;
}
@ -159,10 +184,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
EaglerArrayByteBuffer c = (EaglerArrayByteBuffer)src;
int l = c.limit - c.position;
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
int o = c.dataView.getByteOffset();
Uint8Array.create(dataView.getBuffer()).set(
Uint8Array.create(c.dataView.getBuffer(), o + c.position, c.limit - c.position),
dataView.getByteOffset() + position);
typedArray.set(Int8Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + c.position, l), position);
position += l;
c.position += l;
}else {
@ -179,8 +201,10 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public ByteBuffer put(byte[] src, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dataView.setInt8(position + i, src[offset + i]);
if(offset == 0 && length == src.length) {
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
}else {
typedArray.set(Int8Array.create(TeaVMUtils.unwrapArrayBuffer(src), offset, length), position);
}
position += length;
return this;
@ -189,10 +213,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public ByteBuffer put(byte[] src) {
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
//dataView.set(src, position); // doesn't work
for(int i = 0; i < src.length; ++i) {
dataView.setInt8(position + i, src[i]);
}
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
position += src.length;
return this;
}
@ -211,12 +232,10 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
return new EaglerArrayByteBuffer(ZERO_LENGTH_BUFFER);
}
int o = dataView.getByteOffset();
Int8Array dst = Int8Array.create(limit - position);
dst.set(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, limit - position));
Uint8Array dst = Uint8Array.create(ArrayBuffer.create(limit - position));
dst.set(Uint8Array.create(dataView.getBuffer(), o + position, limit - position));
return new EaglerArrayByteBuffer(DataView.create(dst.getBuffer()));
return new EaglerArrayByteBuffer(dst);
}
@Override
@ -279,7 +298,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public ShortBuffer asShortBuffer() {
return new EaglerArrayShortBuffer(dataView);
return new EaglerArrayShortBuffer(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset(), typedArray.getLength() >> 1));
}
@Override
@ -313,7 +332,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public IntBuffer asIntBuffer() {
return new EaglerArrayIntBuffer(dataView);
return new EaglerArrayIntBuffer(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset(), typedArray.getLength() >> 2));
}
@Override
@ -388,7 +407,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
@Override
public FloatBuffer asFloatBuffer() {
return new EaglerArrayFloatBuffer(dataView);
return new EaglerArrayFloatBuffer(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset(), typedArray.getLength() >> 2));
}
@Override

View File

@ -1,8 +1,8 @@
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.DataView;
import org.teavm.jso.typedarrays.Uint8Array;
import org.teavm.jso.typedarrays.Float32Array;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
/**
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
@ -21,7 +21,7 @@ import org.teavm.jso.typedarrays.Uint8Array;
*/
public class EaglerArrayFloatBuffer implements FloatBuffer {
final DataView dataView;
final Float32Array typedArray;
final int capacity;
int position;
@ -30,17 +30,19 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
private static final int SHIFT = 2;
EaglerArrayFloatBuffer(DataView dataView) {
this.dataView = dataView;
this.capacity = dataView.getByteLength() >> SHIFT;
static final Float32Array ZERO_LENGTH_BUFFER = Float32Array.create(0);
EaglerArrayFloatBuffer(Float32Array typedArray) {
this.typedArray = typedArray;
this.capacity = typedArray.getLength();
this.position = 0;
this.limit = this.capacity;
this.mark = -1;
}
EaglerArrayFloatBuffer(DataView dataView, int position, int limit, int mark) {
this.dataView = dataView;
this.capacity = dataView.getByteLength() >> SHIFT;
EaglerArrayFloatBuffer(Float32Array typedArray, int position, int limit, int mark) {
this.typedArray = typedArray;
this.capacity = typedArray.getLength();
this.position = position;
this.limit = limit;
this.mark = mark;
@ -93,64 +95,66 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
@Override
public FloatBuffer slice() {
int o = dataView.getByteOffset();
return new EaglerArrayFloatBuffer(DataView.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
if(position == limit) {
return new EaglerArrayFloatBuffer(ZERO_LENGTH_BUFFER);
}else {
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
return new EaglerArrayFloatBuffer(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
}
}
@Override
public FloatBuffer duplicate() {
return new EaglerArrayFloatBuffer(dataView, position, limit, mark);
return new EaglerArrayFloatBuffer(typedArray, position, limit, mark);
}
@Override
public FloatBuffer asReadOnlyBuffer() {
return new EaglerArrayFloatBuffer(dataView, position, limit, mark);
return new EaglerArrayFloatBuffer(typedArray, position, limit, mark);
}
@Override
public float get() {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
return dataView.getFloat32((position++) << SHIFT, true);
return typedArray.get(position++);
}
@Override
public FloatBuffer put(float b) {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
dataView.setFloat32((position++) << SHIFT, b, true);
typedArray.set(position++, b);
return this;
}
@Override
public float get(int index) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
return dataView.getFloat32(index << SHIFT, true);
return typedArray.get(index);
}
@Override
public FloatBuffer put(int index, float b) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
dataView.setFloat32(index << SHIFT, b, true);
typedArray.set(index, b);
return this;
}
@Override
public float getElement(int index) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
return dataView.getFloat32(index << SHIFT, true);
return typedArray.get(index);
}
@Override
public void putElement(int index, float value) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
dataView.setFloat32(index << SHIFT, value, true);
typedArray.set(index, value);
}
@Override
public FloatBuffer get(float[] dst, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dst[offset + i] = dataView.getFloat32((position + i) << SHIFT, true);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), length), offset);
position += length;
return this;
}
@ -158,9 +162,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
@Override
public FloatBuffer get(float[] dst) {
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
for(int i = 0; i < dst.length; ++i) {
dst[i] = dataView.getFloat32((position + i) << SHIFT, true);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), dst.length));
position += dst.length;
return this;
}
@ -171,17 +173,14 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
EaglerArrayFloatBuffer c = (EaglerArrayFloatBuffer)src;
int l = c.limit - c.position;
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
int o = c.dataView.getByteOffset();
Uint8Array.create(dataView.getBuffer()).set(
Uint8Array.create(c.dataView.getBuffer(), o + (c.position << SHIFT), (c.limit - c.position) << SHIFT),
dataView.getByteOffset() + (position << SHIFT));
typedArray.set(Float32Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + (c.position << SHIFT), l), position);
position += l;
c.position += l;
}else {
int l = src.remaining();
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
for(int i = 0; i < l; ++i) {
dataView.setFloat32((position + l) << SHIFT, src.get(), true);
typedArray.set(position + l, src.get());
}
position += l;
}
@ -191,8 +190,10 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
@Override
public FloatBuffer put(float[] src, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dataView.setFloat32((position + i) << SHIFT, src[offset + i], true);
if(offset == 0 && length == src.length) {
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
}else {
typedArray.set(Float32Array.create(TeaVMUtils.unwrapArrayBuffer(src), offset << SHIFT, length), position);
}
position += length;
return this;
@ -201,9 +202,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
@Override
public FloatBuffer put(float[] src) {
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
for(int i = 0; i < src.length; ++i) {
dataView.setFloat32((position + i) << SHIFT, src[i], true);
}
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
position += src.length;
return this;
}
@ -219,15 +218,13 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
if(position == limit) {
return new EaglerArrayFloatBuffer(EaglerArrayByteBuffer.ZERO_LENGTH_BUFFER);
return new EaglerArrayFloatBuffer(ZERO_LENGTH_BUFFER);
}
int o = dataView.getByteOffset();
Float32Array dst = Float32Array.create(limit - position);
dst.set(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
Uint8Array dst = Uint8Array.create(ArrayBuffer.create((limit - position) << SHIFT));
dst.set(Uint8Array.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
return new EaglerArrayFloatBuffer(DataView.create(dst.getBuffer()));
return new EaglerArrayFloatBuffer(dst);
}
@Override

View File

@ -1,8 +1,8 @@
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.DataView;
import org.teavm.jso.typedarrays.Uint8Array;
import org.teavm.jso.typedarrays.Int32Array;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
/**
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
@ -21,7 +21,7 @@ import org.teavm.jso.typedarrays.Uint8Array;
*/
public class EaglerArrayIntBuffer implements IntBuffer {
final DataView dataView;
final Int32Array typedArray;
final int capacity;
int position;
@ -30,17 +30,19 @@ public class EaglerArrayIntBuffer implements IntBuffer {
private static final int SHIFT = 2;
EaglerArrayIntBuffer(DataView dataView) {
this.dataView = dataView;
this.capacity = dataView.getByteLength() >> SHIFT;
static final Int32Array ZERO_LENGTH_BUFFER = Int32Array.create(0);
EaglerArrayIntBuffer(Int32Array typedArray) {
this.typedArray = typedArray;
this.capacity = typedArray.getLength();
this.position = 0;
this.limit = this.capacity;
this.mark = -1;
}
EaglerArrayIntBuffer(DataView dataView, int position, int limit, int mark) {
this.dataView = dataView;
this.capacity = dataView.getByteLength() >> SHIFT;
EaglerArrayIntBuffer(Int32Array typedArray, int position, int limit, int mark) {
this.typedArray = typedArray;
this.capacity = typedArray.getLength();
this.position = position;
this.limit = limit;
this.mark = mark;
@ -93,64 +95,66 @@ public class EaglerArrayIntBuffer implements IntBuffer {
@Override
public IntBuffer slice() {
int o = dataView.getByteOffset();
return new EaglerArrayIntBuffer(DataView.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
if(position == limit) {
return new EaglerArrayIntBuffer(ZERO_LENGTH_BUFFER);
}else {
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
return new EaglerArrayIntBuffer(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
}
}
@Override
public IntBuffer duplicate() {
return new EaglerArrayIntBuffer(dataView, position, limit, mark);
return new EaglerArrayIntBuffer(typedArray, position, limit, mark);
}
@Override
public IntBuffer asReadOnlyBuffer() {
return new EaglerArrayIntBuffer(dataView, position, limit, mark);
return new EaglerArrayIntBuffer(typedArray, position, limit, mark);
}
@Override
public int get() {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
return dataView.getInt32((position++) << SHIFT, true);
return typedArray.get(position++);
}
@Override
public IntBuffer put(int b) {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
dataView.setInt32((position++) << SHIFT, b, true);
typedArray.set(position++, b);
return this;
}
@Override
public int get(int index) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
return dataView.getInt32(index << SHIFT, true);
return typedArray.get(index);
}
@Override
public IntBuffer put(int index, int b) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
dataView.setInt32(index << SHIFT, b, true);
typedArray.set(index, b);
return this;
}
@Override
public int getElement(int index) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
return dataView.getInt32(index << SHIFT, true);
return typedArray.get(index);
}
@Override
public void putElement(int index, int value) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
dataView.setInt32(index << SHIFT, value, true);
typedArray.set(index, value);
}
@Override
public IntBuffer get(int[] dst, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dst[offset + i] = dataView.getInt32((position + i) << SHIFT, true);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), length), offset);
position += length;
return this;
}
@ -158,9 +162,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
@Override
public IntBuffer get(int[] dst) {
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
for(int i = 0; i < dst.length; ++i) {
dst[i] = dataView.getInt32((position + i) << SHIFT, true);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), dst.length));
position += dst.length;
return this;
}
@ -171,17 +173,14 @@ public class EaglerArrayIntBuffer implements IntBuffer {
EaglerArrayIntBuffer c = (EaglerArrayIntBuffer)src;
int l = c.limit - c.position;
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
int o = c.dataView.getByteOffset();
Uint8Array.create(dataView.getBuffer()).set(
Uint8Array.create(c.dataView.getBuffer(), o + (c.position << SHIFT), (c.limit - c.position) << SHIFT),
dataView.getByteOffset() + (position << SHIFT));
typedArray.set(Int32Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + (c.position << SHIFT), l), position);
position += l;
c.position += l;
}else {
int l = src.remaining();
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
for(int i = 0; i < l; ++i) {
dataView.setInt32((position + l) << SHIFT, src.get(), true);
typedArray.set(position + l, src.get());
}
position += l;
}
@ -191,8 +190,10 @@ public class EaglerArrayIntBuffer implements IntBuffer {
@Override
public IntBuffer put(int[] src, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dataView.setInt32((position + i) << SHIFT, src[offset + i], true);
if(offset == 0 && length == src.length) {
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
}else {
typedArray.set(Int32Array.create(TeaVMUtils.unwrapArrayBuffer(src), offset << SHIFT, length), position);
}
position += length;
return this;
@ -201,9 +202,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
@Override
public IntBuffer put(int[] src) {
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
for(int i = 0; i < src.length; ++i) {
dataView.setInt32((position + i) << SHIFT, src[i], true);
}
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
position += src.length;
return this;
}
@ -219,15 +218,13 @@ public class EaglerArrayIntBuffer implements IntBuffer {
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
if(position == limit) {
return new EaglerArrayIntBuffer(EaglerArrayByteBuffer.ZERO_LENGTH_BUFFER);
return new EaglerArrayIntBuffer(ZERO_LENGTH_BUFFER);
}
int o = dataView.getByteOffset();
Int32Array dst = Int32Array.create(limit - position);
dst.set(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
Uint8Array dst = Uint8Array.create(ArrayBuffer.create((limit - position) << SHIFT));
dst.set(Uint8Array.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
return new EaglerArrayIntBuffer(DataView.create(dst.getBuffer()));
return new EaglerArrayIntBuffer(dst);
}
@Override

View File

@ -1,8 +1,8 @@
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.DataView;
import org.teavm.jso.typedarrays.Uint8Array;
import org.teavm.jso.typedarrays.Int16Array;
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
/**
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
@ -21,7 +21,7 @@ import org.teavm.jso.typedarrays.Uint8Array;
*/
public class EaglerArrayShortBuffer implements ShortBuffer {
final DataView dataView;
final Int16Array typedArray;
final int capacity;
int position;
@ -30,17 +30,19 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
private static final int SHIFT = 1;
EaglerArrayShortBuffer(DataView dataView) {
this.dataView = dataView;
this.capacity = dataView.getByteLength() >> SHIFT;
static final Int16Array ZERO_LENGTH_BUFFER = Int16Array.create(0);
EaglerArrayShortBuffer(Int16Array typedArray) {
this.typedArray = typedArray;
this.capacity = typedArray.getLength();
this.position = 0;
this.limit = this.capacity;
this.mark = -1;
}
EaglerArrayShortBuffer(DataView dataView, int position, int limit, int mark) {
this.dataView = dataView;
this.capacity = dataView.getByteLength() >> SHIFT;
EaglerArrayShortBuffer(Int16Array typedArray, int position, int limit, int mark) {
this.typedArray = typedArray;
this.capacity = typedArray.getLength();
this.position = position;
this.limit = limit;
this.mark = mark;
@ -93,64 +95,66 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
@Override
public ShortBuffer slice() {
int o = dataView.getByteOffset();
return new EaglerArrayShortBuffer(DataView.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
if(position == limit) {
return new EaglerArrayShortBuffer(ZERO_LENGTH_BUFFER);
}else {
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
return new EaglerArrayShortBuffer(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
}
}
@Override
public ShortBuffer duplicate() {
return new EaglerArrayShortBuffer(dataView, position, limit, mark);
return new EaglerArrayShortBuffer(typedArray, position, limit, mark);
}
@Override
public ShortBuffer asReadOnlyBuffer() {
return new EaglerArrayShortBuffer(dataView, position, limit, mark);
return new EaglerArrayShortBuffer(typedArray, position, limit, mark);
}
@Override
public short get() {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
return dataView.getInt16((position++) << SHIFT, true);
return typedArray.get(position++);
}
@Override
public ShortBuffer put(short b) {
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
dataView.setInt16((position++) << SHIFT, b, true);
typedArray.set(position++, b);
return this;
}
@Override
public short get(int index) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
return dataView.getInt16(index << SHIFT, true);
return typedArray.get(index);
}
@Override
public ShortBuffer put(int index, short b) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
dataView.setInt16(index << SHIFT, b, true);
typedArray.set(index, b);
return this;
}
@Override
public short getElement(int index) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
return dataView.getInt16(index << SHIFT, true);
return typedArray.get(index);
}
@Override
public void putElement(int index, short value) {
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
dataView.setInt16(index << SHIFT, value, true);
typedArray.set(index, value);
}
@Override
public ShortBuffer get(short[] dst, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dst[offset + i] = dataView.getInt16((position + i) << SHIFT, true);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), length), offset);
position += length;
return this;
}
@ -158,9 +162,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
@Override
public ShortBuffer get(short[] dst) {
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
for(int i = 0; i < dst.length; ++i) {
dst[i] = dataView.getInt16((position + i) << SHIFT, true);
}
TeaVMUtils.unwrapArrayBufferView(dst).set(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), dst.length));
position += dst.length;
return this;
}
@ -171,17 +173,14 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
EaglerArrayShortBuffer c = (EaglerArrayShortBuffer)src;
int l = c.limit - c.position;
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
int o = c.dataView.getByteOffset();
Uint8Array.create(dataView.getBuffer()).set(
Uint8Array.create(c.dataView.getBuffer(), o + (c.position << SHIFT), (c.limit - c.position) << SHIFT),
dataView.getByteOffset() + (position << SHIFT));
typedArray.set(Int16Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + (c.position << SHIFT), l), position);
position += l;
c.position += l;
}else {
int l = src.remaining();
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
for(int i = 0; i < l; ++i) {
dataView.setInt16((position + l) << SHIFT, src.get(), true);
typedArray.set(position + l, src.get());
}
position += l;
}
@ -191,8 +190,10 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
@Override
public ShortBuffer put(short[] src, int offset, int length) {
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
for(int i = 0; i < length; ++i) {
dataView.setInt16((position + i) << SHIFT, src[offset + i], true);
if(offset == 0 && length == src.length) {
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
}else {
typedArray.set(Int16Array.create(TeaVMUtils.unwrapArrayBuffer(src), offset << SHIFT, length), position);
}
position += length;
return this;
@ -201,9 +202,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
@Override
public ShortBuffer put(short[] src) {
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
for(int i = 0; i < src.length; ++i) {
dataView.setInt16((position + i) << SHIFT, src[i], true);
}
typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
position += src.length;
return this;
}
@ -219,15 +218,13 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
if(position == limit) {
return new EaglerArrayShortBuffer(EaglerArrayByteBuffer.ZERO_LENGTH_BUFFER);
return new EaglerArrayShortBuffer(ZERO_LENGTH_BUFFER);
}
int o = dataView.getByteOffset();
Int16Array dst = Int16Array.create(limit - position);
dst.set(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
Uint8Array dst = Uint8Array.create(ArrayBuffer.create((limit - position) << SHIFT));
dst.set(Uint8Array.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
return new EaglerArrayShortBuffer(DataView.create(dst.getBuffer()));
return new EaglerArrayShortBuffer(dst);
}
@Override

File diff suppressed because one or more lines are too long

View File

@ -55,6 +55,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
private boolean logInvalidCerts = false;
private boolean checkRelaysForUpdates = false;
private boolean enableSignatureBadge = false;
private boolean allowVoiceClient = true;
public void loadNative(JSObject jsObject) {
integratedServerOpts = new JSONObject();
@ -73,12 +74,14 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
useSpecialCursors = eaglercraftXOpts.getHtml5CursorSupport(false);
logInvalidCerts = EaglercraftVersion.enableUpdateService && !demoMode && eaglercraftXOpts.getLogInvalidCerts(false);
enableSignatureBadge = eaglercraftXOpts.getEnableSignatureBadge(false);
allowVoiceClient = eaglercraftXOpts.getAllowVoiceClient(true);
integratedServerOpts.put("worldsDB", worldsDB);
integratedServerOpts.put("demoMode", demoMode);
integratedServerOpts.put("lang", defaultLocale);
integratedServerOpts.put("allowUpdateSvc", isAllowUpdateSvc);
integratedServerOpts.put("allowUpdateDL", isAllowUpdateDL);
integratedServerOpts.put("allowVoiceClient", allowVoiceClient);
JSEaglercraftXOptsServersArray serversArray = eaglercraftXOpts.getServers();
if(serversArray != null) {
@ -158,6 +161,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
useSpecialCursors = eaglercraftOpts.optBoolean("html5CursorSupport", false);
logInvalidCerts = EaglercraftVersion.enableUpdateService && !demoMode && eaglercraftOpts.optBoolean("logInvalidCerts", false);
enableSignatureBadge = eaglercraftOpts.optBoolean("enableSignatureBadge", false);
allowVoiceClient = eaglercraftOpts.optBoolean("allowVoiceClient", true);
JSONArray serversArray = eaglercraftOpts.optJSONArray("servers");
if(serversArray != null) {
for(int i = 0, l = serversArray.length(); i < l; ++i) {
@ -300,6 +304,11 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
return enableSignatureBadge;
}
@Override
public boolean isAllowVoiceClient() {
return allowVoiceClient;
}
@Override
public String toString() {
JSONObject jsonObject = new JSONObject();
@ -317,6 +326,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
jsonObject.put("logInvalidCerts", logInvalidCerts);
jsonObject.put("checkRelaysForUpdates", checkRelaysForUpdates);
jsonObject.put("enableSignatureBadge", enableSignatureBadge);
jsonObject.put("allowVoiceClient", allowVoiceClient);
JSONArray serversArr = new JSONArray();
for(int i = 0, l = defaultServers.size(); i < l; ++i) {
DefaultServer srv = defaultServers.get(i);

View File

@ -9,6 +9,7 @@ import org.teavm.jso.browser.Window;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.ArrayBufferView;
import org.teavm.jso.typedarrays.Float32Array;
import org.teavm.jso.typedarrays.Int16Array;
import org.teavm.jso.typedarrays.Int32Array;
import org.teavm.jso.typedarrays.Int8Array;
import org.teavm.jso.typedarrays.Uint8Array;
@ -57,6 +58,10 @@ public class TeaVMUtils {
return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
}
public static ArrayBufferView unwrapArrayBufferView(byte[] buf) {
return ((TeaVMArrayObject)(Object)buf).getData();
}
@JSBody(params = { "buf" }, script = "return $rt_createByteArray(buf.buffer)")
private static native JSObject wrapByteArray0(JSObject buf);
@ -80,6 +85,10 @@ public class TeaVMUtils {
return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
}
public static ArrayBufferView unwrapArrayBufferView(int[] buf) {
return ((TeaVMArrayObject)(Object)buf).getData();
}
@JSBody(params = { "buf" }, script = "return $rt_createIntArray(buf.buffer)")
private static native JSObject wrapIntArray0(JSObject buf);
@ -95,6 +104,10 @@ public class TeaVMUtils {
return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
}
public static ArrayBufferView unwrapArrayBufferView(float[] buf) {
return ((TeaVMArrayObject)(Object)buf).getData();
}
@JSBody(params = { "buf" }, script = "return $rt_createFloatArray(buf.buffer)")
private static native JSObject wrapFloatArray0(JSObject buf);
@ -102,6 +115,25 @@ public class TeaVMUtils {
return (float[])(Object)wrapFloatArray0(buf);
}
public static Int16Array unwrapShortArray(short[] buf) {
return Int16Array.create(((TeaVMArrayObject)(Object)buf).getData().getBuffer());
}
public static ArrayBuffer unwrapArrayBuffer(short[] buf) {
return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
}
public static ArrayBufferView unwrapArrayBufferView(short[] buf) {
return ((TeaVMArrayObject)(Object)buf).getData();
}
@JSBody(params = { "buf" }, script = "return $rt_createShortArray(buf.buffer)")
private static native JSObject wrapShortArray0(JSObject buf);
public static short[] wrapShortArray(Int16Array buf) {
return (short[])(Object)wrapShortArray0(buf);
}
@Async
public static native void sleepSetTimeout(int millis);

View File

@ -80,4 +80,7 @@ public abstract class JSEaglercraftXOptsRoot implements JSObject {
@JSBody(params = { "def" }, script = "return (typeof this.checkRelaysForUpdates === \"boolean\") ? this.checkRelaysForUpdates : def;")
public native boolean getCheckRelaysForUpdates(boolean defaultValue);
@JSBody(params = { "def" }, script = "return (typeof this.allowVoiceClient === \"boolean\") ? this.allowVoiceClient : def;")
public native boolean getAllowVoiceClient(boolean defaultValue);
}