mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 02:48:14 -05:00
Update #44 - WebAssembly GC support, fix more WebRTC bugs
This commit is contained in:
@ -0,0 +1,228 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import org.teavm.jso.webgl.WebGLBuffer;
|
||||
import org.teavm.jso.webgl.WebGLFramebuffer;
|
||||
import org.teavm.jso.webgl.WebGLProgram;
|
||||
import org.teavm.jso.webgl.WebGLRenderbuffer;
|
||||
import org.teavm.jso.webgl.WebGLShader;
|
||||
import org.teavm.jso.webgl.WebGLTexture;
|
||||
import org.teavm.jso.webgl.WebGLUniformLocation;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WebGLQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WebGLVertexArray;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
class OpenGLObjects {
|
||||
|
||||
static class BufferGL implements IBufferGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLBuffer ptr;
|
||||
final int hash;
|
||||
|
||||
BufferGL(WebGLBuffer ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteBuffers(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class BufferArrayGL implements IBufferArrayGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLVertexArray ptr;
|
||||
final int hash;
|
||||
|
||||
BufferArrayGL(WebGLVertexArray ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteVertexArrays(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TextureGL implements ITextureGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLTexture ptr;
|
||||
final int hash;
|
||||
|
||||
TextureGL(WebGLTexture ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteTextures(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ProgramGL implements IProgramGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLProgram ptr;
|
||||
final int hash;
|
||||
|
||||
ProgramGL(WebGLProgram ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteProgram(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class UniformGL implements IUniformGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLUniformLocation ptr;
|
||||
final int hash;
|
||||
|
||||
UniformGL(WebGLUniformLocation ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ShaderGL implements IShaderGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLShader ptr;
|
||||
final int hash;
|
||||
|
||||
ShaderGL(WebGLShader ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteShader(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FramebufferGL implements IFramebufferGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLFramebuffer ptr;
|
||||
final int hash;
|
||||
|
||||
FramebufferGL(WebGLFramebuffer ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteFramebuffer(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class RenderbufferGL implements IRenderbufferGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLRenderbuffer ptr;
|
||||
final int hash;
|
||||
|
||||
RenderbufferGL(WebGLRenderbuffer ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteRenderbuffer(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class QueryGL implements IQueryGL {
|
||||
|
||||
private static int hashGen = 0;
|
||||
final WebGLQuery ptr;
|
||||
final int hash;
|
||||
|
||||
QueryGL(WebGLQuery ptr) {
|
||||
this.ptr = ptr;
|
||||
this.hash = ++hashGen;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteQueries(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,308 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.browser.Storage;
|
||||
import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.canvas.CanvasRenderingContext2D;
|
||||
import org.teavm.jso.canvas.ImageData;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.dom.html.HTMLCanvasElement;
|
||||
import org.teavm.jso.dom.html.HTMLDocument;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
import org.teavm.jso.typedarrays.Uint8ClampedArray;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Base64;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.TeaVMUtils;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformApplication {
|
||||
|
||||
public static void openLink(String url) {
|
||||
if(url.indexOf(':') == -1) {
|
||||
url = "http://" + url;
|
||||
}
|
||||
URI parsedURL;
|
||||
try {
|
||||
parsedURL = new URI(url);
|
||||
}catch(URISyntaxException ex) {
|
||||
PlatformRuntime.logger.error("Refusing to open invalid URL: {}", url);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
PlatformRuntime.win.open(parsedURL.toString(), "_blank", "noopener,noreferrer");
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("Exception opening link!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void setClipboard(String text) {
|
||||
long start = PlatformRuntime.steadyTimeMillis();
|
||||
boolean b = false;
|
||||
try {
|
||||
b = setClipboard0(BetterJSStringConverter.stringToJS(text));
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("Exception setting clipboard data");
|
||||
}
|
||||
if(!b) {
|
||||
try {
|
||||
Window.prompt("Here is the text you're trying to copy:", text);
|
||||
}catch(Throwable t2) {
|
||||
}
|
||||
}
|
||||
if(PlatformRuntime.steadyTimeMillis() - start > 500l) {
|
||||
PlatformInput.unpressCTRL = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "setClipboard")
|
||||
private static native boolean setClipboard0(JSString str);
|
||||
|
||||
public static String getClipboard() {
|
||||
long start = PlatformRuntime.steadyTimeMillis();
|
||||
String ret = null;
|
||||
try {
|
||||
ret = BetterJSStringConverter.stringFromJS(getClipboard0());
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("Exception getting clipboard data");
|
||||
}
|
||||
if(ret == null) {
|
||||
try {
|
||||
ret = Window.prompt("Please enter the text to paste:");
|
||||
}catch(Throwable t2) {
|
||||
}
|
||||
}
|
||||
if(PlatformRuntime.steadyTimeMillis() - start > 500l) {
|
||||
PlatformInput.unpressCTRL = true;
|
||||
}
|
||||
return ret != null ? ret : "";
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "getClipboard")
|
||||
private static native JSString getClipboard0();
|
||||
|
||||
public static void setLocalStorage(String name, byte[] data) {
|
||||
setLocalStorage(name, data, true);
|
||||
}
|
||||
|
||||
public static void setLocalStorage(String name, byte[] data, boolean hooks) {
|
||||
IClientConfigAdapter adapter = PlatformRuntime.getClientConfigAdapter();
|
||||
String eagName = adapter.getLocalStorageNamespace() + "." + name;
|
||||
String b64 = data != null ? Base64.encodeBase64String(data) : null;
|
||||
try {
|
||||
Storage s = Window.current().getLocalStorage();
|
||||
if(s != null) {
|
||||
if(b64 != null) {
|
||||
s.setItem(eagName, b64);
|
||||
}else {
|
||||
s.removeItem(eagName);
|
||||
}
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
if(hooks) {
|
||||
adapter.getHooks().callLocalStorageSavedHook(name, b64);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] getLocalStorage(String name) {
|
||||
return getLocalStorage(name, true);
|
||||
}
|
||||
|
||||
public static byte[] getLocalStorage(String name, boolean hooks) {
|
||||
IClientConfigAdapter adapter = PlatformRuntime.getClientConfigAdapter();
|
||||
String eagName = adapter.getLocalStorageNamespace() + "." + name;
|
||||
byte[] hooked = null;
|
||||
if(hooks) {
|
||||
String hookedStr = adapter.getHooks().callLocalStorageLoadHook(eagName);
|
||||
if(hookedStr != null) {
|
||||
try {
|
||||
hooked = Base64.decodeBase64(hookedStr);
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("Invalid Base64 recieved from local storage hook!");
|
||||
hooked = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(hooked == null) {
|
||||
try {
|
||||
Storage s = Window.current().getLocalStorage();
|
||||
if(s != null) {
|
||||
String str = s.getItem(eagName);
|
||||
if(str != null) {
|
||||
return Base64.decodeBase64(str);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
return hooked;
|
||||
}
|
||||
}
|
||||
|
||||
public static final void displayFileChooser(String mime, String ext) {
|
||||
displayFileChooser0(BetterJSStringConverter.stringToJS(mime), BetterJSStringConverter.stringToJS(ext));
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "displayFileChooser")
|
||||
private static native void displayFileChooser0(JSString mime, JSString ext);
|
||||
|
||||
@Import(module = "platformApplication", name = "fileChooserHasResult")
|
||||
public static native boolean fileChooserHasResult();
|
||||
|
||||
public static FileChooserResult getFileChooserResult() {
|
||||
JSFileChooserResult jsResult = getFileChooserResult0();
|
||||
if(jsResult != null) {
|
||||
return new FileChooserResult(jsResult.getFileName(),
|
||||
WASMGCDirectArrayConverter.externU8ArrayToByteArray(new Uint8Array(jsResult.getFileData())));
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private interface JSFileChooserResult extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
String getFileName();
|
||||
|
||||
@JSProperty
|
||||
ArrayBuffer getFileData();
|
||||
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "getFileChooserResult")
|
||||
private static native JSFileChooserResult getFileChooserResult0();
|
||||
|
||||
@Import(module = "platformApplication", name = "clearFileChooserResult")
|
||||
public static native void clearFileChooserResult();
|
||||
|
||||
@Import(module = "platformApplication", name = "getFaviconURL")
|
||||
public static native JSString faviconURLTeaVM();
|
||||
|
||||
public static void showPopup(String msg) {
|
||||
Window.alert(msg);
|
||||
}
|
||||
|
||||
@JSBody(params = { "doc", "str" }, script = "doc.write(str);doc.close();")
|
||||
private static native void documentWrite(HTMLDocument doc, String str);
|
||||
|
||||
public static void openCreditsPopup(String text) {
|
||||
Window currentWin = PlatformRuntime.win;
|
||||
|
||||
int w = (int)(850 * PlatformInput.getDPI());
|
||||
int h = (int)(700 * PlatformInput.getDPI());
|
||||
|
||||
int x = (currentWin.getScreen().getWidth() - w) / 2;
|
||||
int y = (currentWin.getScreen().getHeight() - h) / 2;
|
||||
|
||||
Window newWin = Window.current().open("", "_blank", "top=" + y + ",left=" + x + ",width=" + w + ",height=" + h + ",menubar=0,status=0,titlebar=0,toolbar=0");
|
||||
if(newWin == null || TeaVMUtils.isNotTruthy(newWin)) {
|
||||
Window.alert("ERROR: Popup blocked!\n\nPlease make sure you have popups enabled for this site!");
|
||||
return;
|
||||
}
|
||||
|
||||
newWin.focus();
|
||||
documentWrite(newWin.getDocument(), "<!DOCTYPE html><html><head><meta charset=\"UTF-8\" />"
|
||||
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><title>EaglercraftX 1.8 Credits</title>"
|
||||
+ "<link type=\"image/png\" rel=\"shortcut icon\" href=\""
|
||||
+ BetterJSStringConverter.stringFromJS(PlatformApplication.faviconURLTeaVM()) + "\" />"
|
||||
+ "</head><body><pre style=\"font:15px Consolas,monospace;\">" + text + "</pre></body></html>");
|
||||
}
|
||||
|
||||
public static void downloadFileWithName(String str, byte[] dat) {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(dat);
|
||||
try {
|
||||
downloadFileWithNameTeaVM(BetterJSStringConverter.stringToJS(str), WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "downloadFileWithNameU8")
|
||||
public static native void downloadFileWithNameTeaVM(JSString str, Uint8Array dat);
|
||||
|
||||
@Import(module = "platformApplication", name = "downloadFileWithNameA")
|
||||
public static native void downloadFileWithNameTeaVM(JSString str, ArrayBuffer dat);
|
||||
|
||||
private static final DateFormat dateFormatSS = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
|
||||
|
||||
@JSBody(params = { }, script = "return { willReadFrequently: true };")
|
||||
static native JSObject youEagler();
|
||||
|
||||
public static String saveScreenshot() {
|
||||
PlatformOpenGL._wglBindFramebuffer(0x8D40, null);
|
||||
int w = PlatformInput.getWindowWidth();
|
||||
int h = PlatformInput.getWindowHeight();
|
||||
ByteBuffer buf = PlatformRuntime.allocateByteBuffer(w * h * 4);
|
||||
PlatformOpenGL._wglReadPixels(0, 0, w, h, 6408, 5121, buf);
|
||||
for(int i = 3, l = buf.remaining(); i < l; i += 4) {
|
||||
buf.put(i, (byte)0xFF);
|
||||
}
|
||||
String name = "screenshot_" + dateFormatSS.format(new Date()).toString() + ".png";
|
||||
HTMLCanvasElement copyCanvas = (HTMLCanvasElement) Window.current().getDocument().createElement("canvas");
|
||||
copyCanvas.setWidth(w);
|
||||
copyCanvas.setHeight(h);
|
||||
CanvasRenderingContext2D ctx = (CanvasRenderingContext2D) copyCanvas.getContext("2d", youEagler());
|
||||
ImageData imgData = ctx.createImageData(w, h);
|
||||
Uint8ClampedArray dest = imgData.getData();
|
||||
int ww = w * 4;
|
||||
for(int i = 0, j; i < h; ++i) {
|
||||
j = (h - i - 1) * ww;
|
||||
buf.limit(j + ww);
|
||||
buf.position(j);
|
||||
dest.set(WASMGCBufferAllocator.getUnsignedClampedByteBufferView(buf), i * ww);
|
||||
}
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
downloadScreenshotWithNameTeaVM(BetterJSStringConverter.stringToJS(name), copyCanvas);
|
||||
return name;
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "downloadScreenshot")
|
||||
private static native void downloadScreenshotWithNameTeaVM(JSString str, HTMLCanvasElement cvs);
|
||||
|
||||
@Import(module = "platformApplication", name = "showDebugConsole")
|
||||
public static native void showDebugConsole();
|
||||
|
||||
public static void addLogMessage(String text, boolean err) {
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "isShowingDebugConsole")
|
||||
public static native boolean isShowingDebugConsole();
|
||||
|
||||
@JSBody(params = { "str" }, script = "window.minecraftServer = str;")
|
||||
public static native void setMCServerWindowGlobal(String str);
|
||||
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
import org.teavm.jso.typedarrays.Uint8ClampedArray;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.ClientMain;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.EPKLoader;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformAssets {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("PlatformAssets");
|
||||
|
||||
private static final byte[] MISSING_FILE = new byte[0];
|
||||
|
||||
static Map<String,byte[]> assets = new HashMap<>();
|
||||
|
||||
public static boolean getResourceExists(String path) {
|
||||
if(path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
byte[] ret = assets.get(path);
|
||||
if(ret != null && ret != MISSING_FILE) {
|
||||
return true;
|
||||
}else {
|
||||
if(path.startsWith("assets/minecraft/lang/") && !path.endsWith(".mcmeta")) {
|
||||
byte[] file = PlatformRuntime.downloadRemoteURIByteArray(
|
||||
ClientMain.configLocalesFolder + "/" + path.substring(22));
|
||||
if(file != null) {
|
||||
assets.put(path, file);
|
||||
return true;
|
||||
}else {
|
||||
assets.put(path, MISSING_FILE);
|
||||
return false;
|
||||
}
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] getResourceBytes(String path) {
|
||||
if(path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
byte[] data = assets.get(path);
|
||||
if(data == null && path.startsWith("assets/minecraft/lang/") && !path.endsWith(".mcmeta")) {
|
||||
byte[] file = PlatformRuntime.downloadRemoteURIByteArray(
|
||||
ClientMain.configLocalesFolder + "/" + path.substring(22));
|
||||
if(file != null) {
|
||||
assets.put(path, file);
|
||||
return data;
|
||||
}else {
|
||||
assets.put(path, MISSING_FILE);
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
return data == MISSING_FILE ? null : data;
|
||||
}
|
||||
}
|
||||
|
||||
static void readAssetsTeaVM() {
|
||||
if(!assets.isEmpty()) {
|
||||
assets = new HashMap<>();
|
||||
}
|
||||
|
||||
int epkCount = getEPKFileCount();
|
||||
|
||||
logger.info("Reading {} EPK files", epkCount);
|
||||
|
||||
for(int i = 0; i < epkCount; ++i) {
|
||||
JSEPKFileEntry etr = getEPKFileData(i);
|
||||
String name = etr.getName();
|
||||
String path = etr.getPath();
|
||||
Uint8Array data = etr.getData();
|
||||
int dataLen = data.getLength();
|
||||
|
||||
logger.info("Reading: \"{}\" @ {}", name, path.startsWith("/") ? path : ("/" + path));
|
||||
|
||||
ByteBuffer buf = PlatformRuntime.allocateByteBuffer(dataLen);
|
||||
try {
|
||||
WASMGCBufferAllocator.getUnsignedByteBufferView(buf).set(data);
|
||||
EPKLoader.loadEPK(buf, path, assets);
|
||||
}catch(IOException e) {
|
||||
logger.error("Failed to load the EPK file!");
|
||||
logger.error(e);
|
||||
throw new RuntimeInitializationFailureException("Failed to read EPK file \"" + name + "\"!");
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Loaded {} assets from EPK(s)", assets.size());
|
||||
}
|
||||
|
||||
private interface JSEPKFileEntry extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
String getName();
|
||||
|
||||
@JSProperty
|
||||
String getPath();
|
||||
|
||||
@JSProperty
|
||||
Uint8Array getData();
|
||||
|
||||
}
|
||||
|
||||
@Import(module = "platformAssets", name = "getEPKFileData")
|
||||
private static native JSEPKFileEntry getEPKFileData(int idx);
|
||||
|
||||
@Import(module = "platformAssets", name = "getEPKFileCount")
|
||||
private static native int getEPKFileCount();
|
||||
|
||||
public static ImageData loadImageFile(InputStream data) {
|
||||
return loadImageFile(data, "image/png");
|
||||
}
|
||||
|
||||
public static ImageData loadImageFile(InputStream data, String mime) {
|
||||
byte[] b = EaglerInputStream.inputStreamToBytesQuiet(data);
|
||||
if(b != null) {
|
||||
return loadImageFile(b, mime);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static ImageData loadImageFile(byte[] data) {
|
||||
return loadImageFile(data, "image/png");
|
||||
}
|
||||
|
||||
public static ImageData loadImageFile(byte[] data, String mime) {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(data);
|
||||
JSImageLoadResult asyncResult;
|
||||
try {
|
||||
asyncResult = loadImageFile0(WASMGCBufferAllocator.getUnsignedByteBufferView(buf), BetterJSStringConverter.stringToJS(mime));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
|
||||
if(asyncResult == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int w = asyncResult.getWidth();
|
||||
int h = asyncResult.getHeight();
|
||||
int len = w * h;
|
||||
|
||||
ByteBuffer dataDest = PlatformRuntime.allocateByteBuffer(len << 2);
|
||||
try {
|
||||
loadImageFile1(asyncResult, WASMGCBufferAllocator.getUnsignedClampedByteBufferView(dataDest));
|
||||
int[] pixelsArray = new int[len];
|
||||
copyPixelArrayFast(pixelsArray, WASMGCBufferAllocator.getByteBufferAddress(dataDest), len);
|
||||
return new ImageData(w, h, pixelsArray, true);
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(dataDest);
|
||||
}
|
||||
}
|
||||
|
||||
private interface JSImageLoadResult extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getWidth();
|
||||
|
||||
@JSProperty
|
||||
int getHeight();
|
||||
|
||||
}
|
||||
|
||||
@Import(module = "platformAssets", name = "loadImageFile0")
|
||||
private static native JSImageLoadResult loadImageFile0(Uint8Array bufferData, JSString mime);
|
||||
|
||||
@Import(module = "platformAssets", name = "loadImageFile1")
|
||||
private static native void loadImageFile1(JSImageLoadResult imageLoadResult, Uint8ClampedArray dataDest);
|
||||
|
||||
@Unmanaged
|
||||
private static void copyPixelArrayFast(int[] pixelsArray, Address addr, int count) {
|
||||
Address addrEnd = addr.add(count << 2);
|
||||
int dstOffset = 0;
|
||||
while(addr.isLessThan(addrEnd)) {
|
||||
pixelsArray[dstOffset] = addr.getInt();
|
||||
++dstOffset;
|
||||
addr = addr.add(4);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,530 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.Float32Array;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
import org.teavm.jso.webaudio.AudioBuffer;
|
||||
import org.teavm.jso.webaudio.AudioBufferSourceNode;
|
||||
import org.teavm.jso.webaudio.AudioContext;
|
||||
import org.teavm.jso.webaudio.AudioListener;
|
||||
import org.teavm.jso.webaudio.GainNode;
|
||||
import org.teavm.jso.webaudio.MediaStream;
|
||||
import org.teavm.jso.webaudio.MediaStreamAudioDestinationNode;
|
||||
import org.teavm.jso.webaudio.PannerNode;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.JOrbisAudioBufferDecoder;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformAudio {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("BrowserAudio");
|
||||
|
||||
static AudioContext audioctx = null;
|
||||
static MediaStreamAudioDestinationNode recDestNode = null;
|
||||
static MediaStream recDestMediaStream = null;
|
||||
static AudioBuffer silence = null;
|
||||
static AudioBufferSourceNode recDestSilenceNode = null;
|
||||
static GainNode micRecGain = null;
|
||||
static GainNode gameRecGain = null;
|
||||
private static final Map<String, BrowserAudioResource> soundCache = new HashMap<>();
|
||||
private static final List<BrowserAudioHandle> activeSounds = new LinkedList<>();
|
||||
|
||||
private static long cacheFreeTimer = 0l;
|
||||
private static long activeFreeTimer = 0l;
|
||||
private static boolean oggSupport = false;
|
||||
|
||||
static void initialize() {
|
||||
oggSupport = false;
|
||||
|
||||
audioctx = getContext();
|
||||
if(audioctx == null) {
|
||||
logger.error("Could not initialize audio context!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(((WASMGCClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isUseJOrbisAudioDecoderTeaVM()) {
|
||||
logger.info("Note: Using embedded JOrbis OGG decoder");
|
||||
}else {
|
||||
byte[] fileData = EagRuntime.getRequiredResourceBytes("/assets/eagler/audioctx_test_ogg.dat");
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(fileData);
|
||||
try {
|
||||
AudioBuffer audioBuffer = decodeAudioBrowserAsync(WASMGCBufferAllocator.getUnsignedByteBufferView(buf),
|
||||
BetterJSStringConverter.stringToJS("audioctx_test_ogg.dat"));
|
||||
if(audioBuffer != null && audioBuffer.getLength() > 0) {
|
||||
oggSupport = true;
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
if(!oggSupport) {
|
||||
logger.error("OGG file support detected as false! Using embedded JOrbis OGG decoder");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformAudio", name = "getContext")
|
||||
private static native AudioContext getContext();
|
||||
|
||||
protected static class BrowserAudioResource implements IAudioResource {
|
||||
|
||||
protected AudioBuffer buffer;
|
||||
protected long cacheHit = 0l;
|
||||
|
||||
protected BrowserAudioResource(AudioBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected interface JSBrowserAudioHandleCB extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
boolean getIsEnded();
|
||||
|
||||
@JSProperty
|
||||
void setIsEnded(boolean b);
|
||||
|
||||
}
|
||||
|
||||
@JSBody(script = "return { isEnded: false };")
|
||||
protected static native JSBrowserAudioHandleCB createHandleCBInstance();
|
||||
|
||||
protected static class BrowserAudioHandle implements IAudioHandle {
|
||||
|
||||
protected final BrowserAudioResource resource;
|
||||
protected AudioBufferSourceNode source;
|
||||
protected final PannerNode panner;
|
||||
protected final GainNode gain;
|
||||
protected float pitch;
|
||||
protected boolean repeat;
|
||||
protected boolean isPaused = false;
|
||||
protected boolean isDisposed = false;
|
||||
protected JSBrowserAudioHandleCB isEnded;
|
||||
|
||||
protected BrowserAudioHandle(BrowserAudioResource resource, AudioBufferSourceNode source, PannerNode panner,
|
||||
GainNode gain, float pitch, boolean repeat) {
|
||||
this.resource = resource;
|
||||
this.source = source;
|
||||
this.panner = panner;
|
||||
this.gain = gain;
|
||||
this.pitch = pitch;
|
||||
this.repeat = repeat;
|
||||
this.isEnded = createHandleCBInstance();
|
||||
registerIsEndedHandler(source, isEnded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause(boolean setPaused) {
|
||||
if(setPaused) {
|
||||
if(!isPaused) {
|
||||
isPaused = true;
|
||||
source.getPlaybackRate().setValue(0.0f);
|
||||
}
|
||||
}else {
|
||||
if(isPaused) {
|
||||
isPaused = false;
|
||||
source.getPlaybackRate().setValue(pitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repeat(boolean en) {
|
||||
repeat = en;
|
||||
if(!isEnded.getIsEnded()) {
|
||||
source.setLoop(en);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restart() {
|
||||
if(isEnded.getIsEnded()) {
|
||||
isEnded.setIsEnded(false);
|
||||
registerIsEndedHandler(source, isEnded);
|
||||
isPaused = false;
|
||||
AudioBufferSourceNode src = audioctx.createBufferSource();
|
||||
resource.cacheHit = PlatformRuntime.steadyTimeMillis();
|
||||
src.setBuffer(resource.buffer);
|
||||
src.getPlaybackRate().setValue(pitch);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(float x, float y, float z) {
|
||||
if(panner != null) {
|
||||
panner.setPosition(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pitch(float f) {
|
||||
pitch = f;
|
||||
if(!isPaused) {
|
||||
source.getPlaybackRate().setValue(pitch);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gain(float f) {
|
||||
if(panner != null) {
|
||||
float v1 = f * 16.0f;
|
||||
if(v1 < 16.0f) v1 = 16.0f;
|
||||
panner.setMaxDistance(v1);
|
||||
}
|
||||
float v2 = f;
|
||||
if(v2 > 1.0f) v2 = 1.0f;
|
||||
gain.getGain().setValue(v2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
if(!isEnded.getIsEnded()) {
|
||||
isEnded.setIsEnded(true);
|
||||
releaseIsEndedHandler(source, isEnded);
|
||||
source.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFree() {
|
||||
return isEnded.getIsEnded();
|
||||
}
|
||||
|
||||
private void dispose() {
|
||||
if(!isDisposed) {
|
||||
isDisposed = true;
|
||||
gain.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformAudio", name = "registerIsEndedHandler")
|
||||
protected static native void registerIsEndedHandler(AudioBufferSourceNode source, JSBrowserAudioHandleCB isEnded);
|
||||
|
||||
@Import(module = "platformAudio", name = "releaseIsEndedHandler")
|
||||
protected static native void releaseIsEndedHandler(AudioBufferSourceNode source, JSBrowserAudioHandleCB isEnded);
|
||||
|
||||
public static IAudioResource loadAudioData(String filename, boolean holdInCache) {
|
||||
BrowserAudioResource buffer = soundCache.get(filename);
|
||||
if(buffer == null) {
|
||||
byte[] file = PlatformAssets.getResourceBytes(filename);
|
||||
if(file == null) return null;
|
||||
buffer = new BrowserAudioResource(decodeAudioData(file, filename));
|
||||
if(holdInCache) {
|
||||
soundCache.put(filename, buffer);
|
||||
}
|
||||
}
|
||||
if(buffer.buffer != null) {
|
||||
buffer.cacheHit = PlatformRuntime.steadyTimeMillis();
|
||||
return buffer;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IAudioResource loadAudioDataNew(String filename, boolean holdInCache, IAudioCacheLoader loader) {
|
||||
BrowserAudioResource buffer = soundCache.get(filename);
|
||||
if(buffer == null) {
|
||||
byte[] file = loader.loadFile(filename);
|
||||
if(file == null) return null;
|
||||
buffer = new BrowserAudioResource(decodeAudioData(file, filename));
|
||||
if(holdInCache) {
|
||||
soundCache.put(filename, buffer);
|
||||
}
|
||||
}
|
||||
if(buffer.buffer != null) {
|
||||
buffer.cacheHit = PlatformRuntime.steadyTimeMillis();
|
||||
return buffer;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static AudioBuffer decodeAudioData(byte[] data, String errorFileName) {
|
||||
if(data == null) {
|
||||
return null;
|
||||
}
|
||||
if(oggSupport) {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(data);
|
||||
try {
|
||||
return decodeAudioBrowserAsync(WASMGCBufferAllocator.getUnsignedByteBufferView(buf),
|
||||
BetterJSStringConverter.stringToJS(errorFileName));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}else {
|
||||
if (data.length > 4 && data[0] == (byte) 0x4F && data[1] == (byte) 0x67 && data[2] == (byte) 0x67
|
||||
&& data[3] == (byte) 0x53) {
|
||||
return JOrbisAudioBufferDecoder.decodeAudioJOrbis(data, errorFileName);
|
||||
}else {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(data);
|
||||
try {
|
||||
return decodeAudioBrowserAsync(WASMGCBufferAllocator.getUnsignedByteBufferView(buf),
|
||||
BetterJSStringConverter.stringToJS(errorFileName));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformAudio", name = "decodeAudioBrowser")
|
||||
public static native AudioBuffer decodeAudioBrowserAsync(Uint8Array array, JSString errorFileName);
|
||||
|
||||
public static AudioBuffer decodeAudioBufferPCMBrowser(Float32Array array, int ch, int len, int rate) {
|
||||
AudioBuffer buffer = audioctx.createBuffer(ch, len, rate);
|
||||
for(int i = 0; i < ch; ++i) {
|
||||
buffer.copyToChannel(new Float32Array(array.getBuffer(), array.getByteOffset() + ((i * len) << 2), len), i);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static void clearAudioCache() {
|
||||
long millis = PlatformRuntime.steadyTimeMillis();
|
||||
if(millis - cacheFreeTimer > 30000l) {
|
||||
cacheFreeTimer = millis;
|
||||
Iterator<BrowserAudioResource> itr = soundCache.values().iterator();
|
||||
while(itr.hasNext()) {
|
||||
if(millis - itr.next().cacheHit > 600000l) { // 10 minutes
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(millis - activeFreeTimer > 700l) {
|
||||
activeFreeTimer = millis;
|
||||
Iterator<BrowserAudioHandle> itr = activeSounds.iterator();
|
||||
while(itr.hasNext()) {
|
||||
BrowserAudioHandle h = itr.next();
|
||||
if(h.shouldFree()) {
|
||||
itr.remove();
|
||||
h.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void flushAudioCache() {
|
||||
soundCache.clear();
|
||||
Iterator<BrowserAudioHandle> itr = activeSounds.iterator();
|
||||
while(itr.hasNext()) {
|
||||
itr.next().dispose();
|
||||
}
|
||||
activeSounds.clear();
|
||||
}
|
||||
|
||||
public static boolean available() {
|
||||
return audioctx != null;
|
||||
}
|
||||
|
||||
@JSBody(params = { "node" }, script = "node.distanceModel = \"linear\";")
|
||||
static native void setDistanceModelLinearFast(PannerNode node) ;
|
||||
|
||||
@JSBody(params = { "node" }, script = "node.panningModel = \"HRTF\";")
|
||||
static native void setPanningModelHRTFFast(PannerNode node) ;
|
||||
|
||||
public static IAudioHandle beginPlayback(IAudioResource track, float x, float y, float z,
|
||||
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);
|
||||
float v1 = volume * 16.0f;
|
||||
if(v1 < 16.0f) v1 = 16.0f;
|
||||
panner.setMaxDistance(v1);
|
||||
panner.setRolloffFactor(1.0f);
|
||||
setDistanceModelLinearFast(panner);
|
||||
setPanningModelHRTFFast(panner);
|
||||
panner.setConeInnerAngle(360.0f);
|
||||
panner.setConeOuterAngle(0.0f);
|
||||
panner.setConeOuterGain(0.0f);
|
||||
panner.setOrientation(0.0f, 1.0f, 0.0f);
|
||||
|
||||
GainNode gain = audioctx.createGain();
|
||||
float v2 = volume;
|
||||
if(v2 > 1.0f) v2 = 1.0f;
|
||||
gain.getGain().setValue(v2);
|
||||
|
||||
src.connect(panner);
|
||||
panner.connect(gain);
|
||||
gain.connect(audioctx.getDestination());
|
||||
if(gameRecGain != null) {
|
||||
gain.connect(gameRecGain);
|
||||
}
|
||||
|
||||
src.start();
|
||||
|
||||
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, 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;
|
||||
if(v2 > 1.0f) v2 = 1.0f;
|
||||
gain.getGain().setValue(v2);
|
||||
|
||||
src.connect(gain);
|
||||
gain.connect(audioctx.getDestination());
|
||||
if(gameRecGain != null) {
|
||||
gain.connect(gameRecGain);
|
||||
}
|
||||
|
||||
src.start();
|
||||
|
||||
BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, null, gain, pitch, repeat);
|
||||
activeSounds.add(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void setListener(float x, float y, float z, float pitchDegrees, float yawDegrees) {
|
||||
float var2 = MathHelper.cos(-yawDegrees * 0.017453292F);
|
||||
float var3 = MathHelper.sin(-yawDegrees * 0.017453292F);
|
||||
float var4 = -MathHelper.cos(pitchDegrees * 0.017453292F);
|
||||
float var5 = MathHelper.sin(pitchDegrees * 0.017453292F);
|
||||
AudioListener l = audioctx.getListener();
|
||||
l.setPosition(x, y, z);
|
||||
l.setOrientation(-var3 * var4, -var5, -var2 * var4, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
static MediaStream initRecordingStream(float gameVol, float micVol) {
|
||||
if(recDestMediaStream != null) {
|
||||
return recDestMediaStream;
|
||||
}
|
||||
try {
|
||||
if(silence == null) {
|
||||
silence = audioctx.createBuffer(1, 1, 48000);
|
||||
silence.copyToChannel(new Float32Array(1), 0);
|
||||
}
|
||||
recDestNode = audioctx.createMediaStreamDestination();
|
||||
recDestSilenceNode = audioctx.createBufferSource();
|
||||
recDestSilenceNode.setBuffer(silence);
|
||||
recDestSilenceNode.setLoop(true);
|
||||
recDestSilenceNode.start();
|
||||
recDestSilenceNode.connect(recDestNode);
|
||||
if(micVol > 0.0f) {
|
||||
MediaStream mic = PlatformScreenRecord.getMic();
|
||||
if (mic != null) {
|
||||
micRecGain = audioctx.createGain();
|
||||
micRecGain.getGain().setValue(micVol);
|
||||
audioctx.createMediaStreamSource(mic).connect(micRecGain);
|
||||
micRecGain.connect(recDestNode);
|
||||
}
|
||||
}
|
||||
gameRecGain = audioctx.createGain();
|
||||
gameRecGain.getGain().setValue(gameVol);
|
||||
for(BrowserAudioHandle handle : activeSounds) {
|
||||
if(handle.panner != null) {
|
||||
handle.panner.connect(gameRecGain);
|
||||
}else {
|
||||
handle.gain.connect(gameRecGain);
|
||||
}
|
||||
}
|
||||
PlatformVoiceClient.addRecordingDest(gameRecGain);
|
||||
gameRecGain.connect(recDestNode);
|
||||
recDestMediaStream = recDestNode.getStream();
|
||||
return recDestMediaStream;
|
||||
}catch(Throwable t) {
|
||||
destroyRecordingStream();
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
static void destroyRecordingStream() {
|
||||
if(recDestSilenceNode != null) {
|
||||
try {
|
||||
recDestSilenceNode.disconnect();
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
recDestSilenceNode = null;
|
||||
}
|
||||
if(micRecGain != null) {
|
||||
try {
|
||||
micRecGain.disconnect();
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
micRecGain = null;
|
||||
}
|
||||
if(gameRecGain != null) {
|
||||
try {
|
||||
gameRecGain.disconnect();
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
for(BrowserAudioHandle handle : activeSounds) {
|
||||
try {
|
||||
handle.gain.disconnect(gameRecGain);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
}
|
||||
PlatformVoiceClient.removeRecordingDest(gameRecGain);
|
||||
gameRecGain = null;
|
||||
}
|
||||
recDestNode = null;
|
||||
recDestMediaStream = null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.EaglerFileSystemException;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.IndexedDBFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformFilesystem {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformFilesystem");
|
||||
|
||||
public static IEaglerFilesystem initializePersist(String dbName) {
|
||||
try {
|
||||
return IndexedDBFilesystem.createFilesystem(dbName);
|
||||
}catch(Throwable t) {
|
||||
logger.error("Could not open IndexedDB filesystem: {}", dbName);
|
||||
logger.error(t);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilesystemDatabaseLockedException extends EaglerFileSystemException {
|
||||
public FilesystemDatabaseLockedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilesystemDatabaseInitializationException extends EaglerFileSystemException {
|
||||
public FilesystemDatabaseInitializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,72 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCWebSocketClient;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformNetworking {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformNetworking");
|
||||
|
||||
public static IWebSocketClient openWebSocket(String socketURI) {
|
||||
IWebSocketClient client = openWebSocketImpl(socketURI);
|
||||
if(client == null) {
|
||||
logger.error("Could not open WebSocket to \"{}\"!", socketURI);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
public static IWebSocketClient openWebSocketUnsafe(String socketURI) {
|
||||
IWebSocketClient client = openWebSocketImpl(socketURI);
|
||||
if(client == null) {
|
||||
throw new IllegalArgumentException("Could not open WebSocket to \"" + socketURI + "\"!");
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
public static IWebSocketClient openWebSocketImpl(String socketURI) {
|
||||
WASMGCWebSocketClient.JSWebSocketClientHandle handle = createWebSocketHandle(
|
||||
BetterJSStringConverter.stringToJS(socketURI));
|
||||
if(handle != null) {
|
||||
return new WASMGCWebSocketClient(handle, socketURI);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformNetworking", name = "createWebSocketHandle")
|
||||
private static native WASMGCWebSocketClient.JSWebSocketClientHandle createWebSocketHandle(JSString socketURI);
|
||||
|
||||
}
|
@ -0,0 +1,850 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.core.JSArray;
|
||||
import org.teavm.jso.core.JSNumber;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.ArrayBufferView;
|
||||
import org.teavm.jso.typedarrays.Float32Array;
|
||||
import org.teavm.jso.webgl.WebGLBuffer;
|
||||
import org.teavm.jso.webgl.WebGLFramebuffer;
|
||||
import org.teavm.jso.webgl.WebGLProgram;
|
||||
import org.teavm.jso.webgl.WebGLRenderbuffer;
|
||||
import org.teavm.jso.webgl.WebGLShader;
|
||||
import org.teavm.jso.webgl.WebGLTexture;
|
||||
import org.teavm.jso.webgl.WebGLUniformLocation;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WebGLBackBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WebGLQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WebGLVertexArray;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformOpenGL {
|
||||
|
||||
static int glesVers = -1;
|
||||
|
||||
static final int VAO_IMPL_NONE = -1;
|
||||
static final int VAO_IMPL_CORE = 0;
|
||||
static final int VAO_IMPL_OES = 1;
|
||||
static int vertexArrayImpl = VAO_IMPL_NONE;
|
||||
|
||||
static final int INSTANCE_IMPL_NONE = -1;
|
||||
static final int INSTANCE_IMPL_CORE = 0;
|
||||
static final int INSTANCE_IMPL_ANGLE = 1;
|
||||
static int instancingImpl = INSTANCE_IMPL_NONE;
|
||||
|
||||
static final int CAP_A_BIT_EXT_GPU_SHADER5 = 1;
|
||||
static final int CAP_A_BIT_OES_GPU_SHADER5 = 2;
|
||||
static final int CAP_A_BIT_FBO_RENDER_MIPMAP = 4;
|
||||
static final int CAP_A_BIT_TEXTURE_LOD_CAPABLE = 8;
|
||||
static final int CAP_A_BIT_NPOT_CAPABLE = 16;
|
||||
static final int CAP_A_BIT_HDR_FBO16F = 32;
|
||||
static final int CAP_A_BIT_HDR_FBO32F = 64;
|
||||
static final int CAP_A_BIT_ANISOTROPIC = 128;
|
||||
static int capABits = 0;
|
||||
|
||||
static final int CAP_B_BIT_HDR_LINEAR16F = 1;
|
||||
static final int CAP_B_BIT_HDR_LINEAR32F = 2;
|
||||
static int capBBits = 0;
|
||||
|
||||
static void initContext() {
|
||||
glesVers = getCapBits(0);
|
||||
vertexArrayImpl = getCapBits(1);
|
||||
instancingImpl = getCapBits(2);
|
||||
capABits = getCapBits(3);
|
||||
capBBits = getCapBits(4);
|
||||
_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "getCapBits")
|
||||
static native int getCapBits(int idx);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glEnable")
|
||||
public static native void _wglEnable(int glEnum);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDisable")
|
||||
public static native void _wglDisable(int glEnum);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glClearColor")
|
||||
public static native void _wglClearColor(float r, float g, float b, float a);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glClearDepth")
|
||||
public static native void _wglClearDepth(float f);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glClear")
|
||||
public static native void _wglClear(int bits);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDepthFunc")
|
||||
public static native void _wglDepthFunc(int glEnum);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDepthMask")
|
||||
public static native void _wglDepthMask(boolean mask);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCullFace")
|
||||
public static native void _wglCullFace(int glEnum);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glViewport")
|
||||
public static native void _wglViewport(int x, int y, int w, int h);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBlendFunc")
|
||||
public static native void _wglBlendFunc(int src, int dst);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBlendFuncSeparate")
|
||||
public static native void _wglBlendFuncSeparate(int srcColor, int dstColor, int srcAlpha, int dstAlpha);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBlendEquation")
|
||||
public static native void _wglBlendEquation(int glEnum);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBlendColor")
|
||||
public static native void _wglBlendColor(float r, float g, float b, float a);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glColorMask")
|
||||
public static native void _wglColorMask(boolean r, boolean g, boolean b, boolean a);
|
||||
|
||||
private static final JSArray<JSNumber> drawBuffers = new JSArray<>();
|
||||
|
||||
@JSBody(params = { "arr", "idx", "num" }, script = "arr[idx] = num;")
|
||||
private static native void setArrayInt(JSArray<JSNumber> arr, int idx, int num);
|
||||
|
||||
public static final void _wglDrawBuffers(int buffer) {
|
||||
if(glesVers == 200) {
|
||||
if(buffer != 0x8CE0) { // GL_COLOR_ATTACHMENT0
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}else {
|
||||
drawBuffers.setLength(1);
|
||||
setArrayInt(drawBuffers, 0, buffer);
|
||||
_wglDrawBuffersN(drawBuffers);
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglDrawBuffers(int[] buffers) {
|
||||
if(glesVers == 200) {
|
||||
if(buffers.length != 1 || buffers[0] != 0x8CE0) { // GL_COLOR_ATTACHMENT0
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}else {
|
||||
int cnt = buffers.length;
|
||||
drawBuffers.setLength(cnt);
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
setArrayInt(drawBuffers, i, buffers[i]);
|
||||
}
|
||||
_wglDrawBuffersN(drawBuffers);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDrawBuffers")
|
||||
private static native void _wglDrawBuffersN(JSArray<JSNumber> buffers);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glReadBuffer")
|
||||
public static native void _wglReadBuffer(int glEnum);
|
||||
|
||||
public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer buffer) {
|
||||
_wglReadPixelsN(x, y, width, height, format, type, WASMGCBufferAllocator.getUnsignedByteBufferView(buffer));
|
||||
}
|
||||
|
||||
public static final void _wglReadPixels_u16(int x, int y, int width, int height, int format, int type, ByteBuffer buffer) {
|
||||
_wglReadPixelsN(x, y, width, height, format, type, WASMGCBufferAllocator.getUnsignedShortBufferView(buffer));
|
||||
}
|
||||
|
||||
public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, IntBuffer buffer) {
|
||||
_wglReadPixelsN(x, y, width, height, format, type, WASMGCBufferAllocator.getIntBufferView(buffer));
|
||||
}
|
||||
|
||||
public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, FloatBuffer buffer) {
|
||||
_wglReadPixelsN(x, y, width, height, format, type, WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glReadPixels")
|
||||
static native void _wglReadPixelsN(int x, int y, int width, int height, int format, int type, ArrayBufferView array);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glPolygonOffset")
|
||||
public static native void _wglPolygonOffset(float f1, float f2);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glLineWidth")
|
||||
public static native void _wglLineWidth(float width);
|
||||
|
||||
public static final IBufferGL _wglGenBuffers() {
|
||||
return new OpenGLObjects.BufferGL(_wglGenBuffersN());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGenBuffers")
|
||||
static native WebGLBuffer _wglGenBuffersN();
|
||||
|
||||
public static final ITextureGL _wglGenTextures() {
|
||||
return new OpenGLObjects.TextureGL(_wglGenTexturesN());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGenTextures")
|
||||
static native WebGLTexture _wglGenTexturesN();
|
||||
|
||||
public static final IBufferArrayGL _wglGenVertexArrays() {
|
||||
return new OpenGLObjects.BufferArrayGL(_wglGenVertexArraysN());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGenVertexArrays")
|
||||
public static native WebGLVertexArray _wglGenVertexArraysN();
|
||||
|
||||
public static final IProgramGL _wglCreateProgram() {
|
||||
return new OpenGLObjects.ProgramGL(_wglCreateProgramN());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCreateProgram")
|
||||
static native WebGLProgram _wglCreateProgramN();
|
||||
|
||||
public static final IShaderGL _wglCreateShader(int type) {
|
||||
return new OpenGLObjects.ShaderGL(_wglCreateShaderN(type));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCreateShader")
|
||||
static native WebGLShader _wglCreateShaderN(int type);
|
||||
|
||||
public static final IFramebufferGL _wglCreateFramebuffer() {
|
||||
return new OpenGLObjects.FramebufferGL(_wglCreateFramebufferN());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCreateFramebuffer")
|
||||
static native WebGLFramebuffer _wglCreateFramebufferN();
|
||||
|
||||
public static final IRenderbufferGL _wglCreateRenderbuffer() {
|
||||
return new OpenGLObjects.RenderbufferGL(_wglCreateRenderbufferN());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCreateRenderbuffer")
|
||||
static native WebGLRenderbuffer _wglCreateRenderbufferN();
|
||||
|
||||
public static final IQueryGL _wglGenQueries() {
|
||||
return new OpenGLObjects.QueryGL(_wglGenQueriesN());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGenQueries")
|
||||
static native WebGLQuery _wglGenQueriesN();
|
||||
|
||||
public static final void _wglDeleteBuffers(IBufferGL objId) {
|
||||
_wglDeleteBuffersN(((OpenGLObjects.BufferGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteBuffers")
|
||||
static native void _wglDeleteBuffersN(WebGLBuffer objId);
|
||||
|
||||
public static final void _wglDeleteTextures(ITextureGL objId) {
|
||||
_wglDeleteTexturesN(((OpenGLObjects.TextureGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteTextures")
|
||||
static native void _wglDeleteTexturesN(WebGLTexture objId);
|
||||
|
||||
public static final void _wglDeleteVertexArrays(IBufferArrayGL objId) {
|
||||
_wglDeleteVertexArraysN(((OpenGLObjects.BufferArrayGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteVertexArrays")
|
||||
static native void _wglDeleteVertexArraysN(WebGLVertexArray objId);
|
||||
|
||||
public static final void _wglDeleteProgram(IProgramGL objId) {
|
||||
_wglDeleteProgramN(((OpenGLObjects.ProgramGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteProgram")
|
||||
static native void _wglDeleteProgramN(WebGLProgram objId);
|
||||
|
||||
public static final void _wglDeleteShader(IShaderGL objId) {
|
||||
_wglDeleteShaderN(((OpenGLObjects.ShaderGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteShader")
|
||||
static native void _wglDeleteShaderN(WebGLShader objId);
|
||||
|
||||
public static final void _wglDeleteFramebuffer(IFramebufferGL objId) {
|
||||
_wglDeleteFramebufferN(((OpenGLObjects.FramebufferGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteFramebuffer")
|
||||
static native void _wglDeleteFramebufferN(WebGLFramebuffer objId);
|
||||
|
||||
public static final void _wglDeleteRenderbuffer(IRenderbufferGL objId) {
|
||||
_wglDeleteRenderbufferN(((OpenGLObjects.RenderbufferGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteRenderbuffer")
|
||||
static native void _wglDeleteRenderbufferN(WebGLRenderbuffer objId);
|
||||
|
||||
public static final void _wglDeleteQueries(IQueryGL objId) {
|
||||
_wglDeleteQueriesN(((OpenGLObjects.QueryGL)objId).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDeleteQueries")
|
||||
static native void _wglDeleteQueriesN(WebGLQuery objId);
|
||||
|
||||
public static final void _wglBindBuffer(int target, IBufferGL bufObj) {
|
||||
_wglBindBufferN(target, bufObj != null ? ((OpenGLObjects.BufferGL)bufObj).ptr : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBindBuffer")
|
||||
static native void _wglBindBufferN(int target, WebGLBuffer bufObj);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBufferData")
|
||||
public static native void _wglBufferData(int target, int size, int usage);
|
||||
|
||||
public static final void _wglBufferData(int target, ByteBuffer buffer, int usage) {
|
||||
_wglBufferDataN(target, WASMGCBufferAllocator.getUnsignedByteBufferView(buffer), usage);
|
||||
}
|
||||
|
||||
public static final void _wglBufferData(int target, IntBuffer buffer, int usage) {
|
||||
_wglBufferDataN(target, WASMGCBufferAllocator.getIntBufferView(buffer), usage);
|
||||
}
|
||||
|
||||
public static final void _wglBufferData(int target, FloatBuffer buffer, int usage) {
|
||||
_wglBufferDataN(target, WASMGCBufferAllocator.getFloatBufferView(buffer), usage);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBufferData")
|
||||
static native void _wglBufferDataN(int target, ArrayBufferView typedArray, int usage);
|
||||
|
||||
public static final void _wglBufferSubData(int target, int dstOffset, ByteBuffer buffer) {
|
||||
_wglBufferSubDataN(target, dstOffset, WASMGCBufferAllocator.getUnsignedByteBufferView(buffer));
|
||||
}
|
||||
|
||||
public static final void _wglBufferSubData(int target, int dstOffset, IntBuffer buffer) {
|
||||
_wglBufferSubDataN(target, dstOffset, WASMGCBufferAllocator.getIntBufferView(buffer));
|
||||
}
|
||||
|
||||
public static final void _wglBufferSubData(int target, int dstOffset, FloatBuffer buffer) {
|
||||
_wglBufferSubDataN(target, dstOffset, WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBufferSubData")
|
||||
static native void _wglBufferSubDataN(int target, int dstOffset, ArrayBufferView typedArray);
|
||||
|
||||
public static final void _wglBindVertexArray(IBufferArrayGL objId) {
|
||||
_wglBindVertexArrayN(objId != null ? ((OpenGLObjects.BufferArrayGL)objId).ptr : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBindVertexArray")
|
||||
static native void _wglBindVertexArrayN(WebGLVertexArray objId);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glEnableVertexAttribArray")
|
||||
public static native void _wglEnableVertexAttribArray(int index);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDisableVertexAttribArray")
|
||||
public static native void _wglDisableVertexAttribArray(int index);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glVertexAttribPointer")
|
||||
public static native void _wglVertexAttribPointer(int index, int size, int type,
|
||||
boolean normalized, int stride, int offset);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glVertexAttribDivisor")
|
||||
public static native void _wglVertexAttribDivisor(int index, int divisor);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glActiveTexture")
|
||||
public static native void _wglActiveTexture(int texture);
|
||||
|
||||
public static final void _wglBindTexture(int target, ITextureGL objId) {
|
||||
_wglBindTextureN(target, objId != null ? ((OpenGLObjects.TextureGL)objId).ptr : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBindTexture")
|
||||
static native void _wglBindTextureN(int target, WebGLTexture objId);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glTexParameterf")
|
||||
public static native void _wglTexParameterf(int target, int param, float value);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glTexParameteri")
|
||||
public static native void _wglTexParameteri(int target, int param, int value);
|
||||
|
||||
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) {
|
||||
_wglTexImage3DN(target, level, internalFormat, width, height, depth, border, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getUnsignedByteBufferView(data) : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glTexImage3D")
|
||||
static native void _wglTexImage3DN(int target, int level, int internalFormat, int width, int height, int depth,
|
||||
int border, int format, int type, ArrayBufferView typedArray);
|
||||
|
||||
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width, int height, int border,
|
||||
int format, int type, ByteBuffer data) {
|
||||
_wglTexImage2DN(target, level, internalFormat, width, height, border, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getUnsignedByteBufferView(data) : null);
|
||||
}
|
||||
|
||||
public static final void _wglTexImage2Du16(int target, int level, int internalFormat, int width, int height, int border,
|
||||
int format, int type, ByteBuffer data) {
|
||||
_wglTexImage2DN(target, level, internalFormat, width, height, border, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getUnsignedShortBufferView(data) : null);
|
||||
}
|
||||
|
||||
public static final void _wglTexImage2Df32(int target, int level, int internalFormat, int width, int height, int border,
|
||||
int format, int type, ByteBuffer data) {
|
||||
_wglTexImage2DN(target, level, internalFormat, width, height, border, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getFloatBufferView(data) : null);
|
||||
}
|
||||
|
||||
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width,
|
||||
int height, int border, int format, int type, IntBuffer data) {
|
||||
_wglTexImage2DN(target, level, internalFormat, width, height, border, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getUnsignedByteBufferView(data) : null);
|
||||
}
|
||||
|
||||
public static final void _wglTexImage2Df32(int target, int level, int internalFormat, int width,
|
||||
int height, int border, int format, int type, FloatBuffer data) {
|
||||
_wglTexImage2DN(target, level, internalFormat, width, height, border, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getFloatBufferView(data) : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glTexImage2D")
|
||||
static native void _wglTexImage2DN(int target, int level, int internalFormat, int width, int height, int border,
|
||||
int format, int type, ArrayBufferView typedArray);
|
||||
|
||||
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
|
||||
int width, int height, int format, int type, ByteBuffer data) {
|
||||
_wglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getUnsignedByteBufferView(data) : null);
|
||||
}
|
||||
|
||||
public static final void _wglTexSubImage2Du16(int target, int level, int xoffset, int yoffset,
|
||||
int width, int height, int format, int type, ByteBuffer data) {
|
||||
_wglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getUnsignedShortBufferView(data) : null);
|
||||
}
|
||||
|
||||
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
|
||||
int width, int height, int format, int type, IntBuffer data) {
|
||||
_wglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getUnsignedByteBufferView(data) : null);
|
||||
}
|
||||
|
||||
public static final void _wglTexSubImage2Df32(int target, int level, int xoffset, int yoffset,
|
||||
int width, int height, int format, int type, FloatBuffer data) {
|
||||
_wglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
|
||||
data != null ? WASMGCBufferAllocator.getFloatBufferView(data) : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glTexSubImage2D")
|
||||
static native void _wglTexSubImage2D(int target, int level, int offsetx, int offsety, int width, int height,
|
||||
int format, int type, ArrayBufferView typedArray);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCopyTexSubImage2D")
|
||||
public static native void _wglCopyTexSubImage2D(int target, int level, int xoffset, int yoffset,
|
||||
int x, int y, int width, int height);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glTexStorage2D")
|
||||
public static native void _wglTexStorage2D(int target, int levels, int internalFormat, int w, int h);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glPixelStorei")
|
||||
public static native void _wglPixelStorei(int pname, int value);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGenerateMipmap")
|
||||
public static native void _wglGenerateMipmap(int target);
|
||||
|
||||
public static final void _wglShaderSource(IShaderGL shader, String str) {
|
||||
_wglShaderSourceN(((OpenGLObjects.ShaderGL)shader).ptr, BetterJSStringConverter.stringToJS(str));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glShaderSource")
|
||||
static native void _wglShaderSourceN(WebGLShader shader, JSString str);
|
||||
|
||||
public static final void _wglCompileShader(IShaderGL shader) {
|
||||
_wglCompileShaderN(((OpenGLObjects.ShaderGL)shader).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCompileShader")
|
||||
static native void _wglCompileShaderN(WebGLShader shader);
|
||||
|
||||
public static final int _wglGetShaderi(IShaderGL shader, int param) {
|
||||
return _wglGetShaderiN(((OpenGLObjects.ShaderGL)shader).ptr, param);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetShaderi")
|
||||
static native int _wglGetShaderiN(WebGLShader shader, int param);
|
||||
|
||||
public static final String _wglGetShaderInfoLog(IShaderGL shader) {
|
||||
return BetterJSStringConverter.stringFromJS(_wglGetShaderInfoLogN(((OpenGLObjects.ShaderGL)shader).ptr));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetShaderInfoLog")
|
||||
static native JSString _wglGetShaderInfoLogN(WebGLShader shader);
|
||||
|
||||
public static final void _wglUseProgram(IProgramGL prog) {
|
||||
_wglUseProgramN(prog != null ? ((OpenGLObjects.ProgramGL)prog).ptr : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUseProgram")
|
||||
static native void _wglUseProgramN(WebGLProgram prog);
|
||||
|
||||
public static final void _wglAttachShader(IProgramGL prog, IShaderGL shader) {
|
||||
_wglAttachShaderN(((OpenGLObjects.ProgramGL)prog).ptr, ((OpenGLObjects.ShaderGL)shader).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glAttachShader")
|
||||
static native void _wglAttachShaderN(WebGLProgram prog, WebGLShader shader);
|
||||
|
||||
public static final void _wglDetachShader(IProgramGL prog, IShaderGL shader) {
|
||||
_wglDetachShaderN(((OpenGLObjects.ProgramGL)prog).ptr, ((OpenGLObjects.ShaderGL)shader).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDetachShader")
|
||||
public static native void _wglDetachShaderN(WebGLProgram prog, WebGLShader shader);
|
||||
|
||||
public static final void _wglLinkProgram(IProgramGL prog) {
|
||||
_wglLinkProgramN(((OpenGLObjects.ProgramGL)prog).ptr);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glLinkProgram")
|
||||
static native void _wglLinkProgramN(WebGLProgram prog);
|
||||
|
||||
public static final int _wglGetProgrami(IProgramGL prog, int param) {
|
||||
return _wglGetProgramiN(((OpenGLObjects.ProgramGL)prog).ptr, param);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetProgrami")
|
||||
static native int _wglGetProgramiN(WebGLProgram prog, int param);
|
||||
|
||||
public static final String _wglGetProgramInfoLog(IProgramGL prog) {
|
||||
return BetterJSStringConverter.stringFromJS(_wglGetProgramInfoLogN(((OpenGLObjects.ProgramGL)prog).ptr));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetProgramInfoLog")
|
||||
static native JSString _wglGetProgramInfoLogN(WebGLProgram prog);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDrawArrays")
|
||||
public static native void _wglDrawArrays(int mode, int first, int count);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDrawElements")
|
||||
public static native void _wglDrawElements(int mode, int count, int type, int offset);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDrawArraysInstanced")
|
||||
public static native void _wglDrawArraysInstanced(int mode, int first, int count, int instanced);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glDrawElementsInstanced")
|
||||
public static native void _wglDrawElementsInstanced(int mode, int count, int type, int offset, int instanced);
|
||||
|
||||
public static final void _wglBindAttribLocation(IProgramGL prog, int index, String str) {
|
||||
_wglBindAttribLocationN(((OpenGLObjects.ProgramGL)prog).ptr, index, BetterJSStringConverter.stringToJS(str));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBindAttribLocation")
|
||||
static native void _wglBindAttribLocationN(WebGLProgram prog, int index, JSString str);
|
||||
|
||||
public static final int _wglGetAttribLocation(IProgramGL prog, String str) {
|
||||
return _wglGetAttribLocationN(((OpenGLObjects.ProgramGL)prog).ptr, BetterJSStringConverter.stringToJS(str));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetAttribLocation")
|
||||
static native int _wglGetAttribLocationN(WebGLProgram prog, JSString str);
|
||||
|
||||
public static final IUniformGL _wglGetUniformLocation(IProgramGL prog, String str) {
|
||||
WebGLUniformLocation ret = _wglGetUniformLocationN(((OpenGLObjects.ProgramGL)prog).ptr, BetterJSStringConverter.stringToJS(str));
|
||||
return ret != null ? new OpenGLObjects.UniformGL(ret) : null;
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetUniformLocation")
|
||||
static native WebGLUniformLocation _wglGetUniformLocationN(WebGLProgram prog, JSString str);
|
||||
|
||||
public static final int _wglGetUniformBlockIndex(IProgramGL prog, String str) {
|
||||
return _wglGetUniformBlockIndexN(((OpenGLObjects.ProgramGL)prog).ptr, BetterJSStringConverter.stringToJS(str));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetUniformBlockIndex")
|
||||
static native int _wglGetUniformBlockIndexN(WebGLProgram prog, JSString str);
|
||||
|
||||
public static final void _wglBindBufferRange(int target, int index, IBufferGL bufferId, int offset, int size) {
|
||||
_wglBindBufferRangeN(target, index, ((OpenGLObjects.BufferGL)bufferId).ptr, offset, size);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBindBufferRange")
|
||||
static native void _wglBindBufferRangeN(int target, int index, WebGLBuffer bufferId, int offset, int size);
|
||||
|
||||
public static final void _wglUniformBlockBinding(IProgramGL prog, int blockIndex, int bufferIndex) {
|
||||
_wglUniformBlockBindingN(((OpenGLObjects.ProgramGL)prog).ptr, blockIndex, bufferIndex);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniformBlockBinding")
|
||||
static native void _wglUniformBlockBindingN(WebGLProgram prog, int blockIndex, int bufferIndex);
|
||||
|
||||
public static final void _wglUniform1f(IUniformGL uniformIndex, float x) {
|
||||
if(uniformIndex != null) _wglUniform1fN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform1f")
|
||||
public static native void _wglUniform1fN(WebGLUniformLocation uniformIndex, float x);
|
||||
|
||||
public static final void _wglUniform2f(IUniformGL uniformIndex, float x, float y) {
|
||||
if(uniformIndex != null) _wglUniform2fN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x, y);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform2f")
|
||||
public static native void _wglUniform2fN(WebGLUniformLocation uniformIndex, float x, float y);
|
||||
|
||||
public static final void _wglUniform3f(IUniformGL uniformIndex, float x, float y, float z) {
|
||||
if(uniformIndex != null) _wglUniform3fN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x, y, z);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform3f")
|
||||
public static native void _wglUniform3fN(WebGLUniformLocation uniformIndex, float x, float y, float z);
|
||||
|
||||
public static final void _wglUniform4f(IUniformGL uniformIndex, float x, float y, float z, float w) {
|
||||
if(uniformIndex != null) _wglUniform4fN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x, y, z, w);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform4f")
|
||||
public static native void _wglUniform4fN(WebGLUniformLocation uniformIndex, float x, float y, float z, float w);
|
||||
|
||||
public static final void _wglUniform1i(IUniformGL uniformIndex, int x) {
|
||||
if(uniformIndex != null) _wglUniform1iN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform1i")
|
||||
public static native void _wglUniform1iN(WebGLUniformLocation uniformIndex, int x);
|
||||
|
||||
public static final void _wglUniform2i(IUniformGL uniformIndex, int x, int y) {
|
||||
if(uniformIndex != null) _wglUniform2iN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x, y);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform2i")
|
||||
public static native void _wglUniform2iN(WebGLUniformLocation uniformIndex, int x, int y);
|
||||
|
||||
public static final void _wglUniform3i(IUniformGL uniformIndex, int x, int y, int z) {
|
||||
if(uniformIndex != null) _wglUniform3iN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x, y, z);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform3i")
|
||||
public static native void _wglUniform3iN(WebGLUniformLocation uniformIndex, int x, int y, int z);
|
||||
|
||||
public static final void _wglUniform4i(IUniformGL uniformIndex, int x, int y, int z, int w) {
|
||||
if(uniformIndex != null) _wglUniform4iN(((OpenGLObjects.UniformGL)uniformIndex).ptr, x, y, z, w);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniform4i")
|
||||
public static native void _wglUniform4iN(WebGLUniformLocation uniformIndex, int x, int y, int z, int w);
|
||||
|
||||
public static final void _wglUniformMatrix2fv(IUniformGL uniformIndex, boolean transpose, FloatBuffer buffer) {
|
||||
if (uniformIndex != null)
|
||||
_wglUniformMatrix2fvN(((OpenGLObjects.UniformGL) uniformIndex).ptr, transpose,
|
||||
WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniformMatrix2fv")
|
||||
static native void _wglUniformMatrix2fvN(WebGLUniformLocation uniformIndex, boolean transpose, Float32Array typedArray);
|
||||
|
||||
public static final void _wglUniformMatrix3fv(IUniformGL uniformIndex, boolean transpose, FloatBuffer buffer) {
|
||||
if (uniformIndex != null)
|
||||
_wglUniformMatrix3fvN(((OpenGLObjects.UniformGL) uniformIndex).ptr, transpose,
|
||||
WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniformMatrix3fv")
|
||||
static native void _wglUniformMatrix3fvN(WebGLUniformLocation uniformIndex, boolean transpose, Float32Array typedArray);
|
||||
|
||||
public static final void _wglUniformMatrix4fv(IUniformGL uniformIndex, boolean transpose, FloatBuffer buffer) {
|
||||
if (uniformIndex != null)
|
||||
_wglUniformMatrix4fvN(((OpenGLObjects.UniformGL) uniformIndex).ptr, transpose,
|
||||
WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniformMatrix4fv")
|
||||
static native void _wglUniformMatrix4fvN(WebGLUniformLocation uniformIndex, boolean transpose, Float32Array typedArray);
|
||||
|
||||
public static final void _wglUniformMatrix3x2fv(IUniformGL uniformIndex, boolean transpose, FloatBuffer buffer) {
|
||||
if (uniformIndex != null)
|
||||
_wglUniformMatrix3x2fvN(((OpenGLObjects.UniformGL) uniformIndex).ptr, transpose,
|
||||
WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniformMatrix3x2fv")
|
||||
static native void _wglUniformMatrix3x2fvN(WebGLUniformLocation uniformIndex, boolean transpose, Float32Array typedArray);
|
||||
|
||||
public static final void _wglUniformMatrix4x2fv(IUniformGL uniformIndex, boolean transpose, FloatBuffer buffer) {
|
||||
if (uniformIndex != null)
|
||||
_wglUniformMatrix4x2fvN(((OpenGLObjects.UniformGL) uniformIndex).ptr, transpose,
|
||||
WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniformMatrix4x2fv")
|
||||
static native void _wglUniformMatrix4x2fvN(WebGLUniformLocation uniformIndex, boolean transpose, Float32Array typedArray);
|
||||
|
||||
public static final void _wglUniformMatrix4x3fv(IUniformGL uniformIndex, boolean transpose, FloatBuffer buffer) {
|
||||
if (uniformIndex != null)
|
||||
_wglUniformMatrix4x3fvN(((OpenGLObjects.UniformGL) uniformIndex).ptr, transpose,
|
||||
WASMGCBufferAllocator.getFloatBufferView(buffer));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glUniformMatrix4x3fv")
|
||||
static native void _wglUniformMatrix4x3fvN(WebGLUniformLocation uniformIndex, boolean transpose, Float32Array typedArray);
|
||||
|
||||
public static final void _wglBindFramebuffer(int target, IFramebufferGL framebuffer) {
|
||||
if(framebuffer == null) {
|
||||
framebuffer = WebGLBackBuffer.getBackBuffer();
|
||||
}
|
||||
_wglBindFramebufferN(target, ((OpenGLObjects.FramebufferGL)framebuffer).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglBindFramebufferLow(int target, IFramebufferGL framebuffer) {
|
||||
_wglBindFramebufferN(target, framebuffer != null ? ((OpenGLObjects.FramebufferGL)framebuffer).ptr : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBindFramebuffer")
|
||||
static native void _wglBindFramebufferN(int target, WebGLFramebuffer framebuffer);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glCheckFramebufferStatus")
|
||||
public static native int _wglCheckFramebufferStatus(int target);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBlitFramebuffer")
|
||||
public static native void _wglBlitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0,
|
||||
int dstX1, int dstY1, int bits, int filter);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glRenderbufferStorage")
|
||||
public static native void _wglRenderbufferStorage(int target, int internalformat, int width, int height);
|
||||
|
||||
public static final void _wglFramebufferTexture2D(int target, int attachment, int texTarget, ITextureGL texObj, int level) {
|
||||
_wglFramebufferTexture2DN(target, attachment, texTarget, ((OpenGLObjects.TextureGL)texObj).ptr, level);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glFramebufferTexture2D")
|
||||
static native void _wglFramebufferTexture2DN(int target, int attachment, int texTarget, WebGLTexture texObj, int level);
|
||||
|
||||
public static final void _wglFramebufferTextureLayer(int target, int attachment, ITextureGL texObj, int level, int layer) {
|
||||
_wglFramebufferTextureLayerN(target, attachment, ((OpenGLObjects.TextureGL)texObj).ptr, level, layer);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glFramebufferTextureLayer")
|
||||
static native void _wglFramebufferTextureLayerN(int target, int attachment, WebGLTexture texObj, int level, int layer);
|
||||
|
||||
public static final void _wglBindRenderbuffer(int target, IRenderbufferGL renderbuffer) {
|
||||
_wglBindRenderbufferN(target, renderbuffer != null ? ((OpenGLObjects.RenderbufferGL)renderbuffer).ptr : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glBindRenderbuffer")
|
||||
static native void _wglBindRenderbufferN(int target, WebGLRenderbuffer renderbuffer);
|
||||
|
||||
public static final void _wglFramebufferRenderbuffer(int target, int attachment, int renderbufferTarget,
|
||||
IRenderbufferGL renderbufferId) {
|
||||
_wglFramebufferRenderbufferN(target, attachment, renderbufferTarget,
|
||||
renderbufferId != null ? ((OpenGLObjects.RenderbufferGL) renderbufferId).ptr : null);
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glFramebufferRenderbuffer")
|
||||
static native void _wglFramebufferRenderbufferN(int target, int attachment, int renderbufferTarget, WebGLRenderbuffer renderbufferId);
|
||||
|
||||
public static final String _wglGetString(int param) {
|
||||
return BetterJSStringConverter.stringFromJS(_wglGetStringN(param));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetString")
|
||||
static native JSString _wglGetStringN(int param);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetInteger")
|
||||
public static native int _wglGetInteger(int param);
|
||||
|
||||
@Import(module = "platformOpenGL", name = "glGetError")
|
||||
public static native int _wglGetError();
|
||||
|
||||
public static final int checkOpenGLESVersion() {
|
||||
return glesVers;
|
||||
}
|
||||
|
||||
public static final boolean checkEXTGPUShader5Capable() {
|
||||
return (capABits & CAP_A_BIT_EXT_GPU_SHADER5) != 0;
|
||||
}
|
||||
|
||||
public static final boolean checkOESGPUShader5Capable() {
|
||||
return (capABits & CAP_A_BIT_OES_GPU_SHADER5) != 0;
|
||||
}
|
||||
|
||||
public static final boolean checkFBORenderMipmapCapable() {
|
||||
return (capABits & CAP_A_BIT_FBO_RENDER_MIPMAP) != 0;
|
||||
}
|
||||
|
||||
public static final boolean checkVAOCapable() {
|
||||
return vertexArrayImpl != VAO_IMPL_NONE;
|
||||
}
|
||||
|
||||
public static final boolean checkInstancingCapable() {
|
||||
return instancingImpl != INSTANCE_IMPL_NONE;
|
||||
}
|
||||
|
||||
public static final boolean checkTexStorageCapable() {
|
||||
return glesVers >= 300;
|
||||
}
|
||||
|
||||
public static final boolean checkTextureLODCapable() {
|
||||
return (capABits & CAP_A_BIT_TEXTURE_LOD_CAPABLE) != 0;
|
||||
}
|
||||
|
||||
public static final boolean checkNPOTCapable() {
|
||||
return (capABits & CAP_A_BIT_NPOT_CAPABLE) != 0;
|
||||
}
|
||||
|
||||
public static final boolean checkHDRFramebufferSupport(int bits) {
|
||||
switch(bits) {
|
||||
case 16:
|
||||
return (capABits & CAP_A_BIT_HDR_FBO16F) != 0;
|
||||
case 32:
|
||||
return (capABits & CAP_A_BIT_HDR_FBO32F) != 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean checkLinearHDRFilteringSupport(int bits) {
|
||||
switch(bits) {
|
||||
case 16:
|
||||
return (capBBits & CAP_B_BIT_HDR_LINEAR16F) != 0;
|
||||
case 32:
|
||||
return (capBBits & CAP_B_BIT_HDR_LINEAR32F) != 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// legacy
|
||||
public static final boolean checkLinearHDR32FSupport() {
|
||||
return (capBBits & CAP_B_BIT_HDR_LINEAR32F) != 0;
|
||||
}
|
||||
|
||||
public static final boolean checkAnisotropicFilteringSupport() {
|
||||
return (capABits & CAP_A_BIT_ANISOTROPIC) != 0;
|
||||
}
|
||||
|
||||
public static final String[] getAllExtensions() {
|
||||
return BetterJSStringConverter.stringArrayFromJS(getAllExtensions0());
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "getAllExtensions")
|
||||
static native JSArray<JSString> getAllExtensions0();
|
||||
|
||||
public static final List<String> dumpActiveExtensions() {
|
||||
return Arrays.asList(BetterJSStringConverter.stringArrayFromJS(dumpActiveExtensions0()));
|
||||
}
|
||||
|
||||
@Import(module = "platformOpenGL", name = "dumpActiveExtensions")
|
||||
static native JSArray<JSString> dumpActiveExtensions0();
|
||||
|
||||
public static final void enterVAOEmulationHook() {
|
||||
WebGLBackBuffer.enterVAOEmulationPhase();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,491 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.core.JSString;
|
||||
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.Uint8Array;
|
||||
|
||||
import com.jcraft.jzlib.DeflaterOutputStream;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.GZIPOutputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Filesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.EarlyLoadScreen;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WebGLBackBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformRuntime {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("RuntimeWASMGC");
|
||||
|
||||
public static Window win = null;
|
||||
public static HTMLDocument doc = null;
|
||||
public static HTMLElement root = null;
|
||||
public static HTMLElement parent = null;
|
||||
public static HTMLCanvasElement canvas = null;
|
||||
public static boolean webglExperimental = false;
|
||||
|
||||
public static void create() {
|
||||
win = Window.current();
|
||||
doc = win.getDocument();
|
||||
root = getRootElement();
|
||||
parent = getParentElement();
|
||||
canvas = getCanvasElement();
|
||||
PlatformApplication.setMCServerWindowGlobal(null);
|
||||
PlatformOpenGL.initContext();
|
||||
PlatformInput.initContext(win, parent, canvas);
|
||||
|
||||
// Should contain an event to update the initial screen size
|
||||
pollJSEventsAfterSleep();
|
||||
|
||||
WebGLBackBuffer.initBackBuffer(PlatformInput.getWindowWidth(), PlatformInput.getWindowHeight());
|
||||
|
||||
HTMLElement el = parent.querySelector("._eaglercraftX_early_splash_element");
|
||||
if(el != null) {
|
||||
el.delete();
|
||||
}
|
||||
|
||||
EarlyLoadScreen.extractingAssetsScreen();
|
||||
sleep(20);
|
||||
|
||||
PlatformAssets.readAssetsTeaVM();
|
||||
|
||||
byte[] finalLoadScreen = PlatformAssets.getResourceBytes("/assets/eagler/eagtek.png");
|
||||
|
||||
if(finalLoadScreen != null) {
|
||||
EarlyLoadScreen.loadFinal(finalLoadScreen);
|
||||
EarlyLoadScreen.paintFinal(false);
|
||||
}else {
|
||||
PlatformOpenGL._wglClearColor(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
PlatformOpenGL._wglClear(RealOpenGLEnums.GL_COLOR_BUFFER_BIT);
|
||||
PlatformInput.update();
|
||||
}
|
||||
sleep(20);
|
||||
|
||||
EarlyLoadScreen.destroy();
|
||||
|
||||
logger.info("Initializing filesystem...");
|
||||
|
||||
IEaglerFilesystem resourcePackFilesystem = Filesystem.getHandleFor(getClientConfigAdapter().getResourcePacksDB());
|
||||
VFile2.setPrimaryFilesystem(resourcePackFilesystem);
|
||||
EaglerFolderResourcePack.setSupported(true);
|
||||
|
||||
logger.info("Initializing sound engine...");
|
||||
|
||||
PlatformAudio.initialize();
|
||||
PlatformScreenRecord.initContext(win, canvas);
|
||||
|
||||
PlatformWebRTC.initialize();
|
||||
PlatformVoiceClient.initialize();
|
||||
PlatformWebView.initialize();
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "getRootElement")
|
||||
private static native HTMLElement getRootElement();
|
||||
|
||||
@Import(module = "platformRuntime", name = "getParentElement")
|
||||
private static native HTMLElement getParentElement();
|
||||
|
||||
@Import(module = "platformRuntime", name = "getCanvasElement")
|
||||
private static native HTMLCanvasElement getCanvasElement();
|
||||
|
||||
public static void destroy() {
|
||||
logger.fatal("Game tried to destroy the context! Browser runtime can't do that");
|
||||
}
|
||||
|
||||
public static EnumPlatformType getPlatformType() {
|
||||
return EnumPlatformType.WASM_GC;
|
||||
}
|
||||
|
||||
public static EnumPlatformAgent getPlatformAgent() {
|
||||
return EnumPlatformAgent.getFromUA(getUserAgentString());
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "return navigator.userAgent||null;")
|
||||
public static native String getUserAgentString();
|
||||
|
||||
public static EnumPlatformOS getPlatformOS() {
|
||||
return EnumPlatformOS.getFromUA(getUserAgentString());
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "return location.protocol && location.protocol.toLowerCase() === \"https:\";")
|
||||
public static native boolean requireSSL();
|
||||
|
||||
@JSBody(params = { }, script = "return location.protocol && location.protocol.toLowerCase() === \"file:\";")
|
||||
public static native boolean isOfflineDownloadURL();
|
||||
|
||||
public static void requestANGLE(EnumPlatformANGLE plaf) {
|
||||
}
|
||||
|
||||
public static EnumPlatformANGLE getPlatformANGLE() {
|
||||
return EnumPlatformANGLE.fromGLRendererString(getGLRenderer());
|
||||
}
|
||||
|
||||
public static String getGLVersion() {
|
||||
return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION);
|
||||
}
|
||||
|
||||
public static String getGLRenderer() {
|
||||
return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER);
|
||||
}
|
||||
|
||||
public static ByteBuffer allocateByteBuffer(int length) {
|
||||
return WASMGCBufferAllocator.allocateByteBuffer(length);
|
||||
}
|
||||
|
||||
public static IntBuffer allocateIntBuffer(int length) {
|
||||
return WASMGCBufferAllocator.allocateIntBuffer(length);
|
||||
}
|
||||
|
||||
public static FloatBuffer allocateFloatBuffer(int length) {
|
||||
return WASMGCBufferAllocator.allocateFloatBuffer(length);
|
||||
}
|
||||
|
||||
public static ByteBuffer castPrimitiveByteArray(byte[] array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IntBuffer castPrimitiveIntArray(int[] array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FloatBuffer castPrimitiveFloatArray(float[] array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] castNativeByteBuffer(ByteBuffer buffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int[] castNativeIntBuffer(IntBuffer buffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static float[] castNativeFloatBuffer(FloatBuffer buffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void freeByteBuffer(ByteBuffer byteBuffer) {
|
||||
WASMGCBufferAllocator.freeByteBuffer(byteBuffer);
|
||||
}
|
||||
|
||||
public static void freeIntBuffer(IntBuffer intBuffer) {
|
||||
WASMGCBufferAllocator.freeIntBuffer(intBuffer);
|
||||
}
|
||||
|
||||
public static void freeFloatBuffer(FloatBuffer floatBuffer) {
|
||||
WASMGCBufferAllocator.freeFloatBuffer(floatBuffer);
|
||||
}
|
||||
|
||||
private interface JSAsyncDownloadEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getRequestId();
|
||||
|
||||
@JSProperty
|
||||
ArrayBuffer getArrayBuffer();
|
||||
|
||||
}
|
||||
|
||||
private static final int EVENT_TYPE_INPUT = 0;
|
||||
private static final int EVENT_TYPE_RUNTIME = 1;
|
||||
private static final int EVENT_TYPE_VOICE = 2;
|
||||
private static final int EVENT_TYPE_WEBVIEW = 3;
|
||||
|
||||
public interface JSEagRuntimeEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getEventType();
|
||||
|
||||
@JSProperty
|
||||
<T> T getEventObj();
|
||||
|
||||
}
|
||||
|
||||
static void pollJSEvents() {
|
||||
int cnt = getEventCount();
|
||||
while(cnt-- > 0) {
|
||||
JSEagRuntimeEvent evt = getNextEvent();
|
||||
if(evt != null) {
|
||||
switch(evt.getEventType() >>> 5) {
|
||||
case EVENT_TYPE_INPUT:
|
||||
PlatformInput.handleJSEvent(evt);
|
||||
break;
|
||||
case EVENT_TYPE_RUNTIME:
|
||||
handleJSEvent(evt);
|
||||
break;
|
||||
case EVENT_TYPE_VOICE:
|
||||
PlatformVoiceClient.handleJSEvent(evt);
|
||||
break;
|
||||
case EVENT_TYPE_WEBVIEW:
|
||||
PlatformWebView.handleJSEvent(evt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pollAsyncCallbacksTeaVM();
|
||||
}
|
||||
|
||||
private static boolean isWakingUpFromSleep = false;
|
||||
|
||||
static void pollJSEventsAfterSleep() {
|
||||
if(!isWakingUpFromSleep) {
|
||||
try {
|
||||
isWakingUpFromSleep = true;
|
||||
pollJSEvents();
|
||||
}finally {
|
||||
isWakingUpFromSleep = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int EVENT_RUNTIME_ASYNC_DOWNLOAD = 0;
|
||||
|
||||
private static void handleJSEvent(PlatformRuntime.JSEagRuntimeEvent evt) {
|
||||
switch(evt.getEventType() & 31) {
|
||||
case EVENT_RUNTIME_ASYNC_DOWNLOAD: {
|
||||
JSAsyncDownloadEvent obj = evt.getEventObj();
|
||||
int id = obj.getRequestId();
|
||||
Consumer<ArrayBuffer> handler = waitingAsyncDownloads.get(id);
|
||||
if(handler != null) {
|
||||
handler.accept(obj.getArrayBuffer());
|
||||
}else {
|
||||
logger.warn("Ignoring unknown async download result #{}", id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "teavm", name = "pollAsyncCallbacks")
|
||||
private static native JSEagRuntimeEvent pollAsyncCallbacksTeaVM();
|
||||
|
||||
@Import(module = "platformRuntime", name = "getEventCount")
|
||||
private static native int getEventCount();
|
||||
|
||||
@Import(module = "platformRuntime", name = "getNextEvent")
|
||||
private static native JSEagRuntimeEvent getNextEvent();
|
||||
|
||||
private static final Map<Integer, Consumer<ArrayBuffer>> waitingAsyncDownloads = new HashMap<>();
|
||||
private static int asyncDownloadID = 0;
|
||||
|
||||
private static void queueAsyncDownload(String uri, boolean forceCache, Consumer<ArrayBuffer> cb) {
|
||||
int id = ++asyncDownloadID;
|
||||
waitingAsyncDownloads.put(id, cb);
|
||||
queueAsyncDownload0(BetterJSStringConverter.stringToJS(uri), forceCache, id);
|
||||
}
|
||||
|
||||
public static void downloadRemoteURIByteArray(String assetPackageURI, final Consumer<byte[]> cb) {
|
||||
downloadRemoteURIByteArray(assetPackageURI, false, cb);
|
||||
}
|
||||
|
||||
public static void downloadRemoteURIByteArray(String assetPackageURI, boolean useCache, final Consumer<byte[]> cb) {
|
||||
queueAsyncDownload(assetPackageURI, useCache, arr -> {
|
||||
if(arr == null) {
|
||||
cb.accept(null);
|
||||
}else {
|
||||
cb.accept(WASMGCDirectArrayConverter.externU8ArrayToByteArray(new Uint8Array(arr)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void downloadRemoteURI(String assetPackageURI, Consumer<ArrayBuffer> cb) {
|
||||
queueAsyncDownload(assetPackageURI, false, cb);
|
||||
}
|
||||
|
||||
public static void downloadRemoteURI(String assetPackageURI, boolean useCache, Consumer<ArrayBuffer> cb) {
|
||||
queueAsyncDownload(assetPackageURI, useCache, cb);
|
||||
}
|
||||
|
||||
public static byte[] downloadRemoteURIByteArray(String assetPackageURI) {
|
||||
return downloadRemoteURIByteArray(assetPackageURI, false);
|
||||
}
|
||||
|
||||
public static byte[] downloadRemoteURIByteArray(String assetPackageURI, boolean forceCache) {
|
||||
ArrayBuffer arrayBuffer = downloadSync(BetterJSStringConverter.stringToJS(assetPackageURI), forceCache);
|
||||
pollJSEventsAfterSleep();
|
||||
if(arrayBuffer == null) {
|
||||
return null;
|
||||
}
|
||||
return WASMGCDirectArrayConverter.externU8ArrayToByteArray(new Uint8Array(arrayBuffer));
|
||||
}
|
||||
|
||||
public static ArrayBuffer downloadRemoteURI(String assetPackageURI) {
|
||||
ArrayBuffer ret = downloadSync(BetterJSStringConverter.stringToJS(assetPackageURI), false);
|
||||
pollJSEventsAfterSleep();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static ArrayBuffer downloadRemoteURI(String assetPackageURI, boolean forceCache) {
|
||||
ArrayBuffer ret = downloadSync(BetterJSStringConverter.stringToJS(assetPackageURI), forceCache);
|
||||
pollJSEventsAfterSleep();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "queueAsyncDownload")
|
||||
private static native void queueAsyncDownload0(JSString uri, boolean forceCache, int id);
|
||||
|
||||
@Import(module = "platformRuntime", name = "download")
|
||||
private static native ArrayBuffer downloadSync(JSString uri, boolean forceCache);
|
||||
|
||||
public static boolean isDebugRuntime() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void writeCrashReport(String crashDump) {
|
||||
writeCrashReport0(BetterJSStringConverter.stringToJS(crashDump));
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "writeCrashReport")
|
||||
private static native void writeCrashReport0(JSString crashDump);
|
||||
|
||||
public static void getStackTrace(Throwable t, Consumer<String> ret) {
|
||||
StackTraceElement[] el = t.getStackTrace();
|
||||
if(el.length > 0) {
|
||||
for(int i = 0; i < el.length; ++i) {
|
||||
ret.accept(el[i].toString());
|
||||
}
|
||||
}else {
|
||||
ret.accept("[no stack trace]");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean printJSExceptionIfBrowser(Throwable t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String currentThreadName = "main";
|
||||
|
||||
public static String currentThreadName() {
|
||||
return currentThreadName;
|
||||
}
|
||||
|
||||
public static void setThreadName(String string) {
|
||||
currentThreadName = string;
|
||||
}
|
||||
|
||||
public static long maxMemory() {
|
||||
return 1073741824l;
|
||||
}
|
||||
|
||||
public static long totalMemory() {
|
||||
return 1073741824l;
|
||||
}
|
||||
|
||||
public static long freeMemory() {
|
||||
return 1073741824l;
|
||||
}
|
||||
|
||||
public static String getCallingClass(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long randomSeed() {
|
||||
return (long)(Math.random() * 9007199254740991.0);
|
||||
}
|
||||
|
||||
public static void exit() {
|
||||
logger.fatal("Game is attempting to exit!");
|
||||
}
|
||||
|
||||
public static IClientConfigAdapter getClientConfigAdapter() {
|
||||
return WASMGCClientConfigAdapter.instance;
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "steadyTimeMillis")
|
||||
static native double steadyTimeMillis0();
|
||||
|
||||
public static long steadyTimeMillis() {
|
||||
return (long)steadyTimeMillis0();
|
||||
}
|
||||
|
||||
public static long nanoTime() {
|
||||
return (long)(steadyTimeMillis0() * 1000000.0);
|
||||
}
|
||||
|
||||
public static void sleep(int millis) {
|
||||
sleep0(millis);
|
||||
pollJSEventsAfterSleep();
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "sleep")
|
||||
private static native void sleep0(int millis);
|
||||
|
||||
public static void immediateContinue() {
|
||||
immediateContinue0();
|
||||
pollJSEventsAfterSleep();
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "immediateContinue")
|
||||
private static native void immediateContinue0();
|
||||
|
||||
public static void postCreate() {
|
||||
|
||||
}
|
||||
|
||||
public static void setDisplayBootMenuNextRefresh(boolean en) {
|
||||
|
||||
}
|
||||
|
||||
public static OutputStream newDeflaterOutputStream(OutputStream os) throws IOException {
|
||||
return new DeflaterOutputStream(os);
|
||||
}
|
||||
|
||||
public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException {
|
||||
return new GZIPOutputStream(os);
|
||||
}
|
||||
|
||||
public static InputStream newInflaterInputStream(InputStream is) throws IOException {
|
||||
return new InflaterInputStream(is);
|
||||
}
|
||||
|
||||
public static InputStream newGZIPInputStream(InputStream is) throws IOException {
|
||||
return new GZIPInputStream(is);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.canvas.CanvasRenderingContext2D;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.dom.html.HTMLCanvasElement;
|
||||
import org.teavm.jso.webaudio.MediaStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
|
||||
import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformScreenRecord {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("PlatformScreenRecord");
|
||||
|
||||
static Window win;
|
||||
static HTMLCanvasElement canvas;
|
||||
static boolean support;
|
||||
static final Set<EnumScreenRecordingCodec> supportedCodecs = EnumSet.noneOf(EnumScreenRecordingCodec.class);
|
||||
static float currentGameVolume = 1.0f;
|
||||
static float currentMicVolume = 0.0f;
|
||||
static MediaStream recStream = null;
|
||||
static HTMLCanvasElement downscaleCanvas = null;
|
||||
static CanvasRenderingContext2D downscaleCanvasCtx = null;
|
||||
static long lastDownscaleFrameCaptured = 0l;
|
||||
static boolean currentMicLock = false;
|
||||
static JSObject mediaRec = null;
|
||||
static ScreenRecordParameters currentParameters = null;
|
||||
|
||||
static void initContext(Window theWin, HTMLCanvasElement theCanvas) {
|
||||
win = theWin;
|
||||
canvas = theCanvas;
|
||||
supportedCodecs.clear();
|
||||
support = hasMediaRecorder(theWin, theCanvas);
|
||||
if(support) {
|
||||
logger.info("MediaRecorder is supported, checking codecs...");
|
||||
EnumScreenRecordingCodec[] allCodecs = EnumScreenRecordingCodec.values();
|
||||
for(int i = 0; i < allCodecs.length; ++i) {
|
||||
if(checkCodecSupported(theWin, allCodecs[i].mimeType)) {
|
||||
supportedCodecs.add(allCodecs[i]);
|
||||
}
|
||||
}
|
||||
if(!supportedCodecs.isEmpty()) {
|
||||
logger.info("Found {} codecs that are probably supported!", supportedCodecs.size());
|
||||
}else {
|
||||
logger.error("No supported codecs found!");
|
||||
support = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformScreenRecord", name = "getMic")
|
||||
public static native MediaStream getMic();
|
||||
|
||||
@JSBody(params = { "win", "canvas" }, script = "return (typeof win.MediaRecorder !== \"undefined\") && (typeof win.MediaRecorder.isTypeSupported === \"function\") && (typeof canvas.captureStream === \"function\");")
|
||||
private static native boolean hasMediaRecorder(Window win, HTMLCanvasElement canvas);
|
||||
|
||||
@JSBody(params = { "win", "mime" }, script = "return win.MediaRecorder.isTypeSupported(mime);")
|
||||
private static native boolean checkCodecSupported(Window win, String mime);
|
||||
|
||||
public static boolean isSupported() {
|
||||
return support;
|
||||
}
|
||||
|
||||
public static boolean isCodecSupported(EnumScreenRecordingCodec codec) {
|
||||
return supportedCodecs.contains(codec);
|
||||
}
|
||||
|
||||
static void captureFrameHook() {
|
||||
if(mediaRec != null && currentParameters != null && currentParameters.resolutionDivisior > 1 && downscaleCanvas != null && downscaleCanvasCtx != null) {
|
||||
if(currentParameters.captureFrameRate > 0) {
|
||||
long curTime = PlatformRuntime.steadyTimeMillis();
|
||||
if(curTime - lastDownscaleFrameCaptured < (long)(1000 / currentParameters.captureFrameRate)) {
|
||||
return;
|
||||
}
|
||||
lastDownscaleFrameCaptured = curTime;
|
||||
}
|
||||
int oldWidth = downscaleCanvas.getWidth();
|
||||
int oldHeight = downscaleCanvas.getHeight();
|
||||
float divisor = (float)Math.sqrt(1.0 / Math.pow(2.0, currentParameters.resolutionDivisior - 1));
|
||||
int newWidth = (int)(PlatformInput.getWindowWidth() * divisor);
|
||||
int newHeight = (int)(PlatformInput.getWindowHeight() * divisor);
|
||||
if(oldWidth != newWidth || oldHeight != newHeight) {
|
||||
downscaleCanvas.setWidth(newWidth);
|
||||
downscaleCanvas.setHeight(newHeight);
|
||||
}
|
||||
downscaleCanvasCtx.drawImage(canvas, 0, 0, newWidth, newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setGameVolume(float volume) {
|
||||
currentGameVolume = volume;
|
||||
if(PlatformAudio.gameRecGain != null) {
|
||||
PlatformAudio.gameRecGain.getGain().setValue(volume);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setMicrophoneVolume(float volume) {
|
||||
currentMicVolume = volume;
|
||||
if(PlatformAudio.micRecGain != null) {
|
||||
PlatformAudio.micRecGain.getGain().setValue(volume);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformScreenRecord", name = "setDataAvailableHandler")
|
||||
private static native void setupDataAvailableHandler(JSObject mediaRec, boolean isWebM, JSString nameStr);
|
||||
|
||||
@JSBody(params = { }, script = "return { alpha: false, desynchronized: true };")
|
||||
private static native JSObject youEagler();
|
||||
|
||||
@JSBody(params = { "canvas", "fps", "audio" }, script = "var stream = fps <= 0 ? canvas.captureStream() : canvas.captureStream(fps); stream.addTrack(audio.getTracks()[0]); return stream;")
|
||||
private static native MediaStream captureStreamAndAddAudio(HTMLCanvasElement canvas, int fps, MediaStream audio);
|
||||
|
||||
@JSBody(params = { "stream", "codec", "videoBitrate", "audioBitrate" }, script = "var rec = new MediaRecorder(stream, { mimeType: codec, videoBitsPerSecond: videoBitrate, audioBitsPerSecond: audioBitrate }); rec.start(); return rec;")
|
||||
private static native JSObject createMediaRecorder(MediaStream stream, String codec, int videoBitrate, int audioBitrate);
|
||||
|
||||
@JSBody(params = { "rec" }, script = "rec.stop();")
|
||||
private static native void stopRec(JSObject rec);
|
||||
|
||||
public static void startRecording(ScreenRecordParameters params) {
|
||||
if(!support) {
|
||||
throw new IllegalStateException("Screen recording is not supported");
|
||||
}
|
||||
if(isRecording()) {
|
||||
throw new IllegalStateException("Already recording!");
|
||||
}
|
||||
if(params.captureFrameRate <= 0 && (!PlatformInput.vsync || !PlatformInput.vsyncSupport)) {
|
||||
throw new IllegalStateException("V-Sync is not enabled, please enable it in \"Video Settings\"");
|
||||
}
|
||||
if(params.resolutionDivisior > 1) {
|
||||
float divisor = (float)Math.sqrt(1.0 / Math.pow(2.0, params.resolutionDivisior - 1));
|
||||
int newWidth = (int)(PlatformInput.getWindowWidth() * divisor);
|
||||
int newHeight = (int)(PlatformInput.getWindowHeight() * divisor);
|
||||
if(downscaleCanvas == null) {
|
||||
downscaleCanvas = (HTMLCanvasElement) win.getDocument().createElement("canvas");
|
||||
downscaleCanvas.setWidth(newWidth);
|
||||
downscaleCanvas.setHeight(newHeight);
|
||||
downscaleCanvasCtx = (CanvasRenderingContext2D) downscaleCanvas.getContext("2d", youEagler());
|
||||
if(downscaleCanvasCtx == null) {
|
||||
downscaleCanvas = null;
|
||||
throw new IllegalStateException("Could not create downscaler canvas!");
|
||||
}
|
||||
}else {
|
||||
downscaleCanvas.setWidth(newWidth);
|
||||
downscaleCanvas.setHeight(newHeight);
|
||||
}
|
||||
}
|
||||
currentMicLock = currentMicVolume <= 0.0f;
|
||||
recStream = captureStreamAndAddAudio(params.resolutionDivisior > 1 ? downscaleCanvas : canvas,
|
||||
Math.max(params.captureFrameRate, 0),
|
||||
PlatformAudio.initRecordingStream(currentGameVolume, currentMicVolume));
|
||||
mediaRec = createMediaRecorder(recStream, params.codec.mimeType, params.videoBitsPerSecond * 1000,
|
||||
params.audioBitsPerSecond * 1000);
|
||||
currentParameters = params;
|
||||
setupDataAvailableHandler(mediaRec, "video/webm".equals(params.codec.container),
|
||||
BetterJSStringConverter.stringToJS(EaglercraftVersion.screenRecordingFilePrefix + " - " + EaglerProfile.getName()
|
||||
+ " - ${date}." + params.codec.fileExt));
|
||||
}
|
||||
|
||||
public static void endRecording() {
|
||||
if(mediaRec != null) {
|
||||
stopRec(mediaRec);
|
||||
mediaRec = null;
|
||||
PlatformAudio.destroyRecordingStream();
|
||||
}
|
||||
currentParameters = null;
|
||||
}
|
||||
|
||||
public static boolean isRecording() {
|
||||
return mediaRec != null;
|
||||
}
|
||||
|
||||
public static boolean isMicVolumeLocked() {
|
||||
return mediaRec != null && currentMicLock;
|
||||
}
|
||||
|
||||
public static boolean isVSyncLocked() {
|
||||
return mediaRec != null && currentParameters != null && currentParameters.captureFrameRate == -1;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateProgressStruct;
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateResultObj;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformUpdateSvc {
|
||||
|
||||
private static final UpdateProgressStruct dummyStruct = new UpdateProgressStruct();
|
||||
|
||||
public static boolean supported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
|
||||
}
|
||||
|
||||
public static byte[] getClientSignatureData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] getClientBundleData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void startClientUpdateFrom(UpdateCertificate clientUpdate) {
|
||||
|
||||
}
|
||||
|
||||
public static UpdateProgressStruct getUpdatingStatus() {
|
||||
return dummyStruct;
|
||||
}
|
||||
|
||||
public static UpdateResultObj getUpdateResult() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void installSignedClient(UpdateCertificate clientCert, byte[] clientPayload, boolean setDefault,
|
||||
boolean setTimeout) {
|
||||
|
||||
}
|
||||
|
||||
public static void quine(String filename, byte[] cert, byte[] data, String date) {
|
||||
|
||||
}
|
||||
|
||||
public static void quine(UpdateCertificate clientUpdate, byte[] data) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,473 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
import org.teavm.jso.webaudio.AnalyserNode;
|
||||
import org.teavm.jso.webaudio.AudioContext;
|
||||
import org.teavm.jso.webaudio.AudioNode;
|
||||
import org.teavm.jso.webaudio.GainNode;
|
||||
import org.teavm.jso.webaudio.MediaStream;
|
||||
import org.teavm.jso.webaudio.MediaStreamAudioDestinationNode;
|
||||
import org.teavm.jso.webaudio.MediaStreamAudioSourceNode;
|
||||
import org.teavm.jso.webaudio.PannerNode;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.voice.EnumVoiceChannelReadyState;
|
||||
import net.lax1dude.eaglercraft.v1_8.voice.EnumVoiceChannelType;
|
||||
import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformVoiceClient {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformVoiceClient");
|
||||
|
||||
static boolean support = false;
|
||||
|
||||
private interface JSVoicePeerHandle extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getObjId();
|
||||
|
||||
void setRemoteDescription(JSString desc);
|
||||
|
||||
void addRemoteICECandidate(JSString ice);
|
||||
|
||||
void closeHandle();
|
||||
|
||||
}
|
||||
|
||||
private interface JSVoicePeerICEEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getObjId();
|
||||
|
||||
@JSProperty
|
||||
JSString getData();
|
||||
|
||||
}
|
||||
|
||||
private interface JSVoicePeerOpenEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getObjId();
|
||||
|
||||
@JSProperty
|
||||
MediaStream getStream();
|
||||
|
||||
}
|
||||
|
||||
private interface JSVoicePeerCloseEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getObjId();
|
||||
|
||||
}
|
||||
|
||||
private static final int EVENT_VOICE_ICE = 0;
|
||||
private static final int EVENT_VOICE_DESC = 1;
|
||||
private static final int EVENT_VOICE_OPEN = 2;
|
||||
private static final int EVENT_VOICE_CLOSE = 3;
|
||||
|
||||
static void handleJSEvent(PlatformRuntime.JSEagRuntimeEvent evt) {
|
||||
switch(evt.getEventType() & 31) {
|
||||
case EVENT_VOICE_ICE: {
|
||||
JSVoicePeerICEEvent obj = evt.getEventObj();
|
||||
VoicePeer peer = peerListI.get(obj.getObjId());
|
||||
if(peer != null) {
|
||||
peer.handleEventLocalICECandidate(BetterJSStringConverter.stringFromJS(obj.getData()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_VOICE_DESC: {
|
||||
JSVoicePeerICEEvent obj = evt.getEventObj();
|
||||
VoicePeer peer = peerListI.get(obj.getObjId());
|
||||
if(peer != null) {
|
||||
peer.handleEventLocalDescription(BetterJSStringConverter.stringFromJS(obj.getData()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_VOICE_OPEN: {
|
||||
JSVoicePeerOpenEvent obj = evt.getEventObj();
|
||||
VoicePeer peer = peerListI.get(obj.getObjId());
|
||||
if(peer != null) {
|
||||
peer.handleEventOpened(obj.getStream());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_VOICE_CLOSE: {
|
||||
JSVoicePeerCloseEvent obj = evt.getEventObj();
|
||||
VoicePeer peer = peerListI.remove(obj.getObjId());
|
||||
if(peer != null) {
|
||||
peerList.remove(peer.peerId);
|
||||
peer.handleEventClosed();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final Map<EaglercraftUUID, VoicePeer> peerList = new HashMap<>();
|
||||
static final Map<Integer, VoicePeer> peerListI = new HashMap<>();
|
||||
|
||||
private static class VoicePeer {
|
||||
|
||||
private final int objId;
|
||||
private final EaglercraftUUID peerId;
|
||||
private final JSVoicePeerHandle jsHandle;
|
||||
|
||||
private MediaStream rawStream = null;
|
||||
private AnalyserNode analyser = null;
|
||||
private GainNode gain = null;
|
||||
private PannerNode panner = null;
|
||||
private AudioNode recNode = null;
|
||||
|
||||
private boolean dead = false;
|
||||
|
||||
private VoicePeer(int objId, EaglercraftUUID peerId, JSVoicePeerHandle jsHandle) {
|
||||
this.objId = objId;
|
||||
this.peerId = peerId;
|
||||
this.jsHandle = jsHandle;
|
||||
}
|
||||
|
||||
private void handleEventLocalICECandidate(String data) {
|
||||
VoiceClientController.sendPacketICE(peerId, data);
|
||||
}
|
||||
|
||||
private void handleEventLocalDescription(String data) {
|
||||
VoiceClientController.sendPacketDesc(peerId, data);
|
||||
}
|
||||
|
||||
private void handlePacketRemoteDescription(String descJSON) {
|
||||
jsHandle.setRemoteDescription(BetterJSStringConverter.stringToJS(descJSON));
|
||||
}
|
||||
|
||||
private void handlePacketRemoteICECandidate(String candidate) {
|
||||
jsHandle.addRemoteICECandidate(BetterJSStringConverter.stringToJS(candidate));
|
||||
}
|
||||
|
||||
private void handleEventOpened(MediaStream stream) {
|
||||
rawStream = stream;
|
||||
MediaStreamAudioSourceNode audioNode = PlatformAudio.audioctx.createMediaStreamSource(stream);
|
||||
AnalyserNode analyser = PlatformAudio.audioctx.createAnalyser();
|
||||
analyser.setSmoothingTimeConstant(0f);
|
||||
analyser.setFftSize(32);
|
||||
audioNode.connect(analyser);
|
||||
if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.GLOBAL) {
|
||||
GainNode gain = PlatformAudio.audioctx.createGain();
|
||||
gain.getGain().setValue(VoiceClientController.getVoiceListenVolume());
|
||||
audioNode.connect(gain);
|
||||
gain.connect(PlatformAudio.audioctx.getDestination());
|
||||
if(PlatformAudio.gameRecGain != null) {
|
||||
gain.connect(PlatformAudio.gameRecGain);
|
||||
}
|
||||
VoiceClientController.getVoiceListening().add(peerId);
|
||||
this.analyser = analyser;
|
||||
this.gain = gain;
|
||||
this.recNode = gain;
|
||||
} else if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.PROXIMITY) {
|
||||
PannerNode panner = PlatformAudio.audioctx.createPanner();
|
||||
panner.setRolloffFactor(1f);
|
||||
PlatformAudio.setDistanceModelLinearFast(panner);
|
||||
PlatformAudio.setPanningModelHRTFFast(panner);
|
||||
panner.setConeInnerAngle(360f);
|
||||
panner.setConeOuterAngle(0f);
|
||||
panner.setConeOuterGain(0f);
|
||||
panner.setOrientation(0f, 1f, 0f);
|
||||
panner.setPosition(0, 0, 0);
|
||||
float vol = VoiceClientController.getVoiceListenVolume();
|
||||
panner.setMaxDistance(vol * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
|
||||
GainNode gain = PlatformAudio.audioctx.createGain();
|
||||
gain.getGain().setValue(vol);
|
||||
audioNode.connect(gain);
|
||||
gain.connect(panner);
|
||||
panner.connect(PlatformAudio.audioctx.getDestination());
|
||||
if(PlatformAudio.gameRecGain != null) {
|
||||
panner.connect(PlatformAudio.gameRecGain);
|
||||
}
|
||||
VoiceClientController.getVoiceListening().add(peerId);
|
||||
this.analyser = analyser;
|
||||
this.panner = panner;
|
||||
this.gain = gain;
|
||||
this.recNode = panner;
|
||||
}
|
||||
if (VoiceClientController.getVoiceMuted().contains(peerId)) mute(true);
|
||||
}
|
||||
|
||||
private void mute(boolean muted) {
|
||||
if(rawStream != null) {
|
||||
PlatformVoiceClient.mute(rawStream, muted);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePacketClosed() {
|
||||
closeHandle(true);
|
||||
}
|
||||
|
||||
private void handleEventClosed() {
|
||||
if(!dead) {
|
||||
dead = true;
|
||||
cleanup(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void closeHandle(boolean quiet) {
|
||||
if(!dead) {
|
||||
dead = true;
|
||||
jsHandle.closeHandle();
|
||||
peerListI.remove(objId);
|
||||
peerList.remove(peerId);
|
||||
cleanup(quiet);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup(boolean quiet) {
|
||||
if(analyser != null) {
|
||||
analyser.disconnect();
|
||||
analyser = null;
|
||||
}
|
||||
if(gain != null) {
|
||||
gain.disconnect();
|
||||
gain = null;
|
||||
}
|
||||
if(panner != null) {
|
||||
panner.disconnect();
|
||||
panner = null;
|
||||
}
|
||||
if(rawStream != null) {
|
||||
rawStream = null;
|
||||
}
|
||||
VoiceClientController.getVoiceListening().remove(peerId);
|
||||
if (!quiet) {
|
||||
VoiceClientController.sendPacketDisconnectPeer(peerId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void initialize() {
|
||||
support = PlatformWebRTC.supported() && isSupported0();
|
||||
peerList.clear();
|
||||
peerListI.clear();
|
||||
}
|
||||
|
||||
public static boolean isSupported() {
|
||||
return support;
|
||||
}
|
||||
|
||||
@Import(module = "platformVoiceClient", name = "isSupported")
|
||||
private static native boolean isSupported0();
|
||||
|
||||
public static String iceServers = null;
|
||||
public static boolean hasInit = false;
|
||||
public static MediaStreamAudioDestinationNode localMediaStream;
|
||||
public static GainNode localMediaStreamGain;
|
||||
public static MediaStream localRawMediaStream;
|
||||
public static EnumVoiceChannelReadyState readyState = EnumVoiceChannelReadyState.NONE;
|
||||
public static AudioContext microphoneVolumeAudioContext = null;
|
||||
|
||||
public static void setICEServers(String[] urls) {
|
||||
if (urls == null || urls.length == 0) {
|
||||
iceServers = null;
|
||||
return;
|
||||
}
|
||||
JSONArray arr = new JSONArray();
|
||||
for (String url : urls) {
|
||||
String[] etr = url.split(";");
|
||||
if (etr.length == 1) {
|
||||
JSONObject m = new JSONObject();
|
||||
m.put("urls", etr[0]);
|
||||
arr.put(m);
|
||||
} else if (etr.length == 3) {
|
||||
JSONObject m = new JSONObject();
|
||||
m.put("urls", etr[0]);
|
||||
m.put("username", etr[1]);
|
||||
m.put("credential", etr[2]);
|
||||
arr.put(m);
|
||||
}
|
||||
}
|
||||
iceServers = arr.toString();
|
||||
}
|
||||
|
||||
@JSBody(params = { "rawStream", "muted" }, script = "return rawStream.getAudioTracks()[0].enabled = !muted;")
|
||||
static native void mute(MediaStream rawStream, boolean muted);
|
||||
|
||||
public static void activateVoice(boolean talk) {
|
||||
if (hasInit) {
|
||||
mute(localRawMediaStream, !talk);
|
||||
}
|
||||
}
|
||||
|
||||
public static void initializeDevices() {
|
||||
if (!hasInit) {
|
||||
localRawMediaStream = PlatformScreenRecord.getMic();
|
||||
if (localRawMediaStream == null) {
|
||||
readyState = EnumVoiceChannelReadyState.ABORTED;
|
||||
return;
|
||||
}
|
||||
microphoneVolumeAudioContext = new AudioContext();
|
||||
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 (VoicePeer voicePlayer : peerList.values()) {
|
||||
AnalyserNode analyser = voicePlayer.analyser;
|
||||
if(analyser != null) {
|
||||
Uint8Array array = new Uint8Array(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(voicePlayer.peerId);
|
||||
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 EnumVoiceChannelReadyState getReadyState() {
|
||||
return readyState;
|
||||
}
|
||||
|
||||
public static void signalConnect(EaglercraftUUID peerId, boolean offer) {
|
||||
if(iceServers == null) {
|
||||
logger.error("No ICE servers provided for {}", peerId);
|
||||
return;
|
||||
}
|
||||
JSVoicePeerHandle peerHandle = createRTCPeerConnection(
|
||||
BetterJSStringConverter.stringToJS(iceServers), offer,
|
||||
localMediaStream.getStream());
|
||||
if(peerHandle != null) {
|
||||
int obj = peerHandle.getObjId();
|
||||
VoicePeer peer = new VoicePeer(obj, peerId, peerHandle);
|
||||
peerList.put(peerId, peer);
|
||||
peerListI.put(obj, peer);
|
||||
}else {
|
||||
logger.error("Could not create peer for {}", peerId);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformVoiceClient", name = "createRTCPeerConnection")
|
||||
private static native JSVoicePeerHandle createRTCPeerConnection(JSString iceServers, boolean offer, JSObject localStream);
|
||||
|
||||
public static void signalDescription(EaglercraftUUID peerId, String descJSON) {
|
||||
VoicePeer peer = peerList.get(peerId);
|
||||
if (peer != null) {
|
||||
peer.handlePacketRemoteDescription(descJSON);
|
||||
}
|
||||
}
|
||||
|
||||
public static void signalDisconnect(EaglercraftUUID peerId, boolean quiet) {
|
||||
VoicePeer peer = peerList.remove(peerId);
|
||||
if (peer != null) {
|
||||
peer.handlePacketClosed();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVoiceProximity(int prox) {
|
||||
for (VoicePeer player : peerList.values()) {
|
||||
if(player.panner != null) {
|
||||
player.panner.setMaxDistance(VoiceClientController.getVoiceListenVolume() * 2 * prox + 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateVoicePosition(EaglercraftUUID uuid, double x, double y, double z) {
|
||||
VoicePeer player = peerList.get(uuid);
|
||||
if (player != null && player.panner != null) player.panner.setPosition((float) x, (float) y, (float) z);
|
||||
}
|
||||
|
||||
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.handlePacketRemoteICECandidate(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
static void addRecordingDest(AudioNode destNode) {
|
||||
for(VoicePeer peer : peerList.values()) {
|
||||
if(peer.recNode != null) {
|
||||
peer.recNode.connect(destNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void removeRecordingDest(AudioNode destNode) {
|
||||
for(VoicePeer peer : peerList.values()) {
|
||||
try {
|
||||
if(peer.recNode != null) {
|
||||
peer.recNode.disconnect(destNode);
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVoiceListenVolume(float f) {
|
||||
for (VoicePeer peer : peerList.values()) {
|
||||
if(peer.gain != null) {
|
||||
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;
|
||||
peer.gain.getGain().setValue(val * 2.0f);
|
||||
}
|
||||
if(peer.panner != null) {
|
||||
peer.panner.setMaxDistance(f * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,360 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSArray;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANPeerEvent;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformWebRTC {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformWebRTC");
|
||||
|
||||
private static boolean isSupported = false;
|
||||
|
||||
public static void initialize() {
|
||||
isSupported = supported0();
|
||||
}
|
||||
|
||||
public static boolean supported() {
|
||||
return isSupported;
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "supported")
|
||||
private static native boolean supported0();
|
||||
|
||||
public static void runScheduledTasks() {
|
||||
|
||||
}
|
||||
|
||||
public static void startRTCLANClient() {
|
||||
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANReadyState")
|
||||
public static native int clientLANReadyState();
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANCloseConnection")
|
||||
public static native void clientLANCloseConnection();
|
||||
|
||||
public static void clientLANSendPacket(byte[] pkt) {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(pkt);
|
||||
try {
|
||||
clientLANSendPacket0(WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANSendPacket")
|
||||
private static native void clientLANSendPacket0(Uint8Array pkt);
|
||||
|
||||
public static byte[] clientLANReadPacket() {
|
||||
Uint8Array arr = clientLANReadPacket0();
|
||||
if(arr != null) {
|
||||
return WASMGCDirectArrayConverter.externU8ArrayToByteArray(arr);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANReadPacket")
|
||||
private static native Uint8Array clientLANReadPacket0();
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANAvailable")
|
||||
private static native int clientLANAvailable();
|
||||
|
||||
public static List<byte[]> clientLANReadAllPacket() {
|
||||
int cnt = clientLANAvailable();
|
||||
if(cnt == 0) {
|
||||
return null;
|
||||
}
|
||||
byte[][] ret = new byte[cnt][];
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
ret[i] = clientLANReadPacket();
|
||||
}
|
||||
return Arrays.asList(ret);
|
||||
}
|
||||
|
||||
public static void clientLANSetICEServersAndConnect(String[] servers) {
|
||||
clientLANSetICEServersAndConnect0(BetterJSStringConverter.stringArrayToJS(servers));
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANSetICEServersAndConnect")
|
||||
private static native void clientLANSetICEServersAndConnect0(JSArray<JSString> servers);
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clearLANClientState")
|
||||
public static native void clearLANClientState();
|
||||
|
||||
public static String clientLANAwaitICECandidate() {
|
||||
return BetterJSStringConverter.stringFromJS(clientLANAwaitICECandidate0());
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANAwaitICECandidate")
|
||||
private static native JSString clientLANAwaitICECandidate0();
|
||||
|
||||
public static String clientLANAwaitDescription() {
|
||||
return BetterJSStringConverter.stringFromJS(clientLANAwaitDescription0());
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANAwaitDescription")
|
||||
private static native JSString clientLANAwaitDescription0();
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANAwaitChannel")
|
||||
public static native boolean clientLANAwaitChannel();
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANClosed")
|
||||
public static native boolean clientLANClosed();
|
||||
|
||||
public static void clientLANSetICECandidate(String candidate) {
|
||||
clientLANSetICECandidate0(BetterJSStringConverter.stringToJS(candidate));
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANSetICECandidate")
|
||||
private static native void clientLANSetICECandidate0(JSString candidate);
|
||||
|
||||
public static void clientLANSetDescription(String description) {
|
||||
clientLANSetDescription0(BetterJSStringConverter.stringToJS(description));
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "clientLANSetDescription")
|
||||
private static native void clientLANSetDescription0(JSString description);
|
||||
|
||||
public static void startRTCLANServer() {
|
||||
|
||||
}
|
||||
|
||||
public static void serverLANInitializeServer(String[] servers) {
|
||||
serverLANInitializeServer0(BetterJSStringConverter.stringArrayToJS(servers));
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "serverLANInitializeServer")
|
||||
private static native void serverLANInitializeServer0(JSArray<JSString> servers);
|
||||
|
||||
@Import(module = "platformWebRTC", name = "serverLANCloseServer")
|
||||
public static native void serverLANCloseServer();
|
||||
|
||||
private static final int EVENT_WEBRTC_ICE = 0;
|
||||
private static final int EVENT_WEBRTC_DESC = 1;
|
||||
private static final int EVENT_WEBRTC_OPEN = 2;
|
||||
private static final int EVENT_WEBRTC_PACKET = 3;
|
||||
private static final int EVENT_WEBRTC_CLOSE = 4;
|
||||
|
||||
private interface JSLANPeerEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getType();
|
||||
|
||||
@JSProperty
|
||||
<T> T getData();
|
||||
|
||||
}
|
||||
|
||||
private interface JSLANPeerHandle extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
JSString getPeerId();
|
||||
|
||||
int countAvailableEvents();
|
||||
|
||||
JSLANPeerEvent nextEvent();
|
||||
|
||||
void writePacket(Uint8Array arr);
|
||||
|
||||
void handleRemoteICECandidates(JSString iceCandidates);
|
||||
|
||||
void handleRemoteDescription(JSString description);
|
||||
|
||||
void mapIPC(String ipcChannel);
|
||||
|
||||
void disconnect();
|
||||
|
||||
}
|
||||
|
||||
private static class LANPeer {
|
||||
|
||||
private final String peerId;
|
||||
private final JSLANPeerHandle handle;
|
||||
private boolean dead = false;
|
||||
|
||||
private LANPeer(String peerId, JSLANPeerHandle handle) {
|
||||
this.peerId = peerId;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
private LANPeerEvent getEvent() {
|
||||
if(dead) return null;
|
||||
JSLANPeerEvent peerEvt = handle.nextEvent();
|
||||
switch(peerEvt.getType()) {
|
||||
case EVENT_WEBRTC_ICE: {
|
||||
return new LANPeerEvent.LANPeerICECandidateEvent(peerId,
|
||||
BetterJSStringConverter.stringFromJS(peerEvt.getData()));
|
||||
}
|
||||
case EVENT_WEBRTC_DESC: {
|
||||
return new LANPeerEvent.LANPeerDescriptionEvent(peerId,
|
||||
BetterJSStringConverter.stringFromJS(peerEvt.getData()));
|
||||
}
|
||||
case EVENT_WEBRTC_OPEN: {
|
||||
return new LANPeerEvent.LANPeerDataChannelEvent(peerId);
|
||||
}
|
||||
case EVENT_WEBRTC_PACKET: {
|
||||
return new LANPeerEvent.LANPeerPacketEvent(peerId,
|
||||
WASMGCDirectArrayConverter.externU8ArrayToByteArray(peerEvt.getData()));
|
||||
}
|
||||
case EVENT_WEBRTC_CLOSE: {
|
||||
return new LANPeerEvent.LANPeerDisconnectEvent(peerId);
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<LANPeerEvent> getAllEvent() {
|
||||
if(dead) return null;
|
||||
int cnt = handle.countAvailableEvents();
|
||||
if(cnt == 0) {
|
||||
return null;
|
||||
}
|
||||
LANPeerEvent[] lst = new LANPeerEvent[cnt];
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
lst[i] = getEvent();
|
||||
}
|
||||
return Arrays.asList(lst);
|
||||
}
|
||||
|
||||
private void writePacket(byte[] pkt) {
|
||||
if(dead) return;
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(pkt);
|
||||
try {
|
||||
handle.writePacket(WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRemoteICECandidates(String iceCandidates) {
|
||||
if(dead) return;
|
||||
handle.handleRemoteICECandidates(BetterJSStringConverter.stringToJS(iceCandidates));
|
||||
}
|
||||
|
||||
private void handleRemoteDescription(String description) {
|
||||
if(dead) return;
|
||||
handle.handleRemoteDescription(BetterJSStringConverter.stringToJS(description));
|
||||
}
|
||||
|
||||
private void mapIPC(String ipcChannel) {
|
||||
if(dead) return;
|
||||
handle.mapIPC(ipcChannel);
|
||||
}
|
||||
|
||||
private void disconnect() {
|
||||
if(!dead) {
|
||||
dead = true;
|
||||
handle.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final Map<String, LANPeer> lanServerPeers = new HashMap<>();
|
||||
|
||||
public static void serverLANCreatePeer(String peer) {
|
||||
JSLANPeerHandle handle = serverLANCreatePeer0(BetterJSStringConverter.stringToJS(peer));
|
||||
if(handle != null) {
|
||||
lanServerPeers.put(peer, new LANPeer(peer, handle));
|
||||
}else {
|
||||
logger.error("Failed to create peer for client \"{}\"!", peer);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformWebRTC", name = "serverLANCreatePeer")
|
||||
private static native JSLANPeerHandle serverLANCreatePeer0(JSString peer);
|
||||
|
||||
public static LANPeerEvent serverLANGetEvent(String peer) {
|
||||
LANPeer lanPeer = lanServerPeers.get(peer);
|
||||
if(lanPeer != null) {
|
||||
return lanPeer.getEvent();
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<LANPeerEvent> serverLANGetAllEvent(String peer) {
|
||||
LANPeer lanPeer = lanServerPeers.get(peer);
|
||||
if(lanPeer != null) {
|
||||
return lanPeer.getAllEvent();
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void serverLANWritePacket(String peer, byte[] data) {
|
||||
LANPeer lanPeer = lanServerPeers.get(peer);
|
||||
if(lanPeer != null) {
|
||||
lanPeer.writePacket(data);
|
||||
}
|
||||
}
|
||||
|
||||
public static void serverLANPeerICECandidates(String peer, String iceCandidates) {
|
||||
LANPeer lanPeer = lanServerPeers.get(peer);
|
||||
if(lanPeer != null) {
|
||||
lanPeer.handleRemoteICECandidates(iceCandidates);
|
||||
}
|
||||
}
|
||||
|
||||
public static void serverLANPeerDescription(String peer, String description) {
|
||||
LANPeer lanPeer = lanServerPeers.get(peer);
|
||||
if(lanPeer != null) {
|
||||
lanPeer.handleRemoteDescription(description);
|
||||
}
|
||||
}
|
||||
|
||||
public static void serverLANPeerMapIPC(String peer, String ipcChannel) {
|
||||
LANPeer lanPeer = lanServerPeers.get(peer);
|
||||
if(lanPeer != null) {
|
||||
lanPeer.mapIPC(ipcChannel);
|
||||
}
|
||||
}
|
||||
|
||||
public static void serverLANDisconnectPeer(String peer) {
|
||||
LANPeer lanPeer = lanServerPeers.remove(peer);
|
||||
if(lanPeer != null) {
|
||||
lanPeer.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public static int countPeers() {
|
||||
return lanServerPeers.size();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,426 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime.JSEagRuntimeEvent;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageEnV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformWebView {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformWebView");
|
||||
|
||||
private static String currentMessageChannelName = null;
|
||||
|
||||
private static IPacketSendCallback packetSendCallback = null;
|
||||
|
||||
private static boolean supportedState = false;
|
||||
private static boolean showingState = false;
|
||||
private static boolean supportForce = false;
|
||||
private static boolean enableCSP = true;
|
||||
private static boolean cspSupport = false;
|
||||
|
||||
private static final int EVENT_CHANNEL_OPEN = 0;
|
||||
private static final int EVENT_CHANNEL_CLOSE = 1;
|
||||
|
||||
private interface JSWebViewChannelEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getEventType();
|
||||
|
||||
@JSProperty
|
||||
JSString getChannelName();
|
||||
|
||||
}
|
||||
|
||||
private static final int EVENT_MESSAGE_STRING = 0;
|
||||
private static final int EVENT_MESSAGE_BINARY = 1;
|
||||
|
||||
private interface JSWebViewMessageEvent extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getEventType();
|
||||
|
||||
@JSProperty
|
||||
JSString getChannelName();
|
||||
|
||||
@JSProperty("eventData")
|
||||
JSString getEventDataString();
|
||||
|
||||
@JSProperty("eventData")
|
||||
ArrayBuffer getEventDataBinary();
|
||||
|
||||
}
|
||||
|
||||
private static final int EVENT_WEBVIEW_CHANNEL = 0;
|
||||
private static final int EVENT_WEBVIEW_MESSAGE = 1;
|
||||
private static final int EVENT_WEBVIEW_PERMISSION_ALLOW = 2;
|
||||
private static final int EVENT_WEBVIEW_PERMISSION_BLOCK = 3;
|
||||
private static final int EVENT_WEBVIEW_PERMISSION_CLEAR = 4;
|
||||
|
||||
private static final List<Runnable> messageQueue = new LinkedList<>();
|
||||
|
||||
private static Runnable setJavaScriptAllowedCurrent = null;
|
||||
private static Runnable setJavaScriptBlockedCurrent = null;
|
||||
private static Runnable setJavaScriptClearedCurrent = null;
|
||||
|
||||
private static int webviewResetSerial = 0;
|
||||
|
||||
@Import(module = "platformWebView", name = "checkSupported")
|
||||
private static native boolean checkSupported();
|
||||
|
||||
@Import(module = "platformWebView", name = "checkCSPSupported")
|
||||
private static native boolean checkCSPSupported();
|
||||
|
||||
static void initialize() {
|
||||
currentMessageChannelName = null;
|
||||
packetSendCallback = null;
|
||||
setJavaScriptAllowedCurrent = null;
|
||||
setJavaScriptBlockedCurrent = null;
|
||||
setJavaScriptClearedCurrent = null;
|
||||
supportedState = checkSupported();
|
||||
cspSupport = checkCSPSupported();
|
||||
if(!supportedState) {
|
||||
logger.error("This browser does not meet the safety requirements for webview support, this feature will be disabled");
|
||||
}else if(!cspSupport) {
|
||||
logger.warn("This browser does not support CSP attribute on iframes! (try Chrome)");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean supported() {
|
||||
return supportedState;
|
||||
}
|
||||
|
||||
public static boolean isShowing() {
|
||||
return showingState;
|
||||
}
|
||||
|
||||
public static void setPacketSendCallback(IPacketSendCallback callback) {
|
||||
packetSendCallback = callback;
|
||||
}
|
||||
|
||||
public static void handleJSEvent(JSEagRuntimeEvent evt) {
|
||||
switch(evt.getEventType() & 31) {
|
||||
case EVENT_WEBVIEW_CHANNEL: {
|
||||
JSWebViewChannelEvent obj = evt.getEventObj();
|
||||
final String channel = BetterJSStringConverter.stringFromJS(obj.getChannelName());
|
||||
switch(obj.getEventType()) {
|
||||
case EVENT_CHANNEL_OPEN: {
|
||||
messageQueue.add(() -> {
|
||||
sendMessageEnToServer(true, channel);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case EVENT_CHANNEL_CLOSE: {
|
||||
messageQueue.add(() -> {
|
||||
sendMessageEnToServer(false, channel);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_WEBVIEW_MESSAGE: {
|
||||
JSWebViewMessageEvent obj = evt.getEventObj();
|
||||
final String channel = BetterJSStringConverter.stringFromJS(obj.getChannelName());
|
||||
switch(obj.getEventType()) {
|
||||
case EVENT_MESSAGE_STRING: {
|
||||
final String data = BetterJSStringConverter.stringFromJS(obj.getEventDataString());
|
||||
messageQueue.add(() -> {
|
||||
sendMessageToServer(channel, CPacketWebViewMessageV4EAG.TYPE_STRING, data.getBytes(StandardCharsets.UTF_8));
|
||||
});
|
||||
break;
|
||||
}
|
||||
case EVENT_MESSAGE_BINARY: {
|
||||
final byte[] dataArr = WASMGCDirectArrayConverter
|
||||
.externU8ArrayToByteArray(new Uint8Array(obj.getEventDataBinary()));
|
||||
messageQueue.add(() -> {
|
||||
sendMessageToServer(channel, CPacketWebViewMessageV4EAG.TYPE_BINARY, dataArr);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_WEBVIEW_PERMISSION_ALLOW: {
|
||||
if(setJavaScriptAllowedCurrent != null) {
|
||||
messageQueue.add(setJavaScriptAllowedCurrent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_WEBVIEW_PERMISSION_BLOCK: {
|
||||
if(setJavaScriptBlockedCurrent != null) {
|
||||
messageQueue.add(setJavaScriptBlockedCurrent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_WEBVIEW_PERMISSION_CLEAR: {
|
||||
if(setJavaScriptClearedCurrent != null) {
|
||||
messageQueue.add(setJavaScriptClearedCurrent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTick() {
|
||||
if(!showingState) {
|
||||
return;
|
||||
}
|
||||
List<Runnable> lst = null;
|
||||
if(messageQueue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
lst = new ArrayList<>(messageQueue);
|
||||
messageQueue.clear();
|
||||
for(int i = 0, l = lst.size(); i < l; ++i) {
|
||||
try {
|
||||
lst.get(i).run();
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception processing webview message!");
|
||||
logger.error(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleMessageFromServer(SPacketWebViewMessageV4EAG packet) {
|
||||
if(showingState && currentMessageChannelName != null) {
|
||||
if(packet.type == SPacketWebViewMessageV4EAG.TYPE_STRING) {
|
||||
sendStringMessage(BetterJSStringConverter.stringToJS(currentMessageChannelName),
|
||||
BetterJSStringConverter.stringToJS(new String(packet.data, StandardCharsets.UTF_8)));
|
||||
}else if(packet.type == SPacketWebViewMessageV4EAG.TYPE_BINARY) {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(packet.data);
|
||||
try {
|
||||
sendBinaryMessage(BetterJSStringConverter.stringToJS(currentMessageChannelName),
|
||||
WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
logger.error("Server tried to send the WebView a message, but the message channel is not open!");
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformWebView", name = "sendStringMessage")
|
||||
private static native void sendStringMessage(JSString ch, JSString str);
|
||||
|
||||
@Import(module = "platformWebView", name = "sendBinaryMessage")
|
||||
private static native void sendBinaryMessage(JSString ch, Uint8Array bin);
|
||||
|
||||
private static void sendMessageToServer(String channelName, int type, byte[] data) {
|
||||
if(channelName.length() > 255) {
|
||||
logger.error("WebView tried to send a message packet, but channel name is too long, max is 255 characters!");
|
||||
return;
|
||||
}
|
||||
if(!channelName.equals(currentMessageChannelName)) {
|
||||
logger.error("WebView tried to send a message packet, but the channel is not open!");
|
||||
return;
|
||||
}
|
||||
if(packetSendCallback != null) {
|
||||
if(!packetSendCallback.sendPacket(new CPacketWebViewMessageV4EAG(type, data))) {
|
||||
logger.error("WebView tried to send a packet to the server, but the server does not support this protocol!");
|
||||
}
|
||||
}else {
|
||||
logger.error("WebView tried to send a message, but no callback for sending packets is set!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendMessageEnToServer(boolean messageChannelOpen, String channelName) {
|
||||
if(channelName.length() > 255) {
|
||||
logger.error("WebView tried to {} a channel, but channel name is too long, max is 255 characters!", messageChannelOpen ? "open" : "close");
|
||||
return;
|
||||
}
|
||||
if(messageChannelOpen && currentMessageChannelName != null) {
|
||||
logger.error("WebView tried to open channel, but a channel is already open!");
|
||||
sendMessageEnToServer(false, currentMessageChannelName);
|
||||
}
|
||||
if(!messageChannelOpen && currentMessageChannelName != null && !currentMessageChannelName.equals(channelName)) {
|
||||
logger.error("WebView tried to close the wrong channel!");
|
||||
}
|
||||
if(!messageChannelOpen && currentMessageChannelName == null) {
|
||||
logger.error("WebView tried to close channel, but the channel is not open!");
|
||||
return;
|
||||
}
|
||||
if(packetSendCallback != null) {
|
||||
if(!packetSendCallback.sendPacket(new CPacketWebViewMessageEnV4EAG(messageChannelOpen, messageChannelOpen ? channelName : null))) {
|
||||
logger.error("WebView tried to send a packet to the server, but the server does not support this protocol!");
|
||||
return;
|
||||
}
|
||||
if(messageChannelOpen) {
|
||||
logger.info("WebView opened message channel to server: \"{}\"", channelName);
|
||||
currentMessageChannelName = channelName;
|
||||
}else {
|
||||
logger.info("WebView closed message channel to server: \"{}\"", currentMessageChannelName);
|
||||
currentMessageChannelName = null;
|
||||
}
|
||||
}else {
|
||||
logger.error("WebView tried to send a message, but no callback for sending packets is set!");
|
||||
}
|
||||
}
|
||||
|
||||
private interface JSWebViewOptions extends JSObject {
|
||||
|
||||
@JSProperty("uri")
|
||||
void setURI(JSString title);
|
||||
|
||||
@JSProperty
|
||||
void setBlob(Uint8Array data);
|
||||
|
||||
}
|
||||
|
||||
@JSBody(params = { "a", "b", "c", "d", "e" }, script = "return { contentMode: a, fallbackTitle: b, "
|
||||
+ "scriptEnabled: c, strictCSPEnable: d, serverMessageAPIEnabled: e};")
|
||||
private static native JSWebViewOptions makeOptions(int contentMode, JSString fallbackTitle, boolean scriptEnabled,
|
||||
boolean strictCSPEnable, boolean serverMessageAPIEnabled);
|
||||
|
||||
private static int hashPermissionFlags(WebViewOptions opts) {
|
||||
int i = (opts.scriptEnabled ? 1 : 0);
|
||||
i |= ((enableCSP && cspSupport && opts.strictCSPEnable) ? 0 : 2);
|
||||
i |= (opts.serverMessageAPIEnabled ? 4 : 0);
|
||||
return i;
|
||||
}
|
||||
|
||||
public static void beginShowing(final WebViewOptions options, int x, int y, int w, int h) {
|
||||
if(!supported()) {
|
||||
return;
|
||||
}
|
||||
if(showingState) {
|
||||
endShowing();
|
||||
}
|
||||
showingState = true;
|
||||
++webviewResetSerial;
|
||||
|
||||
messageQueue.clear();
|
||||
|
||||
int state = BEGIN_SHOWING_DIRECT;
|
||||
if(options.scriptEnabled) {
|
||||
PermissionsCache.Permission perm = PermissionsCache.getJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(options));
|
||||
if(perm == null) {
|
||||
state = BEGIN_SHOWING_ENABLE_JAVASCRIPT;
|
||||
}else if(!perm.choice) {
|
||||
state = BEGIN_SHOWING_CONTENT_BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isBlob = options.contentMode == EnumWebViewContentMode.BLOB_BASED;
|
||||
JSWebViewOptions opts = makeOptions(isBlob ? 1 : 0, BetterJSStringConverter.stringToJS(options.fallbackTitle),
|
||||
options.scriptEnabled, options.strictCSPEnable, options.serverMessageAPIEnabled);
|
||||
if(isBlob) {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(options.blob);
|
||||
try {
|
||||
opts.setBlob(WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
beginShowing0(state, opts, x, y, w, h);
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}else {
|
||||
opts.setURI(BetterJSStringConverter.stringToJS(options.url.toString()));
|
||||
beginShowing0(state, opts, x, y, w, h);
|
||||
}
|
||||
|
||||
final int serial = webviewResetSerial;
|
||||
setJavaScriptAllowedCurrent = () -> {
|
||||
if(serial == webviewResetSerial) {
|
||||
PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(options), true);
|
||||
}
|
||||
};
|
||||
setJavaScriptBlockedCurrent = () -> {
|
||||
if(serial == webviewResetSerial) {
|
||||
PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(options), false);
|
||||
}
|
||||
};
|
||||
setJavaScriptClearedCurrent = () -> {
|
||||
if(serial == webviewResetSerial) {
|
||||
PermissionsCache.clearJavaScriptAllowed(options.permissionsOriginUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final int BEGIN_SHOWING_DIRECT = 0;
|
||||
private static final int BEGIN_SHOWING_ENABLE_JAVASCRIPT = 1;
|
||||
private static final int BEGIN_SHOWING_CONTENT_BLOCKED = 2;
|
||||
|
||||
@Import(module = "platformWebView", name = "beginShowing")
|
||||
private static native void beginShowing0(int state, JSWebViewOptions options, int x, int y, int w, int h);
|
||||
|
||||
@Import(module = "platformWebView", name = "resize")
|
||||
public static native void resize(int x, int y, int w, int h);
|
||||
|
||||
public static void endShowing() {
|
||||
if(!supported()) {
|
||||
return;
|
||||
}
|
||||
++webviewResetSerial;
|
||||
if(showingState) {
|
||||
showingState = false;
|
||||
endShowing0();
|
||||
}
|
||||
if(currentMessageChannelName != null) {
|
||||
sendMessageEnToServer(false, currentMessageChannelName);
|
||||
}
|
||||
messageQueue.clear();
|
||||
setJavaScriptAllowedCurrent = null;
|
||||
setJavaScriptBlockedCurrent = null;
|
||||
setJavaScriptClearedCurrent = null;
|
||||
}
|
||||
|
||||
@Import(module = "platformWebView", name = "endShowing")
|
||||
private static native void endShowing0();
|
||||
|
||||
public static boolean fallbackSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void launchFallback(WebViewOptions options) {
|
||||
|
||||
}
|
||||
|
||||
public static boolean fallbackRunning() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getFallbackURL() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void endFallbackServer() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,385 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DirectMalloc;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DirectMallocByteBuffer implements ByteBuffer {
|
||||
|
||||
final Address address;
|
||||
final boolean original;
|
||||
|
||||
private final int capacity;
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
DirectMallocByteBuffer(Address address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
|
||||
DirectMallocByteBuffer(Address address, int capacity, int position, int limit, int mark, boolean original) {
|
||||
this.address = address;
|
||||
this.capacity = capacity;
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int limit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() {
|
||||
return limit - position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRemaining() {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer duplicate() {
|
||||
return new DirectMallocByteBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte get() {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return address.add(position++).getByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte b) {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
address.add(position++).putByte(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte get(int index) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index).getByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(int index, byte b) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index).putByte(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer get(byte[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > dst.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, offset, address.add(position), length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer get(byte[] dst) {
|
||||
int dstLen = dst.length;
|
||||
if(position + dstLen > limit) throw Buffer.makeIOOBE(position + dstLen - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, 0, address.add(position), dstLen);
|
||||
position += dstLen;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(ByteBuffer src) {
|
||||
if(src instanceof DirectMallocByteBuffer) {
|
||||
DirectMallocByteBuffer c = (DirectMallocByteBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
DirectMalloc.memcpy(address.add(position), c.address.add(c.position), l);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
Address addrBase = address.add(position);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
addrBase.add(i).putByte(src.get());
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte[] src, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > src.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position), src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte[] src) {
|
||||
int srcLen = src.length;
|
||||
if(position + srcLen > limit) throw Buffer.makeIOOBE(position + srcLen - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position), src, 0, srcLen);
|
||||
position += srcLen;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar() {
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
char c = address.add(position).getChar();
|
||||
position += 2;
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putChar(char value) {
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
address.add(position).putChar(value);
|
||||
position += 2;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(int index) {
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index).getChar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putChar(int index, char value) {
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index).putChar(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
short s = address.add(position).getShort();
|
||||
position += 2;
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putShort(short value) {
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
address.add(position).putShort(value);
|
||||
position += 2;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int index) {
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index).getShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putShort(int index, short value) {
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index).putShort(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer asShortBuffer() {
|
||||
return new DirectMallocShortBuffer(address, capacity >> 1, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
int i = address.add(position).getInt();
|
||||
position += 4;
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putInt(int value) {
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
address.add(position).putInt(value);
|
||||
position += 4;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int index) {
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index).getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putInt(int index, int value) {
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index).putInt(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer asIntBuffer() {
|
||||
return new DirectMallocIntBuffer(address, capacity >> 2, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
if(position + 8 > limit) throw Buffer.makeIOOBE(position);
|
||||
long l = address.add(position).getLong();
|
||||
position += 8;
|
||||
return l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putLong(long value) {
|
||||
if(position + 8 > limit) throw Buffer.makeIOOBE(position);
|
||||
address.add(position).putLong(value);
|
||||
position += 8;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int index) {
|
||||
if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index).getLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putLong(int index, long value) {
|
||||
if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index).putLong(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
float f = address.add(position).getFloat();
|
||||
position += 4;
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putFloat(float value) {
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
address.add(position).putFloat(value);
|
||||
position += 4;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int index) {
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index).getFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putFloat(int index, float value) {
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index).putFloat(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer asFloatBuffer() {
|
||||
return new DirectMallocFloatBuffer(address, capacity >> 2, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mark() {
|
||||
mark = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer clear() {
|
||||
position = 0;
|
||||
limit = capacity;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer flip() {
|
||||
limit = position;
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer rewind() {
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,238 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DirectMalloc;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DirectMallocFloatBuffer implements FloatBuffer {
|
||||
|
||||
final Address address;
|
||||
final boolean original;
|
||||
|
||||
private final int capacity;
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
private static final int SHIFT = 2;
|
||||
|
||||
DirectMallocFloatBuffer(Address address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
|
||||
DirectMallocFloatBuffer(Address address, int capacity, int position, int limit, int mark, boolean original) {
|
||||
this.address = address;
|
||||
this.capacity = capacity;
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int limit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() {
|
||||
return limit - position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRemaining() {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer duplicate() {
|
||||
return new DirectMallocFloatBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float get() {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return address.add((position++) << SHIFT).getFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float b) {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
address.add((position++) << SHIFT).putFloat(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float get(int index) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index << SHIFT).getFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(int index, float b) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index << SHIFT).putFloat(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getElement(int index) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index << SHIFT).getFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, float value) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index << SHIFT).putFloat(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer get(float[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > dst.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, offset, address.add(position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer get(float[] dst) {
|
||||
int dstLen = dst.length;
|
||||
if(position + dstLen > limit) throw Buffer.makeIOOBE(position + dstLen - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, 0, address.add(position << SHIFT), dstLen);
|
||||
position += dstLen;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(FloatBuffer src) {
|
||||
if(src instanceof DirectMallocFloatBuffer) {
|
||||
DirectMallocFloatBuffer c = (DirectMallocFloatBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
DirectMalloc.memcpy(address.add(position << SHIFT), c.address.add(c.position << SHIFT), l << SHIFT);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
Address addrBase = address.add(position << SHIFT);
|
||||
for(int i = 0, ll = l << SHIFT; i < ll; i += 4) {
|
||||
addrBase.add(i).putFloat(src.get());
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float[] src, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > src.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position << SHIFT), src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float[] src) {
|
||||
if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position << SHIFT), src, 0, src.length);
|
||||
position += src.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer mark() {
|
||||
mark = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer clear() {
|
||||
position = 0;
|
||||
limit = capacity;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer flip() {
|
||||
limit = position;
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer rewind() {
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DirectMalloc;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DirectMallocIntBuffer implements IntBuffer {
|
||||
|
||||
final Address address;
|
||||
final boolean original;
|
||||
|
||||
private final int capacity;
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
private static final int SHIFT = 2;
|
||||
|
||||
DirectMallocIntBuffer(Address address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
|
||||
DirectMallocIntBuffer(Address address, int capacity, int position, int limit, int mark, boolean original) {
|
||||
this.address = address;
|
||||
this.capacity = capacity;
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int limit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() {
|
||||
return limit - position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRemaining() {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer duplicate() {
|
||||
return new DirectMallocIntBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get() {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return address.add((position++) << SHIFT).getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int b) {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
address.add((position++) << SHIFT).putInt(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get(int index) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index << SHIFT).getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int index, int b) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index << SHIFT).putInt(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getElement(int index) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index << SHIFT).getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, int value) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index << SHIFT).putInt(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer get(int[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > dst.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, offset, address.add(position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer get(int[] dst) {
|
||||
int dstLen = dst.length;
|
||||
if(position + dstLen > limit) throw Buffer.makeIOOBE(position + dstLen - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, 0, address.add(position << SHIFT), dstLen);
|
||||
position += dstLen;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(IntBuffer src) {
|
||||
if(src instanceof DirectMallocIntBuffer) {
|
||||
DirectMallocIntBuffer c = (DirectMallocIntBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
DirectMalloc.memcpy(address.add(position << SHIFT), c.address.add(c.position << SHIFT), l << SHIFT);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
Address addrBase = address.add(position << SHIFT);
|
||||
for(int i = 0, ll = l << SHIFT; i < ll; i += 4) {
|
||||
addrBase.add(i).putInt(src.get());
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int[] src, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > src.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position << SHIFT), src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int[] src) {
|
||||
int srcLen = src.length;
|
||||
if(position + srcLen > limit) throw Buffer.makeIOOBE(position + srcLen - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position << SHIFT), src, 0, srcLen);
|
||||
position += src.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer mark() {
|
||||
mark = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer clear() {
|
||||
position = 0;
|
||||
limit = capacity;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer flip() {
|
||||
limit = position;
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer rewind() {
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DirectMalloc;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DirectMallocShortBuffer implements ShortBuffer {
|
||||
|
||||
final Address address;
|
||||
final boolean original;
|
||||
|
||||
private final int capacity;
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
private static final int SHIFT = 1;
|
||||
|
||||
DirectMallocShortBuffer(Address address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
|
||||
DirectMallocShortBuffer(Address address, int capacity, int position, int limit, int mark, boolean original) {
|
||||
this.address = address;
|
||||
this.capacity = capacity;
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int limit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() {
|
||||
return limit - position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRemaining() {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer duplicate() {
|
||||
return new DirectMallocShortBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short get() {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return address.add((position++) << SHIFT).getShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short b) {
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
address.add((position++) << SHIFT).putShort(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short get(int index) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index << SHIFT).getShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(int index, short b) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index << SHIFT).putShort(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getElement(int index) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return address.add(index << SHIFT).getShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, short value) {
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
address.add(index << SHIFT).putShort(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer get(short[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > dst.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, offset, address.add(position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer get(short[] dst) {
|
||||
int dstLen = dst.length;
|
||||
if(position + dstLen > limit) throw Buffer.makeIOOBE(position + dstLen - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(dst, 0, address.add(position << SHIFT), dstLen);
|
||||
position += dstLen;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(ShortBuffer src) {
|
||||
if(src instanceof DirectMallocShortBuffer) {
|
||||
DirectMallocShortBuffer c = (DirectMallocShortBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
DirectMalloc.memcpy(address.add(position << SHIFT), c.address.add(c.position << SHIFT), l << SHIFT);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
Address addrBase = address.add(position << SHIFT);
|
||||
for(int i = 0, ll = l << SHIFT; i < ll; i += 2) {
|
||||
addrBase.add(i).putShort(src.get());
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short[] src, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > src.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position << SHIFT), src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short[] src) {
|
||||
int srcLen = src.length;
|
||||
if(position + srcLen > limit) throw Buffer.makeIOOBE(position + srcLen - 1);
|
||||
WASMGCDirectArrayCopy.memcpy(address.add(position << SHIFT), src, 0, srcLen);
|
||||
position += src.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer mark() {
|
||||
mark = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer clear() {
|
||||
position = 0;
|
||||
limit = capacity;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer flip() {
|
||||
limit = position;
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer rewind() {
|
||||
position = 0;
|
||||
mark = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DirectMalloc;
|
||||
import org.teavm.interop.Import;
|
||||
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.Uint16Array;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
import org.teavm.jso.typedarrays.Uint8ClampedArray;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCBufferAllocator {
|
||||
|
||||
private static final boolean enableBufferOverflowCheck = false;
|
||||
|
||||
public static Address malloc(int size) {
|
||||
if(size == 0) {
|
||||
throw new IllegalArgumentException("Tried to allocate 0 bytes!");
|
||||
}
|
||||
Address addr;
|
||||
if(enableBufferOverflowCheck) {
|
||||
addr = DirectMalloc.malloc(size + 12);
|
||||
if(addr.toInt() == 0) {
|
||||
throw new OutOfMemoryError("DirectMalloc returned null pointer!");
|
||||
}
|
||||
int tag = (int)(Math.random() * 2147483647.0);
|
||||
addr.putInt(size);
|
||||
addr.add(4).putInt(tag);
|
||||
addr.add(size + 8).putInt(tag);
|
||||
addr = addr.add(8);
|
||||
}else {
|
||||
addr = DirectMalloc.malloc(size);
|
||||
if(addr.toInt() == 0) {
|
||||
throw new OutOfMemoryError("DirectMalloc returned null pointer!");
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
public static Address calloc(int size) {
|
||||
Address addr;
|
||||
if(enableBufferOverflowCheck) {
|
||||
if(size == 0) {
|
||||
throw new OutOfMemoryError("Tried to allocate 0 bytes!");
|
||||
}
|
||||
addr = DirectMalloc.calloc(size + 12);
|
||||
if(addr.toInt() == 0) {
|
||||
throw new OutOfMemoryError("DirectMalloc returned null pointer!");
|
||||
}
|
||||
int tag = (int)(Math.random() * 2147483647.0);
|
||||
addr.putInt(size);
|
||||
addr.add(4).putInt(tag);
|
||||
addr.add(size + 8).putInt(tag);
|
||||
addr = addr.add(8);
|
||||
}else {
|
||||
addr = DirectMalloc.calloc(size);
|
||||
if(addr.toInt() == 0) {
|
||||
throw new OutOfMemoryError("DirectMalloc returned null pointer!");
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
public static void free(Address ptr) {
|
||||
if(ptr.toInt() != 0) {
|
||||
if(enableBufferOverflowCheck) {
|
||||
ptr = ptr.add(-8);
|
||||
int size = ptr.getInt();
|
||||
int tag = ptr.add(4).getInt();
|
||||
if(tag != ptr.add(size + 8).getInt()) {
|
||||
throw new RuntimeException("Detected a buffer write overflow");
|
||||
}
|
||||
DirectMalloc.free(ptr);
|
||||
}else {
|
||||
DirectMalloc.free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuffer allocateByteBuffer(int size) {
|
||||
return new DirectMallocByteBuffer(malloc(size), size, true);
|
||||
}
|
||||
|
||||
public static ShortBuffer allocateShortBuffer(int size) {
|
||||
return new DirectMallocShortBuffer(malloc(size << 1), size, true);
|
||||
}
|
||||
|
||||
public static IntBuffer allocateIntBuffer(int size) {
|
||||
return new DirectMallocIntBuffer(malloc(size << 2), size, true);
|
||||
}
|
||||
|
||||
public static FloatBuffer allocateFloatBuffer(int size) {
|
||||
return new DirectMallocFloatBuffer(malloc(size << 2), size, true);
|
||||
}
|
||||
|
||||
public static void freeByteBuffer(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
if(buf.original) {
|
||||
WASMGCBufferAllocator.free(buf.address);
|
||||
}else {
|
||||
throwNotOriginal(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public static void freeShortBuffer(ShortBuffer buffer) {
|
||||
DirectMallocShortBuffer buf = (DirectMallocShortBuffer)buffer;
|
||||
if(buf.original) {
|
||||
WASMGCBufferAllocator.free(buf.address);
|
||||
}else {
|
||||
throwNotOriginal(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public static void freeIntBuffer(IntBuffer buffer) {
|
||||
DirectMallocIntBuffer buf = (DirectMallocIntBuffer)buffer;
|
||||
if(buf.original) {
|
||||
WASMGCBufferAllocator.free(buf.address);
|
||||
}else {
|
||||
throwNotOriginal(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public static void freeFloatBuffer(FloatBuffer buffer) {
|
||||
DirectMallocFloatBuffer buf = (DirectMallocFloatBuffer)buffer;
|
||||
if(buf.original) {
|
||||
WASMGCBufferAllocator.free(buf.address);
|
||||
}else {
|
||||
throwNotOriginal(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public static Address getByteBufferAddress(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return buf.address.add(buf.position());
|
||||
}
|
||||
|
||||
public static Address getShortBufferAddress(ShortBuffer buffer) {
|
||||
DirectMallocShortBuffer buf = (DirectMallocShortBuffer)buffer;
|
||||
return buf.address.add(buf.position() << 1);
|
||||
}
|
||||
|
||||
public static Address getIntBufferAddress(IntBuffer buffer) {
|
||||
DirectMallocIntBuffer buf = (DirectMallocIntBuffer)buffer;
|
||||
return buf.address.add(buf.position() << 2);
|
||||
}
|
||||
|
||||
public static Address getFloatBufferAddress(FloatBuffer buffer) {
|
||||
DirectMallocFloatBuffer buf = (DirectMallocFloatBuffer)buffer;
|
||||
return buf.address.add(buf.position() << 2);
|
||||
}
|
||||
|
||||
public static Int8Array getByteBufferView(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return getByteBufferView0(buf.address.add(buf.position()), buf.remaining());
|
||||
}
|
||||
|
||||
@Import(module = "WASMGCBufferAllocator", name = "getByteBufferView")
|
||||
public static native Int8Array getByteBufferView0(Address addr, int length);
|
||||
|
||||
public static Uint8Array getUnsignedByteBufferView(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return getUnsignedByteBufferView0(buf.address.add(buf.position()), buf.remaining());
|
||||
}
|
||||
|
||||
public static Uint8Array getUnsignedByteBufferView(ShortBuffer buffer) {
|
||||
DirectMallocIntBuffer buf = (DirectMallocIntBuffer)buffer;
|
||||
return getUnsignedByteBufferView0(buf.address.add(buf.position()), buf.remaining() << 1);
|
||||
}
|
||||
|
||||
public static Uint8Array getUnsignedByteBufferView(IntBuffer buffer) {
|
||||
DirectMallocIntBuffer buf = (DirectMallocIntBuffer)buffer;
|
||||
return getUnsignedByteBufferView0(buf.address.add(buf.position()), buf.remaining() << 2);
|
||||
}
|
||||
|
||||
@Import(module = "WASMGCBufferAllocator", name = "getUnsignedByteBufferView")
|
||||
public static native Uint8Array getUnsignedByteBufferView0(Address addr, int length);
|
||||
|
||||
public static Uint8ClampedArray getUnsignedClampedByteBufferView(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return getUnsignedClampedByteBufferView0(buf.address.add(buf.position()), buf.remaining());
|
||||
}
|
||||
|
||||
@Import(module = "WASMGCBufferAllocator", name = "getUnsignedClampedByteBufferView")
|
||||
public static native Uint8ClampedArray getUnsignedClampedByteBufferView0(Address addr, int length);
|
||||
|
||||
public static Int16Array getShortBufferView(ShortBuffer buffer) {
|
||||
DirectMallocShortBuffer buf = (DirectMallocShortBuffer)buffer;
|
||||
return getShortBufferView0(buf.address.add(buf.position() << 1), buf.remaining());
|
||||
}
|
||||
|
||||
public static Int16Array getShortBufferView(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return getShortBufferView0(buf.address.add(buf.position()), buf.remaining() >> 1);
|
||||
}
|
||||
|
||||
@Import(module = "WASMGCBufferAllocator", name = "getShortBufferView")
|
||||
public static native Int16Array getShortBufferView0(Address addr, int length);
|
||||
|
||||
public static Uint16Array getUnsignedShortBufferView(ShortBuffer buffer) {
|
||||
DirectMallocShortBuffer buf = (DirectMallocShortBuffer)buffer;
|
||||
return getUnsignedShortBufferView0(buf.address.add(buf.position() << 1), buf.remaining());
|
||||
}
|
||||
|
||||
public static Uint16Array getUnsignedShortBufferView(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return getUnsignedShortBufferView0(buf.address.add(buf.position()), buf.remaining() >> 1);
|
||||
}
|
||||
|
||||
@Import(module = "WASMGCBufferAllocator", name = "getUnsignedShortBufferView")
|
||||
public static native Uint16Array getUnsignedShortBufferView0(Address addr, int length);
|
||||
|
||||
public static Int32Array getIntBufferView(IntBuffer buffer) {
|
||||
DirectMallocIntBuffer buf = (DirectMallocIntBuffer)buffer;
|
||||
return getIntBufferView0(buf.address.add(buf.position() << 2), buf.remaining());
|
||||
}
|
||||
|
||||
public static Int32Array getIntBufferView(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return getIntBufferView0(buf.address.add(buf.position()), buf.remaining() >> 2);
|
||||
}
|
||||
|
||||
@Import(module = "WASMGCBufferAllocator", name = "getIntBufferView")
|
||||
public static native Int32Array getIntBufferView0(Address addr, int length);
|
||||
|
||||
public static Float32Array getFloatBufferView(FloatBuffer buffer) {
|
||||
DirectMallocFloatBuffer buf = (DirectMallocFloatBuffer)buffer;
|
||||
return getFloatBufferView0(buf.address.add(buf.position() << 2), buf.remaining());
|
||||
}
|
||||
|
||||
public static Float32Array getFloatBufferView(ByteBuffer buffer) {
|
||||
DirectMallocByteBuffer buf = (DirectMallocByteBuffer)buffer;
|
||||
return getFloatBufferView0(buf.address.add(buf.position()), buf.remaining() >> 2);
|
||||
}
|
||||
|
||||
@Import(module = "WASMGCBufferAllocator", name = "getFloatBufferView")
|
||||
public static native Float32Array getFloatBufferView0(Address addr, int length);
|
||||
|
||||
private static void throwNotOriginal(Object clazz) {
|
||||
throw notOriginal(clazz);
|
||||
}
|
||||
|
||||
public static class WrongBufferClassType extends RuntimeException {
|
||||
public WrongBufferClassType(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static WrongBufferClassType notOriginal(Object clazz) {
|
||||
return new WrongBufferClassType("Tried to pass a " + clazz.getClass().getSimpleName() + " which was not the original buffer");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,397 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DirectMalloc;
|
||||
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.Uint16Array;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
import org.teavm.jso.typedarrays.Uint8ClampedArray;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCDirectArrayConverter {
|
||||
|
||||
public static ByteBuffer byteArrayToBuffer(byte[] byteArray) {
|
||||
int len = byteArray.length;
|
||||
Address ret = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, byteArray, 0, len);
|
||||
return new DirectMallocByteBuffer(ret, len, true);
|
||||
}
|
||||
|
||||
public static ByteBuffer byteArrayToBuffer(byte[] byteArray, int offset, int length) {
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > byteArray.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
Address ret = WASMGCBufferAllocator.malloc(length);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, byteArray, offset, length);
|
||||
return new DirectMallocByteBuffer(ret, length, true);
|
||||
}
|
||||
|
||||
public static ShortBuffer shortArrayToBuffer(short[] shortArray) {
|
||||
int len = shortArray.length;
|
||||
Address ret = WASMGCBufferAllocator.malloc(len << 1);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, shortArray, 0, len);
|
||||
return new DirectMallocShortBuffer(ret, len, true);
|
||||
}
|
||||
|
||||
public static ShortBuffer shortArrayToBuffer(short[] shortArray, int offset, int length) {
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > shortArray.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
Address ret = WASMGCBufferAllocator.malloc(length << 1);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, shortArray, offset, length);
|
||||
return new DirectMallocShortBuffer(ret, length, true);
|
||||
}
|
||||
|
||||
public static IntBuffer intArrayToBuffer(int[] intArray) {
|
||||
int len = intArray.length;
|
||||
Address ret = WASMGCBufferAllocator.malloc(len << 2);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, intArray, 0, len);
|
||||
return new DirectMallocIntBuffer(ret, len, true);
|
||||
}
|
||||
|
||||
public static IntBuffer intArrayToBuffer(int[] intArray, int offset, int length) {
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > intArray.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
Address ret = WASMGCBufferAllocator.malloc(length << 2);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, intArray, offset, length);
|
||||
return new DirectMallocIntBuffer(ret, length, true);
|
||||
}
|
||||
|
||||
public static FloatBuffer floatArrayToBuffer(float[] floatArray) {
|
||||
int len = floatArray.length;
|
||||
Address ret = WASMGCBufferAllocator.malloc(len << 2);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, floatArray, 0, len);
|
||||
return new DirectMallocFloatBuffer(ret, len, true);
|
||||
}
|
||||
|
||||
public static FloatBuffer floatArrayToBuffer(float[] floatArray, int offset, int length) {
|
||||
if(offset < 0) throw Buffer.makeIOOBE(offset);
|
||||
if(offset + length > floatArray.length) throw Buffer.makeIOOBE(offset + length - 1);
|
||||
Address ret = WASMGCBufferAllocator.malloc(length << 2);
|
||||
WASMGCDirectArrayCopy.memcpy(ret, floatArray, offset, length);
|
||||
return new DirectMallocFloatBuffer(ret, length, true);
|
||||
}
|
||||
|
||||
private static final Uint8Array UINT8ZeroLength = new Uint8Array(0);
|
||||
private static final Uint8ClampedArray UINT8CZeroLength = new Uint8ClampedArray(0);
|
||||
private static final Int8Array INT8ZeroLength = new Int8Array(0);
|
||||
private static final Uint16Array UINT16ZeroLength = new Uint16Array(0);
|
||||
private static final Int16Array INT16ZeroLength = new Int16Array(0);
|
||||
private static final Int32Array INT32ZeroLength = new Int32Array(0);
|
||||
private static final Float32Array FLOAT32ZeroLength = new Float32Array(0);
|
||||
|
||||
public static Uint8Array byteArrayToExternU8Array(byte[] byteArray) {
|
||||
int len = byteArray.length;
|
||||
if(len == 0) {
|
||||
return UINT8ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, byteArray, 0, len);
|
||||
Uint8Array ret = new Uint8Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getUnsignedByteBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Uint8ClampedArray byteArrayToExternU8CArray(byte[] byteArray) {
|
||||
int len = byteArray.length;
|
||||
if(len == 0) {
|
||||
return UINT8CZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, byteArray, 0, len);
|
||||
Uint8ClampedArray ret = new Uint8ClampedArray(len);
|
||||
ret.set(WASMGCBufferAllocator.getUnsignedClampedByteBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Int8Array byteArrayToExternI8Array(byte[] byteArray) {
|
||||
int len = byteArray.length;
|
||||
if(len == 0) {
|
||||
return INT8ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, byteArray, 0, len);
|
||||
Int8Array ret = new Int8Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getByteBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Uint16Array byteArrayToExternU16Array(byte[] byteArray) {
|
||||
int len = byteArray.length & 0xFFFFFFFE;
|
||||
if(len == 0) {
|
||||
return UINT16ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, byteArray, 0, len);
|
||||
len >>= 1;
|
||||
Uint16Array ret = new Uint16Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getUnsignedShortBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Int16Array byteArrayToExternI16Array(byte[] byteArray) {
|
||||
int len = byteArray.length & 0xFFFFFFFE;
|
||||
if(len == 0) {
|
||||
return INT16ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, byteArray, 0, len);
|
||||
len >>= 1;
|
||||
Int16Array ret = new Int16Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getShortBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Uint16Array shortArrayToExternU16Array(short[] shortArray) {
|
||||
int len = shortArray.length;
|
||||
if(len == 0) {
|
||||
return UINT16ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 1);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, shortArray, 0, len);
|
||||
Uint16Array ret = new Uint16Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getUnsignedShortBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Int16Array shortArrayToExternI16Array(short[] shortArray) {
|
||||
int len = shortArray.length;
|
||||
if(len == 0) {
|
||||
return INT16ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 1);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, shortArray, 0, len);
|
||||
Int16Array ret = new Int16Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getShortBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Int32Array byteArrayToExternI32Array(byte[] byteArray) {
|
||||
int len = byteArray.length & 0xFFFFFFFC;
|
||||
if(len == 0) {
|
||||
return INT32ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, byteArray, 0, len);
|
||||
len >>= 2;
|
||||
Int32Array ret = new Int32Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getIntBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Int32Array intArrayToExternI32Array(int[] intArray) {
|
||||
int len = intArray.length;
|
||||
if(len == 0) {
|
||||
return INT32ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 2);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, intArray, 0, len);
|
||||
Int32Array ret = new Int32Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getIntBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Float32Array byteArrayToExternF32Array(byte[] byteArray) {
|
||||
int len = byteArray.length & 0xFFFFFFFC;
|
||||
if(len == 0) {
|
||||
return FLOAT32ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, byteArray, 0, len);
|
||||
len >>= 2;
|
||||
Float32Array ret = new Float32Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getFloatBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Float32Array floatArrayToExternF32Array(float[] floatArray) {
|
||||
int len = floatArray.length;
|
||||
if(len == 0) {
|
||||
return FLOAT32ZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 2);
|
||||
WASMGCDirectArrayCopy.memcpy(addr, floatArray, 0, len);
|
||||
Float32Array ret = new Float32Array(len);
|
||||
ret.set(WASMGCBufferAllocator.getFloatBufferView0(addr, len));
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static final byte[] byteZeroLength = new byte[0];
|
||||
private static final short[] shortZeroLength = new short[0];
|
||||
private static final int[] intZeroLength = new int[0];
|
||||
private static final float[] floatZeroLength = new float[0];
|
||||
|
||||
public static byte[] externU8ArrayToByteArray(Uint8Array U8Array) {
|
||||
int len = U8Array.getLength();
|
||||
if(len == 0) {
|
||||
return byteZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCBufferAllocator.getUnsignedByteBufferView0(addr, len).set(U8Array);
|
||||
byte[] ret = new byte[len];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] externU8CArrayToByteArray(Uint8ClampedArray U8CArray) {
|
||||
int len = U8CArray.getLength();
|
||||
if(len == 0) {
|
||||
return byteZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCBufferAllocator.getUnsignedClampedByteBufferView0(addr, len).set(U8CArray);
|
||||
byte[] ret = new byte[len];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] externI8ArrayToByteArray(Int8Array I8Array) {
|
||||
int len = I8Array.getLength();
|
||||
if(len == 0) {
|
||||
return byteZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len);
|
||||
WASMGCBufferAllocator.getByteBufferView0(addr, len).set(I8Array);
|
||||
byte[] ret = new byte[len];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] externU16ArrayToByteArray(Uint16Array U16Array) {
|
||||
int len = U16Array.getLength();
|
||||
if(len == 0) {
|
||||
return byteZeroLength;
|
||||
}
|
||||
int len2 = len << 1;
|
||||
Address addr = WASMGCBufferAllocator.malloc(len2);
|
||||
WASMGCBufferAllocator.getUnsignedShortBufferView0(addr, len).set(U16Array);
|
||||
byte[] ret = new byte[len2];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len2);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] externI16ArrayToByteArray(Int16Array I16Array) {
|
||||
int len = I16Array.getLength();
|
||||
if(len == 0) {
|
||||
return byteZeroLength;
|
||||
}
|
||||
int len2 = len << 1;
|
||||
Address addr = WASMGCBufferAllocator.malloc(len2);
|
||||
WASMGCBufferAllocator.getShortBufferView0(addr, len).set(I16Array);
|
||||
byte[] ret = new byte[len2];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len2);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static short[] externU16ArrayToShortArray(Uint16Array U16Array) {
|
||||
int len = U16Array.getLength();
|
||||
if(len == 0) {
|
||||
return shortZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 1);
|
||||
WASMGCBufferAllocator.getUnsignedShortBufferView0(addr, len).set(U16Array);
|
||||
short[] ret = new short[len];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static short[] externI16ArrayToShortArray(Int16Array I16Array) {
|
||||
int len = I16Array.getLength();
|
||||
if(len == 0) {
|
||||
return shortZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 1);
|
||||
WASMGCBufferAllocator.getShortBufferView0(addr, len).set(I16Array);
|
||||
short[] ret = new short[len];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] externI32ArrayToByteArray(Int32Array I32Array) {
|
||||
int len = I32Array.getLength();
|
||||
if(len == 0) {
|
||||
return byteZeroLength;
|
||||
}
|
||||
int len2 = len << 2;
|
||||
Address addr = WASMGCBufferAllocator.malloc(len2);
|
||||
WASMGCBufferAllocator.getIntBufferView0(addr, len).set(I32Array);
|
||||
byte[] ret = new byte[len2];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len2);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int[] externI32ArrayToIntArray(Int32Array I32Array) {
|
||||
int len = I32Array.getLength();
|
||||
if(len == 0) {
|
||||
return intZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 2);
|
||||
WASMGCBufferAllocator.getIntBufferView0(addr, len).set(I32Array);
|
||||
int[] ret = new int[len];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] externF32ArrayToByteArray(Float32Array F32Array) {
|
||||
int len = F32Array.getLength();
|
||||
if(len == 0) {
|
||||
return byteZeroLength;
|
||||
}
|
||||
int len2 = len << 2;
|
||||
Address addr = WASMGCBufferAllocator.malloc(len2);
|
||||
WASMGCBufferAllocator.getFloatBufferView0(addr, len).set(F32Array);
|
||||
byte[] ret = new byte[len2];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len2);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static float[] externF32ArrayToFloatArray(Float32Array F32Array) {
|
||||
int len = F32Array.getLength();
|
||||
if(len == 0) {
|
||||
return floatZeroLength;
|
||||
}
|
||||
Address addr = WASMGCBufferAllocator.malloc(len << 2);
|
||||
WASMGCBufferAllocator.getFloatBufferView0(addr, len).set(F32Array);
|
||||
float[] ret = new float[len];
|
||||
WASMGCDirectArrayCopy.memcpy(ret, 0, addr, len);
|
||||
WASMGCBufferAllocator.free(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCDirectArrayCopy {
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(Address dest, byte[] src, int srcOffset, int count) {
|
||||
Address destEnd = dest.add(count);
|
||||
while(dest.isLessThan(destEnd)) {
|
||||
dest.putByte(src[srcOffset]);
|
||||
++srcOffset;
|
||||
dest = dest.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(Address dest, short[] src, int srcOffset, int count) {
|
||||
Address destEnd = dest.add(count << 1);
|
||||
while(dest.isLessThan(destEnd)) {
|
||||
dest.putShort(src[srcOffset]);
|
||||
++srcOffset;
|
||||
dest = dest.add(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(Address dest, char[] src, int srcOffset, int count) {
|
||||
Address destEnd = dest.add(count << 1);
|
||||
while(dest.isLessThan(destEnd)) {
|
||||
dest.putChar(src[srcOffset]);
|
||||
++srcOffset;
|
||||
dest = dest.add(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(Address dest, int[] src, int srcOffset, int count) {
|
||||
Address destEnd = dest.add(count << 2);
|
||||
while(dest.isLessThan(destEnd)) {
|
||||
dest.putInt(src[srcOffset]);
|
||||
++srcOffset;
|
||||
dest = dest.add(4);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(Address dest, float[] src, int srcOffset, int count) {
|
||||
Address destEnd = dest.add(count << 2);
|
||||
while(dest.isLessThan(destEnd)) {
|
||||
dest.putFloat(src[srcOffset]);
|
||||
++srcOffset;
|
||||
dest = dest.add(4);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(byte[] dest, int destOffset, Address src, int count) {
|
||||
Address srcEnd = src.add(count);
|
||||
while(src.isLessThan(srcEnd)) {
|
||||
dest[destOffset] = src.getByte();
|
||||
++destOffset;
|
||||
src = src.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(short[] dest, int destOffset, Address src, int count) {
|
||||
Address srcEnd = src.add(count << 1);
|
||||
while(src.isLessThan(srcEnd)) {
|
||||
dest[destOffset] = src.getShort();
|
||||
++destOffset;
|
||||
src = src.add(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(char[] dest, int destOffset, Address src, int count) {
|
||||
Address srcEnd = src.add(count << 1);
|
||||
while(src.isLessThan(srcEnd)) {
|
||||
dest[destOffset] = src.getChar();
|
||||
++destOffset;
|
||||
src = src.add(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(int[] dest, int destOffset, Address src, int count) {
|
||||
Address srcEnd = src.add(count << 2);
|
||||
while(src.isLessThan(srcEnd)) {
|
||||
dest[destOffset] = src.getInt();
|
||||
++destOffset;
|
||||
src = src.add(4);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void memcpy(float[] dest, int destOffset, Address src, int count) {
|
||||
Address srcEnd = src.add(count << 2);
|
||||
while(src.isLessThan(srcEnd)) {
|
||||
dest[destOffset] = src.getFloat();
|
||||
++destOffset;
|
||||
src = src.add(4);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DirectMalloc;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
import org.teavm.jso.core.JSArray;
|
||||
import org.teavm.jso.core.JSString;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class BetterJSStringConverter {
|
||||
|
||||
private static final TextDecoder textDecoder = new TextDecoder("utf-16");
|
||||
|
||||
@Unmanaged
|
||||
public static JSString stringToJS(String input) {
|
||||
if(input == null) return null;
|
||||
int len = input.length();
|
||||
Address tmpAddr = WASMGCBufferAllocator.malloc(len << 1);
|
||||
for(int i = 0; i < len; ++i) {
|
||||
tmpAddr.add(i << 1).putChar(input.charAt(i));
|
||||
}
|
||||
JSString ret = textDecoder.decode(WASMGCBufferAllocator.getUnsignedByteBufferView0(tmpAddr, len << 1));
|
||||
WASMGCBufferAllocator.free(tmpAddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static JSArray<JSString> stringArrayToJS(String[] input) {
|
||||
if(input == null) return null;
|
||||
int len = input.length;
|
||||
JSArray<JSString> ret = new JSArray<>(len);
|
||||
for(int i = 0; i < len; ++i) {
|
||||
ret.set(i, stringToJS(input[i]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static String stringFromJS(JSString input) {
|
||||
if(input == null) return null;
|
||||
int len = input.getLength();
|
||||
char[] chars = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
chars[i] = charCodeAt(input, i);
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
@Import(module = "teavmJso", name = "charAt")
|
||||
private static native char charCodeAt(JSString str, int idx);
|
||||
|
||||
@Unmanaged
|
||||
public static String[] stringArrayFromJS(JSArray<JSString> input) {
|
||||
if(input == null) return null;
|
||||
int len = input.getLength();
|
||||
String[] ret = new String[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
ret[i] = stringFromJS(input.get(i));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.browser.Window;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsRoot;
|
||||
import net.minecraft.client.main.Main;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class ClientMain {
|
||||
|
||||
private static final PrintStream systemOut = System.out;
|
||||
private static final PrintStream systemErr = System.err;
|
||||
public static String configLocalesFolder = null;
|
||||
|
||||
public static void _main() {
|
||||
try {
|
||||
systemOut.println("ClientMain: [INFO] eaglercraftx wasm gc is starting...");
|
||||
JSObject opts = getEaglerXOpts();
|
||||
|
||||
if(opts == null) {
|
||||
systemErr.println("ClientMain: [ERROR] the \"window.eaglercraftXOpts\" variable is undefined");
|
||||
systemErr.println("ClientMain: [ERROR] eaglercraftx cannot start");
|
||||
Window.alert("ERROR: game cannot start, the \"window.eaglercraftXOpts\" variable is undefined");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSEaglercraftXOptsRoot eaglercraftOpts = (JSEaglercraftXOptsRoot)opts;
|
||||
|
||||
configLocalesFolder = eaglercraftOpts.getLocalesURI("lang");
|
||||
if(configLocalesFolder.endsWith("/")) {
|
||||
configLocalesFolder = configLocalesFolder.substring(0, configLocalesFolder.length() - 1);
|
||||
}
|
||||
|
||||
((WASMGCClientConfigAdapter)WASMGCClientConfigAdapter.instance).loadNative(eaglercraftOpts);
|
||||
|
||||
systemOut.println("ClientMain: [INFO] configuration was successful");
|
||||
}catch(Throwable t) {
|
||||
systemErr.println("ClientMain: [ERROR] the \"window.eaglercraftXOpts\" variable is invalid");
|
||||
EagRuntime.debugPrintStackTraceToSTDERR(t);
|
||||
systemErr.println("ClientMain: [ERROR] eaglercraftx cannot start");
|
||||
Window.alert("ERROR: game cannot start, the \"window.eaglercraftXOpts\" variable is invalid: " + t.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
systemOut.println("ClientMain: [INFO] initializing eaglercraftx runtime");
|
||||
|
||||
try {
|
||||
EagRuntime.create();
|
||||
}catch(Throwable t) {
|
||||
systemErr.println("ClientMain: [ERROR] eaglercraftx's runtime could not be initialized!");
|
||||
EagRuntime.debugPrintStackTraceToSTDERR(t);
|
||||
PlatformRuntime.writeCrashReport("EaglercraftX's runtime could not be initialized!\n\n" + EagRuntime.getStackTrace(t));
|
||||
systemErr.println("ClientMain: [ERROR] eaglercraftx cannot start");
|
||||
return;
|
||||
}
|
||||
|
||||
systemOut.println("ClientMain: [INFO] launching eaglercraftx main thread");
|
||||
|
||||
try {
|
||||
Main.appMain();
|
||||
}catch(Throwable t) {
|
||||
systemErr.println("ClientMain: [ERROR] unhandled exception caused main thread to exit");
|
||||
EagRuntime.debugPrintStackTraceToSTDERR(t);
|
||||
PlatformRuntime.writeCrashReport("Unhandled exception caused main thread to exit!\n\n" + EagRuntime.getStackTrace(t));
|
||||
}
|
||||
}finally {
|
||||
systemErr.println("ClientMain: [ERROR] eaglercraftx main thread has exited");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Import(module = "platformRuntime", name = "getEaglercraftXOpts")
|
||||
private static native JSObject getEaglerXOpts();
|
||||
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jcraft.jzlib.CRC32;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerBufferInputStream;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class EPKLoader {
|
||||
|
||||
public static final void loadEPK(ByteBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
loadEPK(epkFile, "", loadedFiles);
|
||||
}
|
||||
|
||||
public static final void loadEPK(ByteBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
int byteLength = epkFile.remaining();
|
||||
int l = byteLength - 16;
|
||||
if(l < 1) {
|
||||
throw new IOException("EPK file is incomplete");
|
||||
}
|
||||
|
||||
EaglerBufferInputStream is = new EaglerBufferInputStream(epkFile);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
is.read(header);
|
||||
String type = readASCII(header);
|
||||
|
||||
if(!"EAGPKG$$".equals(type)) {
|
||||
throw new IOException("Invalid EPK file type '" + type + "'");
|
||||
}
|
||||
|
||||
byte[] endCode = new byte[] { (byte)':', (byte)':', (byte)':', (byte)'Y',
|
||||
(byte)'E', (byte)'E', (byte)':', (byte)'>' };
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
if(epkFile.get(byteLength - 8 + i) != endCode[i]) {
|
||||
throw new IOException("EPK file is missing EOF code (:::YEE:>)");
|
||||
}
|
||||
}
|
||||
|
||||
epkFile.limit(epkFile.limit() - 8);
|
||||
|
||||
String vers = readASCII(is);
|
||||
if(!vers.startsWith("ver2.")) {
|
||||
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||
}
|
||||
|
||||
is.skip(is.read()); // skip filename
|
||||
is.skip(loadShort(is)); // skip comment
|
||||
is.skip(8); // skip millis date
|
||||
|
||||
int numFiles = loadInt(is);
|
||||
|
||||
char compressionType = (char)is.read();
|
||||
|
||||
InputStream zis;
|
||||
switch(compressionType) {
|
||||
case 'G':
|
||||
zis = new GZIPInputStream(is);
|
||||
break;
|
||||
case 'Z':
|
||||
zis = new InflaterInputStream(is);
|
||||
break;
|
||||
case '0':
|
||||
zis = is;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Invalid or unsupported EPK compression: " + compressionType);
|
||||
}
|
||||
|
||||
int blockFile = ('F' << 24) | ('I' << 16) | ('L' << 8) | 'E';
|
||||
int blockEnd = ('E' << 24) | ('N' << 16) | ('D' << 8) | '$';
|
||||
int blockHead = ('H' << 24) | ('E' << 16) | ('A' << 8) | 'D';
|
||||
|
||||
if(path.length() > 0 && !path.endsWith("/")) {
|
||||
path = path + "/";
|
||||
}
|
||||
|
||||
CRC32 crc32 = new CRC32();
|
||||
int blockType;
|
||||
for(int i = 0; i < numFiles; ++i) {
|
||||
|
||||
blockType = loadInt(zis);
|
||||
|
||||
if(blockType == blockEnd) {
|
||||
throw new IOException("Unexpected END when there are still " + (numFiles - i) + " files remaining");
|
||||
}
|
||||
|
||||
String name = readASCII(zis);
|
||||
int len = loadInt(zis);
|
||||
|
||||
if(i == 0) {
|
||||
if(blockType == blockHead) {
|
||||
byte[] readType = new byte[len];
|
||||
zis.read(readType);
|
||||
if(!"file-type".equals(name) || !"epk/resources".equals(readASCII(readType))) {
|
||||
throw new IOException("EPK is not of file-type 'epk/resources'!");
|
||||
}
|
||||
if(zis.read() != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
continue;
|
||||
}else {
|
||||
throw new IOException("File '" + name + "' did not have a file-type block as the first entry in the file");
|
||||
}
|
||||
}
|
||||
|
||||
if(blockType == blockFile) {
|
||||
if(len < 5) {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
int expectedCRC = loadInt(zis);
|
||||
|
||||
byte[] load = new byte[len - 5];
|
||||
zis.read(load);
|
||||
|
||||
if(len > 5) {
|
||||
crc32.reset();
|
||||
crc32.update(load, 0, load.length);
|
||||
if(expectedCRC != (int)crc32.getValue()) {
|
||||
throw new IOException("File '" + name + "' has an invalid checksum");
|
||||
}
|
||||
}
|
||||
|
||||
if(zis.read() != ':') {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
loadedFiles.put(path + name, load);
|
||||
}else {
|
||||
zis.skip(len);
|
||||
}
|
||||
|
||||
if(zis.read() != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
}
|
||||
|
||||
if(loadInt(zis) != blockEnd) {
|
||||
throw new IOException("EPK missing END$ object");
|
||||
}
|
||||
|
||||
zis.close();
|
||||
}
|
||||
|
||||
private static final int loadShort(InputStream is) throws IOException {
|
||||
return (is.read() << 8) | is.read();
|
||||
}
|
||||
|
||||
private static final int loadInt(InputStream is) throws IOException {
|
||||
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||
}
|
||||
|
||||
private static final String readASCII(byte[] bytesIn) throws IOException {
|
||||
char[] charIn = new char[bytesIn.length];
|
||||
for(int i = 0; i < bytesIn.length; ++i) {
|
||||
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
private static final String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = bytesIn.read();
|
||||
char[] charIn = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,262 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
|
||||
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Base64;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IBufferArrayGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.ITextureGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformAssets;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class EarlyLoadScreen {
|
||||
|
||||
public static final String loadScreen = "iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHx0lEQVR42u3da27jIBRAYbfqFp1FuovM/GLEMIDBhsRJviNVapsYY8y5vPz4ut/v9wX4UL4VAQgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAMBr86MI3ovf39/i/9Z1XdZ1VUgEeN/Kf7vdqt8hgC7QW6OCE+CjK/+2bcv9fieCLtDjux9x/1t/u1xOveWSlisBXmQASoB/+fr6+vv7/X7vHteE8hxZrrpAkyo/2mU42soSgAAfN8YZ3aoSQOV/GNu2ZX9vGdjPEuBnVmXIVYqePly8famCne0TtuS1tt/a9kfSbWnqZw2u9yQesc91XZv7/iO2a+I+iG3b7uu63pdl2f1Z17WaTksaaXrbtk3JaynvR/O5l6/WtPaON3d8tf3v7e9d+RkVPeIVyDRKpREtfL+nGdxL7/f3d9m2bTdS5VZL4/Rz0fcRszm32604jZrLUyi/UXlb1/WlunKhTE63iCMif0tkao1IaXqlqFWKlr2RsTUPpXRLrUnYpqVlircfdby9LUCpbHpa1lyeW8tgL51SmZ9N+2dE5GqJlrkI0xJxaumV0ixt0xrd07TDdrl+aDoeGNnfbzne0RE1HqSOaF3SljptyXP7qF3QN3zi4Yw9LdF0r5+Zs7u175mLirU85KJiLbK3pt2bj1qZ1CJaz356WoD0u2ejaq11XNf1708uf73jqqeOAXotbIlgZ/t0tfSPRulZ050j0jubRjz2CGU/clyRRvvwv1LPIR4X5r6TtlJPmwY9W5la54vfea5+Zhm2dnniyj+j3GtdxCsMzL+vWAmuyujK2dLXnVGGYSZsduXPlV0625Vbk0nlnFlXhrYAezdjPFOa2sD4GRetlY5hdhnmpoHjKcXZlb927Llp4JCvWYHy8leDxpHgbCH0zBo9s3vyiLK8QiBIxwiPaHWnjwFGZbjl9r5RAtxut92Fp5GLTqPHP735qpXDrK5QbjFz27b/Wp802IXu2Yz6cGoadDmwCHV0enVJFpbCfkqLQ6Mvg9g7riPToEfyfrYMl4ZLOUadw1rZh33H/ytNjcbnunfavakeX02As3P1rZVoT4KeVdBXESDN05HV4pFXDaQrxqkE6TnISfC0dYAZA5PSSu3orkeYiSil/Sl3cm3b9t+NKbMHxHtTpenvcT7C33Gez+b1e3QFvvrUY2nhZ/Qi0KtMC+f6/KWpytnnsjWoXuKWyNaZkyud/HTh55mVvTYt++h8zDiXlTFnkwS1wfhlBZgxj917acNe9H9mZWuJvjPuez0azJ5RPj1T3kMe/zJyUNMzkMpdJts6MNybyckNXo/cwLI0XtZ8ZkaldBwt2x65RHvGMRwZoO9dWLh3CfqofC0zZhtKU5fpiWkVIE4n3b423Zemf0SA5cQdVenxt9x70FJ+8TEfkbxUuXqDytnp0L2p0kewzJjeOnMSWtKKt92rQCNageXEDTot05xH1iZy5Xf2lsra9iMrZDjW2dG9ha/7wLuNS5ctpDevt9y2WBu0ptvnxh2l75YutOrtu+/1m+N8tw66022PlGHrcfVuP+NCwNrg+2ETFPcPI45yLSu8s1Yg8UY3xb8K6WP2WualrzJjhDl8f2Ll721iPeiWAG8hwMw+LQhw6co/cpWaPO/DR4wBchU23APQMiMy43EhuAZDp0FfaQxwRCJjAQK8xTigp0uk4hPgowbH+vkEAD4GL8gAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAK7NJR6M9S6PLQzPHZr1sulSuXmCxQu3APHz+sNP6wOspr09/CL76ym3Tzr2t2sBHhk13+UYwgsmnvFeXwI8qUtRinZxZNq27e/3tm3Lvg8gjWRpxc09Rj3eb2l/ufTiZ5CG78Sfn305eO7durX8tH4W8pB+Pz32vTQJcGAcED+0Nv5//Pbw9GTl+sKh8sVRMo2WoWkPJy0WpiRB6XVFpa5IvF28v3RfvX36mpylBwKXPktbkjiI1I69liYBTg6E4wqTkyOWolRB4nTSE5XuszaI3dvfngRppM1F+9auTG4fuW1raeXendYiWk+aBBjQf44jZW/TWoriV3gRddwi9L57IPfY9lA5Q3nF6YZyq33WIkLt/NTSJMCAcUD4/Wzhxt2o3Hjg0a3emSdPt7Q2t9vtn3KrfXY0L7U091rWo599xBggjSgh0pSa79aTl4ugaR8913qU9ld6vWlvd6bn+7mB+96MUHpcLULtHftemlqAAwKEwVd6MtNBbK4C7kWLuMkuDT5zA+za/nKzMC0VOu0CtXQhal2UeKCfG2PUPsvNZrUcey3NV8Dj0Z/cvctNQ77DmogWAM0S7M0gQQvwluS6HFZ0CQA8DJdDgwAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAYBlWf4A1W4Hx65cJAoAAAAASUVORK5CYII=";
|
||||
|
||||
private static IBufferGL vbo = null;
|
||||
private static IProgramGL program = null;
|
||||
private static ITextureGL finalTexture = null;
|
||||
|
||||
public static void extractingAssetsScreen() {
|
||||
boolean gles3 = checkOpenGLESVersion() >= 300;
|
||||
boolean vaos = checkVAOCapable();
|
||||
|
||||
// create textures:
|
||||
|
||||
ITextureGL tex = _wglGenTextures();
|
||||
_wglActiveTexture(GL_TEXTURE0);
|
||||
_wglBindTexture(GL_TEXTURE_2D, tex);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
ImageData img = PlatformAssets.loadImageFile(Base64.decodeBase64(loadScreen));
|
||||
ByteBuffer upload = PlatformRuntime.allocateByteBuffer(192*192*4);
|
||||
IntBuffer pixelUpload = upload.asIntBuffer();
|
||||
pixelUpload.put(img.pixels);
|
||||
pixelUpload.flip();
|
||||
_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 192, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelUpload);
|
||||
|
||||
// create vertex buffer:
|
||||
|
||||
FloatBuffer vertexUpload = upload.asFloatBuffer();
|
||||
vertexUpload.clear();
|
||||
vertexUpload.put(0.0f); vertexUpload.put(0.0f);
|
||||
vertexUpload.put(0.0f); vertexUpload.put(1.0f);
|
||||
vertexUpload.put(1.0f); vertexUpload.put(0.0f);
|
||||
vertexUpload.put(1.0f); vertexUpload.put(0.0f);
|
||||
vertexUpload.put(0.0f); vertexUpload.put(1.0f);
|
||||
vertexUpload.put(1.0f); vertexUpload.put(1.0f);
|
||||
vertexUpload.flip();
|
||||
|
||||
vbo = _wglGenBuffers();
|
||||
_wglBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
_wglBufferData(GL_ARRAY_BUFFER, vertexUpload, GL_STATIC_DRAW);
|
||||
|
||||
PlatformRuntime.freeByteBuffer(upload);
|
||||
|
||||
// compile the splash shader:
|
||||
|
||||
IShaderGL vert = _wglCreateShader(GL_VERTEX_SHADER);
|
||||
_wglShaderSource(vert, gles3
|
||||
? "#version 300 es\nprecision mediump float; layout(location = 0) in vec2 a_pos; out vec2 v_pos; void main() { gl_Position = vec4(((v_pos = a_pos) - 0.5) * vec2(2.0, -2.0), 0.0, 1.0); }"
|
||||
: "#version 100\nprecision mediump float; attribute vec2 a_pos; varying vec2 v_pos; void main() { gl_Position = vec4(((v_pos = a_pos) - 0.5) * vec2(2.0, -2.0), 0.0, 1.0); }");
|
||||
_wglCompileShader(vert);
|
||||
|
||||
IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(frag, gles3
|
||||
? "#version 300 es\nprecision mediump float; precision mediump sampler2D; in vec2 v_pos; layout(location = 0) out vec4 fragColor; uniform sampler2D tex; uniform vec2 aspect; void main() { fragColor = vec4(textureLod(tex, clamp(v_pos * aspect - ((aspect - 1.0) * 0.5), 0.02, 0.98), 0.0).rgb, 1.0); }"
|
||||
: "#version 100\nprecision mediump float; precision mediump sampler2D; varying vec2 v_pos; uniform sampler2D tex; uniform vec2 aspect; void main() { gl_FragColor = vec4(texture2D(tex, clamp(v_pos * aspect - ((aspect - 1.0) * 0.5), 0.02, 0.98)).rgb, 1.0); }");
|
||||
_wglCompileShader(frag);
|
||||
|
||||
program = _wglCreateProgram();
|
||||
|
||||
_wglAttachShader(program, vert);
|
||||
_wglAttachShader(program, frag);
|
||||
if(!gles3) {
|
||||
_wglBindAttribLocation(program, 0, "a_pos");
|
||||
}
|
||||
_wglLinkProgram(program);
|
||||
_wglDetachShader(program, vert);
|
||||
_wglDetachShader(program, frag);
|
||||
_wglDeleteShader(vert);
|
||||
_wglDeleteShader(frag);
|
||||
|
||||
_wglUseProgram(program);
|
||||
_wglUniform1i(_wglGetUniformLocation(program, "tex"), 0);
|
||||
|
||||
int width = PlatformInput.getWindowWidth();
|
||||
int height = PlatformInput.getWindowHeight();
|
||||
float x, y;
|
||||
if(width > height) {
|
||||
x = (float)width / (float)height;
|
||||
y = 1.0f;
|
||||
}else {
|
||||
x = 1.0f;
|
||||
y = (float)height / (float)width;
|
||||
}
|
||||
|
||||
_wglActiveTexture(GL_TEXTURE0);
|
||||
_wglBindTexture(GL_TEXTURE_2D, tex);
|
||||
|
||||
_wglViewport(0, 0, width, height);
|
||||
_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
_wglClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
_wglUseProgram(program);
|
||||
_wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y);
|
||||
|
||||
IBufferArrayGL vao = null;
|
||||
if(vaos) {
|
||||
vao = _wglGenVertexArrays();
|
||||
_wglBindVertexArray(vao);
|
||||
}
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
|
||||
_wglDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
_wglDisableVertexAttribArray(0);
|
||||
|
||||
PlatformInput.update();
|
||||
|
||||
_wglUseProgram(null);
|
||||
_wglBindBuffer(GL_ARRAY_BUFFER, null);
|
||||
_wglBindTexture(GL_TEXTURE_2D, null);
|
||||
_wglDeleteTextures(tex);
|
||||
if(vaos) {
|
||||
_wglDeleteVertexArrays(vao);
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadFinal(byte[] finalLoadScreen) {
|
||||
ImageData img = PlatformAssets.loadImageFile(finalLoadScreen);
|
||||
if(img == null) {
|
||||
return;
|
||||
}
|
||||
finalTexture = _wglGenTextures();
|
||||
_wglActiveTexture(GL_TEXTURE0);
|
||||
_wglBindTexture(GL_TEXTURE_2D, finalTexture);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
IntBuffer upload = PlatformRuntime.allocateIntBuffer(img.width * img.height);
|
||||
upload.put(img.pixels);
|
||||
upload.flip();
|
||||
_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width, img.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, upload);
|
||||
PlatformRuntime.freeIntBuffer(upload);
|
||||
}
|
||||
|
||||
public static void paintFinal(boolean softVAOs) {
|
||||
if(finalTexture == null) return;
|
||||
boolean vaos = checkVAOCapable();
|
||||
|
||||
_wglBindTexture(GL_TEXTURE_2D, finalTexture);
|
||||
_wglUseProgram(program);
|
||||
|
||||
int width = PlatformInput.getWindowWidth();
|
||||
int height = PlatformInput.getWindowHeight();
|
||||
float x, y;
|
||||
if(width > height) {
|
||||
x = (float)width / (float)height;
|
||||
y = 1.0f;
|
||||
}else {
|
||||
x = 1.0f;
|
||||
y = (float)height / (float)width;
|
||||
}
|
||||
|
||||
_wglActiveTexture(GL_TEXTURE0);
|
||||
_wglBindTexture(GL_TEXTURE_2D, finalTexture);
|
||||
|
||||
_wglViewport(0, 0, width, height);
|
||||
_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
_wglClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
_wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y);
|
||||
|
||||
IBufferArrayGL vao = null;
|
||||
if(vaos) {
|
||||
if(softVAOs) {
|
||||
vao = EaglercraftGPU.createGLBufferArray();
|
||||
EaglercraftGPU.bindGLBufferArray(vao);
|
||||
}else {
|
||||
vao = _wglGenVertexArrays();
|
||||
_wglBindVertexArray(vao);
|
||||
}
|
||||
}
|
||||
if(vaos && softVAOs) {
|
||||
EaglercraftGPU.bindVAOGLArrayBuffer(vbo);
|
||||
EaglercraftGPU.enableVertexAttribArray(0);
|
||||
EaglercraftGPU.vertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
|
||||
EaglercraftGPU.doDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}else {
|
||||
_wglBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
|
||||
_wglDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}
|
||||
|
||||
if(!softVAOs) {
|
||||
_wglDisableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
PlatformInput.update();
|
||||
|
||||
_wglUseProgram(null);
|
||||
if(!(vaos && softVAOs)) {
|
||||
_wglBindBuffer(GL_ARRAY_BUFFER, null);
|
||||
}
|
||||
_wglBindTexture(GL_TEXTURE_2D, null);
|
||||
if(softVAOs) {
|
||||
EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_ACTIVE_TEXTURE | EaglercraftGPU.CLEAR_BINDING_TEXTURE0);
|
||||
}
|
||||
if(vaos) {
|
||||
if(softVAOs) {
|
||||
EaglercraftGPU.destroyGLBufferArray(vao);
|
||||
}else {
|
||||
_wglDeleteVertexArrays(vao);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
if(vbo != null) {
|
||||
_wglDeleteBuffers(vbo);
|
||||
vbo = null;
|
||||
}
|
||||
if(program != null) {
|
||||
_wglDeleteProgram(program);
|
||||
program = null;
|
||||
}
|
||||
if(finalTexture != null) {
|
||||
_wglDeleteTextures(finalTexture);
|
||||
finalTexture = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.indexeddb.IDBDatabase;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.EaglerFileSystemException;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.FilesystemDatabaseInitializationException;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.FilesystemDatabaseLockedException;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class IndexedDBFilesystem implements IEaglerFilesystem {
|
||||
|
||||
public static IEaglerFilesystem createFilesystem(String dbName) {
|
||||
String filesystemDB = "_net_lax1dude_eaglercraft_v1_8_internal_PlatformFilesystem_1_8_8_" + dbName;
|
||||
JSDatabaseOpen dbOpen = openDB(BetterJSStringConverter.stringToJS(filesystemDB));
|
||||
|
||||
if(dbOpen.getFailedLocked()) {
|
||||
throw new FilesystemDatabaseLockedException(dbOpen.getFailedError());
|
||||
}
|
||||
|
||||
if(dbOpen.getFailedInit()) {
|
||||
throw new FilesystemDatabaseInitializationException(dbOpen.getFailedError());
|
||||
}
|
||||
|
||||
IDBDatabase database = dbOpen.getDatabase();
|
||||
if(database == null) {
|
||||
throw new NullPointerException("IDBDatabase is null!");
|
||||
}
|
||||
|
||||
return new IndexedDBFilesystem(dbName, filesystemDB, database);
|
||||
}
|
||||
|
||||
private interface JSDatabaseOpen extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
boolean getFailedInit();
|
||||
|
||||
@JSProperty
|
||||
boolean getFailedLocked();
|
||||
|
||||
@JSProperty
|
||||
String getFailedError();
|
||||
|
||||
@JSProperty
|
||||
IDBDatabase getDatabase();
|
||||
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "openDB")
|
||||
private static native JSDatabaseOpen openDB(JSString filesystemDB);
|
||||
|
||||
private final String name;
|
||||
private final String indexedDBName;
|
||||
private IDBDatabase database;
|
||||
|
||||
private IndexedDBFilesystem(String name, String indexedDBName, IDBDatabase database) {
|
||||
this.name = name;
|
||||
this.indexedDBName = indexedDBName;
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilesystemName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalDBName() {
|
||||
return "indexeddb:" + indexedDBName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRamdisk() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerDelete(String pathName) {
|
||||
return eaglerDelete(database, BetterJSStringConverter.stringToJS(pathName));
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerDelete")
|
||||
private static native boolean eaglerDelete(IDBDatabase database, JSString pathName);
|
||||
|
||||
@Override
|
||||
public ByteBuffer eaglerRead(String pathName) {
|
||||
ArrayBuffer ar = eaglerRead(database, BetterJSStringConverter.stringToJS(pathName));
|
||||
if(ar == null) {
|
||||
return null;
|
||||
}
|
||||
Uint8Array arr = new Uint8Array(ar);
|
||||
ByteBuffer buf = PlatformRuntime.allocateByteBuffer(arr.getLength());
|
||||
WASMGCBufferAllocator.getUnsignedByteBufferView(buf).set(arr);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerRead")
|
||||
private static native ArrayBuffer eaglerRead(IDBDatabase database, JSString pathName);
|
||||
|
||||
@Override
|
||||
public void eaglerWrite(String pathName, ByteBuffer data) {
|
||||
int len = data.remaining();
|
||||
Uint8Array arr = new Uint8Array(len);
|
||||
arr.set(WASMGCBufferAllocator.getByteBufferView(data));
|
||||
if(!eaglerWrite(database, BetterJSStringConverter.stringToJS(pathName), arr.getBuffer())) {
|
||||
throw new EaglerFileSystemException("Failed to write " + len + " byte file to indexeddb table: " + pathName);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerWrite")
|
||||
private static native boolean eaglerWrite(IDBDatabase database, JSString pathName, ArrayBuffer arr);
|
||||
|
||||
@Override
|
||||
public boolean eaglerExists(String pathName) {
|
||||
return eaglerExists(database, BetterJSStringConverter.stringToJS(pathName));
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerExists")
|
||||
private static native boolean eaglerExists(IDBDatabase database, JSString pathName);
|
||||
|
||||
@Override
|
||||
public boolean eaglerMove(String pathNameOld, String pathNameNew) {
|
||||
return eaglerMove(database, BetterJSStringConverter.stringToJS(pathNameOld), BetterJSStringConverter.stringToJS(pathNameNew));
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerMove")
|
||||
private static native boolean eaglerMove(IDBDatabase database, JSString pathNameOld, JSString pathNameNew);
|
||||
|
||||
@Override
|
||||
public int eaglerCopy(String pathNameOld, String pathNameNew) {
|
||||
return eaglerCopy(database, BetterJSStringConverter.stringToJS(pathNameOld), BetterJSStringConverter.stringToJS(pathNameNew));
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerCopy")
|
||||
private static native int eaglerCopy(IDBDatabase database, JSString pathNameOld, JSString pathNameNew);
|
||||
|
||||
@Override
|
||||
public int eaglerSize(String pathName) {
|
||||
return eaglerSize(database, BetterJSStringConverter.stringToJS(pathName));
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerSize")
|
||||
private static native int eaglerSize(IDBDatabase database, JSString pathName);
|
||||
|
||||
private interface JSDatabaseIteratorResult extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getLength();
|
||||
|
||||
String getRow(int idx);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
|
||||
JSDatabaseIteratorResult result = eaglerIterate(database, BetterJSStringConverter.stringToJS(pathName), recursive);
|
||||
if(result != null) {
|
||||
for(int i = 0, len = result.getLength(); i < len; ++i) {
|
||||
itr.next(result.getRow(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformFilesystem", name = "eaglerIterate")
|
||||
private static native JSDatabaseIteratorResult eaglerIterate(IDBDatabase database, JSString pathName, boolean recursive);
|
||||
|
||||
@Override
|
||||
public void closeHandle() {
|
||||
if(database != null) {
|
||||
database.close();
|
||||
database = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,384 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.jso.webaudio.AudioBuffer;
|
||||
|
||||
import com.jcraft.jogg.Packet;
|
||||
import com.jcraft.jogg.Page;
|
||||
import com.jcraft.jogg.StreamState;
|
||||
import com.jcraft.jogg.SyncState;
|
||||
import com.jcraft.jorbis.Block;
|
||||
import com.jcraft.jorbis.Comment;
|
||||
import com.jcraft.jorbis.DspState;
|
||||
import com.jcraft.jorbis.Info;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformAudio;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class JOrbisAudioBufferDecoder {
|
||||
|
||||
private EaglerInputStream inputStream;
|
||||
private boolean endOfStream = false;
|
||||
private byte[] buffer = null;
|
||||
private int bufferSize;
|
||||
private int count = 0;
|
||||
private int index = 0;
|
||||
private float[][] convertedBuffer = null;
|
||||
private float[][][] pcmInfo;
|
||||
private int[] pcmIndex;
|
||||
private Packet joggPacket = new Packet();
|
||||
private Page joggPage = new Page();
|
||||
private StreamState joggStreamState = new StreamState();
|
||||
private SyncState joggSyncState = new SyncState();
|
||||
private DspState jorbisDspState = new DspState();
|
||||
private Block jorbisBlock;
|
||||
private Comment jorbisComment;
|
||||
private Info jorbisInfo;
|
||||
private String errorString;
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("JOrbisAudioBufferDecoder");
|
||||
|
||||
private static final JOrbisAudioBufferDecoder instance = new JOrbisAudioBufferDecoder();
|
||||
|
||||
public static AudioBuffer decodeAudioJOrbis(byte[] data, String errorString) {
|
||||
JOrbisAudioBufferDecoder dec = instance;
|
||||
synchronized(dec) {
|
||||
if(!dec.init(data, errorString)) {
|
||||
logger.error("[{}]: Invalid header detected", errorString);
|
||||
return null;
|
||||
}
|
||||
int ch = -1;
|
||||
int len = 0;
|
||||
List<float[][]> lst = new LinkedList<>();
|
||||
float[][] b;
|
||||
while((b = dec.readBytes()) != null) {
|
||||
if(ch == -1) {
|
||||
ch = b.length;
|
||||
}
|
||||
len += b[0].length;
|
||||
lst.add(b);
|
||||
}
|
||||
if(dec.jorbisInfo.channels != ch) {
|
||||
logger.warn("[{}]: Number of channels in header does not match the stream", errorString);
|
||||
}
|
||||
if(ch == -1 || len == 0) {
|
||||
logger.error("[{}]: Empty file", errorString);
|
||||
return null;
|
||||
}
|
||||
FloatBuffer buf = PlatformRuntime.allocateFloatBuffer(ch * len);
|
||||
try {
|
||||
int len2 = 0;
|
||||
for(float[][] fl : lst) {
|
||||
for(int i = 0; i < ch; ++i) {
|
||||
buf.position(i * len + len2);
|
||||
buf.put(fl[i]);
|
||||
}
|
||||
len2 += fl[0].length;
|
||||
}
|
||||
buf.clear();
|
||||
return PlatformAudio.decodeAudioBufferPCMBrowser(WASMGCBufferAllocator.getFloatBufferView(buf), ch,
|
||||
len, dec.jorbisInfo.rate);
|
||||
}finally {
|
||||
PlatformRuntime.freeFloatBuffer(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JOrbisAudioBufferDecoder() {
|
||||
this.jorbisBlock = new Block(this.jorbisDspState);
|
||||
this.jorbisComment = new Comment();
|
||||
this.jorbisInfo = new Info();
|
||||
}
|
||||
|
||||
private boolean init(byte[] data, String errorString) {
|
||||
this.inputStream = new EaglerInputStream(data);
|
||||
this.errorString = errorString;
|
||||
|
||||
if (this.joggStreamState != null) {
|
||||
this.joggStreamState.clear();
|
||||
}
|
||||
|
||||
if (this.jorbisBlock != null) {
|
||||
this.jorbisBlock.clear();
|
||||
}
|
||||
|
||||
if (this.jorbisDspState != null) {
|
||||
this.jorbisDspState.clear();
|
||||
}
|
||||
|
||||
if (this.jorbisInfo != null) {
|
||||
this.jorbisInfo.clear();
|
||||
}
|
||||
|
||||
if (this.joggSyncState != null) {
|
||||
this.joggSyncState.clear();
|
||||
}
|
||||
|
||||
if (this.inputStream != null) {
|
||||
try {
|
||||
this.inputStream.close();
|
||||
} catch (IOException var7) {
|
||||
}
|
||||
}
|
||||
|
||||
this.bufferSize = 8192;
|
||||
this.buffer = null;
|
||||
this.count = 0;
|
||||
this.index = 0;
|
||||
this.joggStreamState = new StreamState();
|
||||
this.jorbisBlock = new Block(this.jorbisDspState);
|
||||
this.jorbisDspState = new DspState();
|
||||
this.jorbisInfo = new Info();
|
||||
this.joggSyncState = new SyncState();
|
||||
|
||||
this.endOfStream = false;
|
||||
this.joggSyncState.init();
|
||||
this.joggSyncState.buffer(this.bufferSize);
|
||||
this.buffer = this.joggSyncState.data;
|
||||
|
||||
vigg: {
|
||||
this.index = this.joggSyncState.buffer(this.bufferSize);
|
||||
int bytes = this.inputStream.read(this.joggSyncState.data, this.index, this.bufferSize);
|
||||
if (bytes < 0) {
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
this.joggSyncState.wrote(bytes);
|
||||
if (this.joggSyncState.pageout(this.joggPage) != 1) {
|
||||
if (bytes < this.bufferSize) {
|
||||
break vigg;
|
||||
} else {
|
||||
logger.error("[{}]: Ogg header not recognized in method 'readHeader'.", errorString);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
this.joggStreamState.init(this.joggPage.serialno());
|
||||
this.jorbisInfo.init();
|
||||
this.jorbisComment.init();
|
||||
if (this.joggStreamState.pagein(this.joggPage) < 0) {
|
||||
logger.error("[{}]: Problem with first Ogg header page in method 'readHeader'.", errorString);
|
||||
return false;
|
||||
} else if (this.joggStreamState.packetout(this.joggPacket) != 1) {
|
||||
logger.error("[{}]: Problem with first Ogg header packet in method 'readHeader'.", errorString);
|
||||
return false;
|
||||
} else if (this.jorbisInfo.synthesis_headerin(this.jorbisComment, this.joggPacket) < 0) {
|
||||
logger.error("[{}]: File does not contain Vorbis header in method 'readHeader'.", errorString);
|
||||
return false;
|
||||
} else {
|
||||
int i = 0;
|
||||
|
||||
while (i < 2) {
|
||||
label73: while (true) {
|
||||
int result;
|
||||
do {
|
||||
if (i >= 2) {
|
||||
break label73;
|
||||
}
|
||||
|
||||
result = this.joggSyncState.pageout(this.joggPage);
|
||||
if (result == 0) {
|
||||
break label73;
|
||||
}
|
||||
} while (result != 1);
|
||||
|
||||
this.joggStreamState.pagein(this.joggPage);
|
||||
|
||||
while (i < 2) {
|
||||
result = this.joggStreamState.packetout(this.joggPacket);
|
||||
if (result == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == -1) {
|
||||
logger.error("[{}]: Secondary Ogg header corrupt in method 'readHeader'.", errorString);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.jorbisInfo.synthesis_headerin(this.jorbisComment, this.joggPacket);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
this.index = this.joggSyncState.buffer(this.bufferSize);
|
||||
bytes = this.inputStream.read(this.joggSyncState.data, this.index, this.bufferSize);
|
||||
if (bytes < 0) {
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
if (bytes == 0 && i < 2) {
|
||||
logger.error(
|
||||
"[{}]: End of file reached before finished reading Ogg header in method 'readHeader'",
|
||||
errorString);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.joggSyncState.wrote(bytes);
|
||||
}
|
||||
|
||||
this.index = this.joggSyncState.buffer(this.bufferSize);
|
||||
this.buffer = this.joggSyncState.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.jorbisDspState.synthesis_init(this.jorbisInfo);
|
||||
this.jorbisBlock.init(this.jorbisDspState);
|
||||
int channels = this.jorbisInfo.channels;
|
||||
int rate = this.jorbisInfo.rate;
|
||||
this.pcmInfo = new float[1][][];
|
||||
this.pcmIndex = new int[channels];
|
||||
if(convertedBuffer == null || convertedBuffer.length != this.jorbisInfo.channels || (convertedBuffer.length > 0 && convertedBuffer[0].length != this.bufferSize)) {
|
||||
this.convertedBuffer = new float[this.jorbisInfo.channels][this.bufferSize];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private float[][] readBytes() {
|
||||
if (this.endOfStream) {
|
||||
return null;
|
||||
} else {
|
||||
float[][] returnBuffer = null;
|
||||
switch (this.joggSyncState.pageout(this.joggPage)) {
|
||||
default:
|
||||
this.joggStreamState.pagein(this.joggPage);
|
||||
if (this.joggPage.granulepos() == 0L) {
|
||||
this.endOfStream = true;
|
||||
return null;
|
||||
} else {
|
||||
label99: {
|
||||
while (true) {
|
||||
switch (this.joggStreamState.packetout(this.joggPacket)) {
|
||||
case -1:
|
||||
break;
|
||||
case 0:
|
||||
if (this.joggPage.eos() != 0) {
|
||||
this.endOfStream = true;
|
||||
}
|
||||
break label99;
|
||||
default:
|
||||
if (this.jorbisBlock.synthesis(this.joggPacket) == 0) {
|
||||
this.jorbisDspState.synthesis_blockin(this.jorbisBlock);
|
||||
}
|
||||
|
||||
int samples;
|
||||
while ((samples = this.jorbisDspState.synthesis_pcmout(this.pcmInfo,
|
||||
this.pcmIndex)) > 0) {
|
||||
float[][] pcmf = this.pcmInfo[0];
|
||||
int bout = samples < bufferSize ? samples : this.bufferSize;
|
||||
|
||||
for (int i = 0; i < this.jorbisInfo.channels; ++i) {
|
||||
float[] f1 = convertedBuffer[i];
|
||||
float[] f2 = pcmf[i];
|
||||
int mono = this.pcmIndex[i];
|
||||
for (int j = 0; j < bout; ++j) {
|
||||
f1[j] = f2[mono + j];
|
||||
}
|
||||
}
|
||||
|
||||
this.jorbisDspState.synthesis_read(bout);
|
||||
returnBuffer = appendFloatArrays(returnBuffer, this.convertedBuffer, bout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case -1:
|
||||
case 0:
|
||||
if (!this.endOfStream) {
|
||||
this.index = this.joggSyncState.buffer(this.bufferSize);
|
||||
this.buffer = this.joggSyncState.data;
|
||||
|
||||
try {
|
||||
this.count = this.inputStream.read(this.buffer, this.index, this.bufferSize);
|
||||
} catch (Exception var11) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.count == -1) {
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
this.joggSyncState.wrote(this.count);
|
||||
if (this.count == 0) {
|
||||
this.endOfStream = true;
|
||||
}
|
||||
}
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static float[][] appendFloatArrays(float[][] arrayOne, float[][] arrayTwo, int arrayTwoBytes) {
|
||||
int bytes = arrayTwoBytes;
|
||||
int l;
|
||||
if (arrayTwo != null && (l = arrayTwo[0].length) != 0) {
|
||||
if (l < arrayTwoBytes) {
|
||||
bytes = l;
|
||||
}
|
||||
} else {
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
if ((arrayOne != null || arrayTwo != null) && bytes > 0) {
|
||||
float[][] newArray;
|
||||
|
||||
if (arrayOne == null) {
|
||||
int ch = arrayTwo.length;
|
||||
int len1 = arrayTwo[0].length;
|
||||
newArray = new float[ch][bytes];
|
||||
for(int i = 0; i < ch; ++i) {
|
||||
System.arraycopy(arrayTwo[i], 0, newArray[i], 0, bytes);
|
||||
}
|
||||
arrayTwo = null;
|
||||
} else {
|
||||
int ch = arrayOne.length;
|
||||
int len1 = arrayOne[0].length;
|
||||
if (arrayTwo != null && bytes > 0) {
|
||||
newArray = new float[ch][len1 + bytes];
|
||||
for(int i = 0; i < ch; ++i) {
|
||||
System.arraycopy(arrayOne[i], 0, newArray[i], 0, len1);
|
||||
System.arraycopy(arrayTwo[i], 0, newArray[i], len1, bytes);
|
||||
}
|
||||
arrayOne = null;
|
||||
arrayTwo = null;
|
||||
} else {
|
||||
newArray = new float[ch][len1];
|
||||
for(int i = 0; i < ch; ++i) {
|
||||
System.arraycopy(arrayOne[i], 0, newArray[i], 0, len1);
|
||||
}
|
||||
arrayOne = null;
|
||||
}
|
||||
}
|
||||
|
||||
return newArray;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,328 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class LegacyKeycodeTranslator {
|
||||
|
||||
public static class LegacyKeycode {
|
||||
|
||||
public final int keyCode;
|
||||
public final int location;
|
||||
|
||||
private LegacyKeycode(int keyCode, int location) {
|
||||
this.keyCode = keyCode;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof LegacyKeycode))
|
||||
return false;
|
||||
LegacyKeycode other = (LegacyKeycode) obj;
|
||||
if (keyCode != other.keyCode)
|
||||
return false;
|
||||
if (location != other.location)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final Set<String> numpadVolatile = Sets.newHashSet(
|
||||
"Comma", "Minus", "Period", "Slash", "Equal", "Enter", "Digit0", "Digit1", "Digit2", "Digit3",
|
||||
"Digit4", "Digit5", "Digit6", "Digit7", "Digit8", "Digit9", "IntlYen");
|
||||
|
||||
private final Map<String,LegacyKeycode> codeLookupBase = new HashMap<>();
|
||||
private final Map<String,LegacyKeycode> codeLookupLayout = new HashMap<>();
|
||||
|
||||
public LegacyKeycodeTranslator() {
|
||||
codeLookupBase.put("Digit0", new LegacyKeycode(0x30, 0));
|
||||
codeLookupBase.put("Digit1", new LegacyKeycode(0x31, 0));
|
||||
codeLookupBase.put("Digit2", new LegacyKeycode(0x32, 0));
|
||||
codeLookupBase.put("Digit3", new LegacyKeycode(0x33, 0));
|
||||
codeLookupBase.put("Digit4", new LegacyKeycode(0x34, 0));
|
||||
codeLookupBase.put("Digit5", new LegacyKeycode(0x35, 0));
|
||||
codeLookupBase.put("Digit6", new LegacyKeycode(0x36, 0));
|
||||
codeLookupBase.put("Digit7", new LegacyKeycode(0x37, 0));
|
||||
codeLookupBase.put("Digit8", new LegacyKeycode(0x38, 0));
|
||||
codeLookupBase.put("Digit9", new LegacyKeycode(0x39, 0));
|
||||
codeLookupBase.put("KeyA", new LegacyKeycode(0x41, 0));
|
||||
codeLookupBase.put("KeyB", new LegacyKeycode(0x42, 0));
|
||||
codeLookupBase.put("KeyC", new LegacyKeycode(0x43, 0));
|
||||
codeLookupBase.put("KeyD", new LegacyKeycode(0x44, 0));
|
||||
codeLookupBase.put("KeyE", new LegacyKeycode(0x45, 0));
|
||||
codeLookupBase.put("KeyF", new LegacyKeycode(0x46, 0));
|
||||
codeLookupBase.put("KeyG", new LegacyKeycode(0x47, 0));
|
||||
codeLookupBase.put("KeyH", new LegacyKeycode(0x48, 0));
|
||||
codeLookupBase.put("KeyI", new LegacyKeycode(0x49, 0));
|
||||
codeLookupBase.put("KeyJ", new LegacyKeycode(0x4A, 0));
|
||||
codeLookupBase.put("KeyK", new LegacyKeycode(0x4B, 0));
|
||||
codeLookupBase.put("KeyL", new LegacyKeycode(0x4C, 0));
|
||||
codeLookupBase.put("KeyM", new LegacyKeycode(0x4D, 0));
|
||||
codeLookupBase.put("KeyN", new LegacyKeycode(0x4E, 0));
|
||||
codeLookupBase.put("KeyO", new LegacyKeycode(0x4F, 0));
|
||||
codeLookupBase.put("KeyP", new LegacyKeycode(0x50, 0));
|
||||
codeLookupBase.put("KeyQ", new LegacyKeycode(0x51, 0));
|
||||
codeLookupBase.put("KeyR", new LegacyKeycode(0x52, 0));
|
||||
codeLookupBase.put("KeyS", new LegacyKeycode(0x53, 0));
|
||||
codeLookupBase.put("KeyT", new LegacyKeycode(0x54, 0));
|
||||
codeLookupBase.put("KeyU", new LegacyKeycode(0x55, 0));
|
||||
codeLookupBase.put("KeyV", new LegacyKeycode(0x56, 0));
|
||||
codeLookupBase.put("KeyW", new LegacyKeycode(0x57, 0));
|
||||
codeLookupBase.put("KeyX", new LegacyKeycode(0x58, 0));
|
||||
codeLookupBase.put("KeyY", new LegacyKeycode(0x59, 0));
|
||||
codeLookupBase.put("KeyZ", new LegacyKeycode(0x5A, 0));
|
||||
codeLookupBase.put("Comma", new LegacyKeycode(0xBC, 0));
|
||||
codeLookupBase.put("Period", new LegacyKeycode(0xBE, 0));
|
||||
codeLookupBase.put("Semicolon", new LegacyKeycode(0xBA, 0));
|
||||
codeLookupBase.put("Quote", new LegacyKeycode(0xDE, 0));
|
||||
codeLookupBase.put("BracketLeft", new LegacyKeycode(0xDB, 0));
|
||||
codeLookupBase.put("BracketRight", new LegacyKeycode(0xDD, 0));
|
||||
codeLookupBase.put("Backquote", new LegacyKeycode(0xC0, 0));
|
||||
codeLookupBase.put("Backslash", new LegacyKeycode(0xDC, 0));
|
||||
codeLookupBase.put("IntlBackslash", new LegacyKeycode(0xDC, 0));
|
||||
codeLookupBase.put("Minus", new LegacyKeycode(0xBD, 0));
|
||||
codeLookupBase.put("Equal", new LegacyKeycode(0xBB, 0));
|
||||
codeLookupBase.put("Slash", new LegacyKeycode(0xBF, 0));
|
||||
codeLookupBase.put("IntlRo", new LegacyKeycode(0xC1, 0));
|
||||
codeLookupBase.put("IntlYen", new LegacyKeycode(0xFF, 0));
|
||||
codeLookupBase.put("AltLeft", new LegacyKeycode(0x12, 1));
|
||||
codeLookupBase.put("AltRight", new LegacyKeycode(0x12, 2));
|
||||
codeLookupBase.put("CapsLock", new LegacyKeycode(0x14, 0));
|
||||
codeLookupBase.put("ControlLeft", new LegacyKeycode(0x11, 1));
|
||||
codeLookupBase.put("ControlRight", new LegacyKeycode(0x11, 2));
|
||||
codeLookupBase.put("MetaLeft", new LegacyKeycode(0x5B, 1));
|
||||
codeLookupBase.put("MetaRight", new LegacyKeycode(0x5C, 2));
|
||||
codeLookupBase.put("ShiftLeft", new LegacyKeycode(0x10, 1));
|
||||
codeLookupBase.put("ShiftRight", new LegacyKeycode(0x10, 2));
|
||||
codeLookupBase.put("ContextMenu", new LegacyKeycode(0x5D, 0));
|
||||
codeLookupBase.put("Enter", new LegacyKeycode(0x0D, 0));
|
||||
codeLookupBase.put("Space", new LegacyKeycode(0x20, 0));
|
||||
codeLookupBase.put("Backspace", new LegacyKeycode(0x08, 0));
|
||||
codeLookupBase.put("Tab", new LegacyKeycode(0x09, 0));
|
||||
codeLookupBase.put("Delete", new LegacyKeycode(0x2E, 0));
|
||||
codeLookupBase.put("End", new LegacyKeycode(0x23, 0));
|
||||
codeLookupBase.put("Help", new LegacyKeycode(0x2D, 0));
|
||||
codeLookupBase.put("Home", new LegacyKeycode(0x24, 0));
|
||||
codeLookupBase.put("Insert", new LegacyKeycode(0x2D, 0));
|
||||
codeLookupBase.put("PageDown", new LegacyKeycode(0x22, 0));
|
||||
codeLookupBase.put("PageUp", new LegacyKeycode(0x21, 0));
|
||||
codeLookupBase.put("ArrowDown", new LegacyKeycode(0x28, 0));
|
||||
codeLookupBase.put("ArrowLeft", new LegacyKeycode(0x25, 0));
|
||||
codeLookupBase.put("ArrowRight", new LegacyKeycode(0x27, 0));
|
||||
codeLookupBase.put("ArrowUp", new LegacyKeycode(0x26, 0));
|
||||
codeLookupBase.put("Escape", new LegacyKeycode(0x1B, 0));
|
||||
codeLookupBase.put("PrintScreen", new LegacyKeycode(0x2C, 0));
|
||||
codeLookupBase.put("ScrollLock", new LegacyKeycode(0x91, 0));
|
||||
codeLookupBase.put("Pause", new LegacyKeycode(0x13, 0));
|
||||
codeLookupBase.put("F1", new LegacyKeycode(0x70, 0));
|
||||
codeLookupBase.put("F2", new LegacyKeycode(0x71, 0));
|
||||
codeLookupBase.put("F3", new LegacyKeycode(0x72, 0));
|
||||
codeLookupBase.put("F4", new LegacyKeycode(0x73, 0));
|
||||
codeLookupBase.put("F5", new LegacyKeycode(0x74, 0));
|
||||
codeLookupBase.put("F6", new LegacyKeycode(0x75, 0));
|
||||
codeLookupBase.put("F7", new LegacyKeycode(0x76, 0));
|
||||
codeLookupBase.put("F8", new LegacyKeycode(0x77, 0));
|
||||
codeLookupBase.put("F9", new LegacyKeycode(0x78, 0));
|
||||
codeLookupBase.put("F10", new LegacyKeycode(0x79, 0));
|
||||
codeLookupBase.put("F11", new LegacyKeycode(0x7A, 0));
|
||||
codeLookupBase.put("F12", new LegacyKeycode(0x7B, 0));
|
||||
codeLookupBase.put("F13", new LegacyKeycode(0x7C, 0));
|
||||
codeLookupBase.put("F14", new LegacyKeycode(0x7D, 0));
|
||||
codeLookupBase.put("F15", new LegacyKeycode(0x7E, 0));
|
||||
codeLookupBase.put("F16", new LegacyKeycode(0x7F, 0));
|
||||
codeLookupBase.put("F17", new LegacyKeycode(0x80, 0));
|
||||
codeLookupBase.put("F18", new LegacyKeycode(0x81, 0));
|
||||
codeLookupBase.put("F19", new LegacyKeycode(0x82, 0));
|
||||
codeLookupBase.put("F20", new LegacyKeycode(0x83, 0));
|
||||
codeLookupBase.put("F21", new LegacyKeycode(0x84, 0));
|
||||
codeLookupBase.put("F22", new LegacyKeycode(0x85, 0));
|
||||
codeLookupBase.put("F23", new LegacyKeycode(0x86, 0));
|
||||
codeLookupBase.put("F24", new LegacyKeycode(0x87, 0));
|
||||
codeLookupBase.put("NumLock", new LegacyKeycode(0x90, 3));
|
||||
codeLookupBase.put("Numpad0", new LegacyKeycode(0x60, 3));
|
||||
codeLookupBase.put("Numpad1", new LegacyKeycode(0x61, 3));
|
||||
codeLookupBase.put("Numpad2", new LegacyKeycode(0x62, 3));
|
||||
codeLookupBase.put("Numpad3", new LegacyKeycode(0x63, 3));
|
||||
codeLookupBase.put("Numpad4", new LegacyKeycode(0x64, 3));
|
||||
codeLookupBase.put("Numpad5", new LegacyKeycode(0x65, 3));
|
||||
codeLookupBase.put("Numpad6", new LegacyKeycode(0x66, 3));
|
||||
codeLookupBase.put("Numpad7", new LegacyKeycode(0x67, 3));
|
||||
codeLookupBase.put("Numpad8", new LegacyKeycode(0x68, 3));
|
||||
codeLookupBase.put("Numpad9", new LegacyKeycode(0x69, 3));
|
||||
codeLookupBase.put("NumpadAdd", new LegacyKeycode(0x6B, 3));
|
||||
codeLookupBase.put("NumpadComma", new LegacyKeycode(0xC2, 3));
|
||||
codeLookupBase.put("NumpadDecimal", new LegacyKeycode(0x6E, 3));
|
||||
codeLookupBase.put("NumpadDivide", new LegacyKeycode(0x6F, 3));
|
||||
codeLookupBase.put("NumpadEnter", new LegacyKeycode(0x0D, 3));
|
||||
codeLookupBase.put("NumpadEqual", new LegacyKeycode(0x0C, 3));
|
||||
codeLookupBase.put("NumpadMultiply", new LegacyKeycode(0x6A, 3));
|
||||
codeLookupBase.put("NumpadSubtract", new LegacyKeycode(0x6D, 3));
|
||||
}
|
||||
|
||||
public LegacyKeycodeTranslator addBrowserLayoutMapping(String keyChar, String codeStr) {
|
||||
LegacyKeycode mapTo = codeLookupBase.get(codeStr);
|
||||
if(mapTo != null) {
|
||||
String keyCode = getCodeFromLayoutChar(keyChar);
|
||||
if(keyCode != null && !keyCode.equals(codeStr) && !(codeStr.startsWith("Numpad") && numpadVolatile.contains(keyCode)) && !mapTo.equals(codeLookupBase.get(keyCode))) {
|
||||
codeLookupLayout.put(keyCode, mapTo);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getRemappedKeyCount() {
|
||||
return codeLookupLayout.size();
|
||||
}
|
||||
|
||||
public Map<String,LegacyKeycode> buildLayoutTable() {
|
||||
if(codeLookupLayout.isEmpty()) {
|
||||
return codeLookupBase;
|
||||
}
|
||||
Map<String,LegacyKeycode> ret = new HashMap<>();
|
||||
ret.putAll(codeLookupBase);
|
||||
ret.putAll(codeLookupLayout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static String getCodeFromLayoutChar(String keyChar) {
|
||||
if(keyChar.length() != 1) {
|
||||
return null;
|
||||
}
|
||||
char c = keyChar.charAt(0);
|
||||
String ret = getCodeFromLayoutChar0(c);
|
||||
if(ret == null) {
|
||||
ret = getCodeFromLayoutChar0(Character.toLowerCase(c));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static String getCodeFromLayoutChar0(char keyChar) {
|
||||
switch(keyChar) {
|
||||
case 'e':
|
||||
return "KeyE";
|
||||
case 'd':
|
||||
return "KeyD";
|
||||
case 'u':
|
||||
return "KeyU";
|
||||
case '-':
|
||||
return "Minus";
|
||||
case 'h':
|
||||
return "KeyH";
|
||||
case 'z':
|
||||
return "KeyZ";
|
||||
case '=':
|
||||
return "Equal";
|
||||
case 'p':
|
||||
return "KeyP";
|
||||
case ';':
|
||||
return "Semicolon";
|
||||
case ']':
|
||||
return "BracketRight";
|
||||
case '/':
|
||||
return "Slash";
|
||||
case '[':
|
||||
return "BracketLeft";
|
||||
case 'l':
|
||||
return "KeyL";
|
||||
case '8':
|
||||
return "Digit8";
|
||||
case 'w':
|
||||
return "KeyW";
|
||||
case 's':
|
||||
return "KeyS";
|
||||
case '5':
|
||||
return "Digit5";
|
||||
case '9':
|
||||
return "Digit9";
|
||||
case 'o':
|
||||
return "KeyO";
|
||||
case '.':
|
||||
return "Period";
|
||||
case '6':
|
||||
return "Digit6";
|
||||
case 'v':
|
||||
return "KeyV";
|
||||
case '3':
|
||||
return "Digit3";
|
||||
case '`':
|
||||
return "Backquote";
|
||||
case 'g':
|
||||
return "KeyG";
|
||||
case 'j':
|
||||
return "KeyJ";
|
||||
case 'q':
|
||||
return "KeyQ";
|
||||
case '1':
|
||||
return "Digit1";
|
||||
case 't':
|
||||
return "KeyT";
|
||||
case 'y':
|
||||
return "KeyY";
|
||||
case '\'':
|
||||
return "Quote";
|
||||
case '\\':
|
||||
return "Backslash";
|
||||
case 'k':
|
||||
return "KeyK";
|
||||
case 'f':
|
||||
return "KeyF";
|
||||
case 'i':
|
||||
return "KeyI";
|
||||
case 'r':
|
||||
return "KeyR";
|
||||
case 'x':
|
||||
return "KeyX";
|
||||
case 'a':
|
||||
return "KeyA";
|
||||
case '2':
|
||||
return "Digit2";
|
||||
case '7':
|
||||
return "Digit7";
|
||||
case 'm':
|
||||
return "KeyM";
|
||||
case '4':
|
||||
return "Digit4";
|
||||
case '0':
|
||||
return "Digit0";
|
||||
case 'n':
|
||||
return "KeyN";
|
||||
case 'b':
|
||||
return "KeyB";
|
||||
case 'c':
|
||||
return "KeyC";
|
||||
case ',':
|
||||
return "Comma";
|
||||
case '*':
|
||||
return "NumpadMultiply";
|
||||
case 0xA5:
|
||||
return "IntlYen";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm.WorkerMain;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class MainClass {
|
||||
|
||||
public static void main(String[] args) {
|
||||
WASMGCCrashReportStrings.setCrashReportStrings();
|
||||
if(args.length == 1) {
|
||||
if("_worker_process_".equalsIgnoreCase(args[0])) {
|
||||
workerMain();
|
||||
return;
|
||||
}
|
||||
}else if(args.length == 0) {
|
||||
clientMain();
|
||||
return;
|
||||
}
|
||||
System.out.println("???");
|
||||
}
|
||||
|
||||
private static void clientMain() {
|
||||
ClientMain._main();
|
||||
}
|
||||
|
||||
private static void workerMain() {
|
||||
WorkerMain._main();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSArrayReader;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class SortedTouchEvent {
|
||||
|
||||
public interface ITouchUIDMapper {
|
||||
int call(int uidIn);
|
||||
}
|
||||
|
||||
public interface JSTouchPoint extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getPointX();
|
||||
|
||||
@JSProperty
|
||||
int getPointY();
|
||||
|
||||
@JSProperty
|
||||
float getRadius();
|
||||
|
||||
@JSProperty
|
||||
float getForce();
|
||||
|
||||
@JSProperty
|
||||
int getPointUID();
|
||||
|
||||
}
|
||||
|
||||
public static class TouchPoint {
|
||||
|
||||
public final int pointX;
|
||||
public final int pointY;
|
||||
public final float radius;
|
||||
public final float force;
|
||||
public final int uid;
|
||||
|
||||
public TouchPoint(int pointX, int pointY, float radius, float force, int uid) {
|
||||
this.pointX = pointX;
|
||||
this.pointY = pointY;
|
||||
this.radius = radius;
|
||||
this.force = force;
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final Comparator<TouchPoint> touchSortingComparator = (t1, t2) -> {
|
||||
return t1.uid - t2.uid;
|
||||
};
|
||||
|
||||
private static List<TouchPoint> convertTouchList(JSArrayReader<JSTouchPoint> jsArray, ITouchUIDMapper uidMapper,
|
||||
int windowHeight, float windowDPI) {
|
||||
int l = jsArray.getLength();
|
||||
List<TouchPoint> ret = new ArrayList<>(l);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
JSTouchPoint p = jsArray.get(i);
|
||||
ret.add(new TouchPoint((int)(p.getPointX() * windowDPI), windowHeight - (int)(p.getPointY() * windowDPI) - 1,
|
||||
p.getRadius() * windowDPI, p.getForce(), uidMapper.call(p.getPointUID())));
|
||||
}
|
||||
Collections.sort(ret, touchSortingComparator);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static SortedTouchEvent createTouchEvent(EnumTouchEvent type, JSArrayReader<JSTouchPoint> changedTouches,
|
||||
JSArrayReader<JSTouchPoint> targetTouches, ITouchUIDMapper uidMapper, int windowHeight, float windowDPI) {
|
||||
List<TouchPoint> changedTouchesList = convertTouchList(changedTouches, uidMapper, windowHeight, windowDPI);
|
||||
List<TouchPoint> targetTouchesList = convertTouchList(targetTouches, uidMapper, windowHeight, windowDPI);
|
||||
List<TouchPoint> eventTouchesList;
|
||||
switch(type) {
|
||||
case TOUCHSTART:
|
||||
eventTouchesList = changedTouchesList;
|
||||
break;
|
||||
case TOUCHMOVE:
|
||||
eventTouchesList = targetTouchesList;
|
||||
break;
|
||||
case TOUCHEND:
|
||||
default:
|
||||
eventTouchesList = changedTouchesList;
|
||||
break;
|
||||
}
|
||||
return new SortedTouchEvent(type, changedTouchesList, targetTouchesList, eventTouchesList);
|
||||
}
|
||||
|
||||
public final EnumTouchEvent type;
|
||||
private final List<TouchPoint> changedTouchesList;
|
||||
private final List<TouchPoint> targetTouchesList;
|
||||
private final List<TouchPoint> eventTouchesList;
|
||||
|
||||
public SortedTouchEvent(EnumTouchEvent type, List<TouchPoint> changedTouchesList,
|
||||
List<TouchPoint> targetTouchesList, List<TouchPoint> eventTouchesList) {
|
||||
this.type = type;
|
||||
this.changedTouchesList = changedTouchesList;
|
||||
this.targetTouchesList = targetTouchesList;
|
||||
this.eventTouchesList = eventTouchesList;
|
||||
}
|
||||
|
||||
public int getChangedTouchesSize() {
|
||||
return changedTouchesList.size();
|
||||
}
|
||||
|
||||
public List<TouchPoint> getChangedTouches() {
|
||||
return changedTouchesList;
|
||||
}
|
||||
|
||||
public int getTargetTouchesSize() {
|
||||
return targetTouchesList.size();
|
||||
}
|
||||
|
||||
public List<TouchPoint> getTargetTouches() {
|
||||
return targetTouchesList;
|
||||
}
|
||||
|
||||
public int getEventTouchesSize() {
|
||||
return eventTouchesList.size();
|
||||
}
|
||||
|
||||
public List<TouchPoint> getEventTouches() {
|
||||
return eventTouchesList;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class TeaVMUtils {
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return !!obj;")
|
||||
public static native boolean isTruthy(JSObject object);
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return !obj;")
|
||||
public static native boolean isNotTruthy(JSObject object);
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return obj === undefined;")
|
||||
public static native boolean isUndefined(JSObject object);
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.jso.JSClass;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
@JSClass
|
||||
public class TextDecoder implements JSObject {
|
||||
|
||||
public TextDecoder(String encoding) {
|
||||
}
|
||||
|
||||
public native JSString decode(Uint8Array buffer);
|
||||
|
||||
}
|
@ -0,0 +1,480 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
import net.lax1dude.eaglercraft.v1_8.ThreadLocalRandom;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.core.JSArrayReader;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapterHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsRelay;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsRoot;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsServer;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayEntry;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
|
||||
public static final IClientConfigAdapter instance = new WASMGCClientConfigAdapter();
|
||||
|
||||
private String defaultLocale = "en_US";
|
||||
private List<DefaultServer> defaultServers = new ArrayList<>();
|
||||
private List<RelayEntry> relays = new ArrayList<>();
|
||||
private String serverToJoin = null;
|
||||
private String worldsDB = "worlds";
|
||||
private String resourcePacksDB = "resourcePacks";
|
||||
private boolean checkGLErrors = false;
|
||||
private boolean checkShaderGLErrors = false;
|
||||
private boolean demoMode = EaglercraftVersion.forceDemoMode;
|
||||
private boolean isEnableDownloadOfflineButton = true;
|
||||
private String downloadOfflineButtonLink = null;
|
||||
private boolean useSpecialCursors = false;
|
||||
private boolean logInvalidCerts = false;
|
||||
private boolean checkRelaysForUpdates = false;
|
||||
private boolean enableSignatureBadge = false;
|
||||
private boolean allowVoiceClient = true;
|
||||
private boolean allowFNAWSkins = true;
|
||||
private String localStorageNamespace = "_eaglercraftX";
|
||||
private final WASMGCClientConfigAdapterHooks hooks = new WASMGCClientConfigAdapterHooks();
|
||||
private boolean enableMinceraft = true;
|
||||
private boolean enableServerCookies = true;
|
||||
private boolean allowServerRedirects = true;
|
||||
private boolean crashOnUncaughtExceptions = false;
|
||||
private boolean openDebugConsoleOnLaunch = false;
|
||||
private boolean fixDebugConsoleUnloadListener = false;
|
||||
private boolean forceWebViewSupport = false;
|
||||
private boolean enableWebViewCSP = false;
|
||||
private boolean autoFixLegacyStyleAttr = false;
|
||||
private boolean forceProfanityFilter = false;
|
||||
private boolean forceWebGL1 = false;
|
||||
private boolean forceWebGL2 = false;
|
||||
private boolean allowExperimentalWebGL1 = false;
|
||||
private boolean useWebGLExt = true;
|
||||
private boolean useJOrbisAudioDecoder = false;
|
||||
private boolean useXHRFetch = false;
|
||||
private boolean useVisualViewport = true;
|
||||
private boolean deobfStackTraces = true;
|
||||
private boolean disableBlobURLs = false;
|
||||
private boolean eaglerNoDelay = false;
|
||||
private boolean ramdiskMode = false;
|
||||
private boolean singleThreadMode = false;
|
||||
private boolean enforceVSync = true;
|
||||
|
||||
public void loadNative(JSObject jsObject) {
|
||||
JSEaglercraftXOptsRoot eaglercraftXOpts = (JSEaglercraftXOptsRoot)jsObject;
|
||||
|
||||
defaultLocale = eaglercraftXOpts.getLang("en_US");
|
||||
serverToJoin = eaglercraftXOpts.getJoinServer(null);
|
||||
worldsDB = eaglercraftXOpts.getWorldsDB("worlds");
|
||||
resourcePacksDB = eaglercraftXOpts.getResourcePacksDB("resourcePacks");
|
||||
checkGLErrors = eaglercraftXOpts.getCheckGLErrors(false);
|
||||
checkShaderGLErrors = eaglercraftXOpts.getCheckShaderGLErrors(false);
|
||||
demoMode = EaglercraftVersion.forceDemoMode || eaglercraftXOpts.getDemoMode(false);
|
||||
isEnableDownloadOfflineButton = eaglercraftXOpts.getEnableDownloadOfflineButton(true);
|
||||
downloadOfflineButtonLink = eaglercraftXOpts.getDownloadOfflineButtonLink(null);
|
||||
useSpecialCursors = eaglercraftXOpts.getHtml5CursorSupport(false);
|
||||
logInvalidCerts = EaglercraftVersion.enableUpdateService && !demoMode && eaglercraftXOpts.getLogInvalidCerts(false);
|
||||
enableSignatureBadge = eaglercraftXOpts.getEnableSignatureBadge(false);
|
||||
allowVoiceClient = eaglercraftXOpts.getAllowVoiceClient(true);
|
||||
allowFNAWSkins = !demoMode && eaglercraftXOpts.getAllowFNAWSkins(true);
|
||||
localStorageNamespace = eaglercraftXOpts.getLocalStorageNamespace(EaglercraftVersion.localStorageNamespace);
|
||||
enableMinceraft = eaglercraftXOpts.getEnableMinceraft(true);
|
||||
enableServerCookies = !demoMode && eaglercraftXOpts.getEnableServerCookies(true);
|
||||
allowServerRedirects = eaglercraftXOpts.getAllowServerRedirects(true);
|
||||
crashOnUncaughtExceptions = eaglercraftXOpts.getCrashOnUncaughtExceptions(false);
|
||||
openDebugConsoleOnLaunch = eaglercraftXOpts.getOpenDebugConsoleOnLaunch(false);
|
||||
fixDebugConsoleUnloadListener = eaglercraftXOpts.getFixDebugConsoleUnloadListener(false);
|
||||
forceWebViewSupport = eaglercraftXOpts.getForceWebViewSupport(false);
|
||||
enableWebViewCSP = eaglercraftXOpts.getEnableWebViewCSP(true);
|
||||
autoFixLegacyStyleAttr = eaglercraftXOpts.getAutoFixLegacyStyleAttr(true);
|
||||
forceProfanityFilter = eaglercraftXOpts.getForceProfanityFilter(false);
|
||||
forceWebGL1 = eaglercraftXOpts.getForceWebGL1(false);
|
||||
forceWebGL2 = eaglercraftXOpts.getForceWebGL2(false);
|
||||
allowExperimentalWebGL1 = eaglercraftXOpts.getAllowExperimentalWebGL1(true);
|
||||
useWebGLExt = eaglercraftXOpts.getUseWebGLExt(true);
|
||||
useJOrbisAudioDecoder = eaglercraftXOpts.getUseJOrbisAudioDecoder(false);
|
||||
useXHRFetch = eaglercraftXOpts.getUseXHRFetch(false);
|
||||
useVisualViewport = eaglercraftXOpts.getUseVisualViewport(true);
|
||||
deobfStackTraces = eaglercraftXOpts.getDeobfStackTraces(true);
|
||||
disableBlobURLs = eaglercraftXOpts.getDisableBlobURLs(false);
|
||||
eaglerNoDelay = eaglercraftXOpts.getEaglerNoDelay(false);
|
||||
ramdiskMode = eaglercraftXOpts.getRamdiskMode(false);
|
||||
singleThreadMode = eaglercraftXOpts.getSingleThreadMode(false);
|
||||
enforceVSync = eaglercraftXOpts.getEnforceVSync(true);
|
||||
JSEaglercraftXOptsHooks hooksObj = eaglercraftXOpts.getHooks();
|
||||
if(hooksObj != null) {
|
||||
hooks.loadHooks(hooksObj);
|
||||
}
|
||||
|
||||
defaultServers.clear();
|
||||
JSArrayReader<JSEaglercraftXOptsServer> serversArray = eaglercraftXOpts.getServers();
|
||||
if(serversArray != null) {
|
||||
for(int i = 0, l = serversArray.getLength(); i < l; ++i) {
|
||||
JSEaglercraftXOptsServer serverEntry = serversArray.get(i);
|
||||
boolean hideAddr = serverEntry.getHideAddr(false);
|
||||
String serverAddr = serverEntry.getAddr();
|
||||
if(serverAddr != null) {
|
||||
String serverName = serverEntry.getName("Default Server #" + i);
|
||||
defaultServers.add(new DefaultServer(serverName, serverAddr, hideAddr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relays.clear();
|
||||
JSArrayReader<JSEaglercraftXOptsRelay> relaysArray = eaglercraftXOpts.getRelays();
|
||||
if(relaysArray != null) {
|
||||
boolean gotAPrimary = false;
|
||||
for(int i = 0, l = relaysArray.getLength(); i < l; ++i) {
|
||||
JSEaglercraftXOptsRelay relay = relaysArray.get(i);
|
||||
String addr = relay.getAddr();
|
||||
if(addr != null) {
|
||||
boolean p = relay.getPrimary();
|
||||
if(p) {
|
||||
if(gotAPrimary) {
|
||||
p = false;
|
||||
}else {
|
||||
gotAPrimary = true;
|
||||
}
|
||||
}
|
||||
relays.add(new RelayEntry(relay.getAddr(), relay.getComment("Default Relay #" + i), p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean officialUpdates = !demoMode && EaglercraftVersion.updateBundlePackageName.equals("net.lax1dude.eaglercraft.v1_8.client");
|
||||
if (relays.size() <= 0) {
|
||||
int choice = ThreadLocalRandom.current().nextInt(3);
|
||||
relays.add(new RelayEntry("wss://relay.deev.is/", "lax1dude relay #1", choice == 0));
|
||||
relays.add(new RelayEntry("wss://relay.lax1dude.net/", "lax1dude relay #2", choice == 1));
|
||||
relays.add(new RelayEntry("wss://relay.shhnowisnottheti.me/", "ayunami relay #1", choice == 2));
|
||||
checkRelaysForUpdates = !demoMode && eaglercraftXOpts.getCheckRelaysForUpdates(officialUpdates);
|
||||
}else {
|
||||
if(officialUpdates) {
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
String addr = relays.get(i).address;
|
||||
if(!addr.contains("deev.is") && !addr.contains("lax1dude.net") && !addr.contains("shhnowisnottheti.me")) {
|
||||
officialUpdates = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
checkRelaysForUpdates = !demoMode && eaglercraftXOpts.getCheckRelaysForUpdates(officialUpdates);
|
||||
}
|
||||
|
||||
RelayManager.relayManager.load(EagRuntime.getStorage("r"));
|
||||
|
||||
if (RelayManager.relayManager.count() <= 0) {
|
||||
RelayManager.relayManager.loadDefaults();
|
||||
RelayManager.relayManager.save();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLocale() {
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DefaultServer> getDefaultServerList() {
|
||||
return defaultServers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerToJoin() {
|
||||
return serverToJoin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorldsDB() {
|
||||
return worldsDB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourcePacksDB() {
|
||||
return resourcePacksDB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getIntegratedServerOpts() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RelayEntry> getRelays() {
|
||||
return relays;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckGLErrors() {
|
||||
return checkGLErrors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckShaderGLErrors() {
|
||||
return checkShaderGLErrors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDemo() {
|
||||
return demoMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowUpdateSvc() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowUpdateDL() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableDownloadOfflineButton() {
|
||||
return isEnableDownloadOfflineButton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadOfflineButtonLink() {
|
||||
return downloadOfflineButtonLink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSpecialCursors() {
|
||||
return useSpecialCursors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogInvalidCerts() {
|
||||
return logInvalidCerts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckRelaysForUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableSignatureBadge() {
|
||||
return enableSignatureBadge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowVoiceClient() {
|
||||
return allowVoiceClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowFNAWSkins() {
|
||||
return allowFNAWSkins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalStorageNamespace() {
|
||||
return localStorageNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableMinceraft() {
|
||||
return enableMinceraft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableServerCookies() {
|
||||
return enableServerCookies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowServerRedirects() {
|
||||
return allowServerRedirects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpenDebugConsoleOnLaunch() {
|
||||
return openDebugConsoleOnLaunch;
|
||||
}
|
||||
|
||||
public boolean isFixDebugConsoleUnloadListenerTeaVM() {
|
||||
return fixDebugConsoleUnloadListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceWebViewSupport() {
|
||||
return forceWebViewSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableWebViewCSP() {
|
||||
return enableWebViewCSP;
|
||||
}
|
||||
|
||||
public boolean isAutoFixLegacyStyleAttrTeaVM() {
|
||||
return autoFixLegacyStyleAttr;
|
||||
}
|
||||
|
||||
public boolean isForceWebGL1TeaVM() {
|
||||
return forceWebGL1;
|
||||
}
|
||||
|
||||
public boolean isForceWebGL2TeaVM() {
|
||||
return forceWebGL2;
|
||||
}
|
||||
|
||||
public boolean isAllowExperimentalWebGL1TeaVM() {
|
||||
return allowExperimentalWebGL1;
|
||||
}
|
||||
|
||||
public boolean isUseWebGLExtTeaVM() {
|
||||
return useWebGLExt;
|
||||
}
|
||||
|
||||
public boolean isUseJOrbisAudioDecoderTeaVM() {
|
||||
return useJOrbisAudioDecoder;
|
||||
}
|
||||
|
||||
public boolean isUseXHRFetchTeaVM() {
|
||||
return useXHRFetch;
|
||||
}
|
||||
|
||||
public boolean isDeobfStackTracesTeaVM() {
|
||||
return deobfStackTraces;
|
||||
}
|
||||
|
||||
public boolean isUseVisualViewportTeaVM() {
|
||||
return useVisualViewport;
|
||||
}
|
||||
|
||||
public boolean isDisableBlobURLsTeaVM() {
|
||||
return disableBlobURLs;
|
||||
}
|
||||
|
||||
public boolean isSingleThreadModeTeaVM() {
|
||||
return singleThreadMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowBootMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceProfanityFilter() {
|
||||
return forceProfanityFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEaglerNoDelay() {
|
||||
return eaglerNoDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRamdiskMode() {
|
||||
return ramdiskMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnforceVSync() {
|
||||
return enforceVSync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
}
|
||||
|
||||
public JSONObject toJSONObject() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("lang", defaultLocale);
|
||||
jsonObject.put("joinServer", serverToJoin);
|
||||
jsonObject.put("worldsDB", worldsDB);
|
||||
jsonObject.put("resourcePacksDB", resourcePacksDB);
|
||||
jsonObject.put("checkGLErrors", checkGLErrors);
|
||||
jsonObject.put("checkShaderGLErrors", checkShaderGLErrors);
|
||||
jsonObject.put("demoMode", demoMode);
|
||||
jsonObject.put("enableDownloadOfflineButton", isEnableDownloadOfflineButton);
|
||||
jsonObject.put("downloadOfflineButtonLink", downloadOfflineButtonLink);
|
||||
jsonObject.put("html5CursorSupport", useSpecialCursors);
|
||||
jsonObject.put("logInvalidCerts", logInvalidCerts);
|
||||
jsonObject.put("checkRelaysForUpdates", checkRelaysForUpdates);
|
||||
jsonObject.put("enableSignatureBadge", enableSignatureBadge);
|
||||
jsonObject.put("allowVoiceClient", allowVoiceClient);
|
||||
jsonObject.put("allowFNAWSkins", allowFNAWSkins);
|
||||
jsonObject.put("localStorageNamespace", localStorageNamespace);
|
||||
jsonObject.put("enableMinceraft", enableMinceraft);
|
||||
jsonObject.put("enableServerCookies", enableServerCookies);
|
||||
jsonObject.put("allowServerRedirects", allowServerRedirects);
|
||||
jsonObject.put("crashOnUncaughtExceptions", crashOnUncaughtExceptions);
|
||||
jsonObject.put("openDebugConsoleOnLaunch", openDebugConsoleOnLaunch);
|
||||
jsonObject.put("fixDebugConsoleUnloadListener", fixDebugConsoleUnloadListener);
|
||||
jsonObject.put("forceWebViewSupport", forceWebViewSupport);
|
||||
jsonObject.put("enableWebViewCSP", enableWebViewCSP);
|
||||
jsonObject.put("autoFixLegacyStyleAttr", autoFixLegacyStyleAttr);
|
||||
jsonObject.put("forceProfanityFilter", forceProfanityFilter);
|
||||
jsonObject.put("forceWebGL1", forceWebGL1);
|
||||
jsonObject.put("forceWebGL2", forceWebGL2);
|
||||
jsonObject.put("allowExperimentalWebGL1", allowExperimentalWebGL1);
|
||||
jsonObject.put("useWebGLExt", useWebGLExt);
|
||||
jsonObject.put("useJOrbisAudioDecoder", useJOrbisAudioDecoder);
|
||||
jsonObject.put("useXHRFetch", useXHRFetch);
|
||||
jsonObject.put("useVisualViewport", useVisualViewport);
|
||||
jsonObject.put("deobfStackTraces", deobfStackTraces);
|
||||
jsonObject.put("disableBlobURLs", disableBlobURLs);
|
||||
jsonObject.put("eaglerNoDelay", eaglerNoDelay);
|
||||
jsonObject.put("ramdiskMode", ramdiskMode);
|
||||
jsonObject.put("singleThreadMode", singleThreadMode);
|
||||
jsonObject.put("enforceVSync", enforceVSync);
|
||||
JSONArray serversArr = new JSONArray();
|
||||
for(int i = 0, l = defaultServers.size(); i < l; ++i) {
|
||||
DefaultServer srv = defaultServers.get(i);
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("addr", srv.addr);
|
||||
obj.put("hideAddr", srv.hideAddress);
|
||||
obj.put("name", srv.name);
|
||||
serversArr.put(obj);
|
||||
}
|
||||
jsonObject.put("servers", serversArr);
|
||||
JSONArray relaysArr = new JSONArray();
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
RelayEntry rl = relays.get(i);
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("addr", rl.address);
|
||||
obj.put("comment", rl.comment);
|
||||
obj.put("primary", rl.primary);
|
||||
relaysArr.put(obj);
|
||||
}
|
||||
jsonObject.put("relays", relaysArr);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toJSONObject().toString();
|
||||
}
|
||||
|
||||
public String toStringFormatted() {
|
||||
return toJSONObject().toString(4);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapterHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCClientConfigAdapterHooks implements IClientConfigAdapterHooks {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("TeaVMClientConfigAdapterHooks");
|
||||
|
||||
private LocalStorageSaveHook saveHook = null;
|
||||
private LocalStorageLoadHook loadHook = null;
|
||||
private CrashReportHook crashHook = null;
|
||||
private ScreenChangeHook screenChangedHook = null;
|
||||
|
||||
@JSFunctor
|
||||
private static interface LocalStorageSaveHook extends JSObject {
|
||||
void call(String key, String base64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLocalStorageSavedHook(String key, String base64) {
|
||||
if(saveHook != null) {
|
||||
try {
|
||||
saveHook.call(key, base64);
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception while invoking eaglercraftXOpts \"localStorageSaved\" hook!");
|
||||
logger.error(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface LocalStorageLoadHook extends JSObject {
|
||||
String call(String key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String callLocalStorageLoadHook(String key) {
|
||||
if(loadHook != null) {
|
||||
try {
|
||||
return loadHook.call(key);
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception while invoking eaglercraftXOpts \"localStorageLoaded\" hook!");
|
||||
logger.error(t);
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface ScreenChangeHook extends JSObject {
|
||||
String call(String screenName, int scaledWidth, int scaledHeight, int realWidth, int realHeight,
|
||||
int scaleFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callScreenChangedHook(String screenName, int scaledWidth, int scaledHeight, int realWidth,
|
||||
int realHeight, int scaleFactor) {
|
||||
if(screenChangedHook != null) {
|
||||
try {
|
||||
screenChangedHook.call(screenName, scaledWidth, scaledHeight, realWidth, realHeight, scaleFactor);
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception while invoking eaglercraftXOpts \"screenChanged\" hook!");
|
||||
logger.error(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface CrashReportHook extends JSObject {
|
||||
void call(String crashReport, CustomMessageCB customMessageCB);
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface CustomMessageCB extends JSObject {
|
||||
void call(String msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callCrashReportHook(String crashReport, Consumer<String> customMessageCB) {
|
||||
if(crashHook != null) {
|
||||
try {
|
||||
crashHook.call(crashReport, (msg) -> customMessageCB.accept(msg));
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception while invoking eaglercraftXOpts \"screenChanged\" hook!");
|
||||
logger.error(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadHooks(JSEaglercraftXOptsHooks hooks) {
|
||||
saveHook = (LocalStorageSaveHook)hooks.getLocalStorageSavedHook();
|
||||
loadHook = (LocalStorageLoadHook)hooks.getLocalStorageLoadedHook();
|
||||
crashHook = (CrashReportHook)hooks.getCrashReportHook();
|
||||
screenChangedHook = (ScreenChangeHook)hooks.getScreenChangedHook();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.core.JSString;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCCrashReportStrings {
|
||||
|
||||
private static final int CRASH_REPORT_EAGLER_VERSION = 0;
|
||||
private static final int CRASH_REPORT_EAGLER_VENDOR = 1;
|
||||
private static final int CRASH_REPORT_MINECRAFT_VERSION = 2;
|
||||
|
||||
@Import(module = "platformRuntime", name = "setCrashReportString")
|
||||
private static native void setCrashReportString(int id, JSString str);
|
||||
|
||||
public static void setCrashReportStrings() {
|
||||
setCrashReportString(CRASH_REPORT_EAGLER_VERSION, JSString.valueOf(EaglercraftVersion.projectForkVersion));
|
||||
setCrashReportString(CRASH_REPORT_EAGLER_VENDOR, JSString.valueOf(EaglercraftVersion.projectForkVendor));
|
||||
setCrashReportString(CRASH_REPORT_MINECRAFT_VERSION, JSString.valueOf("1.8.8"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,242 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCWebSocketClient implements IWebSocketClient {
|
||||
|
||||
public interface JSWebSocketClientHandle extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getState();
|
||||
|
||||
void closeSocket();
|
||||
|
||||
void sendStringFrame(String str);
|
||||
|
||||
void sendBinaryFrame(Uint8Array arr);
|
||||
|
||||
int availableFrames();
|
||||
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame getNextFrame();
|
||||
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame[] getAllFrames();
|
||||
|
||||
void clearFrames();
|
||||
|
||||
int availableStringFrames();
|
||||
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame getNextStringFrame();
|
||||
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame[] getAllStringFrames();
|
||||
|
||||
void clearStringFrames();
|
||||
|
||||
int availableBinaryFrames();
|
||||
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame getNextBinaryFrame();
|
||||
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame[] getAllBinaryFrames();
|
||||
|
||||
void clearBinaryFrames();
|
||||
|
||||
}
|
||||
|
||||
private final JSWebSocketClientHandle handle;
|
||||
private final String uri;
|
||||
|
||||
public WASMGCWebSocketClient(JSWebSocketClientHandle handle, String uri) {
|
||||
this.handle = handle;
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumEaglerConnectionState getState() {
|
||||
int state = handle.getState();
|
||||
switch(state) {
|
||||
case 0:
|
||||
default:
|
||||
return EnumEaglerConnectionState.CLOSED;
|
||||
case 1:
|
||||
return EnumEaglerConnectionState.CONNECTING;
|
||||
case 2:
|
||||
return EnumEaglerConnectionState.CONNECTED;
|
||||
case 3:
|
||||
return EnumEaglerConnectionState.FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connectBlocking(int timeoutMS) {
|
||||
long startTime = PlatformRuntime.steadyTimeMillis();
|
||||
int state;
|
||||
for(;;) {
|
||||
state = handle.getState();
|
||||
if(state != 1) { // CONNECTING
|
||||
break;
|
||||
}
|
||||
EagUtils.sleep(50);
|
||||
if(PlatformRuntime.steadyTimeMillis() - startTime > timeoutMS) {
|
||||
state = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return state == 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return handle.getState() == 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
int state = handle.getState();
|
||||
return state != 1 && state != 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
handle.closeSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableFrames() {
|
||||
return handle.availableFrames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWebSocketFrame getNextFrame() {
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame nextFrame = handle.getNextFrame();
|
||||
return nextFrame != null ? new WASMGCWebSocketFrame(nextFrame) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IWebSocketFrame> getNextFrames() {
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame[] arrJS = handle.getAllFrames();
|
||||
if(arrJS == null) {
|
||||
return null;
|
||||
}
|
||||
int len = arrJS.length;
|
||||
IWebSocketFrame[] arr = new IWebSocketFrame[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
arr[i] = new WASMGCWebSocketFrame(arrJS[i]);
|
||||
}
|
||||
return Arrays.asList(arr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFrames() {
|
||||
handle.clearFrames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableStringFrames() {
|
||||
return handle.availableStringFrames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWebSocketFrame getNextStringFrame() {
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame nextFrame = handle.getNextStringFrame();
|
||||
return nextFrame != null ? new WASMGCWebSocketFrame(nextFrame) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IWebSocketFrame> getNextStringFrames() {
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame[] arrJS = handle.getAllStringFrames();
|
||||
if(arrJS == null) {
|
||||
return null;
|
||||
}
|
||||
int len = arrJS.length;
|
||||
IWebSocketFrame[] arr = new IWebSocketFrame[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
arr[i] = new WASMGCWebSocketFrame(arrJS[i]);
|
||||
}
|
||||
return Arrays.asList(arr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearStringFrames() {
|
||||
handle.clearStringFrames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableBinaryFrames() {
|
||||
return handle.availableBinaryFrames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWebSocketFrame getNextBinaryFrame() {
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame nextFrame = handle.getNextBinaryFrame();
|
||||
return nextFrame != null ? new WASMGCWebSocketFrame(nextFrame) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IWebSocketFrame> getNextBinaryFrames() {
|
||||
WASMGCWebSocketFrame.JSWebSocketFrame[] arrJS = handle.getAllBinaryFrames();
|
||||
if(arrJS == null) {
|
||||
return null;
|
||||
}
|
||||
int len = arrJS.length;
|
||||
IWebSocketFrame[] arr = new IWebSocketFrame[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
arr[i] = new WASMGCWebSocketFrame(arrJS[i]);
|
||||
}
|
||||
return Arrays.asList(arr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBinaryFrames() {
|
||||
handle.clearStringFrames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String str) {
|
||||
handle.sendStringFrame(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(byte[] bytes) {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(bytes);
|
||||
try {
|
||||
handle.sendBinaryFrame(WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentURI() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WASMGCWebSocketFrame implements IWebSocketFrame {
|
||||
|
||||
public interface JSWebSocketFrame extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
int getType();
|
||||
|
||||
@JSProperty("data")
|
||||
ArrayBuffer getDataBinary();
|
||||
|
||||
@JSProperty("data")
|
||||
JSString getDataJSString();
|
||||
|
||||
@JSProperty
|
||||
double getTimestamp();
|
||||
|
||||
}
|
||||
|
||||
private final JSWebSocketFrame handle;
|
||||
private final boolean isStr;
|
||||
private int cachedLength = -1;
|
||||
private String cachedString = null;
|
||||
private byte[] cachedByteArray = null;
|
||||
|
||||
public WASMGCWebSocketFrame(JSWebSocketFrame handle) {
|
||||
this.handle = handle;
|
||||
this.isStr = handle.getType() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isString() {
|
||||
return isStr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
if(cachedString == null) {
|
||||
cachedString = getString0();
|
||||
}
|
||||
return cachedString;
|
||||
}
|
||||
|
||||
private String getString0() {
|
||||
if(!isStr) return null;
|
||||
return BetterJSStringConverter.stringFromJS(handle.getDataJSString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
if(cachedByteArray == null) {
|
||||
cachedByteArray = getByteArray0();
|
||||
}
|
||||
return cachedByteArray;
|
||||
}
|
||||
|
||||
private byte[] getByteArray0() {
|
||||
if(isStr) return null;
|
||||
return WASMGCDirectArrayConverter.externU8ArrayToByteArray(new Uint8Array(handle.getDataBinary()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return new EaglerInputStream(getByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
if(cachedLength == -1) {
|
||||
cachedLength = getLength0();
|
||||
}
|
||||
return cachedLength;
|
||||
}
|
||||
|
||||
private int getLength0() {
|
||||
if(isStr) {
|
||||
return handle.getDataJSString().getLength();
|
||||
}else {
|
||||
return handle.getDataBinary().getByteLength();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return (long)handle.getTimestamp();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,297 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
|
||||
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IBufferArrayGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IFramebufferGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IRenderbufferGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.ITextureGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WebGLBackBuffer {
|
||||
|
||||
private static int glesVers = -1;
|
||||
|
||||
private static IFramebufferGL eagFramebuffer;
|
||||
private static int width;
|
||||
private static int height;
|
||||
|
||||
// GLES 3.0+
|
||||
private static IRenderbufferGL gles3ColorRenderbuffer;
|
||||
private static IRenderbufferGL gles3DepthRenderbuffer;
|
||||
|
||||
// GLES 2.0
|
||||
private static ITextureGL gles2ColorTexture;
|
||||
private static IRenderbufferGL gles2DepthRenderbuffer;
|
||||
private static IProgramGL gles2BlitProgram;
|
||||
private static IBufferArrayGL gles2BlitVAO;
|
||||
private static IBufferGL gles2BlitVBO;
|
||||
|
||||
private static boolean isVAOCapable = false;
|
||||
private static boolean isEmulatedVAOPhase = false;
|
||||
|
||||
private static final int _GL_FRAMEBUFFER = 0x8D40;
|
||||
private static final int _GL_RENDERBUFFER = 0x8D41;
|
||||
private static final int _GL_COLOR_ATTACHMENT0 = 0x8CE0;
|
||||
private static final int _GL_DEPTH_ATTACHMENT = 0x8D00;
|
||||
private static final int _GL_DEPTH_COMPONENT16 = 0x81A5;
|
||||
private static final int _GL_DEPTH_COMPONENT32F = 0x8CAC;
|
||||
private static final int _GL_READ_FRAMEBUFFER = 0x8CA8;
|
||||
private static final int _GL_DRAW_FRAMEBUFFER = 0x8CA9;
|
||||
|
||||
public static void initBackBuffer(int sw, int sh) {
|
||||
glesVers = checkOpenGLESVersion();
|
||||
eagFramebuffer = _wglCreateFramebuffer();
|
||||
isVAOCapable = checkVAOCapable();
|
||||
isEmulatedVAOPhase = false;
|
||||
width = sw;
|
||||
height = sh;
|
||||
if(glesVers >= 300) {
|
||||
gles3ColorRenderbuffer = _wglCreateRenderbuffer();
|
||||
gles3DepthRenderbuffer = _wglCreateRenderbuffer();
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, eagFramebuffer);
|
||||
_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3ColorRenderbuffer);
|
||||
_wglRenderbufferStorage(_GL_RENDERBUFFER, GL_RGBA8, sw, sh);
|
||||
_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, _GL_RENDERBUFFER, gles3ColorRenderbuffer);
|
||||
_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3DepthRenderbuffer);
|
||||
_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT32F, sw, sh);
|
||||
_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_DEPTH_ATTACHMENT, _GL_RENDERBUFFER, gles3DepthRenderbuffer);
|
||||
_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
|
||||
}else {
|
||||
gles2ColorTexture = _wglGenTextures();
|
||||
gles2DepthRenderbuffer = _wglCreateRenderbuffer();
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, eagFramebuffer);
|
||||
_wglBindTexture(GL_TEXTURE_2D, gles2ColorTexture);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sw, sh, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
|
||||
_wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gles2ColorTexture, 0);
|
||||
_wglBindRenderbuffer(_GL_RENDERBUFFER, gles2DepthRenderbuffer);
|
||||
_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT16, sw, sh);
|
||||
_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_DEPTH_ATTACHMENT, _GL_RENDERBUFFER, gles2DepthRenderbuffer);
|
||||
|
||||
ByteBuffer upload = PlatformRuntime.allocateByteBuffer(48);
|
||||
upload.putFloat(0.0f); upload.putFloat(0.0f);
|
||||
upload.putFloat(1.0f); upload.putFloat(0.0f);
|
||||
upload.putFloat(0.0f); upload.putFloat(1.0f);
|
||||
upload.putFloat(1.0f); upload.putFloat(0.0f);
|
||||
upload.putFloat(1.0f); upload.putFloat(1.0f);
|
||||
upload.putFloat(0.0f); upload.putFloat(1.0f);
|
||||
upload.flip();
|
||||
|
||||
gles2BlitVBO = _wglGenBuffers();
|
||||
EaglercraftGPU.bindVAOGLArrayBufferNow(gles2BlitVBO);
|
||||
_wglBufferData(GL_ARRAY_BUFFER, upload, GL_STATIC_DRAW);
|
||||
|
||||
PlatformRuntime.freeByteBuffer(upload);
|
||||
|
||||
if(isVAOCapable) {
|
||||
gles2BlitVAO = _wglGenVertexArrays();
|
||||
_wglBindVertexArray(gles2BlitVAO);
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
|
||||
}
|
||||
|
||||
IShaderGL vertShader = _wglCreateShader(GL_VERTEX_SHADER);
|
||||
_wglShaderSource(vertShader, "#version 100\nprecision mediump float; attribute vec2 a_pos2f; varying vec2 v_tex2f; void main() { v_tex2f = a_pos2f; gl_Position = vec4(a_pos2f * 2.0 - 1.0, 0.0, 1.0); }");
|
||||
_wglCompileShader(vertShader);
|
||||
|
||||
IShaderGL fragShader = _wglCreateShader(GL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(fragShader, checkTextureLODCapable()
|
||||
? "#version 100\n#extension GL_EXT_shader_texture_lod : enable\nprecision mediump float; precision mediump sampler2D; varying vec2 v_tex2f; uniform sampler2D u_samplerTex; void main() { gl_FragColor = vec4(texture2DLodEXT(u_samplerTex, v_tex2f, 0.0).rgb, 1.0); }"
|
||||
: "#version 100\nprecision mediump float; precision mediump sampler2D; varying vec2 v_tex2f; uniform sampler2D u_samplerTex; void main() { gl_FragColor = vec4(texture2D(u_samplerTex, v_tex2f).rgb, 1.0); }");
|
||||
_wglCompileShader(fragShader);
|
||||
|
||||
gles2BlitProgram = _wglCreateProgram();
|
||||
|
||||
_wglAttachShader(gles2BlitProgram, vertShader);
|
||||
_wglAttachShader(gles2BlitProgram, fragShader);
|
||||
|
||||
_wglBindAttribLocation(gles2BlitProgram, 0, "a_pos2f");
|
||||
|
||||
_wglLinkProgram(gles2BlitProgram);
|
||||
|
||||
_wglDetachShader(gles2BlitProgram, vertShader);
|
||||
_wglDetachShader(gles2BlitProgram, fragShader);
|
||||
|
||||
_wglDeleteShader(vertShader);
|
||||
_wglDeleteShader(fragShader);
|
||||
|
||||
_wglUseProgram(gles2BlitProgram);
|
||||
|
||||
_wglUniform1i(_wglGetUniformLocation(gles2BlitProgram, "u_samplerTex"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IFramebufferGL getBackBuffer() {
|
||||
return eagFramebuffer;
|
||||
}
|
||||
|
||||
public static void enterVAOEmulationPhase() {
|
||||
if(glesVers < 300) {
|
||||
if(!isEmulatedVAOPhase) {
|
||||
if(isVAOCapable) {
|
||||
_wglDeleteVertexArrays(gles2BlitVAO);
|
||||
}
|
||||
gles2BlitVAO = EaglercraftGPU.createGLBufferArray();
|
||||
EaglercraftGPU.bindGLBufferArray(gles2BlitVAO);
|
||||
EaglercraftGPU.bindVAOGLArrayBuffer(gles2BlitVBO);
|
||||
EaglercraftGPU.enableVertexAttribArray(0);
|
||||
EaglercraftGPU.vertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
|
||||
isEmulatedVAOPhase = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawBlitQuad() {
|
||||
if(isEmulatedVAOPhase) {
|
||||
EaglercraftGPU.bindGLBufferArray(gles2BlitVAO);
|
||||
EaglercraftGPU.doDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}else {
|
||||
if(isVAOCapable) {
|
||||
_wglBindVertexArray(gles2BlitVAO);
|
||||
_wglDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}else {
|
||||
EaglercraftGPU.bindGLArrayBuffer(gles2BlitVBO);
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
|
||||
_wglDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void flipBuffer(int windowWidth, int windowHeight) {
|
||||
if(glesVers >= 300) {
|
||||
_wglBindFramebufferLow(_GL_READ_FRAMEBUFFER, eagFramebuffer);
|
||||
_wglBindFramebufferLow(_GL_DRAW_FRAMEBUFFER, null);
|
||||
_wglBlitFramebuffer(0, 0, width, height, 0, 0, windowWidth, windowHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
_wglBindFramebufferLow(_GL_FRAMEBUFFER, eagFramebuffer);
|
||||
|
||||
if(windowWidth != width || windowHeight != height) {
|
||||
width = windowWidth;
|
||||
height = windowHeight;
|
||||
|
||||
_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3ColorRenderbuffer);
|
||||
_wglRenderbufferStorage(_GL_RENDERBUFFER, GL_RGBA8, windowWidth, windowHeight);
|
||||
|
||||
_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3DepthRenderbuffer);
|
||||
_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT32F, windowWidth, windowHeight);
|
||||
}
|
||||
}else {
|
||||
_wglBindFramebufferLow(_GL_FRAMEBUFFER, null);
|
||||
_wglActiveTexture(GL_TEXTURE0);
|
||||
_wglBindTexture(GL_TEXTURE_2D, gles2ColorTexture);
|
||||
|
||||
int[] viewportStash = null;
|
||||
if(isEmulatedVAOPhase) {
|
||||
viewportStash = new int[4];
|
||||
EaglercraftGPU.glGetInteger(GL_VIEWPORT, viewportStash);
|
||||
GlStateManager.viewport(0, 0, windowWidth, windowHeight);
|
||||
GlStateManager.eagPushStateForGLES2BlitHack();
|
||||
GlStateManager.disableDepth();
|
||||
GlStateManager.disableBlend();
|
||||
}else {
|
||||
_wglViewport(0, 0, windowWidth, windowHeight);
|
||||
_wglDisable(GL_DEPTH_TEST);
|
||||
_wglDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_SHADER_PROGRAM | EaglercraftGPU.CLEAR_BINDING_ARRAY_BUFFER);
|
||||
|
||||
EaglercraftGPU.bindGLShaderProgram(gles2BlitProgram);
|
||||
|
||||
drawBlitQuad();
|
||||
|
||||
if(windowWidth != width || windowHeight != height) {
|
||||
width = windowWidth;
|
||||
height = windowHeight;
|
||||
|
||||
_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, windowWidth, windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
|
||||
|
||||
_wglBindRenderbuffer(_GL_RENDERBUFFER, gles2DepthRenderbuffer);
|
||||
_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT16, windowWidth, windowHeight);
|
||||
}
|
||||
|
||||
if(isEmulatedVAOPhase) {
|
||||
EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_TEXTURE0 | EaglercraftGPU.CLEAR_BINDING_ACTIVE_TEXTURE | EaglercraftGPU.CLEAR_BINDING_SHADER_PROGRAM);
|
||||
if(viewportStash[2] > 0) {
|
||||
GlStateManager.viewport(viewportStash[0], viewportStash[1], viewportStash[2], viewportStash[3]);
|
||||
}
|
||||
GlStateManager.eagPopStateForGLES2BlitHack();
|
||||
}else {
|
||||
EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_TEXTURE0 | EaglercraftGPU.CLEAR_BINDING_ACTIVE_TEXTURE | EaglercraftGPU.CLEAR_BINDING_SHADER_PROGRAM | EaglercraftGPU.CLEAR_BINDING_BUFFER_ARRAY);
|
||||
}
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, eagFramebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
if(eagFramebuffer != null) {
|
||||
_wglDeleteFramebuffer(eagFramebuffer);
|
||||
eagFramebuffer = null;
|
||||
}
|
||||
if(gles3ColorRenderbuffer != null) {
|
||||
_wglDeleteRenderbuffer(gles3ColorRenderbuffer);
|
||||
gles3ColorRenderbuffer = null;
|
||||
}
|
||||
if(gles3DepthRenderbuffer != null) {
|
||||
_wglDeleteRenderbuffer(gles3DepthRenderbuffer);
|
||||
gles3DepthRenderbuffer = null;
|
||||
}
|
||||
if(gles2ColorTexture != null) {
|
||||
_wglDeleteTextures(gles2ColorTexture);
|
||||
gles2ColorTexture = null;
|
||||
}
|
||||
if(gles2DepthRenderbuffer != null) {
|
||||
_wglDeleteRenderbuffer(gles2DepthRenderbuffer);
|
||||
gles2DepthRenderbuffer = null;
|
||||
}
|
||||
if(gles2BlitProgram != null) {
|
||||
_wglDeleteProgram(gles2BlitProgram);
|
||||
gles2BlitProgram = null;
|
||||
}
|
||||
if(gles2BlitVAO != null) {
|
||||
if(isEmulatedVAOPhase) {
|
||||
EaglercraftGPU.destroyGLBufferArray(gles2BlitVAO);
|
||||
}else if(isVAOCapable) {
|
||||
_wglDeleteVertexArrays(gles2BlitVAO);
|
||||
}
|
||||
gles2BlitVAO = null;
|
||||
}
|
||||
if(gles2BlitVBO != null) {
|
||||
_wglDeleteBuffers(gles2BlitVBO);
|
||||
gles2BlitVBO = null;
|
||||
}
|
||||
width = 0;
|
||||
height = 0;
|
||||
isVAOCapable = false;
|
||||
isEmulatedVAOPhase = false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface WebGLQuery extends JSObject {
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface WebGLVertexArray extends JSObject {
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface JSEaglercraftXOptsHooks extends JSObject {
|
||||
|
||||
@JSBody(script = "return (typeof this.localStorageSaved === \"function\") ? this.localStorageSaved : null;")
|
||||
JSObject getLocalStorageSavedHook();
|
||||
|
||||
@JSBody(script = "return (typeof this.localStorageLoaded === \"function\") ? this.localStorageLoaded : null;")
|
||||
JSObject getLocalStorageLoadedHook();
|
||||
|
||||
@JSBody(script = "return (typeof this.crashReportShow === \"function\") ? this.crashReportShow : null;")
|
||||
JSObject getCrashReportHook();
|
||||
|
||||
@JSBody(script = "return (typeof this.screenChanged === \"function\") ? this.screenChanged : null;")
|
||||
JSObject getScreenChangedHook();
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface JSEaglercraftXOptsRelay extends JSObject {
|
||||
|
||||
@JSBody(script = "return (typeof this.addr === \"string\") ? this.addr : null;")
|
||||
String getAddr();
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.comment === \"string\") ? this.comment : def;")
|
||||
String getComment(String defaultValue);
|
||||
|
||||
@JSBody(script = "return (typeof this.primary === \"boolean\") ? this.primary : false;")
|
||||
boolean getPrimary();
|
||||
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.core.JSArrayReader;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface JSEaglercraftXOptsRoot extends JSObject {
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.lang === \"string\") ? this.lang : def;")
|
||||
String getLang(String defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.joinServer === \"string\") ? this.joinServer : def;")
|
||||
String getJoinServer(String defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.localesURI === \"string\") ? this.localesURI : def;")
|
||||
String getLocalesURI(String defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.worldsDB === \"string\") ? this.worldsDB : def;")
|
||||
String getWorldsDB(String defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.resourcePacksDB === \"string\") ? this.resourcePacksDB : def;")
|
||||
String getResourcePacksDB(String defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.demoMode === \"boolean\") ? this.demoMode : def;")
|
||||
boolean getDemoMode(boolean defaultValue);
|
||||
|
||||
@JSBody(script = "return (typeof this.servers === \"object\") ? this.servers : null;")
|
||||
JSArrayReader<JSEaglercraftXOptsServer> getServers();
|
||||
|
||||
@JSBody(script = "return (typeof this.relays === \"object\") ? this.relays : null;")
|
||||
JSArrayReader<JSEaglercraftXOptsRelay> getRelays();
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.checkGLErrors === \"boolean\") ? this.checkGLErrors : def;")
|
||||
boolean getCheckGLErrors(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.checkShaderGLErrors === \"boolean\") ? this.checkShaderGLErrors : def;")
|
||||
boolean getCheckShaderGLErrors(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableDownloadOfflineButton === \"boolean\") ? this.enableDownloadOfflineButton : def;")
|
||||
boolean getEnableDownloadOfflineButton(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.downloadOfflineButtonLink === \"string\") ? this.downloadOfflineButtonLink : def;")
|
||||
String getDownloadOfflineButtonLink(String defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.html5CursorSupport === \"boolean\") ? this.html5CursorSupport : def;")
|
||||
boolean getHtml5CursorSupport(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowUpdateSvc === \"boolean\") ? this.allowUpdateSvc : def;")
|
||||
boolean getAllowUpdateSvc(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowUpdateDL === \"boolean\") ? this.allowUpdateDL : def;")
|
||||
boolean getAllowUpdateDL(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.logInvalidCerts === \"boolean\") ? this.logInvalidCerts : def;")
|
||||
boolean getLogInvalidCerts(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableSignatureBadge === \"boolean\") ? this.enableSignatureBadge : def;")
|
||||
boolean getEnableSignatureBadge(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.checkRelaysForUpdates === \"boolean\") ? this.checkRelaysForUpdates : def;")
|
||||
boolean getCheckRelaysForUpdates(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowVoiceClient === \"boolean\") ? this.allowVoiceClient : def;")
|
||||
boolean getAllowVoiceClient(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowFNAWSkins === \"boolean\") ? this.allowFNAWSkins : def;")
|
||||
boolean getAllowFNAWSkins(boolean defaultValue);
|
||||
|
||||
@JSBody(script = "return (typeof this.hooks === \"object\") ? this.hooks : null;")
|
||||
JSEaglercraftXOptsHooks getHooks();
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.localStorageNamespace === \"string\") ? this.localStorageNamespace : def;")
|
||||
String getLocalStorageNamespace(String defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableMinceraft === \"boolean\") ? this.enableMinceraft : def;")
|
||||
boolean getEnableMinceraft(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableServerCookies === \"boolean\") ? this.enableServerCookies : def;")
|
||||
boolean getEnableServerCookies(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowServerRedirects === \"boolean\") ? this.allowServerRedirects : def;")
|
||||
boolean getAllowServerRedirects(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.crashOnUncaughtExceptions === \"boolean\") ? this.crashOnUncaughtExceptions : def;")
|
||||
boolean getCrashOnUncaughtExceptions(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.openDebugConsoleOnLaunch === \"boolean\") ? this.openDebugConsoleOnLaunch : def;")
|
||||
boolean getOpenDebugConsoleOnLaunch(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.fixDebugConsoleUnloadListener === \"boolean\") ? this.fixDebugConsoleUnloadListener : def;")
|
||||
boolean getFixDebugConsoleUnloadListener(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.forceWebViewSupport === \"boolean\") ? this.forceWebViewSupport : def;")
|
||||
boolean getForceWebViewSupport(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableWebViewCSP === \"boolean\") ? this.enableWebViewCSP : def;")
|
||||
boolean getEnableWebViewCSP(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.autoFixLegacyStyleAttr === \"boolean\") ? this.autoFixLegacyStyleAttr : def;")
|
||||
boolean getAutoFixLegacyStyleAttr(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.showBootMenuOnLaunch === \"boolean\") ? this.showBootMenuOnLaunch : def;")
|
||||
boolean getShowBootMenuOnLaunch(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.bootMenuBlocksUnsignedClients === \"boolean\") ? this.bootMenuBlocksUnsignedClients : def;")
|
||||
boolean getBootMenuBlocksUnsignedClients(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowBootMenu === \"boolean\") ? this.allowBootMenu : def;")
|
||||
boolean getAllowBootMenu(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.forceProfanityFilter === \"boolean\") ? this.forceProfanityFilter : def;")
|
||||
boolean getForceProfanityFilter(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.forceWebGL1 === \"boolean\") ? this.forceWebGL1 : def;")
|
||||
boolean getForceWebGL1(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.forceWebGL2 === \"boolean\") ? this.forceWebGL2 : def;")
|
||||
boolean getForceWebGL2(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowExperimentalWebGL1 === \"boolean\") ? this.allowExperimentalWebGL1 : def;")
|
||||
boolean getAllowExperimentalWebGL1(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.useWebGLExt === \"boolean\") ? this.useWebGLExt : def;")
|
||||
boolean getUseWebGLExt(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.useDelayOnSwap === \"boolean\") ? this.useDelayOnSwap : def;")
|
||||
boolean getUseDelayOnSwap(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.useJOrbisAudioDecoder === \"boolean\") ? this.useJOrbisAudioDecoder : def;")
|
||||
boolean getUseJOrbisAudioDecoder(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.useXHRFetch === \"boolean\") ? this.useXHRFetch : def;")
|
||||
boolean getUseXHRFetch(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.useVisualViewport === \"boolean\") ? this.useVisualViewport : def;")
|
||||
boolean getUseVisualViewport(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.deobfStackTraces === \"boolean\") ? this.deobfStackTraces : def;")
|
||||
boolean getDeobfStackTraces(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.disableBlobURLs === \"boolean\") ? this.disableBlobURLs : def;")
|
||||
boolean getDisableBlobURLs(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.eaglerNoDelay === \"boolean\") ? this.eaglerNoDelay : def;")
|
||||
boolean getEaglerNoDelay(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.ramdiskMode === \"boolean\") ? this.ramdiskMode : def;")
|
||||
boolean getRamdiskMode(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.singleThreadMode === \"boolean\") ? this.singleThreadMode : def;")
|
||||
boolean getSingleThreadMode(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enforceVSync === \"boolean\") ? this.enforceVSync : def;")
|
||||
boolean getEnforceVSync(boolean enforceVSync);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableEPKVersionCheck === \"boolean\") ? this.enableEPKVersionCheck : def;")
|
||||
boolean getEnableEPKVersionCheck(boolean deobfStackTraces);
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface JSEaglercraftXOptsServer extends JSObject {
|
||||
|
||||
@JSBody(script = "return (typeof this.addr === \"string\") ? this.addr : null;")
|
||||
String getAddr();
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.hideAddr === \"boolean\") ? this.hideAddr : def;")
|
||||
boolean getHideAddr(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.name === \"string\") ? this.name : def;")
|
||||
String getName(String defaultValue);
|
||||
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm.JS_IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm.SingleThreadWorker;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class ClientPlatformSingleplayer {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("ClientPlatformSingleplayer");
|
||||
|
||||
private static boolean isSingleThreadMode = false;
|
||||
|
||||
private static final LinkedList<IPCPacketData> singleThreadMessageQueue = new LinkedList<>();
|
||||
|
||||
public static void startIntegratedServer(boolean singleThreadMode) {
|
||||
singleThreadMode |= ((WASMGCClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isSingleThreadModeTeaVM();
|
||||
if(singleThreadMode) {
|
||||
if(!isSingleThreadMode) {
|
||||
SingleThreadWorker.singleThreadStartup(singleThreadMessageQueue::add);
|
||||
isSingleThreadMode = true;
|
||||
}
|
||||
}else {
|
||||
if(!startIntegratedServer0()) {
|
||||
logger.error("Failed to start integrated server!");
|
||||
logger.error("Falling back to single thread mode...");
|
||||
startIntegratedServer(true);
|
||||
}else {
|
||||
logger.info("Integrated server started");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "clientPlatformSingleplayer", name = "startIntegratedServer")
|
||||
private static native boolean startIntegratedServer0();
|
||||
|
||||
public static void sendPacket(IPCPacketData packet) {
|
||||
if(isSingleThreadMode) {
|
||||
SingleThreadWorker.sendPacketToWorker(packet);
|
||||
}else {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(packet.contents);
|
||||
try {
|
||||
sendPacket0(BetterJSStringConverter.stringToJS(packet.channel), WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "clientPlatformSingleplayer", name = "sendPacket")
|
||||
private static native void sendPacket0(JSString channel, Uint8Array arr);
|
||||
|
||||
public static List<IPCPacketData> recieveAllPacket() {
|
||||
if(isSingleThreadMode) {
|
||||
if(singleThreadMessageQueue.size() == 0) {
|
||||
return null;
|
||||
}else {
|
||||
List<IPCPacketData> ret = new ArrayList<>(singleThreadMessageQueue);
|
||||
singleThreadMessageQueue.clear();
|
||||
return ret;
|
||||
}
|
||||
}else {
|
||||
int cnt = getAvailablePackets();
|
||||
if(cnt == 0) {
|
||||
return null;
|
||||
}
|
||||
IPCPacketData[] ret = new IPCPacketData[cnt];
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
ret[i] = getNextPacket().internalize();
|
||||
}
|
||||
return Arrays.asList(ret);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "clientPlatformSingleplayer", name = "getAvailablePackets")
|
||||
private static native int getAvailablePackets();
|
||||
|
||||
@Import(module = "clientPlatformSingleplayer", name = "getNextPacket")
|
||||
private static native JS_IPCPacketData getNextPacket();
|
||||
|
||||
public static boolean canKillWorker() {
|
||||
return !isSingleThreadMode;
|
||||
}
|
||||
|
||||
@Import(module = "clientPlatformSingleplayer", name = "killWorker")
|
||||
public static native void killWorker();
|
||||
|
||||
public static boolean isRunningSingleThreadMode() {
|
||||
return isSingleThreadMode;
|
||||
}
|
||||
|
||||
public static boolean isSingleThreadModeSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void updateSingleThreadMode() {
|
||||
if(isSingleThreadMode) {
|
||||
SingleThreadWorker.singleThreadUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public static void showCrashReportOverlay(String report, int x, int y, int w, int h) {
|
||||
showCrashReportOverlay0(BetterJSStringConverter.stringToJS(report), x, y, w, h);
|
||||
}
|
||||
|
||||
@Import(module = "clientPlatformSingleplayer", name = "showCrashReportOverlay")
|
||||
private static native void showCrashReportOverlay0(JSString report, int x, int y, int w, int h);
|
||||
|
||||
@Import(module = "clientPlatformSingleplayer", name = "hideCrashReportOverlay")
|
||||
public static native void hideCrashReportOverlay();
|
||||
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.core.JSString;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Filesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.IWASMCrashCallback;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm.JS_IPCPacketData;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class ServerPlatformSingleplayer {
|
||||
|
||||
private static final List<IPCPacketData> messageQueue = new LinkedList<>();
|
||||
|
||||
private static boolean singleThreadMode = false;
|
||||
private static Consumer<IPCPacketData> singleThreadCB = null;
|
||||
|
||||
private static IEaglerFilesystem filesystem = null;
|
||||
|
||||
public static void initializeContext() {
|
||||
singleThreadMode = false;
|
||||
singleThreadCB = null;
|
||||
filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
|
||||
VFile2.setPrimaryFilesystem(filesystem);
|
||||
}
|
||||
|
||||
public static IEaglerFilesystem getWorldsDatabase() {
|
||||
return filesystem;
|
||||
}
|
||||
|
||||
public static void initializeContextSingleThread(Consumer<IPCPacketData> packetSendCallback) {
|
||||
singleThreadMode = true;
|
||||
singleThreadCB = packetSendCallback;
|
||||
filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
|
||||
}
|
||||
|
||||
public static void sendPacket(IPCPacketData packet) {
|
||||
if(singleThreadMode) {
|
||||
singleThreadCB.accept(packet);
|
||||
}else {
|
||||
ByteBuffer buf = WASMGCDirectArrayConverter.byteArrayToBuffer(packet.contents);
|
||||
try {
|
||||
sendPacket0(BetterJSStringConverter.stringToJS(packet.channel), WASMGCBufferAllocator.getUnsignedByteBufferView(buf));
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "serverPlatformSingleplayer", name = "sendPacket")
|
||||
private static native void sendPacket0(JSString channel, Uint8Array arr);
|
||||
|
||||
public static List<IPCPacketData> recieveAllPacket() {
|
||||
if(singleThreadMode) {
|
||||
if(messageQueue.size() == 0) {
|
||||
return null;
|
||||
}else {
|
||||
List<IPCPacketData> ret = new ArrayList<>(messageQueue);
|
||||
messageQueue.clear();
|
||||
return ret;
|
||||
}
|
||||
}else {
|
||||
int cnt = getAvailablePackets();
|
||||
if(cnt == 0) {
|
||||
return null;
|
||||
}
|
||||
IPCPacketData[] ret = new IPCPacketData[cnt];
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
ret[i] = getNextPacket().internalize();
|
||||
}
|
||||
return Arrays.asList(ret);
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "serverPlatformSingleplayer", name = "getAvailablePackets")
|
||||
private static native int getAvailablePackets();
|
||||
|
||||
@Import(module = "serverPlatformSingleplayer", name = "getNextPacket")
|
||||
private static native JS_IPCPacketData getNextPacket();
|
||||
|
||||
@Import(module = "platformRuntime", name = "immediateContinue")
|
||||
public static native void immediateContinue();
|
||||
|
||||
public static IClientConfigAdapter getClientConfigAdapter() {
|
||||
return WASMGCClientConfigAdapter.instance;
|
||||
}
|
||||
|
||||
public static boolean isSingleThreadMode() {
|
||||
return singleThreadMode;
|
||||
}
|
||||
|
||||
public static void recievePacketSingleThreadTeaVM(IPCPacketData pkt) {
|
||||
messageQueue.add(pkt);
|
||||
}
|
||||
|
||||
public static void setCrashCallbackWASM(IWASMCrashCallback callback) {
|
||||
setCrashCallbackWASM0().call(callback != null ? callback::callback : null);
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface JSWASMCrashCallback extends JSObject {
|
||||
void callback(String crashReport, boolean terminated);
|
||||
}
|
||||
|
||||
private static interface JSWASMCrashCallbackInterface extends JSObject {
|
||||
void call(JSWASMCrashCallback callback);
|
||||
}
|
||||
|
||||
@Import(module = "serverPlatformSingleplayer", name = "setCrashCallback")
|
||||
private static native JSWASMCrashCallbackInterface setCrashCallbackWASM0();
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface JS_IPCPacketData extends JSObject {
|
||||
|
||||
@JSProperty
|
||||
String getCh();
|
||||
|
||||
@JSProperty
|
||||
Uint8Array getData();
|
||||
|
||||
default IPCPacketData internalize() {
|
||||
return new IPCPacketData(getCh(), WASMGCDirectArrayConverter.externU8ArrayToByteArray(getData()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class SingleThreadWorker {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("SingleThreadWorker");
|
||||
|
||||
public static void singleThreadStartup(Consumer<IPCPacketData> packetSendCallback) {
|
||||
logger.info("Starting single-thread mode worker...");
|
||||
ServerPlatformSingleplayer.initializeContextSingleThread(packetSendCallback);
|
||||
EaglerIntegratedServerWorker.singleThreadMain();
|
||||
}
|
||||
|
||||
public static void sendPacketToWorker(IPCPacketData pkt) {
|
||||
ServerPlatformSingleplayer.recievePacketSingleThreadTeaVM(pkt);
|
||||
}
|
||||
|
||||
public static void singleThreadUpdate() {
|
||||
EaglerIntegratedServerWorker.singleThreadUpdate();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket15Crashed;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacketFFProcessKeepAlive;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class WorkerMain {
|
||||
|
||||
public static void _main() {
|
||||
PrintStream systemOut = System.out;
|
||||
PrintStream systemErr = System.err;
|
||||
try {
|
||||
systemOut.println("WorkerMain: [INFO] eaglercraftx worker thread is starting...");
|
||||
JSObject startArgs = getEaglerXOpts();
|
||||
systemOut.println("WorkerMain: [INFO] reading configuration");
|
||||
((WASMGCClientConfigAdapter)WASMGCClientConfigAdapter.instance).loadNative(startArgs);
|
||||
systemOut.println("WorkerMain: [INFO] initializing server runtime");
|
||||
ServerPlatformSingleplayer.initializeContext();
|
||||
systemOut.println("WorkerMain: [INFO] starting worker thread");
|
||||
PlatformRuntime.setThreadName("IntegratedServer");
|
||||
EaglerIntegratedServerWorker.serverMain();
|
||||
}catch(Throwable t) {
|
||||
System.setOut(systemOut);
|
||||
System.setErr(systemErr);
|
||||
systemErr.println("WorkerMain: [ERROR] uncaught exception thrown!");
|
||||
EagRuntime.debugPrintStackTraceToSTDERR(t);
|
||||
EaglerIntegratedServerWorker.sendIPCPacket(new IPCPacket15Crashed("UNCAUGHT EXCEPTION CAUGHT IN WORKER PROCESS!\n\n" + EagRuntime.getStackTrace(t)));
|
||||
EaglerIntegratedServerWorker.sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacketFFProcessKeepAlive.EXITED));
|
||||
}finally {
|
||||
systemErr.println("WorkerMain: [ERROR] eaglercraftx worker thread has exited");
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "getEaglercraftXOpts")
|
||||
private static native JSObject getEaglerXOpts();
|
||||
|
||||
}
|
Reference in New Issue
Block a user